Création d'un prototype de centrale domotique
Depuis un certain temps, je souhaite domotiser mon logement, mais comme il est trop facile d'acheter des modules tout prêts, j'ai choisi de créer ma propre centrale de domotique.
Après avoir lu l'article publié sur framboise314.fr, j'ai souhaité reprendre le mode de fonctionnement fondé sur des cartes à relais pilotant des appareils conventionnels. L'inconvénient est que le câblage de ce système doit être prévu dès le départ pour permettre cette installation. Chaque équipement doit être câblé directement et individuellement sur la carte à relais.
Ce système permet d'utiliser des interrupteurs conventionnels et autorise, moyennant un recâblage, de repasser aisément dans un mode de fonctionnement plus classique.
Habitant dans un appartement en location, j'ai donc fabriqué un prototype dans une boîte de rangement me permettant de créer la partie logicielle et d'expérimenter le système en attendant de pouvoir câbler mon logement à ma guise.
Vous pourriez me dire que ce serait plus facile en utilisant des modules sans-fil, mais non, j'aime le câblage, alors que cela ne facilite pas la mise en œuvre.
Le but de ce prototype est de simuler l'installation cible que je souhaiterais avoir.

Voici les caractéristiques de mon prototype :
- 8 relais alimentant 5 prises de courant pilotables sur lesquelles sont branchés les équipements. Les 3 relais restants me permettent d'expérimenter le fonctionnement d'appareils futurs (thermostat, volets roulants, etc.).
- 5 interrupteurs simulant ceux installés dans une maison.
- Une sortie permettant de brancher un bandeau LED.
- Le bus I2C est brassé sur une prise RJ45 me permettant de concevoir des modules externes raccordables facilement.
Fonctionnement de la centrale domotique
Le système est séparé en plusieurs briques :
- L'espace de stockage partagé
- Il s'agit d'un système de fichiers partagé avec les différents Raspberry Pi. L'état de chaque entrée et sortie est traduite par la présence ou non d'un fichier dans cet espace de stockage. Ce système permet d'avoir une installation pouvant grandir en ajoutant des Raspberry Pi supplémentaires afin d'augmenter le nombre d'entrées/sorties gérées. Plus précisément, il s'agit d'un tmpfs afin de limiter le nombre de cycles d'écriture sur les cartes SD. Il est partagé en NFS.
- L'API
- Écrite en PHP, elle assure toute l'intelligence du système. Elle est appelée par la brique d'entrée/sortie lorsqu'une entrée est activée et par une tâche cron toutes les minutes afin de déclencher les tâches planifiées. Chaque élément (étage, pièce, équipement, script) peut être appelé par l'API avec une URL dédiée.
- Le démon d'entrée/sortie
- Écrit en Python, ce démon pilote les périphériques (relais, bandeau LED, interrupteurs, etc.) et l'espace de stockage. Il crée ou supprime les fichiers dans le répertoire in en fonction de l'état des entrées et active ou désactive les sorties en fonction de la présence ou non des fichiers dans le répertoire out.
- Le client Web
- Ecrit en HTML, CSS et JS, il interroge l'API et propose une interface utilisateur simple et intuitive.
L'architecture du système se schématise comme suit :
Chaque équipement est piloté en central, ce qui implique un câblage spécifique dans le cas où le système est déployé sur un logement :
Lampes et prises de courant
Chaque lampe et chaque prise de courant sont pilotées par un relais dédié. La phase part du bornier et entre dans la borne COM du relais. La borne NO (normalement ouvert) part vers la lampe ou la prise de courant.
Le câblage obtenu est le suivant :
Volets roulants
Un volet roulant filaire dispose de 4 fils :
- Phase montée du volet
- Phase descente du volet
- Neutre
- Terre
Chaque phase est raccordée individuellement à un relais. Le neutre et la terre sont directement raccordés aux borniers.
L'allumage exclusif de chacune des phases est assuré logiciellement. Lorsque la fermeture est demandée, le relais d'ouverture est éteint, puis le relais de fermeture est allumé.
Le câblage obtenu est le suivant :
Thermostat
Le contact du thermostat est assuré par un relais. La fermeture et l'ouverture du contact sont déclenchées par la température de consigne à laquelle est ajoutée ou soustraite une marge de 1°C :
La sonde de température est assurée par l'un des capteurs météo de la maison.
Le câblage obtenu est le suivant :
Lecteur audio
Le lecteur audio est un client pour un serveur MPD. Dans ce prototype, le serveur MPD est le Raspberry Pi lui-même.
Bandeau LED
Le bandeau LED est composé de plusieurs LED RGB réglables individuellement. Chaque LED est associée à une puce WS2812B pilotable depuis un port GPIO du Raspberry Pi.
Station météo
La sonde météo BME280 connectée en I2C permet d'obtenir des informations concernant la température, l'humidité et la pression atmosphérique. Pour ce prototype, elle est déportée afin que les mesures ne soient pas faussées par la chaleur dégagée par le Raspberry Pi. Pour cela, j'ai utilisé une prise RJ45 sur laquelle est brassé le bus I2C pour faciliter la connexion :
Broche | Code couleur T568B | Usage |
---|---|---|
1 | blanc orange | Inutilisée |
2 | orange | Inutilisée |
3 | blanc vert | VCC |
4 | bleu | GND |
5 | blanc bleu | SDA |
6 | vert | SCL |
7 | blanc brun | Inutilisée |
8 | brun | Inutilisée |
Configuration de l'API
La configuration de l'API se fait dans un fichier JSON. Elle décrit la configuration des étages, des pièces et des équipements. On y retrouve également les scripts et les tâches planifiées.
Voici un exemple de configuration :
{ "floors":[ { "name":"Rez-de-chaussée", "rooms":[ { "name":"Cuisine", "icon":"kitchen", "color":"red", "items":[ { "type":"Lamp", "name":"Spots", "relay":{ "no":"spotsCuisine" } }, { "type":"Lamp", "name":"Hotte", "relay":{ "no":"lampeCuisine" } }, { "type":"PowerPlug", "name":"Lave-vaisselle", "relay":{ "no":"laveVaisselle" } }, { "type":"PowerPlug", "name":"Cafetière", "relay":{ "no":"cafetiere" } } ] }, { "name":"Salon", "icon":"livingroom", "color":"yellow", "items":[ { "type":"Lamp", "name":"Spots", "relay":{ "no":"spotsSalon" } }, { "type":"Lamp", "name":"Lampadaire", "relay":{ "no":"lampeSalon" } }, { "type":"Shutter", "name":"Volet", "relayUp":{ "no":"voletSalonOuverture" }, "relayDown":{ "no":"voletSalonFermeture" } }, { "type":"RoomWeather", "name":"Capteur météo", "no":"meteoSalon" } ] } ] }, { "name":"Premier étage", "rooms":[ { "name":"Chambre", "icon":"bedroom", "color":"blue", "items":[ { "type":"Lamp", "name":"Lampe de chevet", "relay":{ "no":"lampeChevetChambre" } }, { "type":"Shutter", "name":"Volet", "relayUp":{ "no":"voletChambreOuverture" }, "relayDown":{ "no":"voletChambreFermeture" } }, { "type":"LedStrip", "name":"Bandeau LED", "label":"bandeauLED" } ] } ] } ], "inputs":{ "interSpotsCuisine":{ "call":"/0/0/0/tooglePower" }, "interLampeCuisine":{ "call":"/0/0/1/tooglePower" }, "interScenarioNuit":{ "call":"/nuit" }, "interOuvertureVoletsSalon":{ "call":"/0/1/2/open" }, "interFermetureVoletsSalon":{ "call":"/0/1/2/close" }, "interScenarioMatin":{ "call":"/matin" }, "interLampeSalon":{ "call":"/0/1/1/tooglePower" }, "interSpotsSalon":{ "call":"/0/1/0/tooglePower" } }, "scripts":{ "matin":{ "name":"Scénario matin", "steps":[ {"action":"run","object":"/0/0/3","method":"powerOn","args":{}}, {"action":"run","object":"/0/1/2","method":"open","args":{}}, {"action":"run","object":"/1/0/0","method":"powerOn","args":{}}, {"action":"run","object":"/1/0/1","method":"open","args":{}} ], "hidden":false }, "nuit":{ "name":"Scénario nuit", "steps":[ {"action":"run","object":"/0/0/0","method":"powerOff","args":{}}, {"action":"run","object":"/0/0/1","method":"powerOff","args":{}}, {"action":"run","object":"/0/0/2","method":"powerOn","args":{}}, {"action":"run","object":"/0/0/3","method":"powerOff","args":{}}, {"action":"run","object":"/0/1/0","method":"powerOff","args":{}}, {"action":"run","object":"/0/1/1","method":"powerOff","args":{}}, {"action":"run","object":"/0/1/2","method":"close","args":{}}, {"action":"run","object":"/1/0/0","method":"powerOn","args":{}}, {"action":"run","object":"/1/0/1","method":"close","args":{}} ], "hidden":false } }, "plannedTasks":{ "arretLaveVaisselle":{ "trigger":{ "and":[ {"==":["hour",23]}, {"==":["minute",0]} ] }, "call":"/0/0/2/powerOff" }, "reveil":{ "trigger":{ "and":[ {"==":["holyday",false]}, {"==":["hour",7]}, {"==":["minute",0]} ] }, "call":"/matin/" } }, "items":[ { "type":"Thermostat", "name":"thermostatChaudiere", "relay":{ "no":"thermostatChaudiere" }, "temperatureSensorUrl":"/0/1/3" } ], "latitude":48.855, "longitude":2.2944, "timezone":1 }
Les scripts
Les scripts permettent d'appeler séquentiellement différentes adresses de l'API. Il est également possible de définir une pause entre deux appels.
Programmation d'événements
Dans la configuration du serveur, il est possible de créer des tâches planifiées selon la configuration du système. Les paramètres pouvant être utilisés sont les suivants :
- L'état des entrées/sorties
- Le temps (heure, minute, lever, azimut ou coucher du Soleil)
- La date (jour, mois, année, jours ouvrés)
Il est possible de combiner les conditions d'exécution avec les opérateurs ET et OU, et également de comparer les valeurs avec les opérateurs "égal", "différent", >, >=, <, <=, incluses ou exclues d'une liste de valeurs.
Voici un exemple de configuration permettant d'allumer la lampe de chevet (selon la configuration ci-dessus) à 7:00 tous les jours ouvrés :
"reveil":{ "trigger":{ "and":[ {"==":["holyday",false]}, {"==":["hour",7]}, {"==":["minute",0]} ] }, "call":"/1/0/0/powerOn" }
Calcul de l'heure de lever, d'azimut et de coucher de Soleil
N'ayant pas de box Internet et souhaitant un système le plus indépendant possible des API externes, j'ai donc voulu implémenter un calcul de l'heure de lever, d'azimut et de coucher du Soleil pour, par exemple, fermer les volets en fin de journée.
Pour cela, je me suis basé sur la feuille de calcul fournie par l'Agence américaine d'observation océanique et atmosphérique qui permets de calculer ces heures à partir de la latitude, la longitude et la date du jour.
Le calcul s'effectue comme suit. Les paramètres choisis sont les heures de lever, d'azimut et de coucher du Soleil pour aujourd'hui à la Tour Eiffel, exprimés en heure locale :
Tout d'abord, le calcul se fait avec les jours julien et les siècles juliens. Pour cela, on effectue la conversion en appliquant les règles suivantes :
- Soit Y l'année, M la valeur numérique du mois (1=janvier, 2=février, etc.) et D le jour.
- Si la date est au mois de janvier ou février, on retire 1 à Y et on ajoute 12 à M.
- On effectue les opérations suivantes en ne retenant que la valeur entière des divisions :
- a = Y/100 = 20
- b = a/4 = 5
- c = 2-a+b = -13
- e = 365,25×(Y+4716) = 2460689
- f = 30,6001×(M+1) = 122
- JJ = c+D+e+f-1524,5 = 2459279,5
- SJ = (JJ-2451545)/36525 = 0,21175906913073
Le calcul des heures se fait comme suit. Soit la la latitude, lo la longitude et fh le fuseau horaire du point à calculer. La lettre des variables correspond à la colonne de la feuille de calcul d'origine :
Explication | Formule | Valeur arrondie |
---|---|---|
Jour julien | Voir ci-dessus | JJ = 2459279,5 |
Siècle julien | Voir ci-dessus | SJ = 0,21 |
Moyenne géométrique de la longitude du Soleil (en degrés) | i = (280,46646+SJ×(36000,76983+SJ×0,0003032)) mod 360 | i = 343° |
Moyenne géométrique de l'anomalie du Soleil (en degrés) | j = 357,52911+SJ×(35999,05029-0,0001537×SJ) | j = 7980,65° |
Excentricité de l'orbite terrestre | k = 0,016708634-SJ×(0,000042037+0,0000001267×SJ) | k = 0,02 |
Équation du centre solaire | l = sin(j×π⁄180)×(1,914602-SJ×(0,004817+0,000014×SJ))+sin(2j×π⁄180)×(0,019993-0,000101×SJ)+sin(3j×π⁄180)×0,000289 | l = 1,69 |
Longitude solaire réelle (en degrés) | m = i+l | m = 344,69° |
Anomalie solaire réelle (en degrés) | n = j+l | n = 7982,34° |
Vecteur du rayon du Soleil (UA) | o = (1,000001018×(1-k2))/(1+k×cos(n×π⁄180)) | o = 0,99 |
Longitude apparente du Soleil (en degrés) | p = m-0,00569-0,00478×sin((125,04-1934,136×SJ)×π⁄180)) | p = 344,67° |
Écliptique de l'obliquité moyenne (en degrés) | q = 23+(26+(21,448-SJ×(46,815+SJ×(0,00059-SJ×0,001813)))/60)/60 | q = 23,44° |
Correction de l'obliquité (en degrés) | r = q+0,00256×cos((125,04-1934,136×SJ)×π⁄180) | r = 23,44° |
Ascention solaire réelle (en degrés) | s = (atan2(cos(p×π⁄180),cos(r×π⁄180)×sin(p×π⁄180)))×180⁄π | s = 104,11° |
Déclinaison du Soleil (en degrés) | t = (asin(sin(r×π⁄180)×sin(p×π⁄180)))×180⁄π | t = -6,03° |
var y | u = tan((r/2)×π⁄180)×tan((r/2)×π⁄180) | u = 0,04 |
Équation du temps (en minutes) | v = 4(u×sin(2i×π⁄180)-2k×sin(j×π⁄180)+4k u×sin(j×π⁄180)×cos(2i×π⁄180)-1⁄2u2×sin(4i×π⁄180)-5⁄4k2×sin(2j×π⁄180))×180⁄π | v = -11,58 minutes |
Angle horaire de lever du Soleil (en degrés) | w = (acos(cos(90,833×π⁄180)/(cos(la×π⁄180)×cos(t×π⁄180))-tan(la×π⁄180)×tan(t×π⁄180)))×180⁄π | w = 84,33° |
Azimut (en fraction de jour julien) | x = (720-4lo-v+fh×60)/1440 | x = 0,54 |
Lever (en fraction de jour julien) | y = (1440x-4w)/1440 | y = 0,31 |
Coucher (en fraction de jour julien) | z = (1440x+4w)/1440 | z = 0,78 |
La conversion d'une fraction de jour julien (noté fJJ) en heure lisible se fait comme suit :
- heures = valeur entière(24×fJJ)
- minutes = valeur entière(1440×(fJJ-heures/24))
- secondes = valeur entière(86400×(fJJ-heures/24-minutes/1440))
Pour la journée du samedi 6 mars 2021, les heures sont les suivantes :
- Lever du Soleil
- 07:25:04
- Azimut du Soleil
- 13:02:24
- Coucher du Soleil
- 18:39:43
L'utilisation de ces heures dans les scripts se fait en vérifiant que les booléens sunrise
(lever de Soleil), sunnoon
(azimut) et sunset
(coucher de Soleil) soient vrais.
Calcul des jours fériés mobiles
En plus des fêtes fixes (8 mai, 14 juillet, 11 novembre, etc.), nous avons des fêtes dites mobiles (car leurs dates varient chaque année). C'est le cas pour Pâques, le Lundi de Pâques, l'Ascension et la Pentecôte. Cependant, il est possible de déterminer, à partir de la date de Pâques, la date du Lundi de Pâques (le lendemain), de l'Ascension (40 jours après Pâques) et de la Pentecôte (50 jours après Pâques).
Pour calculer la date de Pâques, on utilise l'algorithme de Butcher-Meeus. Pour cela, on applique les opérations suivantes. Les valeurs données sont celles pour l'année 2021 :
Dividende | Diviseur | Quotient | Reste | Explication |
---|---|---|---|---|
Année = 2021 | 19 | n = 7 | Cycle de Méton | |
Année = 2021 | 100 | c = 20 | u = 21 | Centaine et rang de l'année |
c | 4 | s = 5 | t = 0 | Siècle bissextile |
c + 8 | 25 | p = 1 | Cycle de proemptose | |
c - p + 1 | 3 | q = 6 | Proemptose | |
19n + c - s - q + 15 | 30 | e = 7 | Epacte | |
u | 4 | b = 5 | d = 1 | Année bissextile |
2t + 2b - e - d + 32 | 7 | L = 6 | Lettre dominicale | |
n + 11e + 22L | 451 | h = 0 | Correction | |
e + L - 7h + 114 | 31 | m = 4 | j = 3 | Mois et quantième du Samedi saint |
- Si m = 3, le dimanche de Pâques est le (j + 1) mars.
- Si m = 4, le dimanche de Pâques est le (j + 1) avril.
Pour l'année 2021, les dates des jours fériés mobiles sont :
- Pâques
- Dimanche 4 avril 2021
- Lundi de Pâques
- Lundi 5 avril 2021
- Ascension
- Jeudi 13 mai 2021
- Pentecôte
- Dimanche 23 mai 2021
Matériel
Pour concevoir ce prototype, j'ai utilisé les éléments suivants. Je donne cette liste à titre indicatif et vous êtes libres de l'adapter à votre guise :
Produit | Fournisseur | PU | Quantité | Total |
---|---|---|---|---|
Boîte de rangement | Leroy Merlin | 3,95 € | 1 | 3,95 € |
Prise femelle | Leroy Merlin | 2,18 € | 5 | 10,90 € |
Câble électrique | Leroy Merlin | 9,90 € | 1 | 9,90 € |
Fil électrique | Leroy Merlin | 7,55 € | 1 | 7,55 € |
Bornier automatique 5 entrées | Leroy Merlin | 5,90 € | 2 | 11,80 € |
Raspberry Pi 3B | Amazon | 39,98 € | 1 | 39,98 € |
Carte SD 16 Go | Amazon | 9,07 € | 1 | 9,07 € |
Alimentation 5V 8A | Amazon | 20,27 € | 1 | 20,27 € |
Carte de 8 relais 5V avec opto-coupleurs | Amazon | 9,99 € | 1 | 9,99 € |
Modules I/O I2C PCF8574 (lot de 2) | Amazon | 6,38 € | 1 | 6,38 € |
Interrupteurs à bascule (lot de 10) | Amazon | 8,99 € | 1 | 8,99 € |
Fils Dupont (lot de 120) | Amazon | 6,99 € | 1 | 6,99 € |
Prises RJ45 femelles (lot de 5) | Amazon | 7,99 € | 1 | 7,99 € |
Capteur météo I2C (température, humidité, pression) BME280 | Amazon | 7,99 € | 1 | 7,99 € |
Horloge temps réel I2C DS3231 | Amazon | 6,29 € | 1 | 6,29 € |
Bandeau 60 LED RGB 1m WS2812B | Amazon | 13,99 € | 1 | 13,99 € |
Total | 182,03 € |
J'ai également utilisé un cordon d'alimentation standard pour tout alimenter. Le choix de ce modèle de Raspberry Pi est motivé par la présence du module WiFi inclus qui me permet de créer un réseau qui lui est propre (et aussi parce que j'en avais un inutilisé sous la main).
L'outillage nécessaire pour réaliser ce prototype est le suivant :
- Perceuse
- Fer à souder
- Pince à dénuder
- Pince coupante
- Tournevis
- Bistouri
Câblage des composants
Voici le câblage final des différents composants du prototype :
Le code
Le système est composé de trois briques logicielles. La communication entre l'API et le démon d'entrée/sortie est assurée par le système de fichiers partagé. Cela permet de partager simplement l'état du système entre plusieurs Raspberry Pi et avoir ainsi un système extensible à volonté : on ajoute des Raspberry Pi avec des modules ad-hoc pour augmenter le nombre d’éléments pilotés.
Le client Web appelle l'API pour connaître l'état du système et envoyer des ordres. Cela me permet de créer différents systèmes pouvant dialoguer avec le système de domotique en appelant l'API pour ajouter des fonctionnalités.
Le démon d'entrée/sortie
Il s'agit d'une boucle qui lit l'état des entrées du module I/O I2C (adresse 0x21) et qui, en fonction de la configuration renseignée dans le fichier io.json, crée les fichiers adéquats dans le répertoire in. A l'inverse, si le fichier adéquat existe dans out, la sortie ad-hoc sur le second module (adresse 0x20) est activée. C'est également durant cette boucle que les valeurs de température, d'humidité et de pression atmosphérique sont lues, si le champ roomWeather
est renseigné. Enfin, le bandeau LED est piloté en fonction des paramètres du fichier dans le répertoire out.
Voici un schéma de fonctionnement du démon d'entrée/sortie :
Voici un exemple de configuration :
{ "in":{ "1":"interSpotsCuisine", "2":"interLampeCuisine", "3":"interScenarioNuit", "4":"interOuvertureVoletsSalon", "5":"interFermetureVoletsSalon", "6":"interScenarioMatin", "7":"interLampeSalon", "8":"interSpotsSalon" }, "out":{ "1":"spotsCuisine", "2":"spotsSalon", "3":"laveVaisselle", "4":"lampeCuisine", "5":"cafetiere", "6":"lampeSalon", "7":"voletSalonOuverture", "8":"voletSalonFermeture" }, "roomWeather":"meteoSalon", "ledStrip":{ "label":"bandeauLED", "leds":60 } }
L'API
L'API représente chaque élément (objet, étages, pièces, tâches, etc.) sous la forme d'objets. Chaque objet est capable d’être appelé par une URL sous la forme suivante : /etage/piece/objet/methode
(exemples : /0/0/0/powerOn
pour allumer les spots de la cuisine, /1/0/powerOff
pour éteindre tous les équipements de la chambre). Si la méthode n'est pas mentionnée, il s'agit de la méthode returnData
qui est appelée. Elle permet de retourner l'état de l'objet.
Il est possible d'obtenir l'état de tous les objets enfants en appelant l'objet parent. Cela limite les appels de l'API.
Voici un exemple de retour fait par l'API. Ici, il s'agit de l'état de l'ensemble du système (/returnData
) :
{ "url": "/", "floors": [ { "url": "/0", "id": 0, "name": "Rez-de-chaussée", "rooms": [ { "url": "/0/0", "id": 0, "name": "Cuisine", "icon": "kitchen", "color": "red", "items": [ { "url": "/0/0/0", "id": 0, "name": "Spots", "scripts": [], "relay": { "no": "spotsCuisine", "status": false }, "status": false, "type": "Lamp", "defaultMethod": "tooglePower" }, { "url": "/0/0/1", "id": 1, "name": "Hotte", "scripts": [], "relay": { "no": "lampeCuisine", "status": true }, "status": true, "type": "Lamp", "defaultMethod": "tooglePower" }, { "url": "/0/0/2", "id": 2, "name": "Lave-vaisselle", "scripts": [], "relay": { "no": "laveVaisselle", "status": true }, "status": true, "type": "PowerPlug", "defaultMethod": "tooglePower" }, { "url": "/0/0/3", "id": 3, "name": "Cafetière", "scripts": [], "relay": { "no": "cafetiere", "status": false }, "status": false, "type": "PowerPlug", "defaultMethod": "tooglePower" } ], "scripts": [] }, { "url": "/0/1", "id": 1, "name": "Salon", "icon": "livingroom", "color": "yellow", "items": [ { "url": "/0/1/0", "id": 0, "name": "Spots", "scripts": [], "relay": { "no": "spotsSalon", "status": false }, "status": false, "type": "Lamp", "defaultMethod": "tooglePower" }, { "url": "/0/1/1", "id": 1, "name": "Lampadaire", "scripts": [], "relay": { "no": "lampeSalon", "status": false }, "status": false, "type": "Lamp", "defaultMethod": "tooglePower" }, { "url": "/0/1/2", "id": 2, "name": "Volet", "scripts": [], "relayUp": { "no": "voletSalonOuverture", "status": false }, "relayDown": { "no": "voletSalonFermeture", "status": false }, "type": "Shutter", "opened": true }, { "url": "/0/1/3", "id": 3, "name": "Capteur météo", "scripts": [], "type": "RoomWeather", "temperature": 22.8, "humidity": 47.5, "pressure": 991.3, "call": "/0/1/3/updateWeather" } ], "scripts": [] } ], "scripts": [] }, { "url": "/1", "id": 1, "name": "Premier étage", "rooms": [ { "url": "/1/0", "id": 0, "name": "Chambre", "icon": "bedroom", "color": "blue", "items": [ { "url": "/1/0/0", "id": 0, "name": "Lampe de chevet", "scripts": [], "relay": { "no": "lampeChevetChambre", "status": false }, "status": false, "type": "Lamp", "defaultMethod": "tooglePower" }, { "url": "/1/0/1", "id": 1, "name": "Volet", "scripts": [], "relayUp": { "no": "voletChambreOuverture", "status": false }, "relayDown": { "no": "voletChambreFermeture", "status": false }, "type": "Shutter", "opened": true }, { "url": "/1/0/2", "id": 2, "name": "Bandeau LED", "scripts": [], "type": "LedStrip", "label": "bandeauLED", "colors": [], "mode": "plain" } ], "scripts": [] } ], "scripts": [] } ], "scripts": [ { "label": "matin", "name": "Scénario matin" }, { "label": "nuit", "name": "Scénario nuit" } ], "inputs": [ { "no": "interSpotsCuisine", "status": false, "call": "/0/0/0/tooglePower" }, { "no": "interLampeCuisine", "status": false, "call": "/0/0/1/tooglePower" }, { "no": "interScenarioNuit", "status": false, "call": "/nuit" }, { "no": "interOuvertureVoletsSalon", "status": false, "call": "/0/1/2/open" }, { "no": "interFermetureVoletsSalon", "status": false, "call": "/0/1/2/close" }, { "no": "interScenarioMatin", "status": false, "call": "/matin" }, { "no": "interLampeSalon", "status": false, "call": "/0/1/1/tooglePower" }, { "no": "interSpotsSalon", "status": false, "call": "/0/1/0/tooglePower" } ], "items": { "2": { "type": "Thermostat", "relay": { "no": "thermostatChaudiere", "status": false }, "temperatureSet": 21, "temperatureSensorUrl": "/0/1/3", "scripts": [] } } }
Ce mode de fonctionnement permet à n'importe quel script ou application de s'interfacer avec le système de domotique sans avoir à recréer d'interface particulière.
Une tâche cron
est exécutée toutes les minutes et appelle l'API via une méthode particulière. Cette méthode vérifie les paramètres de chaque tâche planifiée décrite dans la configuration et les exécute si toutes les conditions sont remplies.
Le client Web
Le client Web est optimisé pour une utilisation sur mobile. La mise à jour de l'état des objets (allumage d'une lampe, fermeture d'un volet, etc.) est transmise à chaque client connecté à l'API par Server Side Events. Une mise à jour de l'état du système est également envoyée toutes les minutes pour maintenir la connexion.



Les icônes utilisées par le client sont de ma création. Elles sont disponibles au téléchargement au format SVG et sous licence CC BY-SA :