spejsiot-polycom/vortexiot.py

165 lines
5.4 KiB
Python
Raw Permalink Normal View History

import os
import json
2017-09-23 19:33:32 +00:00
import itertools
import logging
2017-09-23 19:33:32 +00:00
import paho.mqtt.client as mqtt
import vortex
2017-09-23 19:33:32 +00:00
logging.basicConfig(level=logging.INFO)
2024-02-25 16:31:22 +00:00
2017-09-23 19:33:32 +00:00
class VortexSpejsIOTClient(mqtt.Client):
2024-02-25 16:31:22 +00:00
topic_prefix = "iot/polycom/"
2017-09-23 19:33:32 +00:00
def __init__(self, config, *args, **kwargs):
2017-09-23 19:33:32 +00:00
super(VortexSpejsIOTClient, self).__init__(*args, **kwargs)
self.config = config
2017-09-23 19:33:32 +00:00
self.logger = logging.getLogger(self.__class__.__name__)
self.vortex = vortex.VortexConnection(
self.config["control"]["host"], self.config["control"]["port"]
)
2017-09-23 19:33:32 +00:00
self.vortex.handlers.append(self.on_vortex_message)
2024-02-25 16:31:22 +00:00
self.device_id = ""
2017-09-23 19:33:32 +00:00
def on_connect(self, client, userdata, flags, rc):
2024-02-25 16:31:22 +00:00
self.subscribe(self.topic_prefix + "+/+/set")
self.logger.info("Connected")
2019-04-20 12:05:10 +00:00
self.device_id = list(self.vortex.discover().keys())[0]
2024-02-25 16:31:22 +00:00
self.vortex[self.device_id].call_single("BLAUTO0")
2017-09-23 19:33:32 +00:00
def run(self):
self.connect(**self.config["mqtt"])
2017-09-23 19:33:32 +00:00
self.loop_start()
self.vortex.loop()
def multi_call(self, cmd, channels, args):
for ch in channels:
2024-02-25 16:31:22 +00:00
self.vortex[self.device_id].call_single(
"%s%s%s" % (cmd, ch, args), wait=False
)
2017-09-23 19:33:32 +00:00
def matrix_call(self, cmd, pairs, args):
for s, t in pairs:
2024-02-25 16:31:22 +00:00
self.vortex[self.device_id].call_single(
"%s%s,%s,%s" % (cmd, s, t, args), wait=False
)
2017-09-23 19:33:32 +00:00
def notify(self, node, attribute, value):
if isinstance(value, bool):
value = str(value).lower()
else:
value = str(value)
2024-02-25 16:31:22 +00:00
self.publish("%s%s/%s" % (self.topic_prefix, node, attribute), value)
2017-09-23 19:33:32 +00:00
def on_message(self, client, userdata, msg):
2024-02-25 16:31:22 +00:00
topic = msg.topic[len(self.topic_prefix) :]
self.logger.info("mqtt -> %r %r", topic, msg.payload)
2017-09-23 19:33:32 +00:00
2024-02-25 16:31:22 +00:00
node, attrib, _ = topic.split("/")
msg.payload = msg.payload.decode("utf-8")
2017-09-23 19:33:32 +00:00
if node in self.config["inputs"]:
2024-02-25 16:31:22 +00:00
if attrib == "gain":
self.multi_call("GAINI", self.config["inputs"][node], msg.payload)
2024-02-25 16:31:22 +00:00
elif attrib == "mute":
self.multi_call(
"MUTEI",
self.config["inputs"][node],
"1" if msg.payload == "true" else "0",
2024-02-25 16:31:22 +00:00
)
elif attrib == "mode":
self.multi_call(
"MIC",
self.config["inputs"][node],
"1" if msg.payload == "mic" else "0",
2024-02-25 16:31:22 +00:00
)
elif node in self.config["outputs"]:
2024-02-25 16:31:22 +00:00
if attrib == "gain":
self.multi_call("GAINO", self.config["outputs"][node], msg.payload)
2024-02-25 16:31:22 +00:00
elif attrib == "mute":
self.multi_call(
"MUTEO",
self.config["outputs"][node],
"1" if msg.payload == "true" else "0",
2024-02-25 16:31:22 +00:00
)
elif ":" in node:
2017-09-23 19:33:32 +00:00
# This is matrix operation...
2024-02-25 16:31:22 +00:00
inp, _, out = node.partition(":")
2017-09-23 19:33:32 +00:00
if inp not in self.config["inputs"] or out not in self.config["outputs"]:
2024-02-25 16:31:22 +00:00
self.logger.warning("Invalid route: %r", node)
2017-09-23 19:33:32 +00:00
return
inp_chs = self.config["inputs"][inp]
out_chs = self.config["outputs"][out]
2017-09-23 19:33:32 +00:00
pairs = zip(itertools.cycle(inp_chs), out_chs)
2024-02-25 16:31:22 +00:00
if attrib == "mute":
self.matrix_call("MMUTE", pairs, "1" if msg.payload == "true" else "0")
elif attrib == "gain":
self.matrix_call("MGAIN", pairs, msg.payload)
2017-09-23 19:33:32 +00:00
def on_vortex_message(self, msg):
2024-02-25 16:31:22 +00:00
self.logger.info("vortex -> %r", msg)
2017-09-23 19:33:32 +00:00
device_id, msg = msg[:3], msg[3:]
if self.device_id != device_id.decode():
2024-02-25 16:31:22 +00:00
self.logger.debug("%r/%r: Invalid device id", device_id, self.device_id)
2017-09-23 19:33:32 +00:00
return
if msg.startswith(b"MMUTE"):
inp, out, muted = msg[5:].decode().split(",")
2017-09-23 19:33:32 +00:00
inp_label = self.input_from_channel(inp)
out_label = self.output_from_channel(out)
2024-02-25 16:31:22 +00:00
self.notify("%s:%s" % (inp_label, out_label), "mute", muted == "1")
2017-09-23 19:33:32 +00:00
elif msg.startswith(b"MGAIN"):
inp, out, gain = msg[5:].decode().split(",")
2017-09-23 19:33:32 +00:00
inp_label = self.input_from_channel(inp)
out_label = self.output_from_channel(out)
2024-02-25 16:31:22 +00:00
self.notify("%s:%s" % (inp_label, out_label), "gain", gain)
2017-09-23 19:33:32 +00:00
elif msg.startswith(b"GAINI"):
msg = msg.decode()
2017-09-23 19:33:32 +00:00
channel_id, gain = msg[5], msg[6:]
label = self.input_from_channel(channel_id)
2024-02-25 16:31:22 +00:00
self.notify(label, "gain", gain)
2017-09-23 19:33:32 +00:00
elif msg.startswith(b"MUTEI"):
msg = msg.decode()
2017-09-23 19:33:32 +00:00
channel_id, muted = msg[5], msg[6:]
label = self.input_from_channel(channel_id)
2024-02-25 16:31:22 +00:00
self.notify(label, "mute", muted == "1")
2017-09-23 19:33:32 +00:00
def input_from_channel(self, channel):
return self.find_label(self.config["inputs"], channel)
2017-09-23 19:33:32 +00:00
def output_from_channel(self, channel):
return self.find_label(self.config["outputs"], channel)
2017-09-23 19:33:32 +00:00
def find_label(self, labels, channel):
for label, channels in labels.items():
if channel in map(str, channels):
return label
return None
def main():
config = {}
with open(os.environ["CONFIG_PATH"], "rb") as fd:
config = json.load(fd)
client = VortexSpejsIOTClient(config)
2017-09-23 19:33:32 +00:00
client.run()
2024-02-25 16:31:22 +00:00
2017-09-23 19:33:32 +00:00
if __name__ == "__main__":
main()