change rules
This commit is contained in:
parent
086dba5856
commit
abde312698
BIN
rule-listener/__pycache__/script.cpython-312.pyc
Normal file
BIN
rule-listener/__pycache__/script.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,47 +1,103 @@
|
||||
topics = [
|
||||
"main/fan/one",
|
||||
"main/fan/two",
|
||||
"main/printer/one",
|
||||
"main/printer/two",
|
||||
"main/lamp/one",
|
||||
"main/radio/one"]
|
||||
walkDelay = 1
|
||||
baseRule = {
|
||||
"state": 1,
|
||||
"count": 1,
|
||||
"doMessage": 1,
|
||||
"delay": 30,
|
||||
"reset": False,
|
||||
"doTopic": ""
|
||||
}
|
||||
|
||||
rules = {
|
||||
"main/printer/one": [
|
||||
{
|
||||
"description": "Every time a printer is turned on, plan the gesture for 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
|
||||
"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",
|
||||
"count": 3, # 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": False, # after this amount of seconds
|
||||
"reset": True, # and i should reset my count afterwards
|
||||
},
|
||||
],
|
||||
"main/fan/one": [
|
||||
{ # 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/two", # 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
|
||||
{
|
||||
"description": "after the fan has been on 2 times, another fan should be turned on",
|
||||
"count": 2, # 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": 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/two", # 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
|
||||
# { # 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
|
||||
# },
|
||||
|
||||
],
|
||||
"main/fan/two": [
|
||||
{
|
||||
"description": "after the fan has been on 2 times, another fan should be turned on",
|
||||
"count": 2, # 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": False, # 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/three", # 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
|
||||
|
||||
],
|
||||
"main/radio/one": [
|
||||
{
|
||||
"description": "after the radio has been on 2 times, another fan should be turned on",
|
||||
"count": 2, # 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": 10, # after this amount of seconds
|
||||
"reset": True, # 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/three", # 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/one",
|
||||
"doMessage": "on",
|
||||
"delay": 5 * 60,
|
||||
"reset": True
|
||||
}
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@ -53,4 +109,4 @@ gestures = {
|
||||
"multiplier": 0.7,
|
||||
"range": [4, 8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,108 +2,138 @@ import paho.mqtt.client as mqtt
|
||||
import asyncio
|
||||
import secrets
|
||||
import data
|
||||
from random import randrange
|
||||
import random
|
||||
import pprint
|
||||
|
||||
|
||||
|
||||
state = {}
|
||||
rules = data.rules
|
||||
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
||||
|
||||
async def do_a_gesture(gesture, topic):
|
||||
state = False
|
||||
delay = gesture["delay"]
|
||||
for i in range(randrange(gesture["range"][0],gesture["range"][1])):
|
||||
await asyncio.sleep(delay)
|
||||
delay = delay * gesture["multiplier"]
|
||||
if state:
|
||||
publish("gesture" + topic, gesture["on"])
|
||||
state = False
|
||||
else:
|
||||
publish("gesture" + topic, gesture["off"])
|
||||
state = True
|
||||
def publish_transform(fromTopic, toTopic):
|
||||
if fromTopic and toTopic:
|
||||
ft = fromTopic.removeprefix("main")
|
||||
tt = toTopic.removeprefix("main")
|
||||
path = "transform" + ft + tt
|
||||
publish(path, 1)
|
||||
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
if index > 0:
|
||||
publish(theseTopics[index - 1], 0)
|
||||
print(f"Go off: {theseTopics[index - 1]}")
|
||||
await asyncio.sleep(data.walkDelay * 0.8)
|
||||
|
||||
if(random.random() > 0.8):
|
||||
# TODO send message that gesture is finished
|
||||
print("finished the walk")
|
||||
publish("main/gesture" + topic, 0)
|
||||
isW = False
|
||||
|
||||
|
||||
publish("main/gesture" + topic, 0)
|
||||
|
||||
|
||||
def on_connect(client, userdata, flags, reason_code, properties):
|
||||
print(f"Connected with result code {reason_code}")
|
||||
client.subscribe("main/#")
|
||||
|
||||
|
||||
async def publish_later(rule, transformTopic):
|
||||
print(f"publish_later: Processing message with doTopic {rule['doTopic']} after {rule['delay']} seconds delay")
|
||||
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)
|
||||
|
||||
|
||||
def publish(topic, msg):
|
||||
print(f"publish {topic} {msg}")
|
||||
result = mqttc.publish(topic, msg)
|
||||
|
||||
status = result[0]
|
||||
|
||||
if not status == 0:
|
||||
print(f"Failed to send message to topic {topic}")
|
||||
|
||||
|
||||
def check_against_rules(msg):
|
||||
if msg.topic in rules:
|
||||
print(f"Found {len(rules[msg.topic])} rules on this topic"),
|
||||
|
||||
print(f"Found {len(rules[msg.topic])} rules on {msg.topic}"),
|
||||
willReset = False
|
||||
|
||||
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']:
|
||||
print(f"transform topic is {transformTopic}")
|
||||
if(rule['reset']):
|
||||
for rule in rules[msg.topic]:
|
||||
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 not 'doingDelay' in rule:
|
||||
if 'doingDelay' not in rule:
|
||||
rule['doingDelay'] = True
|
||||
asyncio.run_coroutine_threadsafe(publish_later(rule, transformTopic), loop)
|
||||
else:
|
||||
else:
|
||||
print('not scheduling')
|
||||
else:
|
||||
publish(transformTopic, 1)
|
||||
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")
|
||||
if msg.retain:
|
||||
return False
|
||||
else:
|
||||
msg.payload = str(msg.payload.decode("utf-8"))
|
||||
|
||||
print(f'msg: {msg.payload} topic: {msg.topic}')
|
||||
|
||||
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 if the message has a gesture
|
||||
if "gesture" in msg.topic:
|
||||
if msg.payload.strip() in data.gestures:
|
||||
asyncio.run_coroutine_threadsafe(do_a_gesture(data.gestures[msg.payload], msg.topic.removeprefix('main/gesture')), loop)
|
||||
if msg.payload.strip() != 0:
|
||||
asyncio.run_coroutine_threadsafe(do_a_gesture(msg.topic.removeprefix('main/gesture')), loop)
|
||||
|
||||
else:
|
||||
check_against_rules(msg)
|
||||
|
||||
|
||||
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
|
||||
|
||||
@ -113,9 +143,11 @@ async def main():
|
||||
|
||||
# Start the MQTT loop in a background thread
|
||||
mqttc.loop_start()
|
||||
|
||||
# Keep the asyncio event loop running
|
||||
|
||||
# asyncio.run_coroutine_threadsafe(do_a_gesture(data.topics[0].removeprefix('main')), loop)
|
||||
|
||||
# # Keep the asyncio event loop running
|
||||
await asyncio.Event().wait()
|
||||
|
||||
# Run the main function
|
||||
asyncio.run(main())
|
||||
asyncio.run(main())
|
||||
|
Loading…
Reference in New Issue
Block a user