Add learning offset select to Airgradient (#120532)

This commit is contained in:
Joost Lekkerkerker 2024-06-26 12:18:33 +02:00 committed by GitHub
parent d00fe1ce7f
commit fac8349c37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 489 additions and 29 deletions

View File

@ -79,6 +79,65 @@ LED_BAR_ENTITIES: tuple[AirGradientSelectEntityDescription, ...] = (
),
)
LEARNING_TIME_OFFSET_OPTIONS = {
12: "12",
60: "60",
120: "120",
360: "360",
720: "720",
}
LEARNING_TIME_OFFSET_OPTIONS_INVERSE = {
v: k for k, v in LEARNING_TIME_OFFSET_OPTIONS.items()
}
ABC_DAYS = {
8: "8",
30: "30",
90: "90",
180: "180",
0: "off",
}
ABC_DAYS_INVERSE = {v: k for k, v in ABC_DAYS.items()}
CONTROL_ENTITIES: tuple[AirGradientSelectEntityDescription, ...] = (
AirGradientSelectEntityDescription(
key="nox_index_learning_time_offset",
translation_key="nox_index_learning_time_offset",
options=list(LEARNING_TIME_OFFSET_OPTIONS_INVERSE),
entity_category=EntityCategory.CONFIG,
value_fn=lambda config: LEARNING_TIME_OFFSET_OPTIONS.get(
config.nox_learning_offset
),
set_value_fn=lambda client, value: client.set_nox_learning_offset(
LEARNING_TIME_OFFSET_OPTIONS_INVERSE.get(value, 12)
),
),
AirGradientSelectEntityDescription(
key="voc_index_learning_time_offset",
translation_key="voc_index_learning_time_offset",
options=list(LEARNING_TIME_OFFSET_OPTIONS_INVERSE),
entity_category=EntityCategory.CONFIG,
value_fn=lambda config: LEARNING_TIME_OFFSET_OPTIONS.get(
config.nox_learning_offset
),
set_value_fn=lambda client, value: client.set_tvoc_learning_offset(
LEARNING_TIME_OFFSET_OPTIONS_INVERSE.get(value, 12)
),
),
AirGradientSelectEntityDescription(
key="co2_automatic_baseline_calibration",
translation_key="co2_automatic_baseline_calibration",
options=list(ABC_DAYS_INVERSE),
entity_category=EntityCategory.CONFIG,
value_fn=lambda config: ABC_DAYS.get(
config.co2_automatic_baseline_calibration_days
),
set_value_fn=lambda client,
value: client.set_co2_automatic_baseline_calibration(
ABC_DAYS_INVERSE.get(value, 0)
),
),
)
async def async_setup_entry(
hass: HomeAssistant,
@ -104,7 +163,10 @@ async def async_setup_entry(
coordinator.data.configuration_control is ConfigurationControl.LOCAL
and not added_entities
):
entities: list[AirGradientSelect] = []
entities: list[AirGradientSelect] = [
AirGradientSelect(coordinator, description)
for description in CONTROL_ENTITIES
]
if "I" in model:
entities.extend(
AirGradientSelect(coordinator, description)
@ -123,7 +185,9 @@ async def async_setup_entry(
and added_entities
):
entity_registry = er.async_get(hass)
for entity_description in DISPLAY_SELECT_TYPES + LED_BAR_ENTITIES:
for entity_description in (
DISPLAY_SELECT_TYPES + LED_BAR_ENTITIES + CONTROL_ENTITIES
):
unique_id = f"{coordinator.serial_number}-{entity_description.key}"
if entity_id := entity_registry.async_get_entity_id(
SELECT_DOMAIN, DOMAIN, unique_id

View File

@ -69,6 +69,36 @@
"co2": "Carbon dioxide",
"pm": "Particulate matter"
}
},
"nox_index_learning_time_offset": {
"name": "NOx index learning offset",
"state": {
"12": "12 hours",
"60": "60 hours",
"120": "120 hours",
"360": "360 hours",
"720": "720 hours"
}
},
"voc_index_learning_time_offset": {
"name": "VOC index learning offset",
"state": {
"12": "[%key:component::airgradient::entity::select::nox_index_learning_time_offset::state::12%]",
"60": "[%key:component::airgradient::entity::select::nox_index_learning_time_offset::state::60%]",
"120": "[%key:component::airgradient::entity::select::nox_index_learning_time_offset::state::120%]",
"360": "[%key:component::airgradient::entity::select::nox_index_learning_time_offset::state::360%]",
"720": "[%key:component::airgradient::entity::select::nox_index_learning_time_offset::state::720%]"
}
},
"co2_automatic_baseline_calibration": {
"name": "CO2 automatic baseline calibration",
"state": {
"8": "8 days",
"30": "30 days",
"90": "90 days",
"180": "180 days",
"0": "[%key:common::state::off%]"
}
}
},
"sensor": {
@ -98,10 +128,10 @@
"name": "Carbon dioxide automatic baseline calibration"
},
"nox_learning_offset": {
"name": "NOx learning offset"
"name": "[%key:component::airgradient::entity::select::nox_index_learning_time_offset::name%]"
},
"tvoc_learning_offset": {
"name": "VOC learning offset"
"name": "[%key:component::airgradient::entity::select::voc_index_learning_time_offset::name%]"
},
"led_bar_mode": {
"name": "[%key:component::airgradient::entity::select::led_bar_mode::name%]",

View File

@ -1,4 +1,65 @@
# serializer version: 1
# name: test_all_entities[indoor][select.airgradient_co2_automatic_baseline_calibration-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'8',
'30',
'90',
'180',
'off',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.airgradient_co2_automatic_baseline_calibration',
'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': 'CO2 automatic baseline calibration',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'co2_automatic_baseline_calibration',
'unique_id': '84fce612f5b8-co2_automatic_baseline_calibration',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[indoor][select.airgradient_co2_automatic_baseline_calibration-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient CO2 automatic baseline calibration',
'options': list([
'8',
'30',
'90',
'180',
'off',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_co2_automatic_baseline_calibration',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '8',
})
# ---
# name: test_all_entities[indoor][select.airgradient_configuration_source-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -221,6 +282,189 @@
'state': 'co2',
})
# ---
# name: test_all_entities[indoor][select.airgradient_nox_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.airgradient_nox_index_learning_offset',
'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': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'nox_index_learning_time_offset',
'unique_id': '84fce612f5b8-nox_index_learning_time_offset',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[indoor][select.airgradient_nox_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient NOx index learning offset',
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_nox_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '12',
})
# ---
# name: test_all_entities[indoor][select.airgradient_voc_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.airgradient_voc_index_learning_offset',
'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': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'voc_index_learning_time_offset',
'unique_id': '84fce612f5b8-voc_index_learning_time_offset',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[indoor][select.airgradient_voc_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient VOC index learning offset',
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_voc_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '12',
})
# ---
# name: test_all_entities[outdoor][select.airgradient_co2_automatic_baseline_calibration-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'8',
'30',
'90',
'180',
'off',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.airgradient_co2_automatic_baseline_calibration',
'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': 'CO2 automatic baseline calibration',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'co2_automatic_baseline_calibration',
'unique_id': '84fce612f5b8-co2_automatic_baseline_calibration',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[outdoor][select.airgradient_co2_automatic_baseline_calibration-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient CO2 automatic baseline calibration',
'options': list([
'8',
'30',
'90',
'180',
'off',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_co2_automatic_baseline_calibration',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '8',
})
# ---
# name: test_all_entities[outdoor][select.airgradient_configuration_source-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -276,3 +520,125 @@
'state': 'local',
})
# ---
# name: test_all_entities[outdoor][select.airgradient_nox_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.airgradient_nox_index_learning_offset',
'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': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'nox_index_learning_time_offset',
'unique_id': '84fce612f5b8-nox_index_learning_time_offset',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[outdoor][select.airgradient_nox_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient NOx index learning offset',
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_nox_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '12',
})
# ---
# name: test_all_entities[outdoor][select.airgradient_voc_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.airgradient_voc_index_learning_offset',
'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': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'voc_index_learning_time_offset',
'unique_id': '84fce612f5b8-voc_index_learning_time_offset',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[outdoor][select.airgradient_voc_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient VOC index learning offset',
'options': list([
'12',
'60',
'120',
'360',
'720',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_voc_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '12',
})
# ---

View File

@ -462,7 +462,7 @@
'state': '1',
})
# ---
# name: test_all_entities[indoor][sensor.airgradient_nox_learning_offset-entry]
# name: test_all_entities[indoor][sensor.airgradient_nox_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@ -474,7 +474,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.airgradient_nox_learning_offset',
'entity_id': 'sensor.airgradient_nox_index_learning_offset',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@ -486,7 +486,7 @@
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'NOx learning offset',
'original_name': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
@ -495,15 +495,15 @@
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
})
# ---
# name: test_all_entities[indoor][sensor.airgradient_nox_learning_offset-state]
# name: test_all_entities[indoor][sensor.airgradient_nox_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Airgradient NOx learning offset',
'friendly_name': 'Airgradient NOx index learning offset',
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
}),
'context': <ANY>,
'entity_id': 'sensor.airgradient_nox_learning_offset',
'entity_id': 'sensor.airgradient_nox_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
@ -964,7 +964,7 @@
'state': '99',
})
# ---
# name: test_all_entities[indoor][sensor.airgradient_voc_learning_offset-entry]
# name: test_all_entities[indoor][sensor.airgradient_voc_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@ -976,7 +976,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.airgradient_voc_learning_offset',
'entity_id': 'sensor.airgradient_voc_index_learning_offset',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@ -988,7 +988,7 @@
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'VOC learning offset',
'original_name': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
@ -997,15 +997,15 @@
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
})
# ---
# name: test_all_entities[indoor][sensor.airgradient_voc_learning_offset-state]
# name: test_all_entities[indoor][sensor.airgradient_voc_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Airgradient VOC learning offset',
'friendly_name': 'Airgradient VOC index learning offset',
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
}),
'context': <ANY>,
'entity_id': 'sensor.airgradient_voc_learning_offset',
'entity_id': 'sensor.airgradient_voc_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
@ -1109,7 +1109,7 @@
'state': '1',
})
# ---
# name: test_all_entities[outdoor][sensor.airgradient_nox_learning_offset-entry]
# name: test_all_entities[outdoor][sensor.airgradient_nox_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@ -1121,7 +1121,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.airgradient_nox_learning_offset',
'entity_id': 'sensor.airgradient_nox_index_learning_offset',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@ -1133,7 +1133,7 @@
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'NOx learning offset',
'original_name': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
@ -1142,15 +1142,15 @@
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
})
# ---
# name: test_all_entities[outdoor][sensor.airgradient_nox_learning_offset-state]
# name: test_all_entities[outdoor][sensor.airgradient_nox_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Airgradient NOx learning offset',
'friendly_name': 'Airgradient NOx index learning offset',
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
}),
'context': <ANY>,
'entity_id': 'sensor.airgradient_nox_learning_offset',
'entity_id': 'sensor.airgradient_nox_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
@ -1357,7 +1357,7 @@
'state': '49',
})
# ---
# name: test_all_entities[outdoor][sensor.airgradient_voc_learning_offset-entry]
# name: test_all_entities[outdoor][sensor.airgradient_voc_index_learning_offset-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@ -1369,7 +1369,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.airgradient_voc_learning_offset',
'entity_id': 'sensor.airgradient_voc_index_learning_offset',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@ -1381,7 +1381,7 @@
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'VOC learning offset',
'original_name': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
@ -1390,15 +1390,15 @@
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
})
# ---
# name: test_all_entities[outdoor][sensor.airgradient_voc_learning_offset-state]
# name: test_all_entities[outdoor][sensor.airgradient_voc_index_learning_offset-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Airgradient VOC learning offset',
'friendly_name': 'Airgradient VOC index learning offset',
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
}),
'context': <ANY>,
'entity_id': 'sensor.airgradient_voc_learning_offset',
'entity_id': 'sensor.airgradient_voc_index_learning_offset',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,

View File

@ -83,7 +83,7 @@ async def test_cloud_creates_no_number(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 4
assert len(hass.states.async_all()) == 7
mock_cloud_airgradient_client.get_config.return_value = Config.from_json(
load_fixture("get_config_cloud.json", DOMAIN)