diff --git a/config.yaml.example b/config.yaml.example index 599f102..c4d484a 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -68,11 +68,23 @@ manager: ix: 00:11:22:33:44:55 ia: 11:22:33:44:55:66 topic_prefix: toothbrush - update_interval: 10 + update_interval: 10 + toothbrush_homeassistant: + args: + autodiscovery_prefix: homeassistant + topic_prefix: toothbrush + devices: + ix: + name: IX + mac: 00:11:22:33:44:55 + ia: + name: IA + mac: 11:22:33:44:55:66 + update_interval: 10 switchbot: args: devices: - heater: 00:11:22:33:44:55 + heater: 00:11:22:33:44:55 topic_prefix: switchbot/bathroom state_topic_prefix: switchbot/bathroom topic_subscription: switchbot/+/+/set diff --git a/workers/toothbrush_homeassistant.py b/workers/toothbrush_homeassistant.py new file mode 100644 index 0000000..9ab030a --- /dev/null +++ b/workers/toothbrush_homeassistant.py @@ -0,0 +1,148 @@ +import time +import json + +from bluepy.btle import Scanner, DefaultDelegate +from mqtt import MqttMessage + +from workers.base import BaseWorker +import logger + +REQUIREMENTS = ["bluepy"] +_LOGGER = logger.get(__name__) + +BRUSHSTATES = { + 0: "Unknown", + 1: "Initializing", + 2: "Idle", + 3: "Running", + 4: "Charging", + 5: "Setup", + 6: "Flight Menu", + 113: "Final Test", + 114: "PCB Test", + 115: "Sleeping", + 116: "Transport" +} + +BRUSHMODES = { + 0: "Off", + 1: "Daily Clean", + 2: "Sensitive", + 3: "Massage", + 4: "Whitening", + 5: "Deep Clean", + 6: "Tongue Cleaning", + 7: "Turbo", + 255: "Unknown" +} + +BRUSHSECTORS = { + 0: "Sector 1", + 1: "Sector 2", + 2: "Sector 3", + 3: "Sector 4", + 4: "Sector 5", + 5: "Sector 6", + 7: "Sector 7", + 8: "Sector 8", + 254: "Last sector", + 255: "No sector" +} + +class ScanDelegate(DefaultDelegate): + def __init__(self): + DefaultDelegate.__init__(self) + + def handleDiscovery(self, dev, isNewDev, isNewData): + if isNewDev: + _LOGGER.debug("Discovered new device: %s" % dev.addr) + +class Toothbrush_HomeassistantWorker(BaseWorker): + def _setup(self): + self.autoconfCache = {} + + def searchmac(self, devices, mac): + for dev in devices: + if dev.addr == mac.lower(): + return dev + return None + + def get_autoconf_data(self, key, name): + if key in self.autoconfCache: + return False + else: + self.autoconfCache[key] = True + return { + "platform": "mqtt", + "name": name, + "state_topic": self.topic_prefix+"/"+key+"/state", + "availability_topic": self.topic_prefix+"/"+key+"/presence", + "json_attributes_topic": self.topic_prefix+"/"+key+"/attributes", + "icon": "mdi:tooth-outline" + } + + def get_state(self, item): + if item in BRUSHSTATES: + return BRUSHSTATES[item] + else: + return BRUSHSTATES[0] + + def get_mode(self, item): + if item in BRUSHMODES: + return BRUSHMODES[item] + else: + return BRUSHMODES[255] + + def get_sector(self, item): + if item in BRUSHSECTORS: + return BRUSHSECTORS[item] + else: + return BRUSHSECTORS[255] + + def status_update(self): + scanner = Scanner().withDelegate(ScanDelegate()) + devices = scanner.scan(5.0) + ret = [] + + for key, item in self.devices.items(): + device = self.searchmac(devices, item['mac']) + + rssi = 0 + presence = 0 + state = 0 + pressure = 0 + time = 0 + mode = 255 + sector = 255 + + if device is not None: + bytes_ = bytearray.fromhex(device.getValueText(255)) + _LOGGER.debug("text: %s" % device.getValueText(255) ) + + if bytes_[5] > 0: + rssi = device.rssi + presence = 1 + state = bytes_[5] + pressure = bytes_[6] + time = bytes_[7]*60 + bytes_[8] + mode = bytes_[9] + sector = bytes_[10] + + attributes = { + "rssi": rssi, + "pressure": pressure, + "time": time, + "mode": self.get_mode(mode), + "sector": self.get_sector(sector) + } + presence_value = "online" if presence == 1 else "offline" + + ret.append(MqttMessage(topic=self.format_topic(key+"/presence"), payload=presence_value)) + ret.append(MqttMessage(topic=self.format_topic(key+"/state"), payload=self.get_state(state))) + ret.append(MqttMessage(topic=self.format_topic(key+"/attributes"), payload=json.dumps(attributes))) + + autoconf_data = self.get_autoconf_data(key, item['name']) + if autoconf_data != False: + ret.append(MqttMessage(topic=self.autodiscovery_prefix+"/sensor/"+self.topic_prefix+"_"+key+"/config", payload=json.dumps(autoconf_data), retain=True)) + + return ret \ No newline at end of file