Où sommes nous ?

Retour

Passerelle entre des flux MQTT et une base de données

Ma solution domotique est majoritairement basée sur l'échange de flux MQTT. Avec l'ajout de sondes déportées à base d'ESP8266, c'est rapidement posé la question de savoir comment intégrer ces données dans la BDD de Domestik sans faire une usine à gaz : Lua a été une fois de plus la solution.

Dans ce billet, évidemment lié à mon installation Domotique, je vais souscrire aux topics température et humidité provenant de mon poulailler (un article est à venir lors que ma solution sera finalisée) pour les insérer dans la base de données de Domestik.
Ces topics étant :

Poulailler/Perchoir/Temperature
Poulailler/Perchoir/Humidite

A noter que ce billet n'est qu'un exemple se focalisant sur le coeur de la question posée : Domestik a un compagnon nommé FeedFromMqtt plus complet, ajoutant en particulier le mécanisme qui permet d'indiquer que le client est vivant.

Les dépendances

MQTT

Le sujet ayant été déjà abordé, je vous renvoie à mes billets précédents concernant :

Connexion avec une base de données PostgreSQL

Parmi la flopée de bibliothèques permettant de se connecter à une base PostgreSQL, j'ai choisi (arbitrairement) pgmoon et, à l'heure où j'écris ces lignes, m'apporte entièrement satisfaction.

L'installation s'est faite par un classique

luarocks install pgmoon

Programmons

Le script débute évidemment par le shebang pointant sur l'interpréteur Lua (il est bien évident qu'en fonction de votre système, il faudra peut-être le changer)

#!/usr/bin/lua

suivit de prêt par l'inclusion des bibliothèques.

--[[
-- mqtt2psql
--
-- Subscribes to MQTT topics and insert them in a PostgreSQL database
--
-- 01/03/2018 - Start of dev
]]

local MQTT = require "paho.mqtt"
local posix = require "posix"
local pgmoon = require "pgmoon"

Mais pourquoi Posix ?
Comme nous le verrons par la suite, nous avons besoin de créer une attente dans notre script donc d'un sleep() quelconque.

Définitions des topics

Pour définir les topics, nous utiliserons un tableau associatif dont

local topics = {
['Poulailler/Perchoir/Temperature'] = "INSERT INTO domestik.probe_hardware VALUES ('Poulailler', 'Temperature', %f, false, now() );",
['Poulailler/Perchoir/Humidite'] = "INSERT INTO domestik.probe_hardware VALUES ('Poulailler', 'Humidite', %f, false, now() );",
}

Connectons-nous à la base de données

pgmoon.new() établie la connexion et accepte pas mal d'options (utilisateur, cryptage, ...). Ici, à nouveau, nous faisons simple en ne spécifiant que la base.

local pg = pgmoon.new( {
database = "www"
})

De même plutôt qu'un assert() brutal, on prévoira sans doute une méthode plus civilisée pour gérer un éventuel échec de la connexion.

assert(pg:connect())

Voilà, la base est à nous .

Le callback

La fonction dite de callback est appelée à chaque fois qu'un message arrive : c'est ici que se trouve notre code d'insertion dans la base.

local callback = function(tpc, payload)
print(string.format(topics[tpc], payload))
assert( pg:query( string.format(topics[tpc], payload)) );
end

Le dit code se résume à un simple string.format() qui transformera le fameux %f en la valeur a insérer et à pg:query() qui lancera la requête côté PostgreSQL. Comme précédemment, on gagnera à remplacer l'assert() par quelque chose de plus malin et la ligne avec le print() ne sert qu'à nous montrer qu'il se passe quelque chose.

Notez-bien

Lua n'étant pas multi-threadé, ce callback bloque toute autre activité de notre script : il doit donc être le plus rapide possible.

Connexion au bus MQTT

On crée le client MQTT

local client = MQTT.client.create('votre_serveur.votre_reseau', 1883, callback)

en spécifiant

En on se connecte en indiquant cette fois le nom de notre client ; ce nom se doit d'être unique parmi tous les clients connecté à ce broker.

client:connect('MQTTBridge')

Souscription

Dernière étape : souscrire aux topics qui nous intéressent.

local tpc = {}
for k,v in pairs(topics) do
table.insert( tpc, k )
end
client:subscribe(tpc)

La boucle infinie

Lua n'étant pas multi-threadé, il faut lui créer une boucle d'attente active.

while true do
        client:handler()
        posix.sleep(1)
end

Résultat

Et bien, rien à redire : ça fonctionne très bien.

Du coup, ce n'est plus le démon dmkcheckd qui lit les températures de la maison pour Domestik, mais un script de ce genre qui les récupère depuis Marcel. Non seulement ça évite de faire 2 fois la même chose, mais en plus, la configuration en est simplifiée : tout se fait dans celle de Marcel.


Visitez :
La liste de nos voyages
Nos sorties Ski et rando
Copyright Laurent Faillie 2001-2018
N'oubliez pas d'entrer le mot de passe pour voir aussi les photos perso.
Contactez moi si vous souhaitez réutiliser ces photos et pour les obtenir avec une plus grande résolution.
Visites durant les 7 derniers jours Nombre de visites au total.

Vous pouvez laissez un commentaire sur cette page.