Skip to content

Commit e874a6e

Browse files
committed
Discover Dingz devices by listening to udp broadcast
1 parent dbb21e3 commit e874a6e

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed

dingz/discovery.py

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
21
import asyncio
32
import logging
43
from typing import Optional, List
54

65
_LOGGER = logging.getLogger(__name__)
76

7+
88
class DiscoveredDevice(object):
99
mac: str
1010
type: int
@@ -15,13 +15,15 @@ class DiscoveredDevice(object):
1515

1616
@staticmethod
1717
def create_from_announce_msg(raw_addr, announce_msg):
18+
_LOGGER.debug("received announce msg '%s' from %s ", announce_msg, raw_addr)
1819
if len(announce_msg) != 8:
19-
raise RuntimeError("unexpected announcement, %s" % announce_msg)
20+
raise RuntimeError("unexpected announcement, '%s'" % announce_msg)
2021

21-
device = DiscoveredDevice(host=raw_addr[0],
22-
mac=announce_msg[0:6].hex(":"))
22+
device = DiscoveredDevice(host=raw_addr[0], mac=announce_msg[0:6].hex(":"))
2323
device.type = announce_msg[6]
2424
status = announce_msg[7]
25+
26+
# parse status field
2527
device.is_child = status & 1 != 0
2628
device.mystrom_registered = status & 2 != 0
2729
device.mystrom_online = status & 4 != 0
@@ -33,48 +35,67 @@ def __init__(self, host, mac):
3335
self.mac = mac
3436

3537

38+
class DeviceRegistry(object):
39+
def __init__(self):
40+
self.devices_by_mac = {}
41+
42+
def register(self, device):
43+
self.devices_by_mac[device.mac] = device
44+
45+
def devices(self):
46+
return list(self.devices_by_mac.values())
47+
48+
3649
class DiscoveryProtocol(asyncio.DatagramProtocol):
37-
def __init__(self, registry):
50+
def __init__(self, registry: DeviceRegistry):
3851
super().__init__()
3952
self.registry = registry
4053

4154
def connection_made(self, transport):
55+
_LOGGER.debug("starting up udp listener")
4256
self.transport = transport
4357

4458
def datagram_received(self, data, addr):
4559
device = DiscoveredDevice.create_from_announce_msg(addr, data)
4660
self.registry.register(device)
4761

4862
def connection_lost(self, exc: Optional[Exception]) -> None:
63+
_LOGGER.debug("shutting down udp listener")
4964
super().connection_lost(exc)
5065

5166

52-
class DeviceRegistry(object):
53-
def __init__(self):
54-
self.devices_by_mac = {}
55-
56-
def register(self, device):
57-
self.devices_by_mac[device.mac] = device
58-
59-
def devices(self):
60-
return list(self.devices_by_mac.values())
67+
async def discover_dingz_devices(timeout: int = 7) -> List[DiscoveredDevice]:
68+
"""
69+
Try to discover all local dingz instances. All dingz instances
70+
report their presence every ~5 seconds in a UDP broadcast to port 7979.
6171
62-
63-
async def discover_dingz_devices(timeout=7) -> List[DiscoveredDevice]:
72+
:param timeout: timeout in seconds for discover.
73+
:return: list of discovered devices
74+
"""
6475
registry = DeviceRegistry()
6576
loop = asyncio.get_event_loop()
66-
(transport, protocol) = await loop.create_datagram_endpoint(lambda: DiscoveryProtocol(registry), local_addr=("0.0.0.0", 7979))
67-
77+
(transport, protocol) = await loop.create_datagram_endpoint(
78+
lambda: DiscoveryProtocol(registry), local_addr=("0.0.0.0", 7979)
79+
)
80+
# server runs in the background, meanwhile wait until timeout expires
6881
await asyncio.sleep(timeout)
82+
83+
# shutdown server
6984
transport.close()
85+
7086
devices = registry.devices()
87+
for device in devices:
88+
_LOGGER.debug(
89+
"discovered dingz %s (%s) with mac %s", device.host, device.type, device.mac
90+
)
7191
return devices
7292

7393

7494
if __name__ == "__main__":
95+
logging.basicConfig(level=logging.DEBUG)
7596
loop = asyncio.get_event_loop()
7697
devices = asyncio.run(discover_dingz_devices())
7798

7899
print("found %s devices" % len(devices))
79100
for device in devices:
80-
print(f'{device.mac} {device.host}')
101+
print(f"{device.mac} {device.host}")

0 commit comments

Comments
 (0)