new vertex2 content sensor
This commit is contained in:
1 parent
914d48ae55
commit
d6d470903c
3 files changed
+345
No files matched your search
@@ -0,0 +1,166 @@
|
||||
from ad_toolbox.smartobject import SmartObject
|
||||
|
||||
|
||||
EMPTY_VALUES = {None, "", "unknown", "unavailable", "none", "null"}
|
||||
|
||||
|
||||
def useful(value):
|
||||
"""Return a displayable Home Assistant value, or None."""
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
if value.lower() in EMPTY_VALUES:
|
||||
return None
|
||||
elif value in EMPTY_VALUES:
|
||||
return None
|
||||
return value
|
||||
|
||||
|
||||
class VertexContent(SmartObject):
|
||||
"""Expose normalized metadata for the source currently selected on a Vertex2."""
|
||||
|
||||
def on_initialize_smart_object(self):
|
||||
super().on_initialize_smart_object()
|
||||
self.output = self.args.get("output", "sensor.vertex2_current_content")
|
||||
self.input_selected = self.args.get(
|
||||
"input_selected", "sensor.vertex2_input_selected"
|
||||
)
|
||||
self.has_signal = self.args.get(
|
||||
"has_signal", "binary_sensor.vertex2_has_input_signal"
|
||||
)
|
||||
self.sources = self.args.get("sources", {})
|
||||
|
||||
state, attributes = self.build_content()
|
||||
self.output_entity = self.create_entity(
|
||||
self.output, state=state, attributes=attributes
|
||||
)
|
||||
|
||||
self.listen_state(self._state_changed, self.input_selected)
|
||||
self.listen_state(self._state_changed, self.has_signal)
|
||||
|
||||
# attribute="all" is important: a media title can change while the
|
||||
# media_player state remains "playing".
|
||||
listened = set()
|
||||
for config in self.sources.values():
|
||||
for entity in (config.get("entity"), config.get("artwork_entity")):
|
||||
if entity and entity not in listened:
|
||||
self.listen_state(self._state_changed, entity, attribute="all")
|
||||
listened.add(entity)
|
||||
|
||||
def _state_changed(self, entity, attribute, old, new, kwargs):
|
||||
self.update_content()
|
||||
|
||||
def _entity_data(self, entity):
|
||||
if not entity:
|
||||
return None, {}
|
||||
data = self.get_state(entity, attribute="all") or {}
|
||||
return data.get("state"), data.get("attributes", {}) or {}
|
||||
|
||||
@staticmethod
|
||||
def _first_attribute(attributes, names):
|
||||
for name in names:
|
||||
value = useful(attributes.get(name))
|
||||
if value is not None:
|
||||
return value
|
||||
return None
|
||||
|
||||
def _artwork(self, config, attributes):
|
||||
artwork = self._first_attribute(
|
||||
attributes, config.get("artwork_attributes", ["entity_picture"])
|
||||
)
|
||||
if artwork is not None:
|
||||
return artwork
|
||||
_, artwork_attributes = self._entity_data(config.get("artwork_entity"))
|
||||
return useful(artwork_attributes.get("entity_picture"))
|
||||
|
||||
@staticmethod
|
||||
def _pause_supported(config, application, source_state):
|
||||
pause_states = config.get("pause_states", [])
|
||||
if not pause_states or useful(source_state) is None:
|
||||
return False
|
||||
supported_apps = config.get("pause_supported_apps")
|
||||
if supported_apps is None:
|
||||
return True
|
||||
return application in supported_apps
|
||||
|
||||
def build_content(self):
|
||||
selected = useful(self.get_state(self.input_selected))
|
||||
has_signal = self.get_state(self.has_signal) == "on"
|
||||
|
||||
base = {
|
||||
"friendly_name": "Contenu Vertex2",
|
||||
"icon": "mdi:television-play",
|
||||
"source": selected,
|
||||
"platform": None,
|
||||
"content_type": None,
|
||||
"title": None,
|
||||
"series_title": None,
|
||||
"application": None,
|
||||
"status": "idle",
|
||||
"artwork": None,
|
||||
"entity_picture": None,
|
||||
"available": False,
|
||||
"is_paused": False,
|
||||
"is_pause_supported": False,
|
||||
}
|
||||
|
||||
if not has_signal or selected is None:
|
||||
base["source"] = selected
|
||||
base["icon"] = "mdi:television-off"
|
||||
return "idle", base
|
||||
|
||||
config = self.sources.get(str(selected), {})
|
||||
label = config.get("label", selected)
|
||||
source_state, attributes = self._entity_data(config.get("entity"))
|
||||
application = self._first_attribute(
|
||||
attributes, config.get("application_attributes", ["app_name"])
|
||||
)
|
||||
title = self._first_attribute(
|
||||
attributes, config.get("title_attributes", ["media_title"])
|
||||
)
|
||||
series_title = self._first_attribute(
|
||||
attributes, config.get("series_title_attributes", ["media_series_title"])
|
||||
)
|
||||
|
||||
if title is None and config.get("state_as_title"):
|
||||
title = useful(source_state)
|
||||
|
||||
artwork = self._artwork(config, attributes)
|
||||
pause_supported = self._pause_supported(config, application, source_state)
|
||||
pause_states = config.get("pause_states", [])
|
||||
is_paused = pause_supported and source_state in pause_states
|
||||
content_type = self._first_attribute(
|
||||
attributes, config.get("content_type_attributes", ["media_content_type"])
|
||||
)
|
||||
if content_type is None:
|
||||
content_type = config.get("content_type")
|
||||
if content_type is None and application and title is None:
|
||||
content_type = "application"
|
||||
|
||||
display = title or application or label
|
||||
base.update({
|
||||
"icon": config.get("icon", base["icon"]),
|
||||
"platform": config.get("platform", label),
|
||||
"content_type": content_type,
|
||||
"title": title,
|
||||
"series_title": series_title,
|
||||
"application": application,
|
||||
"status": useful(source_state) or "active",
|
||||
"artwork": artwork,
|
||||
"entity_picture": artwork,
|
||||
"available": True,
|
||||
"is_paused": is_paused,
|
||||
"is_pause_supported": pause_supported,
|
||||
})
|
||||
return str(display)[:255], base
|
||||
|
||||
def update_content(self):
|
||||
state, attributes = self.build_content()
|
||||
current_state = self.output_entity.get_state()
|
||||
current_attributes = self.output_entity.get_state(attribute="all") or {}
|
||||
if isinstance(current_attributes, dict) and "attributes" in current_attributes:
|
||||
current_attributes = current_attributes["attributes"]
|
||||
expected_attributes = dict(attributes)
|
||||
expected_attributes["ad_app"] = self.name
|
||||
if current_state != state or current_attributes != expected_attributes:
|
||||
self.output_entity.set_state(state=state, attributes=expected_attributes)
|
||||
|
||||
Reference in new issue
Block a user