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.

78 lines
2.1 KiB

4 years ago
  1. """Squeezebox/Logitech Media server discovery."""
  2. import socket
  3. from .const import ATTR_HOST, ATTR_PORT
  4. DISCOVERY_PORT = 3483
  5. DEFAULT_DISCOVERY_TIMEOUT = 2
  6. class LMS:
  7. """Base class to discover Logitech Media servers."""
  8. def __init__(self):
  9. """Initialize the Logitech discovery."""
  10. self.entries = []
  11. self.last_scan = None
  12. def scan(self):
  13. """Scan the network."""
  14. self.update()
  15. def all(self):
  16. """Scan and return all found entries."""
  17. self.scan()
  18. return list(self.entries)
  19. def update(self):
  20. """Scan network for Logitech Media Servers."""
  21. lms_ip = '<broadcast>'
  22. lms_port = DISCOVERY_PORT
  23. lms_msg = b"eJSON\0"
  24. lms_timeout = DEFAULT_DISCOVERY_TIMEOUT
  25. entries = []
  26. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  27. sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  28. sock.settimeout(lms_timeout)
  29. sock.bind(('', 0))
  30. try:
  31. sock.sendto(lms_msg, (lms_ip, lms_port))
  32. while True:
  33. try:
  34. data, server = sock.recvfrom(1024)
  35. if data.startswith(b'E'):
  36. # Full response is EJSON\xYYXXXX
  37. # Where YY is length of port string (ie 4)
  38. # And XXXX is the web interface port (ie 9000)
  39. port = None
  40. if data.startswith(b'JSON', 1):
  41. length = data[5:6][0]
  42. port = int(data[0-length:])
  43. entries.append({
  44. ATTR_HOST: server[0],
  45. ATTR_PORT: port,
  46. })
  47. except socket.timeout:
  48. break
  49. finally:
  50. sock.close()
  51. self.entries = entries
  52. def main():
  53. """Test LMS discovery."""
  54. from pprint import pprint
  55. lms = LMS()
  56. pprint("Scanning for Logitech Media Servers...")
  57. lms.update()
  58. pprint(lms.entries)
  59. if __name__ == "__main__":
  60. main()