diff --git a/rule-listener/data.py b/rule-listener/data.py index 0013479..4e8cc1d 100644 --- a/rule-listener/data.py +++ b/rule-listener/data.py @@ -5,29 +5,53 @@ topics = [ "main/printer/two", "main/lamp/one", "main/radio/one"] -walkDelay = 1 -baseRule = { - "state": 1, - "count": 1, - "doMessage": 1, - "delay": 30, - "reset": False, - "doTopic": "" + +config = { + "delay": 1, + "probability": 0.8 } rules = { "main/printer/one": [ { - "description": "Every time a printer is turned on, plan the gesture for 5 minutes later", + "description": "Every time a printer is turned on, make it move 5 minutes later", "count": 0, # the amount of times "state": 1, # it has had this state - "doTopic": "main/gesture/printer/one", # i will send to topic - "doMessage": 1, # this message - "delay": 60 * 5, # after this amount of seconds + "doTopic": "main/printer/one", # i will send to topic + "doMessage": 2, # this message + "delay": 60 * 2, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + }, + { + "description": "The third time a printer is turned on, change the overall delay", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/config/delay", # i will send to topic + "doMessage": 45, # this message + "delay": 0, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + }, + ], + "main/printer/two": [ + { + "description": "Every time a printer is turned on, make it move 5 minutes later", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/printer/two", # i will send to topic + "doMessage": 2, # this message + "delay": 55 * 2, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + }, + { + "description": "The third time a printer is turned off, change the overall delay", + "count": 3, # the amount of times + "state": 0, # it has had this state + "doTopic": "main/config/delay", # i will send to topic + "doMessage": 2, # this message + "delay": 0, # after this amount of seconds "reset": True, # and i should reset my count afterwards }, ], - "main/printer/two": [], "main/lamp/one": [ { "description": "after the lamp has been on 2 times, another fan should be turned on", @@ -38,6 +62,15 @@ rules = { "delay": False, # after this amount of seconds "reset": True, # and i should reset my count afterwards }, + { + "description": "Every time this lamp is turned on, make turn it on again 5 minutes later", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/lamp/one", # i will send to topic + "doMessage": 1, # this message + "delay": 50 * 2, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + } ], "main/fan/one": [ { @@ -49,31 +82,24 @@ rules = { "delay": False, # after this amount of seconds "reset": True, # and i should reset my count afterwards }, - # { # After the fan is turned off, the next fan should be turned on - # "count": 4, # the amount of times - # "state": 0, # it has had this state - # "doTopic": "main/fan/two", # i will send to topic - # "doMessage": 1, # this message - # "delay": 4, # after this amount of seconds - # "reset": True, # and i should reset my count afterwards - # }, - # { # Turn the fan off every time after 1 minute - # "count": 0, - # "state": 1, # it has had this state - # "doTopic": "main/fan/three", # i will send to topic - # "doMessage": 0, # this message - # "delay": 4, # after this amount of seconds - # "reset": False, # and i should reset my count afterwards - # }, - # { # Every 5 minutes, do gesture X - # "state": 1, - # "count": 1, - # "doTopic": "gesture/fan/one", - # "doMessage": 1, - # "delay": 5 * 60, - # "reset": True - # }, - + { + "description": "Always turn the other fan off when this fan is turned on", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/fan/two", # i will send to topic + "doMessage": 1, # this message + "delay": 5, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + }, + { + "description": "Always turn this fan on after 5 minutes", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/fan/one", # i will send to topic + "doMessage": 1, # this message + "delay": 45 * 2, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + } ], "main/fan/two": [ { @@ -85,6 +111,15 @@ rules = { "delay": False, # after this amount of seconds "reset": True, # and i should reset my count afterwards }, + { + "description": "Always turn this fan on after 5 minutes", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/fan/two", # i will send to topic + "doMessage": 1, # this message + "delay": 40 * 2, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + } ], "main/radio/one": [ @@ -97,6 +132,15 @@ rules = { "delay": 10, # after this amount of seconds "reset": True, # and i should reset my count afterwards }, + { + "description": "Always turn this fan on after 5 minutes", + "count": 0, # the amount of times + "state": 1, # it has had this state + "doTopic": "main/radio/one", # i will send to topic + "doMessage": 1, # this message + "delay": 35 * 2, # after this amount of seconds + "reset": True, # and i should reset my count afterwards + } ], } diff --git a/rule-listener/script.py b/rule-listener/script.py index cc76523..41f9e4c 100644 --- a/rule-listener/script.py +++ b/rule-listener/script.py @@ -3,14 +3,13 @@ import asyncio import secrets import data import random -import pprint - state = {} rules = data.rules mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) + def publish_transform(fromTopic, toTopic): if fromTopic and toTopic: ft = fromTopic.removeprefix("main") @@ -19,47 +18,60 @@ def publish_transform(fromTopic, toTopic): publish(path, 1) +async def set_config(topic, payload): + print(f"Set the config for {topic} to {payload}") + data.config[topic] = int(float(payload)) + + async def do_a_gesture(topic): print(f"called to do a gesture for {topic}") - # TODO: make sure the data.topics array is shuffled ánd the send in topic is always first - tl = len(data.topics) - theseTopics = data.topics[random.randint(0, tl / 2):random.randint(tl/2, tl)] - wIndex = random.randint(1, tl) + tl = data.topics.copy() + tl.remove('main' + topic) + random.shuffle(tl) + tl.insert(0, topic) + tl[0:random.randint(0, len(tl))] + wIndex = random.randint(0, len(tl)) isW = True - print(theseTopics) while isW: - wIndex+=1 - index = wIndex%len(theseTopics) - publish(theseTopics[index], 1) - publish_transform(theseTopics[index - 1], theseTopics[index]) - await asyncio.sleep(data.walkDelay) + print("walking") + wIndex += 1 + index = wIndex % len(tl) + publish(tl[index], 1) + publish_transform(tl[index - 1], tl[index]) + + await asyncio.sleep(data.config['delay']) if index > 0: - publish(theseTopics[index - 1], 0) - print(f"Go off: {theseTopics[index - 1]}") - await asyncio.sleep(data.walkDelay * 0.8) + publish(tl[index - 1], 0) + print(f"Go off: {tl[index - 1]}") + await asyncio.sleep(data.config['delay'] * 0.8) - if(random.random() > 0.8): - # TODO send message that gesture is finished + if (random.random() > data.config['probability']): print("finished the walk") publish("main/gesture" + topic, 0) isW = False - + asyncio.run_coroutine_threadsafe(publish_later("main/gesture" + topic, 1), loop) def on_connect(client, userdata, flags, reason_code, properties): print(f"Connected with result code {reason_code}") client.subscribe("main/#") + publish("main/start", 1) -async def publish_later(rule, transformTopic): +async def publish_later_by(topic, payload, delay): + await asyncio.sleep(delay) + publish(topic, payload) + + +async def publish_later(rule, msg): print( f"publish_later: Processing message with doTopic {rule['doTopic']} after {rule['delay']} seconds delay") await asyncio.sleep(rule['delay']) del rule['doingDelay'] publish(rule['doTopic'], rule['doMessage']) - publish(transformTopic, 1) + publish_transform(msg.topic, rule['doTopic']) def publish(topic, msg): @@ -78,21 +90,16 @@ def check_against_rules(msg): if (state[msg.topic]['count'][msg.payload] >= rule['count'] or rule['count'] is None) and int(float(msg.payload)) == rule['state']: - transformTopic = f"transform" + \ - msg.topic.removeprefix("main") + rule['doTopic'].removeprefix("main") - print(f"---- rule is met----") - print(rule) - if (rule['reset']): willReset = True if rule['delay']: if 'doingDelay' not in rule: rule['doingDelay'] = True - asyncio.run_coroutine_threadsafe(publish_later(rule, transformTopic), loop) + asyncio.run_coroutine_threadsafe(publish_later(rule, msg), loop) else: print('not scheduling') else: - publish(transformTopic, 1) + publish_transform(msg.topic, rule['doTopic']) publish(rule['doTopic'], rule['doMessage']) if willReset: @@ -123,7 +130,13 @@ def on_message(client, userdata, msg): # check if the message has a gesture if "gesture" in msg.topic: if msg.payload.strip() != 0: - asyncio.run_coroutine_threadsafe(do_a_gesture(msg.topic.removeprefix('main/gesture')), loop) + asyncio.run_coroutine_threadsafe(do_a_gesture( + msg.topic.removeprefix('main/gesture')), loop) + + if "config" in msg.topic: + if msg.payload.strip() != 0: + asyncio.run_coroutine_threadsafe(set_config( + msg.topic.removeprefix('main/config'), msg.payload), loop) else: check_against_rules(msg) @@ -133,7 +146,6 @@ async def main(): global loop loop = asyncio.get_running_loop() # Store the main event loop - mqttc.on_connect = on_connect mqttc.on_message = on_message