mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Add storage settings for enphase_envoy batteries without enpower device (#125527)
* Add battery storage settings for enphase_envoy EU configuration * Add EU Battery test fixture to enphase_envoy * Add tests and snapshots for enphase_envoy EU battery * refactor eu battery fixture to align with other enphase_envoy fixtures * remove if from test and use test parameter for eu battery enphase_envoy tests
This commit is contained in:
parent
356bca119d
commit
3c1860cca2
@ -88,7 +88,6 @@ async def async_setup_entry(
|
|||||||
envoy_data.tariff
|
envoy_data.tariff
|
||||||
and envoy_data.tariff.storage_settings
|
and envoy_data.tariff.storage_settings
|
||||||
and coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE
|
and coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE
|
||||||
and coordinator.envoy.supported_features & SupportedFeatures.ENPOWER
|
|
||||||
):
|
):
|
||||||
entities.append(
|
entities.append(
|
||||||
EnvoyStorageSettingsNumberEntity(coordinator, STORAGE_RESERVE_SOC_ENTITY)
|
EnvoyStorageSettingsNumberEntity(coordinator, STORAGE_RESERVE_SOC_ENTITY)
|
||||||
@ -152,8 +151,8 @@ class EnvoyStorageSettingsNumberEntity(EnvoyBaseEntity, NumberEntity):
|
|||||||
"""Initialize the Enphase relay number entity."""
|
"""Initialize the Enphase relay number entity."""
|
||||||
super().__init__(coordinator, description)
|
super().__init__(coordinator, description)
|
||||||
self.envoy = coordinator.envoy
|
self.envoy = coordinator.envoy
|
||||||
assert self.data.enpower is not None
|
assert self.data is not None
|
||||||
enpower = self.data.enpower
|
if enpower := self.data.enpower:
|
||||||
self._serial_number = enpower.serial_number
|
self._serial_number = enpower.serial_number
|
||||||
self._attr_unique_id = f"{self._serial_number}_{description.key}"
|
self._attr_unique_id = f"{self._serial_number}_{description.key}"
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
@ -164,6 +163,18 @@ class EnvoyStorageSettingsNumberEntity(EnvoyBaseEntity, NumberEntity):
|
|||||||
sw_version=str(enpower.firmware_version),
|
sw_version=str(enpower.firmware_version),
|
||||||
via_device=(DOMAIN, self.envoy_serial_num),
|
via_device=(DOMAIN, self.envoy_serial_num),
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# If no enpower device assign numbers to Envoy itself
|
||||||
|
self._attr_unique_id = f"{self.envoy_serial_num}_{description.key}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, self.envoy_serial_num)},
|
||||||
|
manufacturer="Enphase",
|
||||||
|
model=coordinator.envoy.envoy_model,
|
||||||
|
name=coordinator.name,
|
||||||
|
sw_version=str(coordinator.envoy.firmware),
|
||||||
|
hw_version=coordinator.envoy.part_number,
|
||||||
|
serial_number=self.envoy_serial_num,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> float:
|
def native_value(self) -> float:
|
||||||
|
@ -143,7 +143,6 @@ async def async_setup_entry(
|
|||||||
envoy_data.tariff
|
envoy_data.tariff
|
||||||
and envoy_data.tariff.storage_settings
|
and envoy_data.tariff.storage_settings
|
||||||
and coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE
|
and coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE
|
||||||
and coordinator.envoy.supported_features & SupportedFeatures.ENPOWER
|
|
||||||
):
|
):
|
||||||
entities.append(
|
entities.append(
|
||||||
EnvoyStorageSettingsSelectEntity(coordinator, STORAGE_MODE_ENTITY)
|
EnvoyStorageSettingsSelectEntity(coordinator, STORAGE_MODE_ENTITY)
|
||||||
@ -209,8 +208,7 @@ class EnvoyStorageSettingsSelectEntity(EnvoyBaseEntity, SelectEntity):
|
|||||||
super().__init__(coordinator, description)
|
super().__init__(coordinator, description)
|
||||||
self.envoy = coordinator.envoy
|
self.envoy = coordinator.envoy
|
||||||
assert coordinator.envoy.data is not None
|
assert coordinator.envoy.data is not None
|
||||||
assert coordinator.envoy.data.enpower is not None
|
if enpower := coordinator.envoy.data.enpower:
|
||||||
enpower = coordinator.envoy.data.enpower
|
|
||||||
self._serial_number = enpower.serial_number
|
self._serial_number = enpower.serial_number
|
||||||
self._attr_unique_id = f"{self._serial_number}_{description.key}"
|
self._attr_unique_id = f"{self._serial_number}_{description.key}"
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
@ -221,6 +219,18 @@ class EnvoyStorageSettingsSelectEntity(EnvoyBaseEntity, SelectEntity):
|
|||||||
sw_version=str(enpower.firmware_version),
|
sw_version=str(enpower.firmware_version),
|
||||||
via_device=(DOMAIN, self.envoy_serial_num),
|
via_device=(DOMAIN, self.envoy_serial_num),
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# If no enpower device assign selects to Envoy itself
|
||||||
|
self._attr_unique_id = f"{self.envoy_serial_num}_{description.key}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, self.envoy_serial_num)},
|
||||||
|
manufacturer="Enphase",
|
||||||
|
model=coordinator.envoy.envoy_model,
|
||||||
|
name=coordinator.name,
|
||||||
|
sw_version=str(coordinator.envoy.firmware),
|
||||||
|
hw_version=coordinator.envoy.part_number,
|
||||||
|
serial_number=self.envoy_serial_num,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_option(self) -> str:
|
def current_option(self) -> str:
|
||||||
|
@ -98,8 +98,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
envoy_data.enpower
|
envoy_data.tariff
|
||||||
and envoy_data.tariff
|
|
||||||
and envoy_data.tariff.storage_settings
|
and envoy_data.tariff.storage_settings
|
||||||
and (coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE)
|
and (coordinator.envoy.supported_features & SupportedFeatures.ENCHARGE)
|
||||||
):
|
):
|
||||||
@ -213,12 +212,13 @@ class EnvoyStorageSettingsSwitchEntity(EnvoyBaseEntity, SwitchEntity):
|
|||||||
self,
|
self,
|
||||||
coordinator: EnphaseUpdateCoordinator,
|
coordinator: EnphaseUpdateCoordinator,
|
||||||
description: EnvoyStorageSettingsSwitchEntityDescription,
|
description: EnvoyStorageSettingsSwitchEntityDescription,
|
||||||
enpower: EnvoyEnpower,
|
enpower: EnvoyEnpower | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the Enphase storage settings switch entity."""
|
"""Initialize the Enphase storage settings switch entity."""
|
||||||
super().__init__(coordinator, description)
|
super().__init__(coordinator, description)
|
||||||
self.envoy = coordinator.envoy
|
self.envoy = coordinator.envoy
|
||||||
self.enpower = enpower
|
self.enpower = enpower
|
||||||
|
if enpower:
|
||||||
self._serial_number = enpower.serial_number
|
self._serial_number = enpower.serial_number
|
||||||
self._attr_unique_id = f"{self._serial_number}_{description.key}"
|
self._attr_unique_id = f"{self._serial_number}_{description.key}"
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
@ -229,6 +229,18 @@ class EnvoyStorageSettingsSwitchEntity(EnvoyBaseEntity, SwitchEntity):
|
|||||||
sw_version=str(enpower.firmware_version),
|
sw_version=str(enpower.firmware_version),
|
||||||
via_device=(DOMAIN, self.envoy_serial_num),
|
via_device=(DOMAIN, self.envoy_serial_num),
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# If no enpower device assign switches to Envoy itself
|
||||||
|
self._attr_unique_id = f"{self.envoy_serial_num}_{description.key}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, self.envoy_serial_num)},
|
||||||
|
manufacturer="Enphase",
|
||||||
|
model=coordinator.envoy.envoy_model,
|
||||||
|
name=coordinator.name,
|
||||||
|
sw_version=str(coordinator.envoy.firmware),
|
||||||
|
hw_version=coordinator.envoy.part_number,
|
||||||
|
serial_number=self.envoy_serial_num,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
|
262
tests/components/enphase_envoy/fixtures/envoy_eu_batt.json
Normal file
262
tests/components/enphase_envoy/fixtures/envoy_eu_batt.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"serial_number": "1234",
|
||||||
|
"firmware": "7.6.358",
|
||||||
|
"part_number": "800-00654-r08",
|
||||||
|
"envoy_model": "Envoy, phases: 3, phase mode: three, net-consumption CT, production CT",
|
||||||
|
"supported_features": 1759,
|
||||||
|
"phase_mode": "three",
|
||||||
|
"phase_count": 3,
|
||||||
|
"active_phase_count": 0,
|
||||||
|
"ct_meter_count": 2,
|
||||||
|
"consumption_meter_type": "net-consumption",
|
||||||
|
"production_meter_type": "production",
|
||||||
|
"storage_meter_type": null,
|
||||||
|
"data": {
|
||||||
|
"encharge_inventory": {
|
||||||
|
"123456": {
|
||||||
|
"admin_state": 6,
|
||||||
|
"admin_state_str": "ENCHG_STATE_READY",
|
||||||
|
"bmu_firmware_version": "2.1.16",
|
||||||
|
"comm_level_2_4_ghz": 4,
|
||||||
|
"comm_level_sub_ghz": 4,
|
||||||
|
"communicating": true,
|
||||||
|
"dc_switch_off": false,
|
||||||
|
"encharge_capacity": 3500,
|
||||||
|
"encharge_revision": 2,
|
||||||
|
"firmware_loaded_date": 1714736645,
|
||||||
|
"firmware_version": "2.6.6618_rel/22.11",
|
||||||
|
"installed_date": 1714736645,
|
||||||
|
"last_report_date": 1714804173,
|
||||||
|
"led_status": 17,
|
||||||
|
"max_cell_temp": 16,
|
||||||
|
"operating": true,
|
||||||
|
"part_number": "830-01760-r46",
|
||||||
|
"percent_full": 4,
|
||||||
|
"serial_number": "122327081322",
|
||||||
|
"temperature": 16,
|
||||||
|
"temperature_unit": "C",
|
||||||
|
"zigbee_dongle_fw_version": "100F"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"encharge_power": {
|
||||||
|
"123456": {
|
||||||
|
"apparent_power_mva": 0,
|
||||||
|
"real_power_mw": 0,
|
||||||
|
"soc": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"encharge_aggregate": {
|
||||||
|
"available_energy": 140,
|
||||||
|
"backup_reserve": 0,
|
||||||
|
"state_of_charge": 4,
|
||||||
|
"reserve_state_of_charge": 0,
|
||||||
|
"configured_reserve_state_of_charge": 0,
|
||||||
|
"max_available_capacity": 3500
|
||||||
|
},
|
||||||
|
"enpower": null,
|
||||||
|
"system_consumption": {
|
||||||
|
"watt_hours_lifetime": 1234,
|
||||||
|
"watt_hours_last_7_days": 1234,
|
||||||
|
"watt_hours_today": 1234,
|
||||||
|
"watts_now": 1234
|
||||||
|
},
|
||||||
|
"system_production": {
|
||||||
|
"watt_hours_lifetime": 1234,
|
||||||
|
"watt_hours_last_7_days": 1234,
|
||||||
|
"watt_hours_today": 1234,
|
||||||
|
"watts_now": 1234
|
||||||
|
},
|
||||||
|
"system_consumption_phases": null,
|
||||||
|
"system_production_phases": null,
|
||||||
|
"system_net_consumption": {
|
||||||
|
"watt_hours_lifetime": 4321,
|
||||||
|
"watt_hours_last_7_days": -1,
|
||||||
|
"watt_hours_today": -1,
|
||||||
|
"watts_now": 2341
|
||||||
|
},
|
||||||
|
"system_net_consumption_phases": null,
|
||||||
|
"ctmeter_production": {
|
||||||
|
"eid": "100000010",
|
||||||
|
"timestamp": 1708006110,
|
||||||
|
"energy_delivered": 11234,
|
||||||
|
"energy_received": 12345,
|
||||||
|
"active_power": 100,
|
||||||
|
"power_factor": 0.11,
|
||||||
|
"voltage": 111,
|
||||||
|
"current": 0.2,
|
||||||
|
"frequency": 50.1,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "production",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": ["production-imbalance", "power-on-unused-phase"]
|
||||||
|
},
|
||||||
|
"ctmeter_consumption": {
|
||||||
|
"eid": "100000020",
|
||||||
|
"timestamp": 1708006120,
|
||||||
|
"energy_delivered": 21234,
|
||||||
|
"energy_received": 22345,
|
||||||
|
"active_power": 101,
|
||||||
|
"power_factor": 0.21,
|
||||||
|
"voltage": 112,
|
||||||
|
"current": 0.3,
|
||||||
|
"frequency": 50.2,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "net-consumption",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": []
|
||||||
|
},
|
||||||
|
"ctmeter_storage": null,
|
||||||
|
"ctmeter_production_phases": {
|
||||||
|
"L1": {
|
||||||
|
"eid": "100000011",
|
||||||
|
"timestamp": 1708006111,
|
||||||
|
"energy_delivered": 112341,
|
||||||
|
"energy_received": 123451,
|
||||||
|
"active_power": 20,
|
||||||
|
"power_factor": 0.12,
|
||||||
|
"voltage": 111,
|
||||||
|
"current": 0.2,
|
||||||
|
"frequency": 50.1,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "production",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": ["production-imbalance"]
|
||||||
|
},
|
||||||
|
"L2": {
|
||||||
|
"eid": "100000012",
|
||||||
|
"timestamp": 1708006112,
|
||||||
|
"energy_delivered": 112342,
|
||||||
|
"energy_received": 123452,
|
||||||
|
"active_power": 30,
|
||||||
|
"power_factor": 0.13,
|
||||||
|
"voltage": 111,
|
||||||
|
"current": 0.2,
|
||||||
|
"frequency": 50.1,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "production",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": ["power-on-unused-phase"]
|
||||||
|
},
|
||||||
|
"L3": {
|
||||||
|
"eid": "100000013",
|
||||||
|
"timestamp": 1708006113,
|
||||||
|
"energy_delivered": 112343,
|
||||||
|
"energy_received": 123453,
|
||||||
|
"active_power": 50,
|
||||||
|
"power_factor": 0.14,
|
||||||
|
"voltage": 111,
|
||||||
|
"current": 0.2,
|
||||||
|
"frequency": 50.1,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "production",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ctmeter_consumption_phases": {
|
||||||
|
"L1": {
|
||||||
|
"eid": "100000021",
|
||||||
|
"timestamp": 1708006121,
|
||||||
|
"energy_delivered": 212341,
|
||||||
|
"energy_received": 223451,
|
||||||
|
"active_power": 21,
|
||||||
|
"power_factor": 0.22,
|
||||||
|
"voltage": 112,
|
||||||
|
"current": 0.3,
|
||||||
|
"frequency": 50.2,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "net-consumption",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": []
|
||||||
|
},
|
||||||
|
"L2": {
|
||||||
|
"eid": "100000022",
|
||||||
|
"timestamp": 1708006122,
|
||||||
|
"energy_delivered": 212342,
|
||||||
|
"energy_received": 223452,
|
||||||
|
"active_power": 31,
|
||||||
|
"power_factor": 0.23,
|
||||||
|
"voltage": 112,
|
||||||
|
"current": 0.3,
|
||||||
|
"frequency": 50.2,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "net-consumption",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": []
|
||||||
|
},
|
||||||
|
"L3": {
|
||||||
|
"eid": "100000023",
|
||||||
|
"timestamp": 1708006123,
|
||||||
|
"energy_delivered": 212343,
|
||||||
|
"energy_received": 223453,
|
||||||
|
"active_power": 51,
|
||||||
|
"power_factor": 0.24,
|
||||||
|
"voltage": 112,
|
||||||
|
"current": 0.3,
|
||||||
|
"frequency": 50.2,
|
||||||
|
"state": "enabled",
|
||||||
|
"measurement_type": "net-consumption",
|
||||||
|
"metering_status": "normal",
|
||||||
|
"status_flags": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ctmeter_storage_phases": null,
|
||||||
|
"dry_contact_status": {},
|
||||||
|
"dry_contact_settings": {},
|
||||||
|
"inverters": {
|
||||||
|
"1": {
|
||||||
|
"serial_number": "1",
|
||||||
|
"last_report_date": 1,
|
||||||
|
"last_report_watts": 1,
|
||||||
|
"max_report_watts": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tariff": {
|
||||||
|
"currency": {
|
||||||
|
"code": "EUR"
|
||||||
|
},
|
||||||
|
"logger": "mylogger",
|
||||||
|
"date": "1714749724",
|
||||||
|
"storage_settings": {
|
||||||
|
"mode": "self-consumption",
|
||||||
|
"operation_mode_sub_type": "",
|
||||||
|
"reserved_soc": 0.0,
|
||||||
|
"very_low_soc": 5,
|
||||||
|
"charge_from_grid": true,
|
||||||
|
"date": "1714749724"
|
||||||
|
},
|
||||||
|
"single_rate": {
|
||||||
|
"rate": 0.0,
|
||||||
|
"sell": 0.0
|
||||||
|
},
|
||||||
|
"seasons": [
|
||||||
|
{
|
||||||
|
"id": "all_year_long",
|
||||||
|
"start": "1/1",
|
||||||
|
"days": [
|
||||||
|
{
|
||||||
|
"id": "all_days",
|
||||||
|
"days": "Mon,Tue,Wed,Thu,Fri,Sat,Sun",
|
||||||
|
"must_charge_start": 0,
|
||||||
|
"must_charge_duration": 0,
|
||||||
|
"must_charge_mode": "CP",
|
||||||
|
"enable_discharge_to_grid": false,
|
||||||
|
"periods": [
|
||||||
|
{
|
||||||
|
"id": "period_1",
|
||||||
|
"start": 0,
|
||||||
|
"rate": 0.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tiers": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"seasons_sell": []
|
||||||
|
},
|
||||||
|
"raw": {
|
||||||
|
"varies_by": "firmware_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,97 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_binary_sensor[envoy_eu_batt][binary_sensor.encharge_123456_communicating-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'binary_sensor',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'binary_sensor.encharge_123456_communicating',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <BinarySensorDeviceClass.CONNECTIVITY: 'connectivity'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Communicating',
|
||||||
|
'platform': 'enphase_envoy',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'communicating',
|
||||||
|
'unique_id': '123456_communicating',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_binary_sensor[envoy_eu_batt][binary_sensor.encharge_123456_communicating-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'connectivity',
|
||||||
|
'friendly_name': 'Encharge 123456 Communicating',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'binary_sensor.encharge_123456_communicating',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'on',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_binary_sensor[envoy_eu_batt][binary_sensor.encharge_123456_dc_switch-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'binary_sensor',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'binary_sensor.encharge_123456_dc_switch',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'DC switch',
|
||||||
|
'platform': 'enphase_envoy',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'dc_switch',
|
||||||
|
'unique_id': '123456_dc_switch',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_binary_sensor[envoy_eu_batt][binary_sensor.encharge_123456_dc_switch-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Encharge 123456 DC switch',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'binary_sensor.encharge_123456_dc_switch',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'on',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_binary_sensor[envoy_metered_batt_relay][binary_sensor.encharge_123456_communicating-entry]
|
# name: test_binary_sensor[envoy_metered_batt_relay][binary_sensor.encharge_123456_communicating-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
|
@ -1,4 +1,61 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_number[envoy_eu_batt][number.envoy_1234_reserve_battery_level-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'max': 100.0,
|
||||||
|
'min': 0.0,
|
||||||
|
'mode': <NumberMode.AUTO: 'auto'>,
|
||||||
|
'step': 1.0,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'number',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'number.envoy_1234_reserve_battery_level',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <NumberDeviceClass.BATTERY: 'battery'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Reserve battery level',
|
||||||
|
'platform': 'enphase_envoy',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'reserve_soc',
|
||||||
|
'unique_id': '1234_reserve_soc',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_number[envoy_eu_batt][number.envoy_1234_reserve_battery_level-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'battery',
|
||||||
|
'friendly_name': 'Envoy 1234 Reserve battery level',
|
||||||
|
'max': 100.0,
|
||||||
|
'min': 0.0,
|
||||||
|
'mode': <NumberMode.AUTO: 'auto'>,
|
||||||
|
'step': 1.0,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'number.envoy_1234_reserve_battery_level',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '0.0',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_number[envoy_metered_batt_relay][number.enpower_654321_reserve_battery_level-entry]
|
# name: test_number[envoy_metered_batt_relay][number.enpower_654321_reserve_battery_level-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
|
@ -1,4 +1,61 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_select[envoy_eu_batt][select.envoy_1234_storage_mode-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'options': list([
|
||||||
|
'backup',
|
||||||
|
'self_consumption',
|
||||||
|
'savings',
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'select',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'select.envoy_1234_storage_mode',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Storage mode',
|
||||||
|
'platform': 'enphase_envoy',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'storage_mode',
|
||||||
|
'unique_id': '1234_storage_mode',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_select[envoy_eu_batt][select.envoy_1234_storage_mode-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Envoy 1234 Storage mode',
|
||||||
|
'options': list([
|
||||||
|
'backup',
|
||||||
|
'self_consumption',
|
||||||
|
'savings',
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'select.envoy_1234_storage_mode',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'self_consumption',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_select[envoy_metered_batt_relay][select.enpower_654321_storage_mode-entry]
|
# name: test_select[envoy_metered_batt_relay][select.enpower_654321_storage_mode-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,50 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_switch[envoy_eu_batt][switch.envoy_1234_charge_from_grid-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'switch',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'switch.envoy_1234_charge_from_grid',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Charge from grid',
|
||||||
|
'platform': 'enphase_envoy',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'charge_from_grid',
|
||||||
|
'unique_id': '1234_charge_from_grid',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch[envoy_eu_batt][switch.envoy_1234_charge_from_grid-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Envoy 1234 Charge from grid',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'switch.envoy_1234_charge_from_grid',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'on',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_switch[envoy_metered_batt_relay][switch.enpower_654321_charge_from_grid-entry]
|
# name: test_switch[envoy_metered_batt_relay][switch.enpower_654321_charge_from_grid-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
|
@ -16,7 +16,9 @@ from tests.common import MockConfigEntry, snapshot_platform
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mock_envoy"), ["envoy_metered_batt_relay"], indirect=["mock_envoy"]
|
("mock_envoy"),
|
||||||
|
["envoy_eu_batt", "envoy_metered_batt_relay"],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
)
|
)
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_binary_sensor(
|
async def test_binary_sensor(
|
||||||
|
@ -21,7 +21,9 @@ from tests.common import MockConfigEntry, snapshot_platform
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mock_envoy"), ["envoy_metered_batt_relay"], indirect=["mock_envoy"]
|
("mock_envoy"),
|
||||||
|
["envoy_metered_batt_relay", "envoy_eu_batt"],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
)
|
)
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_number(
|
async def test_number(
|
||||||
@ -60,19 +62,24 @@ async def test_no_number(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mock_envoy"), ["envoy_metered_batt_relay"], indirect=["mock_envoy"]
|
("mock_envoy", "use_serial"),
|
||||||
|
[
|
||||||
|
("envoy_metered_batt_relay", "enpower_654321"),
|
||||||
|
("envoy_eu_batt", "envoy_1234"),
|
||||||
|
],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
)
|
)
|
||||||
async def test_number_operation_storage(
|
async def test_number_operation_storage(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_envoy: AsyncMock,
|
mock_envoy: AsyncMock,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
|
use_serial: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test enphase_envoy number storage entities operation."""
|
"""Test enphase_envoy number storage entities operation."""
|
||||||
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.NUMBER]):
|
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.NUMBER]):
|
||||||
await setup_integration(hass, config_entry)
|
await setup_integration(hass, config_entry)
|
||||||
|
|
||||||
sn = mock_envoy.data.enpower.serial_number
|
test_entity = f"{Platform.NUMBER}.{use_serial}_reserve_battery_level"
|
||||||
test_entity = f"{Platform.NUMBER}.enpower_{sn}_reserve_battery_level"
|
|
||||||
|
|
||||||
assert (entity_state := hass.states.get(test_entity))
|
assert (entity_state := hass.states.get(test_entity))
|
||||||
assert mock_envoy.data.tariff.storage_settings.reserved_soc == float(
|
assert mock_envoy.data.tariff.storage_settings.reserved_soc == float(
|
||||||
|
@ -28,7 +28,9 @@ from tests.common import MockConfigEntry, snapshot_platform
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mock_envoy"), ["envoy_metered_batt_relay"], indirect=["mock_envoy"]
|
("mock_envoy"),
|
||||||
|
["envoy_metered_batt_relay", "envoy_eu_batt"],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
)
|
)
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_select(
|
async def test_select(
|
||||||
@ -172,19 +174,24 @@ async def test_select_relay_modes(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mock_envoy"), ["envoy_metered_batt_relay"], indirect=["mock_envoy"]
|
("mock_envoy", "use_serial"),
|
||||||
|
[
|
||||||
|
("envoy_metered_batt_relay", "enpower_654321"),
|
||||||
|
("envoy_eu_batt", "envoy_1234"),
|
||||||
|
],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
)
|
)
|
||||||
async def test_select_storage_modes(
|
async def test_select_storage_modes(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_envoy: AsyncMock,
|
mock_envoy: AsyncMock,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
|
use_serial: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test select platform entities storage mode changes."""
|
"""Test select platform entities storage mode changes."""
|
||||||
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.SELECT]):
|
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.SELECT]):
|
||||||
await setup_integration(hass, config_entry)
|
await setup_integration(hass, config_entry)
|
||||||
|
|
||||||
sn = mock_envoy.data.enpower.serial_number
|
test_entity = f"{Platform.SELECT}.{use_serial}_storage_mode"
|
||||||
test_entity = f"{Platform.SELECT}.enpower_{sn}_storage_mode"
|
|
||||||
|
|
||||||
assert (entity_state := hass.states.get(test_entity))
|
assert (entity_state := hass.states.get(test_entity))
|
||||||
assert STORAGE_MODE_MAP[mock_envoy.data.tariff.storage_settings.mode] == (
|
assert STORAGE_MODE_MAP[mock_envoy.data.tariff.storage_settings.mode] == (
|
||||||
|
@ -26,6 +26,7 @@ from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_plat
|
|||||||
[
|
[
|
||||||
"envoy",
|
"envoy",
|
||||||
"envoy_1p_metered",
|
"envoy_1p_metered",
|
||||||
|
"envoy_eu_batt",
|
||||||
"envoy_metered_batt_relay",
|
"envoy_metered_batt_relay",
|
||||||
"envoy_nobatt_metered_3p",
|
"envoy_nobatt_metered_3p",
|
||||||
"envoy_tot_cons_metered",
|
"envoy_tot_cons_metered",
|
||||||
@ -59,6 +60,7 @@ PRODUCTION_NAMES: tuple[str, ...] = (
|
|||||||
[
|
[
|
||||||
"envoy",
|
"envoy",
|
||||||
"envoy_1p_metered",
|
"envoy_1p_metered",
|
||||||
|
"envoy_eu_batt",
|
||||||
"envoy_metered_batt_relay",
|
"envoy_metered_batt_relay",
|
||||||
"envoy_nobatt_metered_3p",
|
"envoy_nobatt_metered_3p",
|
||||||
"envoy_tot_cons_metered",
|
"envoy_tot_cons_metered",
|
||||||
@ -148,6 +150,7 @@ CONSUMPTION_NAMES: tuple[str, ...] = (
|
|||||||
("mock_envoy"),
|
("mock_envoy"),
|
||||||
[
|
[
|
||||||
"envoy_1p_metered",
|
"envoy_1p_metered",
|
||||||
|
"envoy_eu_batt",
|
||||||
"envoy_metered_batt_relay",
|
"envoy_metered_batt_relay",
|
||||||
"envoy_nobatt_metered_3p",
|
"envoy_nobatt_metered_3p",
|
||||||
],
|
],
|
||||||
@ -189,6 +192,7 @@ NET_CONSUMPTION_NAMES: tuple[str, ...] = (
|
|||||||
("mock_envoy"),
|
("mock_envoy"),
|
||||||
[
|
[
|
||||||
"envoy_1p_metered",
|
"envoy_1p_metered",
|
||||||
|
"envoy_eu_batt",
|
||||||
"envoy_metered_batt_relay",
|
"envoy_metered_batt_relay",
|
||||||
"envoy_nobatt_metered_3p",
|
"envoy_nobatt_metered_3p",
|
||||||
"envoy_tot_cons_metered",
|
"envoy_tot_cons_metered",
|
||||||
@ -735,6 +739,7 @@ async def test_sensor_storage_phase_disabled_by_integration(
|
|||||||
[
|
[
|
||||||
"envoy",
|
"envoy",
|
||||||
"envoy_1p_metered",
|
"envoy_1p_metered",
|
||||||
|
"envoy_eu_batt",
|
||||||
"envoy_metered_batt_relay",
|
"envoy_metered_batt_relay",
|
||||||
"envoy_nobatt_metered_3p",
|
"envoy_nobatt_metered_3p",
|
||||||
"envoy_tot_cons_metered",
|
"envoy_tot_cons_metered",
|
||||||
@ -767,6 +772,7 @@ async def test_sensor_inverter_data(
|
|||||||
[
|
[
|
||||||
"envoy",
|
"envoy",
|
||||||
"envoy_1p_metered",
|
"envoy_1p_metered",
|
||||||
|
"envoy_eu_batt",
|
||||||
"envoy_metered_batt_relay",
|
"envoy_metered_batt_relay",
|
||||||
"envoy_nobatt_metered_3p",
|
"envoy_nobatt_metered_3p",
|
||||||
"envoy_tot_cons_metered",
|
"envoy_tot_cons_metered",
|
||||||
|
@ -24,7 +24,9 @@ from tests.common import MockConfigEntry, snapshot_platform
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("mock_envoy"), ["envoy_metered_batt_relay"], indirect=["mock_envoy"]
|
("mock_envoy"),
|
||||||
|
["envoy_metered_batt_relay", "envoy_eu_batt"],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
)
|
)
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_switch(
|
async def test_switch(
|
||||||
@ -109,7 +111,26 @@ async def test_switch_grid_operation(
|
|||||||
mock_envoy.go_off_grid.assert_awaited_once_with()
|
mock_envoy.go_off_grid.assert_awaited_once_with()
|
||||||
mock_envoy.go_off_grid.reset_mock()
|
mock_envoy.go_off_grid.reset_mock()
|
||||||
|
|
||||||
test_entity = f"{Platform.SWITCH}.enpower_{sn}_charge_from_grid"
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("mock_envoy", "use_serial"),
|
||||||
|
[
|
||||||
|
("envoy_metered_batt_relay", "enpower_654321"),
|
||||||
|
("envoy_eu_batt", "envoy_1234"),
|
||||||
|
],
|
||||||
|
indirect=["mock_envoy"],
|
||||||
|
)
|
||||||
|
async def test_switch_charge_from_grid_operation(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_envoy: AsyncMock,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
use_serial: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test switch platform operation for charge from grid switches."""
|
||||||
|
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.SWITCH]):
|
||||||
|
await setup_integration(hass, config_entry)
|
||||||
|
|
||||||
|
test_entity = f"{Platform.SWITCH}.{use_serial}_charge_from_grid"
|
||||||
|
|
||||||
# validate envoy value is reflected in entity
|
# validate envoy value is reflected in entity
|
||||||
assert (entity_state := hass.states.get(test_entity))
|
assert (entity_state := hass.states.get(test_entity))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user