Suivre sa consommation EDF avec un ESP8266 (sans compteur linky)

Pour faire des économies, il est important de savoir combien d'éléctricité est consommée dans votre habitation a chaque moment de la journée. C'est d'autant plus important lorsque EDF vous propose un tarif de nuit, et que vos chauffages sont éléctriques par exemple !

Les nouveaux compteurs linky proposent ce service (dans une certaine mesure) directement via le site de votre fournisseur d'énergie. En revanche si comme moi vous avez un ancien compteur, toutes ces solutions simples et modernes ne sont pas applicables. Heureusement, les anciens compteurs nous proposent tous un indicateur: A chaque fois qu'un Wh est consommé, une LED verte sur le panneau s'allume. On peux donc déduire la consommation du logement sur un intervalle de temps en fonction du nombre de fois ou cette LED s'illumine.

L'idée consiste donc à creer un "compteur" via un ESP, qui va ensuite publier notre consommation sur le réseau wifi du logement.

Fabriquation de la sonde

Pour cette tache, nous allons utiliser un Wemos D1 Mini, couplé avec un module photoresistance pour arduino. Il va aussi nous falloir une alimentation 5V qui rentre dans la gaine technique du compteur.

IMG 20190330 183344

Le module avec la photoresistance (a droite) n'a que trois pins: 5V, GND et Signal (D0). Il permet, via un potentiomètre, de régler l'intensité lumineuse à détecter. Son pin Signal, passera à 5V lorsque l'intensité sera supérieure à celle réglée. Le pin sera à GND le reste du temps. Ce module a l'avantage de proposer un signal "propre" et réglable, chose que l'on aurai du mal à avoir avec une photoresistance seule.

Pour notre montage, on relira les +5V et GND du module au +5V et GND du Wemos. On va ensuite relier le Signal au pin D6 du Wemos (GPIO13). Enfin, on va placer les deux capteurs ensemble, soit en soudant, soit en collant, afin d'avoir une sonde compacte est facile a installer sur notre compteur électrique.

IMG 20190328 203338

Préparation de l'ESP

Pour la partie logicielle, on va utiliser NodeMCU et coder en lua. Le firmware peux être compilé grace ce site, qui propose de builder une version customisée de nodeMCU a la demande.. Si vous n'avez jamais flashé de NodeMCU, je vous conseille mon article de prise en main de NodeMCU. qui explique la marche à suivre.

Pour notre programme nous aurons besoin de:

  • cron (pour envoyer les données a intervalle régulier)
  • file (pour lire/ecrire des fichiers en mémoire flash)
  • gpio (pour relever le Signal du capteur)
  • http (pour envoyer les données)
  • mdns (pour l'intégrer a mon systeme domotique existant)
  • net
  • node
  • rtctime (pour mesurer l'heure actuelle)
  • sjson (pour envoyer les données en JSON)
  • sntp (pour se mettre a l'heure via internet)
  • uart (pour le débug)
  • wifi
  • tls (https everywhere!)

Avant de commencer a programmer, on va charger les librairies wifi.lua et ntp.lua. Ces deux fichiers apportent des fonctions simplifiées pour initialiser le wifi et le ntp (network time protocol) sur l'ESP.

Maintenant nous pouvons passer au vif du sujet, le code de notre programme!

Aprés plusieurs essais, j'ai fini par écrire le script suivant:

DEVICE_NAME="PowerMeter"
GPIO_WH_SENSOR=6

isLow = true
currentPulseCount=0

-- Start the program, setup various listeners and events
function mainInit() 
	gpio.mode(GPIO_WH_SENSOR, gpio.INPUT)
	gpio.trig(GPIO_WH_SENSOR, 'both', mainHandleOnEdge)

	tmr.create():alarm(5000, tmr.ALARM_SINGLE, function ()
		cron.schedule("* * * * *", function(e)
			mainHandleSendData()
			currentPulseCount = 0
		end)
	end)
end

-- Handle when the sensor switched to another state
function mainHandleOnEdge()
	currentValue = gpio.read(GPIO_WH_SENSOR)

	if isLow and currentValue == 1 then
		isLow = false
	elseif not isLow and currentValue == 0 then
		isLow = true
		currentPulseCount=currentPulseCount+1
	end
end

-- Handle when we have to send data remotely
function mainHandleSendData()
	print("Sending...", DEVICE_NAME, currentPulseCount)
	thingspeakPostData(currentPulseCount, mainHandleSentData)
end

function mainHandleSentData(code, data)
	print("Data sent")
end

Lors de l'initialisation, on met en place un compteur de pulse, qui va s'incrémenter à chaque fois que le capteur passe en état haut, puis en état bas. On met aussi en place un cron qui va, toutes les minutes, envoyer les données via la fonction thingspeakPostData (que je vais détailler plus tard).

C'est bien beau tout ça, mais notre code a besoin de plusieurs prérequis pour se lancer: On doit avoir un réseau wifi valide, et l'horloge interne doit être a l'heure.

On va donc programmer l'init.lua de notre ESP pour mettre tout ça en place:

-- Load custom convenience libraries
dofile("wifi.lua")
dofile("ntp.lua")
dofile("thinkspeak.lua")
dofile("main.lua")

-- Very first thing to do on init, start wifi
function init()
	print("WIFI INIT...")

	wifi_cfg={}

	-- HERE you can put you wifi credentials

	--then call
	-- wifiConfig(cfg)
	wifiConnect(handleWifiInit, handleWifiError)
end

-- Wifi initialised, let's launch NTP now
function handleWifiInit(ip)
	print("WIFI INIT: ", ip)

	print("NTP INIT...")
	ntpStart(handleNtpStart, handleNtpError)
end

-- Got an error?
function handleWifiError(err)
	print("WIFI ERROR: ", err)
end

-- NTP initialized, now we have both wifi and internal clock has a valid datetime
-- Here we start our app!
function handleNtpStart()
	print("NTP OK")
	print("APP INIT...")
	mainInit()
	print("APP INIT OK")
end

function handleNtpError(err)
	print("NTP ERROR: ", err)
end

-- Wait 5 seconds before launching init.
-- In case we mess things up, it give us 5 seconds to reupload a new code
-- This avoid locking the esp in a crashes and reboot loop directly on startup
tmr.create():alarm(5000, tmr.ALARM_SINGLE, init)

Enfin, notre ESP va charger les données vers l'api ThingsSpeak afin d'avoir des jolis graphiques. Libre à vous de changer ce code la pour envoyer les résultats autre part biensur!

POST_URL="http://api.thingspeak.com/update"
POST_API_KEY="SomeAPIKey"

-- Send data to Thingspeak
function thingspeakPostData(data, onDone)
	finalUrl = POST_URL.."?api_key="..POST_API_KEY.."&field1="..data
	http.get(finalUrl, nil, function(code, data)
		if (code < 0) then
			print("HTTP request failed")
		else
			print(code, data)
			onDone(code, data)
		end
	end)
end

Pensez à bien tester votre code avant de passer a l'étape suivante. Une fois que votre capteur sera installé dans le tableau éléctrique, il sera bien moins facile d'y apporter des évolutions.

L'installation dans le compteur

En général, la LED de consommation se situe à coté de l'afficheur, sur le compteur éléctrique. Pour simplifier j'ai simplement utilisé du scotch double face pour fixer le capteur au bon endroit. Au final mon montage ressemble à ça:

IMG 20190402 200555

Et la consommation dans thingspeak:

4cxVP2A

Il ne reste plus qu'a étudier ça dans quelques jours pour faire des économies!