Monthly Archives: mai 2012
Interagir en jQuery/Ajax avec le bus KNX
Une semaine après mon article sur un frontend php KNX.
Je bosse sur une interface simple pour visualiser et contrôler des points lumineux.
Pour l’instant, je fais au plus simple, j’ai deux points lumineux :
– Une ampoule sur un TXA213.
– Un bandeau LED RGB contrôlé par OLA.
Je pourrais également paramétrer d’autres ampoules sur mes TXA207C, mais je fais aussi du On/Off avec le TXA213.
J’ai fait un petit screencast aussi simplet que mes scripts, à regarder en 720p.
Il est difficile d’entrer dans les détails du script, cependant, le fonctionnement principal est lié à mon article précédent sur le bus KNX et l’enregistrement des valeurs dans la base MySQL.
La nouveauté provient des scripts jQuery et Ajax pour le rafraîchissement toute les 0,5 secondes des éléments de la page.
Je change un élement à partir de la page web, j’utilise writegroup en php. (Voir mon article : Prise en main du KNX en php ).
Et continue de lire ma BDD, sans y écrire de changement, le frontend php s’en occupe.
Il y’a 3 scripts AJAX/PHP :
- knx-get_light_value.php : me récupère simplement les valeurs dans la BDD selon le « nom système » écrit dans le div id html.
- knx-set_light_toggle.php : me change l’état d’une lumière, On ou Off, rien de plus sur un EIS n° 1.
- knx-set_light_value.php : plus complexe que le précédent script, peut gérer d’autres EIS.
Evidemment, si je change l’état d’une lumière depuis un bouton poussoir, le changement est visible sur la page (ce que je fais à 0:50).
Je partagerai volontiers les sources lorsque j’aurai amélioré le schlimblik en back-end.
Alimentation / injecteur 5 Volts 1-wire (version beta)
Il était temps de changer la version alpha !
Même principe, même schéma électrique, sans pistolet à colle et le luxe d’un fusible :
Le boitier est vendu sur ebay.com (Cat5e Ethernet Keystone RJ-45 Jack & Surface Mount Box).
Ouf ! Il était vraiment temps de changer !
Frontend PHP pour l’écoute du bus KNX
Dans un précédent article, j’ai décris comment écouter le bus KNX pour allumer une rampe de LED via Open DMX.
En fin d’article, j’ai abordé l’aspect possible d’un frontend en PHP pour avoir une base de données MySQL à jour, en fonction des évènements du KNX.
L’intérêt est quasi le même que linknx, un changement sur le bus est égal à un changement en BDD sur les Groupes d’Adresses qui m’intéressent.
Le but est de pouvoir exploiter ces données sur une page web et d’autres scripts maisons sans faire de requête sur le bus, mais en interrogeant ma BDD.
Une espèce de travail en couche d’applications.
Pour rappel, je n’ai rien contre linknx, j’aurais juste du mal à adapter mon cahier des charges à cet outil, voir mon article :
Se passer de linknx et webknx2, une fausse bonne idée ?
Pour ce front-end, je me suis inspiré de mon premier script avec logtail.
En cherchant des solutions, je suis tombé sur l’extention php inotify et son tail (en commentaire).
La base
Pour commencer, toujours depuis Debian Wheezy, il faut posséder php5, php-pear ainsi qu’une base MySQL évidemment.
inotify s’installe comme ceci au plus simple :
L’extention activée pour php5 pour le cli :
Selon mon premier script pour allumer ma rampe LED, re-modification de mon script d’init.d eibnetmux.
A la différence, que je log tout ce qu’il se passe sur le bus.
# Function that starts the daemon/service # do_start() { echo -n "Starting eibdnetmux" /usr/local/bin/eibnetmux $DAEMON_ARGS echo " done" sleep 2 echo -n "Starting group listen" /usr/local/bin/groupsocketlisten ip:127.0.0.1 > /tmp/knx_groupsocketlisten & echo " done" }
Mon fichier « log » du bus est /tmp/knx_groupsocketlisten
J’ai crée, ce qui est pour l’instant une simple table avec les Groupe Addresses qui m’intéressent, à l’éfigie de linknx :
-- -- Structure de la table `knx_ga` -- CREATE TABLE `knx_ga` ( `knx_ga_id` int(3) NOT NULL AUTO_INCREMENT, `knx_ga_groupaddress` tinytext NOT NULL, `knx_ga_value` text NOT NULL, `knx_ga_comment` text NOT NULL, PRIMARY KEY (`knx_ga_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -- -- Contenu de la table `knx_ga` -- INSERT INTO `knx_ga` (`knx_ga_id`, `knx_ga_groupaddress`, `knx_ga_value`, `knx_ga_comment`) VALUES (1, '0/0/1', '1', 'Etat de la lumiere'), (2, '0/0/2', '10', 'Valeur d''éclairement'), (3, '0/0/10', '0', 'DMX');
J’ai 3 groupes d’adresses, ça n’a pas de sens sans une mise en situation.
Mise en situation
J’ai un Hager TXA213 (3 sorties variation 300W), un Hager WKT302 (poussoir 2 boutons), une lampe à la sortie 1 du TXA213.
Une simple pression sur le bouton 1 allume ma lampe, une pression continue augmente la luminosité ; une simple pression sur le bouton 2 éteind la lampe, une pression continue diminue la luminosité.
Pour le détail, voici un export de mes Groupes d’Adresses :
Groupes d’adresses pour tests (pdf)
J’ai trois groupes parmis les sept qui m’intéressent :
0/0/1 → Indication d’état.
0/0/2 → Valeur d’éclairement & Indication valeur d’éclairement.
0/0/10 → Allumage DMX.
Le script
Voici la formule magique, à dérouler, parce que c’est vraiment long.
<!--?php $file = "/tmp/knx_groupsocketlisten"; /** * Tail a file (UNIX only!) * Watch a file for changes using inotify and return the changed data * * @param string $file - filename of the file to be watched * @param integer $pos - actual position in the file * @return string */ function tail($file,&$pos) { // get the size of the file if(!$pos) $pos = filesize($file); // Open an inotify instance $fd = inotify_init(); // Watch $file for changes. $watch_descriptor = inotify_add_watch($fd, $file, IN_ALL_EVENTS); // Loop forever (breaks are below) while (true) { // Read events (inotify_read is blocking!) $events = inotify_read($fd); // Loop though the events which occured foreach ($events as $event=-->$evdetails) { // React on the event type switch (true) { // File was modified case ($evdetails['mask'] & IN_MODIFY): // Stop watching $file for changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance fclose($fd); // open the file $fp = fopen($file,'r'); if (!$fp) return false; // seek to the last EOF position fseek($fp,$pos); // read until EOF while (!feof($fp)) { $buf .= fread($fp,8192); } // save the new EOF to $pos $pos = ftell($fp); // (remember: $pos is called by reference) // close the file pointer fclose($fp); // return the new data and leave the function return $buf; // be a nice guy and program good code ;-) break; // File was moved or deleted case ($evdetails['mask'] & IN_MOVE): case ($evdetails['mask'] & IN_MOVE_SELF): case ($evdetails['mask'] & IN_DELETE): case ($evdetails['mask'] & IN_DELETE_SELF): // Stop watching $file for changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance fclose($fd); // Return a failure return false; break; } } } } // Conection avec la base de données mysql $db = mysql_connect("127.0.0.1", "root", "votremotdepassemysql"); $mysql=mysql_select_db("votrebase",$db); $req_sel_ga = "SELECT knx_ga_id,knx_ga_groupaddress FROM knx_ga"; $qur_sel_ga = mysql_query($req_sel_ga) or die (mysql_error()); $ga_bdd = array(); while($dat_sel_ga = mysql_fetch_array($qur_sel_ga)) { $knx_ga_id = $dat_sel_ga['knx_ga_id']; $knx_ga_groupaddress = $dat_sel_ga['knx_ga_groupaddress']; $ga_bdd[$knx_ga_groupaddress] = $knx_ga_id; } // Use it like that: $lastpos = 0; while (true) { // On tail le fichier de log $knxlisten = tail($file,$lastpos); //echo $knxlisten; // On réagit dès qu'on a un Write if (preg_match('#^Write#',$knxlisten)) { // Recup du Groupe d'Addresse et de la valeur qu'on converti preg_match('#[0-9]*\/[0-9]*\/[0-9]*#',$knxlisten,$groupaddr); preg_match("#[A-F0-9]*(.)$#",$knxlisten,$value); $value = hexdec($value[0]); $groupaddr = $groupaddr[0]; // on regarde si ca fait parti des elements à surveiller if (array_key_exists($groupaddr, $ga_bdd)) { // la valeur associé = l'id dans la BDD $knx_ga_id_update = $ga_bdd[$groupaddr]; $req_sel_ga_update = "UPDATE knx_ga SET knx_ga_value = '$value' WHERE knx_ga_id = $knx_ga_id_update"; // Et on update la BDD ! mysql_query($req_sel_ga_update); if ($knx_ga_id_update == "0/0/10" && $value == "01") exec("dmxchangecolorfader.py 255 0 255"); if ($knx_ga_id_update == "0/0/10" && $value == "00") exec("dmxchangecolor.py 0 0 0"); } } }
Abracadabra !
C’est posté sans mise au propre, mon dernier partage de script PHP était pour le 1-wire, il a fallu faire une archive pour un script plus simple, le voici brut, à personnaliser, poser des includes, variables de configuration, etc…
En gros, il fait quoi ce script ?
Il récupère les groupes d’adresses à surveiller dans la BDD.
Il fait un tail sur notre fichier de sortie groupsocketlisten.
Pour chaque nouvel évènement « Write », il regarde si le groupe d’adresse fait parti de ceux dans la BDD.
Si c’est le cas, il y écrit la valeur.
Cas pratique :
Si j’allume ma lumière, 0/0/1 passe à 1 sur mon bus.
groupsocketlisten l’écris dans le fichier /tmp/knx_groupsocketlisten
Ce script voit passer 0/0/1, il sait que sa valeur m’intéresse, il y écrit immédiatement la valeur dans la base de donnée.
Il suffit de lancer ce script par le cron, à la main (en ligne de commande uniquement), par un init.d ou autre.
La mise à jour de la base est quasi instantanée !
Le fonctionnement du script ci-dessous charge les GA de la base MySQL et les place dans une variable puis les compare à GA qui circule sur le bus.
A la fin du script, la partie liée à 0/0/10 est pour reprendre le fonctionnement de l’article de base et l’allumage du DMX.
Je songe à l’intégrer différemment, très certainement par l’ajout d’un champ contenant la spécificité et le script à exécuter.
Et voila ! Ou comment re-inventer la roue : linknx !
Il me reste à personnaliser ce script via des includes, des paramètres, rajouter un champs dans la table pour appeler un GA par un nom, un autre champs IES pour le write, et faire des essais sur une page web.
Communication entre le bus KNX et un serveur Linux
Jusqu’à présent, j’ai découvert comment envoyer des ordres ou obtenir une valeur avec mon bus KNX.
Que ce soit en PHP ou par ligne de commande.
Mon souhait est de pouvoir faire l’inverse : depuis le bus KNX, de donner un autre à mon serveur.
Plusieurs applications possibles, en voici deux concrètes :
- Allumer/couper les lumières d’ambiance DMX, changer les couleurs.
- Allumer/couper le wifi.
C’est sans limite en fait.
Du moment où j’envois une commande (boutton poussoir) au serveur celui-ci peut être interprété comme bon me semble.
Je passe de l’électrique de puissance à l’informatique classique.
Comment ça marche ?
J’ai essayé de faire un schéma :
Coté programmation, j’ai crée un groupe d’adresses 0/0/10 qui ne contient aucune action, le groupe est lié à l’interrupteur bouton poussoir.
Notre serveur, équipé d’eibnetmux (lien vers son installation) utilise grouplisten pour écouter ce qu’il se passe sur le bus KNX pour un Groupe d’Adresse spécifié, ici le GA 0/0/10.
La fonction grouplisten est exécutée en même temps que le démarrage d’eibnetmux, j’ai rajouté quelques lignes à partir de mon script initial.
La sortie de cette commande est redirigée vers un fichier.
# # Function that starts the daemon/service # do_start() { echo -n "Starting eibdnetmux" /usr/local/bin/eibnetmux $DAEMON_ARGS echo " done" sleep 2 echo -n "Starting group listen" /usr/local/bin/grouplisten ip:127.0.0.1 0/0/10 > /tmp/knx_0-0-10 & echo " done" }
Je vais me servir de ce fichier pour surveiller les changements d’état.
J’utilise l’outil logtail pour vérifier les nouveaux évènements.
Pour cet exemple, je souhaite que l’utilisation du bouton poussoir allume mon bandeau RGB, dont j’ai récemment effectué l’installation.
# chmod +x /usr/local/bin/knx2dmx
# vi /usr/local/bin/knx2dmx
#!/bin/bash lockfile=/tmp/knx2dmx.run if [[ -f $lockfile ]] ; then echo "knx2dmx déjà en cours d'exécution ou supprimer le fichier $lockfile" exit fi touch $lockfile groupaddress=$1 file=/tmp/knx_$groupaddress bouclette="yes" # Boucle sans fin while [ $bouclette = "yes" ] do { # Mais on est pas à 1 seconde près sleep 1 value=`/usr/sbin/logtail -f -o $file | grep "Write" | cut -d" " -f4` if [ "$value" == 01 ] then # Ici j'allume mon bandeau RGB, mais toute autre action est envisageable /usr/local/bin/dmxchangecolorfader.py 255 25 100 elif [ "$value" == 00 ] then # Je l'éteinds /usr/local/bin/dmxchangecolor.py 0 0 0 fi } done
Et celui là, je le lance dans le cron.
*/10 * * * * root /usr/local/bin/knx2dmx 0-0-10
Donc si mon script, via logtail, détecte que l’adresse de groupe 0/0/10 KNX passe à 1, il allume le strip RGB DMX.
A l’inverse, s’il détecte un 0, il l’éteint.
A titre de supplément, le script dmxchangecolor.py est celui abordé dans l’installation d’OLA.
#!/usr/bin/python import sys, array from ola.ClientWrapper import ClientWrapper def DmxSent(state): wrapper.Stop() universe = 1 data = array.array('B') data.append(int(sys.argv[1])) data.append(int(sys.argv[2])) data.append(int(sys.argv[3])) wrapper = ClientWrapper() client = wrapper.Client() client.SendDmx(universe, data, DmxSent) wrapper.Run()
Et le script dmxchangecolorfader.py provient aussi de la page wiki d’OLA.
Que j’ai beaucoup bidouillé car je ne sais pas codé en python :
Je n’en suis pas fier, surtout qu’il ne faut pas mettre de valeur à 0.
#!/usr/bin/python import sys, array from ola.ClientWrapper import ClientWrapper red_arg = int(sys.argv[1]) green_arg = int(sys.argv[2]) blue_arg = int(sys.argv[3]) red = 0 green = 0 blue = 0 wrapper = None loop_count = 0 TICK_INTERVAL = 10 # in ms def DmxSent(state): if not state.Succeeded(): wrapper.Stop() def SendDMXFrame(): # schdule a function call in 100ms # we do this first in case the frame computation takes a long time. wrapper.AddEvent(TICK_INTERVAL, SendDMXFrame) # compute frame here data = array.array('B') global loop_count global red global green global blue if red == (red_arg-1): data.append(red_arg) else: red = loop_count % red_arg data.append(red) if green == (green_arg-1): data.append(green_arg) else: green = loop_count % green_arg data.append(green) if blue == (blue_arg-1): data.append(blue_arg) else: blue = loop_count % blue_arg data.append(blue) loop_count += 1 if (red == (red_arg-1)) and (green == (green_arg-1)) and (blue == (blue_arg-1)): exit() # send wrapper.Client().SendDmx(1, data, DmxSent) wrapper = ClientWrapper() wrapper.AddEvent(TICK_INTERVAL, SendDMXFrame) wrapper.Run()
Résultat
Pour aller plus loin avec un frontend php
Et voila ! Une bonne base pour faire interagir le serveur depuis le bus KNX.
Je pourrai rajouter autant de grouplisten que necessaire, mais dans une certaine mesure, il sera certainement préférable d’écouter tout ce qu’il se passe sur le bus via groupsocketlisten.
Avec un principe un petit peu différent :
Dans ce cas, groupsocketlisten écoute tout ce qu’il se passe sur le bus.
Un script PHP est à l’écoute des informations, certainement sur le même principe du logtail.
Il filtre et remplit des informations dans la base de données MySQL.
Cette partie là est intéressante, si par exemple, j’allume une lumière derrière un variateur TXA213, groupsocketlisten y voit défiler deux informations :
Write from 0.2.189 to 0/0/1: 01 Write from 1.1.2 to 0/0/7: 01 Write from 1.1.2 to 0/0/8: AF
Ici, j’ai allumé ma lumière grâce à un « groupswrite ip:127.0.0.1 0/0/1 1 », je le vois sur mon bus (0.2.189).
Et deux autres informations utiles y circulent :
– 0/0/7 correspond à l’indicateur d’état, à 01 donc ma lampe est allumée.
– 0/0/8 correspond à l’indicateur de la valeure d’éclairement en hexadécimale sur FF (255).
Ici la valeur hexa AF (FF étant le max) correspond à 175 en décimale (255 étant le max).
Ainsi, avec un base de données bien pensée, il est possible de faire un filtre intelligent : un type d’objet c’est tant et tant d’information à récolter avec tels et tels groupes d’adresses.
On peut pousser le bouchon plus loin, c’est ce « frontend » PHP qui pourrait exécuter des actions sur le système tel que l’allumage DMX.
Une fois la BDD avec des informations actualisées, il ne reste plus qu’à les exploiter à travers une page web.
Une solution qui me semble bonne pour les fondations d’une bonne usine à gaz.
Je vais commencer quelque chose dans ce principe pour un prochain article.
Insérer les valeurs 1-wire dans une base MySQL
J’ai déjà abordé la récupération des températures dans un graphique munin.
J’ai également abordé la récupération de ces mêmes valeurs en PHP.
Et maintenant, place à la récupération des valeurs pour l’insertion dans une base de données MySQL.
Le but étant de passer par le cron, d’avoir une table avec les sondes, une table avec les valeurs.
J’ai réalisé ce premier ensemble de scripts regroupant pas mal de require, c’est plus difficile à partager pour la compréhension et les explications mais j’espère que ce script restera sous cette forme pour mon usine à gaz définitive.
Structure de la base
Une première table avec les sondes, voici son squelette :
CREATE TABLE IF NOT EXISTS `1wire_sensor` ( `1wire_sensor_id` int(3) NOT NULL AUTO_INCREMENT, `1wire_sensor_enable` enum('true','false') NOT NULL, `1wire_sensor_type` enum('temperature','presence','sensed.A') NOT NULL, `1wire_sensor_family` tinytext NOT NULL, `1wire_sensor_idaddress` tinytext NOT NULL, `1wire_sensor_comment` text NOT NULL, PRIMARY KEY (`1wire_sensor_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Une seconde table avec les valeurs, son squelette :
CREATE TABLE IF NOT EXISTS `1wire_data` ( `1wire_data_id` int(11) NOT NULL AUTO_INCREMENT, `1wire_data_sensor_id` int(3) NOT NULL, `1wire_data_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `1wire_data_value` text NOT NULL, PRIMARY KEY (`1wire_data_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Le script automatique
Comme expliqué plus haut, difficile de partager un script complexe pour un besoin simple.
Je fais un « require » pour appeler un fichier de config, un autre pour la connexion MySQL, un dernier pour mes fonctions 1-wire.
Ce qui donne cet ensemble :
<?php $pathconfig = "/var/www/domy"; require_once($pathconfig."/require/main.inc.php"); require_once(PATH."/require/database.inc.php"); require_once(PATH."/require/function-1wire.inc.php"); // Recup des données des sondes depuis la BDD $req_sensor = "SELECT * FROM 1wire_sensor WHERE 1wire_sensor_enable IS TRUE"; $qur_sensor = mysql_query($req_sensor); while($dat_sensor = mysql_fetch_array($qur_sensor)) { // Pour chaque sonde on constitue son adresse : $onewire_address = $dat_sensor['1wire_sensor_family'].".".$dat_sensor['1wire_sensor_idaddress']; // On teste sa présence sur le bus if(onewire_presence($onewire_address)) { debug("OUI ! ".$onewire_address." est présent sur le bus","cli"); if ($dat_sensor['1wire_sensor_type'] == "presence") { debug("Seul sa presence sur le bus est nécessaire","cli"); // on ecris dans la BDD qu'il est présent et on s'arrete là $value = 1; } elseif ($dat_sensor['1wire_sensor_type'] == "temperature" || $dat_sensor['1wire_sensor_type'] == "sensed.A") { // on récupère sa valeur, que ca soit la température ou l'état du PIO (DS2406) $value = onewire_read($onewire_address,$dat_sensor['1wire_sensor_type']); } } else { // Composant absent du bus debug ("NON ! ".$onewire_address." n'est pas présent sur le bus","cli"); $value = 0; } // on écris le resultat dans la BDD $req_insdata = "INSERT INTO 1wire_data SET 1wire_data_sensor_id = ".$dat_sensor['1wire_sensor_id'].", 1wire_data_value = '".$value."'"; mysql_query($req_insdata) or die ("Erreur à l'insertion des données 1-wire : ".mysql_error()); } ?>
J’espère que le principe de ce script php reste compréhensible avec les commentaires.
L’ensemble des fichiers sont disponible à la fin de l’article.
Le contenu de la base
Une fois la structure de la base établie ainsi que le script chargé de consulter les élements 1-wire, il reste à saisir les informations liés aux éléments 1-wire.
Pour cela, en plus d’avoir identifiant chaque sonde au moment de son câblage, je me sert de owhttpd pour récupérer l’ID des sondes. ( http://ipduserveur:2121/ )
J’ai descidé de spliter en deux l’ID des sondes 1-wire.
Par exemple, pour 28.7B2DB5030000 :
– Famille : 28.
– ID : 7B2DB5030000.
Et j’utilise phpmyadmin pour inserer la 1re sonde de température ( 28.7B2DB5030000 ) afin d’obtenir ceci :
Ainsi de suite pour chaque sonde désirée, 1wire_sensor_id étant la clée primaire en AUTO_INCREMENT.
A terme, le but étant de créer une interface pour gérer l’ajout, l’édition et la supression de sonde plus facilement via une page développée dans ce sens.
Idem pour chaque famille de sonde : température / présence / PIO.
Execution
On peut faire un simple test :
# php fetch-1wire.php
Vous devriez obtenir les valeurs de température.
Si vous obtenez le message :
PHP Notice: Can’t create socket [ow://127.0.0.1:4304], errno: 111, error: Connection refused in /var/www/1-wire/require/ownet.php on line 205
PHP Notice: Can’t connect get#1 in /var/www/1-wire/require/ownet.php on line 388
Modifiez le /etc/owfs.conf pour remplacer :
server: port = localhost:4304
Par :
server: port = 4304
Redemarrez owserver et refaite le test.
Si tout est ok, l’execution se fait via le cron, tout simplement :
*/5 * * * * root /usr/bin/php -q /var/www/1-wire/cron/fetch-1wire.php
Au bout de quelques heures :
Télécharger
A adapter, bidouiller, comprendre, améliorer, etc…
Et bientôt la génération de beaux graphs à partir de ces valeurs.
Se passer de linknx et webknx2, une fausse bonne idée ?
Aujourd’hui, grande réflexion autour de linknx et knxweb2.
Je me suis attardé sur ces deux outils, en plus de leur découverte via une Live CD.
Le but étant, entre autres, de découvrir l’interface de knxweb2 (knxweb v1 sur le LiveCD), et comprendre la communication entre le click et l’ampoule.
KnxWeb2
C’est à peu près démystifié : knxweb2 tourne en AJAX/jQuery qui communique en XML à travers un savant mélange avec linknx.
C’est puissant ! Instantané.
Seul bémol, au jour d’aujourd’hui, je ne me vois pas capable de « maîtriser » linknx et knxweb2, car là dedans, je n’ai pas mes lots :
– Asterisk
– Notifry
– DMX
– 1-wire
– Alarme
– Teleinfo
– ZoneMinder (vidéo surveillance).
C’est très certainement insérable dans knxweb2, mais le temps que je prenne pour intégrer l’ensemble de mon cahier des charges, j’ai mieux fait de partir de zéro.
Je souhaite connaître au maximum le cheminement de mon usine à gaz pour l’adapter et la faire évoluer au grès des besoins.
Mon problème, c’est que jamais je n’arriverai à égaler la réactivité de knxweb2, mais je vais essayer de m’en approcher.
Linknx
J’ai continué l’approche sur linknx avec une page de test php, et les actions en rapports.
Ça permet de bien saisir la communication :
Clic → PHP → linknx → eibnetmux → knx → ampoule.
Mais au final, d’après ce script de test en php, ça revient à la même chose que :
Clic → PHP → Class PHP Eibnetmux → eibnetmux → knx → ampoule.
Pour linknx, la base utilise un fichier le config xml du paquet.
Pour PHP @ eibnetmux, la base utilise une base de données MySQL et des scripts.
C’est kif kif.
Entre la Class PHP KNX et l’utilisation de linknx par PHP, le fonctionnement est semblable : il y’a ouverture d’un socket pour lire et écrire les informations à la couche inférieure.
Donc pour la partie PHP → KNX, avec ou sans linknx, je ne m’évite pas du travail, ne me complique pas plus la tâche.
Pour conclure
Beaucoup de doutes et de questions.
Au jour d’aujourd’hui, je pense remplacer linknx par des scripts PHP et une base MySQL.
Ainsi que knxweb2 par une interface web perso, en sachant que je n’arriverai pas à égaler sa réactivité, mais je gagnerai en maîtrise, souplesse vis à vis de mon cahier des charges.
Interroger les sondes 1-wire par un script PHP
Un point que je n’avais pour l’instant pas abordé dans mes différents articles sur le 1-wire :
- Premiers pas avec le 1-wire et owserver sous Debian Wheezy
- Découvertes des sondes DS18B20 et DS18B20PAR
- Capteur d’ouverture de fenêtres avec un DS2406
- Capteur d’ouverture de fenêtres avec un DS2401
Je n’ai pas abordé le contrôle du 1-wire en PHP.
Pour faire quoi ?
Une grosse usine à gaz !
Utiliser PHP pour interroger les sondes 1-wire, c’est tout simplement ce qu’il y’a de plus logique dans mon projet, vue que je souhaite une interface à la knxweb2 mais home made.
L’affichage d’une température sur un plan et toute autre utilisation des mesures se fera par PHP.
Quels paquets php à installer ?
Comme vu dans la phase de découverte, owserver est désormais disponible en package compilé pour Debian Wheezy.
Pour les librairies PHP, il existe deux paquets aux noms semblables : libow-php5 et libownet-php.
Quelle différence ? La question a été posée au contributeur du package, voici sa réponse :
libownet-php ne peut que communiquer avec owserver, qui, lui-même pourra communiquer avec d’autres owserver et/ou matériel 1-wire.
libow-php5 est un wrapper autour de la bibliothèque C qui permet de communiquer directement avec le matériel 1-wire.
Alors on installe libownet-php.
Ce qui a pour effet d’installer un fichier php de class au chemin suivant :
/usr/share/php/OWNet/ownet.php
Une page d’exemple est disponible au chemin suivant :
/usr/share/doc/libownet-php/examples/ownet_example.php
Cet exemple fait référence à un fichier bcadd.php, il s’agit d’un hack car certaines versions distribuées de php ne permettent pas l’utilisation de cette fonction, fournir cette fonction par un include permet de contourner le problème. Evidemment, sous Debian Wheezy hébergement maison, ce qu’il y’a de plus classique, pas de problème avec bcadd, donc le « require » ne sera pas utilisé.
Récupérer des valeurs en PHP
Pour ce test, j’ai placé sur mon bus 1-wire :
- 1x DS18B20 : sonde de température à l’extérieur.
- 1x DS18B20+PAR : sonde de température à l’intérieur.
- 1x DS2406 : capteur d’ouverture de fenêtre.
- 1x DS2401 : capteur d’ouverture de fenêtre.
L’ensemble des fonctions ownet php sont visibles sur la page du projet :
http://owfs.org/index.php?page=ownet-php
Je récupère le fichier ownet.php, sans quoi on obtient forcément l’erreur suivante :
PHP Fatal error: Class 'OWNet' not found
Et mon index.php
<?php require "ownet.php"; $ow=new OWNet("tcp://127.0.0.1:4304"); ?> Température extérieure : <? $temp_ext = $ow->read("/28.EA54B5030000/temperature"); // Décommenter la ligne suivante pour avoir les détails du composant //var_dump($ow->dir("/28.EA54B5030000",OWNET_MSG_READ,true)); echo $temp_ext; // ------------------ ?> <br /> Température intérieure : <?php $temp_int = $ow->get("/28.919277030000/temperature",OWNET_MSG_READ,false); // Décommenter la ligne suivante pour avoir toutes les infos sur la température //var_dump($ow->get("/28.919277030000/temperature",OWNET_MSG_READ,true)); echo $temp_int; // ------------------ ?> <br /> Fenêtre DS2406 : <?php $fenetre_ds2406 = $ow->read("/12.D0457D000000/sensed.A"); // Décommenter la ligne suivant pour avoir toutes les infos sur le PIO A //var_dump($ow->get("/12.D0457D000000/sensed.A",OWNET_MSG_READ,true)); echo ($fenetre_ds2406)?"ouverte":"fermée"; // ------------------ ?> <br /> Fenêtre DS2401 : <?php $fenetre_ds2406 = $ow->presence("/01.DC4343140000"); // Décommencer la ligne suivante pour avoir les détails, minimaliste car c'est une présence //var_dump($ow->dir("/01.DC4343140000",OWNET_MSG_READ,true)); echo ($fenetre_ds2406)?"fermée":"ouverte"; // ------------------ ?> <br />
J’ai laissé les lignes var_dump commentées, elles peuvent servir de débogage.
Le port 4304 à adapter selon votre serveur owserver ( /etc/owfs.conf ).
A noter, comme vue dans mon article sur le DS2406, sensed.A retourne un 1 lorsque l’ILS est ouvert, 0 lorsque qu’un aimant est à proximité, ce qui pourrait porter à confusion.
Read et Get sont sur un bateau
Les read et le get, syntaxé comme ceci, apportent le même résultat.
$ow->get("/28.919277030000/temperature",OWNET_MSG_READ,false); $ow->read("/28.919277030000/temperature");
D’après la doc de owfs.org le get parcourt chaque valeur de l’élément désiré et y applique une fonction/constante.
Tandis que le read, récupère la valeur demandée, point final.
Dans mes tests, et pour une requête de température il s’avère que le get ne retourne pas toujours de valeurs.
Il semble fonctionner à un niveau plus « bas » que le read.
Donc la fonction read est à privilégier.
Et maintenant ?
L’insertion des données dans une base MySQL, pour un prochain article.
Configuration d’une platine de tests KNX avec ETS
ETS, le Saint Graal du KNX ! Un prix exorbitant pour le simple particulier.
Heureusement, l’association KNX s’adapte.
ETS 4 ?
KNX ETS4 eCampus est un super moyen d’apprendre le principe de programmation du KNX via ETS4.
C’est de l’e-formation bien faite.
Ça semble fastidieux, surtout lorsque les vidéos sont en anglais, la simulation en allemand et les questions en français (ça fait travailler les langues)
Tâchez d’obtenir votre diplôme avec un niveau d’apprentissage de 85 %.
La récompense ? Une licence ETS4 Lite, cette licence permet de gérer un projet de 20 éléments KNX.
Suffisant pour savoir si KNX est fait pour vous et si vous êtes fait pour KNX.
Direction l’eCampus pour tout savoir sur ETS et le KNX : http://wbt4.knx.org/
(j’espère obtenir une licence Pro avec la pub que je leur fait !)
Le seul souci est lié à l’utilisation eibnetmux, vu qu’il ne fonctionne qu’avec ETS3.
Quoi qu’il en soit, l’ETS4 eCampus permet de se familiariser avec ETS et le jour venu d’acquérir une licence.
Je n’ai pas le besoin de rédiger un article sur comment programmer une platine avec ETS4, ce genre de support reprend très bien le b-a ba de la programmation.
Commande groupée ?
Sur certains forums, sont régulièrement organisées des commandes groupées de licence ETS, ce qui permet d’obtenir pas loin de 50% de réduction.
Il faut rester à l’affût et saisir les bonnes occasions.
ETS 3 ?
Il est possible d’obtenir une licence ETS3 par l’intermédiaire d’un autre passionné de domotique, ou si vous êtes suffisamment proche de votre électricien.
Le logiciel est plus ancien, il est théoriquement plus facile d’en trouver.
De temps en temps, on retrouve des ventes eBay pour une license ETS3, de ce style :
Une opportunité à saisir.
Concernant la programmation avec ETS3, en ayant suivi les cours de l’eCampus ETS4, on s’en sort avec le 3.
Autrement, il existe un très bon dictatiel disponible sur le forum electrotechnique-fr.com.