Commit 0017c9d6 authored by Peter-Bernd Otte's avatar Peter-Bernd Otte

Added functionality to relais-control

parent 0e2633b2
relais:
- hi
- ti
# all parameters, except for MQTTRelaisTopic are optional
# - if debug is supplied, it will override the global -v option
# - defaultTopics, switchOffTopics, toggleTopics and inverseSwitchOnTopics are either
# lists or a sinlge string
testraum/testrelais:
MQTTRelaisTopic: homie/fsr-ww/2
debug: true
defaultSwitchOffTime: 5
defaultTopics:
- homie/enocean/test/schalter
- homie/enocean/test/schalter2
switchOffTopics:
- homie/enocean/test/schalter3
toggleTopics: homie/enocean/test/schalter2
testraum/testrelais2:
MQTTRelaisTopic: homie/fsr-ww/3
defaultSwitchOffTime: 15
toggleTopics: homie/enocean/test/schalter2
\ No newline at end of file
......@@ -4,15 +4,12 @@ import json
import time
from datetime import datetime
import paho.mqtt.client as paho
#import numbers
#import parse
from relais import *
import yaml #pip3 install pyyaml
import os #for os.path.isfile
import logging, argparse
format = "%(asctime)-9s %(levelname)-8s %(message)s"
logging.basicConfig(format=format, datefmt="%H:%M:%S")
logging.basicConfig(format="%(asctime)-15s %(levelname)-8s %(message)s")
logger = logging.getLogger("Actor")
parser = argparse.ArgumentParser(description='Workload distributor for trivial parallelism.')
......@@ -23,12 +20,6 @@ parser.add_argument("mqtt_client_name", help="MQTT client name. Needs to be uniq
args = parser.parse_args()
logger.setLevel(logging.WARNING-(args.verbosity*10 if args.verbosity <=2 else 20) )
#broker="dom"
#MQTTClientName = "I2CActor"
if os.path.exists(args.config_file):
logger.debug("config file exists")
mlast = {}
def on_connect(client, userdata, flags, rc):
......@@ -38,10 +29,14 @@ def on_connect(client, userdata, flags, rc):
# client.subscribe("#")
client.subscribe(x.MQTTRelaisTopic)
for y in x.defaultTopics: client.subscribe(y)
logger.debug("MQTT: "+x.MQTTname+" defaultTopics subscribed")
for y in x.toggleTopics: client.subscribe(y)
logger.debug("MQTT: "+x.MQTTname+" toggleTopics subscribed")
for y in x.switchOffTopics: client.subscribe(y)
logger.debug("MQTT: "+x.MQTTname+" switchOffTopics subscribed")
for y in x.inverseSwitchOnTopics: client.subscribe(y)
client.subscribe(x.MQTTName+"/set")
logger.debug("MQTT: "+x.MQTTname+" inverseSwitchOnTopics subscribed")
client.subscribe(x.MQTTname+"/set")
logger.debug("MQTT: Subscribed to all topics")
else:
logger.error("Bad connection. Return code="+str(rc))
......@@ -71,7 +66,7 @@ def on_message(client, userdata, message):
if message.topic == x.MQTTRelaisTopic:
x.relaisMsg(j)
x.checkAction(message.topic,j)
if message.topic == x.MQTTRelaisTopic+"/set":
if message.topic == x.MQTTname+"/set":
x.setV(j['v'],j['time'])
mlast[message.topic] = j
......@@ -79,6 +74,51 @@ def on_message(client, userdata, message):
client= paho.Client(args.mqtt_client_name)
# test with:
# mosquitto_pub -t homie/fsr-ww/1 -m '{"setv": 0, "time": 1564251546.330417, "type": "FUD14", "v": 1}'
# mosquitto_sub -t 'homie/I2CActor/testraum/testrelais' -v
relaisList = []
debug = True if args.verbosity>1 else False
if os.path.exists(args.config_file):
logger.debug("config file exists")
with open("config.yml", 'r') as ymlfile:
cfg = yaml.full_load(ymlfile) # see https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation
for section in cfg:
MQTTName="homie/"+args.mqtt_client_name+"/"+section
logger.info("Adding Relais with MQTT topic: "+MQTTName)
logger.info("Configuration: "+str(cfg[section]))
if "MQTTRelaisTopic" not in cfg[section]:
logger.error("MQTTRelaisTopic property is missing. Will not be added.")
continue
for x in relaisList:
if x.MQTTRelaisTopic == cfg[section]["MQTTRelaisTopic"]:
logger.error("MQTTRelaisTopic: "+str(cfg[section]["MQTTRelaisTopic"])+" does already exist. Will not be added.")
continue
defaultTopics = cfg[section]["defaultTopics"] if "defaultTopics" in cfg[section] else []
toggleTopics = cfg[section]["toggleTopics"] if "toggleTopics" in cfg[section] else []
switchOffTopics = cfg[section]["switchOffTopics"] if "switchOffTopics" in cfg[section] else []
inverseSwitchOnTopics = cfg[section]["inverseSwitchOnTopics"] if "inverseSwitchOnTopics" in cfg[section] else []
# print(type(toggleTopics))
if type(defaultTopics) is not list: defaultTopics = [defaultTopics]
if type(toggleTopics) is not list: toggleTopics = [toggleTopics]
if type(switchOffTopics) is not list: toggleTopics = [switchOffTopics]
if type(inverseSwitchOnTopics) is not list: toggleTopics = [inverseSwitchOnTopics]
defaultSwitchOffTime = cfg[section]["defaultSwitchOffTime"] if "defaultSwitchOffTime" in cfg[section] else None
debugItem = cfg[section]["debug"] if "debug" in cfg[section] else debug
relaisList.append(relais(MQTTClient=client, MQTTName=MQTTName,
MQTTRelaisTopic=cfg[section]["MQTTRelaisTopic"], toggleTopics=toggleTopics, switchOffTopics=switchOffTopics,
defaultTopics=defaultTopics, inverseSwitchOnTopics=inverseSwitchOnTopics,
defaultSwitchOffTime=defaultSwitchOffTime, debug=debugItem))
logger.info("Adding successfully.")
client.on_message=on_message
client.on_connect = on_connect
client.on_disconnect = on_disconnect
......@@ -87,25 +127,13 @@ client.connect(args.mqtt_broker_host)
client.loop_start() #start loop to process received messages in separate thread
logger.debug("MQTT Loop started.")
# test with:
# mosquitto_pub -t homie/fsr-ww/1 -m '{"setv": 0, "time": 1564251546.330417, "type": "FUD14", "v": 1}'
# mosquitto_sub -t 'homie/I2CActor/testraum/testrelais' -v
relaisList = []
relaisList.append(relais(MQTTClient=client, MQTTName="homie/"+args.mqtt_client_name+"/testraum/testrelais",
MQTTRelaisTopic="homie/fsr-ww/2",
toggleTopics=["homie/enocean/test/schalter2"],
switchOffTopics=["homie/enocean/test/schalter3"],
defaultTopics=["homie/enocean/test/schalter",'homie/enocean/wohnzimmer/bewegungsmelder/bewegungsmelderDeckeGaube', 'homie/enocean/bügelzimmerUG/bewegungsmelder/bewegungsmelderDecke'],
defaultSwitchOffTime=5))
#relaisList.append(relais("testraum/testrelais2", "homie/fsr-ww/2", ["test/schalter2"], 5))
sleepTime = 1 if args.verbosity>0 else 0.025
while True:
for x in relaisList:
x.check()
# x.relaisMsg(json.loads('{"time": 1564578103.410478, "type": "FSR14", "setv": 1.0, "v": 1.0}'))
time.sleep((1-time.time() % 1)/1) #every second, even if the processing before took longer
time.sleep((1-time.time() % 1) * sleepTime) #every second, even if the processing before took longer
client.disconnect()
client.loop_stop()
\ No newline at end of file
......@@ -21,9 +21,10 @@ class rLightDesire(Enum):
class relais:
def __init__(self, MQTTClient, MQTTName, MQTTRelaisTopic, defaultTopics=None, toggleTopics=None, switchOffTopics=None,
inverseSwitchOnTopics=None, defaultSwitchOffTime=None):
inverseSwitchOnTopics=None, defaultSwitchOffTime=None, debug=False):
self.MQTTname = MQTTName #string
self.type = "relais"
self.debug = debug
self.MQTTClient = MQTTClient #object
self.MQTTRelaisTopic = MQTTRelaisTopic #string
......@@ -51,7 +52,7 @@ class relais:
"v": self.v, "time": t, "reason":reason}, sort_keys=True), qos=1, retain=True)
def relaisMsg(self, j):
print("Feedback-Msg from Relais (",self.MQTTname,"): ",j)
if self.debug: print(self.MQTTname,"Feedback-Msg from Relais: ",j)
if self.v is None: self.v = j['v']
if self.timeLastChange is None: self.timeLastChange = j['time']
self.vFeedback = j['v']
......@@ -59,11 +60,11 @@ class relais:
if self.timeLastStateConfirm is None: self.timeLastStateConfirm = time.time()
self.state = rStates.confirmed if self.vFeedback == self.v else rStates.switching
self.publishCurrentStatus(reason="relais feedback")
print("Feedback Ende.")
if self.debug: print(self.MQTTname,"Feedback Ende.")
self.printCurrentState()
def setV(self, v, t=None, reason=None):
print("New Value set to:", v, "Old Value:", self.v, "Relais:", self.MQTTname)
if self.debug: print(self.MQTTname, "New Value set to:", v, "Old Value:", self.v)
if t is None: t = time.time()
if len(self.lockingPIRs) == 0 or v == 0: self.lightdesire = rLightDesire.stable
if self.v != v: # a change of output state
......@@ -74,12 +75,12 @@ class relais:
retain=False) # send command to Relais
self.timeLastStateConfirm = t
self.publishCurrentStatus(t, reason)
print("setV Ende")
if self.debug: print(self.MQTTname, "setV Ende")
def checkAction(self, topic, msg):
for x in self.defaultTopics: # Normally the topics, which switches the relais on
if topic == x:
print("Default Topic:", topic, "msg:", msg)
if self.debug: print(self.MQTTname,"Default Topic:", topic, "msg:", msg)
if msg['type'] in ('TFBHSB55', 'FBH63'): # motion sensors
self.timeLastStateConfirm = time.time()
if msg['v'] > 0:
......@@ -92,7 +93,7 @@ class relais:
self.lightdesire = rLightDesire.stable
self.timeLastStateConfirm = time.time() # to avoid immediate switch off after last PIR
self.publishCurrentStatus(reason="last PIR sees no motion")
print("Relais:", self.MQTTname, "len(self.lockingPIRs)", len(self.lockingPIRs), "self.lockingPIRs",
if self.debug: print(self.MQTTname, "len(self.lockingPIRs)", len(self.lockingPIRs), "self.lockingPIRs",
self.lockingPIRs)
elif msg['type'] in ('FRW', 'FHF', 'FSM60B', 'FTK',
'FTKE'): # smoke detector, window handle, waterleak detector, magnet sensor, handle bar sensor
......@@ -103,10 +104,10 @@ class relais:
elif msg['type'] == "PTM215": # switches
if msg['v'] > 0: self.setV(1, reason="PTM215 pressed down, switch on") # Switch on, if key pressed down
else:
print("Error: Type not supported for normal actions.")
print(self.MQTTname, "Error: Type not supported for normal actions.")
for x in self.toggleTopics: # topics do a toggle of the relais
if topic == x:
print("Toggle Topic:", topic, "msg:", msg)
if self.debug: print(self.MQTTname, "Toggle Topic:", topic, "msg:", msg)
if msg['type'] == "PTM215": # switches
if msg['v'] > 0: # on key pressed down
if self.v == 0:
......@@ -114,43 +115,43 @@ class relais:
else:
self.setV(0, reason="PTM215 pressed down, toggle")
else:
print("Error: Type not supported for toggle.")
print(self.MQTTname, "Error: Type not supported for toggle.")
for x in self.switchOffTopics: # topics switch off the relais
if topic == x:
print("Switch Off Topic:", topic, "msg:", msg)
if self.debug: print(self.MQTTname, "Switch Off Topic:", topic, "msg:", msg)
if msg['type'] == "PTM215": # switches
if msg['v'] > 0: self.setV(0, reason="PTM pressed down, switch off") # Switch Off, if key pressed down
else:
print("Error: Type not supported for switch off.")
print(self.MQTTname, "Error: Type not supported for switch off.")
for x in self.inverseSwitchOnTopics: # topics switch on the relais, but inverted input
if topic == x:
print("inverseSwitchOnTopics:", topic, "msg:", msg)
if self.debug: print(self.MQTTname, "inverseSwitchOnTopics:", topic, "msg:", msg)
if msg['type'] in ('FRW', 'FHF', 'FSM60B', 'FTK', 'FTKE'):
if msg['v'] == 0: self.setV(1, reason="inverseSwitchOnTopics "+msg['type']) # Switch on
else:
print("Error: Type not supported for inverseSwitchOnTopics.")
print(self.MQTTname, "Error: Type not supported for inverseSwitchOnTopics.")
def printCurrentState(self):
print("Relais",self.MQTTname,"v:",self.v,self.state,self.lightdesire,"lockingPIRs:",self.lockingPIRs)
if self.debug: print(self.MQTTname, "Relais",self.MQTTname,"v:",self.v,self.state,self.lightdesire,"lockingPIRs:",self.lockingPIRs)
def check(self):
if self.lightdesire == rLightDesire.stable and self.state != rStates.noFeedback and self.v is not None:
if (self.defaultSwitchOffTime is not None) and self.v > 0 and self.timeLastStateConfirm + self.defaultSwitchOffTime < time.time(): # test for switch off
print("Time up!")
if self.debug: print(self.MQTTname, "Time up!")
self.setV(0, reason="time up") # switch off now
self.state = rLightDesire.stable # no dimming etc. any longer
if self.vFeedback is None:
print("No Feedback from Relais, yet: "+self.MQTTname)
if self.debug: print(self.MQTTname, "No Feedback from Relais yet.")
else:
t = time.time()
if self.v!=self.vFeedback and t-self.timeLastChange>10 and t-self.timeFeedback > 10: #if feedback state differs too long from desired state
print("No OR wrong Feedback from Relais since last chance since more than 10 seconds.")
print(self.MQTTname, "No OR wrong Feedback from Relais since last chance since more than 10 seconds.")
self.v = self.vFeedback
self.timeLastChange = self.timeFeedback
self.timeLastStateConfirm = self.timeFeedback
self.state = rStates.noFeedback
self.printCurrentState()
self.publishCurrentStatus(reason="no feedback from relais")
self.publishCurrentStatus(reason="no or wrong feedback from relais")
# test with:
# mosquitto_pub -t homie/fsr-ww/1 -m '{"setv": 0, "time": 1564251546.330417, "type": "FUD14", "v": 1}'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment