Boitier Fil Pilote Heatzy

De GCE Electronics
Aller à : navigation, rechercher


Heatzy & IPX800 V4
Heatzy2.png
Nom Heatzy & IPX800 V4
Famille Objets connectés
Wiki créé le 16/05/2018
Wiki mis à jour le 16/05/2018
Auteur PatLeHibou
Patrice Le Graverend

Introduction à l'intégration d’un boitier Heatzy Pilote avec un IPX 800 v.4

Le boitier Heatzy Pilote apporte une solution de pilotage sans fils via le WiFi pour des radiateurs dont l’arrivée électrique ne comporte pas de fil pilote venant du tableau électrique.

Quoi que non triviale, son intégration avec un IPX 800 de GCE est tout à fait possible et apporte une solution au pilotage sans fil de radiateurs depuis cet équipement. C’est une alternative intéressante à une solution de pilotage via une extension X-ENO (Enocean), l’utilisation d’un micro-module Enocean 2 canaux et de diodes (2 diodes 1N4007 font très bien l’affaire, ou un module diodes fil pilote) qui est actuellement la seule autre possibilité. Vu la portée limitée de la technologie Enocean, le boitier Heatzy offre une latitude plus grande quant au placement des boitiers de pilotage (sous réserve de couverture WiFi dans la zone où se trouve le radiateur à commander).

Cette intégration recouvre plusieurs aspects :

- la consultation et le pilotage via un Widget de l’IPX 800 (partie la plus simple mais qui fait appel pour la programmation du chauffage aux seules possibilités offertes par l’App Heatzy : pilotage hebdomadaire par plages horaires, voir sur https://heatzy.com/pilote/)

- le pilotage du boitier via les scénarii de l’IPX 800 (partie plus complexe car nécessitant l’utilisation d’un serveur relais Node.js, mais permettant une intégration complète avec l’IPX 800)

Préalable : avoir un boitier Heatzy installé et opérationnel via l’App Android ou iOS, ce qui sous-entend d’avoir créé un compte sur le service Heatzy avec une adresse mail et un mot de passe (nécessaires pour la suite).

Réserves : les indications et scripts ci-dessous se basent sur la version des APIs fournies par Heatzy à la date de rédaction de ce document. L’auteur n’apporte aucune garantie au bon fonctionnement de ceux-ci.

Première étape : récupérer le « did » du boitier.

Le « device identifier » ou « did » du boitier est une chaîne de caractères alphanumérique unique, propre au boitier et à son raccordement à un réseau WiFi particulier (attention : en cas de changement de réseau WiFi ou de perte de connexion nécessitant un réenregistrement, le « did » changera). La connaissance de ce did permettra d’interroger et de piloter le boitier.

La récupération de ce « did » peut se faire très simplement via un widget HTML de l’IPX utilisant le code ci-dessous :

<script>
const HeatzyAppId='c70a66ff039d41b4a220e198b0fcc8b3';
const myHeatzyMail='my_email';
const myHeatzyPwd='my_pwd';
const Heatzy_List_Version='1.0';

let url_heatzy='https://euapi.gizwits.com/app/login';
let headers={
	'Content-Type': 'application/json',
	'Accept': 'application/json',
	'X-Gizwits-Application-Id': HeatzyAppId
	};
	fetch(url_heatzy, {headers, method:'POST', body:JSON.stringify({username: myHeatzyMail, password: myHeatzyPwd,lang: "en"})}).then(r => r.json()).then(data_login => {
		myuid=data_login.uid;
		mytoken=data_login.token;
		url_heatzy="https://euapi.gizwits.com/app/bindings?limit=20&skip=0";
		headers={
			'Accept': 'application/json',
			'X-Gizwits-Application-Id': HeatzyAppId,
			'X-Gizwits-User-token': mytoken
		};
		fetch(url_heatzy, {headers}).then(r => r.json()).then(data_device => {
			console.log("Nombre d'appareils détectés : "+data_device.devices.length);
			let Heatzy_List=document.getElementById('Heatzy_List');
			Heatzy_List.innerHTML='Liste des Heatzy trouvés :<br /><br />';
			for(let i=0; i < data_device.devices.length; i++) {
				Heatzy_List.innerHTML=Heatzy_List.innerHTML+'<b>'+data_device.devices[0].dev_alias+'</b><br />• Did : '+data_device.devices[i].did+'<br />• MAC address : '+data_device.devices[i].mac+'<br /><br />';
				console.log(data_device.devices[0].dev_alias+' / Did : '+data_device.devices[i].did+' / MAC address : '+data_device.devices[i].mac);				
				};
			Heatzy_List.innerHTML=Heatzy_List.innerHTML+'<i>Widget Heatzy List v.'+Heatzy_List_Version+', by PatLeHibou</i>';
			});
		});
</script>
<div id="Heatzy_List" style="margin-left:6px; margin-top:6px">
Login serveur Heatzy...<br />
</div>

NB : les valeurs des constantes MyHeatzyMail et de MyHeatzyPwd (3ème et 4ème lignes du script) sont à personnaliser avec votre propre adresse mail utilisée pour la connexion au service Heatzy et le mot de passe défini à cette occasion.

Si le boitier a été correctement déclaré sur le service Heatzy, le widget donnera les indications suivantes :

Liste Boitiers.png

Widget d’interrogation du serveur Heatzy permettant de récupérer le did du boitier

Outre le nom donné au boitier via l’App, on y trouve le fameux « did » ainsi que la « MAC address », pouvant être utile pour identifier l’équipement sur son réseau et lui donner une adresse IP fixe par exemple (pas indispensable).

NB : s’il y a plusieurs boitiers raccordés sur l’installation et déclarés sur le même compte, le widget devrait lister tous les boitiers connus dans la fenêtre (bien que cela n’ait pas été expérimenté, vu que nous ne disposions que d’un seul boitier au moment du test).

Ce widget n’a pas d’autre utilité que d’obtenir ce(s) did et il peut donc être soit supprimé du Dashboard ensuite, soit placé sur un Dashboard peu utilisé pour vérification.

Deuxième étape : interrogation et pilotage du boitier Heatzy

L’interrogation et le pilotage des 4 états du boitiers Heazy peut se faire à l’aide d’un widget HTML utilisant le code suivant :

<script>
const HeatzyAppId='c70a66ff039d41b4a220e198b0fcc8b3';
const myHeatzyMail='my_email';
const myHeatzyPwd='my_pwd';
var myDid=['my_did'];
const Heatzy_Device_Name='Salle de Bain';
const Heatzy_Widget_Version='(v.1.1 by PatLeHibou)';
var etatFP = ['Confort', 'Eco', 'Hors Gel', 'Arrêt'];
var etatCH = ['舒适','经济','解冻','停止'];

var url_heatzy='https://euapi.gizwits.com/app/login';
var mytoken='';
var headers={
	'Content-Type': 'application/json',
	'Accept': 'application/json',
	'X-Gizwits-Application-Id': HeatzyAppId
	};
fetch(url_heatzy, {headers, method:'POST', body:JSON.stringify({username: myHeatzyMail, password: myHeatzyPwd,lang: "en"})}).then(r => r.json()).then(data_login => {
	mytoken=data_login.token;
	});

function status_Heatzy () {
	url_heatzy="https://euapi.gizwits.com/app/devdata/"+myDid[0]+"/latest";
	headers={
		'Accept': 'application/json',
		'X-Gizwits-Application-Id': HeatzyAppId,
		};
	fetch(url_heatzy, {headers}).then(r => r.json()).then(data_state => {
		let status=etatCH.indexOf(data_state.attr.mode);
		for(let i=0; i < 4; i++) {
			if (i==status) {document.getElementById('fp_h0'+i).style.color='#3FB740'} else {document.getElementById('fp_h0'+i).style.color='#C9C5C5'};
			};
		document.getElementById('fp_h0Text').value=etatFP[status];
		document.getElementById('fp_name0').innerHTML=Heatzy_Device_Name+' '+Heatzy_Widget_Version;
		});
	};

function cmd_Heatzy (boitier, status) {
	let url_heatzy="https://euapi.gizwits.com/app/control/"+myDid[boitier];
	let headers={
		'Content-Type': 'application/json',
		'Accept': 'application/json',
		'X-Gizwits-Application-Id': HeatzyAppId,
		'X-Gizwits-User-token': mytoken
		};
	fetch(url_heatzy, {headers, method:'POST', body:JSON.stringify({raw: [1,1,status]})})
	};

setInterval(status_Heatzy, 1000);

</script>
<div id="fp_heatzy0" style="margin-left:12px; margin-top:6px">
	<h2 id="fp_name0" class="section-title">Recherche boitier</h2>
	<p></p>
	<input value='----' id="fp_h0Text" class="bouton2" style="margin-bottom: 15px; width: 110px; background-color: rgb(68, 68, 68);" type="button"></input>
	<br>
	<div id="fp_h03" onclick='cmd_Heatzy(0,3);' class="police-switch" style="font-size: 25px; width: 40px; color: '#C9C5C5'};"></div>
	<div id="fp_h02" onclick='cmd_Heatzy(0,2);' class="police-snowflake-alt2" style="font-size: 30px; position: relative; top: -27.5px; left: 40px; width: 40px; color: '#C9C5C5'};"></div>
	<div id="fp_h01" onclick='cmd_Heatzy(0,1);' class="police-moon_fill" style="font-size: 25px; width: 40px; position: relative; top: -55px; left: 90px; color: '#C9C5C5'};"></div>
	<div id="fp_h00" onclick='cmd_Heatzy(0,0);' class="pol-sunny18" style="font-size: 35px; width: 40px; position: relative; top: -85.5px; left: 130px; color: '#C9C5C5'};"></div>
</div>

NB 1 : ici aussi, les valeurs de MyHeatzyMail et de MyHeatzyPwd sont à personnaliser avec votre propre adresse mail utilisée pour la connexion au service Heatzy et le mot de passe défini à cette occasion, mais le paramètre du tableau MyDid doit aussi être remplacé par la valeur de « did » obtenue avec le widget de l’étape précédente.

NB 2 : bien que cela n’ait pas pu être expérimenté dans le cadre de ce test, le widget a été préparé pour pouvoir montrer l’état de plusieurs boitiers et les piloter. Mais cela nécessitera des adaptations relativement importantes pour ce faire.

NB 3 : le tableau EtatCH fait appel à des caractères Unicode chinois, s'assurer qu'ils sont bien copiés/collés lors de l’intégration dans son IPX 800 lors de la personnalisation.


A ce stade, l’état du boitier est visible dans le DashBoard de l’IPX 800 où le widget HTML a été implémenté, et il peut être piloté très simplement en cliquant sur les icônes d’état :

Widget Heatzy.png

Widget HTML de pilotage d’un boitier Heatzy

Tout changement fait à partir de l’App Android (ou iOS, bien que cela n’ait pas pu être testé, faute d’un iPhone dans le cadre de cette expérimentation) se répercute avec un très léger retard (1 seconde environ) dans l’interface et réciproquement.

Troisième étape : pilotage du boitier Heatzy via les scénarii de l’IPX

C’est la partie la plus complexe car elle nécessite de passer par un serveur relais pour transférer les ordres.

En effet les commandes PUSH envoyées par l’IPX 800 ne permettent pas :

- de récupérer d’abord le « token » (jeton) nécessaire à l’opération pour pouvoir ensuite passer la commande de changement d’état du radiateur ;

- de transmettre un « header » et éventuellement un « body » dans la requête http.

Dans le cadre de ce test, le rôle de ce serveur a été joué par un NAS Synology DS414slim (sous DSM 6) présent sur le réseau. Pour cela, un package Node.js v8 a été préalablement installé. Les versions précédentes de Node.js marchent probablement, bien que cela n’ait pas été testé.

Package NodeJS.png

Package Node.js v8 après installation sur le Synology

NB : il est très certainement possible de réaliser la même opération sur un autre modèle ou une autre marque de NAS ou toute autre machine pouvant exécuter Node.js et les paquets utilisés (par exemple un Raspberry Pi ou un serveur domotique sous LinuX).

Il faut définir sur le serveur un répertoire dans lequel sera installé le script permettant de faire la fonction de relais des ordres. Un partage spécialement dédié à cela peut être une bonne solution.

Installation du package « request »

Le script repose sur l’utilisation d’un package pour Node.js « request » permettant de simplifier l’envoi des requêtes http nécessaires. Celui-ci pourra être trouvé sur ce lien chez NPM.

Pour l’installation, il faut se connecter en SSH sur le serveur, via un outil comme PuTTY sur PC/Windows ou via le Terminal sur Mac, avec un compte administrateur et se placer dans le dossier qui va accueillir le script et le package « request » par une commande :
cd /le/chemin/d’accès/au/répertoire/du/script
L’installation se fait via la commande
npm i request

L’exécution en sudo peut être nécessaire (et donc nécessiter l’entrée du mot de passe administrateur).

Personnalisation et installation du script de pilotage

Quand l’installation est terminée, ou pendant que celle-ci s’exécute, copier le script ci-dessous dans un fichier texte nommé par exemple "Heatzy_Pilot_2.2a.js" et le placer dans ce même répertoire que précédemment (depuis l’interface du PC ou du Mac) :

//Heatzy Pilot v.2.2a by PatLeHibou
//Code optimisé par Zogstrip (merci à lui ;-) )
//26 avril 2018
const qs      = require("qs");
const url     = require("url");
const http    = require("http");
const request = require("request");

const IP   = "IP_de_mon_serveur";
const PORT = port_du_service_node.js;

const HEATZY_APP_ID = "c70a66ff039d41b4a220e198b0fcc8b3";
const HEATZY_MAIL   = "my_email";
const HEATZY_PWD    = "my_pwd";

http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url);
  const params = qs.parse(parsedUrl.query);

  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('200 OK\nDid : '+params.did+'\nStatus : '+params.status);

  let options = {
    method: "POST",
    url: "https://euapi.gizwits.com/app/login",
    headers: {
      "Content-Type": "application/json",
      "Accept": "application/json",
      "X-Gizwits-Application-Id": HEATZY_APP_ID,
    },
    body: JSON.stringify({
      username: HEATZY_MAIL,
      password: HEATZY_PWD,
      lang: "en",
    })
  };

  request(options, (error, response, body) => {
    const token = JSON.parse(body).token;
    console.log(`Token: ${token}`);

    options.url = `https://euapi.gizwits.com/app/control/${params.did}`;
    options.headers["X-Gizwits-User-Token"] = token;
    options.body = JSON.stringify({
      raw: [1, 1, parseInt(params.status) % 4]
    });

    request(options, () => {
      console.log(`Commande effectuée \nDid : ${params.did}\nStatus : ${parseInt(params.status)%4}`);
    });
  });


}).listen(PORT, IP);

console.log(`Server running @ http://${IP}:${PORT}`);

Là encore, il faut personnaliser le script à sa propre situation (lignes 9, 10, 13 et 14 du script) :

- IP_serveur : indiquer l’IP du serveur qui exécute le service Node.js

- port_node.js : indiquer le n° de port TCP qui reçoit les requêtes Node.js (1337 par défaut)

- my_email : email de connexion au service Heatzy

- my_pwd : mot de passe associé

Test du bon fonctionnement du serveur Node.js

Quand tout est installé, le bon fonctionnement peut être testé en lançant le script via la commande :

node Heatzy_Pilot_2.2a.js

Le terminal doit répondre que le serveur est en exécution : Server running @ http://IP_serveur:port_node.js

Depuis un navigateur, tester le basculement du fil pilote en entrant l’URL :

http://IP_serveur:port_node.js/Command?did=my_did&status=X

my_did est à remplacer par la valeur de did obtenue via l’interface de l’IPX et utilisée dans les scripts de consultation et de pilotage du boitier.

status prendra, selon le mode voulu, les valeurs suivantes (identiques à celles utilisées pour le pilotage d’une extension Fil Pilote X-FP de GCE) :

- 0 = Confort

- 1 = Eco

- 2 = Hors Gel

- 3 = Arrêt

NB 1 : pour mémoire, le boitier Heatzy ne sait pas, actuellement, piloter les ordres Confort 1° et Confort -2°, mais qui sont relativement peu utiles.

NB 2 : le « Command » dans l’URL n’est pas utilisé actuellement mais pourra l’être ultérieurement si d’autres ordres sont amenés à être passés par ce biais (interrogation d’état ou autre).

Le navigateur doit afficher en réponse :

200 OK
Did : my_did
Status : X

Et le statut du boitier doit changer (visible soit sur le boitier lui-même, soit via l’App, soit dans l’interface de l’IPX).

NB : cette réponse faite par le serveur accuse simplement bonne réception de l’ordre transmis, mais pas de sa bonne exécution via les serveurs de Heatzy. En cas d’erreur sur le did ou de dysfonctionnement des serveurs de Heatzy, cela ne sera pas indiqué.

Le service Node.js peut être maintenant arrêté en appuyant sur « Ctrl C ». L’invite de commande revient dans le terminal.

Lancement automatique du script

Le lancement et la surveillance du bon fonctionnement du script Node.js sur le serveur se fait, sur le Synology, via le Planificateur de Tâches. Sur un autre type de serveur, il pourra être nécessaire de créer un script « cron » effectuant cette tâche, mais cela ne sera pas détaillé ici.

Pour cela il faut :

- créer une « Tâche planifiée » (dans le Panneau de configuration)

- lui donner un nom dans l’onglet « Général

- planifier son exécution quotidienne toutes les minutes de 0:00 à 23:59 dans l’onglet « Programmer »

- indiquer la commande "node /chemin/Heatzy_Pilot_2.2a.js" (avec « chemin » à personnaliser vers le répertoire où se trouve le script) dans l’onglet « Paramètres de tâche »

Planificateur.png

Ecrans de configuration du Planificateur de Tâches du Synology

Le NAS vérifiera en permanence le bon fonctionnement de la tâche et la relancera si jamais elle venait à s’arrêter pour une quelconque raison.

A ce stade, le bon fonctionnement du pilotage du boitier peut de nouveau être testé depuis un navigateur avec les commandes HTTP.

Pilotage par l’IPX 800

Le pilotage du boitier par l’IPX 800 se fera via des « périphériques » PUSH de celui-ci. Il faut créer 4 « périphériques », un pour chaque état, en indiquant l’adresse IP et le port du serveur qui fait fonctionner le script ainsi que le did du boitier à piloter :

Commande Push Confort.png

Commande PUSH pour la bascule en mode « confort »

Ces « périphériques » PUSH sont ensuite utilisables dans la programmation de l’IPX 800 pour faire basculer l’état du boitier selon certains évènements (comme tout autre périphérique piloté par un IPX). Cela inclut :

- la bascule entre mode Confort et mode Eco selon des plages horaires ;

- un délestage pendant la période où le chauffage n’est pas utilisé (été) ;

- la bascule en mode Hors Gel sur une période d’absence ;

- la mise à l’arrêt en cas de détection d’une fenêtre ouverte par exemple ;

- et toutes les autres possibilités que les utilisateurs d’IPX 800 connaissent bien…

Conclusion

L’intégration d’un boitier Heatzy dans une installation domotique basée sur un IPX 800 de GCE est donc tout à fait possible, même si elle nécessite quelques compétences en informatique pour pouvoir installer les services nécessaires.

C’est une alternative tout à fait pertinente à une solution à base d’outils Enocean telle que décrite en introduction, et présentant l’avantage d’une plus grande latitude de placement des radiateurs car fonctionnant en WiFi.

Elle présente toutefois quelques inconvénients :

- nécessiter un serveur Web, et donc disposer d’un équipement pour ce faire et d’un minimum de compétences informatiques pour l’installer et l’administrer, afin de pouvoir tirer pleinement parti des possibilités de programmation de l’IPX 800 et permettre une intégration complète à l’environnement de celui-ci. Sauf si on se contente de visualiser l’état du boitier et de piloter manuellement des changements d’état via un widget de l’IPX, la programmation hebdomadaire restant faite avec le système de calendrier de l’App Heatzy.

- faire appel à une identification du boitier (« did ») qui peut changer s’il y a une modification au niveau du réseau WiFi nécessitant une redéclaration de l’équipement sur le service Heatzy, alors que ce « did » est utilisé à de nombreux endroits dans la programmation (widgets HTML, commandes PUSH de pilotage…). Il faut donc bien penser à faire les modifications partout où c’est nécessaire en cas de changement de ce « did ».

- ne pas être totalement autonome mais dépendant du fonctionnement des serveurs gérés par Heatzy dont les APIs peuvent éventuellement évoluer sans avertissement et nécessiter de modifier la programmation.

- en conséquence, ne pas avoir de garantie sur la pérennité à long terme de la solution (éventuel changement de stratégie concernant l’utilisation des APIs, voire éventuelle disparition de la société).

- comme toute solution à base d’IoT, pouvoir potentiellement poser d’éventuels problèmes de sécurité du réseau domestique, du fait de la nécessaire ouverture de celui-ci pour permettre à ces objets de communiquer avec les serveurs qui les pilotent depuis l’extérieur, ce qui rend leur utilisation très facile pour le grand public (visualisation et pilotage depuis n’importe où via Smartphone disposant d’une connexion à Internet) au prix d’une ouverture rarement maîtrisée du réseau domestique sur le monde extérieur.