implemented buttons and projector shutdown
This commit is contained in:
Vendored
+1
@@ -47,6 +47,7 @@
|
||||
"cwd": "${workspaceFolder}",
|
||||
"console": "integratedTerminal",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceFolder}",
|
||||
"INTERVAL" : "15",
|
||||
"LOG_FILE": "/tmp/upsmon.log",
|
||||
"LOG_FILE_LVL": "WARNING",
|
||||
|
||||
+62
-24
@@ -2,7 +2,7 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from typing import Dict, List, Optional, Type, TypeVar, Set, Any
|
||||
from typing import List, Optional, Type, TypeVar, Set, Any, Callable
|
||||
from uuid import UUID
|
||||
|
||||
import projrequest
|
||||
@@ -22,28 +22,48 @@ LOGGER: logging.Logger
|
||||
|
||||
DISCOVERY_PREFIX = "homeassistant"
|
||||
|
||||
class HAsensor(BaseModel):
|
||||
class HAentity(BaseModel):
|
||||
name: str
|
||||
unique_id: str
|
||||
state_topic: str
|
||||
device: Any
|
||||
entity_type: str = Field(exclude=True, default="sensor")
|
||||
|
||||
class HAsensor(HAentity):
|
||||
value_template: Optional[str] = None
|
||||
unit_of_measurement: Optional[str] = None
|
||||
state_topic: str
|
||||
device_class: Optional[str] = None
|
||||
state_class: Optional[str] = None
|
||||
icon: Optional[str] = None
|
||||
device: Any
|
||||
sensor_type: str = Field(exclude = True, default="sensor")
|
||||
request: Type = Field(exclude=True)
|
||||
|
||||
class HAbutton(HAentity):
|
||||
command_topic: str
|
||||
payload_press: str = ""
|
||||
device_class: Optional[str] = None
|
||||
icon: Optional[str] = None
|
||||
callback: Optional[Callable[[mqtt_client.Client, Any, mqtt_client.MQTTMessage], None]] = Field(exclude=True, default=None)
|
||||
|
||||
class HAdevice(BaseModel):
|
||||
identifiers: List[str]
|
||||
name: str
|
||||
manufacturer: str
|
||||
model: str
|
||||
via_device: str | None = None
|
||||
sensors: List[HAsensor] = Field(exclude=True, default_factory=list)
|
||||
entities: List[HAentity] = Field(exclude=True, default_factory=list)
|
||||
short_name: str = Field(exclude=True)
|
||||
|
||||
def on_shutwown(client: mqtt_client.Client, userdata: Any, msg: mqtt_client.MQTTMessage) -> None:
|
||||
LOGGER.info("Shutdown command received")
|
||||
if msg and msg.payload.decode() == "shutdown":
|
||||
LOGGER.info("Shutting down projector")
|
||||
projector: projrequest.ProjectorConnection = projrequest.ProjectorConnection(
|
||||
ip=env['PROJECTOR_IP'],
|
||||
username=env['PROJECTOR_USER'],
|
||||
password=env['PROJECTOR_PASSWORD']
|
||||
)
|
||||
projector.shutdown()
|
||||
|
||||
##################
|
||||
###### MAIN ######
|
||||
##################
|
||||
@@ -79,7 +99,18 @@ def main() -> int:
|
||||
short_name="sony_projector"
|
||||
)
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAbutton (
|
||||
name="Power Off",
|
||||
unique_id=f"{sony_device.short_name}_power_off",
|
||||
command_topic=f"{sony_device.short_name}/commands",
|
||||
icon="mdi:power",
|
||||
payload_press="shutdown",
|
||||
entity_type="button",
|
||||
callback=on_shutwown,
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Free DCP Storage",
|
||||
unique_id=f"{sony_device.short_name}_free_storage",
|
||||
state_topic=f"{sony_device.short_name}/storage_info",
|
||||
@@ -92,7 +123,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Used DCP Storage",
|
||||
unique_id=f"{sony_device.short_name}_used_storage",
|
||||
state_topic=f"{sony_device.short_name}/storage_info",
|
||||
@@ -105,7 +136,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Play State",
|
||||
unique_id=f"{sony_device.short_name}_play_state",
|
||||
state_topic=f"{sony_device.short_name}/show_info",
|
||||
@@ -115,7 +146,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Playback Mode",
|
||||
unique_id=f"{sony_device.short_name}_playback_mode",
|
||||
state_topic=f"{sony_device.short_name}/show_info",
|
||||
@@ -125,7 +156,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Total Duration",
|
||||
unique_id=f"{sony_device.short_name}_total_duration",
|
||||
state_topic=f"{sony_device.short_name}/show_info",
|
||||
@@ -138,7 +169,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Elapsed Time",
|
||||
unique_id=f"{sony_device.short_name}_elapsed_time",
|
||||
state_topic=f"{sony_device.short_name}/show_info",
|
||||
@@ -151,7 +182,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Remaining Time",
|
||||
unique_id=f"{sony_device.short_name}_remaining_time",
|
||||
state_topic=f"{sony_device.short_name}/show_info",
|
||||
@@ -164,7 +195,7 @@ def main() -> int:
|
||||
device=sony_device
|
||||
))
|
||||
|
||||
sony_device.sensors.append(HAsensor (
|
||||
sony_device.entities.append(HAsensor (
|
||||
name="Event Title",
|
||||
unique_id=f"{sony_device.short_name}_event_title",
|
||||
state_topic=f"{sony_device.short_name}/show_info",
|
||||
@@ -188,7 +219,7 @@ def main() -> int:
|
||||
via_device=sony_device.identifiers[0]
|
||||
)
|
||||
|
||||
lamp_device.sensors.append(HAsensor (
|
||||
lamp_device.entities.append(HAsensor (
|
||||
name=f"Hours of Use",
|
||||
unique_id=f"{lamp_device.short_name}_hours",
|
||||
state_topic=f"{sony_device.short_name}/{lamp_device.short_name}/state",
|
||||
@@ -201,7 +232,7 @@ def main() -> int:
|
||||
device=lamp_device
|
||||
))
|
||||
|
||||
lamp_device.sensors.append(HAsensor (
|
||||
lamp_device.entities.append(HAsensor (
|
||||
name=f"Power",
|
||||
unique_id=f"{lamp_device.short_name}_power",
|
||||
state_topic=f"{sony_device.short_name}/{lamp_device.short_name}/state",
|
||||
@@ -214,7 +245,7 @@ def main() -> int:
|
||||
device=lamp_device
|
||||
))
|
||||
|
||||
lamp_device.sensors.append(HAsensor (
|
||||
lamp_device.entities.append(HAsensor (
|
||||
name=f"Status",
|
||||
unique_id=f"{lamp_device.short_name}_status",
|
||||
state_topic=f"{sony_device.short_name}/{lamp_device.short_name}/state",
|
||||
@@ -225,14 +256,14 @@ def main() -> int:
|
||||
device=lamp_device
|
||||
))
|
||||
|
||||
lamp_device.sensors.append(HAsensor (
|
||||
lamp_device.entities.append(HAsensor (
|
||||
name=f"Lamp ON",
|
||||
unique_id=f"{lamp_device.short_name}_lampon",
|
||||
state_topic=f"{sony_device.short_name}/{lamp_device.short_name}/state",
|
||||
value_template="{{ value_json.LampOn }}",
|
||||
device_class="power",
|
||||
icon="mdi:lightbulb-on-outline",
|
||||
sensor_type="binary_sensor",
|
||||
entity_type="binary_sensor",
|
||||
request=PrjLampInformation,
|
||||
device=lamp_device
|
||||
))
|
||||
@@ -242,10 +273,16 @@ def main() -> int:
|
||||
all_devices: List[HAdevice] = [sony_device, *lamp_devices]
|
||||
|
||||
for d in all_devices:
|
||||
for s in d.sensors:
|
||||
mqtt.publish(topic=f"{DISCOVERY_PREFIX}/{s.sensor_type}/{s.unique_id}/config",
|
||||
for s in d.entities:
|
||||
# Publish config mesasge
|
||||
mqtt.publish(topic=f"{DISCOVERY_PREFIX}/{s.entity_type}/{s.unique_id}/config",
|
||||
payload=s.model_dump_json(indent=1, exclude_none=True),
|
||||
retain=True)
|
||||
# subscrie to command topic if this is a button
|
||||
if isinstance(s, HAbutton):
|
||||
mqtt.subscribe(topic=s.command_topic)
|
||||
if s.callback is not None:
|
||||
mqtt.message_callback_add(sub=s.command_topic, callback=s.callback)
|
||||
time.sleep(0.2)
|
||||
|
||||
playlists: SPLList | None = None
|
||||
@@ -257,12 +294,13 @@ def main() -> int:
|
||||
# update projector states
|
||||
lamp_num: int = 0
|
||||
for d in all_devices:
|
||||
states: Set[Type] = set([s.request for s in d.sensors])
|
||||
sensors: List[HAsensor] = [x for x in d.entities if isinstance(x, HAsensor)]
|
||||
states: Set[Type] = set([s.request for s in sensors])
|
||||
|
||||
for s in states:
|
||||
# include lamp id in the requests parameters
|
||||
if s == PrjLampInformation:
|
||||
resp = projector.request(s, reqParams={"lampId": lamp_num})
|
||||
resp = projector.request(s, addlParams={"lampId": lamp_num})
|
||||
lamp_num += 1
|
||||
else:
|
||||
resp = projector.request(s)
|
||||
@@ -286,7 +324,7 @@ def main() -> int:
|
||||
# send only one message for sensor with this type of request
|
||||
last_cls: Type = SMSMessage
|
||||
# filter sensors of this device per this type of request
|
||||
for sens in filter(lambda x: x.request == s, d.sensors):
|
||||
for sens in filter(lambda x: x.request == s, sensors):
|
||||
if last_cls == sens.request:
|
||||
continue
|
||||
if isinstance(resp, SMSMessage):
|
||||
|
||||
@@ -43,13 +43,13 @@ class ProjectorConnection():
|
||||
return xmltodict.parse(response.text.replace("%2F", "/").replace("%3A", ":")) # Common containert for all messages
|
||||
return {}
|
||||
|
||||
def request(self, cls: Type[T], reqParams: Dict[str, Any] = {}) -> T | None:
|
||||
def request(self, cls: Type[T], addlParams: Dict[str, Any] = {}) -> T | None:
|
||||
rv: dict
|
||||
if TEST:
|
||||
with open(f'{getcwd()}/projmon/xmlresponses/showstatus.xml', 'r') as fd:
|
||||
rv = xmltodict.parse(fd.read().replace("%2F", "/").replace("%3A", ":"))
|
||||
else:
|
||||
rv = self.get(cls.path, cls.params | reqParams)
|
||||
rv = self.get(cls.path, cls.params | addlParams)
|
||||
if isinstance(rv, dict) and rv.items():
|
||||
rv = rv['SMSMessage']
|
||||
tt: str = rv['MessageHeader']['Type']
|
||||
@@ -59,3 +59,6 @@ class ProjectorConnection():
|
||||
#print(json.dumps(rv, indent = 2))
|
||||
return cls.model_validate(rv)
|
||||
return None
|
||||
|
||||
def shutdown(self) -> None:
|
||||
self.get(['command', 'sms', 'shutdown'])
|
||||
|
||||
Reference in New Issue
Block a user