Ah, das hatte ich überhaupt nicht realisiert, dass Du es direkt aus Jython heraus nutzen wolltest.
openHAB kennt kein Python, lediglich Jython (das wäre quasi Python für Java oder so ähnlich). Du wirst die Bibliothek also bestimmt irgendwie nutzen können, aber eben nicht mit nativem Python Code in Jython.
Aber ich bin nicht in der Materie drin, ich nutze selbst ausschließlich die DSL für Rules.
Wenn ich etwas extern steuern muss, was nicht einfach mit Bordmitteln geht, nutze ich gewöhnlich Python Scripte, die ich als Dienst laufen lasse.
Die Scripte steuere ich dann per mqtt, das ist sehr einfach umzusetzen und benötigt keine Klimmzüge wie mit exec usw.
Beispielscript, um auf einer Remote Maschine Calibre Server oder Calibre Web zu starten und zu stoppen:
Code: Alles auswählen
#!/usr/bin/python
import configparser
import logging
from paho.mqtt import client as mqtt
import time
from sysdmanager import SystemdManager
config = configparser.ConfigParser()
config.read('/etc/default/mqttclient')
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)
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
# 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")
# more callbacks, etc
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)
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()
mqttclient.service:
Code: Alles auswählen
[Install]
WantedBy=multi-user.target
Type=simple
[Service]
ExecStart=/usr/bin/python3 /usr/local/sbin/mqttclient.py
User=root
Restart=always
RestartSec=10
und /etc/default/mqttclient:
Code: Alles auswählen
[mqtt]
url = 192.168.178.155
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
Das Script stellt nicht wirklich fest, ob der entsprechende Dienst erfolgreich gestartet wurde (weil ich dazu zu faul war... funktioniert auch so zuverlässig)
Ich habe mehrere ähnliche Scripte, bei denen der Rumpf quasi identisch ist, lediglich die konkrete Funktion unterscheidet sich dann. Hier ist halt als "Herausforderung" Systemd mit im Spiel, was eher ungewöhnlich sein dürfte.
Logging und Configparser sind aber eine schöne Möglichkeit, die nötigen Einstellungen komfortabel vom eigentlichen Script zu trennen. Lohn ist ein Zweig im mqtt Baum, über den die beiden Dienste gestartet und gestoppt werden können. Das Script stellt dabei sicher, dass maximal einer der beiden Dienste läuft. So in etwa könntest Du ein externes Python Script zum Steuern des Projektors auch einbinden. Das Script läuft dann dauerhaft als Dienst, die Verbindung zu openHAB findet über mqtt statt und du bekommst ein Topic, in dem der Zustand gemeldet wird (in welcher Form auch immer... man könnte z.B. ein JSON Objekt zusammensetzen) und ein weiteres Topic, welches die Steuerbefehle als Klartext oder auch beliebig codiert entgegen nimmt. In openHAB brauchst Du dann nur entsprechende Gegenstücke, welche die Status darstellen und die Befehle (ggf. codiert) an mqtt senden.
mqtt ist wesentlich flexibler als exec, weshalb ich diesen Weg gewählt habe. Allerdings laufen die Scripte bei mir auch auf unterschiedlichen Rechnern, so dass ich ohnehin Netzwerkkommunikation brauche.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet