Domotique (et toc !)

Après ce merveilleux projet de télécommande, je me suis dit que j’étais bien lancé pour continuer. Je dispose d’un Banana Pi, d’une télécommande infrarouge, que se passe-t-il si on branche tout ça sur le réseau Wi-Fi en plus ? Ca laisse le champ à des appareils qui communiquent entre eux et à des script d’automatisme ! J’ai procédé par petites étapes.

Interface web sur le Banana Pi

Je suis parti d’un tuto sur Instructables qui décrit comment faire une interface web sur un Raspberry Pi. Cela m’a permis de profiter d’1-2 scripts de base comme point de départ pour afficher l’état des prises que je commande. Le projet original utilise deux pages php et un javascript pour modifier des pins GPIO du Raspberry Pi. Moi à la place j’envoie des commandes au script que j’avais précédemment réalisé pour piloter les prises électriques. J’obtiens une jolie page web avec des boutons pour allumer ou éteindre des appareils. J’affiche la page web sur une tablette android et ça me fait un petit panneau de contrôle tactile sympa.IMG_3627A côté de ça, j’ai branché dans ma sono un petit module qui est une Google Chromecast Audio. Elle permet de lire du son depuis un appareil Android. Sur Android, j’ai installé et configuré l’application Bubble UPnP qui liste la musique présente sur mon NAS, me permet d’organiser des playlist et streame la musique sur la Chromecast.

Bubble UPnP qui lit de la musique depuis le NAS sur la Chromecast Audio

Bubble UPnP qui lit de la musique depuis le NAS sur la Chromecast Audio

Rendez vous compte de ce progrès de l’humanité ! Sans quitter mon lit je peux allumer la sono depuis la tablette et écouter de la musique. Fort bien mais j’ai envie d’aller plus loin.

Une révolution nommée ESP8266

En 2014 ont commencé à apparaitre sur des sites chinois des petits modules Wi-Fi comme l’a détecté rapidement le célèbre site de makers Hackaday. Bien que peu cher le module est resté peu ou pas documenté mais courant 2015 les succès se sont enchaîné lorsque le fabricant Espressif a sorti la documentation permettant de programmer la puce. Cela a ouvert la voie à des applications infinies. Cette puce est nommée ESP8266 et est disponible sur une variété de petites boards dont la première et la plus simple est la ESP-01.

esp8266-01

Module ESP-01

Programmer un ESP-01

Pour utiliser et programmer un ESP8266, il faut l’alimenter en 3.3v puis connecter certains pins pour décider de le faire démarrer en mode éxécution de programme ou en mode programmation. Présentation des 8 pins de l’ESP-01 :

Broches de l'ESP-01

Broches de l’ESP-01

  • RX – Receive Data (attention, respecter les niveaux logique 3.3v, intolérant au 5v)
  • TX – Transmit Data
  • CH_PH – Activation de la puce, doit être tiré à VCC pour utiliser l’ESP-01
  • RST – Reset, doit être tiré à VCC pour fonctionner, GND pour reset
  • GPIO0 – Doit être tiré à VCC au démarrage pour le mode normal, GND au démarrage pour entrer en mode programmation
  • GPIO2 – Doit être tiré à VCC au démarrage
  • VCC – 3.3v
  • GND

Pour programmer l’ESP-01 en respectant les indications des broches, j’ai réalisé le montage suivant (j’ai utilisé en pratique un programmateur USB USART 5v et un mini module qui adapte les signaux logiques de programmtion de 5v à 3.3v pour pas griller l’ESP) :
eagle_esp01Grâce aux boutons poussoir, pour programmer l’ESP-01, il suffit de maintenir reset et program en même temps, puis de relâcher reset. Ensuite, on peut envoyer un programme via notre environnement de développement préféré, par exemple, Arduino IDE qui est très simple à utiliser. Nous reviendrons sur ce module après la présentation d’un autre module : l’ESP-12E

ESP-12E

Module ESP-12E

Module ESP-12E

Les modules ESP-12E, à peine plus grands que les ESP-01 possèdent la même puce ESP8266 mais offrent à l’utilisateur bien plus de ports d’entrée sortie GPIO.
La programmation de ces modules est similaire à celle de l’ESP-01. Ce module étant adapté pour la soudure de surface, j’ai réalisé un adaptateur pour plaque d’expérimentation, qui adapte l’espacement des pins. J’ai placé le module à l’envers pour profiter du marquage des pins au dos, ce qui est bin plus pratique pour le prototypage.

Adaptateur pour ESP-12E

Adaptateur pour ESP-12E

Un ESP-12E pour commander de l’éclairage

Le projet “LEDs RGB + Arduino” m’a familiarisé avec la commande d’une bande de 5m de LEDs RGB. Je décide d’utiliser 3 ports GPIO pour commander les 3 couleurs, un port pour lire un capteur infrarouge qui télécommande les LEDs et deux ports pour commander un relais qui allume ou éteint ma lampe de chevet. Je réalise le montage sur une plaque d’expérimentation, avec les accès pour la programmation et j’obtiens un beau plat de spaghettis mais le prototype est fonctionnel.

Prototype de contrôleur d'éclairage avec programmateur UART et alimentation 3v3

Prototype de contrôleur d’éclairage avec programmateur UART et alimentation 3v3

Je programme le module pour pouvoir le commander à la fois par télécommande infrarouge et à la fois par des requêtes HTTP via Wi-Fi. Une fois satisfait, je soude les éléments sur une plaque à trous en ajoutant des headers qui permettent de brancher ou débrancher les sorties. Le module ESP eut aussi être retiré pour le reprogrammer puis réinséré.

montage soudé

montage soudé

module final

module final

Yeelight

Lampe LED RGB

Lampe LED RGB

Non content d’utiliser des ESP8266, je décide ensuite de remplacer l’ampoule de ma lampe de chevet et celle de ma chambre par des ampoules LED RGB Wi-Fi pas cher trouvées en Chine. Ce sont des Yeelight.
Ces lampes se contrôle par le cloud – chinois – depuis smartphone via l’application Yeelight. Mais on peut activer le mode développeur et envoyer des commandes directement via le réseau local. La documentation est sur leur site.
C’est on ne peut plus simple :

{id:0, “method”:”toggle”,”params”:[]} pour allumer ou éteindre

{id:0, “method”:”set_scene”,”params”:[“color”,16711680,100]} pour allumer en rouge

J’ai fait des scripts PHP, Python et C++ selon les appareils sur lesquels je suis pour envoyer des commandes aux lampes. La télécommande infrarouge et l’interface web sont adaptées et commandent tout l’éclairage.

Automatisme

Je peux désormais à l’aide d’un simple script python sur mon Banana Pi appeler des scènes d’éclairage pédéfinies ou lancer des animations lumineuses. Il m’est possible via un simple script d’allumer ma sono puis d’envoyer de la musique dessus tout en adaptant l’éclairage.

J’ai tout ce qu’il faut pour réaliser un… Emergency Party Button
Ce serait un gros bouton coup de poing dans un boitier sans fil qui, lorsque l’envie s’en fait sentir met la chambre en mode fête instantanément. Je fais un script qui lance de la musique et synchronise l’éclairage. Je m’attaque ensuite à la réalisation à l’aide d’un ESP-01.

Emergency Party Button

Je reprends le montage simple de l’ESP01 et connecte un gros bouton fin de course au pin GPIO0. Le code sur l’ESP01 ne fait que lire ce bouton et appeler le script sur le bananapi via une requête HTTP lorsqu’il est appuyé.
Je soude le montage sur une plaque à trous avec un régulateur de tension, 4 piles 1.2v et un interrupteur ON/OFF

L'électronique de l'Emergency Party Button

L’électronique de l’Emergency Party Button

Le code de l’ESP-01 est simplement le suivant :

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
ESP8266WiFiMulti WiFiMulti;

void setup(){
   pinMode(0,INPUT); // le bouton poussoir rouge
   // se connecte au Wi-Fi
   WiFiMulti.addAP("*******", "***********");
}

void loop(){
   if((WiFiMulti.run() == WL_CONNECTED) && !digitalRead(0)) {
      HTTPClient http;
      http.begin("http://192.168.1.139/partyMode.php");
      int httpCode = http.GET();
      http.end();
      delay(500);
   }
}

Je dessine ensuite en 3D un boîtier et un champignon rouge que j’imprime avec mon imprimante 3D.

button_solidworks

Dessin 3D du boîtier

IMG_3638

Le bouton et le script qu’il exécute en arrière plan

Le meilleur pour la fin la petite démo :

Télécommande universelle du pauvre

Bogoss attitude dans une documentation technique

Bogoss attitude dans une documentation technique

Un nouveau jouet

Je me suis procuré récemment un Avocent SPC810. Waah ça en jette comme ça ! Mais… c’est quoi ? C’est un appareil qui permet de gérer la puissance d’équipements dans un datacenter. Il possède 8 prises et on peut par exemple éteindre et allumer 8 serveurs à distance. Pour la gestion, on peut nommer des ports, leur donner un état au démarrage (“lorsque le courant revient, j’allume ce port ou le laisse éteint ?”), voir le courant total consommé mais aussi créer des utilisateurs, donner des droits d’accès à des utilisateurs sur des ports,…

Prises de sortie du SPC810, moniteur d'ampérage et port série

Prises de sortie du SPC810, moniteur d’ampérage et port série

Pour se connecter dessus, on utilise un port série en RS232 qui le plus souvent se trouve sur une prise DB-9. Or ici, comme c’est de coutume dans les datacenter, ils n’utilisent pas de prises DB-9, mais des câbles RJ45 pour causer en série. Les appareils récent font tout en IP via le réseau de gestion du datacenter. Le fabricant de cet appareil a prévu de vendre un appareil (chez Avocent ils appellent ça un CPS) qui fait du “serial over IP” : d’un côté de ce boîtier CPS il y a du réseau RJ45, de l’autre des ports Serial RJ45. Ce qui est fun avec ces gens qui font du série en RJ45 (Avocent, Cisco et d’autres) c’est qu’ils ne se sont pas mis d’accord pour le pinout. Un ami m’a aidé après un peu de trial and error à retrouver le pinout, et on a pu fabriquer un adaptateur DB9-RJ45 spécifique que je peux planter dans un port série DB9-USB sur le PC.

Adaptateur DB-9 RJ45

Adaptateur DB-9 vers RJ45

pinout de la prise RJ45 du SPC

pinout de la prise RJ45 du SPC

Adaptateur C13 vers T13 (suisse)

Adaptateur C13 vers T13 (suisse)

Infrared Power

Voilà mon idée avec ce machin : dans ma chambre, j’ai une télécommande infrarouge qui commande une lampe RGB autour de mon lit et ma lampe de chevet ( c’est basé sur ce projet, je ne vais pas y revenir en détails ). But : utiliser la même télécommande pour d’autres appareils dans ma chambre comme l’éclairage de mon bureau.
Et pour ce faire, je vais utiliser… un Banana Pi que j’ai sous la main. Le Banana Pi est un clone du Raspberry Pi original mais sous stéroïdes. A l’heure actuelle, il est un peu dépassé mais il possède un capteur infrarouge. Je vais m’en servir pour envoyer des commandes au SPC810.

Banana Pi dans son boîtier imprimé en 3D

Banana Pi dans son boîtier imprimé en 3D

Configuration de l’infrarouge sur le Banana Pi

Pour commencer, on vérifie que le capteur IR est reconnu sur le Banana Pi :

cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="sunxi-ir"
P: Phys=RemoteIR/input1
S: Sysfs=/devices/virtual/input/input0
U: Uniq=
H: Handlers=sysrq rfkill kbd event0
B: PROP=0
B: EV=3
B: KEY=ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe

On voit une référence à event0, on se référera par la suite à ce capteur via : /dev/input/event0

Pour trouver une télécommande qui est reconnue (là c’est la loterie mais en général ça fonctionne) on utilise evtest :

apt-get install evtest
evtest /dev/input/event0
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "sunxi-ir"
Supported events:
[...]
Properties:
Testing ... (interrupt to exit)
Event: time 1457262850.435187, type 1 (EV_KEY), code 5 (KEY_4), value 1
Event: time 1457262850.435194, -------------- EV_SYN ------------
Event: time 1457262850.686531, type 1 (EV_KEY), code 5 (KEY_4), value 0
Event: time 1457262850.686536, -------------- EV_SYN ------------
Event: time 1457262852.554246, type 1 (EV_KEY), code 9 (KEY_8), value 1
Event: time 1457262852.554255, -------------- EV_SYN ------------
Event: time 1457262852.796536, type 1 (EV_KEY), code 9 (KEY_8), value 0
Event: time 1457262852.796542, -------------- EV_SYN ------------

So far so good, il reconnait des touches de ma télécommande ! Installons lirc qui va s’occuper le lire et décoder les signaux de la télécommande :

apt-get install lirc

Edition de /etc/lirc/hardware.conf pour qu’il ressemble à :

# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS=""

#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD=false

#Don't start irexec, even if a good config file seems to exist.
#START_IREXEC=false

#Try to load appropriate kernel modules
LOAD_MODULES=true

# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="devinput"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/input/event0"
#MODULES="sunxi-ir"

# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""

Maintenant il faut configurer LIRC avec cette télécommande spécifique. Il existe une BDD de télécommandes du marché avec LIRC mais la mienne n’y figure pas, je configure quelques touches à la main. Je récupère pour commencer la configuration d’une télécommande générique :

wget http://lirc.sourceforge.net/remotes/generic/NEC.conf

Puis je lance irrecord qui est l’utilitaire de configuration :

irrecord -H devinput -d /dev/input/event0 NEC.conf

Après avoir identifié quelques touches, je me retrouve avec un fichier NEC.conf.conf (sic) qui contient des trucs du genre :

          KEY_POWER2               0x01000900000001 0x00000000000000
          KEY_POWER                0x01000500000001 0x00000000000000
          KEY_F10                  0x01000E00000001 0x00000000000000
          KEY_F11                  0x01001200000001 0x00000000000000
          KEY_F12                  0x01000A00000001 0x00000000000000

J’enlève à la main le deuxième code 0x00000000000000 et enregistre sous le nom /etc/lirc/lircd.conf
J’édite le fichier /etc/lirc/lircrc, c’est lui qui enverra les signaux vers mon script python plus tard. Je crée des blocs du style pour chaque touche que je compte utiliser :

begin
        prog = myProg
        button = KEY_F10
        config = key1
        repeat = 0
end

Voilà, lirc est configuré, on peut le redémarrer pour appliquer les changements :

service lirc restart

Test avec irw :

irw
0001000e00000001 00 KEY_F10 rgbremote
0001001200000001 00 KEY_F11 rgbremote
0001000a00000001 00 KEY_F12 rgbremote
0001000900000001 00 KEY_POWER2 rgbremote
0001000500000001 00 KEY_POWER rgbremote

Yay ! Passons à la partie Python qui fera le lien entre la télécommande et SPC810

Python, IR et Série

Python discute avec l’IR par le biais de la librairie pylirc :

apt-get install python-pylirc

et discute en série via le module PySerial.
Pour utiliser le serial, je branche mon adaptateur serial dans l’USB et regarde ce que me dit dmesg :

[   15.738687] usbserial: USB Serial Driver core
[   15.781537] usbcore: registered new interface driver ftdi_sio
[   15.809006] USB Serial support registered for FTDI USB Serial Device
[   15.830876] ftdi_sio 4-1:1.0: FTDI USB Serial Device converter detected
[   15.850186] usb 4-1: Detected FT232BM
[   15.864004] usb 4-1: Number of endpoints 2
[   15.878486] usb 4-1: Endpoint 1 MaxPacketSize 64
[   15.893360] usb 4-1: Endpoint 2 MaxPacketSize 64
[   15.908012] usb 4-1: Setting MaxPacketSize 64
[   15.928439] usb 4-1: FTDI USB Serial Device converter now attached to ttyUSB0
[   15.947323] ftdi_sio: v1.6.0:USB FTDI Serial Converters Driver

ah, il faudra donc utiliser le port /dev/ttyUSB0

Bon, on a enfin tout configuré, l’infrarouge, le serial, installé les librairies il est temps de pondre un petit code qui fait le lien entre tout ça :

import pylirc
import serial
import time

LSonAllume = False
LBureauAllume = False
sonAllume = False

#
#initialisation du serial
#
ser = serial.Serial(
        port='/dev/ttyUSB0',
        baudrate=9600,
        parity=serial.PARITY_ODD,
        stopbits=serial.STOPBITS_TWO,
        bytesize=serial.SEVENBITS
)
ser.close()
ser.open()
if ser.isOpen():
        print 'Serial connection done...'

#
#initialisation de l'infrarouge
#
pylirc.init("myProg","/etc/lirc/lircrc")

def read():
        out = ''
        while ser.inWaiting() > 0:
                out += ser.read(1)
        print out
        return out

def login():
        ser.write('\r\r')
        time.sleep(1)
        read()
        #login par défaut, j'attends le hacker
        #qui rentre dans ma chambre, se branche sur
        #le SPC, éteint la lumière et repart en ricanant
        ser.write('Admn\r')
        time.sleep(0.5)
        read()
        ser.write('admn\r') 
        time.sleep(0.5)
        read()

def toggleLSon():
        global LSonAllume
        if LSonAllume:
                ser.write('off port lson\r')
        else:
                ser.write('on port lson\r')
        time.sleep(0.5)
        read()
        LSonAllume = not LSonAllume

def toggleLBureau():
        global LBureauAllume
        if LBureauAllume:
                ser.write('off port lbureau\r')
        else:
                ser.write('on port lbureau\r')
        time.sleep(0.5)
        read()
        LBureauAllume = not LBureauAllume

def toggleSon():
        global sonAllume
        if sonAllume:
                ser.write('off port son\r')
        else:
                ser.write('on port son\r')
        time.sleep(0.5)
        read()
        sonAllume = not sonAllume

def offAll():
        global sonAllume
        global LBureauAllume
        global LSonAllume
        ser.write('off ports all\r')
        time.sleep(0.5)
        read()
        sonAllume = False
        LBureauAllume = False
        LSonAllume = False

login()
while True:
        list = pylirc.nextcode()
        if list is not None:
                for code in list:
                        if code == "key1":
                                toggleLSon()
                        if code == "key2":
                                toggleLBureau()
                        if code == "key3":
                                toggleSon()
                        if code == "powerOff":
                                offAll()

        #garder la connexion active après 5 min
        if ser.inWaiting() > 0:
                time.sleep(1)
                if(read().find('ended') != -1) : #session ended
                        print 'Reconnecting...'
                        time.sleep(1)
                        login()

A l’aide de ce script, j’ai configuré 4 nouveaux boutons sur ma télécommande : un qui allume/éteint ma sono, un qui fait la lumière au dessus de mes platines, un qui fait la lumière sur mon bureau et un OFF qui éteint tout en même temps. Combiné à l’arduino qui possède son propre capteur vers mon lit, ma télécommande est configurée comme suit :

boutons de ma télécommande multifonctions

boutons de ma télécommande multifonctions