Added a select entity to manually switch input.

This commit is contained in:
Pierre committed 2026-10-18 00:09:10 +02:00
1 parent 1fd4dab916
commit 5dbfd2a805
3 files changed
+222

No files matched your search

+6
View File
@@ -165,6 +165,12 @@ vertex_2:
sensors:
binary_sensor.projector_screen_down: input_boolean.projection_screen
input_select:
entity: select.vertex2_input
mqtt_namespace: mqtt
mqtt_topic: appdaemon/vertex2/input
unique_id: vertex2_input
input_config:
default:
name: None
+98
View File
@@ -4,6 +4,7 @@ from requests.exceptions import Timeout,ConnectionError,RequestException
from ad_toolbox.smartobject import SmartObject
import ad_toolbox.smartcondition as SmartCondition
import time
import json
import socket
import threading
import re
@@ -186,9 +187,104 @@ class Vertex2(SmartObject):
name=f'{self.name}_interrupt_listener',
daemon=True,
)
self._initialize_input_select()
self.update_vertex2_states()
self._interrupt_thread.start()
def _initialize_input_select(self):
"""Expose a real HA select, with device-confirmed state, through MQTT."""
self._input_select_config = self.args.get('input_select')
if not self._input_select_config:
return
config = self._input_select_config
self._select_namespace = config.get('mqtt_namespace', 'mqtt')
self._select_topic = config.get('mqtt_topic', f'appdaemon/{self.name}/input').rstrip('/')
self._select_uid = config.get('unique_id', f'{self.name}_input')
self.listen_event(self._on_input_select_mqtt, 'MQTT_MESSAGE',
namespace=self._select_namespace)
for entity in (self.args['input_selected_sensor'], self.args['unreachable_sensor']):
self.listen_state(self._on_input_select_state, entity, attribute='all')
if self.power_plug_entity:
self.listen_state(self._on_input_select_state, self.power_plug_entity)
self._discover_input_select()
def _publish_input_select(self, suffix, payload):
if not isinstance(payload, str):
payload = json.dumps(payload, ensure_ascii=False)
self.call_service('mqtt/publish', topic=self._select_topic + suffix,
payload=payload, retain=True, namespace=self._select_namespace)
def _discover_input_select(self):
config = self._input_select_config
for topic in (self._select_topic + '/set', 'homeassistant/status'):
self.call_service('mqtt/subscribe', topic=topic, namespace=self._select_namespace)
availability = [{'topic': self._select_topic + '/availability'}]
# The shared plugin's connection topic belongs to the MQTT transport,
# regardless of the name originally chosen for that plugin.
mqtt_config = self.get_plugin_config(namespace=self._select_namespace) or {}
connection_topic = config.get('connection_topic') or mqtt_config.get('will_topic')
if connection_topic:
availability.append(dict(
topic=connection_topic,
payload_available=mqtt_config.get('birth_payload', 'online'),
payload_not_available=mqtt_config.get('will_payload', 'offline'),
))
payload = dict(
name='Input', unique_id=self._select_uid,
default_entity_id=config.get('entity', 'select.vertex2_input'),
device=dict(identifiers=[f'appdaemon_{self.name}'], name='Vertex2',
manufacturer='HDFury', model='Vertex2'),
options=list(self.input_names), optimistic=False,
command_topic=self._select_topic + '/set',
state_topic=self._select_topic + '/state',
json_attributes_topic=self._select_topic + '/attributes',
availability=availability, availability_mode='all',
)
self._select_discovery_payload = payload
self._sync_input_select(force_discovery=True)
self.log_info(f'Published MQTT discovery for {payload["default_entity_id"]}')
def _on_input_select_state(self, entity, attribute, old, new, kwargs):
self._sync_input_select()
def _sync_input_select(self, force_discovery=False):
if not getattr(self, '_input_select_config', None):
return
name = self.input_selected_sensor.get_state()
valid = name in self.input_names
config = self.get_input_config(self.input_names[name] if valid else None)
icon = config.get('icon') or 'mdi:video-input-hdmi'
# HA's MQTT JSON attributes do not override the entity's icon property.
# Update discovery only when the icon changes (or on reconnect).
discovery = self._select_discovery_payload
if force_discovery or discovery.get('icon') != icon:
discovery['icon'] = icon
self.call_service('mqtt/publish',
topic=f'homeassistant/select/{self._select_uid}/config',
payload=json.dumps(discovery), retain=True,
namespace=self._select_namespace)
self._publish_input_select('/attributes', {'icon': icon})
self._publish_input_select('/state', name if valid else 'None')
available = (valid and self._vertex2_powered()
and self.unreachable_sensor.get_state() == 'off')
self._publish_input_select('/availability', 'online' if available else 'offline')
def _on_input_select_mqtt(self, event, data, kwargs):
topic, payload = data.get('topic'), data.get('payload')
if ((topic is None and data.get('state') == 'Connected')
or (topic == 'homeassistant/status' and payload == 'online')):
self._discover_input_select()
elif topic == self._select_topic + '/set':
if payload not in self.input_names:
self.log_warning(f'Rejected unknown Vertex2 input: {payload!r}')
return
if not self._vertex2_ready():
self.log_warning('Vertex2 input command ignored: device is not ready')
return
# insel sets both TX ports; only a subsequent device status updates HA.
self.select_input(payload)
self.update_vertex2_states()
def _reset_no_signal_spam(self, state='off'):
if getattr(self, 'no_signal_spam_sensor', None) is None:
return
@@ -391,6 +487,8 @@ class Vertex2(SmartObject):
self._command_processing_handle = None
def terminate(self):
if getattr(self, '_input_select_config', None):
self._publish_input_select('/availability', 'offline')
self._stop_interrupt_listener()
super().terminate()