added +5v sensor to vertex2
This commit is contained in:
1 parent
264619565e
commit
914d48ae55
2 files changed
+252
-3
No files matched your search
+76
-3
@@ -17,6 +17,7 @@ class Vertex2(SmartObject):
|
||||
self._interrupt_stop = threading.Event()
|
||||
self._status_requested = threading.Event()
|
||||
self._last_logged_status = None
|
||||
self._input_5v_states = {}
|
||||
self._spam_lock = threading.RLock()
|
||||
self._spam_last_interrupt = None
|
||||
self._spam_snapshot = None
|
||||
@@ -187,10 +188,77 @@ class Vertex2(SmartObject):
|
||||
name=f'{self.name}_interrupt_listener',
|
||||
daemon=True,
|
||||
)
|
||||
self._initialize_input_5v_sensors()
|
||||
self._initialize_input_select()
|
||||
self.update_vertex2_states()
|
||||
self._interrupt_thread.start()
|
||||
|
||||
def _initialize_input_5v_sensors(self):
|
||||
self.input_5v_sensors = {}
|
||||
prefix = self.args['input_selected_sensor'].split('.', 1)[1].removesuffix('_input_selected')
|
||||
used_ids = set()
|
||||
for name, index in self.input_names.items():
|
||||
if index not in range(4):
|
||||
continue
|
||||
slug = re.sub(r'[^a-z0-9]+', '_', str(name).lower()).strip('_') or f'input_{index}'
|
||||
entity_id = f'binary_sensor.{prefix}_{slug}_5v'
|
||||
if entity_id in used_ids:
|
||||
entity_id = f'binary_sensor.{prefix}_{slug}_{index}_5v'
|
||||
used_ids.add(entity_id)
|
||||
config = self.get_input_config(index)
|
||||
self.input_5v_sensors[index] = self.create_entity(
|
||||
entity_id, state='unavailable', friendly_name=f'{name} +5 V',
|
||||
icon=config.get('icon'), device_class='power',
|
||||
)
|
||||
|
||||
def _invalidate_input_5v_sensors(self):
|
||||
self._input_5v_states = {}
|
||||
for sensor in getattr(self, 'input_5v_sensors', {}).values():
|
||||
if sensor.get_state() != 'unavailable':
|
||||
sensor.set_state(state='unavailable')
|
||||
|
||||
def _schedule_input_5v_refresh(self):
|
||||
# Device monitoring must run even when no HA input sensors are exposed.
|
||||
self.run_in(self._refresh_input_5v_sensors, 0.1)
|
||||
|
||||
def _refresh_input_5v_sensors(self, kwargs=None):
|
||||
if not self._vertex2_ready():
|
||||
self._invalidate_input_5v_sensors()
|
||||
return
|
||||
try:
|
||||
response = get(f'{self.args["vertex2_address"].rstrip("/")}/ssi/infopage.ssi', timeout=5)
|
||||
response.raise_for_status()
|
||||
status = response.json()
|
||||
if not isinstance(status, dict):
|
||||
raise ValueError('expected an information object')
|
||||
except (RequestException, ValueError) as error:
|
||||
self._invalidate_input_5v_sensors()
|
||||
self.log_warning(f'Vertex2 input +5V readback failed: {error}')
|
||||
return
|
||||
if not self._vertex2_ready():
|
||||
self._invalidate_input_5v_sensors()
|
||||
return
|
||||
states = {}
|
||||
for index in range(4):
|
||||
# Firmware uses 2 for present and 1 for absent, not boolean 1/0.
|
||||
states[index] = {'2': 'on', '1': 'off'}.get(
|
||||
str(status.get(f'rx{index}in5v')), 'unavailable')
|
||||
previous_states = self._input_5v_states
|
||||
self._input_5v_states = states
|
||||
input_changed = any(
|
||||
previous_states.get(index) in ('on', 'off')
|
||||
and state in ('on', 'off')
|
||||
and previous_states[index] != state
|
||||
for index, state in states.items()
|
||||
)
|
||||
if input_changed:
|
||||
self._start_command_processing()
|
||||
# HA sensors only expose the monitored state; they do not drive detection.
|
||||
for index, sensor in getattr(self, 'input_5v_sensors', {}).items():
|
||||
state = states[index]
|
||||
if sensor.get_state() != state:
|
||||
sensor.set_state(state=state)
|
||||
|
||||
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')
|
||||
@@ -296,7 +364,7 @@ class Vertex2(SmartObject):
|
||||
self._spam_last_interrupt = None
|
||||
self._spam_snapshot = None
|
||||
self._spam_count = 0
|
||||
if self.no_signal_spam_sensor.get_state() != state:
|
||||
if state is not None and self.no_signal_spam_sensor.get_state() != state:
|
||||
self.no_signal_spam_sensor.set_state(state=state)
|
||||
|
||||
def _observe_no_signal_spam(self, status):
|
||||
@@ -438,6 +506,7 @@ class Vertex2(SmartObject):
|
||||
continue
|
||||
self._reset_no_signal_spam('unavailable')
|
||||
self._invalidate_plus5_sensors()
|
||||
self._invalidate_input_5v_sensors()
|
||||
self.unreachable_sensor.set_state(state='on')
|
||||
self.video_tx_signal_sensor.set_state(state='unavailable')
|
||||
for sensor in self.video_tx_signal_sensors.values():
|
||||
@@ -466,10 +535,11 @@ class Vertex2(SmartObject):
|
||||
connection.close()
|
||||
|
||||
def _stop_interrupt_listener(self):
|
||||
self._reset_no_signal_spam('unavailable')
|
||||
interrupt_stop = getattr(self, '_interrupt_stop', None)
|
||||
if interrupt_stop is not None:
|
||||
interrupt_stop.set()
|
||||
# Cancel spam tracking without emitting state changes during app teardown.
|
||||
self._reset_no_signal_spam(state=None)
|
||||
self._close_interrupt_connection()
|
||||
interrupt_thread = getattr(self, '_interrupt_thread', None)
|
||||
if interrupt_thread is not None:
|
||||
@@ -651,6 +721,7 @@ class Vertex2(SmartObject):
|
||||
)
|
||||
|
||||
def _suspend_vertex2(self):
|
||||
self._invalidate_input_5v_sensors()
|
||||
self._reset_no_signal_spam()
|
||||
self._invalidate_plus5_sensors()
|
||||
self._close_interrupt_connection()
|
||||
@@ -689,7 +760,7 @@ class Vertex2(SmartObject):
|
||||
self.turn_off(self.power_plug_entity)
|
||||
|
||||
def _start_command_processing(self, only_if_active=False):
|
||||
# Only commands start a window; changed status may extend an active one.
|
||||
# Commands and input +5V transitions start a window; status may extend it.
|
||||
if self.command_processing_sensor is None:
|
||||
return
|
||||
with self._command_processing_lock:
|
||||
@@ -1003,3 +1074,5 @@ class Vertex2(SmartObject):
|
||||
if kwargs.get('reconfigure', False):
|
||||
self._reconfigure_vertex2()
|
||||
self._refresh_plus5_sensors()
|
||||
# Let the firmware settle before HTTP readback, including initial connection.
|
||||
self._schedule_input_5v_refresh()
|
||||
Reference in new issue
Block a user