Remove the Sofar serial number sensor (#180371)

This commit is contained in:
darkrain-nl
2026-08-27 08:56:50 +02:00
committed by GitHub
parent 12483ebb0d
commit 26880d33dd
5 changed files with 54 additions and 104 deletions
-6
View File
@@ -434,12 +434,6 @@ SENSOR_DESCRIPTIONS: tuple[SofarSensorDescription, ...] = (
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
),
SofarSensorDescription(
key="serial_number",
component="identity",
translation_key="serial_number",
entity_category=EntityCategory.DIAGNOSTIC,
),
SofarSensorDescription(
key="grid_frequency",
component="grid",
@@ -399,9 +399,6 @@
"reactive_power_pcc_total": {
"name": "Reactive power PCC total"
},
"serial_number": {
"name": "Serial number"
},
"solar_generation_today": {
"name": "Solar generation today"
},
@@ -6709,56 +6709,6 @@
'state': '0.0',
})
# ---
# name: test_all_entities[sensor.hydxxktl_3p_serial_number-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'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': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.hydxxktl_3p_serial_number',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Serial number',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Serial number',
'platform': 'sofar',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'serial_number',
'unique_id': 'SP1XXES100XX_serial_number',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.hydxxktl_3p_serial_number-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'HYDxxKTL-3P Serial number',
}),
'context': <ANY>,
'entity_id': 'sensor.hydxxktl_3p_serial_number',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'SP1XXES100XX',
})
# ---
# name: test_all_entities[sensor.hydxxktl_3p_solar_generation_today-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
+30 -36
View File
@@ -130,7 +130,6 @@ async def test_setup_entry_unreachable_link_retries_and_recovers(
async def test_settings_failure_does_not_block_reading_sensors(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_connection: MockModbusConnection,
mock_config_entry: MockConfigEntry,
) -> None:
@@ -154,51 +153,42 @@ async def test_settings_failure_does_not_block_reading_sensors(
assert mock_config_entry.state is ConfigEntryState.LOADED
assert hass.states.async_entity_ids("sensor")
# Created despite the failure, so the coordinator keeps a listener and
# retries; without one it would never poll again short of a reload.
entity_id = entity_registry.async_get_entity_id(
SENSOR_DOMAIN, DOMAIN, f"{MOCK_SERIAL}_serial_number"
)
assert entity_id is not None
assert (state := hass.states.get(entity_id)) is not None
assert state.state == STATE_UNAVAILABLE
assert mock_config_entry.runtime_data.settings.last_update_success is False
async def test_settings_recover_without_a_reload(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
entity_registry: er.EntityRegistry,
mock_connection: MockModbusConnection,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test settings sensors come back on their own once the link heals."""
mock_config_entry.add_to_hass(hass)
unit = mock_connection.for_unit(1)
"""Test the settings coordinator recovers on its own once the link heals."""
connection = MockModbusConnection()
seed_hybrid_inverter(connection.for_unit(1))
unit = connection.for_unit(1)
# A settings-only register, so the readings poll still sets up.
unit.fail_read(0x1105, ModbusConnectionError("settings unreachable"))
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=MOCK_HYBRID_SERIAL,
data=MOCK_USER_INPUT,
title=MOCK_HYBRID_MODEL,
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sofar.async_get_unit",
side_effect=lambda hass, entry, params, unit_id: mock_connection.for_unit(
unit_id
),
side_effect=lambda hass, entry, params, unit_id: connection.for_unit(unit_id),
):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
entity_id = entity_registry.async_get_entity_id(
SENSOR_DOMAIN, DOMAIN, f"{MOCK_SERIAL}_serial_number"
)
assert entity_id is not None
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
assert entry.runtime_data.settings.last_update_success is False
unit.fail_read(0x1105, None)
freezer.tick(timedelta(seconds=SETTINGS_SCAN_INTERVAL))
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == MOCK_SERIAL
assert entry.runtime_data.settings.last_update_success is True
async def test_sensor_platform_is_forwarded(
@@ -228,26 +218,30 @@ async def test_device_versions_recover_without_a_reload(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
device_registry: dr.DeviceRegistry,
mock_connection: MockModbusConnection,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test firmware versions reach the device once identity answers."""
mock_config_entry.add_to_hass(hass)
unit = mock_connection.for_unit(1)
connection = MockModbusConnection()
seed_hybrid_inverter(connection.for_unit(1))
unit = connection.for_unit(1)
# Inside the identity block, so the whole component fails to read.
unit.fail_read(0x044D, ModbusConnectionError("identity unreachable"))
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=MOCK_HYBRID_SERIAL,
data=MOCK_USER_INPUT,
title=MOCK_HYBRID_MODEL,
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sofar.async_get_unit",
side_effect=lambda hass, entry, params, unit_id: mock_connection.for_unit(
unit_id
),
side_effect=lambda hass, entry, params, unit_id: connection.for_unit(unit_id),
):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
device = device_registry.async_get_device_by_identifier(
(DOMAIN, MOCK_SERIAL), mock_config_entry.entry_id
(DOMAIN, MOCK_HYBRID_SERIAL), entry.entry_id
)
assert device is not None
assert device.hw_version is None
@@ -259,7 +253,7 @@ async def test_device_versions_recover_without_a_reload(
await hass.async_block_till_done()
device = device_registry.async_get_device_by_identifier(
(DOMAIN, MOCK_SERIAL), mock_config_entry.entry_id
(DOMAIN, MOCK_HYBRID_SERIAL), entry.entry_id
)
assert device is not None
assert device.hw_version == MOCK_HW_VERSION
+24 -9
View File
@@ -98,13 +98,13 @@ async def test_sensor_entities_created_and_state(
@pytest.mark.parametrize(
("serial", "model", "seed", "created", "enabled"),
[
pytest.param(MOCK_SERIAL, MOCK_MODEL, seed_pv_inverter, 73, 23, id="pv"),
pytest.param(MOCK_SERIAL, MOCK_MODEL, seed_pv_inverter, 72, 22, id="pv"),
pytest.param(
MOCK_HYBRID_SERIAL,
MOCK_HYBRID_MODEL,
seed_hybrid_inverter,
139,
46,
138,
45,
id="hybrid",
),
],
@@ -155,15 +155,30 @@ async def test_enabled_by_default_partition(
async def test_settings_backed_sensor_created_and_state(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
init_integration: MockConfigEntry,
) -> None:
"""Test a settings-polled component reaches the sensor platform."""
serial_id = entity_registry.async_get_entity_id(
SENSOR_DOMAIN, "sofar", f"{MOCK_SERIAL}_serial_number"
connection = MockModbusConnection()
seed_hybrid_inverter(connection.for_unit(1))
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=MOCK_HYBRID_SERIAL,
data=MOCK_USER_INPUT,
title=MOCK_HYBRID_MODEL,
)
assert serial_id is not None
assert (state := hass.states.get(serial_id)) is not None
assert state.state == MOCK_SERIAL
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sofar.async_get_unit",
side_effect=lambda hass, entry, params, unit_id: connection.for_unit(unit_id),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
rtc_id = entity_registry.async_get_entity_id(
SENSOR_DOMAIN, "sofar", f"{MOCK_HYBRID_SERIAL}_sync_rtc_result"
)
assert rtc_id is not None
assert (state := hass.states.get(rtc_id)) is not None
assert state.state == "successful"
@pytest.mark.usefixtures("entity_registry_enabled_by_default")