This repository has been archived by the owner on Apr 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from roopesh/separate_socket
Background socket and mqtt
- Loading branch information
Showing
8 changed files
with
459 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[{"id":"cbfaf013.0e5e","type":"tab","label":"Monitor QolSys Panel","disabled":false,"info":""},{"id":"20c47d1f.7e57d2","type":"debug","z":"cbfaf013.0e5e","name":"mqtt out","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":980,"y":120,"wires":[]},{"id":"a272ddf7.56ba6","type":"debug","z":"cbfaf013.0e5e","name":"Zone id to zone name mapping","active":false,"tosidebar":true,"console":false,"tostatus":true,"complete":"$flowContext(\"zones\")\t","targetType":"jsonata","statusVal":"$flowContext(\"zones\")","statusType":"auto","x":1030,"y":260,"wires":[]},{"id":"7593a9f9.4b4dc8","type":"function","z":"cbfaf013.0e5e","name":"initialize zone ids and names","func":"class door_window {\n constructor(zoneid, entity_id, name, state=\"Closed\", partition_id=0, device_class=\"door\") {\n this.state = state\n this.id = zoneid\n this.device_class = device_class\n this.name = name\n this.entity_id = entity_id\n this.partition_id = partition_id\n this.payload_on = \"Open\"\n this.payload_off = \"Closed\"\n this.config_topic = \"homeassistant/binary_sensor/\" + entity_id + \"/config\"\n this.state_topic = \"mqtt_states/binary_sensor/\" + entity_id + \"/state\"\n //node.log(\"Name: \" + name + \"\\n\" + \n // \"ZoneID: \" + zoneid + \"\\n\" +\n // \"EntityID: \" + entity_id + \"\\n\" + \n // \"PartitionID: \" + partition_id + \"\\n\" + \n // \"Device Class: \" + device_class + \"\\n\" +\n // \"State: \" + state)\n }\n toString(self){\n return self.name\n } \n}\n\nvar zones = flow.get(\"zones\")\n\nfor (var zone in msg.payload) {\n// node.log(zone)\n var id = msg.payload[zone][\"zone_id\"]\n var name = msg.payload[zone][\"name\"]\n var state = msg.payload[zone][\"status\"]\n var partition_id = msg.payload[zone][\"partition_id\"]\n var entity_id = name.replace(/\\W/g, \"_\").toLowerCase()\n var thisZone = new door_window(zoneid=id, entity_id=entity_id, name=name, state=state, partition_id=partition_id)\n zones[id] = thisZone\n// node.log(thisZone)\n \n}\n//msg.payload = zones\n//node.log(\"Zones:\" + zones)\nflow.set(\"zones\", zones)\nreturn msg\n","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\n\nclass door_window {\n constructor(zoneid, entity_id=\"\", name, device_class=\"door\", state=\"Closed\", partition_id=0 ) {\n this.state = state\n this.id = zoneid\n this.name = name\n this.device_class = device_class\n this.entity_id = entity_id\n this.partition_id = partition_id\n this.payload_on = \"Open\"\n this.payload_off = \"Closed\"\n this.config_topic = \"homeassistant/binary_sensor/\" + entity_id + \"/config\"\n this.state_topic = \"mqtt_states/binary_sensor/\" + entity_id + \"/state\" \n }\n \n}\nzones = []\n\n//zones[1] = new door_window(1, \"front_door\", \"Front Door\")\n//zones[2] = new door_window(2, \"trash_gate\", \"Trash Gate\")\n//zones[3] = new door_window(3, \"neela_s_garage_entry\", \"Neela's Garage Entry\")\n//zones[4] = new door_window(4, \"roopesh_s_garage_entry\", \"Roopesh's Garage Entry\")\n//zones[6] = new door_window(6, \"great_room_slider\", \"Great Room Slider\")\n//zones[7] = new door_window(7, \"garage_side_door\", \"Garage Side Door\")\n//zones[9] = new door_window(9, \"kitchen_slider\", \"Kitchen Slider\")\n//zones[10] = new door_window(10, \"game_room_slider\", \"Game Room Slider\")\n//zones[11] = new door_window(11, \"loft_slider\", \"Loft Slider\")\n//zones[12] = new door_window(12, \"guest_room_side_gate\", \"Guest Room Side Gate\")\nflow.set(\"zones\", zones)\n","finalize":"","x":460,"y":260,"wires":[["a272ddf7.56ba6","4e0e16a3.7cd0f8"]]},{"id":"59822226.0248cc","type":"function","z":"cbfaf013.0e5e","name":"Build MQTT Update Payload","func":"var zid = msg.payload[\"zone\"][\"zone_id\"]\nvar zones = flow.get(\"zones\")\nvar state_topic = zones[zid][\"state_topic\"]\nvar state = msg.payload[\"zone\"][\"status\"]\nzones[zid][\"state\"] = state\nflow.set(\"zones\", zones)\nmsg.payload = state\nmsg.topic = state_topic\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":580,"y":120,"wires":[["7a8a7809.26cf68","20c47d1f.7e57d2"]]},{"id":"4e0e16a3.7cd0f8","type":"array-loop","z":"cbfaf013.0e5e","name":"loop zones","key":"al4e0e16a37cd0f8","keyType":"msg","reset":true,"resetValue":"value-null","array":"zones","arrayType":"flow","x":430,"y":320,"wires":[["89ebb812.5ea3a8"],["a51867e3.622258"]]},{"id":"89ebb812.5ea3a8","type":"debug","z":"cbfaf013.0e5e","name":"All HA Init'd","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":970,"y":340,"wires":[]},{"id":"a51867e3.622258","type":"switch","z":"cbfaf013.0e5e","name":"","property":"payload","propertyType":"msg","rules":[{"t":"null"},{"t":"empty"},{"t":"else"}],"checkall":"false","repair":false,"outputs":3,"x":230,"y":420,"wires":[["4e0e16a3.7cd0f8"],["4e0e16a3.7cd0f8"],["48744f25.dce7a"]]},{"id":"3f8da6fc.a7238a","type":"catch","z":"cbfaf013.0e5e","name":"Catch","scope":null,"uncaught":false,"x":530,"y":40,"wires":[["cd788dfe.d978"]]},{"id":"cd788dfe.d978","type":"debug","z":"cbfaf013.0e5e","name":"All Uncaught Errors","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":990,"y":40,"wires":[]},{"id":"dfd2c176.68a0e","type":"debug","z":"cbfaf013.0e5e","name":"Initialized in HA","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":980,"y":420,"wires":[]},{"id":"1534a5cd.807cea","type":"mqtt out","z":"cbfaf013.0e5e","name":"","topic":"","qos":"","retain":"","broker":"b1167957.68aa08","x":810,"y":460,"wires":[]},{"id":"48744f25.dce7a","type":"function","z":"cbfaf013.0e5e","name":"Build MQTT topic and payload","func":"//var topic = \"\"\ntry {\n var type = msg.payload[\"type\"]\n var entity_id = msg.payload[\"entity_id\"]\n var name = msg.payload[\"name\"]\n var device_class = msg.payload[\"device_class\"]\n var state_topic = msg.payload[\"state_topic\"]\n var config_topic = msg.payload[\"config_topic\"]\n var payload_on = msg.payload[\"payload_on\"]\n var payload_off = msg.payload[\"payload_off\"]\n var state = msg.payload[\"state\"]\n var config_msg = {\n \"topic\": config_topic,\n \"payload\": {\n \"name\": name,\n \"device_class\": device_class,\n \"state_topic\": state_topic,\n \"payload_on\": payload_on,\n \"payload_off\": payload_off\n }\n }\n}\ncatch(err) {\n node.log(\"failed making variables\", err)\n}\n\n\n//msg.topic = config_topic\n\n//msg.payload = config_msg\ntry {\n var zone_update_msg = {\n \"topic\": state_topic,\n \"payload\": state\n }\n}\ncatch(err) {\n node.log(\"failed making zone_update_msg\")\n}\n//msg.zone_update_msg = zone_update_msg\n//msg.config_msg = config_msg\n//flow.set(\"zone_update_msg\", zone_update_msg)\n//flow.set(\"config_msg\", config_msg)\ntry {\n node.log(\"config msg: \" + config_msg.topic + config_msg.payload.name)\n node.log(\"zone msg: \" + zone_update_msg.topic + zone_update_msg.payload)\n node.log(\"msg: \" + msg.payload.name)\n}\ncatch(err) {\n node.log(\"error logging data\")\n}\n//return(msg, config_msg, zone_update_msg)\n//return(zone_update_msg, config_msg, msg)\nreturn[msg, config_msg, zone_update_msg]","outputs":3,"noerr":0,"initialize":"","finalize":"","x":470,"y":420,"wires":[["4e0e16a3.7cd0f8"],["dfd2c176.68a0e","1534a5cd.807cea"],["94a3b1f.1389e5"]]},{"id":"7a8a7809.26cf68","type":"mqtt out","z":"cbfaf013.0e5e","name":"","topic":"","qos":"","retain":"","broker":"b1167957.68aa08","x":790,"y":160,"wires":[]},{"id":"c1e92bd3.455468","type":"mqtt in","z":"cbfaf013.0e5e","name":"INFO","topic":"qolsys/info","qos":"0","datatype":"auto","broker":"b1167957.68aa08","x":110,"y":100,"wires":[["15befb3c.f83975"]]},{"id":"ec802f9d.c402f","type":"change","z":"cbfaf013.0e5e","name":"Set Zones payload for INFO","rules":[{"t":"set","p":"payload","pt":"msg","to":"$lookup($lookup(payload, \"partition_list\"[0]), \"zone_list\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":180,"y":260,"wires":[["ff9d620d.a7c55","7593a9f9.4b4dc8"]]},{"id":"df81c870.4ecda8","type":"mqtt out","z":"cbfaf013.0e5e","name":"Send INFO request","topic":"qolsys/requests","qos":"","retain":"","broker":"b1167957.68aa08","x":330,"y":40,"wires":[]},{"id":"46573582.43dbcc","type":"inject","z":"cbfaf013.0e5e","name":"Start with INFO","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"{\"event\":\"INFO\",\"token\":\"shw9s8\"}","payloadType":"json","x":120,"y":40,"wires":[["df81c870.4ecda8"]]},{"id":"15befb3c.f83975","type":"json","z":"cbfaf013.0e5e","name":"","property":"payload","action":"","pretty":false,"x":230,"y":140,"wires":[["7488361e.748058"]]},{"id":"ff9d620d.a7c55","type":"debug","z":"cbfaf013.0e5e","name":"Zones Payload","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":980,"y":180,"wires":[]},{"id":"7488361e.748058","type":"switch","z":"cbfaf013.0e5e","name":"","property":"payload","propertyType":"msg","rules":[{"t":"jsonata_exp","v":"\"ZONE_EVENT\" = $lookup(payload, \"event\")","vt":"jsonata"},{"t":"jsonata_exp","v":"\"ZONE_UPDATE\" = $lookup(payload, \"event\")","vt":"jsonata"},{"t":"jsonata_exp","v":"\"INFO\" = $lookup(payload, \"event\")","vt":"jsonata"},{"t":"jsonata_exp","v":"\"ARMING\" = $lookup(payload, \"event\")","vt":"jsonata"}],"checkall":"true","repair":false,"outputs":4,"x":350,"y":140,"wires":[["59822226.0248cc"],["59822226.0248cc"],["ec802f9d.c402f"],[]]},{"id":"94a3b1f.1389e5","type":"delay","z":"cbfaf013.0e5e","name":"Zone Update Delay","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":590,"y":500,"wires":[["1534a5cd.807cea","20ab17af.414598"]]},{"id":"e3a9fee7.6b71e","type":"mqtt in","z":"cbfaf013.0e5e","name":"ZONE UPDATE","topic":"qolsys/zone_update","qos":"0","datatype":"auto","broker":"b1167957.68aa08","x":80,"y":180,"wires":[["15befb3c.f83975"]]},{"id":"b49e6dbf.498da","type":"mqtt in","z":"cbfaf013.0e5e","name":"ZONE EVENT","topic":"qolsys/zone_event","qos":"0","datatype":"auto","broker":"b1167957.68aa08","x":90,"y":140,"wires":[["15befb3c.f83975"]]},{"id":"20ab17af.414598","type":"debug","z":"cbfaf013.0e5e","name":"Zone Update in HA","active":false,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":990,"y":500,"wires":[]},{"id":"b1167957.68aa08","type":"mqtt-broker","name":"HA MQTT","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import sys | ||
import time | ||
import json | ||
import logging | ||
from paho.mqtt.client import MQTTMessage | ||
import qolsys_socket, mqtt_client | ||
from mqtt_subscriber import MQTTSubscriber | ||
|
||
################################################################################ | ||
# Code | ||
#args = {} | ||
|
||
def qolsys_data_received(data:dict): | ||
''' This is where any json data coming from the qolsys panel will be sent. | ||
In this case I have the data being published to a mqtt topic, but you can do what you want. | ||
Parameters: | ||
data: json object containing the output from the qolsys panel''' | ||
|
||
args = get_command_line_args() | ||
if "mqtt-broker" in args: | ||
mqtt_broker = args["mqtt-broker"] | ||
mqtt_port = args["mqtt-port"] if "mqtt-port" in args else 1883 | ||
topic = "qolsys/" | ||
jdata = json.loads(data) | ||
event_type = jdata["event"] | ||
if event_type == "INFO": | ||
topic += "info" | ||
if event_type == "ZONE_EVENT": | ||
topic += "zone_event" | ||
if event_type == "ZONE_UDPATE": | ||
topic += "zone_update" | ||
|
||
logging.debug(("publishing " + event_type + " event to: " + topic)) | ||
mq = mqtt_client.mqtt(mqtt_broker, mqtt_port) | ||
mq.publish(topic, data) | ||
else: | ||
print(data) | ||
|
||
def main(): | ||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s: %(levelname)s: %(module)s: %(funcName)s: %(lineno)d: %(message)s') | ||
logging.debug(("Command line arguments:", sys.argv[1:])) | ||
args = get_command_line_args() | ||
|
||
#Deal with some arguments that stop execution | ||
if "help" in args: | ||
help() | ||
if not "token" in args: | ||
print("Qolsys IQ 2 Panel token required") | ||
help()#sys.exit() | ||
if not "host" in args: | ||
print("Qolsys IQ 2 Panel IP address or hostname required") | ||
help()#sys.exit() | ||
|
||
token, host = args["token"], args["host"] | ||
port = int(args["port"]) if "port" in args else 12345 | ||
timeout = int(args["timeout"]) if "timeout" in args else 86400 | ||
mqtt_broker = args["mqtt-broker"] if "mqtt-broker" in args else None | ||
mqtt_port = args["mqtt-port"] if "mqtt-port" in args else 1883 | ||
topics = [] #args["topics"] if "topics" in args else ["qolsys/requests"] | ||
if args["topics"]: | ||
topic_data = str(args["topics"]) | ||
logging.debug(("topics arg:", topic_data)) | ||
if topic_data.find(",") > 0: | ||
topic_array = args["topics"].split(",") | ||
logging.debug(("topic_array:", topic_array)) | ||
for t in topic_array: | ||
logging.debug(("t:", t)) | ||
topics.append(t) | ||
else: | ||
topics.append(topic_data) | ||
else: | ||
raise("No topics") | ||
|
||
|
||
logging.debug("Creating qolsys_socket") | ||
qolsys = qolsys_socket.qolsys() | ||
|
||
qolsys.create_socket(hostname=host, port=port, token=token, cb=qolsys_data_received, timeout=timeout) | ||
|
||
logging.debug("main: qolsys_socket created") | ||
|
||
#logging.debug("doing the info check on startup") | ||
#qolsys_status(qolsys, token) | ||
|
||
#qolsys_arm(qolsys,token,"stay") | ||
if mqtt_broker: | ||
mqtt_sub = MQTTSubscriber(broker=mqtt_broker, port=mqtt_port, qolsys=qolsys, topics=topics) | ||
else: | ||
logging.info("No MQTT Broker. Only getting status events from panel") | ||
|
||
|
||
def get_command_line_args() -> dict: | ||
args = {} | ||
for arg in sys.argv[1:]: | ||
arg_name = "" | ||
arg_value = "" | ||
arg_name = arg.split("=",1)[0] | ||
arg_name = arg_name.split("--",1)[1] | ||
try: | ||
arg_value = arg.split("=",1)[1] | ||
except: | ||
arg_value = "" | ||
logging.debug(("argument name: ", arg_name, " | ", arg_value)) | ||
this_arg = { arg_name: arg_value } | ||
args.update(this_arg) | ||
logging.debug(("all arguments: ", args)) | ||
return args | ||
|
||
def help(): | ||
help_text = """ | ||
Parameters: | ||
Required: | ||
--host IP address or hostname of the Qolsys IQ 2(+) Panel | ||
--port Port to connect on the Qolsys panel. Usually 12345 | ||
--timeout Timeout (seconds) to wait after last data sent/received from the panel before disconnecting. Default will be one day. | ||
--token Token from the Qolsys panel | ||
--usercode (UNUSED) If you want to use disarm, you need to supply a usercode | ||
Optional: | ||
--mqtt-broker IP address or hostname of the MQTT broker | ||
--mqtt-port MQTT broker port to connect to (default is 1883) | ||
--topics A list (array) of topics to subscribe to for qolsys event requests e.g. --topics=["qolsys/requests"] (Default) | ||
Usage: | ||
python3 main.py --host=192.168.1.123 --port=12345 --token=yourtoken --timeout=86400 --mqtt-broker=192.168.1.2 --mqtt-port=1883 --topics=["qolsys/requests"] | ||
""" | ||
print(help_text) | ||
sys.exit() | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import paho.mqtt.client as pmqtt | ||
import paho.mqtt.subscribe as smqtt | ||
import json | ||
import time | ||
import logging | ||
|
||
class mqtt: | ||
|
||
def __init__(self, broker: str, port=1883): | ||
self.client = "" | ||
self.broker = broker | ||
self.port = port | ||
self.connect() | ||
|
||
def connect(self): | ||
self.client = pmqtt.Client() | ||
self.client.connect(host=self.broker, port=self.port) | ||
|
||
def publish(self, topic:str, message:str): | ||
if topic == "" or message == "": | ||
raise Exception("Topic and Message required") | ||
published = self.client.publish(topic, message) | ||
while not published.is_published(): | ||
time.sleep(0.5) | ||
print("published:", published.rc) | ||
|
||
def subscribe(self, topics:[], cb:callable): | ||
if topics == []: | ||
raise Exception("Need a topic to listen to") | ||
logging.debug("Starting the MQTT subscriber") | ||
smqtt.callback(cb, topics, hostname=self.broker) | ||
#subscribed.callback(cb,) | ||
#self.client.subscribe(topic) | ||
#self.client.on | ||
|
Oops, something went wrong.