Add camera entity in Fully Kiosk Browser (#119483)
parent
7f20173f6d
commit
6caf614efd
|
@ -13,6 +13,7 @@ from .services import async_setup_services
|
||||||
PLATFORMS = [
|
PLATFORMS = [
|
||||||
Platform.BINARY_SENSOR,
|
Platform.BINARY_SENSOR,
|
||||||
Platform.BUTTON,
|
Platform.BUTTON,
|
||||||
|
Platform.CAMERA,
|
||||||
Platform.MEDIA_PLAYER,
|
Platform.MEDIA_PLAYER,
|
||||||
Platform.NUMBER,
|
Platform.NUMBER,
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
"""Support for Fully Kiosk Browser camera."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.components.camera import Camera, CameraEntityFeature
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .coordinator import FullyKioskDataUpdateCoordinator
|
||||||
|
from .entity import FullyKioskEntity
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
|
) -> None:
|
||||||
|
"""Set up the cameras."""
|
||||||
|
coordinator: FullyKioskDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
async_add_entities([FullyCameraEntity(coordinator)])
|
||||||
|
|
||||||
|
|
||||||
|
class FullyCameraEntity(FullyKioskEntity, Camera):
|
||||||
|
"""Fully Kiosk Browser camera entity."""
|
||||||
|
|
||||||
|
_attr_name = None
|
||||||
|
_attr_supported_features = CameraEntityFeature.ON_OFF
|
||||||
|
|
||||||
|
def __init__(self, coordinator: FullyKioskDataUpdateCoordinator) -> None:
|
||||||
|
"""Initialize the camera."""
|
||||||
|
FullyKioskEntity.__init__(self, coordinator)
|
||||||
|
Camera.__init__(self)
|
||||||
|
self._attr_unique_id = f"{coordinator.data['deviceID']}-camera"
|
||||||
|
|
||||||
|
async def async_camera_image(
|
||||||
|
self, width: int | None = None, height: int | None = None
|
||||||
|
) -> bytes | None:
|
||||||
|
"""Return bytes of camera image."""
|
||||||
|
image_bytes: bytes = await self.coordinator.fully.getCamshot()
|
||||||
|
return image_bytes
|
||||||
|
|
||||||
|
async def async_turn_on(self) -> None:
|
||||||
|
"""Turn on camera."""
|
||||||
|
await self.coordinator.fully.enableMotionDetection()
|
||||||
|
await self.coordinator.async_refresh()
|
||||||
|
|
||||||
|
async def async_turn_off(self) -> None:
|
||||||
|
"""Turn off camera."""
|
||||||
|
await self.coordinator.fully.disableMotionDetection()
|
||||||
|
await self.coordinator.async_refresh()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_coordinator_update(self) -> None:
|
||||||
|
"""Handle updated data from the coordinator."""
|
||||||
|
self._attr_is_on = self.coordinator.data["settings"].get("motionDetection")
|
||||||
|
self.async_write_ha_state()
|
|
@ -0,0 +1,55 @@
|
||||||
|
"""Test the Fully Kiosk Browser camera platform."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.camera import async_get_image
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_camera(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
mock_fully_kiosk: MagicMock,
|
||||||
|
init_integration: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test the camera entity."""
|
||||||
|
entity_camera = "camera.amazon_fire"
|
||||||
|
entity = hass.states.get(entity_camera)
|
||||||
|
assert entity
|
||||||
|
assert entity.state == "idle"
|
||||||
|
entry = entity_registry.async_get(entity_camera)
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == "abcdef-123456-camera"
|
||||||
|
|
||||||
|
mock_fully_kiosk.getSettings.return_value = {"motionDetection": True}
|
||||||
|
await hass.services.async_call(
|
||||||
|
"camera",
|
||||||
|
"turn_on",
|
||||||
|
{"entity_id": entity_camera},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(mock_fully_kiosk.enableMotionDetection.mock_calls) == 1
|
||||||
|
|
||||||
|
mock_fully_kiosk.getCamshot.return_value = b"image_bytes"
|
||||||
|
image = await async_get_image(hass, entity_camera)
|
||||||
|
assert mock_fully_kiosk.getCamshot.call_count == 1
|
||||||
|
assert image.content == b"image_bytes"
|
||||||
|
|
||||||
|
mock_fully_kiosk.getSettings.return_value = {"motionDetection": False}
|
||||||
|
await hass.services.async_call(
|
||||||
|
"camera",
|
||||||
|
"turn_off",
|
||||||
|
{"entity_id": entity_camera},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(mock_fully_kiosk.disableMotionDetection.mock_calls) == 1
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError) as error:
|
||||||
|
await async_get_image(hass, entity_camera)
|
||||||
|
assert error.value.args[0] == "Camera is off"
|
|
@ -113,6 +113,8 @@ async def test_browse_media(
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"type": "media_player/browse_media",
|
"type": "media_player/browse_media",
|
||||||
|
"media_content_id": "media-source://media_source",
|
||||||
|
"media_content_type": "library",
|
||||||
"entity_id": "media_player.amazon_fire",
|
"entity_id": "media_player.amazon_fire",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue