Ultraschallsensor in OpenHAB intigrieren

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
Benutzeravatar
udo1toni
Beiträge: 4324
Registriert: 11. Apr 2018 18:05
Answers: 45
Wohnort: Darmstadt

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von udo1toni »

So, hier mal mein mqtt client script, welches zwei verschiedene calibre Server startet und stoppt.

Die eigentliche Funktion des Scripts sollte hier nicht so wichtig sein, aber man kann ein paar Dinge sehen.
  1. mittels configparser Library werden die Zugangsdaten zum mqtt Server geholt. Liegt der entsprechende Wert nicht vor, wird ein Default Wert gesetzt.
  2. Auch das logging ist über einen Import bequem erledigt.
  3. Die Library, um die es eigentlich geht (paho.mqtt.client) und wie sie angesprochen wird.

Code: Alles auswählen

#!/usr/bin/python

import configparser
import logging
import paho.mqtt.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):

    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!")
    logging.info(msg.topic+" : "+str(msg.payload))
    startunit=""
    stopunit1=""
    stopunit2=""
    if str(msg.payload) == "1":
        logging.debug("Payload is 1 -> CS")
        stopunit1="cps.service"
        startunit="calibre-server.service"
    elif str(msg.payload) == "2":
        logging.debug("Payload is 2 -> CPS")
        startunit="cps.service"
        stopunit1="calibre-server.service"
    elif str(msg.payload) == "0":
        logging.debug("Payload is 0 -> OFF")
        stopunit2="cps.service"
        stopunit1="calibre-server.service"
    else:
        logging.info("Payload is "+str(msg.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.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()
Vorne werden ein paar Funktionen definiert (on_connect und on_message), die eigentliche Programmausführung läuft danach in den Zeilen

Code: Alles auswählen

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect(MQTT_SERVER, MQTT_PORT, MQTT_RECONNECT)

client.loop_forever()
Die erste Zeile erzeugt den mqtt client, die zweite und dritte Zeile definiert, welche Funktionen bei den beiden Ereignissen on_connect und on_message ausgeführt werden sollen, anschließend wird connect aufgerufen.
Danach geht der client in eine Endlosschleife (client.loop_forever).
in der connect-Routine wird nach dem connect ein Topic subscribed, auf welches der Client fortan reagiert. Die Reaktion passiert in on_message, hier findet die eigentliche Arbeit statt.

Das Script läuft bei mir als Daemon. Ich sollte vielleicht noch erwähnen, dass ich von python keine Ahnung habe ;) vermutlich ließe sich das alles auch viel eleganter lösen, aber es tut, was es soll ;)

Pepe1907
Beiträge: 148
Registriert: 1. Jun 2020 17:29
Answers: 1

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von Pepe1907 »

Das ist ja mal wieder völliges Neuland für mich. Bin beeindruckt von deinen Kenntnissen. Hut ab. Muss mich wohl mal mehrere Stunden mit beschäftigen damit ich nur ein Hauch trotz deiner Erklärungen davon verstehe

Pepe1907
Beiträge: 148
Registriert: 1. Jun 2020 17:29
Answers: 1

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von Pepe1907 »

Wie liest er denn die distanz aus dem Script? Muss ich das dafür anpassen?
Beim Script würde ich vor dem return einfach nur sleep setzten und dann 5min.

Benutzeravatar
udo1toni
Beiträge: 4324
Registriert: 11. Apr 2018 18:05
Answers: 45
Wohnort: Darmstadt

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von udo1toni »

Na ja, wenn Du mqtt zur Kommunikation nutzen willst, musst Du halt eine Client Bibliothek einbinden und die passenden Funktionen implementieren.

Mein Beispiel ist in python gehalten, bei Deinem Script kann ich nicht sicher sagen, ob das auch python ist :)
Letztlich muss das Scriptnicht unbedingt als Dienst laufen, weil Du ja nicht darauf angewiesen bist, auf Befehle von mqtt in Richtung Script zu reagieren.
Der eigentliche Befehl, den Messwert zu publizieren, wäre

Code: Alles auswählen

client.publish(MQTT_PATH+"cs/state", payload=csstate, qos=0, retain=False)
Das verwendete Topic wäre hier MQTT_PATH+"cs/state", wenn MQTT_PATH z.B. den String meinPfad/ enthält, ergäbe sich als Topic meinPfad/cs/state. Der payload ist der eigentliche Messwert und wird hier mit dem Inhalt der Variablen csstate gesetzt. qos=0 bedeutet, dass exakt einmal publiziert wird und retain=False, dass der Broker das topic nach dem Weiterleiten wieder vergisst. In Deinem Fall wäre retain=True sicher sinnvoll, dann kann openHAB den Status unmittelbar anfragen, wenn es startet und muss nicht darauf warten, dass der Sensor den ersten Wert liefert.

Pepe1907
Beiträge: 148
Registriert: 1. Jun 2020 17:29
Answers: 1

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von Pepe1907 »

udo1toni hat geschrieben: 30. Jun 2020 19:57 Na ja, wenn Du mqtt zur Kommunikation nutzen willst, musst Du halt eine Client Bibliothek einbinden und die passenden Funktionen implementieren.

Mein Beispiel ist in python gehalten, bei Deinem Script kann ich nicht sicher sagen, ob das auch python ist :)
Letztlich muss das Scriptnicht unbedingt als Dienst laufen, weil Du ja nicht darauf angewiesen bist, auf Befehle von mqtt in Richtung Script zu reagieren.
Der eigentliche Befehl, den Messwert zu publizieren, wäre

Code: Alles auswählen

client.publish(MQTT_PATH+"cs/state", payload=csstate, qos=0, retain=False)
Das verwendete Topic wäre hier MQTT_PATH+"cs/state", wenn MQTT_PATH z.B. den String meinPfad/ enthält, ergäbe sich als Topic meinPfad/cs/state. Der payload ist der eigentliche Messwert und wird hier mit dem Inhalt der Variablen csstate gesetzt. qos=0 bedeutet, dass exakt einmal publiziert wird und retain=False, dass der Broker das topic nach dem Weiterleiten wieder vergisst. In Deinem Fall wäre retain=True sicher sinnvoll, dann kann openHAB den Status unmittelbar anfragen, wenn es startet und muss nicht darauf warten, dass der Sensor den ersten Wert liefert.
Ich glaube da würde ich nicht nur an meine Grenzen gehen sondern über meine Grenzen.
Also zurück zum exec binding.
Da muss ich ja eine rule erstellen.
könnte die so aussehen?

Code: Alles auswählen

rule "Teichstand"
	when
		Time cron "0 0/5 * 1/1 * ? *"

    then
        teichstand.postUpdate(Float::parseFloat(sensor.state.toString))

end

Benutzeravatar
udo1toni
Beiträge: 4324
Registriert: 11. Apr 2018 18:05
Answers: 45
Wohnort: Darmstadt

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von udo1toni »

Ja und Nein.

Ja, was das postUpdate betrifft.
Nein, was den Trigger betrifft.
Die Rule sollte nicht zyklisch aufgerufen werden, sondern wenn Item sensor changed auftritt (meinetwegen auch, wenn Item sensor received update auftritt).
Der Unterschied besteht darin, dass changed nur bei Wertänderung triggert. Das spielt allerdings nur dann eine Rolle, wenn man in einer Datenbank alle Updates mit Zeitstempel sehen will.
Beiden Varianten gemein ist aber, dass der Wert unmittelbar übernommen wird, sobald er im System vorliegt, während der Time cron Trigger den Wert stumpf alle 5 Minuten schreibt, beginnend zur vollen Stunde, zur vollen Minute.
Wenn das exec Binding den Befehl ebenfalls alle 5 Minuten absetzt, ist damit noch lange nicht gesagt, dass der Befehl immer zur vollen Stunde oder gar zur vollen Minute abgesetzt wird. Aber selbst wenn das der Fall sein sollte, liegt das Ergebnis erst einige 100ms später vor, womit die Rule dann den alten Wert übernähme und somit der numerische Wert volle fünf Minuten inaktuell ist.
Das mag beim Teichpegel nicht wesentlich sein ;) aber ich sage immer "Wehret den Anfängen!"

Was den Time cron Trigger als solchen betrifft: Das Jahr ist optional, wenn es keine Rolle spielt, muss man es nicht angeben. Ein * steht für einen unberücksichtigten Wert, was beim Tag das gleiche ist, wie jeden Tag (1/1). Entsprechend könnte man den Trigger auch so schreiben:

Code: Alles auswählen

Time cron "0 0/5 * * * ?"
was in meinen Augen besser lesbar ist.

Pepe1907
Beiträge: 148
Registriert: 1. Jun 2020 17:29
Answers: 1

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von Pepe1907 »

Bekomme es einfach nicht hin.


Logfile

Code: Alles auswählen

2020-07-01 18:30:38.344 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Teichstand': For input string: "/etc/openhab2/scripts/hc.py: 2: /etc/openhab2/scripts/hc.py: import: not found

/etc/openhab2/scripts/hc.py: 3: /etc/openhab2/scripts/hc.py: import: not found

/etc/openhab2/scripts/hc.py: 6: /etc/openhab2/scripts/hc.py: Syntax error: word unexpected (expecting ")")

/etc/openhab2/scripts/hc.py: 2: /etc/openhab2/scripts/hc.py: import: not found

/etc/openhab2/scripts/hc.py: 3: /etc/openhab2/scripts/hc.py: import: not found

/etc/openhab2/scripts/hc.py: 6: /etc/openhab2/scripts/hc.py: Syntax error: word unexpected (expecting ")")"

Code: Alles auswählen

#Bibliotheken
import RPi.GPIO as GPIO
import time
 
#GPIO definieren (Modus, Pins, Output)
GPIO.setmode(GPIO.BCM)
GPIO_TRIGGER = 18
GPIO_ECHO = 24
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)
 
def entfernung():
    # Trig High setzen
    GPIO.output(GPIO_TRIGGER, True)
 
    # Trig Low setzen (nach 0.01ms)
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
 
    Startzeit = time.time()
    Endzeit = time.time()
 
    # Start/Stop Zeit ermitteln
    while GPIO.input(GPIO_ECHO) == 0:
        Startzeit = time.time()
 
    while GPIO.input(GPIO_ECHO) == 1:
        Endzeit = time.time()
 
    # Vergangene Zeit
    Zeitdifferenz = Endzeit - Startzeit
	
    # Schallgeschwindigkeit (34300 cm/s) einbeziehen
    entfernung = 140 - (Zeitdifferenz * 34300) / 2
 
    return entfernung
 
if __name__ == '__main__':
    try:
        while True:
            distanz = entfernung()
            print ("Distanz = %.1f cm" % distanz)
            time.sleep(10)
 
        # Programm beenden
    except KeyboardInterrupt:
        print("Programm abgebrochen")
        GPIO.cleanup()
Die Items habe ich per PaperUi angelegt.
Rückgabewert ist als String Item sensor definiert

Code: Alles auswählen

Number teichstand    "Wasserspiegel Teich [%.2f cm]"	<water>	(gVentil)
und die passende Rule

Code: Alles auswählen

rule "Teichstand"
  when
     Item sensor received update
    then
        teichstand.postUpdate(Float::parseFloat(sensor.state.toString)
      )
 
end
Das script kann ich problemlos per SSH ausführen und zeigt mir alle 20Sek. den aktuellen Wasserstand an..

Benutzeravatar
udo1toni
Beiträge: 4324
Registriert: 11. Apr 2018 18:05
Answers: 45
Wohnort: Darmstadt

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von udo1toni »

Wo ist denn die Anbindung des Scripts?


Gesendet von iPad mit Tapatalk

Pepe1907
Beiträge: 148
Registriert: 1. Jun 2020 17:29
Answers: 1

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von Pepe1907 »

udo1toni hat geschrieben: 3. Jul 2020 18:37 Wo ist denn die Anbindung des Scripts?


Gesendet von iPad mit Tapatalk
Oh entschuldige da ist mir wohl was durchgerutscht.
Bild

Benutzeravatar
udo1toni
Beiträge: 4324
Registriert: 11. Apr 2018 18:05
Answers: 45
Wohnort: Darmstadt

Re: Ultraschallsensor in OpenHAB intigrieren

Beitrag von udo1toni »

Da vorne im Script nicht erwähnt ist, dass es sich um ein Python Script handelt - das wäre diese Zeile:

Code: Alles auswählen

#!/usr/bin/python
kann der Ausruf so nicht sauber funktionieren.
Vermutlich musst Du mindestens /usr/bin/python vorne dran schreiben:

Code: Alles auswählen

/usr/bin/python /etc/openhab2/scripts/hc.py
Mit welchem User kannst Du das Script ausführen? openHAB nutzt immer den User openhab, um solche Befehle auszuführen. Falls der User openhab bestimmte Rechte nicht hat, geht es schief.
Ob der User openhab das Script ausführen kann, kannst Du mit

Code: Alles auswählen

sudo -u openhab /etc/openhab2/scripts/hc.py
testen.

Antworten