Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,7 @@ omit =
homeassistant/components/reolink/camera.py
homeassistant/components/reolink/entity.py
homeassistant/components/reolink/host.py
homeassistant/components/reolink/light.py
homeassistant/components/reolink/number.py
homeassistant/components/reolink/update.py
homeassistant/components/repetier/__init__.py
Expand Down
8 changes: 7 additions & 1 deletion homeassistant/components/reolink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@

_LOGGER = logging.getLogger(__name__)

PLATFORMS = [Platform.BINARY_SENSOR, Platform.CAMERA, Platform.NUMBER, Platform.UPDATE]
PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.CAMERA,
Platform.LIGHT,
Platform.NUMBER,
Platform.UPDATE,
]
DEVICE_UPDATE_INTERVAL = timedelta(seconds=60)
FIRMWARE_UPDATE_INTERVAL = timedelta(hours=12)

Expand Down
154 changes: 154 additions & 0 deletions homeassistant/components/reolink/light.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
"""This component provides support for Reolink light entities."""
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import Any

from reolink_aio.api import Host

from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ColorMode,
LightEntity,
LightEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import ReolinkData
from .const import DOMAIN
from .entity import ReolinkCoordinatorEntity


@dataclass
class ReolinkLightEntityDescriptionMixin:
"""Mixin values for Reolink light entities."""

is_on: Callable[[Host, int | None], bool]
turn_on_off: Callable[[Host, int | None, bool], Any]


@dataclass
class ReolinkLightEntityDescription(
LightEntityDescription, ReolinkLightEntityDescriptionMixin
):
"""A class that describes light entities."""

supported: Callable[[Host, int | None], bool] = lambda api, ch: True
get_brightness: Callable[[Host, int | None], float] | None = None
Comment thread
starkillerOG marked this conversation as resolved.
Outdated
set_brightness: Callable[[Host, int | None, float], Any] | None = None


LIGHT_ENTITIES = (
ReolinkLightEntityDescription(
key="floodlight",
name="Floodlight",
icon="mdi:spotlight-beam",
supported=lambda api, ch: api.supported(ch, "floodLight"),
is_on=lambda api, ch: api.whiteled_state(ch),
turn_on_off=lambda api, ch, value: api.set_whiteled(ch, state=value),
get_brightness=lambda api, ch: api.whiteled_brightness(ch),
set_brightness=lambda api, ch, value: api.set_whiteled(
ch, brightness=int(value)
Comment thread
frenck marked this conversation as resolved.
Outdated
),
),
ReolinkLightEntityDescription(
key="ir_lights",
name="Infra red lights in night mode",
icon="mdi:led-off",
supported=lambda api, ch: api.supported(ch, "ir_lights"),
is_on=lambda api, ch: api.ir_enabled(ch),
turn_on_off=lambda api, ch, value: api.set_ir_lights(ch, value),
),
ReolinkLightEntityDescription(
Comment thread
starkillerOG marked this conversation as resolved.
key="status_led",
name="Status LED",
icon="mdi:lightning-bolt-circle",
supported=lambda api, ch: api.supported(ch, "status_led"),
is_on=lambda api, ch: api.status_led_enabled(ch),
turn_on_off=lambda api, ch, value: api.set_status_led(ch, value),
),
)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up a Reolink light entities."""
reolink_data: ReolinkData = hass.data[DOMAIN][config_entry.entry_id]

async_add_entities(
ReolinkLightEntity(reolink_data, channel, entity_description)
for entity_description in LIGHT_ENTITIES
for channel in reolink_data.host.api.channels
if entity_description.supported(reolink_data.host.api, channel)
)


class ReolinkLightEntity(ReolinkCoordinatorEntity, LightEntity):
"""Base light entity class for Reolink IP cameras."""

_attr_has_entity_name = True
entity_description: ReolinkLightEntityDescription

def __init__(
self,
reolink_data: ReolinkData,
channel: int,
Comment thread
starkillerOG marked this conversation as resolved.
entity_description: ReolinkLightEntityDescription,
) -> None:
"""Initialize Reolink light entity."""
super().__init__(reolink_data, channel)
self.entity_description = entity_description

self._attr_unique_id = (
f"{self._host.unique_id}_{self._channel}_{entity_description.key}"
Comment thread
starkillerOG marked this conversation as resolved.
Outdated
)

if self.entity_description.set_brightness is None:
self._attr_supported_color_modes = {ColorMode.ONOFF}
self._attr_color_mode = ColorMode.ONOFF
else:
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
self._attr_color_mode = ColorMode.BRIGHTNESS
Comment thread
starkillerOG marked this conversation as resolved.
Outdated

@property
def is_on(self) -> bool:
"""Return true if light is on."""
return self.entity_description.is_on(self._host.api, self._channel)

@property
def brightness(self) -> int | None:
"""Return the brightness of this light between 0.255."""
if self.entity_description.get_brightness is None:
return None

return round(
255
* (
self.entity_description.get_brightness(self._host.api, self._channel)
/ 100
Comment thread
starkillerOG marked this conversation as resolved.
Outdated
)
)

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn light off."""
await self.entity_description.turn_on_off(self._host.api, self._channel, False)
self.async_write_ha_state()

async def async_turn_on(self, **kwargs):
"""Turn light on."""
if (
brightness := kwargs.get(ATTR_BRIGHTNESS)
) is not None and self.entity_description.set_brightness is not None:
brightness_pct = int(brightness / 255.0 * 100)
await self.entity_description.set_brightness(
self._host.api, self._channel, brightness_pct
)

await self.entity_description.turn_on_off(self._host.api, self._channel, True)
self.async_write_ha_state()
Comment thread
starkillerOG marked this conversation as resolved.