82 lines
2.8 KiB
Python
Executable File
82 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from home import http
|
|
from home.config import config
|
|
from home.mqtt import MqttPayload, MqttWrapper, MqttNode, MqttModule
|
|
from home.mqtt.module.relay import MqttRelayState, MqttRelayModule
|
|
from home.mqtt.module.diagnostics import InitialDiagnosticsPayload, DiagnosticsPayload
|
|
from typing import Optional, Union
|
|
|
|
mqtt: Optional[MqttWrapper] = None
|
|
mqtt_nodes: dict[str, MqttNode] = {}
|
|
relay_modules: dict[str, Union[MqttRelayModule, MqttModule]] = {}
|
|
relay_states: dict[str, MqttRelayState] = {}
|
|
|
|
|
|
def on_mqtt_message(node: MqttNode,
|
|
message: MqttPayload):
|
|
if isinstance(message, InitialDiagnosticsPayload) or isinstance(message, DiagnosticsPayload):
|
|
kwargs = dict(rssi=message.rssi, enabled=message.flags.state)
|
|
if device_id not in relay_states:
|
|
relay_states[device_id] = MqttRelayState()
|
|
relay_states[device_id].update(**kwargs)
|
|
|
|
|
|
class RelayMqttHttpProxy(http.HTTPServer):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.get('/relay/{id}/on', self.relay_on)
|
|
self.get('/relay/{id}/off', self.relay_off)
|
|
self.get('/relay/{id}/toggle', self.relay_toggle)
|
|
|
|
async def _relay_on_off(self,
|
|
enable: Optional[bool],
|
|
req: http.Request):
|
|
node_id = req.match_info['id']
|
|
node_secret = req.query['secret']
|
|
|
|
node = mqtt_nodes[node_id]
|
|
relay_module = relay_modules[node_id]
|
|
|
|
if enable is None:
|
|
if node_id in relay_states and relay_states[node_id].ever_updated:
|
|
cur_state = relay_states[node_id].enabled
|
|
else:
|
|
cur_state = False
|
|
enable = not cur_state
|
|
|
|
if not node.secret:
|
|
node.secret = node_secret
|
|
relay_module.switchpower(enable)
|
|
return self.ok()
|
|
|
|
async def relay_on(self, req: http.Request):
|
|
return await self._relay_on_off(True, req)
|
|
|
|
async def relay_off(self, req: http.Request):
|
|
return await self._relay_on_off(False, req)
|
|
|
|
async def relay_toggle(self, req: http.Request):
|
|
return await self._relay_on_off(None, req)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
config.load_app('relay_mqtt_http_proxy')
|
|
|
|
mqtt = MqttWrapper()
|
|
for device_id, data in config['relays'].items():
|
|
mqtt_node = MqttNode(node_id=device_id)
|
|
relay_modules[device_id] = mqtt_node.load_module('relay')
|
|
mqtt_nodes[device_id] = mqtt_node
|
|
mqtt_node.add_payload_callback(on_mqtt_message)
|
|
mqtt.add_node(mqtt_node)
|
|
mqtt_node.add_payload_callback(on_mqtt_message)
|
|
|
|
mqtt.configure_tls()
|
|
mqtt.connect_and_loop(loop_forever=False)
|
|
|
|
proxy = RelayMqttHttpProxy(config.get_addr('server.listen'))
|
|
try:
|
|
proxy.run()
|
|
except KeyboardInterrupt:
|
|
mqtt.disconnect()
|