async def process_outgoing_light1(reply, req_event, Cont): if req_event | TileMessages.GetTileEffect: yield TileMessages.StateTileEffect.create( type=TileEffectType.FLAME, speed=10, duration=1, palette_count=2, palette=[hp.Color(120, 1, 1, 3500), hp.Color(360, 1, 1, 3500)], **reply, ) else: raise Cont()
async def process_outgoing(reply, req_event, Cont): if req_event | MultiZoneMessages.GetColorZones: yield MultiZoneMessages.StateMultiZone.create( zones_count=22, zone_index=0, colors=[hp.Color(i, 1, 1, 3500) for i in range(8)], **reply, ) yield MultiZoneMessages.StateMultiZone.create( zones_count=22, zone_index=8, colors=[hp.Color(i, 1, 1, 3500) for i in range(8, 16)], ) else: raise Cont()
async def __call__(self, event, options): palette_count = options.palette_count if not options.palette and not options.palette_count: palette_count = 0 elif not options.palette_count: palette_count = len(options.palette) if event.zerod: palette = [hp.Color(0, 0, 0, 0) for _ in range(palette_count)] else: palette = [p.clone() for p in options.palette] while len(palette) < palette_count: palette.append(hp.Color(0, 0, 0, 0)) palette = palette[:palette_count] yield event.device.attrs.attrs_path("palette").changer_to(palette)
def normalise(self, meta, val): if val is sb.NotSpecified: return hp.Color(0, 0, 1, 3500) keys = ("hue", "saturation", "brightness", "kelvin") if isinstance(val, (list, tuple)): while len(val) < 4: val = (*val, 0) elif isinstance(val, dict): for k in keys: if k not in val: val = {**val, k: 0} val = tuple(val[k] for k in keys) elif any(hasattr(val, k) for k in keys): val = tuple(getattr(val, k, 0) for k in keys) else: raise BadSpecValue("Unknown value for color", got=val, meta=meta) return hp.Color(*val[:4])
async def __call__(self, event, options): zones_count = options.zones_count if not options.zones and not options.zones_count: zones_count = 16 elif not options.zones_count: zones_count = len(options.zones) if zones_count > 82: zones_count = 82 if zones_count < 0: zones_count = 0 if event.zerod: zones = [hp.Color(0, 1, 1, 3500) for _ in range(zones_count)] else: zones = [c.clone() for c in options.zones] while len(zones) < zones_count: zones.append(hp.Color(0, 0, 1, 3500)) zones = zones[:zones_count] yield event.device.attrs.attrs_path("zones").changer_to(zones)
async def __call__(self, event, options): chain_length = options.chain_length if not options.chain and not options.chain_length: chain_length = 5 elif not options.chain_length: chain_length = len(options.chain) spec = TileChild.FieldSpec() if event.zerod: chain = [spec.empty_normalise() for _ in range(chain_length)] else: chain = [ch.clone() for ch in options.chain] while len(chain) < chain_length: chain.append(spec.empty_normalise()) chain = chain[:chain_length] for ch in chain: ch.firmware_build = event.device.firmware.build ch.firmware_version_minor = event.device.firmware.minor ch.firmware_version_major = event.device.firmware.major if "candle" in event.device.cap.product.name.lower(): ch.width = 5 ch.height = 6 else: ch.width = 8 ch.height = 8 ch.device_version_vendor = event.device.cap.product.vendor.vid ch.device_version_product = event.device.cap.product.pid while len(ch.colors) < ch.height * ch.width: ch.colors.append(hp.Color(0, 1, 1, 3500)) yield event.device.attrs.attrs_path("chain").changer_to(chain)
async def respond(self, event): if event | Events.SET_ZONES: changes = [] for index, color in event.zones: if index >= len(self.device.attrs.zones): continue changes.append( self.device.attrs.attrs_path("zones", index).changer_to(color)) await self.device.attrs.attrs_apply(*changes, event=event) elif event | MultiZoneMessages.GetMultiZoneEffect: event.add_replies( self.state_for(MultiZoneMessages.StateMultiZoneEffect)) elif event | MultiZoneMessages.GetColorZones: getter = self.state_for(GetZonesCallable()) for state in getter(event.pkt.start_index, event.pkt.end_index): event.add_replies(state) elif event | MultiZoneMessages.SetMultiZoneEffect: state = self.state_for(MultiZoneMessages.StateMultiZoneEffect) await self.change_one("zones_effect", event.pkt.type, event=event) event.add_replies(state) elif event | MultiZoneMessages.SetColorZones: getter = self.state_for(GetZonesCallable()) state = getter(event.pkt.start_index, event.pkt.end_index) event.add_replies(*state) zones = [] color = hp.Color(event.pkt.hue, event.pkt.saturation, event.pkt.brightness, event.pkt.kelvin) for i in range(event.pkt.start_index, event.pkt.end_index + 1): zones.append((i, color)) await self.respond(Events.SET_ZONES(self.device, zones=zones))
s.equal = None def __eq__(s, other): print(f"Item {s.index}") pytest.helpers.assertPayloadsEquals(other, s.item, allow_missing=True) s.equal = other return True def __repr__(s): if s.equal: return repr(s.equal) else: return f"<DIFFERENT: {repr(s.item)}>" zones1 = [hp.Color(i, 1, 1, 3500) for i in range(30)] zones2 = [hp.Color(60 - i, 1, 1, 6500) for i in range(20)] zones3 = [hp.Color(90 - i, 1, 1, 9000) for i in range(40)] devices = pytest.helpers.mimic() light1 = devices.add("light1")( next(devices.serial_seq), Products.LCM3_TILE, hp.Firmware(3, 50), value_store=dict( power=0, label="bob", infrared=100, color=hp.Color(100, 0.5, 0.5, 4500), ),
from photons_messages import DeviceMessages, LightMessages, DiscoveryMessages from photons_products import Products import pytest devices = pytest.helpers.mimic() light1 = devices.add("light1")( "d073d5000001", Products.LCM3_A19_CLEAN, hp.Firmware(3, 70), value_store=dict( power=0, color=hp.Color(0, 1, 0.3, 2500), ), ) light2 = devices.add("light2")( "d073d5000002", Products.LCM3_A19_CLEAN, hp.Firmware(3, 70), value_store=dict( power=65535, indication=True, color=hp.Color(100, 1, 0.5, 2500), ), ) light3 = devices.add("light3")(
it "supports colors by name": for name in ColourParser.named_colors: self.assertCorrect(name, *ColourParser.named_colors[name]) it "supports stacking": self.assertCorrect("hsb:240,0.1,0.8 kelvin:2500", 240, 0, 0.8, 2500) self.assertCorrect("#010101 hue:240 kelvin:2500", 240, 0, 0.00392156862745098, 2500) self.assertCorrect("blue kelvin:3500 saturation:0.4", 250, 0.4, None, 3500) describe "color_to_msg": it "creates a SetWaveformOptional": h, s, b, k = 240, 0.1, None, 2500 hsbk = mock.Mock(name="hsbk", return_value=(h, s, b, k)) components = mock.Mock(name="components") c = hp.Color(h, s, 0, k) with mock.patch.object(ColourParser, "hsbk", hsbk): msg = ColourParser.msg(components) assert msg | LightMessages.SetWaveformOptional pytest.helpers.assertPayloadsEquals( msg.payload, { "transient": 0, "hue": c.hue, "saturation": c.saturation, "brightness": c.brightness, "kelvin": c.kelvin, "period": 0.0, "cycles": 1.0, "skew_ratio": 0.0,
assert thing.blah is blah assert called == [1] assert thing._blah == blah assert thing.blah is blah assert called == [1] del thing.blah assert not hasattr(thing, "_blah") assert thing.blah is blah assert called == [1, 1] describe "Color": it "can be made and cloned": c1 = hp.Color(2, 0, 0.3, 3500) c2 = c1.clone() assert c1 is not c2 for c in (c1, c2): assert c.hue == 2 assert c["hue"] == 2 assert c.saturation == 0 assert c["saturation"] == 0 assert c.brightness == 0.3 assert c["brightness"] == 0.3 assert c.kelvin == 3500
) async it "responds to tile effect messages", device, assertResponse: await assertResponse( TileMessages.GetTileEffect(), [ TileMessages.StateTileEffect.create( type=TileEffectType.OFF, speed=0.005, palette_count=0, parameters={} ) ], ) await assertResponse( TileMessages.SetTileEffect( type=TileEffectType.FLAME, palette_count=1, palette=[hp.Color(1, 0, 1, 3500)], ), [ TileMessages.StateTileEffect.create( type=TileEffectType.OFF, speed=0.005, palette_count=0, parameters={}, palette=[] ) ], matrix_effect=TileEffectType.FLAME, ) await assertResponse( TileMessages.GetTileEffect(), [ TileMessages.StateTileEffect.create( type=TileEffectType.FLAME, palette_count=1, speed=0.005,
group_two_label = "Bathroom" group_two_uuid = identifier() group_three_label = "desk" group_three_uuid = identifier() location_one_label = "Home" location_one_uuid = identifier() location_two_label = "Work" location_two_uuid = identifier() zones = [] for i in range(16): zones.append(hp.Color(i * 10, 1, 1, 2500)) ds.add("a19_1")( next(ds.serial_seq), Products.LCM2_A19, hp.Firmware(2, 75), value_store=dict( label="kitchen", power=0, group={ "label": group_one_label, "identity": group_one_uuid }, location={ "label": location_one_label, "identity": location_one_uuid
from photons_messages import ( DeviceMessages, LightMessages, MultiZoneMessages, MultiZoneEffectType, DiscoveryMessages, ) from photons_products.lifx import Capability from photons_products import Products from delfick_project.errors_pytest import assertRaises import pytest zeroColor = hp.Color(0, 0, 0, 3500) zones1 = [hp.Color(i, 1, 1, 3500) for i in range(30)] zones2 = [hp.Color(90 - i, 1, 1, 3500) for i in range(6)] zones3 = [hp.Color(300 - i, 1, 1, 3500) for i in range(16)] devices = pytest.helpers.mimic() light1 = devices.add("light1")( "d073d5000001", Products.LCM3_TILE, hp.Firmware(3, 50), value_store=dict( power=0, label="bob", infrared=100, color=hp.Color(100, 0.5, 0.5, 4500),
async def respond(self, event): if event | TileMessages.GetTileEffect: event.add_replies(self.state_for(TileMessages.StateTileEffect)) elif event | TileMessages.SetTileEffect: state = self.state_for(TileMessages.StateTileEffect) state.instanceid = event.pkt.instanceid event.add_replies(state) palette_count = max( [len(self.device.attrs.palette), len(event.pkt.palette)]) changes = [] for i, palette in enumerate(self.device.attrs.palette): if i >= palette_count: changes.append( self.device.attrs.attrs_path("palette", i).changer_to( hp.Color(0, 0, 0, 0))) else: if self.device.attrs.palette[i] != event.pkt.palette[i]: changes.append( self.device.attrs.attrs_path( "palette", i).changer_to(event.pkt.palette[i])) for i in range(palette_count): if i >= len(self.device.attrs.palette): changes.append( self.device.attrs.attrs_path("palette", i).changer_to( event.pkt.palette[i])) if event.pkt.palette_count > len(self.device.attrs.palette): changes.append( self.device.attrs.attrs_path("palette").reduce_length_to( event.pkt.palette_count)) changes.append( self.device.attrs.attrs_path("matrix_effect").changer_to( event.pkt.type)) await self.device.attrs.attrs_apply(*changes, event=event) elif event | TileMessages.GetDeviceChain: event.add_replies(self.state_for(TileMessages.StateDeviceChain)) elif event | TileMessages.Get64: state = [] res = { ch.tile_index: ch for ch in self.state_for(TileMessages.State64, expect_one=False) } for i in range(event.pkt.tile_index, event.pkt.tile_index + event.pkt.length): if i in res: state.append(res[i]) event.add_replies(*state) if event | TileMessages.SetUserPosition: if event.pkt.tile_index < len(self.device.attrs.chain): await self.device.change( (("chain", event.pkt.tile_index, "user_x"), event.pkt.user_x), (("chain", event.pkt.tile_index, "user_y"), event.pkt.user_y), event=event, ) event.set_replies() elif event | TileMessages.Set64: state = [] res = { ch.tile_index: ch for ch in self.state_for(TileMessages.State64, expect_one=False) } for i in range(event.pkt.tile_index, event.pkt.tile_index + event.pkt.length): if i in res: state.append(res[i]) event.add_replies(*state) for i in range(event.pkt.tile_index, event.pkt.tile_index + event.pkt.length): if i < len(self.device.attrs.chain): # For efficiency, not gonna make events for this chain = self.device.attrs.chain[i] chain.colors.clear() chain.colors.extend([ hp.Color(c.hue, c.saturation, c.brightness, c.kelvin) for c in event.pkt.colors ])
class LightState(Operator): class Options(dictobj.Spec): color = dictobj.Field(color_spec) @classmethod def select(kls, device): if not kls.only_io_and_viewer_operators( device.value_store) and device.cap.is_light: return kls(device, device.value_store) attrs = [ Operator.Attr.Lambda( "color", from_zero=lambda event, options: hp.Color(0, 1, 1, 3500), from_options=lambda event, options: options.color, ) ] async def respond(self, event): if event | LightMessages.GetColor: event.add_replies(self.state_for(LightMessages.LightState)) elif event | LightMessages.GetLightPower: event.add_replies(self.state_for(DeviceMessages.StatePower)) elif event | LightMessages.SetLightPower: event.add_replies(self.state_for(LightMessages.StateLightPower)) await self.change_one("power", event.pkt.level, event=event) elif event | LightMessages.SetColor or event | LightMessages.SetWaveform: event.add_replies(self.state_for(LightMessages.LightState)) await self.change( (("color", "hue"), event.pkt.hue), (("color", "saturation"), event.pkt.saturation), (("color", "brightness"), event.pkt.brightness), (("color", "kelvin"), event.pkt.kelvin), event=event, ) elif event | LightMessages.SetWaveformOptional: event.add_replies(self.state_for(LightMessages.LightState)) changes = [] for k in ("hue", "saturation", "brightness", "kelvin"): if getattr(event.pkt, f"set_{k}"): changes.append( self.device.attrs.attrs_path("color", k).changer_to( event.pkt[k])) if changes: await self.device.attrs.attrs_apply(*changes, event=event) def make_state_for(self, kls, result): if kls | LightMessages.StateLightPower: result.append(kls(level=self.device.attrs.power)) elif kls | LightMessages.LightState: result.append( kls( label=self.device.attrs.label, power=self.device.attrs.power, **self.device.attrs.color.as_dict(), ))
from photons_products import Products import pytest devices = pytest.helpers.mimic() devices.add("striplcm1")( "d073d5000003", Products.LCM1_Z, hp.Firmware(1, 22), value_store=dict( power=0, label="lcm1-no-extended", zones=[hp.Color(0, 0, 0, 0)] * 16, ), ) devices.add("striplcm2noextended")( "d073d5000004", Products.LCM2_Z, hp.Firmware(2, 70), value_store=dict( power=0, label="lcm2-no-extended", zones=[hp.Color(0, 0, 0, 0)] * 16, ), ) devices.add("striplcm2extended")(
def convert(c): return hp.Color(c["hue"], c["saturation"], c["brightness"], c["kelvin"]).as_dict()
def device(self): device = devices["a19"] devices.store(device).assertAttrs(label="", power=0, color=hp.Color(0, 0, 1, 3500)) return device
def hsbk(*args, **kwargs): h, s, b, k = ColourParser.hsbk(*args, **kwargs) return hp.Color(h, s, b, k)
from photons_canvas.theme import ApplyTheme from photons_app.special import FoundSerials from photons_app import helpers as hp from photons_products import Products import pytest devices = pytest.helpers.mimic() devices.add("bulb")( "d073d5000002", Products.LMB_MESH_A21, hp.Firmware(2, 2), value_store=dict(power=0, label="sam", infrared=0, color=hp.Color(0, 0, 0, 0)), ) devices.add("tile")( "d073d5000001", Products.LCM3_TILE, hp.Firmware(3, 50), value_store=dict( power=0, label="bob", infrared=100, color=hp.Color(100, 0.5, 0.5, 4500), ), ) devices.add("striplcm1")(
from contextlib import contextmanager from collections import defaultdict from functools import partial import asyncio import pytest import time import sys devices = pytest.helpers.mimic() light1 = devices.add("light1")( "d073d5000001", Products.LCM2_A19, hp.Firmware(2, 80), value_store=dict(power=0, color=hp.Color(0, 1, 0.3, 2500)), ) light2 = devices.add("light2")( "d073d5000002", Products.LCM2_A19, hp.Firmware(2, 80), value_store=dict(power=65535, color=hp.Color(100, 1, 0.5, 2500)), ) light3 = devices.add("light3")( "d073d5000003", Products.LCM2_A19, hp.Firmware(2, 80), value_store=dict(color=hp.Color(100, 1, 0.5, 2500)), )
assert devices.store(device) == [ devices.Events.INCOMING(device, device.io["MEMORY"], pkt=original), devices.Events.OUTGOING( device, device.io["MEMORY"], pkt=CoreMessages.Acknowledgement, replying_to=original, ), devices.Events.OUTGOING( device, device.io["MEMORY"], pkt=expected, replying_to=original ), ] async it "can get multiple replies", send_single, device: await device.event( devices.Events.SET_ZONES, zones=[(i, hp.Color(i, 1, 1, 3500)) for i in range(22)] ) devices.store(device).clear() original = MultiZoneMessages.GetColorZones(start_index=0, end_index=255) expected = [ ( MultiZoneMessages.StateMultiZone, { "zones_count": 22, "zone_index": 0, "colors": [hp.Color(i, 1, 1, 3500) for i in range(8)], }, ), ( MultiZoneMessages.StateMultiZone,