summaryrefslogtreecommitdiff
path: root/netdisco/lms.py
diff options
context:
space:
mode:
Diffstat (limited to 'netdisco/lms.py')
-rw-r--r--netdisco/lms.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/netdisco/lms.py b/netdisco/lms.py
new file mode 100644
index 0000000..6026a86
--- /dev/null
+++ b/netdisco/lms.py
@@ -0,0 +1,78 @@
+"""Squeezebox/Logitech Media server discovery."""
+import socket
+
+from .const import ATTR_HOST, ATTR_PORT
+
+DISCOVERY_PORT = 3483
+DEFAULT_DISCOVERY_TIMEOUT = 2
+
+
+class LMS:
+ """Base class to discover Logitech Media servers."""
+
+ def __init__(self):
+ """Initialize the Logitech discovery."""
+ self.entries = []
+ self.last_scan = None
+
+ def scan(self):
+ """Scan the network."""
+ self.update()
+
+ def all(self):
+ """Scan and return all found entries."""
+ self.scan()
+ return list(self.entries)
+
+ def update(self):
+ """Scan network for Logitech Media Servers."""
+ lms_ip = '<broadcast>'
+ lms_port = DISCOVERY_PORT
+ lms_msg = b"eJSON\0"
+ lms_timeout = DEFAULT_DISCOVERY_TIMEOUT
+
+ entries = []
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
+ sock.settimeout(lms_timeout)
+ sock.bind(('', 0))
+
+ try:
+ sock.sendto(lms_msg, (lms_ip, lms_port))
+
+ while True:
+ try:
+ data, server = sock.recvfrom(1024)
+ if data.startswith(b'E'):
+ # Full response is EJSON\xYYXXXX
+ # Where YY is length of port string (ie 4)
+ # And XXXX is the web interface port (ie 9000)
+ port = None
+ if data.startswith(b'JSON', 1):
+ length = data[5:6][0]
+ port = int(data[0-length:])
+ entries.append({
+ ATTR_HOST: server[0],
+ ATTR_PORT: port,
+ })
+ except socket.timeout:
+ break
+ finally:
+ sock.close()
+ self.entries = entries
+
+
+def main():
+ """Test LMS discovery."""
+ from pprint import pprint
+
+ lms = LMS()
+
+ pprint("Scanning for Logitech Media Servers...")
+ lms.update()
+ pprint(lms.entries)
+
+
+if __name__ == "__main__":
+ main()