Ich glaube nicht, dass Du die Aufbereitung der Daten in Blockly hinbekommen wirst, mal abgesehen davon, dass Du ja auch die Kommunikation mit der seriellen Schnittstelle brauchst.
Ich habe in der Zwischenzeit einige kleine Scripte bei mir laufen, die über mqtt mit openHAB sprechen. Allerdings geht es bei mir darum, auf Befehle von openHAB zu reagieren. Aber um mal zu zeigen, dass es zwar nicht selbsterklärend, aber auch keine Raketenwissenschaft ist...
Ich zäume hier das Pferd mal von hinten auf. Programm als Dienst starten: die meisten GNU/Linux Distros nutzen inzwischen systemd, so auch Raspberry Pi OS. Die Dienste werden über service-Dateien gesteuert.
Code: Alles auswählen
udo1toni@calibre:~$ cat /etc/systemd/system/mqttclient.service
[Install]
WantedBy=multi-user.target
Type=simple
[Service]
ExecStart=/usr/bin/python3 /usr/local/sbin/mqttclient.py
User=root
Restart=always
RestartSec=10
udo1toni@calibre:~$
Diese Datei definiert also einen Service, der mqttclient heißt. Dein Dienst könnte z.B. weather2mqtt heißen (nur so als Vorschlag)
Der Install-Teil definiert, unter welchen Umständen der Dienst gestartet werden soll. Wenn der Rechner startet, durchläuft er mehrere Phasen, wovon der Normalzustand (also wenn das System komplett läuft) das multi-user.target ist. Der Dienst wird also gestartet, wenn das System nach multi-user wechselt und wird gestoppt, wenn dieser Modus verlassen wird.
Der Service-Teil beschreibt die notwendigen Schritte. Unter ExecStart steht also, wie das Programm aufzurufen ist, die anderen Parameter sind eigentlich genauso selbsterklärend. Restart besagt, dass der Dienst im Normalbetrieb automatisch wieder gestartet wird, sobald er abstürzt.
Um so einen Dienst im System bekannt zu machen, muss man lediglich die Daemon-Liste neu laden, den Dienst starten und als Autostart einrichten:
Code: Alles auswählen
sudo systemctl daemon-reload
sudo systemctl enable mqttclient.service
sudo systemctl start mqttclient.service
Der Dienst kann immer gestartet oder gestoppt werden, auch wenn er disabled ist. Das enable bezieht sich einzig auf den Autostart.
Dieses Script dient dazu, remote zwei Dienste alternativ zu starten oder zu stoppen. Es ist deshalb etwas komplexer, weil ich ja systemd fernsteuern muss. Das ist übrigens auch der Grund, warum dieses Script als root gestartet wird. Man könnte versuchen, einen extra User anzulegen, aber da der User ohnehin Rechte auf Systemebene benötigt, kann er nicht komplett ausgesperrt werden (abgesehen davon bin ich ja auch nur Laie...)
Code: Alles auswählen
udo1toni@calibre:~$ cat /usr/local/sbin/mqttclient.py
#!/usr/bin/python
# define imports
import configparser
import logging
from paho.mqtt import client as mqtt
import time
from sysdmanager import SystemdManager
# define config reader
config = configparser.ConfigParser()
# read config from /etc/default/mqttclient
config.read('/etc/default/mqttclient')
# set config and default value if not set
# for logger
log_file = (config['logging']).get('filename','/var/log/pymqtt.log')
log_level = int((config['logging']).get('level','30'))
logging.basicConfig(filename=log_file,format='%(asctime)s %(levelname)s:%(message)s', datefmt='%Y/%m/%d/ %H:%M:%S', level=log_level)
# for mqtt connection
MQTT_SERVER = (config['mqtt']).get('url','localhost')
MQTT_PORT = int((config['mqtt']).get('port','1883'))
MQTT_RECONNECT = int((config['mqtt']).get('reconnect','60'))
MQTT_PATH = (config['mqtt']).get('path','/')
MQTT_COMMAND = (config['mqtt']).get('command','cmnd')
MQTT_STATE = (config['mqtt']).get('state','state')
MY_COMMAND = MQTT_PATH+MQTT_COMMAND
MY_STATE = MQTT_PATH+MQTT_STATE
# define functions
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
client.publish(MQTT_PATH+"LWT", payload="Online", qos=0, retain=True)
logging.info("Connected with result code "+str(rc))
if rc: logging.warning("Connecting resulted with" +str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe(MY_COMMAND)
logging.info("Subscribed to "+str(MY_COMMAND))
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
manager = SystemdManager()
logging.debug("got message!")
payload=format(msg.payload.decode("utf-8"))
logging.info(msg.topic+" : "+payload)
startunit=""
stopunit1=""
stopunit2=""
if payload == "1":
logging.debug("Payload is 1 -> CS")
stopunit1="cps.service"
startunit="calibre-server.service"
elif payload == "2":
logging.debug("Payload is 2 -> CPS")
startunit="cps.service"
stopunit1="calibre-server.service"
elif payload == "0":
logging.debug("Payload is 0 -> OFF")
stopunit2="cps.service"
stopunit1="calibre-server.service"
else:
logging.info("Payload is "+payload+" -> only send state")
if stopunit1 != "":
logging.debug("stop service "+stopunit1+"!")
manager.stop_unit(stopunit1)
if stopunit2 != "":
logging.debug("stop service "+stopunit2+"!")
manager.stop_unit(stopunit2)
client.publish(MY_STATE, payload="0", qos=0, retain=False)
logging.debug("published state 0 to "+MY_STATE)
if startunit != "":
logging.debug("wait until starting service!")
time.sleep(10)
logging.debug("starting service "+startunit+"!")
manager.start_unit(startunit)
logging.debug("publishing state")
if manager.is_active("cps.service"):
cpsstate="ON"
client.publish(MY_STATE, payload="2", qos=0, retain=False)
logging.debug("published state 2 to "+MY_STATE)
else:
cpsstate="OFF"
if manager.is_active("calibre-server.service"):
csstate="ON"
client.publish(MY_STATE, payload="1", qos=0, retain=False)
logging.debug("published state 1 to "+MY_STATE)
else:
csstate="OFF"
client.publish(MQTT_PATH+"cs/state", payload=csstate, qos=0, retain=False)
client.publish(MQTT_PATH+"cps/state", payload=cpsstate, qos=0, retain=False)
logging.debug("published state "+csstate+" to "+MQTT_PATH+"cs/state")
logging.debug("published state "+cpsstate+" to "+MQTT_PATH+"cps/state")
# main program
# set a new client and create hooks to functions
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.will_set(MQTT_PATH+"LWT", payload="Offline", qos=0, retain=True)
# connect
client.connect(MQTT_SERVER, MQTT_PORT, MQTT_RECONNECT)
# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()
udo1toni@calibre:~$
Witzigerweise benötigst Du den on_message-Part nicht (das macht den Löwenanteil meines Codes aus...)
Aber Du kannst am Code die notwendigen Schritte sehen, um die Verbindung zum Broker aufzubauen, die Konfiguration über eine Konfigurationsdatei zu lesen und auf ankommende Nachrichten zu reagieren. Genauso kannst Du sehen, dass zum Senden nicht wirklich viel passieren muss. Letztlich wird nur eine Funktion
client.publish() aufgerufen, in meinem Fall mit der Rückmeldung über den gestarteten Dienst, bei Dir kommt dann dort das gesendete JSON Objekt rein.
Fehlt noch die Konfigurationsdatei:
Code: Alles auswählen
udo1toni@calibre:~$ cat /etc/default/mqttclient
[mqtt]
url = 192.168.178.55
port = 1883
reconnect = 60
path = calibre/
command = cmnd
state = state
lwt = LWT
[logging]
filename = /var/log/pymqtt.log
# CRITICAL=50 ERROR=40 WARNING=30 INFO=20 DEBUG=10 NOTSET=0
level = 30
udo1toni@calibre:~$
Damit das ganze funkitioniert, braucht das System ein paar Pakete:
und natürlich ein paar python Libraries:
Wobei Du das letzte Paket natürlich nicht brauchst, nur der Vollständigkeit halber...
Der wesentliche Teil für Dein Programm ist natürlich das zyklische Lesen der seriellen Schnittstelle und die Umsetzung in die zu sendende Payload.
Als Einstieg mag dieser Link diesen
https://stackoverflow.com/questions/676 ... al-package. Ich bin mir nicht sicher, ob serial ohne weiteres Zutun bei Python3 mit kommt, aber das "schlimmste" was passieren kann, ist, dass ein Programm, welches den Import nutzt, mit einer Fehlermeldung abbricht, weil die Bibliothek fehlt.
Hier noch ein Beispiel einer serial<->mqtt Bridge:
https://github.com/perrin7/ninjacape-mq ... TBridge.py, das kommt Deinen Bedürfnissen schon recht nahe, Du musst also den Code "nur" verstehen und anschließend so abändern, dass a) die Kommunikation nur in einer Richtung läuft (bedeutet Du musst nur Code weg lassen...) und b) der Teil, welcher aus der empfangenen Datenzeile die Daten aufbereitet wird entsprechend angepasst ist.