forked from Nickduino/Pi-Somfy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mymqtt.py
197 lines (169 loc) · 8.09 KB
/
mymqtt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
import sys, re, argparse
import fcntl
import os
import re
import time
import locale
import pigpio
import socket
import signal, atexit, subprocess, traceback
import threading
import json
from copy import deepcopy
try:
# pip3 install paho-mqtt
from mylog import MyLog
import paho.mqtt.client as paho
except Exception as e1:
print("\n\nThis program requires the modules located from the same github repository that are not present.\n")
print("Error: " + str(e1))
sys.exit(2)
class DiscoveryMsg():
DISCOVERY_MSG = {"name": "",
"command_topic": "somfy/%s/level/cmd",
"position_topic": "somfy/%s/level/set_state",
"set_position_topic": "somfy/%s/level/cmd",
"payload_open": "100",
"payload_close": "0",
"state_open": "100",
"state_closed": "0",
"unique_id": "",
"device": {"name": "",
"model": "Pi-Somfy controlled shutter",
"manufacturer": "Nickduino",
"identifiers": ""
}
}
def __init__(self, shutter, shutterId):
self.discovery_msg = deepcopy(DiscoveryMsg.DISCOVERY_MSG)
self.discovery_msg["name"] = shutter
self.discovery_msg["command_topic"] = DiscoveryMsg.DISCOVERY_MSG["command_topic"] % shutterId
self.discovery_msg["position_topic"] = DiscoveryMsg.DISCOVERY_MSG["position_topic"] % shutterId
self.discovery_msg["set_position_topic"] = DiscoveryMsg.DISCOVERY_MSG["set_position_topic"] % shutterId
self.discovery_msg["unique_id"] = shutterId
self.discovery_msg["device"]["name"] = "Somfy " + shutter.replace('_', ' ').title()
self.discovery_msg["device"]["identifiers"] = shutterId
def __str__(self):
return json.dumps(self.discovery_msg)
class MQTT(threading.Thread, MyLog):
connected_flag = False
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None):
threading.Thread.__init__(self, group=group, target=target, name="MQTT")
self.shutdown_flag = threading.Event()
self.t = ()
self.args = args
self.kwargs = kwargs
if kwargs["log"] != None:
self.log = kwargs["log"]
if kwargs["shutter"] != None:
self.shutter = kwargs["shutter"]
if kwargs["config"] != None:
self.config = kwargs["config"]
return
def receiveMessageFromMQTT(self, client, userdata, message):
self.LogInfo("starting receiveMessageFromMQTT")
try:
msg = str(message.payload.decode("utf-8"))
topic = message.topic
self.LogInfo("message received from MQTT: "+topic+" = "+msg)
[prefix, shutterId, property, command] = topic.split("/")
if (command == "cmd"):
self.LogInfo("sending message: "+str(msg))
if msg == "STOP":
self.shutter.stop(shutterId)
elif int(msg) == 0:
self.shutter.lower(shutterId)
elif int(msg) == 100:
self.shutter.rise(shutterId)
elif (int(msg) > 0) and (int(msg) < 100):
currentPosition = self.shutter.getPosition(shutterId)
if int(msg) > currentPosition:
self.shutter.risePartial(shutterId, int(msg))
elif int(msg) < currentPosition:
self.shutter.lowerPartial(shutterId, int(msg))
else:
self.LogError("received unkown message: "+topic+", message: "+msg)
except Exception as e1:
self.LogError("Exception Occured: " + str(e1))
self.LogInfo("finishing receiveMessageFromMQTT")
def sendMQTT(self, topic, msg):
self.LogInfo("sending message to MQTT: " + topic + " = " + msg)
self.t.publish(topic,msg,retain=True)
def sendStartupInfo(self):
for shutter, shutterId in sorted(self.config.ShuttersByName.items(), key=lambda kv: kv[1]):
self.sendMQTT("homeassistant/cover/"+shutterId+"/config", str(DiscoveryMsg(shutter, shutterId)))
def on_connect(self, client, userdata, flags, rc):
if rc==0:
self.LogInfo("Connected to MQTT with result code "+str(rc))
self.connected_flag = True
for shutter, shutterId in sorted(self.config.ShuttersByName.items(), key=lambda kv: kv[1]):
self.LogInfo("Subscribe to shutter: "+shutter)
self.t.subscribe("somfy/"+shutterId+"/level/cmd")
if self.config.EnableDiscovery == True:
self.LogInfo("Sending Home Assistant MQTT Discovery messages")
self.sendStartupInfo()
else:
print("Bad connection Returned code= ",rc)
self.connected_flag=False
def on_disconnect(self, client, userdata, rc=0):
self.connected_flag=False
if rc != 0:
self.LogInfo("Disconnected from MQTT Server. result code: " + str(rc))
#while not self.connected_flag: #wait in loop
# self.LogInfo("Waiting 30sec for reconnect")
# time.sleep(30)
# self.t.connect(self.config.MQTT_Server,self.config.MQTT_Port)
def set_state(self, shutterId, level):
self.LogInfo("Received request to set Shutter "+shutterId+" to "+str(level))
self.sendMQTT("somfy/"+shutterId+"/level/set_state", str(level))
def run(self):
self.connected_flag = False
self.LogInfo("Entering MQTT polling loop")
# Setup the mqtt client
self.t = paho.Client(client_id=self.config.MQTT_ClientID)
if not (self.config.MQTT_Password.strip() == ""):
self.t.username_pw_set(username=self.config.MQTT_User,password=self.config.MQTT_Password)
self.t.on_connect = self.on_connect
self.t.on_message = self.receiveMessageFromMQTT
self.t.on_disconnect = self.on_disconnect
self.shutter.registerCallBack(self.set_state)
# Startup the mqtt listener
error_failure_count = 5
error = 0
while not self.shutdown_flag.is_set():
# Loop until the server is available
try:
self.LogInfo("Connecting to MQTT server")
self.t.connect(self.config.MQTT_Server,self.config.MQTT_Port)
time.sleep(10)
break
except Exception as e:
error += 1
self.LogInfo("Exception in MQTT connect " + str(error) + ": "+ str(e.args))
if error >= error_failure_count:
self.LogError(f"MQTT connect error count exceeded failure threshold of {error_failure_count}. MQQT functionality will not be active. Have you installed mosquitto?")
return
time.sleep(2)
error = 0
while not self.shutdown_flag.is_set():
# Loop and poll for incoming requests
try:
#NOTE: Timeout value must be smaller than MQTT keep_alive (which is 60s by default)
self.t.loop(timeout=30)
# self.t.loop_start()
if self.connected_flag == False:
self.LogInfo("Re-Connecting to MQTT server")
self.t.connect(self.config.MQTT_Server,self.config.MQTT_Port)
time.sleep(10)
except Exception as e:
error += 1
self.LogInfo("Critical MQTT exception " + str(error) + ": "+ str(e.args))
if error >= error_failure_count:
self.LogError(f"MQTT connect error count exceeded failure threshold of {error_failure_count}. MQQT functionality will not be active.")
return
time.sleep(0.5) #Wait half a second when an exception occurs
self.LogError("Received Signal to shut down MQTT thread")
return