Lorsque nous analysons des composants, nous prenons en compte l'effet qu'ils ont sur la consommation globale d'une machine. Pour cela nous utilisons depuis quelques mois une méthode spécifique, exploitant une prise connectée et un script Python maison.
Lorsque nous réfléchissions au contenu de notre second magazine en général, puis à son dossier domotique en particulier, nous avions imaginé le compléter par l'analyse de nombreuses prises connectées. Une série qui nous a demandé plusieurs semaines de recherche et de travail, dont nous avons commencé la publication.
Il nous a permis de prendre conscience de l'ampleur des disparités entre les différents produits disponibles sur le marché. L'intérêt des uns, l'inutilité des autres. Puis, il y avait une fonctionnalité qui revenait régulièrement : le relevé de la consommation électrique. Un sujet d'importance, dont nous vous avons aussi parlé en détail.
Il nous intéressait d'autant plus qu'il pouvait avoir une utilité pour nos propres tests en intégrant notre protocole afin de le renforcer. Comme beaucoup, nous nous sommes longtemps reposé sur des méthodes classiques comme les prises à écran intégré, qui ont de nombreuses limites. Nous n'avions ainsi pas de solution pour générer des graphiques, relever la consommation moyenne précise, l'énergie consommée même sur de courts tests, etc.
Il nous fallait donc trouver une prise connectée donnant accès à de telles données tout en nous permettant de les exploiter comme bon nous semble. Cela n'a pas été simple, mais nous avons fini par trouver notre bonheur.
Watts, Joules et compagnie
Commençons par quelques rappels et un peu de terminologie. La puissance dont on parle de manière courante est la puissance dite active et s'exprime en watts. C'est le produit d'une tension (Volt) et d'une intensité (Ampere) nécessaires à l'alimentation d'un appareil, mais aussi d'un déphasage (Cos Φ) dans le cas d'un système alternatif.
Avec un PC, cette puissance nécessaire à son fonctionnement varie sans cesse. On ne peut donc pas dire que telle ou telle machine nécessite 200 ou 300 watts et ce n'est pas une bonne valeur à relever lorsque l'on veut comparer l'efficacité énergétique de deux machines pour réaliser une tâche donnée (rendu 3D, compression, etc.). C'est tout le problème des prises à écran, qui l'affichent de manière « instantanée ».

Elles permettent néanmoins d'obtenir un autre résultat : la quantité d'énergie consommée sur une période donnée, bien plus intéressante lorsqu'il s'agit de faire des comparaisons. Car si l'on représente par une courbe l'évolution de la tension, du courant et de la puissance d'un système alternatif sinusoïdal (230 V à 50 Hz en France), relever la puissance revient à noter la valeur d'un point. L'énergie représente l'aire entre la courbe et l’axe des abscisses (voir ci-dessus).
Elle est le produit d'une puissance et d'un temps. Elle s'exprime en watt-heure (Wh) ou en Joules (J) lorsque l'unité de temps est la seconde. C'est ce que vous facture votre fournisseur d'électricité par tranches de 1 000 Wh.
Ainsi, une machine ayant consommé 3,5 kWh sur une période de 8 heures aura peut-être parfois nécessité 200 watts pour fonctionner, parfois 600 watts. Dans tous les cas, la puissance moyenne sur la période aura été de 437,5 watts. Ce sont ces valeurs que nous chercherons à relever et calculer, sur de courtes ou longues périodes.
Relever un point n'a aucun intérêt. Mais on peut calculer la consommation : environ 12 Wh en 1h30... et comparer
La prise connectée : une solution efficace et pratique
Dans l'idéal, il nous faudrait un équipement digne d'un laboratoire d'électronicien pour effectuer de tels relevés avec précision. Mais cela complexifierait alors grandement notre installation, son coût et son entretien.
Les prises à écran ne relevant la consommation d'énergie qu'avec une granularité d'1 Wh (3 600 J) sans nous fournir les résultats de manière exploitable (fichier CSV par exemple), nous avons cherché d'autres solutions. Nous nous sommes rapidement tournés vers les prises connectées afin de trouver un modèle convenant à nos besoins.
Dans un premier temps, nous avions monté une solution exploitant des prises Z-Wave/Zigbee avec un Raspberry Pi 3/4 où était installé Jeedom. Via les API de certains plugins nous pouvions effectuer des relevés de puissance puis déterminer la consommation d'énergie. Mais cette fois encore, ce n'était pas très pratique.
Car il fallait maintenir un système Jeedom à jour, avec la dépendance aux évolutions de l'OS et de ses plugins. Nous avons donc cherché des solutions sans box domotique pour simplifier encore le processus. C'est là que nous avons trouvé l'API officieuse de la prise HS110 de TP-Link et les modules communautaires pour de nombreux langages.
Notez que si vous préférez opter pour une solution similaire, mais avec une prise Wi-Fi disposant d'une API officielle, la marque Shelly propose de tels produits pour une 20/30 euros environ, comme ses Plug (S).
Détection et gestion de la prise via un module Python
Il existe des solutions clé en main construites autour des HS110 comme TPLink Energy Monitor basé sur Node.js. Mais il nous fallait quelque chose de plus « bas niveau ». Nous voulions en effet un outil sans interface graphique, nous permettant d'obtenir un relevé à l'écran et éventuellement un export au format CSV.
Nous nous sommes donc tournés vers la multitude de modules Python existant pour les produits TP-Link. Dans un premier temps nous avions utilisé pyHS100, qui est toujours parfaitement fonctionnel mais n'est plus maintenu. Un développeur a néanmoins repris la suite avec un fork, plus stable : python-kasa. Sa documentation est ici.
Il permet tant de configurer une nouvelle prise sans application, que d'utiliser celles déjà configurées. On note d'ailleurs que ses possibilités sont plus complètes que l'application officielle de TP-Link.
Pour l'utiliser, il faut disposer d'une machine avec Python 3.7+ et le gestionnaire de paquet PiPy (qui l'accompagne par défaut). Pour rappel, Python peut désormais officiellement être installé sous Windows 10 via le Microsoft Store en complément de la méthode à l'ancienne). Sinon, vous pouvez toujours passer par le sous-système Linux.
Dans ce dernier cas, l'installation nécessite de taper la commande suivante :
sudo apt update && sudo apt install python3 python3-pip
Il faut ensuite installer le module python-kasa sur le système :
pip install python-kasa --pre
Ou si votre système distingue Python 2.x et 3.x :
pip3 install python-kasa --pre
Le flag --pre
est ici nécessaire car l'outil est encore en développement. Les seules versions disponibles sont pour le moment toutes des pre-release, nécessitant cet élément pour être prises en compte par l'installeur.
Une fois l'installation terminée, vous aurez certainement une alerte vous indiquant que le dossier où sont installés les modules ne sont pas dans la variable d'environnement $PATH
. Il faut l'y ajouter afin de pouvoir les lancer directement, si vous voulez utiliser le module sous forme de script uniquement, vous pouvez passer cette étape.
Pour vérifier que tout fonctionne, lancez une découverte des prises connectées au réseau local :
kasa discover
Dans notre cas, on obtient bien un résultat pour notre prise nommée « Benchs » :
== Benchs - HS110(FR) ==
Host: 192.168.1.34
Device state: ON
== Generic information ==
Time: 2021-01-15 13:37:42
Hardware: 2.0
Software: 1.5.5 Build 191125 Rel.114303
MAC (rssi): ###
Location: ###
== Device specific information ==
LED state: True
On since: 2021-01-01 13:37:42.421337
== Current State ==
{'voltage_mv': 236010, 'current_ma': 12, 'power_mw': 0, 'total_wh': 1, 'err_code': 0}
Si vous voulez obtenir uniquement les informations de consommation de la prise :
kasa --host 192.168.1.34 --plug emeter
Qui donne le résultat suivant :
== Emeter ==
Current: 0.012 A
Voltage: 232.062 V
Power: 0.0 W
Total consumption: 0.001 kWh
Today: 0.0 kWh
This month: 0.0 kWh
Bien entendu, il faut lancer le script sur une machine présente sur le même réseau local que les prises HS110. Comme vous pouvez le constater, elles ne nécessitent aucune authentification particulière, connaître leur adresse IP suffit à les interroger pour obtenir des informations et faire changer leur état.
Pratique, mais dangereux sur un réseau trop ouvert à des tiers.
Un premier script de relevé en continu
Passons maintenant à la création de notre script, dans un fichier nommé energy.py. Nous allons y intégrer le module python-kasa et l'utiliser pour afficher la puissance fournie en continu. Ici, nous cherchons surtout à nous familiariser avec le module, ses concepts de base et ses possibilités :
import asyncio
from kasa import SmartPlug
from time import sleep
P = SmartPlug("192.168.1.34")
async def check():
while True:
await P.update()
watts = await P.current_consumption()
print(f"Puissance : {watts:.2f} W")
sleep(1)
asyncio.run(check())
Pour lancer le script, tapez :
python energy.py
Ou si votre système distingue Python 2.x et 3.x :
python3 energy.py
Cet exemple, basé sur la documentation, commence par une spécificité de python-kasa par rapport à pyHS100, il ne fonctionne pas toujours de manière synchrone, nécessitant asyncio et la syntaxe de type async/await (que nous ne détaillerons pas ici). Sachez seulement que cela permet de lancer une tâche en parallèle du reste du code puis ensuite de préciser lorsqu'il faut attendre qu'elle soit complétée pour passer à la suite.
Nous importons ensuite les différents modules nécessaires : celui de gestion des prises, puis sleep
qui nous permettra de marquer une pause, d'un temps indiqué en secondes. On désigne la prise qui recevra les requêtes par son adresse IP, nommée P (en majuscule, une convention indiquant que cette valeur ne changera pas).
On définit alors une fonction asynchrone nommée check()
, comportant une boucle infinie. Dans celle-ci, on lit les informations depuis la prise avec P.update()
puis on attribue la valeur de la puissance consommée à la variable watts
. Dans les deux cas, on attend d'obtenir le résultat avant de passer à la suite en ajoutant le mot clé await
.
On affiche ensuite la valeur de puissance sous la forme d'un nombre flottant avec deux chiffres après la virgule (:.2f
). Pour une meilleure lisibilité, on utilise les chaînes de caractères formatées litérales. Cela permet, en ajoutant un « f » avant une chaîne de caractères, d'y introduire des variables en indiquant leur nom/format entre accolades.
On termine par une pause d'une seconde. Plus ce temps sera court, plus vous aurez de relevés et donc un résultat précis. Mais attention : le résultat est obtenu de la prise en quelques centaines de millisecondes en général. Il est donc déconseillé de passer sous une valeur de 0.5, et d'augmenter ce chiffre si les résultats se répètent trop.
Pour interrompre la boucle, pressez sur les touches CTRL+C.
On calcule l'énergie consommée et la dépense que cela engendre
Corsons maintenant un peu le jeu, en ajoutant quelques relevés et calculs avec le script suivant :
import asyncio
from kasa import SmartPlug
from time import time, sleep
# On déclare l'IP de la prise
P = SmartPlug("192.168.1.34")
async def check():
# On initialise les variables qui seront utilisées
count = total = 0
price_1kWh = 15.58
time_start = time()
while True:
# On lit les données de la prise et on récupère la consommation actuelle
await P.update()
watts = await P.current_consumption()
# On met à jour les différentes variables
count += 1
total += watts
# On effectue les calculs des valeurs à afficher
average = total/count
elapsed = time() - time_start
energy_J = average * elapsed
energy_Wh = energy_J / 3600
price_total = energy_Wh / 1000 * price_1kWh
# On affiche le résultat et on attend 1 seconde avant de recommencer
print(f"{count}. "
f"Relevé : {watts:.2f} W - "
f"Moyenne : {average:.2f} W - "
f"Temps : {elapsed:.2f} s - "
f"Energie : {energy_J:.2f} J ou {energy_Wh:.2f} Wh - "
f"Coût : {price_total:.10f} cts€")
sleep(1)
asyncio.run(check())
Nous l'avons directement commenté pour en simplifier la lisibilité pour les débutants. On retrouve l'import des différents modules en début de fichier, avec un ajout : time
qui nous permet de relever l'heure courante pour définir le temps écoulé, ce qui sera nécessaire pour le calcul de l'énergie consommée.
Dans la fonction check()
, avant e lancer la boucle infinie, on initialise d'ailleurs les différentes variables qui seront utilisées : count
pour le nombre de relevés, total
pour le cumul des valeurs relevées, price_1kWh
pour le prix du kWh selon les tarifs bleus d'EDF (6 kVA dans notre exemple) et time_start
pour l'heure de lancement du script.
Dans la boucle, une fois les valeurs récupérées depuis la prise, on ajoute le résultat à count et total. On calcule ensuite la puissance moyenne, le temps écoulé puis l'énergie consommée. Celle-ci est simplement le produit des deux précédentes valeurs. On obtient alors un résultat en joules (ou watt-seconde). On le divise par 3 600 pour obtenir des Wh. Ce dernier résultat est lui-même divisé par 1 000 pour obtenir le nombre de kWh consommés puis multiplié par le prix d'1 kWh. On peut alors connaître le coût d'une tâche réalisée sur une période donnée.
Toutes les valeurs utiles sont ensuite affichées. Ici, nous avons opté pour une chaîne de caractères construite sur plusieurs lignes, là encore pour simplifier la lecture du code et faciliter les modifications. On pourrait ensuite ajouter de quoi écrire les résultats dans un fichier csv ou optimiser le lancement du script en permettant à l'utilisateur de définir certains éléments par des arguments/flags via le module argparse par exemple. Libre à vous !