Compare commits

...

30 Commits

Author SHA1 Message Date
Ludovic BOUÉ
289490faa3 Refactor setpoint_change_timestamp device_to_ha conversion to use matter_epoch_seconds_to_utc 2026-01-12 20:57:39 +00:00
Ludovic BOUÉ
dea46f7b2e Add tests for Eve Thermo v5 SetpointChangeSource, timestamp, and amount sensors 2026-01-12 20:54:52 +00:00
Ludovic BOUÉ
82e3221126 Update Matter Eve Thermo sensor entries to reflect last change and change amount attributes 2026-01-12 19:28:15 +00:00
Ludovic BOUÉ
47e8fbc1ed Add Matter Eve Thermo 20ECD1701 sensor entries and update mock thermostat configurations 2026-01-12 19:25:10 +00:00
Ludovic BOUÉ
0428d0b97f Merge branch 'dev' into setpoint_change_source 2026-01-12 20:19:09 +01:00
Ludovic BOUÉ
514b6e243c Rename Matter Eve Thermostat Fixture to eve_thermo_v4 (#160796) 2026-01-12 20:16:13 +01:00
Ludovic BOUÉ
45344c04c1 Refactor setpoint change source mapping and add utility functions for Matter epoch conversion 2026-01-12 19:14:54 +00:00
Ludovic BOUÉ
c472b6ac5e Add support for RoomAirConditioner device type 2025-12-01 15:12:33 +00:00
Ludovic BOUÉ
58f533feb6 Add device_type attribute for Thermostat sensors 2025-11-30 21:43:43 +01:00
Ludovic BOUÉ
0af8c8fd8c Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-30 21:37:01 +01:00
Ludovic BOUÉ
b9d6c3b9fe Update homeassistant/components/matter/strings.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-30 21:36:08 +01:00
Ludovic BOUÉ
b700940bb9 Merge branch 'dev' into setpoint_change_source 2025-11-30 21:31:19 +01:00
Ludovic BOUÉ
3b73f6d37e Update thermostat setpoint change timestamp to January 1, 2025 2025-11-30 20:21:45 +00:00
Ludovic BOUÉ
2812bb21da Add offset for Matter 2000 epoch in timestamp conversion 2025-11-30 20:20:13 +00:00
Ludovic BOUÉ
5d474675e8 Update mock thermostat state timestamp to January 1, 2025 2025-11-30 20:15:31 +00:00
Ludovic BOUÉ
ea7bcf6cda Update mock thermostat JSON to correct timestamp for attribute 1/513/50 2025-11-30 20:11:19 +00:00
Ludovic BOUÉ
725bd3d671 Add mock thermostat entity and state snapshots for temperature display mode 2025-11-21 12:38:04 +00:00
Ludovic BOUÉ
cfc4fa6342 Merge branch 'dev' into setpoint_change_source 2025-11-21 13:35:31 +01:00
Ludovic BOUÉ
b650e71660 Update mock thermostat snapshots with new attributes and state values 2025-11-18 18:05:29 +00:00
Ludovic BOUÉ
9ddf15e348 Update mock thermostat JSON with additional attributes and values 2025-11-18 18:03:46 +00:00
Ludovic BOUÉ
15082f9111 Merge branch 'dev' into setpoint_change_source 2025-11-18 16:45:05 +01:00
Ludovic BOUÉ
12f16611ff Rename mock thermostat entity IDs and friendly names in snapshots for consistency 2025-11-18 15:30:39 +00:00
Ludovic BOUÉ
8041be3d08 Merge branch 'dev' into setpoint_change_source 2025-11-18 14:08:38 +01:00
Ludovic BOUÉ
40b021e755 Add tests for Thermostat SetpointChangeSource, Timestamp, and Amount sensors 2025-11-18 13:02:44 +00:00
Ludovic BOUÉ
aab57eda96 Update mock thermostat product name to "Mock Thermostat" 2025-11-18 13:00:26 +00:00
Ludovic BOUÉ
f0dd37caa5 Add mock thermostat sensors and states for testing 2025-11-18 12:49:32 +00:00
Ludovic BOUÉ
662b178495 Remove unused attribute from thermostat fixture 2025-11-18 12:48:56 +00:00
Ludovic BOUÉ
cb3d30884a Add mock thermostat fixture for integration tests 2025-11-18 12:48:21 +00:00
Ludovic BOUÉ
49e6f20372 Add Setpoint Change Source timestamp and amount sensors with localization strings 2025-11-18 12:39:28 +00:00
Ludovic BOUÉ
75d02661eb Add Setpoint Change Source sensor and localization strings 2025-11-14 17:19:28 +00:00
13 changed files with 558 additions and 69 deletions

View File

@@ -173,6 +173,13 @@ EVSE_FAULT_STATE_MAP = {
clusters.EnergyEvse.Enums.FaultStateEnum.kOther: "other",
}
SETPOINT_CHANGE_SOURCE_MAP = {
clusters.Thermostat.Enums.SetpointChangeSourceEnum.kManual: "manual",
clusters.Thermostat.Enums.SetpointChangeSourceEnum.kSchedule: "schedule",
clusters.Thermostat.Enums.SetpointChangeSourceEnum.kExternal: "external",
clusters.Thermostat.Enums.SetpointChangeSourceEnum.kUnknownEnumValue: None,
}
PUMP_CONTROL_MODE_MAP = {
clusters.PumpConfigurationAndControl.Enums.ControlModeEnum.kConstantSpeed: "constant_speed",
clusters.PumpConfigurationAndControl.Enums.ControlModeEnum.kConstantPressure: "constant_pressure",
@@ -1541,4 +1548,48 @@ DISCOVERY_SCHEMAS = [
required_attributes=(clusters.DoorLock.Attributes.DoorClosedEvents,),
featuremap_contains=clusters.DoorLock.Bitmaps.Feature.kDoorPositionSensor,
),
MatterDiscoverySchema(
platform=Platform.SENSOR,
entity_description=MatterSensorEntityDescription(
key="SetpointChangeSource",
translation_key="setpoint_change_source",
device_class=SensorDeviceClass.ENUM,
state_class=None,
options=[x for x in SETPOINT_CHANGE_SOURCE_MAP.values() if x is not None],
device_to_ha=lambda x: SETPOINT_CHANGE_SOURCE_MAP[x],
),
entity_class=MatterSensor,
required_attributes=(clusters.Thermostat.Attributes.SetpointChangeSource,),
device_type=(device_types.Thermostat, device_types.RoomAirConditioner),
),
MatterDiscoverySchema(
platform=Platform.SENSOR,
entity_description=MatterSensorEntityDescription(
key="SetpointChangeSourceTimestamp",
translation_key="setpoint_change_timestamp",
device_class=SensorDeviceClass.TIMESTAMP,
state_class=None,
device_to_ha=matter_epoch_seconds_to_utc,
),
entity_class=MatterSensor,
required_attributes=(
clusters.Thermostat.Attributes.SetpointChangeSourceTimestamp,
),
device_type=(device_types.Thermostat, device_types.RoomAirConditioner),
),
MatterDiscoverySchema(
platform=Platform.SENSOR,
entity_description=MatterSensorEntityDescription(
key="ThermostatSetpointChangeAmount",
translation_key="setpoint_change_amount",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
suggested_display_precision=1,
device_class=SensorDeviceClass.TEMPERATURE,
device_to_ha=lambda x: x / TEMPERATURE_SCALING_FACTOR,
state_class=SensorStateClass.MEASUREMENT,
),
entity_class=MatterSensor,
required_attributes=(clusters.Thermostat.Attributes.SetpointChangeAmount,),
device_type=(device_types.Thermostat, device_types.RoomAirConditioner),
),
]

View File

@@ -549,6 +549,20 @@
"rms_voltage": {
"name": "Effective voltage"
},
"setpoint_change_amount": {
"name": "Last change amount"
},
"setpoint_change_source": {
"name": "Last change source",
"state": {
"external": "External",
"manual": "Manual",
"schedule": "Schedule"
}
},
"setpoint_change_timestamp": {
"name": "Last change"
},
"switch_current_position": {
"name": "Current switch position"
},

View File

@@ -96,7 +96,7 @@ async def integration_fixture(
"eve_energy_20ecn4101",
"eve_energy_plug",
"eve_energy_plug_patched",
"eve_thermo",
"eve_thermo_v4",
"eve_thermo_v5",
"eve_shutter",
"eve_weather_sensor",

View File

@@ -61,7 +61,7 @@
"0/40/0": 17,
"0/40/1": "Eve Systems",
"0/40/2": 4874,
"0/40/3": "Eve Thermo",
"0/40/3": "Eve Thermo 20EBP1701",
"0/40/4": 79,
"0/40/5": "",
"0/40/6": "**REDACTED**",

View File

@@ -391,7 +391,7 @@
'state': 'off',
})
# ---
# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_local_temperature_remote_sensing-entry]
# name: test_binary_sensors[eve_thermo_v4][binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -404,7 +404,7 @@
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.eve_thermo_local_temperature_remote_sensing',
'entity_id': 'binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -426,20 +426,20 @@
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_local_temperature_remote_sensing-state]
# name: test_binary_sensors[eve_thermo_v4][binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Eve Thermo Local temperature remote sensing',
'friendly_name': 'Eve Thermo 20EBP1701 Local temperature remote sensing',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.eve_thermo_local_temperature_remote_sensing',
'entity_id': 'binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_outdoor_temperature_remote_sensing-entry]
# name: test_binary_sensors[eve_thermo_v4][binary_sensor.eve_thermo_20ebp1701_outdoor_temperature_remote_sensing-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -452,7 +452,7 @@
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.eve_thermo_outdoor_temperature_remote_sensing',
'entity_id': 'binary_sensor.eve_thermo_20ebp1701_outdoor_temperature_remote_sensing',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -474,13 +474,13 @@
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_outdoor_temperature_remote_sensing-state]
# name: test_binary_sensors[eve_thermo_v4][binary_sensor.eve_thermo_20ebp1701_outdoor_temperature_remote_sensing-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Eve Thermo Outdoor temperature remote sensing',
'friendly_name': 'Eve Thermo 20EBP1701 Outdoor temperature remote sensing',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.eve_thermo_outdoor_temperature_remote_sensing',
'entity_id': 'binary_sensor.eve_thermo_20ebp1701_outdoor_temperature_remote_sensing',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@@ -1418,7 +1418,7 @@
'state': 'unknown',
})
# ---
# name: test_buttons[eve_thermo][button.eve_thermo_identify-entry]
# name: test_buttons[eve_thermo_v4][button.eve_thermo_20ebp1701_identify-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -1431,7 +1431,7 @@
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.eve_thermo_identify',
'entity_id': 'button.eve_thermo_20ebp1701_identify',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1453,14 +1453,14 @@
'unit_of_measurement': None,
})
# ---
# name: test_buttons[eve_thermo][button.eve_thermo_identify-state]
# name: test_buttons[eve_thermo_v4][button.eve_thermo_20ebp1701_identify-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'identify',
'friendly_name': 'Eve Thermo Identify',
'friendly_name': 'Eve Thermo 20EBP1701 Identify',
}),
'context': <ANY>,
'entity_id': 'button.eve_thermo_identify',
'entity_id': 'button.eve_thermo_20ebp1701_identify',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@@ -191,7 +191,7 @@
'state': 'heat',
})
# ---
# name: test_climates[eve_thermo][climate.eve_thermo-entry]
# name: test_climates[eve_thermo_v4][climate.eve_thermo_20ebp1701-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -211,7 +211,7 @@
'disabled_by': None,
'domain': 'climate',
'entity_category': None,
'entity_id': 'climate.eve_thermo',
'entity_id': 'climate.eve_thermo_20ebp1701',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -233,11 +233,11 @@
'unit_of_measurement': None,
})
# ---
# name: test_climates[eve_thermo][climate.eve_thermo-state]
# name: test_climates[eve_thermo_v4][climate.eve_thermo_20ebp1701-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_temperature': 21.0,
'friendly_name': 'Eve Thermo',
'friendly_name': 'Eve Thermo 20EBP1701',
'hvac_modes': list([
<HVACMode.OFF: 'off'>,
<HVACMode.HEAT: 'heat'>,
@@ -248,7 +248,7 @@
'temperature': 17.0,
}),
'context': <ANY>,
'entity_id': 'climate.eve_thermo',
'entity_id': 'climate.eve_thermo_20ebp1701',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@@ -1037,7 +1037,7 @@
'state': '3',
})
# ---
# name: test_numbers[eve_thermo][number.eve_thermo_temperature_offset-entry]
# name: test_numbers[eve_thermo_v4][number.eve_thermo_20ebp1701_temperature_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -1055,7 +1055,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.eve_thermo_temperature_offset',
'entity_id': 'number.eve_thermo_20ebp1701_temperature_offset',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1077,11 +1077,11 @@
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_numbers[eve_thermo][number.eve_thermo_temperature_offset-state]
# name: test_numbers[eve_thermo_v4][number.eve_thermo_20ebp1701_temperature_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Eve Thermo Temperature offset',
'friendly_name': 'Eve Thermo 20EBP1701 Temperature offset',
'max': 50,
'min': -50,
'mode': <NumberMode.BOX: 'box'>,
@@ -1089,7 +1089,7 @@
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'number.eve_thermo_temperature_offset',
'entity_id': 'number.eve_thermo_20ebp1701_temperature_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@@ -1400,7 +1400,7 @@
'state': 'previous',
})
# ---
# name: test_selects[eve_thermo][select.eve_thermo_temperature_display_mode-entry]
# name: test_selects[eve_thermo_v4][select.eve_thermo_20ebp1701_temperature_display_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -1418,7 +1418,7 @@
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.eve_thermo_temperature_display_mode',
'entity_id': 'select.eve_thermo_20ebp1701_temperature_display_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1440,17 +1440,17 @@
'unit_of_measurement': None,
})
# ---
# name: test_selects[eve_thermo][select.eve_thermo_temperature_display_mode-state]
# name: test_selects[eve_thermo_v4][select.eve_thermo_20ebp1701_temperature_display_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Eve Thermo Temperature display mode',
'friendly_name': 'Eve Thermo 20EBP1701 Temperature display mode',
'options': list([
'Celsius',
'Fahrenheit',
]),
}),
'context': <ANY>,
'entity_id': 'select.eve_thermo_temperature_display_mode',
'entity_id': 'select.eve_thermo_20ebp1701_temperature_display_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@@ -4904,7 +4904,7 @@
'state': '100',
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_battery-entry]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -4919,7 +4919,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.eve_thermo_battery',
'entity_id': 'sensor.eve_thermo_20ebp1701_battery',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -4941,23 +4941,23 @@
'unit_of_measurement': '%',
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_battery-state]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'battery',
'friendly_name': 'Eve Thermo Battery',
'friendly_name': 'Eve Thermo 20EBP1701 Battery',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_battery',
'entity_id': 'sensor.eve_thermo_20ebp1701_battery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '100',
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_battery_voltage-entry]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery_voltage-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -4972,7 +4972,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.eve_thermo_battery_voltage',
'entity_id': 'sensor.eve_thermo_20ebp1701_battery_voltage',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -5000,23 +5000,23 @@
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_battery_voltage-state]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery_voltage-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'voltage',
'friendly_name': 'Eve Thermo Battery voltage',
'friendly_name': 'Eve Thermo 20EBP1701 Battery voltage',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_battery_voltage',
'entity_id': 'sensor.eve_thermo_20ebp1701_battery_voltage',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '3.05',
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_temperature-entry]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -5031,7 +5031,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.eve_thermo_temperature',
'entity_id': 'sensor.eve_thermo_20ebp1701_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -5056,23 +5056,23 @@
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_temperature-state]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Eve Thermo Temperature',
'friendly_name': 'Eve Thermo 20EBP1701 Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_temperature',
'entity_id': 'sensor.eve_thermo_20ebp1701_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '21.0',
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_valve_position-entry]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_valve_position-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -5085,7 +5085,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.eve_thermo_valve_position',
'entity_id': 'sensor.eve_thermo_20ebp1701_valve_position',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -5107,14 +5107,14 @@
'unit_of_measurement': '%',
})
# ---
# name: test_sensors[eve_thermo][sensor.eve_thermo_valve_position-state]
# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_valve_position-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Eve Thermo Valve position',
'friendly_name': 'Eve Thermo 20EBP1701 Valve position',
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_valve_position',
'entity_id': 'sensor.eve_thermo_20ebp1701_valve_position',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
@@ -5174,6 +5174,171 @@
'state': '100',
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_last_change-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.eve_thermo_20ecd1701_last_change',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last change',
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'setpoint_change_timestamp',
'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-SetpointChangeSourceTimestamp-513-50',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_last_change-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'Eve Thermo 20ECD1701 Last change',
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_20ecd1701_last_change',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_last_change_amount-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.eve_thermo_20ecd1701_last_change_amount',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Last change amount',
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'setpoint_change_amount',
'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-ThermostatSetpointChangeAmount-513-49',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_last_change_amount-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Eve Thermo 20ECD1701 Last change amount',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_20ecd1701_last_change_amount',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.0',
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_last_change_source-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'manual',
'schedule',
'external',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.eve_thermo_20ecd1701_last_change_source',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Last change source',
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'setpoint_change_source',
'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-SetpointChangeSource-513-48',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_last_change_source-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Eve Thermo 20ECD1701 Last change source',
'options': list([
'manual',
'schedule',
'external',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.eve_thermo_20ecd1701_last_change_source',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'manual',
})
# ---
# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -8741,6 +8906,171 @@
'state': '25',
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_last_change-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_thermostat_last_change',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last change',
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'setpoint_change_timestamp',
'unique_id': '00000000000004D2-0000000000000096-MatterNodeDevice-1-SetpointChangeSourceTimestamp-513-50',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_last_change-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'Mock Thermostat Last change',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_thermostat_last_change',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2025-01-01T00:00:00+00:00',
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_last_change_amount-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_thermostat_last_change_amount',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Last change amount',
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'setpoint_change_amount',
'unique_id': '00000000000004D2-0000000000000096-MatterNodeDevice-1-ThermostatSetpointChangeAmount-513-49',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_last_change_amount-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Mock Thermostat Last change amount',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_thermostat_last_change_amount',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1.5',
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_last_change_source-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'manual',
'schedule',
'external',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_thermostat_last_change_source',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Last change source',
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'setpoint_change_source',
'unique_id': '00000000000004D2-0000000000000096-MatterNodeDevice-1-SetpointChangeSource-513-48',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_last_change_source-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Mock Thermostat Last change source',
'options': list([
'manual',
'schedule',
'external',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.mock_thermostat_last_change_source',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'manual',
})
# ---
# name: test_sensors[mock_thermostat][sensor.mock_thermostat_outdoor_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -487,7 +487,7 @@
'state': 'off',
})
# ---
# name: test_switches[eve_thermo][switch.eve_thermo_child_lock-entry]
# name: test_switches[eve_thermo_v4][switch.eve_thermo_20ebp1701_child_lock-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@@ -500,7 +500,7 @@
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.eve_thermo_child_lock',
'entity_id': 'switch.eve_thermo_20ebp1701_child_lock',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -522,13 +522,13 @@
'unit_of_measurement': None,
})
# ---
# name: test_switches[eve_thermo][switch.eve_thermo_child_lock-state]
# name: test_switches[eve_thermo_v4][switch.eve_thermo_20ebp1701_child_lock-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Eve Thermo Child lock',
'friendly_name': 'Eve Thermo 20EBP1701 Child lock',
}),
'context': <ANY>,
'entity_id': 'switch.eve_thermo_child_lock',
'entity_id': 'switch.eve_thermo_20ebp1701_child_lock',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@@ -201,7 +201,7 @@ async def test_battery_sensor_description(
state = hass.states.get("sensor.smoke_sensor_battery_type") is None
@pytest.mark.parametrize("node_fixture", ["eve_thermo"])
@pytest.mark.parametrize("node_fixture", ["eve_thermo_v4"])
async def test_eve_thermo_sensor(
hass: HomeAssistant,
matter_client: MagicMock,
@@ -209,30 +209,124 @@ async def test_eve_thermo_sensor(
) -> None:
"""Test Eve Thermo."""
# Valve position
state = hass.states.get("sensor.eve_thermo_valve_position")
state = hass.states.get("sensor.eve_thermo_20ebp1701_valve_position")
assert state
assert state.state == "10"
set_node_attribute(matter_node, 1, 319486977, 319422488, 0)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get("sensor.eve_thermo_valve_position")
state = hass.states.get("sensor.eve_thermo_20ebp1701_valve_position")
assert state
assert state.state == "0"
# LocalTemperature
state = hass.states.get("sensor.eve_thermo_temperature")
state = hass.states.get("sensor.eve_thermo_20ebp1701_temperature")
assert state
assert state.state == "21.0"
set_node_attribute(matter_node, 1, 513, 0, 1800)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get("sensor.eve_thermo_temperature")
state = hass.states.get("sensor.eve_thermo_20ebp1701_temperature")
assert state
assert state.state == "18.0"
@pytest.mark.parametrize("node_fixture", ["eve_thermo_v5"])
async def test_eve_thermo_v5_setpoint_change_source(
hass: HomeAssistant,
matter_client: MagicMock,
matter_node: MatterNode,
) -> None:
"""Test Eve Thermo v5 SetpointChangeSource sensor."""
entity_id = "sensor.eve_thermo_20ecd1701_last_change_source"
# Initial state and options
state = hass.states.get(entity_id)
assert state
assert state.state == "manual"
assert state.attributes["options"] == ["manual", "schedule", "external"]
# Change to schedule
set_node_attribute(matter_node, 1, 513, 48, 1)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get(entity_id)
assert state
assert state.state == "schedule"
# Change to external
set_node_attribute(matter_node, 1, 513, 48, 2)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get(entity_id)
assert state
assert state.state == "external"
@pytest.mark.parametrize("node_fixture", ["eve_thermo_v5"])
async def test_eve_thermo_v5_setpoint_change_timestamp(
hass: HomeAssistant,
matter_client: MagicMock,
matter_node: MatterNode,
) -> None:
"""Test Eve Thermo v5 SetpointChangeSourceTimestamp sensor."""
entity_id = "sensor.eve_thermo_20ecd1701_last_change"
# Initial is unknown per snapshot
state = hass.states.get(entity_id)
assert state
assert state.state == "unknown"
# Update to 2024-01-01 00:00:00+00:00 (Matter epoch seconds since 2000)
set_node_attribute(matter_node, 1, 513, 50, 757382400)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get(entity_id)
assert state
assert state.state == "2024-01-01T00:00:00+00:00"
# Set to zero should yield unknown
set_node_attribute(matter_node, 1, 513, 50, 0)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get(entity_id)
assert state
assert state.state == "unknown"
@pytest.mark.parametrize("node_fixture", ["eve_thermo_v5"])
async def test_eve_thermo_v5_setpoint_change_amount(
hass: HomeAssistant,
matter_client: MagicMock,
matter_node: MatterNode,
) -> None:
"""Test Eve Thermo v5 SetpointChangeAmount sensor."""
entity_id = "sensor.eve_thermo_20ecd1701_last_change_amount"
# Initial per snapshot
state = hass.states.get(entity_id)
assert state
assert state.state == "0.0"
# Update to 2.0°C (200 in Matter units)
set_node_attribute(matter_node, 1, 513, 49, 200)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get(entity_id)
assert state
assert state.state == "2.0"
# Update to -0.5°C (-50 in Matter units)
set_node_attribute(matter_node, 1, 513, 49, -50)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get(entity_id)
assert state
assert state.state == "-0.5"
@pytest.mark.parametrize("node_fixture", ["longan_link_thermostat"])
async def test_thermostat_outdoor(
hass: HomeAssistant,

View File

@@ -116,32 +116,32 @@ async def test_power_switch(hass: HomeAssistant, matter_node: MatterNode) -> Non
assert state.attributes["friendly_name"] == "Room AirConditioner Power"
@pytest.mark.parametrize("node_fixture", ["eve_thermo"])
@pytest.mark.parametrize("node_fixture", ["eve_thermo_v4"])
async def test_numeric_switch(
hass: HomeAssistant,
matter_client: MagicMock,
matter_node: MatterNode,
) -> None:
"""Test numeric switch entity is discovered and working using an Eve Thermo fixture ."""
state = hass.states.get("switch.eve_thermo_child_lock")
state = hass.states.get("switch.eve_thermo_20ebp1701_child_lock")
assert state
assert state.state == "off"
# name should be derived from description attribute
assert state.attributes["friendly_name"] == "Eve Thermo Child lock"
assert state.attributes["friendly_name"] == "Eve Thermo 20EBP1701 Child lock"
# test attribute changes
set_node_attribute(matter_node, 1, 516, 1, 1)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get("switch.eve_thermo_child_lock")
state = hass.states.get("switch.eve_thermo_20ebp1701_child_lock")
assert state.state == "on"
set_node_attribute(matter_node, 1, 516, 1, 0)
await trigger_subscription_callback(hass, matter_client)
state = hass.states.get("switch.eve_thermo_child_lock")
state = hass.states.get("switch.eve_thermo_20ebp1701_child_lock")
assert state.state == "off"
# test switch service
await hass.services.async_call(
"switch",
"turn_on",
{"entity_id": "switch.eve_thermo_child_lock"},
{"entity_id": "switch.eve_thermo_20ebp1701_child_lock"},
blocking=True,
)
assert matter_client.write_attribute.call_count == 1
@@ -156,7 +156,7 @@ async def test_numeric_switch(
await hass.services.async_call(
"switch",
"turn_off",
{"entity_id": "switch.eve_thermo_child_lock"},
{"entity_id": "switch.eve_thermo_20ebp1701_child_lock"},
blocking=True,
)
assert matter_client.write_attribute.call_count == 2