Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2125a41

Browse files
authored
Add zones support to Shelly Irrigation controller (home-assistant#152382)
1 parent 27516de commit 2125a41

File tree

4 files changed

+133
-6
lines changed

4 files changed

+133
-6
lines changed

‎homeassistant/components/shelly/switch.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class RpcSwitchDescription(RpcEntityDescription, SwitchEntityDescription):
165165
"boolean_zone0": RpcSwitchDescription(
166166
key="boolean",
167167
sub_key="value",
168+
entity_registry_enabled_default=False,
168169
is_on=lambda status: bool(status["value"]),
169170
method_on="boolean_set",
170171
method_off="boolean_set",
@@ -175,6 +176,7 @@ class RpcSwitchDescription(RpcEntityDescription, SwitchEntityDescription):
175176
"boolean_zone1": RpcSwitchDescription(
176177
key="boolean",
177178
sub_key="value",
179+
entity_registry_enabled_default=False,
178180
is_on=lambda status: bool(status["value"]),
179181
method_on="boolean_set",
180182
method_off="boolean_set",
@@ -185,6 +187,7 @@ class RpcSwitchDescription(RpcEntityDescription, SwitchEntityDescription):
185187
"boolean_zone2": RpcSwitchDescription(
186188
key="boolean",
187189
sub_key="value",
190+
entity_registry_enabled_default=False,
188191
is_on=lambda status: bool(status["value"]),
189192
method_on="boolean_set",
190193
method_off="boolean_set",
@@ -195,6 +198,7 @@ class RpcSwitchDescription(RpcEntityDescription, SwitchEntityDescription):
195198
"boolean_zone3": RpcSwitchDescription(
196199
key="boolean",
197200
sub_key="value",
201+
entity_registry_enabled_default=False,
198202
is_on=lambda status: bool(status["value"]),
199203
method_on="boolean_set",
200204
method_off="boolean_set",
@@ -205,6 +209,7 @@ class RpcSwitchDescription(RpcEntityDescription, SwitchEntityDescription):
205209
"boolean_zone4": RpcSwitchDescription(
206210
key="boolean",
207211
sub_key="value",
212+
entity_registry_enabled_default=False,
208213
is_on=lambda status: bool(status["value"]),
209214
method_on="boolean_set",
210215
method_off="boolean_set",
@@ -215,6 +220,7 @@ class RpcSwitchDescription(RpcEntityDescription, SwitchEntityDescription):
215220
"boolean_zone5": RpcSwitchDescription(
216221
key="boolean",
217222
sub_key="value",
223+
entity_registry_enabled_default=False,
218224
is_on=lambda status: bool(status["value"]),
219225
method_on="boolean_set",
220226
method_off="boolean_set",

‎homeassistant/components/shelly/utils.py‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,11 @@ def get_rpc_sub_device_name(
417417
"""Get name based on device and channel name."""
418418
if key in device.config and key != "em:0":
419419
# workaround for Pro 3EM, we don't want to get name for em:0
420+
if (zone_id := get_irrigation_zone_id(device.config, key)) is not None:
421+
# workaround for Irrigation controller, name stored in "service:0"
422+
if zone_name := device.config["service:0"]["zones"][zone_id]["name"]:
423+
return cast(str, zone_name)
424+
420425
if entity_name := device.config[key].get("name"):
421426
return cast(str, entity_name)
422427

@@ -787,6 +792,13 @@ async def get_rpc_scripts_event_types(
787792
return script_events
788793

789794

795+
def get_irrigation_zone_id(config: dict[str, Any], key: str) -> int | None:
796+
"""Return the zone id if the component is an irrigation zone."""
797+
if key in config and (zone := get_rpc_role_by_key(config, key)).startswith("zone"):
798+
return int(zone[4:])
799+
return None
800+
801+
790802
def get_rpc_device_info(
791803
device: RpcDevice,
792804
mac: str,
@@ -823,7 +835,10 @@ def get_rpc_device_info(
823835
)
824836

825837
if (
826-
component not in (*All_LIGHT_TYPES, "cover", "em1", "switch")
838+
(
839+
component not in (*All_LIGHT_TYPES, "cover", "em1", "switch")
840+
and get_irrigation_zone_id(device.config, key) is None
841+
)
827842
or idx is None
828843
or len(get_rpc_key_instances(device.status, component, all_lights=True)) < 2
829844
):

‎homeassistant/components/shelly/valve.py‎

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
from homeassistant.core import HomeAssistant, callback
1818
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
1919

20-
from .const import MODEL_FRANKEVER_WATER_VALVE, MODEL_NEO_WATER_VALVE
20+
from .const import (
21+
MODEL_FRANKEVER_IRRIGATION_CONTROLLER,
22+
MODEL_FRANKEVER_WATER_VALVE,
23+
MODEL_NEO_WATER_VALVE,
24+
)
2125
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
2226
from .entity import (
2327
BlockEntityDescription,
@@ -92,8 +96,8 @@ async def async_set_valve_position(self, position: int) -> None:
9296
await self.coordinator.device.number_set(self._id, position)
9397

9498

95-
class RpcShellyNeoWaterValve(RpcShellyBaseWaterValve):
96-
"""Entity that controls a valve on RPC Shelly NEO Water Valve."""
99+
class RpcShellySimpleWaterValve(RpcShellyBaseWaterValve):
100+
"""Entity that controls a valve on RPC Shelly Open/Close Water Valve."""
97101

98102
_attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE
99103
_attr_reports_position = False
@@ -124,9 +128,51 @@ async def async_close_valve(self, **kwargs: Any) -> None:
124128
key="boolean",
125129
sub_key="value",
126130
role="state",
127-
entity_class=RpcShellyNeoWaterValve,
131+
entity_class=RpcShellySimpleWaterValve,
128132
models={MODEL_NEO_WATER_VALVE},
129133
),
134+
"boolean_zone0": RpcValveDescription(
135+
key="boolean",
136+
sub_key="value",
137+
role="zone0",
138+
entity_class=RpcShellySimpleWaterValve,
139+
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
140+
),
141+
"boolean_zone1": RpcValveDescription(
142+
key="boolean",
143+
sub_key="value",
144+
role="zone1",
145+
entity_class=RpcShellySimpleWaterValve,
146+
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
147+
),
148+
"boolean_zone2": RpcValveDescription(
149+
key="boolean",
150+
sub_key="value",
151+
role="zone2",
152+
entity_class=RpcShellySimpleWaterValve,
153+
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
154+
),
155+
"boolean_zone3": RpcValveDescription(
156+
key="boolean",
157+
sub_key="value",
158+
role="zone3",
159+
entity_class=RpcShellySimpleWaterValve,
160+
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
161+
),
162+
"boolean_zone4": RpcValveDescription(
163+
key="boolean",
164+
sub_key="value",
165+
role="zone4",
166+
entity_class=RpcShellySimpleWaterValve,
167+
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
168+
),
169+
"boolean_zone5": RpcValveDescription(
170+
key="boolean",
171+
sub_key="value",
172+
role="zone5",
173+
entity_class=RpcShellySimpleWaterValve,
174+
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
175+
),
130176
}
131177

132178

‎tests/components/shelly/test_devices.py‎

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
import pytest
1313
from syrupy.assertion import SnapshotAssertion
1414

15-
from homeassistant.components.shelly.const import DOMAIN
15+
from homeassistant.components.shelly.const import (
16+
DOMAIN,
17+
MODEL_FRANKEVER_IRRIGATION_CONTROLLER,
18+
)
1619
from homeassistant.core import HomeAssistant
1720
from homeassistant.helpers.device_registry import DeviceRegistry
1821
from homeassistant.helpers.entity_registry import EntityRegistry
@@ -475,6 +478,63 @@ async def test_shelly_pro_3em_with_emeter_name(
475478
assert device_entry.name == "Test name Phase C"
476479

477480

481+
async def test_shelly_fk_06x_with_zone_names(
482+
hass: HomeAssistant,
483+
mock_rpc_device: Mock,
484+
entity_registry: EntityRegistry,
485+
device_registry: DeviceRegistry,
486+
monkeypatch: pytest.MonkeyPatch,
487+
) -> None:
488+
"""Test Shelly Irrigation controller FK-06X with zone names.
489+
490+
We should get the main device and 6 subdevices, one subdevice per one zone.
491+
"""
492+
device_fixture = await async_load_json_object_fixture(
493+
hass, "fk-06x_gen3_irrigation.json", DOMAIN
494+
)
495+
monkeypatch.setattr(mock_rpc_device, "shelly", device_fixture["shelly"])
496+
monkeypatch.setattr(mock_rpc_device, "status", device_fixture["status"])
497+
monkeypatch.setattr(mock_rpc_device, "config", device_fixture["config"])
498+
499+
await init_integration(hass, gen=3, model=MODEL_FRANKEVER_IRRIGATION_CONTROLLER)
500+
501+
# Main device
502+
entity_id = "sensor.test_name_average_temperature"
503+
504+
state = hass.states.get(entity_id)
505+
assert state
506+
507+
entry = entity_registry.async_get(entity_id)
508+
assert entry
509+
510+
device_entry = device_registry.async_get(entry.device_id)
511+
assert device_entry
512+
assert device_entry.name == "Test name"
513+
514+
# 3 zones with names, 3 with default names
515+
zone_names = [
516+
"Zone Name 1",
517+
"Zone Name 2",
518+
"Zone Name 3",
519+
"Zone 4",
520+
"Zone 5",
521+
"Zone 6",
522+
]
523+
524+
for zone_name in zone_names:
525+
entity_id = f"valve.{zone_name.lower().replace(' ', '_')}"
526+
527+
state = hass.states.get(entity_id)
528+
assert state
529+
530+
entry = entity_registry.async_get(entity_id)
531+
assert entry
532+
533+
device_entry = device_registry.async_get(entry.device_id)
534+
assert device_entry
535+
assert device_entry.name == zone_name
536+
537+
478538
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
479539
async def test_block_channel_with_name(
480540
hass: HomeAssistant,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /