Domotiser son compteur eau avec du Wifi

Dans ce projet, nous allons voir comment « domotiser » votre consommation d’eau. A l’aide d’un compteur (débitmètre) eau à impulsion, d’une carte électronique et du wifi, je vais vous montrer comment être prévenu de fuites d’eau ou tout simplement surveiller sa consommation.

Dans mon cas, mon compteur d’eau est relié à la sortie d’une pompe à forage. L’eau sert à alimenter le jardin, les toilettes et le lave-linge.

Note

Utilité:4 Stars (4 / 5)
Simplicité:3 Stars (3 / 5)
Coût:2 Stars (2 / 5)

Outils

Achats

img_20160918_155939

Total : ~= Moins de 95€

Bon ce n’est pas l’affaire du siècle, mais je trouve que le projet est assez intéressant et qu’il s’intègre parfaitement  dans l’esprit de la maison connectée.

L’investissement paraît important, mais si un jour vous avez une fuite d’eau (surtout les toutes petites qui ne se voient pas à l’oeil nu), vous verrez que le système est largement amorti.

Conception

La conception de la carte électronique est plutôt simple. Avec le NodeMCU en guise de coeur, vous n’avez plus qu’à vous préoccuper du fonctionnel.

Qu’est-ce que le NodeMCU ?

C’est une carte électronique à base de ESP8266 (ESP-12F) intégrant un microcontrôleur et un transceiver WIFI compatible Arduinonodemcu - esp8266

Grâce à son convertisseur USB et son régulateur intégrés, vous pourrez le brancher sur votre ordinateur dans le but de le programmer ou interagir facilement. Un simple câble USB / micro-USB vous suffit.

nodemcudevkit_v1-0_io

Voici toutes les fonctionnalités des pattes du NodeMCU. Pour approfondir toutes les fonctionnalités vous pouvez aller vous rendre le site officiel.

Attention, tous les GPIOs sont 3.3v compatibles. Ce qui signifie que vous ne devez pas « infliger » aux GPIOs une tension supérieure à 3.3v.

Compteur d’eau à impulsion

compteur eau à impulsion

Passons maintenant au compteur d’eau à impulsion. Comment les impulsions sont-elles générées ? Eh bien, c’est assez simple, regardons le schéma de fonctionnement.

schema_compteur_eau

En effet, le compteur à impulsion fonctionne comme un interrupteur. En fait, la petite aiguille rouge du compteur est aimantée et à chaque fois qu’elle va passer au dessus d’un capteur à effet hall, les deux fils (marrons et blanc) vont être connectés.

Il suffit donc d’alimenter d’un côté un fil (marron ou blanc peu importe) et de connecter l’autre à un GPIO du NodeMCU configuré en entrée.

Vu que mon alimentation délivre du 12Vdc et que le NodeMCU n’accepte que du 3.3Vdc sur les IOs, il va falloir faire un petit pont diviseur de tension. Bien entendu, je peux me permettre d’utiliser cette technique car il n’y a pas ou peu de courant sur cette liaison.

PS: le NodeMCU sera alimenté directement par l’alimentation 12Vdc car il est muni d’un régulateur de tension pouvant aller jusqu’à 15Vdc me semble-t-il.

Voici le schéma général du NodeMCU

nodemcu_devkit_sch

En fait, c’est dans ce schéma que l’on voit que tout à déjà été fait dans ce module. La gestion du RESET, ENABLE, L’alimentation, « USB to UART », le paramétrage des pattes pour le mode RUN ou FLASH…schema_compteur_eau_sans_led

Du coup, pas grand chose à faire, juste le fonctionnel (un pont diviseur de tension) pour récupérer les impulsions du compteur à eau.

Allez on est fou !!! On va rajouter une LED bleu (3.3v / 20mA) pour être averti visuellement lorsqu’une impulsion est générée.

schema_compteur_eau_avec_led

Et voilà on change les valeurs des résistances + la LED et c’est OK !

Réalisation

Il n’y a plus qu’à découper la carte à trous au format de votre boitier DIN. Ensuite, il faut souder les différents connecteurs, borniers, « pins header », les résistances, la LED et faire les trous pour la fixation au boitier.

img_20160918_155458 img_20160918_155326

Alors sur les photos, j’ai rajouté d’autres fonctionnalités (je ferai un article dédié) comme un capteur de température en 1wire (DS18B20) et un compteur monophasé (qui fonctionne différemment du compteur eau)

Software

Les outils

Une fois que la partie matérielle est réalisée, il faut maintenant passer à la partie logicielle. Et oui, vous pensiez quoi !!!. (Attention ! C’est la partie la plus complexe)

Plusieurs solutions existent pour développer avec le NodeMCU:

  • La première, la plus répandue est d’intégrer le firmware Arduino et utiliser les librairies à base de ESP8266
  • La deuxième, très répandue aussi, est de flasher le module avec un moteur LUA. J’ai choisi ce mode car je suis curieux.

Le LUA est un language script interprété (requiert un « moteur ») au même titre que du PHP, Python, Perl … mais en beaucoup moins gourmand. Cependant, dans les microcontrôleurs, on a pour habitude (pour des raisons de performance) de coder en C ou assembleur. C’est pour cette raison qu’il m’a paru très intéressant d’essayer cette méthode.

Afin de pouvoir programmer le module, plusieurs outils existent:

Je vous recommande tout d’abord le github de NodeMCU.

il faudra télécharger :

Ensuite pour outil de développement, j’ai utilisé ESPlorer qui est, ma foi, bien utile. Avec le Getting started

esplorer

Fonctionnement général

Comment rendre tout ce bordel compatible avec votre domotique ? Eh bien, grâce au Wifi. Voici le principe de fonctionnement.

fonctionnement général

Le module NodeMCU va se connecter à votre borne Wifi et monter un serveur Web, puis incrémenter un compteur à chaque impulsion du débitmètre.

Votre domotique n’a plus qu’à accéder à la page web du module pour récupérer la valeur distribuée en JSON (par exemple). La page web est bien entendu protégée par un système d’authentification basique. Une fois que la valeur est lue, il faut renvoyer « OK » pour remettre à zéro la valeur du compteur.

Le code

Une fois que vous avez tout installé, voici le programme en LUA répondant au fonctionnement général.
A chaque démarrage du module, c’est le fichier init.lua qui est appelé. (c’est obligatoire, le bootloader du NodeMCU lance cette page)

--CONFIGURATION DES IOS EN ENTREES
gpio.mode(1,gpio.INPUT)
gpio.mode(2,gpio.INPUT)
gpio.mode(5,gpio.INPUT)
gpio.mode(6,gpio.INPUT)

--PASSAGE DES IOS A L'ETAT BAS
gpio.write(1, gpio.LOW)
gpio.write(2, gpio.LOW)
gpio.write(5, gpio.LOW)
gpio.write(6, gpio.LOW)
--TABLEAU LISTAGE DES ENTREES
tabInput={1,2,5,6}
CONFIG DES ENTREES

En tout début de programme je paramètre 4 pattes en entrée à l’état bas (0). Attention, j’ai choisi ces pattes parce qu’elles n’ont pas de fonctions de config du NodeMCU comme D0 –> wake ou D4 –> qui doit être obligatoirement à 1 au démarrage. (Voir le schéma général plus haut)

En gros il faut éviter d’utiliser D0, D3, D4, D9 si vous avez besoin de garantir un état au démarrage. Je m’explique: imaginez que vous souhaitez utiliser une commande relais. Si vous le branchez sur D4, à chaque redémarrage de votre carte, le relai va s’actionner …

C’est pour cette raison que j’ai utilisé les pattes D1, D2, D5, D6.

-- INCLUSION DES FICHIERS DE CONFIG
INI = require 'inifile';
configfile = INI.load('config.ini');
protect = INI.load('auth.ini');
inputs = INI.load('inputs.ini');
CONFIG

Le fichier config.ini regroupe les infos de connexion wifi

[network]
ssid=<SSID>
pass=<PASS>
ip=<IP>
mask=<MASK>
gateway=<GW>
mode=2

Le fichier auth.ini regroupe le login/pass de la connexion web

[AUTH]
pass=admin
user=admin

Le fichier inputs.ini regroupe le paramétrage des entrées

[INPUTS]
in2=1
in1=1
in4=1
in3=1
url=10.0.100.54
page=nodemcu.php

En effet, ce n’est pas utilisé pour le projet de compteur d’eau mais j’ai développé 3 types de fonctionnalités:

  • soit comptage (0..65000)
  • soit entrée simple (1 ou 0)
  • soit évènementiel avec le lancement de l’url+page
local wifiConfigStation = {}
wifiConfigStation.mode = wifi.STATION  -- CONFIG EN MODE STATION ( PAS DE MODE AP dans ce cas)
wifiConfigStation.stationPointConfig = {}
-- ON RECUPERE LES INFOS D'AUTHENTIFICATION
wifiConfigStation.stationPointConfig.ssid = configfile.network.ssid
wifiConfigStation.stationPointConfig.pwd =  configfile.network.pass
--ON CHOISI LE MODE EN IP STATIQUE // PAS DE DHCP
local mode;
mode = configfile.network.mode
local cfgip ={};
cfgip.ip = configfile.network.ip
cfgip.netmask = configfile.network.mask
cfgip.gateway = configfile.network.gateway
wifi.sta.setip(cfgip)
wifi.sta.autoconnect(1)
-- ON SE CONNECTE
wifi.sta.config(wifiConfigStation.stationPointConfig.ssid, wifiConfigStation.stationPointConfig.pwd)
local joinCounter = 0
local joinMaxAttempts = 5
-- ON CREE UN TIMER 0 QUI SE D2CLENCHE AU BOUT DE 3 SEC ET SORTIR S'IL EST BIEN CONNECTE
tmr.alarm(0, 3000, 1, function()
   local ip = wifi.sta.getip()
   local status = wifi.sta.status()
   if status ~= 5 then
      print('Connecting to WiFi Access Point ...')
   else
		print("IP : "..ip)
      tmr.stop(0)
   end
end)
WIFI

Voilà la partie connexion Wifi. Je l’ai vachement simplifié pour ce projet mais vous pouvez vous amuser à gérer le DHCP ou STATIQUE et le mode AP (point d’accès) ou STATION (client)

valin1 = 0
valin2 = 0
valin3 = 0
valin4 = 0
eventin1=0
eventin2=0
eventin3=0
eventin4=0
temperature = -99
--PARAMETRAGE DES ENTREES SELON LES MODES
dofile("inputs.lc")
--LANCEMENT DU SERVEUR WEB
dofile("httpserver.lc")(80)
-- LANCEMENT D'UN TIMER TOUTES LES 30 SEC POUR FAIRE L'ACQUISITION D'UN CAPTEUR DE TEMPERATURE
tmr.alarm(3,30000,1,
		function ()
			wifi.sta.connect()
			dofile("temp.lua")
		end)
Fonctionnel

Voici le cœur du programme, la partie acquisition de température ne concerne pas le projet de comptage mais vous pouvez le garder de côté quand je ferai l’article sur le capteur de température (DS18B20).

A noter aussi que l’inclusion de fichier code comme dofile « inputs.lc » permet de rendre plus lisible le code. D’autres part, l’extension « lc » est du LUA compressé. Le logiciel ESPlorer permet de compresser vos fichiers LUA à la volée.

collectgarbage()
tLastcount1=0
tLastcount2=0
tLastcount3=0
tLastcount4=0
function in1Count(level)
     if  (tmr.now()<tLastcount1) or  (tmr.now()-tLastcount1 > 20000) then -- only 1x per 0.2 sec, or overflow of tmr.now
        tLastcount1=tmr.now()
		if level == 0 then 
			valin1 = valin1 +1
			
		end
    end
end
function in2Count(level)
     if  (tmr.now()<tLastcount2) or (tmr.now()-tLastcount2 > 20000) then -- only 1x per 0.2 sec, or overflow of tmr.now
        tLastcount2=tmr.now()
		if level == 0 then 
			valin2 = valin2 +1
		end
     end

end
function in3Count(level)
     if  (tmr.now()<tLastcount3) or  (tmr.now()-tLastcount3 > 20000) then -- only 1x per 0.2 sec, or overflow of tmr.now
        tLastcount3=tmr.now()
		if level == 0 then 
			valin3 = valin3 +1
			
		end
     end
end
function in4Count(level)
     if  (tmr.now()<tLastcount4) or  (tmr.now()-tLastcount4 > 20000) then -- only 1x per 0.2 sec, or overflow of tmr.now
        tLastcount4=tmr.now()
		if level == 0 then 
			valin4 = valin4 +1
		end
   end
end
if (tonumber(inputs.INPUTS.in1)==1) then 
	gpio.mode(tonumber(tabInput[1]),gpio.INT)
	gpio.trig(tonumber(tabInput[1]), "down",in1Count) 
else
	gpio.mode(tonumber(tabInput[1]),gpio.INPUT)
end
if (tonumber(inputs.INPUTS.in2)==1) then 
	gpio.mode(tonumber(tabInput[2]),gpio.INT)
	gpio.trig(tonumber(tabInput[2]), "down",in2Count) 
else
	gpio.mode(tonumber(tabInput[2]),gpio.INPUT)
end
if (tonumber(inputs.INPUTS.in3)==1) then 
	gpio.mode(tonumber(tabInput[3]),gpio.INT)
	gpio.trig(tonumber(tabInput[3]), "down",in3Count) 
else
	gpio.mode(tonumber(tabInput[3]),gpio.INPUT)
end

if (tonumber(inputs.INPUTS.in4)==1) then 
	gpio.mode(tonumber(tabInput[4]),gpio.INT)
	gpio.trig(tonumber(tabInput[4]), "down",in4Count) 
else
	gpio.mode(tonumber(tabInput[4]),gpio.INPUT)
end
GESTION DES ENTREES

En fonction du mode d’entrée (compteur ,entrée simple ou évènement), je vais gérer les entrées différemment. Pour notre cas, c’est ce code qui nous intéresse :

function in1Count(level)
     if  (tmr.now()<tLastcount1) or  (tmr.now()-tLastcount1 > 20000) then -- only 1x per 0.2 sec, or overflow of tmr.now
        tLastcount1=tmr.now()
        if level == 0 then
            valin1 = valin1 +1
            
        end
    end
end

if (tonumber(inputs.INPUTS.in1)==1) then
    gpio.mode(tonumber(tabInput[1]),gpio.INT)
    gpio.trig(tonumber(tabInput[1]), "down",in1Count)
else
    gpio.mode(tonumber(tabInput[1]),gpio.INPUT)
end
COMPTAGE

La première fonction permet d’incrémenter le comptage pour chaque impulsion. Elle permet aussi de gérer les rebonds. (Bien que le compteur d’eau fonctionnant avec un système à un effet hall, les impulsions sont normalement stables). Cependant, pour régler une éventuelle instabilité (appelée rebonds) je prend en compte la première impulsion mais pas celle qui arrive dans les 20ms suivantes. (C’est utile si vous souhaitez faire des tests en court-circuitant l’entrée avec un fil)

Le code après la fonction permet de paramétrer l’entrée en fonction du fichier ini « inputs.ini »

Pour la partie serveur Web, j’ai utilisé un code déjà tout fait en LUA. vous pouvez le retrouver ici.

Il n’y a plus qu’à coder la page HTML en LUA. (vous pouvez suivre l’exemple du site)

return function (connection, args)
	 connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n")
   connection:send('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>COMPTEUR EAU WIFI</title></head>')
   connection:send('<body>')
   local input1
	local input2
	local input3
	local input4
	if (tonumber(inputs.INPUTS.in1) ==1) then
		input1 = valin1
	else
		input1 = gpio.read(tonumber(tabInput[1]))
	end
	if (tonumber(inputs.INPUTS.in2) ==1) then
		input2 = valin2
	else
		input2 = gpio.read(tonumber(tabInput[2]))
	end
	if (tonumber(inputs.INPUTS.in3) ==1) then
		input3 = valin3
	else
		input3 = gpio.read(tonumber(tabInput[3]))
	end
	if (tonumber(inputs.INPUTS.in4) ==1) then
		input4 = valin4
	else
		input4 = gpio.read(tonumber(tabInput[4]))
	end
	connection:send("{1:"..input1..",2:"..input2..",3:"..input3..",4:"..input4.."}")
   connection:send('</body></html>')
   connection:close()
	
 end
page WEB

C’est presque fini !!! Il ne vous reste plus qu’à uploader avec ESPlorer tout le code dans votre NodeMCU

Enfin ouvrez un navigateur pour tester et tapez l’URL suivante :

http:///getinput.lua

getinput

Si vous avez cette page, c’est gagné !

Vous pourrez retrouver l’ensemble du code sur mon github :

https://github.com/fairecasoimeme/Compteur_eau_wifi.

Conclusion

Enfin c’est terminé ! ce projet est assez simple en définitive mais prend pas mal de temps et vous devez maîtriser pas mal de concepts, mais c’est ça qui est bien parce que vous avez presque tout fait vous même !

img_20160918_154429

Après, vous avez plusieurs possibilités pour installer tout ça mais moi j’ai choisi de placer l’électronique dans un boitier DIN dans un tableau électrique. C’était dans mon cas la manière la plus propre pour mettre en œuvre ce projet. A vous de trouver la meilleure méthode !

Enfin, mon ressenti par rapport au langage LUA. Je trouve que le langage est assez rudimentaire mais le moteur ultra performant. L’ESP8266 ne semble pas à l’agonie mais par contre, parfois, lorsque l’on utilise trop les ressources. Exemple : rafraichir violemment les pages web servies par le NodeMCU, il plante et Redémarre. Je pense qu’il y a peut-être une gestion du Watchdog à faire. Pareillement, sur les fichiers, vous ne pouvez pas dépasser une certaine taille sans que cela crache le système. On peut tout de même contourner en compressant les fichiers (extension LC) ou en multipliant ces derniers en faisant des inclusions.

Cependant, je maintiens que c’est pour moi un mini exploit ce système et que ça permet à beaucoup de monde d’obtenir de bon résultats sans avoir de grosses connaissances dans le domaine.

Par contre, oubliez cette méthode si vous pensez faire un produit industriel.

D’ailleurs, j’ai vu qu’il existait un SDK avec visual studio ou un autre IDE dans le genre et dès que le temps me le permet, j’approfondirai cette méthode. A suivre …

Bonus : une petite vidéo pour illustrer tout le projet :

[Total : 2    Moyenne : 1/5]

Leave a Reply

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *