Add support for Plugwise Anna P1 (#155916)

This commit is contained in:
Bouwe Westerdijk
2025-11-07 11:19:50 +01:00
committed by GitHub
parent 5237dc073a
commit 568ed2f0f6
10 changed files with 1734 additions and 188 deletions

View File

@@ -8,6 +8,6 @@
"iot_class": "local_polling",
"loggers": ["plugwise"],
"quality_scale": "platinum",
"requirements": ["plugwise==1.8.3"],
"requirements": ["plugwise==1.9.0"],
"zeroconf": ["_plugwise._tcp.local."]
}

2
requirements_all.txt generated
View File

@@ -1719,7 +1719,7 @@ plexauth==0.0.6
plexwebsocket==0.0.14
# homeassistant.components.plugwise
plugwise==1.8.3
plugwise==1.9.0
# homeassistant.components.serial_pm
pmsensor==0.4

View File

@@ -1456,7 +1456,7 @@ plexauth==0.0.6
plexwebsocket==0.0.14
# homeassistant.components.plugwise
plugwise==1.8.3
plugwise==1.9.0
# homeassistant.components.poolsense
poolsense==0.0.8

View File

@@ -270,6 +270,34 @@ def mock_smile_anna(chosen_env: str, cooling_present: bool) -> Generator[MagicMo
yield api
@pytest.fixture
def mock_smile_anna_p1() -> Generator[MagicMock]:
"""Create a Mock Anna-P1 type for testing."""
chosen_env = "anna_p1"
data = _read_json(chosen_env, "data")
with patch(
"homeassistant.components.plugwise.coordinator.Smile", autospec=True
) as api_mock:
api = api_mock.return_value
api.async_update.return_value = data
api.connect.return_value = Version("4.4.4")
api.cooling_present = False
api.gateway_id = "53130847be2f436cb946b78dedb9053a"
api.heater_id = "36b937e44ad145bab165fa0fe99d742d"
api.reboot = True
api.smile = build_smile(
hostname="smile98765",
model="Gateway",
model_id="smile_thermo",
name="Smile Anna P1",
type="thermostat",
version="4.4.4",
)
yield api
@pytest.fixture
def mock_smile_p1(chosen_env: str, gateway_id: str) -> Generator[MagicMock]:
"""Create a base Mock P1 type for testing with different datasets and gateway-ids."""

View File

@@ -0,0 +1,104 @@
{
"1e5e55b958ac445583602f767cb45942": {
"active_preset": "home",
"available_schedules": ["Thermostat schedule", "off"],
"climate_mode": "heat",
"control_state": "idle",
"dev_class": "thermostat",
"firmware": "2018-02-08T11:15:53+01:00",
"hardware": "6539-1301-500",
"location": "5b13651d79c4454684fd268850b1bff8",
"model": "ThermoTouch",
"name": "Anna",
"preset_modes": ["home", "asleep", "away", "vacation", "no_frost"],
"select_schedule": "off",
"sensors": {
"illuminance": 2.0,
"setpoint": 19.0,
"temperature": 19.4
},
"temperature_offset": {
"lower_bound": -2.0,
"resolution": 0.1,
"setpoint": 0.0,
"upper_bound": 2.0
},
"thermostat": {
"lower_bound": 4.0,
"resolution": 0.1,
"setpoint": 19.0,
"upper_bound": 30.0
},
"vendor": "Plugwise"
},
"36b937e44ad145bab165fa0fe99d742d": {
"available": true,
"binary_sensors": {
"dhw_state": false,
"flame_state": false,
"heating_state": false
},
"dev_class": "heater_central",
"location": "da7be222ab3b420c927f3e49fade0304",
"model": "Generic heater",
"model_id": "HR24",
"name": "OpenTherm",
"sensors": {
"intended_boiler_temperature": 0.0,
"modulation_level": 0.0,
"water_pressure": 6.0,
"water_temperature": 35.0
},
"switches": {
"dhw_cm_switch": true
},
"vendor": "Intergas"
},
"53130847be2f436cb946b78dedb9053a": {
"binary_sensors": {
"plugwise_notification": false
},
"dev_class": "gateway",
"firmware": "4.4.4",
"hardware": "AME Smile 2.0 board",
"location": "da7be222ab3b420c927f3e49fade0304",
"mac_address": "C493000ABCD",
"model": "Gateway",
"model_id": "smile_thermo",
"name": "Smile Anna P1",
"notifications": {},
"sensors": {
"outdoor_temperature": 11.8
},
"vendor": "Plugwise"
},
"da7be222ab3b420c927f3e49fade0304": {
"available": true,
"dev_class": "smartmeter",
"location": "da7be222ab3b420c927f3e49fade0304",
"model": "2MS212 SMR5.5",
"name": "P1",
"sensors": {
"electricity_consumed_off_peak_cumulative": 618.001,
"electricity_consumed_off_peak_interval": 7,
"electricity_consumed_off_peak_point": 393,
"electricity_consumed_peak_cumulative": 576.014,
"electricity_consumed_peak_interval": 0,
"electricity_consumed_peak_point": 0,
"electricity_phase_one_consumed": 393,
"electricity_phase_one_produced": 0,
"electricity_produced_off_peak_cumulative": 246.504,
"electricity_produced_off_peak_interval": 0,
"electricity_produced_off_peak_point": 0,
"electricity_produced_peak_cumulative": 709.442,
"electricity_produced_peak_interval": 0,
"electricity_produced_peak_point": 0,
"gas_consumed_cumulative": 25.37,
"gas_consumed_interval": 0.01,
"net_electricity_cumulative": 238.069,
"net_electricity_point": 393,
"voltage_phase_one": 234.6
},
"vendor": "SAGEM"
}
}

View File

@@ -1,97 +0,0 @@
{
"015ae9ea3f964e668e490fa39da3870b": {
"binary_sensors": {
"plugwise_notification": false
},
"dev_class": "gateway",
"firmware": "4.0.15",
"hardware": "AME Smile 2.0 board",
"location": "a57efe5f145f498c9be62a9b63626fbf",
"mac_address": "012345670001",
"model": "Gateway",
"model_id": "smile_thermo",
"name": "Smile Anna",
"notifications": {},
"sensors": {
"outdoor_temperature": 28.2
},
"vendor": "Plugwise"
},
"1cbf783bb11e4a7c8a6843dee3a86927": {
"available": true,
"binary_sensors": {
"compressor_state": false,
"cooling_enabled": true,
"cooling_state": false,
"dhw_state": false,
"flame_state": false,
"heating_state": false,
"secondary_boiler_state": false
},
"dev_class": "heater_central",
"location": "a57efe5f145f498c9be62a9b63626fbf",
"max_dhw_temperature": {
"lower_bound": 35.0,
"resolution": 0.01,
"setpoint": 53.0,
"upper_bound": 60.0
},
"maximum_boiler_temperature": {
"lower_bound": 0.0,
"resolution": 1.0,
"setpoint": 60.0,
"upper_bound": 100.0
},
"model": "Generic heater/cooler",
"name": "OpenTherm",
"sensors": {
"dhw_temperature": 46.3,
"intended_boiler_temperature": 18.0,
"modulation_level": 0,
"outdoor_air_temperature": 28.2,
"return_temperature": 22.0,
"water_pressure": 1.57,
"water_temperature": 19.1
},
"switches": {
"dhw_cm_switch": false
},
"vendor": "Techneco"
},
"3cb70739631c4d17a86b8b12e8a5161b": {
"active_preset": "home",
"available_schedules": ["standaard", "off"],
"climate_mode": "auto",
"control_state": "idle",
"dev_class": "thermostat",
"firmware": "2018-02-08T11:15:53+01:00",
"hardware": "6539-1301-5002",
"location": "c784ee9fdab44e1395b8dee7d7a497d5",
"model": "ThermoTouch",
"name": "Anna",
"preset_modes": ["no_frost", "home", "away", "asleep", "vacation"],
"select_schedule": "standaard",
"sensors": {
"cooling_activation_outdoor_temperature": 25.0,
"cooling_deactivation_threshold": 4.0,
"illuminance": 86.0,
"setpoint_high": 30.0,
"setpoint_low": 20.5,
"temperature": 23.0
},
"temperature_offset": {
"lower_bound": -2.0,
"resolution": 0.1,
"setpoint": -0.5,
"upper_bound": 2.0
},
"thermostat": {
"lower_bound": 4.0,
"resolution": 0.1,
"setpoint_high": 30.0,
"setpoint_low": 20.5,
"upper_bound": 30.0
},
"vendor": "Plugwise"
}
}

View File

@@ -658,89 +658,6 @@
'state': 'auto',
})
# ---
# name: test_anna_3_climate_snapshot[platforms0-True-m_anna_heatpump_idle][climate.anna-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'hvac_modes': list([
<HVACMode.AUTO: 'auto'>,
<HVACMode.HEAT_COOL: 'heat_cool'>,
]),
'max_temp': 30.0,
'min_temp': 4.0,
'preset_modes': list([
'no_frost',
'home',
'away',
'asleep',
'vacation',
]),
'target_temp_step': 0.1,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'climate',
'entity_category': None,
'entity_id': 'climate.anna',
'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': None,
'platform': 'plugwise',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ClimateEntityFeature: 18>,
'translation_key': 'plugwise',
'unique_id': '3cb70739631c4d17a86b8b12e8a5161b-climate',
'unit_of_measurement': None,
})
# ---
# name: test_anna_3_climate_snapshot[platforms0-True-m_anna_heatpump_idle][climate.anna-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_temperature': 23.0,
'friendly_name': 'Anna',
'hvac_action': <HVACAction.IDLE: 'idle'>,
'hvac_modes': list([
<HVACMode.AUTO: 'auto'>,
<HVACMode.HEAT_COOL: 'heat_cool'>,
]),
'max_temp': 30.0,
'min_temp': 4.0,
'preset_mode': 'home',
'preset_modes': list([
'no_frost',
'home',
'away',
'asleep',
'vacation',
]),
'supported_features': <ClimateEntityFeature: 18>,
'target_temp_high': 30.0,
'target_temp_low': 20.5,
'target_temp_step': 0.1,
}),
'context': <ANY>,
'entity_id': 'climate.anna',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'auto',
})
# ---
# name: test_anna_climate_snapshot[platforms0-True-anna_heatpump_heating][climate.anna-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -824,3 +741,85 @@
'state': 'auto',
})
# ---
# name: test_anna_p1_climate_snapshot[platforms0][climate.anna-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'hvac_modes': list([
<HVACMode.AUTO: 'auto'>,
<HVACMode.HEAT: 'heat'>,
]),
'max_temp': 30.0,
'min_temp': 4.0,
'preset_modes': list([
'home',
'asleep',
'away',
'vacation',
'no_frost',
]),
'target_temp_step': 0.1,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'climate',
'entity_category': None,
'entity_id': 'climate.anna',
'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': None,
'platform': 'plugwise',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ClimateEntityFeature: 17>,
'translation_key': 'plugwise',
'unique_id': '1e5e55b958ac445583602f767cb45942-climate',
'unit_of_measurement': None,
})
# ---
# name: test_anna_p1_climate_snapshot[platforms0][climate.anna-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_temperature': 19.4,
'friendly_name': 'Anna',
'hvac_action': <HVACAction.IDLE: 'idle'>,
'hvac_modes': list([
<HVACMode.AUTO: 'auto'>,
<HVACMode.HEAT: 'heat'>,
]),
'max_temp': 30.0,
'min_temp': 4.0,
'preset_mode': 'home',
'preset_modes': list([
'home',
'asleep',
'away',
'vacation',
'no_frost',
]),
'supported_features': <ClimateEntityFeature: 17>,
'target_temp_step': 0.1,
'temperature': 19.0,
}),
'context': <ANY>,
'entity_id': 'climate.anna',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'heat',
})
# ---

File diff suppressed because it is too large Load Diff

View File

@@ -471,16 +471,14 @@ async def test_anna_2_climate_snapshot(
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
@pytest.mark.parametrize("chosen_env", ["m_anna_heatpump_idle"], indirect=True)
@pytest.mark.parametrize("cooling_present", [True], indirect=True)
@pytest.mark.parametrize("platforms", [(CLIMATE_DOMAIN,)])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_anna_3_climate_snapshot(
async def test_anna_p1_climate_snapshot(
hass: HomeAssistant,
mock_smile_anna: MagicMock,
mock_smile_anna_p1: MagicMock,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
setup_platform: MockConfigEntry,
) -> None:
"""Test Anna 3 climate snapshot."""
"""Test Anna P1 climate snapshot."""
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)

View File

@@ -95,6 +95,19 @@ async def test_anna_sensor_snapshot(
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_anna_p1_sensor_snapshot(
hass: HomeAssistant,
mock_smile_anna_p1: MagicMock,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
setup_platform: MockConfigEntry,
) -> None:
"""Test Anna P1 sensor snapshot."""
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
@pytest.mark.parametrize("chosen_env", ["p1v4_442_single"], indirect=True)
@pytest.mark.parametrize(
"gateway_id", ["a455b61e52394b2db5081ce025a430f3"], indirect=True