MQTT API
Qui viene descritto come connettere dispositivi di qualsiasi tipo, in grado di comunicare con il protocollo MQTT.

Requisiti

Affinché possiate integrare i vostri dispositivi è necessario aver configurato come scheda Master una delle nostre schede o un nostro dispositivo Gateway.

MQTT

MQTT è l’acronimo di Message Queuing Telemetry Transport e indica un protocollo di trasmissione dati TCP/IP basato su un modello di pubblicazione e sottoscrizione che opera attraverso un apposito Message Broker.
La scheda Master del Sistema (o il Gateway che forniamo in impianti privi di schede) fa le veci del Broker, quindi il dispositivo è ad essa che si deve connettere.

Connessione al Broker

Dall'applicazione tecnico potete ottenere l'indirizzo IP della scheda Master, quindi per la connessione al Broker è sufficiente definire:
  • Porta: 1883
  • Indirizzo Server: IP scheda Master
Consigliamo di impostare un indirizzo IP statico per la scheda Master, per evitare che questo cambi in seguito a riavvii della scheda o del router.

Publish

I topic per la pubblicazione degli stati non devono avere un formato particolare, ma è importante che siano univoci per ciascun input e output che desiderate integrare; è invece importante che il messaggio contenga soltanto il valore.
Quindi se vogliamo integrare un sensore di temperatura, il topic potrebbe essere test/temperatura e il messaggio il valore numerico che vogliamo comunicare.
Non ci sono vincoli sull'origine del valore numerico, potrebbe ad esempio trattarsi di un valore di temperatura ottenuto tramite internet sfruttando qualche API Meteo, o in seguito alla digitazione di un valore da tastiera.
Di seguito il formato del valore da inviare a seconda del tipo di elemento:
  • Sensore: invio del valore numerico con . come separatore decimale (es. 23.4).
  • Input: inviare 0 nel caso di input verificato, 1 se verificato.
  • Output Digitale (relè): 0 se disattivo, 1 se attivo.
  • Output Analogico: valore tra 1 (o valore minimo di dimmerazione) e 255 (o valore massimo di dimmerazione) se attivo, mentre se è disattivo va inviato 0 e separato dai : il valore dell'output prima di essere disattivato (es. 0:130).
  • Variabile Virtuale: numero intero o decimale (con il . come separatore decimale).

Subscribe

Nel caso si voglia integrare un output va definito anche il topic per la ricezione delle richieste. Anche in questo caso non ci sono vincoli, se non la definizione di topic univoci per ciascun output.
Il topic per la ricezione delle richieste potrebbe essere ad esempio out_1/comando, e a seconda del tipo di richiesta il messaggio sarà:
  • on: per l'attivazione dell'output
  • off: per la disattivazione
  • Valore tra 0 e 255: se l'uscita è analogica viene inviato un valore numerico (0 corrisponde alla minima intensità, 255 alla massima)
Anche in questo caso non è obbligatorio che il comando sia inviato ad un output reale, o comunque connesso fisicamente al dispositivo che volete integrare, ma tale valore potrebbe essere allegato ad una richiesta HTTP o ad un messaggio via bus seriale.

Esempi

Il codice sottostante (in Python) è stato testato su un Raspberry Pi, e permette di integrare un sensore DHT, per l'invio di temperatura e umidità:
1
import Adafruit_DHT
2
import time
3
import uuid
4
import paho.mqtt.client as mqtt
5
6
7
disconnected = False
8
last_message_sent = time.time()
9
10
11
class SuperClient(mqtt.Client):
12
13
def loop(self, timeout=1.0, max_packets=1):
14
time.sleep(0.001)
15
return super(SuperClient, self).loop()
16
17
18
class DHTSensor(object):
19
20
def __init__(self, pin):
21
self.pin = pin
22
self.temperature = 0.0
23
self.humidity = 0.0
24
self.old_temperature = 0.0
25
self.old_humidity = 0.0
26
self.last_update = 0
27
28
def check(self) -> bool:
29
return self.old_humidity != self.humidity or self.old_temperature != self.temperature
30
31
def upate(self) -> bool:
32
if time.time() - self.last_update > 5:
33
self.old_humidity = self.humidity
34
self.old_temperature = self.temperature
35
humidity, temperature = Adafruit_DHT.read(sensor=Adafruit_DHT.DHT22, pin=self.pin)
36
if None not in [humidity, temperature]:
37
self.humidity = round(float(humidity), 1)
38
self.temperature = round(float(temperature), 1)
39
self.last_update = time.time()
40
return self.check()
41
return False
42
43
# The callback for when the client receives a CONNACK response from the server.
44
def on_connect(client, userdata, flags, rc):
45
global disconnected
46
disconnected = False
47
48
49
# The callback for when the client receives a CONNACK response from the server.
50
def on_disconnect(client, userdata, rc):
51
global disconnected
52
disconnected = True
53
54
55
def set_client(host):
56
try:
57
global mqtt_client
58
client_id = "rasp-" + str(uuid.uuid4())
59
mqtt_client = SuperClient(client_id=client_id, clean_session=True)
60
# Set callbacks methods
61
mqtt_client.on_connect = on_connect
62
mqtt_client.on_disconnect = on_disconnect
63
mqtt_client._host = host
64
mqtt_client._port = 1883
65
mqtt_client._keepalive = 60
66
67
#mqtt_client.max_queued_messages_set(queue_size=1)
68
69
# Start connection
70
mqtt_client.loop_start()
71
mqtt_client.reconnect()
72
except:
73
pass
74
75
76
def update_via_mqtt(sensor: DHTSensor):
77
global mqtt_client
78
try:
79
mqtt_client.publish(topic=f"rasp/dht/humidity/{sensor.pin}", payload=f"{sensor.humidity}", qos=0, retain=True)
80
mqtt_client.publish(topic=f"rasp/dht/temperature/{sensor.pin}", payload=f"{sensor.temperature}", qos=0, retain=True)
81
except:
82
pass
83
84
85
set_client(host="x.x.x.x")
86
87
sensors = [DHTSensor(pin=19), DHTSensor(pin=26)]
88
89
# Set client loop
90
while True:
91
for sensor in sensors:
92
if sensor.upate():
93
update_via_mqtt(sensor=sensor)
94
95
if time.time() - last_message_sent > 10:
96
for sensor in sensors:
97
update_via_mqtt(sensor=sensor)
98
last_message_sent = time.time()
99
100
time.sleep(0.1)
Copied!