Merge branch 'franga2000/barco-legacy'
This commit is contained in:
commit
6aacdcadbc
4 changed files with 314 additions and 0 deletions
67
barco_rlmw_http/barco_rlwm_http.py
Normal file
67
barco_rlmw_http/barco_rlwm_http.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
import re
|
||||
import asyncio
|
||||
import aiohttp
|
||||
from asyncio.exceptions import CancelledError
|
||||
|
||||
PORT = 43680
|
||||
RE_STATUS = re.compile(r".stats.txt(.+).value='(.+)';")
|
||||
REMOTEKEY_TIMEOUT = aiohttp.ClientTimeout(total=1)
|
||||
|
||||
|
||||
class BarcoRLM_Control:
|
||||
def __init__(self, projector_ip):
|
||||
self.projector_ip = projector_ip
|
||||
self.session = None
|
||||
|
||||
async def _request(self, method, path, *args, **kwargs):
|
||||
if not self.session:
|
||||
self.session = aiohttp.ClientSession()
|
||||
url = f"http://{self.projector_ip}{path}"
|
||||
resp = await self.session.request(method, url, *args, **kwargs)
|
||||
resp.raise_for_status()
|
||||
return await resp.text()
|
||||
|
||||
async def get_status(self):
|
||||
resp = await self._request("GET", "/tgi/firststatus.tgi")
|
||||
matches = RE_STATUS.findall(resp)
|
||||
status = dict(matches)
|
||||
return status
|
||||
|
||||
async def toggle_power(self):
|
||||
await self._request("GET", "/tgi/general.tgi?powertog")
|
||||
|
||||
async def click_remote(self, key):
|
||||
try:
|
||||
await self._request("GET", f"/tgi/remote.tgi?{key}", timeout=REMOTEKEY_TIMEOUT, raise_for_status=False)
|
||||
except TimeoutError:
|
||||
pass
|
||||
|
||||
async def set_shutter(self, shutter):
|
||||
endpoint = f"/tgi/general.tgi?pause{onoff(shutter)}"
|
||||
await self._request("GET", endpoint)
|
||||
|
||||
async def set_power(self, power):
|
||||
key = onoff(power) + "ky"
|
||||
await self.click_remote(key)
|
||||
|
||||
async def set_input(self, input):
|
||||
endpoint = f"/tgi/input.tgi?{input}"
|
||||
await self._request("GET", endpoint)
|
||||
|
||||
|
||||
def onoff(state: bool) -> str:
|
||||
if state:
|
||||
return "on"
|
||||
else:
|
||||
return "off"
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
async def main():
|
||||
barco = BarcoRLM_Control("192.168.192.12")
|
||||
status = await barco.get_status()
|
||||
print(status)
|
||||
|
||||
await barco.click_remote("kymenu")
|
||||
|
||||
asyncio.run(main())
|
79
barco_rlmw_http/main.py
Normal file
79
barco_rlmw_http/main.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import asyncio
|
||||
import aiomqtt
|
||||
from collections import defaultdict
|
||||
|
||||
from barco_legacy import BarcoRLM_Control
|
||||
|
||||
# TODO MAKE THIS CONFIGURALBE
|
||||
PROJECTOR_IP = "192.168.192.12"
|
||||
MQTT_PREFIX = "p22/projektorji/glavni"
|
||||
MQTT_HOST = "-----"
|
||||
POLLING_PERIOD_SEC = 10
|
||||
|
||||
|
||||
class BarcoRLM_MQTT:
|
||||
def __init__(self, projector_ip, mqtt_prefix):
|
||||
self.projector_ip = projector_ip
|
||||
self.mqtt_prefix = mqtt_prefix
|
||||
self.barco = BarcoRLM_Control(projector_ip)
|
||||
self.last_status = defaultdict(lambda: '')
|
||||
|
||||
async def run(self):
|
||||
async with aiomqtt.Client(MQTT_HOST, 1883) as client:
|
||||
self.client = client
|
||||
task_polling = asyncio.create_task(self.task_polling())
|
||||
task_control = asyncio.create_task(self.task_control())
|
||||
await asyncio.gather(task_control, task_polling)
|
||||
|
||||
async def task_control(self):
|
||||
topicMatch = f"{self.mqtt_prefix}/ukaz/+"
|
||||
await self.client.subscribe(topicMatch)
|
||||
|
||||
async for mesg in self.client.messages:
|
||||
cmd = mesg.topic.value.split("/")[-1]
|
||||
val = mesg.payload.decode()
|
||||
|
||||
if cmd == "power":
|
||||
await self.barco.set_power(onoff(val))
|
||||
elif cmd == "shutter":
|
||||
await self.barco.set_shutter(onoff(val))
|
||||
|
||||
async def task_polling(self):
|
||||
while True:
|
||||
status = await self.barco.get_status()
|
||||
for key, val in status.items():
|
||||
if self.last_status[key] != val:
|
||||
print(f"Status change {key}={val}")
|
||||
await self.on_status_change(key, val)
|
||||
|
||||
self.last_status = status
|
||||
await asyncio.sleep(POLLING_PERIOD_SEC)
|
||||
|
||||
async def on_status_change(self, key, val):
|
||||
mkey = mval = None
|
||||
if key == "status":
|
||||
mkey = "power"
|
||||
if val == "Imaging":
|
||||
mval = "1"
|
||||
if val == "Standby":
|
||||
mval = "0"
|
||||
if key == "src":
|
||||
mkey = "input"
|
||||
mval = val
|
||||
if key == "fmr":
|
||||
mkey = "input_format"
|
||||
mval = val
|
||||
if mkey is not None and mval is not None:
|
||||
await self.client.publish(f"{self.mqtt_prefix}/status/{mkey}", payload=mval)
|
||||
|
||||
|
||||
def onoff(input):
|
||||
if input == "1":
|
||||
return True
|
||||
elif input == "0":
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
barco = BarcoRLM_MQTT(PROJECTOR_IP, MQTT_PREFIX)
|
||||
asyncio.run(barco.run())
|
96
barco_rlmw_tcp/barco_rlmw_tcp.py
Normal file
96
barco_rlmw_tcp/barco_rlmw_tcp.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
import re
|
||||
import asyncio
|
||||
import telnetlib3
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
|
||||
PORT = 43680
|
||||
RE_STATUS = re.compile(r"OP (.+?)(?:$| = (.+)$)")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ACK:
|
||||
command: str
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ValueUpdate:
|
||||
key: str
|
||||
value: str
|
||||
|
||||
class Status(StrEnum):
|
||||
standby = "0"
|
||||
warmup = "1"
|
||||
imaging = "2"
|
||||
cooling = "3"
|
||||
warning = "4"
|
||||
|
||||
class LampMode(StrEnum):
|
||||
economy = "0"
|
||||
standard = "1"
|
||||
dimming = "2"
|
||||
|
||||
class ValueType(StrEnum):
|
||||
status = "status"
|
||||
picture_mute = "picture.mute"
|
||||
lamp_mode = "lamp.mode"
|
||||
|
||||
|
||||
class BarcoRLMW_TCP:
|
||||
def __init__(self, projector_ip):
|
||||
self.projector_ip = projector_ip
|
||||
self.session = None
|
||||
|
||||
async def init(self):
|
||||
self.reader, self.writer = await telnetlib3.open_connection(self.projector_ip, 3023)
|
||||
|
||||
async def exec(self, cmd):
|
||||
await self.writer.write("op " + cmd + "\r")
|
||||
|
||||
async def set(self, key, val):
|
||||
await self.writer.write("op " + key + " = " + val + "\r")
|
||||
|
||||
async def query(self, key):
|
||||
await self.writer.write("op " + key + " ?\r")
|
||||
|
||||
async def set_power(self, power):
|
||||
await self.exec(f"power.{onoff(power)}")
|
||||
|
||||
async def set_shutter(self, shutter):
|
||||
await self.set("picture.mute", int(shutter))
|
||||
|
||||
async def iter_messages(self):
|
||||
"""Async iterator that processes feedback from the projector.
|
||||
Yields ACK (acknowledgement) and ValueUpdate (value has changed) messages."""
|
||||
while True:
|
||||
line = await self.reader.readuntil('\r').decode().strip()
|
||||
msg = self.parse_response(line)
|
||||
if msg:
|
||||
yield msg
|
||||
|
||||
def parse_response(self, line):
|
||||
matches = RE_STATUS.findall(line)
|
||||
if len(matches) == 0:
|
||||
return None
|
||||
match = matches[0]
|
||||
if len(match) == 2:
|
||||
return ACK(match[1])
|
||||
if len(match) == 3:
|
||||
return ValueUpdate(match[1], match[2])
|
||||
|
||||
|
||||
def onoff(state: bool) -> str:
|
||||
if state:
|
||||
return "on"
|
||||
else:
|
||||
return "off"
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
async def main():
|
||||
barco = BarcoRLMW_TCP("192.168.192.12")
|
||||
status = await barco.get_status()
|
||||
print(status)
|
||||
|
||||
await barco.click_remote("kymenu")
|
||||
|
||||
asyncio.run(main())
|
72
barco_rlmw_tcp/main.py
Normal file
72
barco_rlmw_tcp/main.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
import asyncio
|
||||
import aiomqtt
|
||||
from collections import defaultdict
|
||||
|
||||
from barco_rlmw_tcp import BarcoRLMW_TCP, ValueUpdate, Status, ACK, ValueType
|
||||
|
||||
# TODO MAKE THIS CONFIGURALBE
|
||||
PROJECTOR_IP = "192.168.192.12"
|
||||
MQTT_PREFIX = "p22/projektorji/glavni"
|
||||
MQTT_HOST = "-------"
|
||||
POLLING_PERIOD_SEC = 10
|
||||
|
||||
|
||||
class BarcoRLMW_TCP_MQTT:
|
||||
def __init__(self, projector_ip, mqtt_prefix):
|
||||
self.projector_ip = projector_ip
|
||||
self.mqtt_prefix = mqtt_prefix
|
||||
self.barco = BarcoRLMW_TCP(projector_ip)
|
||||
self.last_status = defaultdict(lambda: '')
|
||||
|
||||
async def run(self):
|
||||
async with aiomqtt.Client(MQTT_HOST, 1883) as client:
|
||||
self.client = client
|
||||
task_polling = asyncio.create_task(self.task_polling())
|
||||
task_control = asyncio.create_task(self.task_control())
|
||||
await asyncio.gather(task_control, task_polling)
|
||||
|
||||
async def task_control(self):
|
||||
topicMatch = f"{self.mqtt_prefix}/ukaz/+"
|
||||
await self.client.subscribe(topicMatch)
|
||||
|
||||
async for mesg in self.client.messages:
|
||||
cmd = mesg.topic.value.split("/")[-1]
|
||||
val = mesg.payload.decode()
|
||||
|
||||
if cmd == "power":
|
||||
await self.barco.set_power(onoff(val))
|
||||
elif cmd == "shutter":
|
||||
await self.barco.set_shutter(onoff(val))
|
||||
|
||||
async def task_polling(self):
|
||||
while True:
|
||||
await self.barco.query("status")
|
||||
await asyncio.sleep(POLLING_PERIOD_SEC)
|
||||
|
||||
async def write_status(self, status, value):
|
||||
await self.client.publish(f"{self.mqtt_prefix}/status/{status}", payload=value)
|
||||
|
||||
async def task_process_messages(self):
|
||||
async for msg in self.barco.iter_messages():
|
||||
# We only care about value updates
|
||||
if isinstance(msg, ValueUpdate):
|
||||
# Power status
|
||||
if msg.key == ValueType.status:
|
||||
if msg.value in (Status.imaging, Status.warmup):
|
||||
self.write_status("power", 1)
|
||||
elif msg.value in (Status.standby, Status.cooling):
|
||||
self.write_status("power", 0)
|
||||
# Video mute
|
||||
if msg.key == ValueType.picture_mute:
|
||||
self.write_status("shutter", msg.value)
|
||||
|
||||
def onoff(input):
|
||||
if input == "1":
|
||||
return True
|
||||
elif input == "0":
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
barco = BarcoRLMW_TCP_MQTT(PROJECTOR_IP, MQTT_PREFIX)
|
||||
asyncio.run(barco.run())
|
Loading…
Reference in a new issue