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.

102 lines
2.8 KiB

4 years ago
  1. """Daikin device discovery."""
  2. import socket
  3. from datetime import timedelta
  4. from urllib.parse import unquote
  5. DISCOVERY_MSG = b"DAIKIN_UDP/common/basic_info"
  6. UDP_SRC_PORT = 30000
  7. UDP_DST_PORT = 30050
  8. DISCOVERY_ADDRESS = '<broadcast>'
  9. DISCOVERY_TIMEOUT = timedelta(seconds=2)
  10. class Daikin:
  11. """Base class to discover Daikin devices."""
  12. def __init__(self):
  13. """Initialize the Daikin discovery."""
  14. self.entries = []
  15. def scan(self):
  16. """Scan the network."""
  17. self.update()
  18. def all(self):
  19. """Scan and return all found entries."""
  20. self.scan()
  21. return self.entries
  22. def update(self):
  23. """Scan network for Daikin devices."""
  24. entries = []
  25. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  26. sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  27. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  28. sock.settimeout(DISCOVERY_TIMEOUT.seconds)
  29. sock.bind(("", UDP_SRC_PORT))
  30. try:
  31. sock.sendto(DISCOVERY_MSG, (DISCOVERY_ADDRESS, UDP_DST_PORT))
  32. while True:
  33. try:
  34. data, (address, _) = sock.recvfrom(1024)
  35. # pylint: disable=consider-using-dict-comprehension
  36. entry = dict([e.split('=')
  37. for e in data.decode("UTF-8").split(',')])
  38. # expecting product, mac, activation code, version
  39. if 'ret' not in entry or entry['ret'] != 'OK':
  40. # non-OK return on response
  41. continue
  42. if 'mac' not in entry:
  43. # no mac found for device"
  44. continue
  45. if 'type' not in entry or entry['type'] != 'aircon':
  46. # no mac found for device"
  47. continue
  48. if 'name' in entry:
  49. entry['name'] = unquote(entry['name'])
  50. # in case the device was not configured to have an id
  51. # then use the mac address
  52. if 'id' in entry and entry['id'] == '':
  53. entry['id'] = entry['mac']
  54. entries.append({
  55. 'id': entry['id'],
  56. 'name': entry['name'],
  57. 'ip': address,
  58. 'mac': entry['mac'],
  59. 'ver': entry['ver'],
  60. })
  61. except socket.timeout:
  62. break
  63. finally:
  64. sock.close()
  65. self.entries = entries
  66. def main():
  67. """Test Daikin discovery."""
  68. from pprint import pprint
  69. daikin = Daikin()
  70. pprint("Scanning for Daikin devices..")
  71. daikin.update()
  72. pprint(daikin.entries)
  73. if __name__ == "__main__":
  74. main()