Mercurial > code > home > repos > light-bridge
view light.py @ 20:24a574108365
more protocols; bugs in setColor
author | drewp@bigasterisk.com |
---|---|
date | Mon, 29 Jan 2024 11:52:43 -0800 |
parents | 1d15dc4d673f |
children | b8201490c731 |
line wrap: on
line source
import asyncio import logging from dataclasses import dataclass from typing import Callable from color import Color from color_convert import DeviceColor, oneWhiteConv, relayConv, twoWhitesConv, zbConv from mqtt_io import MqttIo from protocols import ShellyGen1WebTransport, SonoffRelayTransport, TasmotaWebTransport, Transport, ZigbeeTransport log = logging.getLogger('lite') @dataclass class Light: name: str transport: Transport convertColor: Callable[[Color], DeviceColor] requestingColor: Color = Color.fromHex('#000000') requestingDeviceColor: DeviceColor = DeviceColor() emittingColor: Color = Color.fromHex('#000000') online: bool | None = None latencyMs: float | None = None notifyChanged: Callable | None = None def __post_init__(self): self.requestingDeviceColor = self.convertColor(self.requestingColor) def to_dict(self): d = { 'name': self.name, 'address': self.transport.linked(), 'requestingColor': self.requestingColor.hex(), 'requestingDeviceColor': self.requestingDeviceColor.summary(), 'emittingColor': self.emittingColor.hex(), 'online': self.online, 'latencyMs': self.latencyMs, } return {'light': d} async def setColor(self, c: Color): if c == self.requestingColor: return self.requestingColor = c dc = self.convertColor(self.requestingColor) log.info(f'setColor from {self.requestingColor} to {c} = {dc.summary()=}') if dc != self.requestingDeviceColor: self.requestingDeviceColor = dc if self.notifyChanged: self.notifyChanged() # waits for the relevant round-trip log.info(f'transport send {self.requestingDeviceColor.summary()}') await self.transport.send(self.requestingDeviceColor) self.emittingColor = self.requestingColor if self.notifyChanged: self.notifyChanged() def makeZbBar(mqtt: MqttIo, name: str, ieee: str) -> Light: return Light(name=name, convertColor=zbConv, transport=ZigbeeTransport(mqtt, name, ieee)) def makeTasmota(name: str, hostname: str) -> Light: return Light(name=name, convertColor=twoWhitesConv, transport=TasmotaWebTransport(hostname)) def makeShellyRGW2(name: str, hostname: str) -> Light: return Light(name=name, convertColor=oneWhiteConv, transport=ShellyGen1WebTransport(hostname)) def makeSonoffRelay(mqtt: MqttIo, name: str, topic: str) -> Light: return Light(name=name, convertColor=relayConv, transport=SonoffRelayTransport(mqtt, topic)) class Lights: _d: dict[str, Light] = {} def __init__(self, mqtt: MqttIo): self.mqtt = mqtt self.add(makeZbBar(mqtt, 'do-bar', '0xa4c13844948d2da4')) self.add(makeTasmota('do-lamp', 'tasmota-9E2AB7-2743')) self.add(makeShellyRGW2('ki-ceiling', 'shellyrgbw2-e868e7f34c35')) self.add(makeShellyRGW2('ki-counter', 'shellyrgbw2-e868e7f34cb2')) # br-floor online=online | metric=1 (graph) lqi=93 bright=12 # br-wall online=online | metric=1 (graph) lqi=30 bright=0 # en online=online | metric=1 (graph) lqi=36 bright=216 # ft-ceil online=online | metric=1 (graph) lqi=96 bright=252 # go-high online=online | metric=1 (graph) lqi=93 bright=253 # li-toys online=online | metric=1 (graph) lqi=96 bright=28 # py online=online | metric=1 (graph) lqi=93 bright=216 # rr-lamp online=offline | metric=0 (graph) lqi=... bright=... # sh-top online=online | metric=1 (graph) lqi=93 bright=254 # ws-hanging online=online | metric=1 (graph) lqi=39 bright=... # light-li-high-shelf uptimesec=2232334 wifi=-65 dim=100 color=0000002FD0 # light-sh uptimesec=... wifi=... dim=... color=... # light-tr-wall uptimesec=5082251 wifi=-38 dim=34 color=5700000000 # wled-ft-hanging offline #FFA000 bright=128 # string-tr online #8CFF82 bright=128 # light-tr-ball online #808A03 bright=12 # string-hr online #C9FFDC bright=131 self.add(makeSonoffRelay(mqtt, 'li-lamp0', 'sonoff_0')) self.add(makeSonoffRelay(mqtt, 'li-lamp1', 'sonoff_1')) self.add(makeSonoffRelay(mqtt, 'li-lamp2', 'sonoff_2')) self.add(makeSonoffRelay(mqtt, 'li-lamp3', 'sonoff_3')) self.add(makeSonoffRelay(mqtt, 'li-lamp4', 'sonoff_4')) def add(self, d: Light): d.notifyChanged = self.notifyChanged self._d[d.name] = d self.notifyChanged() def byName(self, name: str) -> Light: return self._d[name] def to_dict(self): return {'lights': [d.to_dict() for d in sorted(self._d.values(), key=lambda r: r.name)]} # the following is bad. Get a better events lib. _changeSleepTask: asyncio.Task | None = None async def changes(self): # yields None on any data change while True: log.info('Lights has a change') yield None self._changeSleepTask = asyncio.create_task(self._sleep()) try: await self._changeSleepTask except asyncio.CancelledError: pass self._changeSleepTask = None async def _sleep(self): await asyncio.sleep(100) def notifyChanged(self): log.info('Lights.notifyChanged()') if self._changeSleepTask is not None: self._changeSleepTask.cancel()