S-Energy : la solution de monitoring des ressources énergétiques de la maison – Geek Is In Da House 2015 – quand la maison vous fera sortir de votre douche, de gré ou de force !
Suite à la mythique “Geek Is In Da House” des Microsoft Techdays 2015 que j’ai pu animer aux côtés de David Catuhe, Stanislas Quastana et Laurent Ellerbach , retour en détail sur mon projet “S-Energy” !
L’idée du projet fait suite à un problème de chaudière qui est intervenu en Septembre 2014. En effet lors de l’entretien annuel nous avons constaté que la vanne de sécurité du ballon d’eau chaude était défaillante laissant ainsi partir dans les canalisations des litres et des litres d’eau en continue !
Après investigation, ce problème est apparu environ 4 mois plus tôt, soit une perte sèche de plus de 450m3, l’équivalent de 3750 litres par jour (environ 25 bains tous les jours !).
Alors forcément côté portefeuille c’est dur et côté orgueil, pour un “geek” avec une maison ultra connectée, ne pas détecter une perte de près de 4.000L/jour pendant plus de 4 mois, c’est tout simplement honteux
Dès lors, je me mis en tête de concevoir “S-Energy”, une solution de monitoring intelligente des ressources énergétiques de la maison : eau, gaz et électricité.
Intelligente car une simple solution de monitoring qui ne produit que des graphiques de la consommation n’a pour moi que peu d’intérêt ! C’est bien sûr indispensable d’avoir un historique très précis sur sa consommation mais ça ne suffit pas !
L’intelligence réside dans le fait que la maison “prend conscience” de cette consommation en temps réel et dans la durée et est capable d’agir en fonction ! Vous avertir en cas de consommation anormale, vous incitez à consommer moins, etc…
Dans cet article vous découvrirez comment j’ai pu monitorer mes anciens compteurs qui n’ont pourtant pas d’interface pour permettre de faire des “auto-relevés” (impulsions, télé info, etc..) mais aussi comment je me sers des données produites grâce à la plateforme d’interconnexion des objets connectés “Constellation” pour créer de l’intelligence autour des ressources énergiques de la maison.
Mes compteurs et les solutions du marché
Quand on regarde mes compteurs, il s’agit là de vieux compteurs datant des années 90.
Hélas pas de télé-info ou d’impulsion pouvant être facilement captée à l’image du compteur d’eau “Sensus Résidia Jet” qui couplé au module Z-Wave SECURE par exemple, permet de remonter très facilement votre consommation d’eau à une box domotique.
Il existe bien des solutions sur le marché comme OpenEnergyMonitor ou encore la solution “made in france” d’EWattch mais ces dernières sont basées sur des compteurs à impulsion et télé-info pour la partie électrique, bref tout ce que je n’ai pas !
Ces deux solutions utilisent aussi des pinces ampérométrique pour l’électricité : il s’agit de pinces qu’on fixe autour d’un câble de phase et qui en déduisent l’intensité du courant électrique (donc la puissance en connaissant la tension) par le champ magnétique généré.
C’est une technique que j’utilise depuis des années. Il y a plus de trois ans, à l’aide de modules Gadgeteer et du .NET MicroFramework, j’avais réalisé un système d’estimation de ma consommation d’électricité basée sur une pince ampérométrique. La mainboard affichait la consommation instantanée sur un écran touch et envoyait, via un module Wifi, l’information dans le cloud Windows Azure. En quelque sorte, l’ancêtre de S-Energy :
Plus tard j’ai remplacé ce système par le module Z-Wave HEM de chez Aeon Labs comme présenté dans mon article “Piloter sa maison : c’est facile !”.
Mais le problème des pinces ampérométrique est qu’ils ne donnent qu’une estimation car il y a un taux d’erreur non-négligeable due à la technique de mesure et de calcul. Parfait pour donner une estimation de la consommation instantanée, mais il y une dérive importante dans le temps quant à la consommation cumulée.
Alors dernier recours : changer les compteurs par des modèles plus récents ?… Bien trop cher (plusieurs centaines d’euros par compteur) !
Pour résumer : les solutions existantes ne peuvent pas monitorer mes vieux compteurs et je refuse de dépenser de grosses sommes pour les changer ! En clair je dois trouver des solutions (qui plus est, fiables et précises) compatibles avec mes compteurs actuels !
Monitoring du compteur électrique avec un opto-interrupteur
Il y a un moyen très fiable de calculer la consommation électrique : le disque métallique qui tourne ! En effet, il s’agit d’un disque métallique avec une petite bande noir ! Chaque tour équivaut à 4 Watts/heures consommés.
Il suffit donc de compter le nombre de tour pour connaitre très précisément combien j’ai consommé d’électricité et chronométrer la vitesse de révolution pour estimer ma consommation instantanée ! C’est d’autant plus facile que le disque est métallique, donc réfléchit bien la lumière !
Pour cela j’utilise un opto-interrupteur ! Il s’agit d’un interrupteur optique : d’un côté il y a un émetteur et de l’autre un récepteur.
Installé face au disque du compteur, l’opto-interrupteur va émettre un faisceau infrarouge qui sera réfléchit par le disque métallique et capté par la partie récepteur. Dès lors que la bande noir passera devant on ne captera plus cette lumière infrarouge : un nouveau tour vient d’être détecté !
Pour driver çà, j’utilise un Arduino Pro Mini à 16Mhez et fonctionnant sur 5V (environ 2€ sur eBay !!) :
Pour le circuit, j’ai utilisé une simple plaque époxy découpé à la bonne taille :
Et pour pouvoir facilement remplacer l’Arduino ou le module de RF, j’utile des barrettes male/femelle :
L’idée du circuit est de pouvoir commander l’émetteur IR via la sortie digital n° 2 (D2) de mon Arduino. Pour la lecture de la valeur du capteur, on utilisera l’entrée analogique n°2 (A2).
Une LED rouge s’allumera à chaque tour détecté pour avoir un feedback visuel du bon fonctionnement de notre circuit. On connecte cette LED sur la sortie digitale n°9 (D9).
Enfin, à chaque tour l’idée est d’envoyer l’information à une base que nous verrons dans la suite de cet article. Pour la communication, nous utiliserons les radiofréquences sur la bande des 2,4Ghz. Pour cela j’utilise un module nRF24L01+ connecté sur le bus SPI de l’Arduino.
Comme ce module doit être alimenté en 3,3V et que notre Arduino est en 5V, j’ai ajouté un régulateur de tension LM1117T 3,3V avec quelques condensateurs 10uF.
Le schéma final :
Pour la suite, il ne reste plus qu’à installer le circuit dans un petit boitier et connecter la puce nRF24L01+ ainsi que l’Arduino Pro Mini :
Pour la programmation, j’utilise une interface FTDI USB pour “téléverser” le code de l’Arduino:
Le code est relativement simple. Je commence par déclarer les librairies que je vais utiliser, principalement le SPI et la librairie RF24 pour émettre nos informations en RF.
1 2 3 4 | #include #include "nRF24L01.h" #include "RF24.h" #include "printf.h" |
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Const const int edgeThreshold = 25; // seuil max. dans la bande noir const int normalThreshold = 150; // seuil min. sur la bande argentée const int interval = 20; // interval entre deux mesures // HW Configuration const int emitterPin = 2; // sortie digitale const int analogSendorPin = 2; // entrée analogique const int ledPin = 9; // sortie digitale const uint64_t pipe = 0xF0F0F0F0E1LL; // Set up nRF24L01 radio on SPI + pin for CE, CSN RF24 radio(8, 7); |
1 2 3 | // Variables unsigned long c=0; // c = nombre de revolutions unsigned int t=0; // t = 0 : je suis sur la bande noir, t = 1 ; je suis sur la bande argentée |
Au démarrage du programme je configure mes IO et la radio :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void setup() { // Starting serial console Serial.begin(57600); printf_begin(); // Configure outputs pinMode(emitterPin, OUTPUT); pinMode(ledPin, OUTPUT); digitalWrite(emitterPin, HIGH); digitalWrite(ledPin, LOW); // Configure RF radio radio.begin(); radio.setAutoAck(1); // Ensure autoACK is enabled radio.setRetries(15,15); radio.openWritingPipe(pipe); radio.printDetails(); // Started Serial.println("Started !"); } |
Dans ce cas j’incrémente la variable du nombre de tour (c) et je place “t” à 0 pour indiquer que je suis maintenant sur la bande noire.
J’allume ensuite la LED rouge et je prépare un tableau de long qui contiendra le n° du tour (variable c) ainsi que le timestamp (fonction “millis()” qui nous retourne le nombre de millisecondes depuis le démarrage du programme). Cette information nous permettra de calculer le temps de révolution et donc d’en déduire la consommation instantanée.
Après avoir envoyé ce tableau dans le pipe de notre module RF, j’éteins la LED rouge.
Autrement si la mesure de l’intensité du faisceau infrarouge est (deux fois de suite) supérieure au seuil “normalThreshold” c’est que je suis dans la bande argentée, je positionne alors notre variable “t” à 1, prêt pour détecter un nouveau tour !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | void loop() { if (analogRead(analogSendorPin) < edgeThreshold) { delay(interval); int sensorValue = analogRead(analogSendorPin); if (sensorValue < edgeThreshold) { if (t==1) { // Increment counter t=0; c++; // LED Power On digitalWrite(ledPin, HIGH); // Prepare data to send unsigned long datas[2]; datas[0] = c; datas[1] = millis(); // Send datas radio.write(datas, sizeof(datas)); // LED Power Off digitalWrite(ledPin, LOW); } } } if (analogRead(analogSendorPin) > normalThreshold) { delay(interval); if (analogRead(analogSendorPin) > normalThreshold) { t=1; } } } |
Il ne me reste plus qu’à installer notre système devant le compteur électrique :
Je vous conseille d’utiliser un appareil photo ou une caméra pour “voir” le rayon IR afin de positionner précisément votre opto-interrupteur. La LED rouge vous permettra de savoir si la détection des tours est correcte.
Il ne restera plus qu’à réceptionner les données reçues par RF, ce que nous verrons dans la suite de cet article.
Monitoring du compteur d’eau avec une simple caméra
Comme vous le savez impossible d’équiper une quelconque solution de monitoring pour mon compteur d’eau sans le remplacer !
Pour éviter d’en arriver là, j’ai opté pour une bonne veille technique : lire le compteur d’eau !!!
Côté hardware, il faudra “juste” faire une photo du compteur que j’analyserai ensuite par un programme de reconnaissance des caractères (OCR).
Comme la solution sera basée sur un Raspberry Pi, j’ai sélectionné la RaspiCam ! Il faudra cependant régler l’objectif pour pouvoir prendre des photos nettes à moins de 30 cm. Bon courage car l’objectif est collé, vraiment pas évident
Comme le compteur est dans un environnement obscur, il faudra ajouter des LEDs pour pouvoir éclairer le compteur lors des photos.
Monitoring du compteur de gaz avec un compteur d’impulsion magnétique
Le compteur de gaz est la partie la plus facile du projet. En effet je suis équipé d’un compteur Itron Gallon G4 sur lequel il est possible d’installer un compteur d’impulsion :
J’ai tout simplement tiré un câble RJ45 (double blindage) derrière les grilles des radiateurs jusqu’au module de compteur d’impulsion qui sera installé sur le compteur.
Réalisation de la base S-Energy avec un Raspberry Pi
Le Raspberry Pi va permettre de faire l’acquisition des trois compteurs :
- Gaz : en captant les impulsions du compteur de gaz Itron Gallus
- Electricité : réceptionnant les données émises en RF
- Eau : en analysant par OCR des photos du compteur d’eau
Pour clarifier les choses, le compteur d’eau et de gaz sont relativement proche (dans le salon) à l’inverse du compteur d’électricité qui se trouve dans l’entrée, c’est pourquoi j’ai choisi une communication sans fil entre la base « Raspberry » et l’Arduino pour le compteur électrique afin d’éviter de devoir passer un câble.
Le Raspberry sera connecté dans mon système Constellation, une plateforme d’interconnexion des objets connectés qui me permettra beaucoup de chose comme nous le verrons par la suite.
Pour la réalisation technique, j’ai utilisé un boitier étanche transparent dans lequel j’ai fait passer un câble RJ45 par un presse-étoupe :
Le câble RJ45 me permettra :
- De connecter le Raspberry au réseau (donc à la Constellation) en utilisant seulement 2 paires (100 MBits sur un RPi, donc pas besoin de plus)
- De l’alimenter (utilisation d’une paire pour faire arriver du 5V, attention tout de même à la section de votre câble)
- D’y connecter le module d’impulsion pour le gaz (via une paire)
Sur la paroi j’ai installé quelques LED et la camera pour photographier le compteur d’eau dans le noir :
J’ai ensuite réalisé un petit circuit pour le pilotage des LEDs via le RPi et pour pouvoir accueillir un module nRF24L01+ pour la réception des infos du compteur électrique.
Le tout assemblé dans le boitier :
Il ne reste plus qu’à l’installer juste au-dessus du compteur d’eau :
Pour l’expérience WAF, on remet les grilles des radiateurs et les meubles en place, pour une technologie invisible :
Il ne reste plus qu’à programmer et exploiter tout cela maintenant
Programmation et intégration dans la Constellation
Chez moi j’ai beaucoup de machines qui tournent. Des serveurs physiques, des machines virtuelles, des NUC, les laptops, des Raspberry, etc… Que ce soit sous Linux ou Windows !
Sur chacune de ces machines, il y a une armée de programme qui fonctionne 24/7 ! Une passerelle vers la Vera, une pour l’alarme Paradox, les lampes Hue, la NetAtmo, mais aussi des programmes comme Slight, S-Sound mon système audio multiroom, des programmes de surveillance du hardware, The Mirror, etc.. etc…
Il n’est pas envisageable d’écrire autant de programme/service en repartant “from scratch” et à déployer sur autant de machine !!! A chaque mise à jour, il faudrait se connecter sur la machine en RDP ou SSH pour linux, arrêter les services, déployer les MAJ, relancer les services, etc.. Quelle perte de temps !
Pour simplifier tout cela, j’ai conçu depuis plus d’un an, une technologie nommée Constellation que vous avez pu découvrir dans mon article : l’alarme du geek connectée au poignet et dans les nuages
Cette technologie sera ouverte très prochainement en open-source et vous permet de connecter vos applications, vos devices et objets sur une technologie simple et efficace !
Pour en revenir à S-Energy, la seule chose que je dois faire sur mon Raspberry est de connecter la bête à Constellation. Pour cela il suffit d’installer une “Sentinel” Constellation : copier des binaires, renseigner l’adresse du serveur Constellation et la clé d’accès, et hop mon Raspberry est enregistré dans ma constellation :
Maintenant je peux commencer le développement d’un “Package” Constellation.
La plateforme Constellation est livrée avec un SDK basé sur l’IDE de Microsoft Visual Studio 2013 disponible gratuitement avec l’édition “Community”.
Pour développer sur une plateforme Raspberry, le plus simple est de concevoir son package en Python :
Grace l’IDE Visual Studio et au SDK Constellation, il devient très confortable de développer en Python depuis Visual Studio avec tout l’IntelliSense dont on a besoin :
Réception des données du compteur électrique
Par manque de temps, je n’ai pas réussi à piloter le module nRF24 depuis un script Python, alors pour faire plus simple j’ai écrit un programme en C++ qui réceptionne les informations (numéro du tour et le timestamp) et l’affichage sur la sortie standard :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include <cstdlib> #include <iostream> #include <sstream> #include <string> #include <RF24/RF24.h> using namespace std; // Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_8MHZ); // Radio pipe address const uint64_t pipe_address = 0xF0F0F0F0E1LL; int main(int argc, char** argv) { // Make line buffered stdout setvbuf( stdout, (char *) NULL, _IOLBF, 0 ); // Starting server printf("S-Energy - Elec Server is starting ...\n"); // Configure RF radio radio.begin(); // optionally, increase the delay between retries & # of retries radio.setRetries( 15,15 ); // Dump the configuration of the rf unit for debugging radio.printDetails(); // Listening radio.openReadingPipe( 1, pipe_address ); radio.startListening(); printf("Listening ...\n"); while (1) { if ( radio.available() ) { // Receive datas unsigned long revolution_count[2]; radio.read( &revolution_count, sizeof(revolution_count) ); // Display datas printf( "Got revolution counter ! C = %lu @ %lu\n", revolution_count[0], revolution_count[1] ); } //Delay to minimize RPi CPU time delay( 925 ); } return 0; } |
Côté Python, je n’ai plus qu’à lancer ce programme et lire la sortie standard. Une petite regex pour extraire les informations et le tour est joué !
Pour lancer le process (en prenant soin de conserver son PID pour pouvoir tuer le processus en cas d’arrêt de notre package Constellation) :
1 2 3 4 5 6 7 8 9 10 11 12 13 | def startElecServerProcess(): global elecServerPID # Make the ElecServer's file as executable st = os.stat(ELECSERVER_EXECUTABLE_FILENAME) os.chmod(ELECSERVER_EXECUTABLE_FILENAME, st.st_mode | stat.S_IEXEC) # Start process process = subprocess.Popen("./" + ELECSERVER_EXECUTABLE_FILENAME, stdout=subprocess.PIPE) # Save his PID elecServerPID = process.pid # On exit, kill process Constellation.OnExitCallback = killChildProcess atexit.register(killChildProcess) return process |
Au démarrage du package dans la Constellation, on lance le process et on parse chaque ligne sur la sortie standard :
1 2 3 4 5 6 7 8 9 10 11 12 | def Start(): Constellation.WriteInfo("Starting Electricy RF Receiver") if Constellation.GetSetting("ShowDebug") is not None: SHOW_DEBUG = str(Constellation.GetSetting("ShowDebug")).lower() == "true" # Start ElecServer process process = startElecServerProcess() while Constellation.IsRunning: # Reading elec server output for line in iter(process.stdout.readline, ''): readElecServerOutputLine(line) Constellation.Start(Start) |
Pour chaque ligne de notre programme C++, si la ligne match avec la regex, on récupère le n° du tour et le timestamp qu’on a plus qu’à envoyer dans la Constellation :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | def readElecServerOutputLine(line): global e_lasttime global e_lastcounter global e_cumul isFirstRev = e_lasttime == 0 # Parse line matchObj = re.match('Got revolution counter ! C = (\d*) @ (\d*)', line) if matchObj: # Reading value counter = int(matchObj.group(1)) ts = int(matchObj.group(2)) # Compare timediff = ts - e_lasttime counterNb = counter - e_lastcounter timePerRevolution = timediff / counterNb wattPerHour = (MS_PER_HOUR / timePerRevolution) * WATT_PER_REVOLUTION # History e_lasttime = ts e_lastcounter = counter e_cumul = counter * WATT_PER_REVOLUTION # Print if isFirstRev: Constellation.WriteInfo("[ELEC] First revolution detected #%s (%s - Cumul %s W)" % (counter, ts, e_cumul)) else: Constellation.PushStateObject("Electricity", { "Counter": counter, "Timestamp" : ts, "RevolutionTime" : timePerRevolution, "WattPerHour" : wattPerHour, "Cumul" : e_cumul }, "SEnergy.Electricity") if SHOW_DEBUG: Constellation.WriteInfo("[ELEC] New revolution #%s (%s) Time/rev: %s ms => %s Wh (Cumul %s W)" % (counter, ts, timePerRevolution, wattPerHour, e_cumul)) else: Constellation.WriteInfo("INFO: %s" % line) |
Vous remarquerez quelques fonctionnalités propres à la Constellation :
- WriteInfo : permettant d’écrire des logs sur la Constellation
- PushStateObject : permettant d’envoyer dans la Constellation des objets d’état. Ici notre script envoi un StateObject nommé “Electricity” qui contient les propriétés “Counter”, “Timestamp”, “RevolutionTime”, “WattPerHour” et “Cumul” représentant l’état du compteur electrique
Nous verrons plus loin comment nous pourrons exploiter les StateObjects produits par les packages Constellation pour réaliser des systèmes d’alerting, des dashboards temps réel ou encore des systèmes de reporting.
Capter les impulsions du compteur de gaz
Notre script pour le gaz est encore olus simple, on définit une GPIO d’entrée où est connectée le compteur d’impulsion en “Pull-Up” et on attend que l’entrée soit “risée” :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def Start(): Constellation.WriteInfo("Starting GAS Sensor") Constellation.OnExitCallback = OnExit loadConfiguration() # Configure Gaz Sensor GPIO.setmode(GPIO.BCM) GPIO.setup(GAZ_SENSOR_GPIO, GPIO.IN, pull_up_down = GPIO.PUD_UP) # Start sensor # GPIO.add_event_detect(GAZ_SENSOR_GPIO, GPIO.RISING, callback=risingGazSensor, bouncetime=300) while Constellation.IsRunning: # Wait rising sensor GPIO.wait_for_edge(GAZ_SENSOR_GPIO, GPIO.FALLING) GPIO.wait_for_edge(GAZ_SENSOR_GPIO, GPIO.RISING) # Rising sensor risingGazSensor() Constellation.Start(Start) |
A chaque impulsion captée, on push un StateObject dans la Constellation où on indique le n° de l’impulsion (variable incrémentée à chaque révolution) ou encore le temps de révolution :
1 2 3 4 5 6 7 8 9 10 11 12 13 | def risingGazSensor(): global g_counter global g_lasttime global g_lastdiff if g_counter == 0: Constellation.WriteInfo("[GAS] First revolution detected") ts = int(round(time.time() * 1000)) # Compare timediff = ts - g_lasttime g_counter += 1 g_lasttime = ts # Push SO Constellation.PushStateObject("Gas", { "Counter": g_counter, "Timestamp" : ts, "RevolutionTime" : (timediff if g_counter > 1 else 0), "Cumul" : g_counter * 10 }, "SEnergy.Gas") |
Lecture du compteur d’eau
C’est la véritable difficulté du projet : lire la valeur du compteur d’eau à partir d’une photo !
Le démarrage du script est relativement simple : on charge les valeurs de configuration depuis la Constellation et on enregistre des MessageCallabcks.
Les MessageCallbacks permettent d’exposer des méthodes dans la Constellation pour que d’autre package ou application puissent les invoquer : c’est un système de Messaging intégré qui permet faire parler tout le monde (un script Python, Powershell, un programme C#, un Arduino, une page Web Javascript, etc..) ! Ici par exemple, on peut à partir d’une page Web par exemple, envoyer un message au Package “Senergy” de type “SendWaterMeterByMail” pour déclencher l’envoi de la photo du compteur par mail (utile pour un contrôle manuel).
Le plus important c’est qu’une fois démarré, on appelle la méthode “readWaterMeter” toutes les 30 secondes :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def Start(): Constellation.WriteInfo("Starting OCR Water Reader") GPIO.setmode(GPIO.BOARD) GPIO.setup(LED_GPIO, GPIO.OUT) loadConfiguration() # Register MessageCallbacks Constellation.RegisterMessageCallback("CalibrateNumbersShape", calibrateNumbersShape, True, "Recalibrate the numbers shape") Constellation.RegisterMessageCallback("SendWaterMeterByMail", sendReportByMail, True, "Send the WaterMeter report by mail") Constellation.DeclarePackageDescriptor() Constellation.OnExitCallback = OnExit # Start while Constellation.IsRunning: readWaterMeter(IMAGE_FILENAME) time.sleep(INTERVAL) Constellation.Start(Start) |
La première étape lors de la lecture du compteur c’est de prendre la photo du compteur !
Pour cela on allume les LEDs, on prend une photo en BGR et on éteint la lumière :
1 2 3 4 5 6 7 8 9 | def takePicture(): GPIO.output(LED_GPIO, True) with picamera.PiCamera() as camera: with picamera.array.PiRGBArray(camera) as stream: camera.resolution = CAMERA_RESOLUTION camera.capture(stream, format="bgr") image = stream.array GPIO.output(LED_GPIO, False) return image |
On obtient cela :
La deuxième étape est de “trouver” l’emplacement des chiffres !
Nous allons utiliser des algorithmes de “template matching” inclut dans OpenCV pour trouver les coordonnées de ces deux images :
Si vous regardez attentivement il s’agit des bords gauche et droit :
Comme nous travaillons sur une image haute résolution le traitement est assez long (environ 20 secondes sur un RPi V1). Nous conservons donc ces coordonnées dans la variable “numbersShapes” car d’une photo à l’autre les coordonnées ne sont pas censées bouger !
Reste ensuite à faire du cropping pour découper la partie de l’image qui nous intéresse, puis faire une rotation :
1 2 3 4 5 6 7 8 9 10 11 12 | # Convert BGR to gray image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Find numbers shape if not numbersShape: numbersShape = findNumbersShape(image_gray) # Cropping (startingPoint, endingPoint, left, right) = numbersShape numbers = image_gray[startingPoint[1] + left[0] - 20 : endingPoint[1], startingPoint[0] : endingPoint[0] + left[1] + 20] # Rotation transposeImage = cv2.transpose(numbers) rotated = cv2.flip(transposeImage, 0) sizePerNumber = rotated.shape[1] / 8 |
Pour la suite, nous allons découper notre image en 8 parties égales, une pour chaque chiffre à “lire” :
1 2 3 4 | # Searching numbers for i in range(0, 8): # Cropping number area number = rotated[0:rotated.shape[0], (sizePerNumber * i) - (10 if i > 1 else 0) :(sizePerNumber * i) + sizePerNumber - 10] |
Pour chacun des huit nombres du compteur nous allons tenter de trouver à quel chiffres possibles (0 à 9) il correspond, sachant que les 4 premiers chiffres sont blancs sur fond noir et les 4 dernières sont rouges sur fond blanc.
Si la correspondance dépasse 90% on considère qu’on tient le bon chiffre, sinon on tentera d’autre type de matching : par le haut et par le bas ! En fait on “crop” le template dans sa partie supérieure ou inférieure car le compteur tourne : on peut voir la fin d’un “2” et le début d’un “3”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # For each type (0: full, 1: top & 2: bottom) for t in range(0, 3): # For each potential number from 0 to 9 (include) for j in range(0, 10): for file in os.listdir("OCR_Data/"): if file.startswith(str(j) + str('r' if i > 3 else 'b')): # Open template digit = cv2.imread("OCR_Data/" + file, 0) if digit is not None: if t == 0: template = digit elif t == 1: digitW, digitH = digit.shape[::-1] template = digit[0:digitH/1.5, 0:digitW] elif t == 2: digitW, digitH = digit.shape[::-1] template = digit[digitH/2.5:digitH, 0:digitW] # Finding template x, y, score = findTemplate(number, template) # Save the best score if score > bestScore: bestScore = score bestNumber = j bestType = t # If it's top or bottom matching, keep potential number if t > 0 and score > 0.8: (scoringOnTop[i] if t == 1 else scoringOnBottom[i]).append((j, score)) # Break search type if match more than 90% if bestScore >= 0.9: break |
Si un chiffre n’est pas reconnu, j’inscris un “?” dans le résultat :
Comme vous le voyez, l’algorithme arrive bien a découvrir des chiffres même en partie caché (comme ci-dessus où les nombre 7 et 9 sont partiels).
Je “push” un premier StateObject nommé “Water.ProcessInfo” qui contient mon objet “OrcResult” (un tableau qui pour chaque chiffre indique le type de matching et son score) mais aussi le temps de capture, le temps de traitement pour l’OCR, etc… En clair un StateObject de “debug” !
J’ai ensuite quelques tests pour valider le résultat de l’OCR :
- un résultat ne peut avoir qu’un seul chiffre inconnu “?” et seulement le dernier (les décilitres)
- un résultat ne peut pas être inferieure à la valeur précédente (c’est comme le temps, ca s’écoule que dans un sens )
- la différente entre deux résultats ne peut pas être supérieure au débit maximum admissible par mon compteur d’eau (5m3/h max soit 0,00138 L / milliseconde).
En cas d’erreur, je m’envoi un mail avec la photo du compteur en pièce jointe pour analyse.
Si la valeur du compteur est cohérente, je pousse deux StateObjects dans la Constellation :
- Water.Counter : qui indique la valeur actuelle du compteur (poussé si et seulement si la valeur est différente du compteur précèdent)
- Water.Flow : contient des informations sur le débit d’eau courant : il s’agit du différentiel de temps et de litre entre les deux valeurs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # Push detail Constellation.PushStateObject("Water.ProcessInfo", { "OcrResult": result, "Timestamp" : ts, "StringResult" : strResult, "CaptureTime": captureTime, "ProcessingTime": processingTime - captureTime }, "SEnergy.WaterProcessInfo") # Check result errorMessage = "" if not checkResult(result): errorMessage = "Error: unable to read the water meter. The result was : %s" % strResult if not errorMessage and w_lastcounter > 0 and w_lastcounter > intResult : if strResult.endswith("?") and strResult[:-1] == str(w_lastcounter)[:-1]: strResult = str(w_lastcounter) intResult = w_lastcounter literDelta = 0 literPerHour = 0 else: errorMessage = "Error while reading water meter. The result was : %s but its less than the previous counter: %s" % (strResult, str(w_lastcounter)) if not errorMessage and (w_lastcounter > 0 and literDelta > timediff * QN): errorMessage = "Error while reading water meter. The result was : %s but the difference between the last counter (%s) is too high. LiterDelta:%s in %s ms" % (strResult, str(w_lastcounter), str(literDelta), str(timediff)) if errorMessage: Constellation.WriteError(errorMessage) sendErrorByMail(errorMessage, strResult) return None # Push result only if new value w_lasttime = ts if w_lastcounter != intResult: Constellation.PushStateObject("Water.Counter", { "StringResult" : strResult, "Counter" : intResult, "Timestamp" : ts }, "SEnergy.WaterResult") w_lastcounter = intResult Constellation.PushStateObject("Water.Flow", { "Timestamp" : ts, "TimeDelta" : timediff, "LiterDelta" : literDelta, "LiterPerHour" : literPerHour }, "SEnergy.WaterProcessInfo") |
Déploiement du package dans la Constellation
Et voilà, notre package Constellation “S-Energy” est prêt ! Réception des infos par RF, lecture du compteur d’eau par OCR, détection des impulsions du compteur de gaz ! Toutes ses informations sont poussées dans des StateObjects Constellation !
Pour le déploiement il suffit depuis Visual Studio de publier le package dans la Constellation :
Sur la WebConsole de ma Constellation, j’assigne le package “SEnergy” à la sentinelle installée sur le Raspberry du même nom. Le package démarre !
A coup d’œil dans la Console Web pour voir que tout démarre correctement :
Cette Console Web vous permettra de suivre en temps réel tous les “WriteLog” produits par tous vos packages de toutes vos sentinelles de votre Constellation.
Maintenant que tous mes compteurs sont publiés dans la Constellation, il ne reste plus qu’à exploiter les données !
Dashboard temps-réel
Première mission : afficher en temps-réel la valeur de mes compteurs ! Pour cela je vais utiliser l’API Javascript de la Constellation pour m’abonner aux modifications des StateObjects de SEnergy.
L’API Javascript Constellation est également disponible dans un package Nuget, il suffit donc d’installer le package pour récupérer les fichiers JS :
Ensuite dans notre page HTML ajoutons les références qui vont bien :
1 2 3 | <script type="text/javascript" src="Scripts/jquery-2.1.3.min.js"></script> <script type="text/javascript" src="Scripts/jquery.signalR-2.2.0.min.js"></script> <script type="text/javascript" src="Scripts/Constellation.js"></script> |
Dans l’exemple ci-dessous, j’affiche dans la console de mon navigateur le débit courant de l’eau (LiterPerHour du StateObject “Water.Flow”).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var constellation = $.signalR.createConstellationClient("http://myConstellationServer:8888/constellation", "AccessKeyWithControlHubAccess", "SEnergy"); constellation.client.onUpdateStateObject(function (message) { if (message.Name == "Water.Flow") { console.log("Debit courant = " + message.Value.LiterPerHour); } }); constellation.connection.stateChanged(function (change) { if (change.newState === $.signalR.connectionState.connected) { constellation.server.requestStateObjects("*", "SEnergy", "*", "*"); constellation.server.subscribeStateObjects("*", "SEnergy", "*", "*"); } }); constellation.connection.start(); |
Pour faire quelque chose de plus poussé, on peut utiliser le framework AngularJS. Pour cela, à chaque modification d’un StateObject je “broadcaste” le message de la Constellation dans le scope Angular :
1 2 3 4 | constellation.client.onUpdateStateObject(function (message) { $rootScope.$broadcast('updateStateObject', message); }); |
Puis dans mon scope, j’affecte tout simplement les propriétés de mes StateObjects à des variables de scope avec les différentes informations qui m’intéresse d’afficher :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | $scope.$on('updateStateObject', function (event, message) { $scope.$apply(function () { if(message.Name == "Electricity"){ $scope.WattPerHour = message.Value.WattPerHour; $scope.ElectricityCumul = message.Value.Cumul; $scope.ElectricityRevolutionTime = message.Value.RevolutionTime; $scope.ElectricityCounter = message.Value.Counter; } if(message.Name == "Gas"){ $scope.m3PerHour = message.Value.RevolutionTime > 0 ? Math.round(((60 * 60 * 1000) / message.Value.RevolutionTime) * 10) / 1000 : 0; $scope.GasCumul = message.Value.Cumul; $scope.GasRevolutionTime = message.Value.RevolutionTime; $scope.GasCounter = message.Value.Counter; $scope.GasLastUpdate = message.LastUpdate; } if(message.Name == "Water.Counter"){ $scope.WaterCumul = message.Value.Counter; } if(message.Name == "Water.Flow") { $scope.LiterPerHour = Math.round(message.Value.LiterPerHour * 100) / 100; $scope.LiterDelta = message.Value.LiterDelta; } }); |
Ne reste plus qu’à faire un bon template HTML. J’utilise une directive angular pour afficher des gauges JustGage :
1 2 3 4 5 6 7 8 9 10 11 12 | <table> <tr> <td><just-gage id="gage1" value="baieReseauWatts" min=0 max=250 title="Baie Réseau"></just-gage></td> <td><just-gage id="gage2" value="hcWatts" min=0 max=500 title="Home Cinema"></just-gage></td> <td><just-gage id="gage6" value="light" min=0 max=20000 title="Light"></just-gage></td> </tr> <tr> <td><just-gage id="gage3" value="WattPerHour" min=0 max=6000 title="Electricity (W/h)"></just-gage></td> <td><just-gage id="gage4" value="m3PerHour" min=0 max=6 title="Gas (m3/h)"></just-gage></td> <td><just-gage id="gage5" value="LiterPerHour" min=0 max=2000 title="Water (L/h)"></just-gage></td> </tr> </table> |
J’utilise aussi dans mon template HTML le plugin jQuery Counter pour afficher les variables “Cumul”, la valeur des compteurs.
Et avec ces quelques lignes d’HTML, un peu de JS, le framework AngularJS et surtout l’API Constellation, j’obtiens très rapidement une interface HTML5 temps réel et responsive qui affiche ma consommation instantanée et cumulée de mes compteurs d’eau, de gaz et d’électricité :
Vous remarquerez d’ailleurs que j’affiche également les informations de consommation de ma baie réseau et du home cinéma qui sont en fait issues du package Vera (interface Z-Wave dans la Constellation) qui push des StateObjects pour mes prises Z-Wave AN158 d’Everspring ! L’une des forces de la Constellation : tout est fédéré et interconnecté !
Reporting avec Windows Azure et Excel
Une fois notre interface Web temps réel réalisé, il me faut du reporting de mes consommations énergétiques.
Le principe est exactement le même que celui mis en place pour le reporting de mon système d’alarme que vous avez découvert dans mon article : l’alarme du geek connectée au poignet et dans les nuages.
On utilisera le même package Constellation, le “Could Conector” :
Ce package s’abonne aux mises à jour des StateObjects et dès que la valeur change, il l’enregistre dans une table Windows Azure Table :
La suite vous la connaissez déjà : je charge les données de ma table Azure dans Excel avec PowerQuery !
Une fois mes données prétraitées, j’utilise un “data model” PowerPivot dans lequel je calcule le différentiel entre chaque ligne pour connaitre la consommation en utilisant des formules DAX.
J’ajoute également des colonnes pour calculer le cout de chaque énergie :
Maintenant je peux créer des “Pivot Tables” dans ma feuille Excel et sélectionner le reporting que je souhaite :
Et bien sûr générer un tas de graphique
La puissance d’Excel et de Power Pivot me permet de faire des analyses très poussées.
Détection des fuites
Un dashboard temps réel ou une solution de reporting c’est bien mais ce qui est mieux c’est quand le système est proactif et est capable de détecter des situations nécessitant votre attention ! En gros un système d’alerting !
Déjà présenté dans mon article sur mon système d’alarme, le package MyBrain est un package Constellation écrit en C# qui contient toute l’intelligence de la maison.
Grace à l’API .NET Constellation il suffit de poser l’attribut “StateObjectLink” sur une propriété .NET pour la binder à un StateObject de la Constellation en temps réel.
Dans MyBrain, j’ai donc écrit une classe avec 4 propriétés bindées aux StateObjects de SEnergy pour l’electricité, le gaz et l’eau (compteur et débit) :
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class SEnergy { [StateObjectLink("SEnergy", "Gas")] public StateObjectNotifier Gas { get; set; } [StateObjectLink("SEnergy", "Electricity")] public StateObjectNotifier Electricity { get; set; } [StateObjectLink("SEnergy", "Water.Counter")] public StateObjectNotifier Water { get; set; } [StateObjectLink("SEnergy", "Water.Flow")] public StateObjectNotifier WaterFlow { get; set; } |
Il suffit donc d’enregistrer le compteur d’eau lorsque j’active l’alarme puis de surveiller si le compteur change ou pas ! Si oui, j’envoie une notification sur mon GSM.
Comme l’alarme est également connectée dans la Constellation et que son StateObject est bindée dans ma classe (avec la encore un StateObjectLink), il n’y a plus qu’à s’abonner au changement d’état. Pour envoyer un push j’utilise le service “PushBullet” qui est lui aussi un package dans ma Constellation !
Le système de détection est donc implémenté en 2 lignes de C# :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int waterCounterWhenArmed = 0; this.AreaStatus.ValueChanged += (s, e) => { if (e.NewState.DynamicValue.IsFullArmed) { waterCounterWhenArmed = (int)this.Water.DynamicValue.Counter; } }; this.Water.ValueChanged += (s, e) => { // Compteur différent de plus d'un litre (10 décilitres) avec l'alarme full-armed = pas normal !! if (this.AreaStatus.DynamicValue.IsFullArmed && waterCounterWhenArmed < (int)e.NewState.DynamicValue.Counter && ((int)e.NewState.DynamicValue.Counter - waterCounterWhenArmed > 10)) { this.SendMessage("PushBullet").SendPush(new { Title = "Water", Message = "Consommation d'eau alors que la maison est sous alarme complète ! Fuite ?" }); } }; |
Rien ne m’échappe à présent (même pas une machine à laver lancée pendant notre absence )
Relevé par SMS
Parce qu’une fois dans la Constellation c’est tellement simple de tout interconnecter qu’on est tenté d’ajouter un tas de lien plus ou moins gadget
Sur un autre Raspberry j’ai branché un modem GSM avec une carte SIM. Dessus je fais tourner un package Constellation nommé “GSM” qui est ni plus ni moins qu’un package Python qui exploite la librairie “Gammu” pour exposer le GSM dans la Constellation :
Ainsi dès qu’un SMS est reçu, le package transfert le SMS dans la Constellation et inversement, n’importe qui connecté dans ma Constellation peut envoyer un SMS via ce package !
En .NET il suffit de marquer une méthode avec l’attribut “MessageCallback” pour l’exposer dans la Constellation. Lorsque le package GSM reçoit un SMS, il envoi le contenu du SMS dans la Constellation dans un message “IncomingSMS”.
Comme le Package “MyBrain” a enregistré un MessageCallback “IncomingSMS”, il reçoit donc les SMS ! Si le contenu du SMS est “energie” il répond un message au package GSM pour envoyer un SMS au même numéro en indiquant la valeur des différents compteurs.
Merci Constellation !
1 2 3 4 5 6 7 8 9 10 11 12 13 | [MessageCallback(Key = "IncomingSMS")] private void ReceiveIncomingSMS(string number, string text) { if (text.ToLower() == "energie" || text.ToLower() == "energy") { this.SendMessage("GSM").SendSMS(new { Number = number, Text = string.Format("Gaz: {0}dm3 - Electricity: {1}W - Water: {2}L", (int)this.Gas.DynamicValue.Cumul, (int)this.Electricity.DynamicValue.Cumul, ((double)this.Water.DynamicValue.Counter / 10)) }); } } |
Dans la vrai vie, j’ai des méthodes me simplifiant le code avec un contrôle de l’émetteur pour ne pas répondre au SMS de n’importe qui
Vers une douche plus économique : quand votre salle bain vous parles !
Je pense que vous commencez à bien comprendre tout ce qu’apporte la Constellation !
Encore un autre package qui tourne dans la Constellation : S-Sound, un système de diffusion audio multi-room !
Un article très complet sur SSound paraitra prochainement, mais ce qu’il faut retenir pour l’heure c’est que ce package tourne dans plusieurs pièces de la maison, dans le salon, la cuisine, la chambre ou encore la salle de bain.
Il me permet de diffuser tout type de média : fichier audio, streaming MP3 (web radio & co), entrée audio (line ou chromecast), etc… Mais aussi de la synthèse vocale (TTS).
Comme c’est un package Constellation, tout peut être contrôlé depuis une application Web et surtout chaque package de la Constellation peut envoyer des messages aux différents S-Sound de la maison !
Dans mon article sur mon système d’alarme, je vous avais déjà montré comment la maison vous dit bonjour dès qu’on rentre, en utilisant SSound comme interface vocale.
Ici notre package “MyBrain” va utiliser le package SSound de la salle de bain pour parler en fonction de notre consommation d’eau !
Le code est très simple :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | double cumul = 0; var lastValue = DateTime.MinValue; int avertissement = 0; double cumulSpoke = 0; this.WaterFlow.ValueChanged += (s, e) => { // 2 valeurs à 0 + cumul > à 30 litres, douche finie ! if ((int)e.NewState.DynamicValue.LiterDelta == 0 && cumul >= 30 && cumulSpoke != cumul) { cumulSpoke = cumul; this.SendMessage("SSound-SalleDeBain").Speech("Vous avez consommé " + cumulSpoke.ToString() + " litres"); } // Surveillance de la douche if ((int)e.NewState.DynamicValue.LiterDelta > 0) { if (DateTime.Now.Subtract(lastValue).TotalMinutes >= 3) { cumul = 0; avertissement = 0; } lastValue = DateTime.Now; cumul += (double)e.NewState.DynamicValue.LiterDelta; } }; |
A chaque modification du StateObject du débit de l’eau (Water.Flow) pushé par le Raspberry S-Energy, on incrémente la variable “cumul” pour avoir le nombre litre cumulé consommé (cette variable est remise à 0 au bout de 3 minutes sans consommation).
Si on a consommé plus de 30 litres sans interruption (= cas d’une douche ou bain) et que le delta entre deux mesures (= deux photos) est de 0 on considère qu’on a fini sa douche ! On envoi alors un message au S-Sound de la Salle de Bain pour indiquer combien de litres on vient de consommer !
En sortant de votre douche, vous entendez un “Vous avez consommé 45 litres” !
On prend conscience de notre consommation et on essaye maintenant de trouver des stratégies pour changer nos habitudes afin de consommer moins !
LA procédure de sortie de douche (pour ceux qui abusent !!)
Avoir son “score” à la fin d’une douche c’est bien, mais le suivre en direct c’est mieux ! Car il y a des jours où on ne fait pas forcement attention au temps que l’on passe sous la douche.
De ce fait, la salle de bain vous parle tout au long de votre douche pour vous indiquer les “seuils” que vous dépassez !
A la maison, on a défini un 1er seuil à 60 litres, puis à 80, 90 et enfin à 100 litres :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | if (avertissement == 0 && cumul >= 60) { avertissement++; this.SendMessage("SSound-SalleDeBain").Speech("Vous dépassez les 60 litres"); } if (avertissement == 1 && cumul >= 80) { avertissement++; this.SendMessage("SSound-SalleDeBain").Speech("Attention, vous dépassez 80 litres"); } else if (avertissement == 2 && cumul >= 90) { avertissement++; this.SendMessage("SSound-SalleDeBain").Speech("Ceci est le dernier avertissement, 90 litres d’eau consommés"); } else if (avertissement == 3 && cumul >= 100) { avertissement++; this.SendMessage("SSound-SalleDeBain").Speech("Déclenchement du plan de sortie de l’eau, veuillez couper l’eau pour annuler !"); // Suite du code ci-dessous ... ! } |
En général lorsque l’on prend sa douche et qu’on entend notre salle de bain nous informer que l’on dépasse les 60 litres on termine très rapidement !
Mais il y a le cas où l’utilisateur ne souhaite pas sortir Alors la maison engage “son plan de sortie de douche”.
Le code tient en deux lignes :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Faire dans 5 sec (le temps d’entendre le message vocale de démarrage du plan de sortie de douche)... this.DoAsync(() => { // Eteindre lumière SdB this.SendMessage("Vera").SetSwitchState(new { DeviceID = (int)this.EclairagesSalleDeBain.DynamicValue.Id, State = false }); // Démarrer playlist dans la SdB this.SendMessage("SSound-SalleDeBain").PlayPlaylist(PackageHost.GetSettingValue("MusicNetworkShare") + "HorribleMusic.m3u"); }, delayBeforeAction: 5000); // Faire lorsque LiterDelta = 0 this.DoAsync(() => { // Rallumer lumière SdB si pas de lumière du jour if (!this.SunInfo.IsDayLight) { this.SendMessage("Vera").SetSwitchState(new { DeviceID = (int)this.EclairagesSalleDeBain.DynamicValue.Id, State = true }); } // Couper SSound dans la SdB this.SendMessage("SSound-SalleDeBain").Stop(); }, waitUntil: () => (int)this.WaterFlow.DynamicValue.LiterDelta == 0); |
Comme tout est connecté dans la Constellation, y compris ma Vera Lite (passerelle domotique Z-Wave pour le contrôle des luminaires, volets, etc…), le plan de sortie de douche c’est :
- Ferme la lumière dans la salle de bain (en envoyant un message à la Vera)
- Démarre une musique “horrible” via S-Sound
- Si le nombre de litre consommé revient à 0 (arrêt de la douche), on rallume la lumière et surtout on éteint la musique
Pour la démo, avancez à 9’15 :
(ps: merci à Framboise314 pour cette vidéo raccourcie)
Je vous assure que se retrouver dans le noir complet sous la douche avec une telle musique, nous ne tenez pas plus de 10 secondes
Conclusion
S-Energy fonctionne maintenant depuis plusieurs mois en continue. Les techniques d’acquisition des différents compteurs m’ont permis de répondre à ma 1ère contrainte qui était de pouvoir les lire sans changer de compteurs et avec très grande précision.
L’intégration dans la Constellation permet d’envisager des interactions avec d’autres devices/programmes de la maison très facilement et de réaliser des interfaces de contrôle & dashboard de visualisation temps réel en quelques lignes de code.
Aujourd’hui je peux donc surveiller tout çà en temps réel depuis n’importe quel device, faire des rapports de consommation très précis mais surtout, au quotidien, nous sommes constamment sensibilisé quand nous consommons trop d’eau dans la salle de bain ! Après quelques mois d’utilisation, nous avons réellement changé nos habitudes pour consommer moins (comme réduire le débit d’eau par exemple). Un gain mesuré de 20 à 50% d’eau pour chaque douche !
Une fuite comme nous avons connu au mois de Septembre ne pourrait plus se produire; je serai automatiquement harcelé de notifications sur mon téléphone et dans la journée nous aurons déjà appelé un plombier en urgence et éviter ainsi plusieurs centaines de m3 gaspillés.
Pour finir, côté cout, le plus cher reste le Raspberry Pi (30€) et la camera (25 €). Pour le reste, le module de compteur d’impulsion pour le gaz (15€ sur eBay), un Arduino Pro Mini (version chinoise à 2,5€), deux modules nRF24 (5€ les deux), l’opto-interrupteur (4€), boitier étanche (18€), alimentation 5V (10 €) et moins de 3 euros pour les différents composants électronique. Bref un peu plus de 100€ au total pour une solution de monitoring temps réel pour l’eau, l’électricité et le gaz.
Note : la plateforme Constellation sera très prochainement ouverte en open-source. Pour les early adopters qui souhaitent tester cette technologie en beta, n’hésitez pas à me contacter
Plessis Marc
Tout d’abord félicitations !!!! Quel travail de fou il vous a surement fallu produire pour écrire une plateforme d’agrégation et d’interconnexion de tous ces modules, et le tout en produisant le tooling Visual Studio qui va avec, bravo !!! Vivement la disponibilité de cette plateforme, je suis tout à la fois curieux et impatient de voir l’architecture qu’il y derrière et pouvoir « jouer » avec ce cerveau de maison.
hydro
Vraiment impressionnant, j’aime l’idée d’un « cerveau » qui contrôle chaque module.
Ton system multi room audio permet de synchroniser plusieurs zones ?
thierry perrier
Un grand bravo pour tout ce travail . Impressionnant. quel boulot extraordinaire
PIERRE
Chapeau l’artiste…
Christian Hougardy
Seb, suis pas sur d’avoir tout compris (ça t’aurait étonné aussi 🙂 ) mais c’est génial comme truc. Toujours aussi génial tu es !!! Take care.
François
Bonjour,
bravo pour l’article, comme d’habitude c’est super intéressant ! Une petite question, pour le compteur d’impulsion, tu ne précises pas comment tu l’as connecté à ton système pour en déduire la consommation de gaz ?
Il me tarde de voir Constellation !
Sebastien
Merci pour vos commentaires !
@hydro : oui et non 🙂 Chaque S-Sound est indépendant des uns des autres bien qu’on puisse lancer un seul ordre pour toutes les instances (by Constellation). Typiquement on peut lancer le même son dans toutes les pièces mais il peut y avoir un léger décalage (un peu moins d’une seconde).
Après chez moi, les enceintes de la cuisine & SdB sont connectées sur le même serveur sur lequel deux instances SSound tournent. Et là tu as la synchronisation entre les deux !
Donc pour résumer, si tes SSound des différentes pièces sont reliées sur le même serveur physique c’est parfaitement synchro, sinon si chaque pièce à son propre système tu peux tout contrôler depuis Constellation mais avec un léger décalage !
@ Francois : le module compteur d’impulsion est connecté en « pull-up »sur le RPi ! Sur le module tu as un bornier pour 2 fils afin de faire l’impulsion (en gros c’est un interrupteur qui se ferme lors d’une impulsion). Les deux fils arrivent au RPi à travers un câble RJ45 blindé (pour éviter les perturbations). L’un des fils est connecté à la masse (GND) du RPi et l’autre sur une GPIO en entrée (chez moi j’ai pris la GPIO18). Pour filtrer le signal de potentielles perturbations extérieures tu peux rajouter un condensateur 1uF entre ta GPIO et la masse au niveau du RPi.
Bien à vous
François
Merci pour la précision Sébastien ! malheureusement sur mon RPI la GPIO est utilisé par le RaZBerry, il va falloir que je trouve une autre solution !
Sebastien
SI j’en crois les specs, le RaZBerry prend les 5 premières pin (des deux côtés). Tu as donc toute la partie inférieure disponible. Tu peux donc utiliser n’importe quel IO pour connecter un entrée en pullup : http://raspi.tv/wp-content/uploads/2014/07/Raspberry-Pi-GPIO-pinouts.png
François
Pas con, je m’en souvenais plus vu qu’il est fermé dans un boitier. Une doc sur comment traiter les données reçues sur GPIO par la suite ? Je n’ai jamais fait ça !
Trackback: Resource monitoring solution | Hackaday
Trackback: Resource monitoring solution - zeax blog (ze-ax.com)
Trackback: Resource monitoring solution | Hack The Planet
carfnann
bravo!
j’étais mort de rire pour l’opération sortie de douche mais ca me donne une bonne idée!
Dodutils
« Chaque tour équivaut à 4 Watts/heures consommés. » attention cela dépend des compteurs, mais la valeur est indiquée dessus le mien par exemple fait 1.6Wh/tr
Dodutils
Dommage que se soit sur le chauffe eau car le Décret n° 2012-1078 du 24 septembre 2012 relatif à la facturation en cas de fuites sur les canalisations d’eau potable après compteur qui protège en partie des grosses factures ne fonctionne pas si l’augmentation de volume d’eau consommée est due à des fuites sur les appareils ménagers et les équipements sanitaires ou de chauffage.
Sebastien
Bonjour Dodutils,
Oui tu as raison de le préciser, cela dépend bien sûr du calibrage différent sur chaque compteur.
Cette indication est gravée sur le compteur. Dans mon cas, C = 4Wh/tour.
Cette constante est configurée au niveau du script Python qui push le StateObject de l’électricité dans la Constellation. Car au niveau de l’Arduino il n’y a pas besoin de cette information (l’Arduino sur le compteur n’a que pour seule mission que de compter le nombre de révolution et le temps mis !).
Bien sûr nous avons engagé une médiation avec la compagnie de eaux mais comme tu le dis les « accessoires » (comprenez chauffe eau / chaudière, etc…) ne sont pas couverts ! Dans mon cas il s’agit d’un accessoire d’un accessoire (la vanne de sécurité d’une chaudière). Bref c’est pas gagné !
Dodutils
Par curiosité ils veulent te facturer combien ?
Quid du taux d’erreur de ce type de lecture optique quand la roue tourne vite ? il lui arrive de rater des tours ?
J’ai aussi une citerne de gaz pour le chauffage et eau chaude sanitaire, mais c’est un manomètre et il est difficile de faire une lecture précise et automatisée via une prise de photo, déjà qu’à l’oeil nu c’est pas simple 😉
Il existe des compteur à chiffres ou numérique mais ça doit coûter cher.
Voici un bel exemple de révision de chaudière ratée par le gars de l’entretien heureusement que je regarde mes courbes régulièrement !
http://i.imgur.com/vlBFPUr.png
Le technicien avait commis une erreur en réglant la puissance chaudière à seulement 50%, par grand froid la chaudière aurait tourné non-stop… bonjour la conso !
p.s : dommage qu’on ne puisse pas s’abonner aux commentaires du billet ça oblige à venir relire régulièrement voir ce qui s’y passe.
Dodutils
Par contre plutôt que d’utiliser une RaspiCam et d’y adjoindre des LED et faire un montage (ce qui au final coûte du temps et de l’argent) j’utilise une simple caméra Hercules USB à 20€ avec des LED autour qui a un objectif réglable ce qui permet d’avoir une image nette de très prêt ou de plus loin.
Je m’en suis d’ailleurs servi pour suivre la vie d’un nid de guêpes 😉
http://i.imgur.com/9kIbV8j.jpg.
Sebastien
Oui il y a toujours plein de moyen de faire les choses 😉
La RaspiCam ne coûte que 25€ et dans mon cas elle m’a été offerte par Farnell l’an passé ce qui explique ce choix !
Mais en effet une simple webcam USB aurait pu aussi faire l’affaire ! Je ne connaissais pas ce modèle avec LED intégré, c’est tjs bon à savoir 😉
Pour le petit circuit j’en avais dans tous les cas besoin pour le module nRF ! Ca n’a pas été très long d’adjoindre un transistor + résistance pour piloter des leds 🙂
Autrement pour le compteur d’elec, même quand le disque tourne très vite il n’y a aucun tour « loupé » ! Au max j’ai enregistré une conso d’un peu plus de 6000W soit une rotation en moins de 2,4 secondes, aucun problème de détection !
Pour vérifier çà, après plusieurs mois d’utilisation d’S-Energy, j’ai comparé le compteur EDF avec celui d’S-Energy… Bon la précision n’est qu’au kW sur le compteur EDF mais l’information était la même ! Donc visiblement on ne loupe « aucun » tour ou très peu car il n’y a aucune décalage (en 6 mois de monitoring).
MARC
Bonjour,
Je suis intéressé pour testé en version bêta la plateforme Constellation. Merci de m’informer comment faire.
marc, @Belgique
Olivier
Hello,
Impressionnant Oo
Le coup de la caméra et de la lecture optique correspond tout à fait à l’adage : « Parce que si on ne se compliquait pas un peu la vie, ce serait beaucoup moins drôle ! » 😀
Pour la suivi conso EDF y a ça : http://www.magdiblog.fr/gpio/teleinfo-edf-suivi-conso-de-votre-compteur-electrique/ ! Parce que si on ne se compliquait pas un peu la vie, ce serait beaucoup moins drôle !
Bonne continuation 🙂
Sebastien
Salut Olivier,
Merci pour ton commentaire mais je crois que tu as loupé une partie 😉
Comme je l’explique dans le 1er paragraphe de cet article mes compteurs sont trop vieux et n’ont aucune interface pour faire des auto-relevés !
Pas d’impulsion ni de téléinfo sur mon compteur EDF, ce qui explique la mise en place d’un opto-interrupteur pour capter les tours du compteur EDF via un Arduino ! La solution que tu proposes utilise la téléinformation EDF que je n’ai pas, donc pas envisageable pour moi 🙂
Idem pour le compteur d’eau, je ne suis pas (complètement) fou, même si c’est amusant de faire de l’OCR, je m’en serais bien passé 😉 Mais je n’ai pas eu le choix : pas d’impulsion ou autre « indice » sur mon compteur me permettant de capturer l’eau consommée !
De ce fait, la seule solution fut de « lire » (littéralement) le compteur, donc de faire de l’OCR !
Ainsi ce n’est donc pas pour se compliquer la vie mais plutôt parce qu’à m’a connaissance je n’avais pas d’autre solution (autre que remplacer mes compteurs eau & EDF, ce qui est très coûteux !).
Cependant, si il n’y avait pas eu autant de contrainte ça aurait été moins drôle 🙂
Bien à toi,
Doudy
Impressionnant…
Chez moi (en Belgique) mon compteur électrique tourne dans les deux sens.
Lorsque je produit avec mes panneaux photovoltaïques plus que je ne consomme le disque tourne dans l’autre sens (donc il décompte).
Une idée pour la lecture avec l’ opto-interrupteur?
Merci
Yves Accard
Bonjour
Bravo pour cette réalisation et surtout pour les idées originales permettant de « lire » un compteur sans intervention sur la partie hydraulique.
De mon coté, j’ai un projet « open source » (hard et soft) dans le domaine GTC/domotique dont une partie ressemble beaucoup à ce que tu a fais.
Une des différences est qu’il s’agira de faire des produits « professionnels » c’est à dire avec un boîtier, un notice, une garantie, un service après vente et le plus possible « plug and play
Lien vers une version plus détaillée de ce texte :
http://speranto.accard.fr/texte-linux.php
Lien vers le site speranto.fr :
http://speranto.fr
Tout le monde est bienvenu pour participer à Speranto.
Yves Accard
Olivier
Salut Sebastien,
Tout à fait, j’ai bien compris la nécessité d’utiliser un opto-interrupteur, c’était une boutade 🙂 Et comme tu le dis « si il n’y avait pas eu autant de contrainte ça aurait été moins drôle » 🙂
Excellent boulot en tout cas 🙂
Bonne continuation
FredThx
Merci beaucoup pour les explications précises. Pour ma part, je m’en suis inspiré pour réaliser la lecture de mon compteur électrique (à roue comme le tien). J’ai directement mis le Rpi sur le coup et ça fonctionne très bien. Par contre je me pose la question pour différencier les heures creuses et heures pleines. La solution de lire l’heure ne me plait pas trop (changement d’heure, de tarification …). As tu une solution pour lire directement le relais EDF?
Trackback: MakerFaire Paris 2015 : retrouvez-moi en conférence le 2 & 3 Mai 2015 - Sebastien.warin.fr
Dodutils
Tu connais le module ESP8266 ? c’est une petite merveille programmable en LUA (mais l’IDE Arduino sait aussi travailler avec lu) intégrant des GPIO et le WiFi, le tout dans un module de 2.5 x 1.4cm pour moins de 4€ !
Je pense que je vais tenter le coup avec ça pour le compteur EDF.
Sebastien
Excellent merci Dodutils !
Je cherchais justement depuis plusieurs semaines un module Wifi pour Arduino assez petit !
Je viens d’en commander 5 sur eBay !
Dodutils
Parfait 🙂 question pourquoi un LM1137 et pas un LM317 pour reguler le 5v en 3.3v ? pour info l’ESP8266 peut demander des pics à 300mA.
Sebastien
Hello, petite correction de ma part sur l’article ! Ça m’a fait tilte en lisant ton commentaire, je n’utilise pas des LM1137 (qui n’existe pas ;)) mais des LM1117 ! LM1117T pour être précis !
Le LM317 a une tension de sortie ajustable entre 1,25V et 37V mais il faut piloter ce réglage via la patte d’ajustement via des diodes zener !
A l’inverse du LM1117T lui à une tension de sortie fixe en 3.3V à partir d’une entrée 5V.
Il était donc plus simple d’utiliser directement un LM1117 étant donné que mon Arduino est alimenté en 5V et que j’ai juste besoin d’un 3.3V régulé pour la puce nRF24.
Sur la charge, le LM1117 délivre jusqu’à 800mA bien au delà des 115mA max du nRF24L01+ !
Si le l’ESP8266 demande jusqu’à 300mA le LM1117T fera donc parfaitement l’affaire 🙂
Dodutils
OK ça explique pourquoi je ne trouvais aucune info sur ce régulateur du coup je ne savais pas trop ce qu’il faisait 😉
Sebastien
Hello Dodutils,
J’ai reçu et commencé à jouer avec les ESP8266 ! Absolument super comme puce, plein de nouveau projets en tête que je ne manquerai pas de présenter ici !
De ce fait, on pourrait en effet revoir le module de comptage d’elec sans Arduino ni RPi comme passerelle !
Car l’ESP peut être une passerelle Wifi pour Arduino ou directement programmée (Lua, C ou Arduino) !
Ceci dit, l’ESP-01 n’offre que 2 GPIO ce qui est assez limité ! Il existe plus d’une 10aine de modèles, voir : http://l0l.org.uk/2014/12/esp8266-modules-hardware-guide-gotta-catch-em-all/
Aussi, pour refaire une version de mon compteur d’elec, il faut prendre l’ESP-07 ou 12 qui disposent tout deux d’un ADC pour les signaux analogiques (je rappelle que l’opto-interrupteur utilisé pour compteur les tours est analogique).
Bref que du bonheur et encore merci de l’info 🙂
Hervé
Bonjour, bravo pour ce projet très intéressant. J’ai expérimenté à mon tour la lecture du disque de mon compteur EDF, mais l’opto interrupteur ne détecte pas les alternances de la bande noire. J’ai rigoureusement les mêmes composants que les votres. Des conseils pour la mise au point ? Merci. Hervé
Sebastien
Bonjour Hervé,
Il faudrait voir en premier lieu si la lecture de l’opto -interrupteur fonctionne bien, typiquement si ton analogRead() renvoi bien une mesure « correcte » !
Testes ensuite de passer devant un objet métallique ou un miroir pour voir si ton algo fonctionne bien !
Si tout est fonctionnel à ce stade, il faudra chercher du côté de l’installation sur ton compteur, il faut aligner très précisément le rayon IR devant le disque qui ne fait qu’un millimètre d’épaisseur ! La tache la plus compliquée du projet 😉
Bon courage
Schoubi
Bonjour,
Superbe article qui m’a motivé à fond pour domotiser ma maison …
Je suis dans le même cas qu’hervé, je n’arrive pas à reproduire la technique de lecture du compteur par opto-interrupteur.
Quelle est la référence précis de votre opto-interrupteur ? Le mien est de récupération et j’ai l’impression que le faisceau infrarouge est trop ‘fin’ et pas assez puissant pour que j’arrive à l’aligner sur le disque et/ou que le faisceau retourne sur le récepteur…
Merci d’avance,
Sebastien
Il s’agit d’un H21B1 offrant de meilleur résultat qu’un classique CNY70 : « The H21B1, H21B2 and H21B3 consist of a gallium arsenide infrared emitting diode coupled with a silicon photodarlington in a plastic housing. The packaging system is designed to optimize the mechanical resolution, coupling efficiency, ambient light rejection, cost and reliability. The gap in the housing provides a means of interrupting the signal with an opaque material, switching the output from an “ON” to an “OFF” state. » : http://pdf.datasheetcatalog.com/datasheet/fairchild/H21B1.pdf
Trackback: S-Panel : une interface domotique et IoT multi-plateforme avec Cordova, AngularJS et Constellation–ou comment créer son dashboard domotique mural - Sebastien.warin.fr
emmanuel
Bonjour Sébastien,
mon compteur de gaz est comme ton compteur d’eau… y-a-t-il un moyen d’extraire ton code de reconnaissance de caractère pour le faire fonctionner sans constellation ?
En te remerciant par avance,
Emmanuel (epierre)
doudy
Bonjour Sébastien,
Je suis comme emmanuel intéressé par ton code sans constellation.
Merci.
Doudy
Witty
A] J’ai l’impression que l’image montrant les soudures est une photo avant la fin des soudures, ( https://sebastien.warin.fr/wp-content/uploads/2015/02/P1160070.jpg )
en effet, il semble manquer plusieurs points de soudures!
Serait-ce possible d’ajouter un dessin des soudures a faire de l’autre coté de la plaque ?
B] On ne voit pas non plus a quoi correspond les pins qui doivent etre reliés au FTDI USB !
C] Est il prévu une mise a jour utilisant le ESP8266 ???
Cordialement.
Sebastien
Hello,
@emmanuel & doudy : le code peut fonctionner sans Constellation si vous remplacez les WriteInfo par des simples « print » et les PushStateObject par ce que vous voulez faire du resultat 🙂
@Witty : A) pas de soudure sur la face « avant », tout est sur l’image, ni plus ni moins 🙂 Il y a un schéma sur l’article pour résume tout çà ! B) le FTDI te sert à programmer ton Arduino (Vcc, Gnd, Rx et Tx), ca dépends de ton modèle d’arduino ! C) je posterai des articles sur les ESP8266 et nottament la connexion avec COnstellaiton, mais je ne vais pas « porter » S-Energy sur ESP : 1- je n’en ai pas d’intérêt puisque cette solution marche terriblement bien depuis des moins, 2 – les ESP ne sont vraiment pas fiable sur le long terme ! Cependant pour le faire il faudrait un ESP8266 07 ou 12 avec un port ADC pour pouvoir exploiter le signal analogique de l’opto-interrupteur ! C’est pas très compliqué à faire en Lua via NodeMCU… J’ai un article à poster dans ce sens avec un capteur de luminosité prochainement 🙂
doudy
Merci pour les infos
Dodutils
Tu as essayé de remplacer ta puce GSM par un module compatible SigFox genre TD1208 ?
Dodutils
C’est quoi le problème de fiabilité des ESP ? ils plantent ? ils tombent en panne ?
Sebastien
Hello,
Non pas testé SigFox… J’ai un package Constellation qui tourne sur un RPi et exploite l’API Gammu via une carte USB/3G qui me sert de passerelle SMS. De la même manière un package Luync pour la passerelle vers le réseau RTC/Voix.
Mon prochain article sera consacré aux ESP qu’on découvrira en long et en large… NodeMCU n’est pas stable dès qu’on fait quelque chose d’un peu plus complexe que l’acquisition d’un capteur pour générer une requête HTTP !
Par contre en développement en C++ sur le SDK natif ou en Arduino ca marche du tonnerre ! Le SDK Constellation est compatible avec, et de ce fait on peut faire des trucs de folie car dès lors, la petite puce ESP à accès à tout ce qui se trouve dans la Constellation comme contrôler un Nest, l’alarme, les XBMC, la domotique Z-Wave, etc.. Et bien sûr, vice-versa, exploiter les données produites des ESP dans vos pages Web, programme Windows & Linux, le tout en 2 lignes de code 🙂
Sebastien
Et en parlant d’ESP8266, je viens juste de finir de porter ce soir/cette nuit, la lib Arduino-IRRemote sur l’ESP8266 en prenant notamment en charge la partie réception & décodage des signaux IR ce qui n’était pas une mince affaire sans l’ISR des Arduinos. Je publie çà sur mon Github cette semaine et j’en reparlerai dans mon article à paraître prochainement et notamment ce qui ça ouvre comme possibilité une fois dans la Constellation 🙂
Dodutils
Attention à NodeMCU c’est pas le firmware d’origine des ESP en plus il est en retard par rapport au firmware actuel
Trackback: Créez votre “Home Analytics” : l’analyse et le reporting de votre domotique, informatique et objets connectés avec ElasticSearch, Graylog, Kibana et la plateforme Constellation - Sebastien.warin.fr
Dodutils
Bon j’ai testé le montage (sans le nRF24 pour l’instant), face à face l’opto clignote bien la LED mais côte-à-côte ça fait rien, jai même tenté de mettre un mirroir devant, pareil, j’ai essayé avec une lampe devant le récepteur, là ça marche, alors j’ai pensé que peut-être je ne donnais pas assez de jus à l’émetteur IR, du coup j’ai baissé à 47 ohms, puis 39, puis 22 toujours rien même avec un miroir en va-et-vient en face pour obtenir une meilleur réflexion, puis je suis descendu à 10 ohms et pour le coup je crois que j’ai grillé la bestiole elle n’émet plus de lumière, pas grave j’avais prévu le coup j’en ai un second.
Trackback: FERG : Mon vieux compteur EDF connecté en mode framboise - Oui Are Makers
Dodutils
APrès quelques jours de fonctionnement avec une LED IR TCRT5000 ça fonctionne pas mal, il fallait sûrement un truc plus puissant pour ma roulette par contre les valeurs hautes et basses ont un peu évolué dans la temps (ou alors le module IR a légèrement bougé du coup le reflet est un poil différent) ça ne comptait plus rien il a fallu modifier les valeurs du palier haut/bas je vais voir à modifier le code pour essayer de faire en sorte qu’il s’auto calibre.
Bientzou
Bonjour,
Ce travail est vraiment top!!
Je me demandais si tu pouvais fournir le code complet pour tester chez moi.
Merci
Marc
bonjour ,
Pour commencer je ne suis ni électronicien ni informaticien ou développeur , j’ai péniblement instaler motion et la pi cam sur mon rspberry autant dire que je maitrise pas énormément . je voudrais piloter mon chauffage avec le raspberry ..un ami ma parler des sonde 18b20 facile a utiliser avec le raspberry mais je ne trouve rien pour programmer la mise en route ou l’extinction du chauffage en fonction de seuil préétablis ni du module de puissance …l’un de vous peux il m’aider ?
Thibaut
Bonjour et bravo,
je travaille dans une collectivité et tous les systèmes de télérelève existant coûte une fortune. Soucieux d’économiser l’argent public, je me suis dit qu’il y a surement un moyen plus économe de récupérer lesindex des compteurs. En cherchant si quelqu’un avait déja utilisé une caméra et un logiciel de reconnaissance de texte je suis tombé sur votre blog. MERCI!
Pensez-vous qu’il soit possible de reproduire vos différents moyens de lecture de compteur? Quelles compétences faut-il? Je travaille sur Bordeaux, avec un peu de chance vous n’êtes pas loin et nous pourrions nous rencontrer….
En tous cas encore bravo!
MobO
Merci pour ce partage que je vais m’empresser de mettre en place chez moi. Existe-t-il un lien pour acceder à la totalité des scripts/codes utilisés ?
Cela me permettrais de gagner bcp de temps et de partir d’une base « saine et productive ».
Merci
Trackback: Fonctionnement de la fibre Orange et remplacement de la Livebox par un routeur Mikrotik sous RouterOS – Petit aperçu de mon réseau local, du GPON, de l’IGMP, Asterisk et Cacti sans oublier Constellation - Sebastien.warin.fr
py
bonjour, je galère sur la reconnaissance des chiffres du compteur d’eau. Pourriez vous donner le détail de la fonction findTemplate svp ?
Sebastien
Bonjour py,
Ma fonction est implémentée de la façon suivante :
def findTemplate(baseImage, templateImage):
res = cv2.matchTemplate(baseImage, templateImage, cv2.TM_CCOEFF_NORMED)
min_score, max_score, (min_x, min_y), (max_x, max_y) = cv2.minMaxLoc(res)
return max_x, max_y, max_score
On passe l’image de base et l’image du template et on retourne la position et le score du « meilleur match ».
Concernant le Template Matching avec Open CV, voir : http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/template_matching/template_matching.html
Trackback: S-Electricity : connecter son compteur d’électricité en Wifi dans Constellation - le remake d'S-Energy avec un ESP8266 - Sebastien.warin.fr
Trackback: Retrouvez Constellation à la DevCon #4 le 26 octobre à l’école 42 - Sebastien.warin.fr
Trackback: S-Watch : pilotez votre domotique et objets connectés depuis une montre Samsung Gear S2 ou comment développer des applications Tizen connectées à Constellation - Sebastien.warin.fr
Trackback: Dossier spécial sur la maison intelligente et Constellation dans le numéro d’été du magazine Programmez! dans vos kiosques partout en France - Sebastien.warin.fr
FONGANG
Bonjour.
Vous êtes un génie surdimensionné.
Même un peu trop. Cependant, combien de temps est-ce que cela vous a pris pour produire ce cerveau. Je suis très touché !
Fred
Bonjour Sébastien,
je tente de mettre en pratique ce superbe tuto. Je te félicite pour ce travail.
Pour le compteur élec, j’ai un Linky alors cela a été rapidement OK. Idem pour le compteur gaz avec un simple contact de porte détourné mais comme tu le dis le véritable défit est la lecture du compteur d’eau.
Sur ce point je souffre depuis quelque temps déjà. Pourrais tu m’aider à avancer en me postant l’ensemble de ton programme python car la récupération de tes bouts d’exemple ne donne pas grand chose.
Ce que j’ai réussi à faire: l’installation d’OPENCV (pénible) :OK, la prise de photo et le post traitement:OK, les photos références et la bibliothèque de chiffre je pense que c’est OK, le découpage théorique de la zone de chiffre: OK. Je marque théorique car je n’ai pas réussi à réaliser la recherche dans l’image origine des images références pour trouver en automatique la zone de chiffres.
Comme tu le vois, avant de t’écrire HELP j’ai cherché et cherché et en définitive HELP Sébastien.
Dans tes exemples il me manque, me semble t’il, cette recherche d’image avec le « template matching » que je n’arrive pas à mettre en œuvre.
Merci pour ton aide,
Fred
Fred59
Bonjour Sébastien,
J’ai implèmenté ta fonction de lecture de mon compteur d’eau suivant ton exemple.
Tout se passe bien pour les recherches, isolation des chiffre, bibliothèque réalisé, mais j’ai un taux de reconnaissance des chiffres déplorable (à peine 60% ce qui n’est pas suffisant).
En regardant les images générés, il y a un méchant reflet sur les chiffres du compteur qui perturbe la reconnaissance.
Peux tu me donner un petit coup de pousse pour régler ce problème?
Déjà tenté: LED IR: NOK, Replacer 6 LED Blanches au dessus des chiffres: NOK, 3 puis 3 LED à différents endroits pour générer des reflets différent: fait (je pense que c’est la solution…. avec le traitement adéquat).
Sur le post traitement des images j’ai tenté: un « GaussianBlur » à (5,5) avec un « Flougaussier » à (150,255) sur les 2 images prises sous 2 éclairages différent mais je n’arrive pas à supprimer le reflet.
Un sujet casse, merci de tous les conseils…
Fréd