Le Blog de C-quad

Archive pour juin 2014

Domotiser un poêle à granulés ( partie 2 : Le code )

Nous avons vu dans un précédent article le montage électronique pour contrôler le poêle grâce à un raspberry et un potentiomètre digital. Nous allons voir maintenant le code utilisé pour cela.

Nous allons avoir 2 processus qui tournent en tache de fond :

  • L’alimentation en continu de la température en faisant varier la résistance du potentiomètre digital.
  • L’interface web qui me permettra de piloter tout cela.

J’ai choisi de tout programmer en python pour diverses raisons. La principale étant que je ne connais pas et que le meilleur moyen d’apprendre est d’avoir quelque chose de concret à réaliser. Il se peut donc qu’il y ai des améliorations à apporter au code qui vous sera présenté ci dessous.

Communication avec le potentiomètre digital

Le potentiomètre digital choisi est le MCP4162. Voici la datasheet de ce potentiomètre.

Comme vous pourrez le constater, ce potentiomètre communique via SPI. J’ai choisi d’utiliser la librairie python spidev.

import spidev

# Ouverture du bus SPI
spi = spidev.SpiDev()
spi.open(0,0) # car j'utilise la pin CE0: serait spi.open(0,1) si j'utilisais la pin CE1

# Transfert de la temperature (plus exactement un pas sur le digipot)
resp = spi.xfer2([0, index])

Dans notre cas, le potentiomètre digital possède 256 valeur de 0 à 255, index prendra l’une de ces 256 valeurs.

Ce qui donne le code complet :

!/usr/bin/python
# -*- coding: utf-8 -*-
 
import spidev
import time
import urllib2
import json

# Ouverture du bus SPI
spi = spidev.SpiDev()
spi.open(0,0) # car j'utilise la pin CE0: serait spi.open(0,1) si j'utilisais la pin CE1

coeff = 0.087
TEMP_OFF = 25
CONSIGNE_POELE = 19

try:
    while True :
        content = urllib2.urlopen("http://ip_raspberry:5000/status").read()
        d = json.loads(content)    
        print d
        if d[u'Etat'] == u'off' :
            print "poele eteint"
            index = 0
        else :
            print "poele allume"
            print (d[u'Temperature']- d[u'Consigne'] + CONSIGNE_POELE)
            index = int((TEMP_OFF - (d[u'Temperature']- d[u'Consigne'] + CONSIGNE_POELE))/coeff)
            if index < 0 :
                index = 0
            if index > 255 :
                index = 255
        resp = spi.xfer2([0, index])
        time.sleep(10)

finally:
    spi.close()

Voici le code, celui ci n’est pas indépendant du service web. C’est grâce au service web que cette boucle déduit la température à donner au poêle.

L’appel au « status » retourne le json suivant :

{
  "Consigne": 19.0, 
  "Etat": "on", 
  "Exterieur": 17.6, 
  "Temperature": 23
}

Ce json est ensuite converti en dict pour être utilisé simplement dans la suite du traitement.

On demande au poêle de se mettre en route si la température est inférieure à 19°C. La température dans la pièce est actuellement de 23°C. La température extérieure n’est actuellement pas utilisée, elle le sera peut-être plus tard si je trouve comment l’utiliser convenablement.

L’interface web

Pour l’interface web, j’ai fait le choix d’utiliser Flask.

L’objectif est de pouvoir piloter le poêle directement depuis un smartphone, ou de pouvoir l’inclure dans ma solution domotique existante (Zibase pour le moment).

Récupération de la température

La température de la pièce est fournie par la station météo Netatmo, qui fournit une API. j’utilise une API python déjà existante.

Ce qui se traduit par le bout de code suivant:

# Connexion à la Netatmo
authorization = lnetatmo.ClientAuth()
devList = lnetatmo.DeviceList(authorization)

#Récupération de la température
temperature_interieur = devList.lastData()[u'Intérieur']['Temperature']
temperature_exterieur = devList.lastData()[u'Extérieur']['Temperature']

Communication avec la zibase

Je veux pouvoir connecter le poêle à la zibase, parce que celle-ci fournit directement une fonctionnalité de thermostat.

En réalité ce dont j’ai besoin que la zibase connaisse, c’est la température relevée par la station météo Netatmo.

La Zibase peut peut effectuer des commandes http, mais elle est plutôt limitée de ce coté. Elle sait lire du XML. Le service web fourni donc une page qui transforme le dict retourné par l’API netatmo en XML compréhensible par la Zibase.

#Appel par la zibase pour récupérer les infos de la Netatmo    
@app.route("/netatmo")
def netatmo():
    global devList
    xml = unicode(dicttoxml(devList.lastData()), "utf-8")
    xml = re.sub(r" type=(.*?)>",">",xml)
    xml = unicodedata.normalize('NFKD', xml).encode('ascii','ignore')
    return Response(xml, mimetype='text/xml')

Pour simplifier la configuration coté Zibase, j’ai retiré les accents par exemple « Extérieur » devient « Exterieur » et simplifier au maximum le xml produit en retirant les types.

La zibase ne permet que d’allumer/éteindre, j’ai donc un service qui recoit le on/off :

#Appel par la zibase pour allumer/eteindre le thermostat    
@app.route("/thermostat/<consigne>")
def thermostat(consigne):
    global VAR_ZIBASE_TEMP_INT
    global VAR_ZIBASE_CONSIGNE
    global zibase_control
    global Statut
    if zibase_control :
        Statut['Etat'] = consigne
        content = urllib2.urlopen("http://ip_zibase/sensors.xml").read()
        root = ET.fromstring(content)
        for var in root.iter('var'):
            if var.attrib['num'] == VAR_ZIBASE_TEMP_INT :
                Statut['Temperature'] = float(var.attrib['val'])/10
            if var.attrib['num'] == VAR_ZIBASE_CONSIGNE :
                Statut['Consigne'] = float(var.attrib['val'])/10
    return "OK"

Par contre, heureusement pour moi, les variables qui servent au thermostat de la zibase, sont accessibles dans sensors.xml. J’utilise ElementTree pour lire ce XML et affecter mes variables gloables qui sont retournées dans la page status (utilisée par l’autre processus).

Le statut global

C’est donc dans les variables globales du service Web que l’état du poêle est connu : température de la pièce, température demandée, thermostat activé ou non, température extérieure.

@app.route(« /status »)
def status():
global Statut
Statut[‘Temperature’] = devList.lastData()[u’Intérieur’][‘Temperature’]
Statut[‘Exterieur’] = devList.lastData()[u’Extérieur’][‘Temperature’]
return jsonify(**Statut)

Cette page status se contente donc juste d’afficher un json du dict global qui contient toutes les infos nécessaires.

Interface indépendante de la zibase

Parce que je n’ai pas envie de dépendre uniquement de la zibase, j’ai aussi réalisé une petite interface web. J’utilise Jquery Mobile pour que celle ci soit accessible de n’importe quel type de matériel que ce soit mon ordinateur, smartphone ou tablette.

Voici un petit aperçu de cette page :

Capture d'écran de 2014-06-19 14:13:14

Comme vous pouvez le constater, l’interface web prend en compte le niveau de granulés dans la réserve. Cela sera réalisé via un émetteur à ultra-son HC-SR04.

Mais au même titre qu’il me manque un boitier pour le raspberry qui accueille la Pi Plate, il me manque aussi une mise en place discrète sous le couvercle des granulés de l’émetteur à ultra-son.

Il est bien souvent plus simple de faire les prototypes et de programmer que d’intégrer cela proprement chez soi.

 

Domotiser un poêle à granulés ( partie 1 : Le montage )

Ma maison est une maison récente, mais dont la seule source d’énergie est l’électricité. Le chauffage était donc un plafond rayonnant au rez de chaussée et des « grilles pains » à l’étage.

Je n’ai aucun reproche à faire à la chaleur et le confort procuré par le plafond rayonnant, par contre, d’après nos estimations nous pensons être environ à 900€ de chauffage par an (comparaison de la consommation hiver/été). Nous avons donc pris la décision d’installer un poêle à pellets pour réduire cette facture et le plaisir de voir une flamme.

Notre choix s’est porté sur le CMG Dual :

Poêle à granulés CMG Dual

Ce poêle présente l’avantage d’être plutôt silencieux. Il était hors de question qu’il nous réveille en se mettant en route le matin.

Ce poêle a néanmoins 2 défauts (qui sont liés) :

  1. La sonde de température est filaire. De ce fait, elle est perturbée par la chaleur dégagée par le poêle en fonctionnement.
  2. La programmation est hebdomadaire, il n’est pas possible de programmer un allumage à une date précise ou dans X jours (exemple retour de vacances etc).

Voila donc pourquoi domotiser le poêle !

Domotiser le poêle

Les objectifs

Objectif numéro 1 : Faire en sorte que la température remontée au poêle ne soit plus perturbée par le fonctionnement du poêle.

Objectif numéro 2 : Pouvoir programmer le poêle plus finement.

Comment ?

CMG ne fourni pas à ce jour de solutions pour rendre connecté son matériel. Il ne me reste donc qu’a bidouiller avec ce que j’ai et mes connaissances.

Le gros point noir que j’ai c’est une sonde filaire.

Comment faire pour remplacer une sonde filaire par une sonde distante ?

Il existe deux types de sondes filaires, les sonde numériques et les sondes analogiques. La mienne ne possède que 2 files et a une résistance variable en fonction de la température constatée.

La première étape est donc de débrancher cette sonde et de prendre un ampèremètre pour mesurer la résistance de celle-ci. Cela me donne une résistance d’environ 12kohm.

Deuxième étape : je décide de remplacer cette sonde par un potentiomètre classique de 10 kohm avec en série une résistance de 10kohm. Il me reste maintenant à faire varier le potentiomètre, noter la température donnée par le poêle, débrancher et mesurer pour avoir la résistance équivalente.

Ce qui donne ces quelques mesures :

8°C       = 19,7 kohm
18,1 °C = 13    kohm
18,4 °C = 12.9 kohm
20 °C    = 12   kohm
25 °C    = 10   kohm

La solution : remplacer ce potentiomètre analogique, par un potentiomètre digital.

Le matériel

L’objectif est de pouvoir connecter le poêle pour qu’il soit contrôlable à la fois via un PC ou Smartphone. Il me fallait donc une connexion sans fil. Mon choix s’est donc porté sur :

  • Un raspberry PI
  • Une clé USB wifi
  • Un potentiomètre digital MCP 4162

Et pour les tests :

  • Un ampèremetre
  • Un Pi Cobler
  • Une breadbord (platine d’essai)
  • des fils 😉

Au départ je n’était pas parti sur ce potentiomètre, mais sur un AD5175 qui présente l’avantage d’avoir un pas de 1024 alors que celui-ci n’a que 256 valeurs possibles. Mais il présente l’avantage d’être dans un format qui me permet de le tester facilement sur une platine d’essai. Et surtout n’ayant jamais soudé, au plus simple au mieux.

Le montage

Voila donc une photo du prototype.

Le montage d’essai

Ce qui donne les schémas suivants :

raspberry_digipot_bb

 

raspberry_digipot_schéma

Voila pour le montage.

Résumé

Donc pour résumer, nous utilisons un potentiomètre digital connecté via SPI au Raspberry PI. Ce potentiomètre remplace la sonde filaire du poêle et lui indique la température. Nous allons jouer sur cette température pour alluer ou non le poêle.

Au niveau du poêle, il sera toujours allumé avec une température demandée à 19°C. Si on veut que le poêle se coupe, on fait croire à celui-ci qu’il fait 25°C dans la pièce sinon on lui envoie la température relevée par une sonde déportée. Dans mon cas je récupère la température via la station netatmo.

Dans le cas d’un poêle à granulé, il est impossible de le faire fonctionner en on/off parce que la quantité de granulés consommée par le poêle est variable en fonction de l’écart entre la température constatée et la température demandée. Il est donc nécessaire de prendre cela en compte.

Reste à faire

Comme vous pouvez le constater, actuellement le WAF n’est pas au rendez vous 😉

J’ai donc acheté une Pi plate :

http://www.adafruit.com/products/801

http://www.adafruit.com/products/801

Je cherche encore un boitier qui peut accueillir le raspberry et la Pi plate que je puisse facilement attacher derrière le poêle.

A suivre : Le code utilisé pour que tout cela fonctionne 😉