diff --git a/rule-listener/data.py b/rule-listener/data.py new file mode 100644 index 0000000..a4cf49b --- /dev/null +++ b/rule-listener/data.py @@ -0,0 +1,45 @@ + +rules = { + "main/fan/1": [ + { # after the fan has been on 2 times, another fan should be turned on + "count": 2, # the amount of times + "state": "on", # it has had this state + "doTopic": "main/fan/2", # i will send to topic + "doMessage": "on", # this message + "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": "off", # it has had this state + "doTopic": "main/fan/2", # i will send to topic + "doMessage": "on", # 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": False, # the amount of times. If its false, just do it. + "state": "on", # it has had this state + "doTopic": "main/fan/1", # i will send to topic + "doMessage": "off", # this message + "delay": 4, # after this amount of seconds + "reset": False, # and i should reset my count afterwards + }, + { # Turn the fan on every time after 6 minute + "count": 3, # the amount of times. If its false, just do it. + "state": "on", # it has had this state + "doTopic": "main/fan/1", # i will send to topic + "doMessage": "off", # this message + "delay": 360, # after this amount of seconds + "reset": False, # and i should reset my count afterwards + }, + { # Every 5 minutes, do gesture X + "count": 1, + "state": "on", + "doTopic": "gesture/fan/1", + "doMessage": "on", + "delay": 5 * 60, + "reset": True + } + ] +} diff --git a/rule-listener/rules.py b/rule-listener/rules.py deleted file mode 100644 index 0a87709..0000000 --- a/rule-listener/rules.py +++ /dev/null @@ -1,12 +0,0 @@ -{ - "main/fan/1": [ - { # after the fan has been on 2 times, another fan should be turned on - "count": 2, # the amount of times - "state": "on", # it has had this state - "doTopic": "main/fan/2", # i will send to topic - "doMessage": "on", # this message - "delay": 3, # 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 cc9926d..ce4a287 100644 --- a/rule-listener/script.py +++ b/rule-listener/script.py @@ -1,23 +1,46 @@ import paho.mqtt.client as mqtt import asyncio import secrets -import rules +import data +from random import randrange + state = {} - +rules = data.rules mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) +async def on_gesture_message(): + state = False + delay = 3 + for i in range(randrange(4,8)): + await asyncio.sleep(delay) + delay = delay * 0.7 + if state: + print("do left") + state = False + else: + print("do right") + state = True + + print("done") + + + def on_connect(client, userdata, flags, reason_code, properties): print(f"Connected with result code {reason_code}") client.subscribe("main/#") + mqttc.message_callback_add("gesture/#", on_gesture_message) + + client.subscribe("gesture/#") -async def publish_later(topic, msg, delay): - print(f"publish_later: Processing message with topic {topic} after {delay} seconds delay") - await asyncio.sleep(delay) - print(f"publish_later: completed delay") - publish(topic, msg) +async def publish_later(rule): + 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']) def publish(topic, msg): + print(f"publish {topic} {msg}") result = mqttc.publish(topic, msg) status = result[0] @@ -27,34 +50,49 @@ def publish(topic, msg): def check_against_rules(msg): if msg.topic in rules: - print(f"... ... Found {len(rules[msg.topic])} rules on this topic") - for rule in rules[msg.topic]: - print(f"... ... Rule is met when the count is above {rule['count']}. Current count is {state[msg.topic]['count']}") + print(f"Found {len(rules[msg.topic])} rules on this topic"), + + willReset = False - if state[msg.topic]['count'] > rule['count']: + for rule in rules[msg.topic]: + print(f"Rule: when the count is > {rule['count']}. Current = {state[msg.topic]['count'][msg.payload]} on payload {msg.payload}"), + + if (state[msg.topic]['count'][msg.payload] >= rule['count'] or rule['count'] == False) and msg.payload == rule['state']: if(rule['reset']): - state[msg.topic]['count'] = 0 - + willReset = True if rule['delay']: - asyncio.run_coroutine_threadsafe(publish_later(rule['doTopic'], rule['doMessage'], rule['delay']), loop) + if not 'doingDelay' in rule: + rule['doingDelay'] = True + asyncio.run_coroutine_threadsafe(publish_later(rule), loop) + else: + print('not scheduling') else: publish(rule['doTopic'], rule['doMessage']) + + if willReset: + state[msg.topic]['count'][msg.payload] = 0 + else: print("... ... i have no rules for this topic") # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): - print("on_message") + print("on message") if msg.retain: return False - - if msg.topic in state: - state[msg.topic]["count"] += 1 else: - state[msg.topic] = {} - state[msg.topic]["count"] = 0 - - check_against_rules(msg) + msg.payload = str(msg.payload.decode("utf-8")) + + if len(msg.payload) > 140: + print("way to long of a message, not gonna store that") + return False + + if msg.topic not in state: + state[msg.topic] = {'count': {}} + + state[msg.topic]['count'].setdefault(msg.payload, 0) + state[msg.topic]['count'][msg.payload] += 1 + check_against_rules(msg) async def main(): global loop @@ -69,7 +107,7 @@ async def main(): # Start the MQTT loop in a background thread mqttc.loop_start() - + # Keep the asyncio event loop running await asyncio.Event().wait()