comparison service/rdf_to_mqtt/rdf_to_mqtt.py @ 778:acf58b83022f

rdf_to_mqtt sylvania bulbs and code cleanup and k8s updates
author drewp@bigasterisk.com
date Sat, 08 Aug 2020 13:56:39 -0700
parents df7035db28f1
children e7eb3fc8db54
comparison
equal deleted inserted replaced
777:df7035db28f1 778:acf58b83022f
28 ) 28 )
29 29
30 devs = { 30 devs = {
31 ROOM['kitchenLight']: { 31 ROOM['kitchenLight']: {
32 'root': 'h801_skylight', 32 'root': 'h801_skylight',
33 'hasWhite': True,
33 }, 34 },
34 ROOM['kitchenCounterLight']: { 35 ROOM['kitchenCounterLight']: {
35 'root': 'h801_counter', 36 'root': 'h801_counter',
37 'hasWhite': True,
36 }, 38 },
37 ROOM['livingLampShelf']: { 39 ROOM['livingLampShelf']: {
38 'root': 'sonoff_0/switch/sonoff_basic_relay/command', 40 'root': 'sonoff_0/switch/sonoff_basic_relay/command',
39 'values': 'binary', 41 'values': 'binary',
40 }, 42 },
58 'root': 'theater_blaster/ir_out', 60 'root': 'theater_blaster/ir_out',
59 'values': 'theaterOutputs', 61 'values': 'theaterOutputs',
60 }, 62 },
61 ROOM['bedHeadboard']: { 63 ROOM['bedHeadboard']: {
62 'root': 'bed/light/headboard/command', 64 'root': 'bed/light/headboard/command',
63 }, 65 'hasWhite': True,
64 #-t theater_blaster/ir_out -m 'input_game' 66 },
65 #-t theater_blaster/ir_out -m 'input_bd' 67 # https://github.com/Koenkk/zigbee2mqtt.io/blob/new_api/docs/information/mqtt_topics_and_message_structure.md#general
66 #-t theater_blaster/ir_out -m 'input_cbl' 68 ROOM['syl1']: {
67 #-t theater_blaster/ir_out -m 'input_pc' 69 'root': 'zigbee2mqtt/syl1/set',
68 #-t theater_blaster/ir_out/volume_up -m '{"times":1}' 70 'hasBrightness': True,
69 #-t theater_blaster/ir_out/volume_down -m '{"times":1}' 71 'defaults': {
72 'transition': 0,
73 }
74 },
75 ROOM['syl2']: {
76 'root': 'zigbee2mqtt/syl2/set',
77 'hasBrightness': True,
78 'defaults': {
79 'transition': 0,
80 }
81 },
82 ROOM['syl3']: {
83 'root': 'zigbee2mqtt/syl3/set',
84 'hasBrightness': True,
85 'defaults': {
86 'transition': 0,
87 }
88 },
89 ROOM['syl4']: {
90 'root': 'zigbee2mqtt/syl4/set',
91 'hasBrightness': True,
92 'defaults': {
93 'transition': 0,
94 }
95 },
70 } 96 }
71 97
72 98
73 class OutputPage(PrettyErrorHandler, cyclone.web.RequestHandler): 99 class OutputPage(PrettyErrorHandler, cyclone.web.RequestHandler):
100
74 @STATS.putRequests.time() 101 @STATS.putRequests.time()
75 def put(self): 102 def put(self):
76 for stmt in rdf_over_http.rdfStatementsFromRequest( 103 for stmt in rdf_over_http.rdfStatementsFromRequest(self.request.arguments, self.request.body, self.request.headers):
77 self.request.arguments, self.request.body,
78 self.request.headers):
79 self._onStatement(stmt) 104 self._onStatement(stmt)
80 105
81 @STATS.statement.time() 106 @STATS.statement.time()
82 def _onStatement(self, stmt): 107 def _onStatement(self, stmt):
83 log.info(f'incoming statement: {stmt}') 108 log.info(f'incoming statement: {stmt}')
99 self._publish(topic=attrs['root'], message=f'input_{choice}') 124 self._publish(topic=attrs['root'], message=f'input_{choice}')
100 ignored = False 125 ignored = False
101 if stmt[0:2] == (dev, ROOM['volumeChange']): 126 if stmt[0:2] == (dev, ROOM['volumeChange']):
102 delta = int(stmt[2].toPython()) 127 delta = int(stmt[2].toPython())
103 which = 'up' if delta > 0 else 'down' 128 which = 'up' if delta > 0 else 'down'
104 self._publish(topic=f'theater_blaster/ir_out/volume_{which}', 129 self._publish(topic=f'theater_blaster/ir_out/volume_{which}', message=json.dumps({'timed': abs(delta)}))
105 message=json.dumps({'timed': abs(delta)}))
106 ignored = False 130 ignored = False
107 if stmt[0:2] == (dev, ROOM['color']): 131 if stmt[0:2] == (dev, ROOM['color']):
108 h = stmt[2].toPython() 132 h = stmt[2].toPython()
109 r, g, b = int(h[1:3], 16), int(h[3:5], 16), int(h[5:7], 16) 133 r, g, b = int(h[1:3], 16), int(h[3:5], 16), int(h[5:7], 16)
110 self._publish(topic=attrs['root'], 134 msg = {
111 message=json.dumps({ 135 'state': 'ON' if r or g or b else 'OFF',
112 'state': 136 'color': {
113 'ON' if r or g or b else 'OFF', 137 'r': r,
114 'color': { 138 'g': g,
115 'r': r, 139 'b': b
116 'g': g, 140 },
117 'b': b 141 }
118 }, 142 if attrs.get('hasBrightness', False):
119 'white_value': 143 # todo- still not right for sylvania bulbs; they want color x-y.
120 max(r, g, b) 144 # see https://www.zigbee2mqtt.io/information/mqtt_topics_and_message_structure.html#zigbee2mqttfriendly_nameset
121 })) 145 msg['brightness'] = max(r, g, b)
122 ignored = False 146 if msg['brightness'] != 0:
147 scl = msg['brightness'] / 255
148 for chan in ['r', 'g', 'b']:
149 msg['color'][chan] = int(msg['color'][chan] / 255.0 / scl * 255)
150
151 if attrs.get('hasWhite', False):
152 msg['white_value'] = max(r, g, b)
153 msg.update(attrs.get('defaults', {}))
154 self._publish(topic=attrs['root'], message=json.dumps(msg))
155 ignored = False
156
123 if ignored: 157 if ignored:
124 log.warn("ignoring %s", stmt) 158 log.warn("ignoring %s", stmt)
125 159
126 def _publishOnOff(self, attrs, brightness): 160 def _publishOnOff(self, attrs, brightness):
127 msg = 'OFF' 161 msg = 'OFF'
140 def _publishFrontScreenText(self, stmt): 174 def _publishFrontScreenText(self, stmt):
141 ignored = True 175 ignored = True
142 for line in ['line1', 'line2', 'line3', 'line4']: 176 for line in ['line1', 'line2', 'line3', 'line4']:
143 if stmt[1] == ROOM[line]: 177 if stmt[1] == ROOM[line]:
144 ignored = False 178 ignored = False
145 self.settings.mqtt.publish( 179 self.settings.mqtt.publish(b'frontwindow/%s' % line.encode('ascii'), stmt[2].toPython())
146 b'frontwindow/%s' % line.encode('ascii'),
147 stmt[2].toPython())
148 return ignored 180 return ignored
149 181
150 @STATS.mqttPublish.time() 182 @STATS.mqttPublish.time()
151 def _publish(self, 183 def _publish(self, topic: str, messageJson: object = None, message: str = None):
152 topic: str,
153 messageJson: object = None,
154 message: str = None):
155 log.debug(f'mqtt.publish {topic} {message} {messageJson}') 184 log.debug(f'mqtt.publish {topic} {message} {messageJson}')
156 if messageJson is not None: 185 if messageJson is not None:
157 message = json.dumps(messageJson) 186 message = json.dumps(messageJson)
158 self.settings.mqtt.publish(topic.encode('ascii'), 187 self.settings.mqtt.publish(topic.encode('ascii'), message.encode('ascii'))
159 message.encode('ascii'))
160 188
161 189
162 if __name__ == '__main__': 190 if __name__ == '__main__':
163 arg = docopt(""" 191 arg = docopt("""
164 Usage: rdf_to_mqtt.py [options] 192 Usage: rdf_to_mqtt.py [options]
165 193
166 -v Verbose 194 -v Verbose
167 """) 195 """)
168 verboseLogging(arg['-v']) 196 verboseLogging(arg['-v'])
169 197
170 mqtt = MqttClient(clientId='rdf_to_mqtt', 198 mqtt = MqttClient(clientId='rdf_to_mqtt', brokerHost='mosquitto-ext.default.svc.cluster.local', brokerPort=1883)
171 brokerHost='mosquitto-ext.default.svc.cluster.local',
172 brokerPort=1883)
173 199
174 port = 10008 200 port = 10008
175 reactor.listenTCP(port, 201 reactor.listenTCP(port,
176 cyclone.web.Application([ 202 cyclone.web.Application([
177 (r"/()", cyclone.web.StaticFileHandler, { 203 (r"/()", cyclone.web.StaticFileHandler, {