Skip to content

Commit

Permalink
Merge pull request #820 from tpjanssen/master
Browse files Browse the repository at this point in the history
Added uptime sensor
  • Loading branch information
dermotduffy authored Jan 6, 2025
2 parents 2e5e690 + 862eada commit 09b711c
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 1 deletion.
1 change: 1 addition & 0 deletions custom_components/frigate/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
# Unit of measurement
FPS = "fps"
MS = "ms"
S = "s"

# Attributes
ATTR_CLIENT = "client"
Expand Down
1 change: 1 addition & 0 deletions custom_components/frigate/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ICON_SERVER = "mdi:server"
ICON_SPEEDOMETER = "mdi:speedometer"
ICON_WAVEFORM = "mdi:waveform"
ICON_UPTIME = "mdi:clock-time-five"

ICON_DEFAULT_ON = "mdi:home"

Expand Down
60 changes: 59 additions & 1 deletion custom_components/frigate/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@
get_frigate_entity_unique_id,
get_zones,
)
from .const import ATTR_CONFIG, ATTR_COORDINATOR, DOMAIN, FPS, MS, NAME
from .const import ATTR_CONFIG, ATTR_COORDINATOR, DOMAIN, FPS, MS, NAME, S
from .icons import (
ICON_CORAL,
ICON_SERVER,
ICON_SPEEDOMETER,
ICON_UPTIME,
ICON_WAVEFORM,
get_icon_from_type,
)
Expand Down Expand Up @@ -104,6 +105,7 @@ async def async_setup_entry(
]
)
entities.append(FrigateStatusSensor(coordinator, entry))
entities.append(FrigateUptimeSensor(coordinator, entry))
async_add_entities(entities)


Expand Down Expand Up @@ -207,6 +209,62 @@ def icon(self) -> str:
return ICON_SERVER


class FrigateUptimeSensor(
FrigateEntity, CoordinatorEntity[FrigateDataUpdateCoordinator]
):
"""Frigate Uptime Sensor class."""

_attr_entity_category = EntityCategory.DIAGNOSTIC
_attr_name = "Uptime"

def __init__(
self, coordinator: FrigateDataUpdateCoordinator, config_entry: ConfigEntry
) -> None:
"""Construct a FrigateUptimeSensor."""
FrigateEntity.__init__(self, config_entry)
CoordinatorEntity.__init__(self, coordinator)
self._attr_entity_registry_enabled_default = False

@property
def unique_id(self) -> str:
"""Return a unique ID to use for this entity."""
return get_frigate_entity_unique_id(
self._config_entry.entry_id, "uptime", "frigate"
)

@property
def device_info(self) -> DeviceInfo:
"""Get device information."""
return {
"identifiers": {get_frigate_device_identifier(self._config_entry)},
"name": NAME,
"model": self._get_model(),
"configuration_url": self._config_entry.data.get(CONF_URL),
"manufacturer": NAME,
}

@property
def state(self) -> int | None:
"""Return the state of the sensor."""
if self.coordinator.data:
data = self.coordinator.data.get("service", {}).get("uptime", 0)
try:
return int(data)
except (TypeError, ValueError):
pass
return None

@property
def unit_of_measurement(self) -> str:
"""Return the unit of measurement of the sensor."""
return S

@property
def icon(self) -> str:
"""Return the icon of the sensor."""
return ICON_UPTIME


class DetectorSpeedSensor(
FrigateEntity, CoordinatorEntity[FrigateDataUpdateCoordinator]
):
Expand Down
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
TEST_SENSOR_FRONT_DOOR_SKIPPED_FPS_ENTITY_ID = "sensor.front_door_skipped_fps"
TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID = "sensor.front_door_sound_level"
TEST_SENSOR_FRIGATE_STATUS_ENTITY_ID = "sensor.frigate_status"
TEST_SENSOR_FRIGATE_UPTIME_ENTITY_ID = "sensor.frigate_uptime"
TEST_UPDATE_FRIGATE_CONTAINER_ENTITY_ID = "update.frigate_server"

TEST_SERVER_VERSION = "0.14.1-f4f3cfa"
Expand Down
34 changes: 34 additions & 0 deletions tests/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
ICON_PERSON,
ICON_SERVER,
ICON_SPEEDOMETER,
ICON_UPTIME,
ICON_WAVEFORM,
)
from homeassistant.const import PERCENTAGE, UnitOfSoundPressure, UnitOfTemperature
Expand All @@ -44,6 +45,7 @@
TEST_SENSOR_CPU2_INTFERENCE_SPEED_ENTITY_ID,
TEST_SENSOR_DETECTION_FPS_ENTITY_ID,
TEST_SENSOR_FRIGATE_STATUS_ENTITY_ID,
TEST_SENSOR_FRIGATE_UPTIME_ENTITY_ID,
TEST_SENSOR_FRONT_DOOR_ALL_ACTIVE_ENTITY_ID,
TEST_SENSOR_FRONT_DOOR_ALL_ENTITY_ID,
TEST_SENSOR_FRONT_DOOR_CAMERA_FPS_ENTITY_ID,
Expand Down Expand Up @@ -375,6 +377,38 @@ async def test_status_sensor_error(hass: HomeAssistant) -> None:
assert entity_state.attributes["icon"] == ICON_SERVER


async def test_uptime_sensor(hass: HomeAssistant) -> None:
"""Test FrigateUptimeSensor expected state."""

client = create_mock_frigate_client()
await setup_mock_frigate_config_entry(hass, client=client)
await enable_and_load_entity(hass, client, TEST_SENSOR_FRIGATE_UPTIME_ENTITY_ID)

entity_state = hass.states.get(TEST_SENSOR_FRIGATE_UPTIME_ENTITY_ID)
assert entity_state
assert entity_state.state == "101113"
assert entity_state.attributes["icon"] == ICON_UPTIME

stats: dict[str, Any] = copy.deepcopy(TEST_STATS)
client.async_get_stats = AsyncMock(return_value=stats)

stats["service"]["uptime"] = None
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()

entity_state = hass.states.get(TEST_SENSOR_FRIGATE_UPTIME_ENTITY_ID)
assert entity_state
assert entity_state.state == "unknown"

stats["service"]["uptime"] = "NOT_A_NUMBER"
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()

entity_state = hass.states.get(TEST_SENSOR_FRIGATE_UPTIME_ENTITY_ID)
assert entity_state
assert entity_state.state == "unknown"


async def test_per_entry_device_info(hass: HomeAssistant) -> None:
"""Verify switch device information."""
config_entry = await setup_mock_frigate_config_entry(hass)
Expand Down

0 comments on commit 09b711c

Please sign in to comment.