Add power sensor to WiZ (#73260)
This commit is contained in:
parent
5863d57e73
commit
a9ab98fb45
8 changed files with 95 additions and 11 deletions
|
@ -1,4 +1,6 @@
|
|||
"""WiZ Platform integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
@ -80,10 +82,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
"Found bulb {bulb.mac} at {ip_address}, expected {entry.unique_id}"
|
||||
)
|
||||
|
||||
async def _async_update() -> None:
|
||||
async def _async_update() -> float | None:
|
||||
"""Update the WiZ device."""
|
||||
try:
|
||||
await bulb.updateState()
|
||||
if bulb.power_monitoring is not False:
|
||||
power: float | None = await bulb.get_power()
|
||||
return power
|
||||
return None
|
||||
except WIZ_EXCEPTIONS as ex:
|
||||
raise UpdateFailed(f"Failed to update device at {ip_address}: {ex}") from ex
|
||||
|
||||
|
@ -117,7 +123,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
def _async_push_update(state: PilotParser) -> None:
|
||||
"""Receive a push update."""
|
||||
_LOGGER.debug("%s: Got push update: %s", bulb.mac, state.pilotResult)
|
||||
coordinator.async_set_updated_data(None)
|
||||
coordinator.async_set_updated_data(coordinator.data)
|
||||
if state.get_source() == PIR_SOURCE:
|
||||
async_dispatcher_send(hass, SIGNAL_WIZ_PIR.format(bulb.mac))
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from abc import abstractmethod
|
||||
from typing import Any
|
||||
from typing import Any, Optional
|
||||
|
||||
from pywizlight.bulblibrary import BulbType
|
||||
|
||||
|
@ -10,12 +10,15 @@ from homeassistant.const import ATTR_HW_VERSION, ATTR_MODEL
|
|||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity, ToggleEntity
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
)
|
||||
|
||||
from .models import WizData
|
||||
|
||||
|
||||
class WizEntity(CoordinatorEntity, Entity):
|
||||
class WizEntity(CoordinatorEntity[DataUpdateCoordinator[Optional[float]]], Entity):
|
||||
"""Representation of WiZ entity."""
|
||||
|
||||
def __init__(self, wiz_data: WizData, name: str) -> None:
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": ["network"],
|
||||
"quality_scale": "platinum",
|
||||
"documentation": "https://www.home-assistant.io/integrations/wiz",
|
||||
"requirements": ["pywizlight==0.5.13"],
|
||||
"requirements": ["pywizlight==0.5.14"],
|
||||
"iot_class": "local_push",
|
||||
"codeowners": ["@sbidy"]
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ from homeassistant.components.sensor import (
|
|||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import SIGNAL_STRENGTH_DECIBELS_MILLIWATT
|
||||
from homeassistant.const import POWER_WATT, SIGNAL_STRENGTH_DECIBELS_MILLIWATT
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
@ -30,6 +30,17 @@ SENSORS: tuple[SensorEntityDescription, ...] = (
|
|||
)
|
||||
|
||||
|
||||
POWER_SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="power",
|
||||
name="Current Power",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.POWER,
|
||||
native_unit_of_measurement=POWER_WATT,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
|
@ -37,9 +48,17 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up the wiz sensor."""
|
||||
wiz_data: WizData = hass.data[DOMAIN][entry.entry_id]
|
||||
async_add_entities(
|
||||
entities = [
|
||||
WizSensor(wiz_data, entry.title, description) for description in SENSORS
|
||||
)
|
||||
]
|
||||
if wiz_data.coordinator.data is not None:
|
||||
entities.extend(
|
||||
[
|
||||
WizPowerSensor(wiz_data, entry.title, description)
|
||||
for description in POWER_SENSORS
|
||||
]
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class WizSensor(WizEntity, SensorEntity):
|
||||
|
@ -63,3 +82,16 @@ class WizSensor(WizEntity, SensorEntity):
|
|||
self._attr_native_value = self._device.state.pilotResult.get(
|
||||
self.entity_description.key
|
||||
)
|
||||
|
||||
|
||||
class WizPowerSensor(WizSensor):
|
||||
"""Defines a WiZ power sensor."""
|
||||
|
||||
@callback
|
||||
def _async_update_attrs(self) -> None:
|
||||
"""Handle updating _attr values."""
|
||||
# Newer firmwares will have the power in their state
|
||||
watts_push = self._device.state.get_power()
|
||||
# Older firmwares will be polled and in the coordinator data
|
||||
watts_poll = self.coordinator.data
|
||||
self._attr_native_value = watts_poll if watts_push is None else watts_push
|
||||
|
|
|
@ -2029,7 +2029,7 @@ pywemo==0.9.1
|
|||
pywilight==0.0.70
|
||||
|
||||
# homeassistant.components.wiz
|
||||
pywizlight==0.5.13
|
||||
pywizlight==0.5.14
|
||||
|
||||
# homeassistant.components.ws66i
|
||||
pyws66i==1.1
|
||||
|
|
|
@ -1349,7 +1349,7 @@ pywemo==0.9.1
|
|||
pywilight==0.0.70
|
||||
|
||||
# homeassistant.components.wiz
|
||||
pywizlight==0.5.13
|
||||
pywizlight==0.5.14
|
||||
|
||||
# homeassistant.components.ws66i
|
||||
pyws66i==1.1
|
||||
|
|
|
@ -150,6 +150,17 @@ FAKE_SOCKET = BulbType(
|
|||
white_channels=2,
|
||||
white_to_color_ratio=80,
|
||||
)
|
||||
FAKE_SOCKET_WITH_POWER_MONITORING = BulbType(
|
||||
bulb_type=BulbClass.SOCKET,
|
||||
name="ESP25_SOCKET_01",
|
||||
features=Features(
|
||||
color=False, color_tmp=False, effect=False, brightness=False, dual_head=False
|
||||
),
|
||||
kelvin_range=KelvinRange(2700, 6500),
|
||||
fw_version="1.26.2",
|
||||
white_channels=2,
|
||||
white_to_color_ratio=80,
|
||||
)
|
||||
FAKE_OLD_FIRMWARE_DIMMABLE_BULB = BulbType(
|
||||
bulb_type=BulbClass.DW,
|
||||
name=None,
|
||||
|
@ -197,7 +208,9 @@ def _mocked_wizlight(device, extended_white_range, bulb_type) -> wizlight:
|
|||
)
|
||||
bulb.getMac = AsyncMock(return_value=FAKE_MAC)
|
||||
bulb.turn_on = AsyncMock()
|
||||
bulb.get_power = AsyncMock(return_value=None)
|
||||
bulb.turn_off = AsyncMock()
|
||||
bulb.power_monitoring = False
|
||||
bulb.updateState = AsyncMock(return_value=FAKE_STATE)
|
||||
bulb.getSupportedScenes = AsyncMock(return_value=list(SCENES.values()))
|
||||
bulb.start_push = AsyncMock(side_effect=_save_setup_callback)
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
"""Tests for the sensor platform."""
|
||||
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import (
|
||||
FAKE_DUAL_HEAD_RGBWW_BULB,
|
||||
FAKE_MAC,
|
||||
FAKE_SOCKET_WITH_POWER_MONITORING,
|
||||
_mocked_wizlight,
|
||||
_patch_discovery,
|
||||
_patch_wizlight,
|
||||
async_push_update,
|
||||
|
@ -35,3 +39,29 @@ async def test_signal_strength(hass: HomeAssistant) -> None:
|
|||
|
||||
await async_push_update(hass, bulb, {"mac": FAKE_MAC, "rssi": -50})
|
||||
assert hass.states.get(entity_id).state == "-50"
|
||||
|
||||
|
||||
async def test_power_monitoring(hass: HomeAssistant) -> None:
|
||||
"""Test power monitoring."""
|
||||
socket = _mocked_wizlight(None, None, FAKE_SOCKET_WITH_POWER_MONITORING)
|
||||
socket.power_monitoring = None
|
||||
socket.get_power = AsyncMock(return_value=5.123)
|
||||
_, entry = await async_setup_integration(
|
||||
hass, wizlight=socket, bulb_type=FAKE_SOCKET_WITH_POWER_MONITORING
|
||||
)
|
||||
entity_id = "sensor.mock_title_current_power"
|
||||
entity_registry = er.async_get(hass)
|
||||
reg_entry = entity_registry.async_get(entity_id)
|
||||
assert reg_entry.unique_id == f"{FAKE_MAC}_power"
|
||||
updated_entity = entity_registry.async_update_entity(
|
||||
entity_id=entity_id, disabled_by=None
|
||||
)
|
||||
assert not updated_entity.disabled
|
||||
|
||||
with _patch_discovery(), _patch_wizlight(device=socket):
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(entity_id).state == "5.123"
|
||||
await async_push_update(hass, socket, {"mac": FAKE_MAC, "pc": 800})
|
||||
assert hass.states.get(entity_id).state == "0.8"
|
||||
|
|
Loading…
Add table
Reference in a new issue