mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add Shelly support for Plus WallDimmer US (#83385)
This commit is contained in:
parent
874315c3fc
commit
e1923bc13b
@ -109,10 +109,15 @@ def async_setup_rpc_entry(
|
|||||||
unique_id = f"{coordinator.mac}-switch:{id_}"
|
unique_id = f"{coordinator.mac}-switch:{id_}"
|
||||||
async_remove_shelly_entity(hass, "switch", unique_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
|
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):
|
class BlockShellyLight(ShellyBlockEntity, LightEntity):
|
||||||
@ -367,8 +372,8 @@ class BlockShellyLight(ShellyBlockEntity, LightEntity):
|
|||||||
super()._update_callback()
|
super()._update_callback()
|
||||||
|
|
||||||
|
|
||||||
class RpcShellyLight(ShellyRpcEntity, LightEntity):
|
class RpcShellySwitchAsLight(ShellyRpcEntity, LightEntity):
|
||||||
"""Entity that controls a light on RPC based Shelly devices."""
|
"""Entity that controls a relay as light on RPC based Shelly devices."""
|
||||||
|
|
||||||
_attr_color_mode = ColorMode.ONOFF
|
_attr_color_mode = ColorMode.ONOFF
|
||||||
_attr_supported_color_modes = {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:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn off light."""
|
"""Turn off light."""
|
||||||
await self.call_rpc("Switch.Set", {"id": self._id, "on": False})
|
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})
|
||||||
|
@ -298,7 +298,7 @@ def get_rpc_channel_name(device: RpcDevice, key: str) -> str:
|
|||||||
entity_name = device.config[key].get("name", device_name)
|
entity_name = device.config[key].get("name", device_name)
|
||||||
|
|
||||||
if entity_name is None:
|
if entity_name is None:
|
||||||
if key.startswith(("input:", "switch:")):
|
if key.startswith(("input:", "light:", "switch:")):
|
||||||
return f"{device_name} {key.replace(':', '_')}"
|
return f"{device_name} {key.replace(':', '_')}"
|
||||||
return device_name
|
return device_name
|
||||||
|
|
||||||
|
@ -124,6 +124,7 @@ MOCK_BLOCKS = [
|
|||||||
|
|
||||||
MOCK_CONFIG = {
|
MOCK_CONFIG = {
|
||||||
"input:0": {"id": 0, "type": "button"},
|
"input:0": {"id": 0, "type": "button"},
|
||||||
|
"light:0": {"name": "test light_0"},
|
||||||
"switch:0": {"name": "test switch_0"},
|
"switch:0": {"name": "test switch_0"},
|
||||||
"cover:0": {"name": "test cover_0"},
|
"cover:0": {"name": "test cover_0"},
|
||||||
"sys": {
|
"sys": {
|
||||||
@ -169,6 +170,7 @@ MOCK_STATUS_COAP = {
|
|||||||
|
|
||||||
MOCK_STATUS_RPC = {
|
MOCK_STATUS_RPC = {
|
||||||
"switch:0": {"output": True},
|
"switch:0": {"output": True},
|
||||||
|
"light:0": {"output": True, "brightness": 53.0},
|
||||||
"cloud": {"connected": False},
|
"cloud": {"connected": False},
|
||||||
"cover:0": {
|
"cover:0": {
|
||||||
"state": "stopped",
|
"state": "stopped",
|
||||||
|
@ -383,3 +383,60 @@ async def test_rpc_device_switch_type_lights_mode(hass, mock_rpc_device, monkeyp
|
|||||||
)
|
)
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
assert hass.states.get("light.test_switch_0").state == STATE_OFF
|
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user