Add Shelly support for Plus WallDimmer US (#83385)

This commit is contained in:
Shay Levy 2022-12-06 19:44:17 +02:00 committed by GitHub
parent 874315c3fc
commit e1923bc13b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 5 deletions

View File

@ -109,10 +109,15 @@ def async_setup_rpc_entry(
unique_id = f"{coordinator.mac}-switch:{id_}"
async_remove_shelly_entity(hass, "switch", unique_id)
if not switch_ids:
if switch_ids:
async_add_entities(
RpcShellySwitchAsLight(coordinator, id_) for id_ in switch_ids
)
return
async_add_entities(RpcShellyLight(coordinator, id_) for id_ in switch_ids)
light_key_ids = get_rpc_key_ids(coordinator.device.status, "light")
if light_key_ids:
async_add_entities(RpcShellyLight(coordinator, id_) for id_ in light_key_ids)
class BlockShellyLight(ShellyBlockEntity, LightEntity):
@ -367,8 +372,8 @@ class BlockShellyLight(ShellyBlockEntity, LightEntity):
super()._update_callback()
class RpcShellyLight(ShellyRpcEntity, LightEntity):
"""Entity that controls a light on RPC based Shelly devices."""
class RpcShellySwitchAsLight(ShellyRpcEntity, LightEntity):
"""Entity that controls a relay as light on RPC based Shelly devices."""
_attr_color_mode = ColorMode.ONOFF
_attr_supported_color_modes = {ColorMode.ONOFF}
@ -390,3 +395,39 @@ class RpcShellyLight(ShellyRpcEntity, LightEntity):
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off light."""
await self.call_rpc("Switch.Set", {"id": self._id, "on": False})
class RpcShellyLight(ShellyRpcEntity, LightEntity):
"""Entity that controls a light on RPC based Shelly devices."""
_attr_color_mode = ColorMode.BRIGHTNESS
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
def __init__(self, coordinator: ShellyRpcCoordinator, id_: int) -> None:
"""Initialize light."""
super().__init__(coordinator, f"light:{id_}")
self._id = id_
@property
def is_on(self) -> bool:
"""If light is on."""
return bool(self.coordinator.device.status[self.key]["output"])
@property
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
brightness_pct = self.coordinator.device.status[self.key]["brightness"]
return round(255 * brightness_pct / 100)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on light."""
params: dict[str, Any] = {"id": self._id, "on": True}
if ATTR_BRIGHTNESS in kwargs:
params["brightness"] = int(100 * (kwargs[ATTR_BRIGHTNESS] + 1) / 255)
await self.call_rpc("Light.Set", params)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off light."""
await self.call_rpc("Light.Set", {"id": self._id, "on": False})

View File

@ -298,7 +298,7 @@ def get_rpc_channel_name(device: RpcDevice, key: str) -> str:
entity_name = device.config[key].get("name", device_name)
if entity_name is None:
if key.startswith(("input:", "switch:")):
if key.startswith(("input:", "light:", "switch:")):
return f"{device_name} {key.replace(':', '_')}"
return device_name

View File

@ -124,6 +124,7 @@ MOCK_BLOCKS = [
MOCK_CONFIG = {
"input:0": {"id": 0, "type": "button"},
"light:0": {"name": "test light_0"},
"switch:0": {"name": "test switch_0"},
"cover:0": {"name": "test cover_0"},
"sys": {
@ -169,6 +170,7 @@ MOCK_STATUS_COAP = {
MOCK_STATUS_RPC = {
"switch:0": {"output": True},
"light:0": {"output": True, "brightness": 53.0},
"cloud": {"connected": False},
"cover:0": {
"state": "stopped",

View File

@ -383,3 +383,60 @@ async def test_rpc_device_switch_type_lights_mode(hass, mock_rpc_device, monkeyp
)
mock_rpc_device.mock_update()
assert hass.states.get("light.test_switch_0").state == STATE_OFF
async def test_rpc_light(hass, mock_rpc_device, monkeypatch):
"""Test RPC light."""
entity_id = f"{LIGHT_DOMAIN}.test_light_0"
monkeypatch.delitem(mock_rpc_device.status, "switch:0")
await init_integration(hass, 2)
# Turn on
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
mock_rpc_device.call_rpc.assert_called_once_with("Light.Set", {"id": 0, "on": True})
state = hass.states.get(entity_id)
assert state.state == STATE_ON
assert state.attributes[ATTR_BRIGHTNESS] == 135
# Turn off
mock_rpc_device.call_rpc.reset_mock()
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "light:0", "output", False)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
mock_rpc_device.mock_update()
mock_rpc_device.call_rpc.assert_called_once_with(
"Light.Set", {"id": 0, "on": False}
)
state = hass.states.get(entity_id)
assert state.state == STATE_OFF
# Turn on, brightness = 33
mock_rpc_device.call_rpc.reset_mock()
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 33},
blocking=True,
)
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "light:0", "output", True)
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "light:0", "brightness", 13)
mock_rpc_device.mock_update()
mock_rpc_device.call_rpc.assert_called_once_with(
"Light.Set", {"id": 0, "on": True, "brightness": 13}
)
state = hass.states.get(entity_id)
assert state.state == STATE_ON
assert state.attributes[ATTR_BRIGHTNESS] == 33