You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
1.9 KiB

4 years ago
  1. """Tellstick device discovery."""
  2. import socket
  3. from datetime import timedelta
  4. import logging
  5. DISCOVERY_PORT = 30303
  6. DISCOVERY_ADDRESS = '<broadcast>'
  7. DISCOVERY_PAYLOAD = b"D"
  8. DISCOVERY_TIMEOUT = timedelta(seconds=2)
  9. class Tellstick:
  10. """Base class to discover Tellstick devices."""
  11. def __init__(self):
  12. """Initialize the Tellstick discovery."""
  13. self.entries = []
  14. def scan(self):
  15. """Scan the network."""
  16. self.update()
  17. def all(self):
  18. """Scan and return all found entries."""
  19. self.scan()
  20. return self.entries
  21. def update(self):
  22. """Scan network for Tellstick devices."""
  23. entries = []
  24. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  25. sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  26. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  27. sock.settimeout(DISCOVERY_TIMEOUT.seconds)
  28. sock.sendto(DISCOVERY_PAYLOAD, (DISCOVERY_ADDRESS, DISCOVERY_PORT))
  29. while True:
  30. try:
  31. data, (address, _) = sock.recvfrom(1024)
  32. entry = data.decode("ascii").split(":")
  33. # expecting product, mac, activation code, version
  34. if len(entry) != 4:
  35. continue
  36. entry = (address,) + tuple(entry)
  37. entries.append(entry)
  38. except socket.timeout:
  39. break
  40. except UnicodeDecodeError:
  41. # Catch invalid responses
  42. logging.getLogger(__name__).debug(
  43. 'Ignoring invalid unicode response from %s', address)
  44. continue
  45. self.entries = entries
  46. sock.close()
  47. def main():
  48. """Test Tellstick discovery."""
  49. from pprint import pprint
  50. tellstick = Tellstick()
  51. pprint("Scanning for Tellstick devices..")
  52. tellstick.update()
  53. pprint(tellstick.entries)
  54. if __name__ == "__main__":
  55. main()