async def run(*args, **kwargs): s1 = DiscoveryMessages.StateService( service=Services.UDP, port=56, target="d073d5000001" ) s1.Information.update( remote_addr=("192.168.0.3", 56700), sender_message=DiscoveryMessages.GetService(), ) yield s1
async def _do_search(self, serials, timeout, **kwargs): found_now = set() discovery_options = self.transport_target.discovery_options if discovery_options.has_hardcoded_discovery: log.info("Using hard coded discovery information") return await discovery_options.discover(self.add_service) get_service = DiscoveryMessages.GetService( target=None, tagged=True, addressable=True, res_required=True, ack_required=False ) kwargs["no_retry"] = True kwargs["broadcast"] = kwargs.get("broadcast", True) or True kwargs["accept_found"] = True kwargs["error_catcher"] = [] async for time_left, time_till_next in self._search_retry_iterator(timeout): kwargs["message_timeout"] = time_till_next async for pkt in self(get_service, **kwargs): if discovery_options.want(pkt.serial): addr = pkt.Information.remote_addr found_now.add(pkt.target[:6]) await self.add_service(pkt.serial, pkt.service, host=addr[0], port=pkt.port) if serials is None: if found_now: break elif all(binascii.unhexlify(serial)[:6] in found_now for serial in serials): break return list(found_now)
async def respond(s, event): if event | DeviceMessages.GetPower: event.set_replies(DeviceMessages.StatePower(level=s.device_attrs.power)) if event | DeviceMessages.GetLabel: event.ignore_request() elif event | DeviceMessages.SetPower: event.set_replies(DeviceMessages.StatePower(level=s.device_attrs.power)) await s.device_attrs.attrs_apply( s.device_attrs.attrs_path("power").changer_to(event.pkt.level), event=None, ) elif event | DiscoveryMessages.GetService: event.set_replies( DiscoveryMessages.StateService(service=Services.UDP, port=56700), DiscoveryMessages.StateService(service=Services.UDP, port=76500), )
async def respond(self, event): if event | DiscoveryMessages.GetService and event.io is self: port = self.options.get("state_service_port", self.options.port) state_service_port = 0 if port is None else port event.add_replies( DiscoveryMessages.StateService( service=self.options.state_service, port=state_service_port))
async def run(*args, **kwargs): called.append("run") if len(called) > 0: s1 = DiscoveryMessages.StateService( service=Services.UDP, port=56, target="d073d5000001" ) s1.Information.update( remote_addr=("192.168.0.3", 56700), sender_message=DiscoveryMessages.GetService(), ) yield s1 if len(called) > 1: s2 = DiscoveryMessages.StateService( service=Services.UDP, port=58, target="d073d5000002" ) s2.Information.update( remote_addr=("192.168.0.4", 56700), sender_message=DiscoveryMessages.GetService(), ) yield s2 if len(called) > 2: s3 = DiscoveryMessages.StateService( service=Services.UDP, port=59, target="d073d5000003" ) s3.Information.update( remote_addr=("192.168.0.5", 56700), sender_message=DiscoveryMessages.GetService(), ) yield s3
async def ensure_udp_service(self): await self.stop_service(Services.UDP) class ServerProtocol(asyncio.Protocol): def connection_made(sp, transport): sp.udp_transport = transport def datagram_received(sp, data, addr): if not self.attrs.online: return async def received_data(bts, a): sp.udp_transport.sendto(bts, addr) self.sync_write("udp", received_data, data) def error_received(sp, exc): log.error(hp.lc("Error on udp transport", error=exc)) remote = None for i in range(3): port = self.port if port is None: port = self.make_port() try: remote, _ = await asyncio.get_event_loop( ).create_datagram_endpoint(ServerProtocol, local_addr=("0.0.0.0", port)) break except OSError: log.exception("Couldn't make datagram server") await asyncio.sleep(0.1) if remote is None: raise Exception("Failed to bind to a udp socket for fake device") async def closer(): remote.close() async def add_service(adder): await adder(self.serial, Services.UDP, host="127.0.0.1", port=port) def address(source): if source == "udp": return ("127.0.0.1", port) state_service = DiscoveryMessages.StateService(service=Services.UDP, port=port) self.services.append( Service(Services.UDP, closer, add_service, state_service, address))
async def doit(): async with target.session() as afr: async with target.with_devices(device1): script = target.script(DiscoveryMessages.GetService()) got = [] async for pkt, _, _ in script.run_with(device1.serial, afr): got.append((pkt.service.value, pkt.port)) self.assertEqual(sorted(got) , [ (Services.UDP.value, device1.port) ] )
async def find_devices(self, broadcast, ignore_lost=False, raise_on_none=False, timeout=60, **kwargs): """ Broadcast a Discovery Packet (GetService) and interpret the return StateService messages. """ discovery = DiscoveryMessages.GetService(ack_required=False, res_required=True, target=None, addressable=True, tagged=True) script = self.transport_target.script(discovery) found_now = [] try: kwargs["broadcast"] = broadcast kwargs["accept_found"] = True kwargs["timeout"] = timeout async for pkt, addr, broadcast in script.run_with([], self, **kwargs): target = pkt.target[:6] found_now.append(target) if target not in self.found: self.found[target] = (set(), broadcast) if pkt.protocol == 1024 and pkt.pkt_type == 3: service = pkt.payload.service self.found[target][0].add((service, addr)) except TimedOut as error: if raise_on_none: raise FoundNoDevices() log.error("Didn't find any devices!\terror=%s", error) if not ignore_lost: for target in list(self.found): if target not in found_now: del self.found[target] return self.found
async def ensure_memory_service(self): await self.stop_service(MemoryService) async def closer(): pass async def add_service(adder): await adder(self.serial, MemoryService, writer=partial(self.write, "memory")) def address(source): if source == "memory": return (f"fake://{self.serial}/memory", 56700) state_service = DiscoveryMessages.StateService(service=Services.UDP, port=56700) self.services.append( Service(MemoryService, closer, add_service, state_service, address))
kwargs = { "a": a, "no_retry": True, "broadcast": True, "accept_found": True, "error_catcher": [], "message_timeout": 1, } script.run.assert_called_once_with(None, V.session, **kwargs) V.transport_target.script.assert_called_once_with( DiscoveryMessages.GetService( target=None, tagged=True, addressable=True, res_required=True, ack_required=False, ) ) assert sorted(fn) == sorted( [binascii.unhexlify(s) for s in ("d073d5000001", "d073d5000002")] ) assert V.session.found.serials == ["d073d5000001", "d073d5000002"] assert V.session.found["d073d5000001"] == { Services.UDP: await V.session.make_transport( "d073d5000001", Services.UDP, {"host": "192.168.0.3", "port": 56} ) }
# coding: spec from photons_messages import Services, DiscoveryMessages, protocol_register from photons_app.test_helpers import print_packet_difference import binascii describe "DiscoveryMessages": it "can unpack": hexd = "29000014f7f15496d073d51261e200004c49465856320101000000000000000003000000017cdd0000" unpackd = DiscoveryMessages.unpack(hexd, protocol_register=protocol_register) expected = DiscoveryMessages.StateService.empty_normalise( **{ "frame_address": { "ack_required": False, "res_required": True, "reserved2": "4c4946585632", "reserved3": "00", "sequence": 1, "target": "d073d51261e20000", }, "frame_header": { "addressable": True, "protocol": 1024, "reserved1": "00", "size": 41, "source": 2522149367, "tagged": False,
def make_response(self, pkt, protocol): if pkt | DiscoveryMessages.GetService: msgs = [] for service, (_, port) in self.services[0]: msgs.append(DiscoveryMessages.StateService(service=service, port=port)) return msgs
), ) v = V() async with V.devices.for_test(final_future) as sender: v.sender = sender yield v async it "can get serials and info", V: reference = DeviceFinder.empty() found, ss = await reference.find(V.sender, timeout=5) reference.raise_on_missing(found) assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss) assert ss == sorted(V.serials) for device in V.devices: V.devices.store(device).assertIncoming(DiscoveryMessages.GetService()) V.devices.store(device).clear() reference = DeviceFinder.from_kwargs(label="kitchen") found, ss = await reference.find(V.sender, timeout=5) reference.raise_on_missing(found) assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss) assert ss == [] for device in V.devices: expected = [ DiscoveryMessages.GetService(), DeviceMessages.GetVersion(), LightMessages.GetColor(), ] if device is V.devices["d4"]:
import asyncio describe "Fake device": async it "works with sockets": device = FakeDevice("d073d5000001", [], use_sockets=True) options = {"final_future": asyncio.Future(), "protocol_register": protocol_register} target = MemoryTarget.create(options, {"devices": device}) await device.start() assert len(device.services) == 1 device_port = device.services[0].state_service.port async with target.session() as sender: msg = DiscoveryMessages.GetService() got = defaultdict(list) async for pkt in sender(msg, device.serial): got[pkt.serial].append(pkt.payload.as_dict()) assert dict(got) == {"d073d5000001": [{"service": Services.UDP, "port": device_port}]} lantarget = LanTarget.create(options) async with lantarget.session() as sender: await sender.add_service( device.serial, Services.UDP, host="127.0.0.1", port=device_port ) msg = DeviceMessages.EchoRequest(echoing=b"hi")
def datagram_received(sp, data, addr): pkt = DiscoveryMessages.unpack(data, protocol_register=protocol_register) assert pkt | DiscoveryMessages.GetService res = DiscoveryMessages.StateService(target=target, source=pkt.source, sequence=pkt.sequence, service=Services.UDP, port=port) self.transport.sendto(res.tobytes(None), addr)
def datagram_received(sp, data, addr): pkt = DiscoveryMessages.unpack(data, protocol_register=protocol_register) assert pkt | DiscoveryMessages.GetService res = DiscoveryMessages.StateService(target=target, source=pkt.source, sequence=pkt.sequence, service=Services.UDP, port=port) self.transport.sendto(res.tobytes(None), addr) remote, _ = await self.loop.create_datagram_endpoint(ServerProtocol, local_addr=("0.0.0.0", port)) try: self.assertEqual(self.bridge.found, {}) await self.bridge.find_devices(('127.0.0.1', port), timeout=3) self.assertEqual(self.bridge.found , { binascii.unhexlify(target)[:6]: (set([(Services.UDP, ("127.0.0.1", port))]), "127.0.0.1") } ) found = [] script = self.target.script(DiscoveryMessages.GetService(ack_required=False)) async for pkt, _, _ in script.run_with([target], self.bridge, timeout=3): found.append(pkt) self.assertEqual(len(found), 1) self.assertEqual(pkt.target[:6], binascii.unhexlify(target)) self.assertEqual(pkt.service, Services.UDP) self.assertEqual(pkt.port, port) finally: remote.close()
service1 = mock.Mock(name="service", service=Services.UDP, state_service=state_service1) state_service2 = mock.NonCallableMock(name="state_service2", spec=[]) service2 = mock.Mock( name="service", service=AnotherService, state_service=state_service2 ) state_service3 = mock.NonCallableMock(name="state_service3", spec=[]) service3 = mock.Mock( name="service", service=MemoryService, state_service=state_service3 ) device.services = [service1, service2, service3] got = [] get_service = DiscoveryMessages.GetService() async for m in responder.respond(device, get_service, "UDP"): got.append(m) assert got == [state_service1, state_service2, state_service3] got = [] with ServicesResponder.limited_services(device, Services.UDP, AnotherService): async for m in responder.respond(device, get_service, "UDP"): got.append(m) assert got == [state_service1, state_service2] got = [] with ServicesResponder.limited_services(device, MemoryService): async for m in responder.respond(device, get_service, "UDP"): got.append(m)
devices.Events.OUTGOING( device, device.io["MEMORY"], pkt=CoreMessages.Acknowledgement, replying_to=original, ), *[ devices.Events.OUTGOING( device, device.io["MEMORY"], pkt=ex, replying_to=original ) for ex in expected ], ] async it "can get unlimited replies", send_single, device, FakeTime, MockedCallLater: original = DiscoveryMessages.GetService(ack_required=False) with FakeTime() as t: async with MockedCallLater(t): result = await send_single(original, timeout=1) assert t.time == 0.1 expected = ( DiscoveryMessages.StateService, {"service": Services.UDP, "port": device.io["MEMORY"].options.port}, ) pytest.helpers.assertSamePackets(result, expected) assert devices.store(device) == [ devices.Events.INCOMING(device, device.io["MEMORY"], pkt=original), devices.Events.OUTGOING( device, device.io["MEMORY"], pkt=expected, replying_to=original