Domotique avec raspberryPi et Domoticz

J’utilise depuis quelques mois une solution domotique qui me donne pleinement satisfaction. Cette solution relativement économique repose sur l’utilisation d’un RaspberryPi avec le logiciel Domoticz ainsi que d’un « modem » radio 433MHz RFXCom

Je ne vais pas détailler l’installation de Domoticz, tout est décrit sur leur site et l’opération reste très simple.

Mes besoins essentiels concernent les consommations de l’habitation ( eau, gaz, électricité ) et les relevés de température et humidité dans certaines pièces. De plus, je pilote quelques lumières ainsi qu’un radiateur de type sèche serviettes. Depuis quelques temps j’ai ajouté des capteurs d’ouverture sur les Vélux et les portes. Je peux ainsi savoir par une notification sur le téléphone si l’on quitte la maison avec un Vélux oublié ouvert…

La solution à base de technologie radio en 433MHz présente quelques avantages:

  • Le prix
  • Le nombre de modules disponibles sur le marché
  • La possibilité de créer facilement ses propres capteurs avec un arduino par exemple

Le gros inconvénient c’est que contrairement au Zwave, il n’y a pas de retour d’état. Pour piloter des éléments « critiques » comme le chauffage, c’est un peu gênant mais on peut y remédier d’une façon assez satisfaisante à l’aide d’un script.

Les modules que j’utilise sont disponibles facilement dans les grandes surfaces de bricolage ou sur internet.

 

Le raspberry équipé d’une carte RFM12Pi en 868MHz pour un usage futur.

RasberryPi
RaspberryPi

 

Le modem RFXCom. On pourrait en créer un avec un arduino pour beaucoup moins cher mais il faut décoder les différents protocoles ce qui m’aurait demandé trop de temps. J’ai donc préféré acheter un module « tout fait » et consacrer plus de temps sur les autres parties.

Module RFXCom
Module RFXCom

 

Des sondes de température Oregon sont disposées aux endroits stratégiques ( Salon, Salle de bain, extérieur, chambres…)

Capteur oregon de température et humidité
Capteur Oregon de température et humidité

 

Le carillon de la porte d’entrée est lui aussi compatible. Il peut donc servir d’alerte sonore si besoin, d’autant qu’il dispose de 3 mélodies utilisables avec des codes différents.

Carillion
Carillon

 

Pour les Vélux, de simples capteurs d’ouverture

Capteur d'ouverture
Capteur d’ouverture

 

Pareil pour la porte du garage

Capteur d'ouverture
Capteur d’ouverture

 

Il y a aussi un capteur de mouvement pour le déclenchement d’un éclairage et d’une notification sur smartphone

Capteur de mouvements
Capteur de mouvements

 

Les lumières sont pilotables par ces petits relais.

Module d'éclairage
Module d’éclairage

J’utilise aussi les modules d’éclairage pour piloter le sèche serviette. Attention, il faut le piloter au travers du fil pilote. Il y a une petite astuce très bien décrite sur le site d’Alexandre.

La consommation électrique est relevée par un OWL180. Une petite pince ampèremétrique branchée sur le compteur transmet la consommation en temps réel.

Consommation électrique - OWL180
Consommation électrique – OWL180

 

Un petit écran déporté affiche la consommation en temps réel

Consommation électrique - OWL180
Consommation électrique – OWL180

 

Pour le gaz, c’est un peu plus compliqué mais aussi plus amusant. Les modules du commerce sont très chers, le DIY vient à la rescousse.

Capteur DIY Gasmonitor
Capteur DIY Gasmonitor

C’est simple, un arduino relève les impulsions générées par le compteur de gaz (un aimant est placé sur la roue du compteur) et les transmet à Domoticz par radio. On peut capter les impulsions d’un compteur de gaz avec un interrupteur reed.

Par la même occasion je relève la température et l’humidité du garage avec un DHT22.

Je vais aussi ajouter la consommation d’eau un peu plus tard.

IMG_20141230_095054_

Et le circuit vraiment très simple

Sélection_023

Le schéma et le code pour programmer l’arduino sont sur Github ici. C’est une première version mais ça marche très bien.

Pour la transmission des informations, j’ai utilisé une librairie permettant de simuler un capteur de type RFXMeter et RFXSensor. Du coup domoticz détecte le capteur tout seul comme un grand. Pour les informations de température et d’humidité, j’ai plutôt utilisé le format Oregon V2 gentiment mis à disposition par Olivier ici. Le nombre d’impulsions comptées est stocké dans l’EEPROM de l’arduino toutes les heures afin de ne pas perdre les informations en cas de coupure de courant.

Un seul arduino peut donc émuler toutes les sondes possibles et imaginables. D’autant qu’il ne faut qu’un arduino et un petit transmetteur 433MHz qui coûte 2-3€ ! Pour les arduino, j’utilise des Mini Pro en 5v ou en 3.3v suivant le type d’alimentation.

 

Après les informations concernant le matériel, voilà un petit tour de ce que ça donne dans Domoticz.

 

Le dashboard
Le dashboard
Les compteurs
Les compteurs
La conso de gaz
La conso de gaz
Les rapports d'électricité avec les coûts
Les rapports d’électricité avec les coûts
La météo
La météo
Des scénarios
Des scénarios

 

Des scripts lua sont aussi possibles pour faire ce qui n’est pas possible avec l’interface web. Ici par exemple, on envoie une notification sur mobile si la porte du garage est restée ouverte. Pratique avec des enfants 😀

print(‘Porte de garage…’)

t1 = os.time()
s = otherdevices_lastupdate[‘Porte de garage’]
— returns a date time like 2013-07-11 17:23:12

year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)

commandArray = {}

t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = (os.difftime (t1, t2))
if (otherdevices[‘Porte de garage’] == ‘Open’ and difference > 300 and difference < 400) then
commandArray[‘SendNotification’]=’La porte de garage est ouverte depuis plus de 5 minutes!’

end

return commandArray

Il y a aussi des applications android / iphone pour piloter le tout avec son mobile.

Voilà un bref aperçu de ce que l’on peut faire. Tout ou presque est possible ! Si vous avez des questions sur cette solution, n’hésitez pas à laisser un commentaire 🙂

Fabriquer un lecteur de carte MicroSD pour Arduino

Pour mon projet de datalogger, il me fallait un lecteur de cartes SD ou MicroSD. N’en ayant pas sous la main, j’en ai fabriqué un à partir d’un adaptateur SD / MicroSD. Il y a plusieurs avantages à cela:

  • l’encombrement très réduit.
  • Le coût dérisoire ( < 10 € avec la carte MicroSD ).
  • la simplicité.
Attention, la tension d’alimentation et des différents signaux est en 3.3v. Ne le branchez surtout pas sur un arduino 5V sans utiliser des résistances pour réduire la tension à 3.3v !
Le projet nécessite seulement des barettes sécables males, droites ou coudées ainsi qu’un adaptateur de cartes MicroSD.
Il suffit ensuite de souder la barettes sur les contacts cuivrés de l’adaptateur.
Voilà, votre lecteur de carte est prêt à être embarqué ! Temps de réalisation: 5 min 🙂

Projet DataLogger pour vélo

Encore un projet dans les cartons. Concevoir un petit enregistreur me permettant de stocker sur une carte SD plusieurs paramètres lorsque je fais des sorties à vélo. Je souhaiterai enregistrer:

  • La date / heure
  • La position GPS
  • La vitesse
  • Le cap
  • la cadence de pédalage
  • l’accélération X Y et Z
  • la température
  • Le rythme cardiaque
L’ensemble des données sont récupérées / calculées par un Atmega 328 embarquant du code Arduino. Les données sont ensuite enregistrées sur carte SD et présentées en temps réel sur l’écran.

Voilà un schéma de principe du système. 

Arduino PhotoLab – Schéma

Comme promis, voici le schéma de la carte principale du montage Arduino PhotoLab

Je débute avec Eagle alors mon schéma n’est pas forcément très clair, mais bon…

photolab

Le voici au format Eagle

  • Prise SENSORS: branchement des capteurs
  • Prise TTL: Branchement d’un convertisseur USB/TTL pour reprogrammer l’arduino.
  • Prise STROBE: Sortie pour la prise de commande du flash ou de l’appareil photo suivant l’usage.
  • Prise POWER: Alimentation 5V par transfo ou pack de piles.

Les 4 boutons permettent de se ballader dans les menus pour choisir les capteurs et changer les valeurs.

Il reste quelques ports dispo sur l’arduino pour un usage futur…

Je n’ai pas mis le schéma des capteurs. Vous pouvez en trouver plein sur le playground arduino ici. Il suffit d’utiliser une prise jack 3.5mm male et de la brancher sur la prise SENSORS. Vous avez alors VCC,  GND, DATA. Où DATA est un voltage entre 0 et 5 v.

Je ne suis pas sûr que mon système soit utilisable tel quel chez vous, mais vous pouvez vous en inspirer pour créer le votre. En tout cas, chez moi ça marche très bien 🙂

Pour ce qui est du code, le voici:

[code]

#include <LCD4Bit.h>

//BUG ?
#undef int()
// END BUG
#include <stdio.h>

LCD4Bit lcd = LCD4Bit(2);

//#define DEBUG 1

// global defs
#define shootPin  11
#define sensorPin 4
#define bt1Pin 3
#define bt2Pin 4
#define bt3Pin 5
#define bt4Pin 6
#define ledPin 13 //digital

#define MAXMENU 4

#define MENUSENSOR 1
#define MENUSTROBEDELAY 2
#define MENURUN 3

#define MODESENSOR 1

#define NO 0
#define YES 1
#define TEST 2

#define SOUNDSENSOR 0
#define IRSENSOR 1
#define CONTACTSENSOR 2
#define LIGHTSENSOR 3

volatile unsigned int menu0Pos = MENUSENSOR;
volatile unsigned int debounce = 0;
volatile unsigned int modeSensor = 0;
volatile unsigned int modeDrop= 0;
volatile unsigned int modeApp = MODESENSOR;
volatile unsigned int sensorType = IRSENSOR;
volatile unsigned int firstPass = 0;
volatile unsigned int sndLevel = 0;

volatile int strobeDelay = 10;

void setup() {
pinMode(ledPin,OUTPUT);
pinMode(shootPin,OUTPUT);
pinMode(bt1Pin,INPUT);
pinMode(bt2Pin,INPUT);
pinMode(bt3Pin,INPUT);
pinMode(bt4Pin,INPUT);
setLed(1);
lcd.init();

/*lcd.commandWrite(0x0F);//cursor on, display on, blink on.  (nasty!)
*/
lcd.clear();
lcd.printIn(« equinoxefr.org »);
lcd.cursorTo(2, 0);  //line=2, x=0.
lcd.printIn(« Photo lab v0.3″);
delay(2000);
fillLine(2, »FW Trigger »);
delay(2000);
lcd.clear();
setLed(0);
#ifdef DEBUG
Serial.begin (9600);
Serial.println(« start »);                // a personal quirk
#endif
}

void loop() {
int val=0;
int keyFactor=1;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  SENSOR SECTION
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (modeSensor)
{
while (1)
{
val=analogRead(sensorPin);
switch (sensorType)
{
case LIGHTSENSOR:

if (val > 500)
{
shoot();
}
//      char buffer[50];
//      strobeDelay=getValue(strobeDelay,-1,9999);
//      itoa(strobeDelay,buffer,DEC);
//      fillLine(2,buffer);
break;

case IRSENSOR:

if (val < 900)
{
shoot();
}
//      char buffer[50];
//      strobeDelay=getValue(strobeDelay,-1,9999);
//      itoa(strobeDelay,buffer,DEC);
//      fillLine(2,buffer);
break;

case SOUNDSENSOR:
if (firstPass)
{
fillLine(2, »Getting snd level »);
sndLevel=soundLevel();
clearLcdLine(2);
firstPass=0;
}
val = analogRead(sensorPin);

if ((val > (sndLevel + 40)) && (val < 1024))
{
shoot();
}

break;

case CONTACTSENSOR:
if ( val < 500)
{
shoot();
}
break;
}
}
}

/*
#ifdef DEBUG
Serial.println(menu0Pos,DEC);
#endif
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  MENU SECTION
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

switch (menu0Pos)
{
case MENUSTROBEDELAY:
fillLine(1, »Strobe delay ms »);
modeSensor=0;
strobeDelay=getValue(strobeDelay,-1,9999);
if (strobeDelay==-1)
{
fillLine(2, »not used »);
}
else
{
char buffer[50];
itoa(strobeDelay,buffer,DEC);
fillLine(2,buffer);
}
break;
case MENUSENSOR:
fillLine(1, »Select sensor »);
sensorType=getValue(sensorType,0,3);
switch(sensorType)
{
case SOUNDSENSOR:
fillLine(2, »SOUND »);
firstPass=1;
break;
case IRSENSOR:
fillLine(2, »IR BARRIER »);
break;
case CONTACTSENSOR:
fillLine(2, »CONTACT »);
break;
case LIGHTSENSOR:
fillLine(2, »IR LIGHT »);
break;
}
//digitalWrite(ledPin, HIGH);
modeSensor=0;
break;

case MENURUN:
if (!modeSensor)
{
fillLine(1, »***SHOOT MODE*** »);
}
modeSensor=1;
break;
}
getMenu();
}

//
//  soundLevel()
//
int soundLevel()
{
int value=analogRead(sensorPin);

Serial.println(« Getting sound level… »);
for(int i=0; i < 50 && !modeSensor; i++)
{
value = ( value + analogRead(sensorPin) ) / 2;
delay(50);
}
Serial.println(« Done! »);

return value;

}

void clearLcdLine(int line)
{
lcd.cursorTo(line, 0);
lcd.printIn( »                     « );
}

void fillLine(int line,char* str)
{
char buffer[21];
int len=strlen(str);
for (int i=0;i<20;i++)
{
if (i < len)
{
buffer[i]=str[i];
}
else
{
buffer[i]=’ ‘;
}
}
lcd.cursorTo(line,0);
lcd.printIn(buffer);
}

void shoot()
{
if (strobeDelay > 0 )
{
delay(strobeDelay);
}
digitalWrite(shootPin,HIGH);
delay(10);
digitalWrite(shootPin,LOW);
fillLine(2, »Shoot ! »);
digitalWrite(ledPin,HIGH);
delay(3000);
digitalWrite(ledPin,LOW);
clearLcdLine(2);

}

void getMenu()
{
int bt1=digitalRead(bt3Pin);
int bt2=digitalRead(bt4Pin);

if (!bt1 && !bt2)
{
return;
}

if (bt1 && menu0Pos < MAXMENU)
{
menu0Pos++;
}
if (bt2 && menu0Pos > 0)
{
menu0Pos–;
}

}

int getValue(int value, int mini, int maxi)
{
unsigned int keyFactor=1;
int bt1=digitalRead(bt1Pin);
int bt2=digitalRead(bt2Pin);

if  (value < 50 )
{
keyFactor=1;
}
else
{
if (value >= 50 )
{
keyFactor=10;
}
}
if  ( bt1 )
{
value+=keyFactor;
}
if  ( bt2 )
{
value-=keyFactor;
}

if ( value <= mini)
{
value=mini;
}
else
{
if (value >= maxi)
{
value=maxi;
}
}
/*
if ( bt1 && bt2 )
{
modeSensor=0;
fillLine(2, »switch off »);
}
*/
return value;

}

void setLed(int value)
{
if (value)
{
digitalWrite(ledPin,HIGH);
}
else
{
digitalWrite(ledPin,LOW);
}
}
[/code]