Add Home Assistant discovery icons

This commit is contained in:
2026-08-03 01:50:42 +02:00
parent 15ec93f82e
commit 91b0fedbe8
3 changed files with 80 additions and 0 deletions
+2
View File
@@ -14,6 +14,8 @@ through Home Assistant MQTT Discovery plus an emergency HTTP fallback GUI.
can update MQTT Discovery without a container restart.
- On startup it runs a safe `all-off` by default, sets switch entities to `OFF`,
and publishes retained MQTT state.
- Home Assistant MQTT Discovery payloads include semantic MDI icons for all-off,
siren, red-blue/strobe, and white-light entities.
- Alarms and lights have default auto-off timers: siren 180s, red-blue/strobe
300s, white light 600s. The GUI timer is rendered from a backend timestamp,
so page refreshes do not reset it.
+23
View File
@@ -19,6 +19,12 @@ VERSION = "1.0"
DEFAULT_CONFIG = "/etc/frigate-camera-control-bridge.json"
LOG = logging.getLogger("frigate-camera-control-bridge")
STREAM_URL_RE = re.compile(r"(?:rtsp|rtsps|http|https)://[^\s'\"<>]+", re.IGNORECASE)
HOME_ASSISTANT_ACTION_ICONS = {
"action.siren": "mdi:bullhorn",
"action.red_blue": "mdi:alarm-light",
"action.manual_white": "mdi:lightbulb-on",
"action.all_off": "mdi:power",
}
from .i18n import DEFAULT_LANGUAGE, available_languages, normalize_language, text_for
from .ui import read_static_file, render_page
@@ -1401,6 +1407,9 @@ class CameraControlBridge:
},
"qos": 0,
}
icon = self.home_assistant_icon(action)
if icon:
payload["icon"] = icon
if action.platform == "switch":
payload.update(
{
@@ -1424,6 +1433,20 @@ class CameraControlBridge:
)
return payload
@staticmethod
def home_assistant_icon(action):
# Home Assistant MQTT discovery accepts MDI icons on switches and
# buttons. Keep icons semantic and overrideable by static action config.
configured = action.cfg.get("icon")
if configured:
return configured
name_key = action.cfg.get("name_key")
if name_key in HOME_ASSISTANT_ACTION_ICONS:
return HOME_ASSISTANT_ACTION_ICONS[name_key]
if action.kind == "all_off":
return HOME_ASSISTANT_ACTION_ICONS["action.all_off"]
return None
def execute_action(self, action_id, command, publish=True):
action = self.action_by_id(action_id)
if action is None:
+55
View File
@@ -0,0 +1,55 @@
import unittest
from frigate_camera_control_bridge.app import Action, CameraControlBridge
class HomeAssistantDiscoveryTest(unittest.TestCase):
def setUp(self):
self.bridge = object.__new__(CameraControlBridge)
self.bridge.config = {"mqtt": {"base_topic": "test/camera_control"}}
self.bridge.default_language = "en"
def payload_for(self, cfg):
base_cfg = {
"id": "example_action",
"name": "Example action",
"platform": "switch",
"kind": "dahua_coaxial_io",
"device": {"identifiers": ["camera_example"], "name": "Example camera"},
}
base_cfg.update(cfg)
action = Action(base_cfg, http_client=None)
return self.bridge.discovery_payload(action, "test/camera_control/status")
def test_switch_discovery_includes_semantic_icons(self):
cases = {
"action.siren": "mdi:bullhorn",
"action.red_blue": "mdi:alarm-light",
"action.manual_white": "mdi:lightbulb-on",
}
for name_key, icon in cases.items():
with self.subTest(name_key=name_key):
payload = self.payload_for({"name_key": name_key})
self.assertEqual(payload["icon"], icon)
def test_all_off_button_discovery_includes_power_icon(self):
payload = self.payload_for(
{
"platform": "button",
"kind": "all_off",
"name_key": "action.all_off",
}
)
self.assertEqual(payload["icon"], "mdi:power")
def test_configured_icon_overrides_default_icon(self):
payload = self.payload_for({"name_key": "action.siren", "icon": "mdi:test-tube"})
self.assertEqual(payload["icon"], "mdi:test-tube")
if __name__ == "__main__":
unittest.main()