spejsiot-polycom/vortex.py

157 lines
4.0 KiB
Python
Raw Permalink Normal View History

2017-09-23 19:33:32 +00:00
import socket
import threading
import logging
import queue
import contextlib
import time
DEFAULT_TIMEOUT = 0.5
2024-02-25 16:31:22 +00:00
class TimeoutException(Exception):
pass
2017-09-23 19:33:32 +00:00
class VortexConnection(object):
def __init__(self, ip, port):
self.logger = logging.getLogger(self.__class__.__name__)
2024-02-25 16:31:22 +00:00
self.handlers = [self.on_message]
2017-09-23 19:33:32 +00:00
self.queues = []
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((ip, port))
2024-02-25 16:31:22 +00:00
self.fd = self.socket.makefile("rw")
2017-09-23 19:33:32 +00:00
def loop_start(self):
self.th = threading.Thread(target=self.loop)
self.th.daemon = True
self.th.start()
def loop(self):
2024-02-25 16:31:22 +00:00
print("Looping...")
2017-09-23 19:33:32 +00:00
for line in self.readlines():
for h in self.handlers:
h(line.strip())
def send(self, cmd):
2024-02-25 16:31:22 +00:00
self.logger.debug(">> %r", cmd)
self.fd.write(cmd + "\r")
2017-09-23 19:33:32 +00:00
self.fd.flush()
def readlines(self):
2024-02-25 16:31:22 +00:00
buf = b""
2017-09-23 19:33:32 +00:00
data = True
while data:
2019-04-20 12:05:10 +00:00
try:
2024-02-25 16:31:22 +00:00
data = self.socket.recv(512)
except KeyboardInterrupt:
raise
2019-04-20 12:05:10 +00:00
except:
time.sleep(0.1)
2024-02-25 16:31:22 +00:00
self.logger.warning("Recv failed")
2019-04-20 12:05:10 +00:00
continue
if not data:
raise Exception("Connection closed")
2017-09-23 19:33:32 +00:00
buf += data
2024-02-25 16:31:22 +00:00
while buf.find(b"\r") != -1:
line, buf = buf.split(b"\r", 1)
2017-09-23 19:33:32 +00:00
yield line
def on_message(self, msg):
2024-02-25 16:31:22 +00:00
self.logger.debug("<< %r", msg)
2017-09-23 19:33:32 +00:00
for q in self.queues:
q.put_nowait(msg)
@contextlib.contextmanager
def client(self):
q = queue.Queue()
self.queues.append(q)
2024-02-25 16:31:22 +00:00
self.logger.debug("Adding queue...")
2017-09-23 19:33:32 +00:00
try:
yield q
finally:
2024-02-25 16:31:22 +00:00
self.logger.debug("Removing queue...")
2017-09-23 19:33:32 +00:00
self.queues.remove(q)
def call(self, cmd, timeout=DEFAULT_TIMEOUT, wait=True):
with self.client() as q:
self.send(cmd)
if not wait:
return
start = time.time()
2024-02-25 16:31:22 +00:00
while time.time() - start < timeout:
2017-09-23 19:33:32 +00:00
try:
2024-02-25 16:31:22 +00:00
m = q.get(timeout=timeout - (time.time() - start))
2017-09-23 19:33:32 +00:00
except queue.Empty:
2024-02-25 16:31:22 +00:00
self.logger.debug("Request timeout")
2017-09-23 19:33:32 +00:00
return
yield m
def discover(self, timeout=DEFAULT_TIMEOUT):
return {
2024-02-25 16:31:22 +00:00
resp[:3].decode(): VortexDevice(self, resp[:3].decode())
for resp in self.call("***PING", timeout=timeout)
if resp[3:].decode() == "PONG"
}
2017-09-23 19:33:32 +00:00
def __getitem__(self, key):
return VortexDevice(self, key)
2024-02-25 16:31:22 +00:00
2017-09-23 19:33:32 +00:00
class VortexDevice(object):
def __init__(self, connection, device_id):
self.conn = connection
self.device_id = device_id
2024-02-25 16:31:22 +00:00
self.logger = logging.getLogger("vortex.%s" % (self.device_id,))
2017-09-23 19:33:32 +00:00
def __repr__(self):
2024-02-25 16:31:22 +00:00
return "<VortexDevice {}>".format(self.device_id)
2017-09-23 19:33:32 +00:00
def mute(self):
2024-02-25 16:31:22 +00:00
self.call_single("GMUTEO1")
2017-09-23 19:33:32 +00:00
def unmute(self):
2024-02-25 16:31:22 +00:00
self.call_single("GMUTEO0")
2017-09-23 19:33:32 +00:00
def call_single(self, *args, **kwargs):
return next(self.call(*args, **kwargs), None)
def call(self, cmd, expect=None, *args, **kwargs):
if expect is None:
2024-02-25 16:31:22 +00:00
expect = cmd.replace("?", "")
2017-09-23 19:33:32 +00:00
for resp in self.conn.call(self.device_id + cmd, *args, **kwargs):
2024-02-25 16:31:22 +00:00
self.logger.debug("Received: %r (%r)", resp, self.device_id)
if resp[: len(self.device_id)] != self.device_id.encode():
2017-09-23 19:33:32 +00:00
continue
2024-02-25 16:31:22 +00:00
resp = resp[len(self.device_id) :]
2017-09-23 19:33:32 +00:00
2024-02-25 16:31:22 +00:00
if expect is None or resp[: len(expect)] == expect.encode():
2017-09-23 19:33:32 +00:00
yield resp
2024-02-25 16:31:22 +00:00
2017-09-23 19:33:32 +00:00
if __name__ == "__main__":
2024-02-25 16:31:22 +00:00
import logging
logging.basicConfig(level=logging.DEBUG)
c = VortexConnection("127.0.0.1", 10001)
2017-09-23 19:33:32 +00:00
c.loop_start()
2024-02-25 16:31:22 +00:00
d = c.discover()
print(d)
d["F00"].call_single("PING", "PONG")
2017-09-23 19:33:32 +00:00
2024-02-25 16:31:22 +00:00
# for n in range(1000):
2017-09-23 19:33:32 +00:00
# c['T00'].call_single('SSTEXT0,1,XD {}'.format(n), expect=False, timeout=0)
# time.sleep(0.1)