Add sensors to Trafikverket Camera (#100078)

* Add sensors to Trafikverket Camera

* Remove active

* Fix test len
This commit is contained in:
G Johansson 2023-09-11 00:56:12 +02:00 committed by GitHub
parent 45fc158823
commit 4ebb6bb823
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 196 additions and 5 deletions

View File

@ -3,7 +3,7 @@ from homeassistant.const import Platform
DOMAIN = "trafikverket_camera" DOMAIN = "trafikverket_camera"
CONF_LOCATION = "location" CONF_LOCATION = "location"
PLATFORMS = [Platform.CAMERA] PLATFORMS = [Platform.CAMERA, Platform.SENSOR]
ATTRIBUTION = "Data provided by Trafikverket" ATTRIBUTION = "Data provided by Trafikverket"
ATTR_DESCRIPTION = "description" ATTR_DESCRIPTION = "description"

View File

@ -0,0 +1,139 @@
"""Sensor platform for Trafikverket Camera integration."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import DEGREE
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import CameraData, TVDataUpdateCoordinator
PARALLEL_UPDATES = 0
@dataclass
class DeviceBaseEntityDescriptionMixin:
"""Mixin for required Trafikverket Camera base description keys."""
value_fn: Callable[[CameraData], StateType | datetime]
@dataclass
class TVCameraSensorEntityDescription(
SensorEntityDescription, DeviceBaseEntityDescriptionMixin
):
"""Describes Trafikverket Camera sensor entity."""
SENSOR_TYPES: tuple[TVCameraSensorEntityDescription, ...] = (
TVCameraSensorEntityDescription(
key="direction",
translation_key="direction",
native_unit_of_measurement=DEGREE,
icon="mdi:sign-direction",
value_fn=lambda data: data.data.direction,
),
TVCameraSensorEntityDescription(
key="modified",
translation_key="modified",
icon="mdi:camera-retake-outline",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.data.modified,
entity_registry_enabled_default=False,
),
TVCameraSensorEntityDescription(
key="photo_time",
translation_key="photo_time",
icon="mdi:camera-timer",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.data.phototime,
),
TVCameraSensorEntityDescription(
key="photo_url",
translation_key="photo_url",
icon="mdi:camera-outline",
value_fn=lambda data: data.data.photourl,
entity_registry_enabled_default=False,
),
TVCameraSensorEntityDescription(
key="status",
translation_key="status",
icon="mdi:camera-outline",
value_fn=lambda data: data.data.status,
entity_registry_enabled_default=False,
),
TVCameraSensorEntityDescription(
key="camera_type",
translation_key="camera_type",
icon="mdi:camera-iris",
value_fn=lambda data: data.data.camera_type,
entity_registry_enabled_default=False,
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Trafikverket Camera sensor platform."""
coordinator: TVDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
TrafikverketCameraSensor(coordinator, entry.entry_id, entry.title, description)
for description in SENSOR_TYPES
)
class TrafikverketCameraSensor(
CoordinatorEntity[TVDataUpdateCoordinator], SensorEntity
):
"""Representation of a Trafikverket Camera Sensor."""
entity_description: TVCameraSensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
coordinator: TVDataUpdateCoordinator,
entry_id: str,
name: str,
entity_description: TVCameraSensorEntityDescription,
) -> None:
"""Initiate Trafikverket Camera Sensor."""
super().__init__(coordinator)
self.entity_description = entity_description
self._attr_unique_id = f"{entry_id}-{entity_description.key}"
self._attr_device_info = DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, entry_id)},
manufacturer="Trafikverket",
model="v1.0",
name=name,
configuration_url="https://api.trafikinfo.trafikverket.se/",
)
self._update_attr()
@callback
def _update_attr(self) -> None:
"""Update _attr."""
self._attr_native_value = self.entity_description.value_fn(
self.coordinator.data
)
@callback
def _handle_coordinator_update(self) -> None:
self._update_attr()
return super()._handle_coordinator_update()

View File

@ -46,6 +46,26 @@
} }
} }
} }
},
"sensor": {
"direction": {
"name": "Direction"
},
"modified": {
"name": "Modified"
},
"photo_time": {
"name": "Photo time"
},
"photo_url": {
"name": "Photo url"
},
"status": {
"name": "Status"
},
"camera_type": {
"name": "Camera type"
}
} }
} }
} }

View File

@ -16,6 +16,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker
async def test_exclude_attributes( async def test_exclude_attributes(
recorder_mock: Recorder, recorder_mock: Recorder,
entity_registry_enabled_by_default: None,
hass: HomeAssistant, hass: HomeAssistant,
load_int: ConfigEntry, load_int: ConfigEntry,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
@ -37,10 +38,12 @@ async def test_exclude_attributes(
None, None,
hass.states.async_entity_ids(), hass.states.async_entity_ids(),
) )
assert len(states) == 1 assert len(states) == 7
assert states.get("camera.test_location") assert states.get("camera.test_location")
for entity_states in states.values(): for entity_states in states.values():
for state in entity_states: for state in entity_states:
if state.entity_id == "camera.test_location":
assert "location" not in state.attributes assert "location" not in state.attributes
assert "description" not in state.attributes assert "description" not in state.attributes
assert "type" in state.attributes assert "type" in state.attributes
break

View File

@ -0,0 +1,29 @@
"""The test for the sensibo select platform."""
from __future__ import annotations
from pytrafikverket.trafikverket_camera import CameraInfo
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
async def test_sensor(
hass: HomeAssistant,
entity_registry_enabled_by_default: None,
load_int: ConfigEntry,
get_camera: CameraInfo,
) -> None:
"""Test the Trafikverket Camera sensor."""
state = hass.states.get("sensor.test_location_direction")
assert state.state == "180"
state = hass.states.get("sensor.test_location_modified")
assert state.state == "2022-04-04T04:04:04+00:00"
state = hass.states.get("sensor.test_location_photo_time")
assert state.state == "2022-04-04T04:04:04+00:00"
state = hass.states.get("sensor.test_location_photo_url")
assert state.state == "https://www.testurl.com/test_photo.jpg"
state = hass.states.get("sensor.test_location_status")
assert state.state == "Running"
state = hass.states.get("sensor.test_location_camera_type")
assert state.state == "Road"