1 """Select platform for Enphase Envoy solar energy monitor."""
3 from __future__
import annotations
5 from collections.abc
import Awaitable, Callable, Coroutine
6 from dataclasses
import dataclass
9 from pyenphase
import Envoy, EnvoyDryContactSettings
10 from pyenphase.const
import SupportedFeatures
11 from pyenphase.models.dry_contacts
import DryContactAction, DryContactMode
12 from pyenphase.models.tariff
import EnvoyStorageMode, EnvoyStorageSettings
19 from .const
import DOMAIN
20 from .coordinator
import EnphaseConfigEntry, EnphaseUpdateCoordinator
21 from .entity
import EnvoyBaseEntity
24 @dataclass(frozen=True, kw_only=True)
26 """Describes an Envoy Dry Contact Relay select entity."""
28 value_fn: Callable[[EnvoyDryContactSettings], str]
30 [Envoy, EnvoyDryContactSettings, str], Coroutine[Any, Any, dict[str, Any]]
34 @dataclass(frozen=True, kw_only=True)
36 """Describes an Envoy storage settings select entity."""
38 value_fn: Callable[[EnvoyStorageSettings], str]
39 update_fn: Callable[[Envoy, str], Awaitable[dict[str, Any]]]
43 DryContactMode.MANUAL:
"standard",
44 DryContactMode.STATE_OF_CHARGE:
"battery",
46 REVERSE_RELAY_MODE_MAP = {v: k
for k, v
in RELAY_MODE_MAP.items()}
48 DryContactAction.APPLY:
"powered",
49 DryContactAction.SHED:
"not_powered",
50 DryContactAction.SCHEDULE:
"schedule",
51 DryContactAction.NONE:
"none",
53 REVERSE_RELAY_ACTION_MAP = {v: k
for k, v
in RELAY_ACTION_MAP.items()}
54 MODE_OPTIONS =
list(REVERSE_RELAY_MODE_MAP)
55 ACTION_OPTIONS =
list(REVERSE_RELAY_ACTION_MAP)
58 EnvoyStorageMode.BACKUP:
"backup",
59 EnvoyStorageMode.SELF_CONSUMPTION:
"self_consumption",
60 EnvoyStorageMode.SAVINGS:
"savings",
62 REVERSE_STORAGE_MODE_MAP = {v: k
for k, v
in STORAGE_MODE_MAP.items()}
63 STORAGE_MODE_OPTIONS =
list(REVERSE_STORAGE_MODE_MAP)
68 translation_key=
"relay_mode",
70 value_fn=
lambda relay: RELAY_MODE_MAP[relay.mode],
71 update_fn=
lambda envoy, relay, value: envoy.update_dry_contact(
74 "mode": REVERSE_RELAY_MODE_MAP[value],
80 translation_key=
"relay_grid_action",
81 options=ACTION_OPTIONS,
82 value_fn=
lambda relay: RELAY_ACTION_MAP[relay.grid_action],
83 update_fn=
lambda envoy, relay, value: envoy.update_dry_contact(
86 "grid_action": REVERSE_RELAY_ACTION_MAP[value],
91 key=
"microgrid_action",
92 translation_key=
"relay_microgrid_action",
93 options=ACTION_OPTIONS,
94 value_fn=
lambda relay: RELAY_ACTION_MAP[relay.micro_grid_action],
95 update_fn=
lambda envoy, relay, value: envoy.update_dry_contact(
98 "micro_grid_action": REVERSE_RELAY_ACTION_MAP[value],
103 key=
"generator_action",
104 translation_key=
"relay_generator_action",
105 options=ACTION_OPTIONS,
106 value_fn=
lambda relay: RELAY_ACTION_MAP[relay.generator_action],
107 update_fn=
lambda envoy, relay, value: envoy.update_dry_contact(
110 "generator_action": REVERSE_RELAY_ACTION_MAP[value],
117 translation_key=
"storage_mode",
118 options=STORAGE_MODE_OPTIONS,
119 value_fn=
lambda storage_settings: STORAGE_MODE_MAP[storage_settings.mode],
120 update_fn=
lambda envoy, value: envoy.set_storage_mode(
121 REVERSE_STORAGE_MODE_MAP[value]
128 config_entry: EnphaseConfigEntry,
129 async_add_entities: AddEntitiesCallback,
131 """Set up Enphase Envoy select platform."""
132 coordinator = config_entry.runtime_data
133 envoy_data = coordinator.envoy.data
134 assert envoy_data
is not None
135 entities: list[SelectEntity] = []
136 if envoy_data.dry_contact_settings:
139 for entity
in RELAY_ENTITIES
140 for relay
in envoy_data.dry_contact_settings
144 and envoy_data.tariff.storage_settings
145 and coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE
154 """Representation of an Enphase Enpower select entity."""
156 entity_description: EnvoyRelaySelectEntityDescription
160 coordinator: EnphaseUpdateCoordinator,
161 description: EnvoyRelaySelectEntityDescription,
164 """Initialize the Enphase relay select entity."""
165 super().
__init__(coordinator, description)
168 assert enpower
is not None
169 serial_number = enpower.serial_number
171 self.
_attr_unique_id_attr_unique_id = f
"{serial_number}_relay_{relay_id}_{description.key}"
173 identifiers={(DOMAIN, relay_id)},
174 manufacturer=
"Enphase",
175 model=
"Dry contact relay",
176 name=self.
relayrelay.load_name,
177 sw_version=
str(enpower.firmware_version),
178 via_device=(DOMAIN, serial_number),
182 def relay(self) -> EnvoyDryContactSettings:
183 """Return the relay object."""
188 """Return the state of the Enpower switch."""
192 """Update the relay."""
198 """Representation of an Enphase storage settings select entity."""
200 entity_description: EnvoyStorageSettingsSelectEntityDescription
204 coordinator: EnphaseUpdateCoordinator,
205 description: EnvoyStorageSettingsSelectEntityDescription,
207 """Initialize the Enphase storage settings select entity."""
208 super().
__init__(coordinator, description)
210 assert coordinator.envoy.data
is not None
211 if enpower := coordinator.envoy.data.enpower:
216 manufacturer=
"Enphase",
218 name=f
"Enpower {self._serial_number}",
219 sw_version=
str(enpower.firmware_version),
224 self.
_attr_unique_id_attr_unique_id = f
"{self.envoy_serial_num}_{description.key}"
227 manufacturer=
"Enphase",
228 model=coordinator.envoy.envoy_model,
229 name=coordinator.name,
230 sw_version=
str(coordinator.envoy.firmware),
231 hw_version=coordinator.envoy.part_number,
237 """Return the state of the select entity."""
238 assert self.
datadatadata.tariff
is not None
239 assert self.
datadatadata.tariff.storage_settings
is not None
243 """Update the relay."""
None __init__(self, EnphaseUpdateCoordinator coordinator, EnvoyRelaySelectEntityDescription description, str relay_id)
EnvoyDryContactSettings relay(self)
None async_select_option(self, str option)
None async_select_option(self, str option)
None __init__(self, EnphaseUpdateCoordinator coordinator, EnvoyStorageSettingsSelectEntityDescription description)
None async_request_refresh(self)
None async_setup_entry(HomeAssistant hass, EnphaseConfigEntry config_entry, AddEntitiesCallback async_add_entities)