Support for commands handling
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
class BaseWorker:
|
||||
def __init__(self, **args):
|
||||
for arg, value in args.items():
|
||||
setattr(self, arg, value)
|
||||
self._setup()
|
||||
|
||||
def _setup(self):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def status_update(self, **args):
|
||||
...
|
||||
|
||||
def format_topic(self, *args):
|
||||
return '/'.join([self.topic_prefix, *args])
|
||||
+5
-5
@@ -2,23 +2,22 @@ import time
|
||||
from interruptingcow import timeout
|
||||
|
||||
from mqtt import MqttMessage
|
||||
from workers.base import BaseWorker
|
||||
|
||||
REQUIREMENTS = ['bluepy']
|
||||
|
||||
|
||||
# Bluepy might need special settings
|
||||
# sudo setcap 'cap_net_raw,cap_net_admin+eip' /usr/local/lib/python3.6/dist-packages/bluepy/bluepy-helper
|
||||
|
||||
class MiscaleWorker():
|
||||
def __init__(self, mac):
|
||||
self._mac = mac
|
||||
|
||||
class MiscaleWorker(BaseWorker):
|
||||
def status_update(self):
|
||||
return [MqttMessage(topic='weight/kg', payload=self._get_weight())]
|
||||
|
||||
def _get_weight(self):
|
||||
from bluepy import btle
|
||||
|
||||
scan_processor = ScanProcessor(self._mac)
|
||||
scan_processor = ScanProcessor(self.mac)
|
||||
scanner = btle.Scanner().withDelegate(scan_processor)
|
||||
scanner.scan(5, passive=True)
|
||||
|
||||
@@ -29,6 +28,7 @@ class MiscaleWorker():
|
||||
|
||||
return -1
|
||||
|
||||
|
||||
class ScanProcessor():
|
||||
def __init__(self, mac):
|
||||
self._mac = mac
|
||||
|
||||
+76
-19
@@ -1,41 +1,98 @@
|
||||
from builtins import staticmethod
|
||||
from mqtt import MqttMessage
|
||||
from workers.base import BaseWorker
|
||||
|
||||
REQUIREMENTS = ['python-eq3bt']
|
||||
|
||||
monitoredAttrs = ["low_battery", "valve_state", "target_temperature"]
|
||||
|
||||
class ThermostatWorker:
|
||||
def __init__(self, devices):
|
||||
self._devices = devices
|
||||
STATE_BOOST = 'boost'
|
||||
STATE_AWAY = 'away'
|
||||
STATE_MANUAL = 'manual'
|
||||
|
||||
def status_update(self):
|
||||
from eq3bt import Thermostat, Mode
|
||||
class ThermostatWorker(BaseWorker):
|
||||
class ModesMapper():
|
||||
from eq3bt import Mode
|
||||
|
||||
haModesMapping = {
|
||||
MAPPED_MODES = {
|
||||
Mode.Closed: 'off',
|
||||
Mode.Open: 'on',
|
||||
Mode.Auto: 'auto',
|
||||
Mode.Manual: 'manual',
|
||||
Mode.Away: 'away',
|
||||
Mode.Boost: 'boost',
|
||||
Mode.Manual: STATE_MANUAL,
|
||||
Mode.Away: STATE_AWAY,
|
||||
Mode.Boost: STATE_BOOST,
|
||||
}
|
||||
|
||||
ret = []
|
||||
REVERSED_MODES = {v: k for k, v in MAPPED_MODES.items()}
|
||||
|
||||
@classmethod
|
||||
def get_mapping(cls, mode):
|
||||
return cls.MAPPED_MODES[mode]
|
||||
|
||||
@classmethod
|
||||
def get_reverse_mapping(cls, mode):
|
||||
return cls.REVERSED_MODES[mode]
|
||||
|
||||
@staticmethod
|
||||
def away_mode_on_off(mode):
|
||||
if mode == STATE_AWAY:
|
||||
return 'ON'
|
||||
else:
|
||||
return 'OFF'
|
||||
|
||||
@staticmethod
|
||||
def on_off_to_mode(on_off):
|
||||
if on_off == 'ON':
|
||||
return STATE_AWAY
|
||||
else:
|
||||
return 'auto'
|
||||
|
||||
|
||||
def _setup(self):
|
||||
from eq3bt import Thermostat
|
||||
|
||||
for name, mac in self.devices.items():
|
||||
thermostat = Thermostat(mac)
|
||||
thermostat.update()
|
||||
self.devices[name] = Thermostat(mac)
|
||||
|
||||
for attr in monitoredAttrs:
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, attr), payload=getattr(thermostat, attr)))
|
||||
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'mode'), payload=haModesMapping[thermostat.mode]))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'away'), payload='ON' if thermostat.mode == Mode.Away else 'OFF'))
|
||||
def status_update(self):
|
||||
ret = []
|
||||
for name, thermostat in self.devices.items():
|
||||
ret += self.update_device_state(name, thermostat)
|
||||
|
||||
return ret
|
||||
|
||||
@property
|
||||
def devices(self):
|
||||
return self._devices
|
||||
def on_command(self, topic, value):
|
||||
_, device_name, method = topic.split('/')
|
||||
thermostat = self.devices[device_name]
|
||||
|
||||
if method == STATE_AWAY:
|
||||
method = "mode"
|
||||
value = ModesMapper.on_off_to_mode(value)
|
||||
|
||||
# It needs to be on separate if because first if can change method
|
||||
if method == "mode":
|
||||
value = ModesMapper.get_reverse_mapping(value)
|
||||
elif method == "target_temperature":
|
||||
value = float(value)
|
||||
|
||||
setattr(thermostat, method, value)
|
||||
return self.update_device_state(device_name, thermostat)
|
||||
|
||||
def update_device_state(self, name, thermostat):
|
||||
thermostat.update()
|
||||
|
||||
ret = []
|
||||
for attr in monitoredAttrs:
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, attr), payload=getattr(thermostat, attr)))
|
||||
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'mode'), payload=self.ModesMapper.get_mapping(thermostat.mode)))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'away'), payload=self.ModesMapper.away_mode_on_off(thermostat.mode)))
|
||||
|
||||
return ret
|
||||
|
||||
def device_for(self, mac):
|
||||
return eq3bt.Thermostat(mac)
|
||||
|
||||
def format_topic(self, device, attr):
|
||||
return '/'.join([device, attr])
|
||||
|
||||
Reference in New Issue
Block a user