1 """Support for airthings ble sensors."""
3 from __future__
import annotations
8 from airthings_ble
import AirthingsDevice
13 SensorEntityDescription,
17 CONCENTRATION_PARTS_PER_BILLION,
18 CONCENTRATION_PARTS_PER_MILLION,
31 async_entries_for_device,
37 from .const
import DOMAIN, VOLUME_BECQUEREL, VOLUME_PICOCURIE
38 from .coordinator
import AirthingsBLEConfigEntry, AirthingsBLEDataUpdateCoordinator
40 _LOGGER = logging.getLogger(__name__)
42 SENSORS_MAPPING_TEMPLATE: dict[str, SensorEntityDescription] = {
45 translation_key=
"radon_1day_avg",
46 native_unit_of_measurement=VOLUME_BECQUEREL,
47 suggested_display_precision=0,
48 state_class=SensorStateClass.MEASUREMENT,
51 key=
"radon_longterm_avg",
52 translation_key=
"radon_longterm_avg",
53 native_unit_of_measurement=VOLUME_BECQUEREL,
54 suggested_display_precision=0,
55 state_class=SensorStateClass.MEASUREMENT,
58 key=
"radon_1day_level",
59 translation_key=
"radon_1day_level",
62 key=
"radon_longterm_level",
63 translation_key=
"radon_longterm_level",
67 device_class=SensorDeviceClass.TEMPERATURE,
68 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
69 state_class=SensorStateClass.MEASUREMENT,
73 device_class=SensorDeviceClass.HUMIDITY,
74 native_unit_of_measurement=PERCENTAGE,
75 state_class=SensorStateClass.MEASUREMENT,
79 device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
80 native_unit_of_measurement=UnitOfPressure.MBAR,
81 state_class=SensorStateClass.MEASUREMENT,
85 device_class=SensorDeviceClass.BATTERY,
86 native_unit_of_measurement=PERCENTAGE,
87 state_class=SensorStateClass.MEASUREMENT,
88 entity_category=EntityCategory.DIAGNOSTIC,
92 device_class=SensorDeviceClass.CO2,
93 native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
94 state_class=SensorStateClass.MEASUREMENT,
98 device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
99 native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
100 state_class=SensorStateClass.MEASUREMENT,
104 translation_key=
"illuminance",
105 native_unit_of_measurement=PERCENTAGE,
106 state_class=SensorStateClass.MEASUREMENT,
112 def async_migrate(hass: HomeAssistant, address: str, sensor_name: str) ->
None:
113 """Migrate entities to new unique ids (with BLE Address)."""
114 ent_reg = er.async_get(hass)
115 unique_id_trailer = f
"_{sensor_name}"
116 new_unique_id = f
"{address}{unique_id_trailer}"
117 if ent_reg.async_get_entity_id(DOMAIN, Platform.SENSOR, new_unique_id):
120 dev_reg = dr.async_get(hass)
122 device := dev_reg.async_get_device(
123 connections={(CONNECTION_BLUETOOTH, address)}
130 include_disabled_entities=
True,
132 matching_reg_entry: RegistryEntry |
None =
None
133 for entry
in entities:
134 if entry.unique_id.endswith(unique_id_trailer)
and (
135 not matching_reg_entry
or "(" not in entry.unique_id
137 matching_reg_entry = entry
138 if not matching_reg_entry
or matching_reg_entry.unique_id == new_unique_id:
141 entity_id = matching_reg_entry.entity_id
142 ent_reg.async_update_entity(entity_id=entity_id, new_unique_id=new_unique_id)
143 _LOGGER.debug(
"Migrated entity '%s' to unique id '%s'", entity_id, new_unique_id)
148 entry: AirthingsBLEConfigEntry,
149 async_add_entities: AddEntitiesCallback,
151 """Set up the Airthings BLE sensors."""
152 is_metric = hass.config.units
is METRIC_SYSTEM
154 coordinator = entry.runtime_data
157 sensors_mapping = SENSORS_MAPPING_TEMPLATE.copy()
159 for key, val
in sensors_mapping.items():
160 if val.native_unit_of_measurement
is not VOLUME_BECQUEREL:
162 sensors_mapping[key] = dataclasses.replace(
164 native_unit_of_measurement=VOLUME_PICOCURIE,
165 suggested_display_precision=1,
169 _LOGGER.debug(
"got sensors: %s", coordinator.data.sensors)
170 for sensor_type, sensor_value
in coordinator.data.sensors.items():
171 if sensor_type
not in sensors_mapping:
173 "Unknown sensor type detected: %s, %s",
180 AirthingsSensor(coordinator, coordinator.data, sensors_mapping[sensor_type])
187 CoordinatorEntity[AirthingsBLEDataUpdateCoordinator], SensorEntity
189 """Airthings BLE sensors for the device."""
191 _attr_has_entity_name =
True
195 coordinator: AirthingsBLEDataUpdateCoordinator,
196 airthings_device: AirthingsDevice,
197 entity_description: SensorEntityDescription,
199 """Populate the airthings entity with relevant data."""
203 name = airthings_device.name
204 if identifier := airthings_device.identifier:
205 name += f
" ({identifier})"
207 self.
_attr_unique_id_attr_unique_id = f
"{airthings_device.address}_{entity_description.key}"
211 CONNECTION_BLUETOOTH,
212 airthings_device.address,
216 manufacturer=airthings_device.manufacturer,
217 hw_version=airthings_device.hw_version,
218 sw_version=airthings_device.sw_version,
219 model=airthings_device.model.product_name,
224 """Check if device and sensor is available in data."""
232 """Return the value reported by the sensor."""
StateType native_value(self)
None __init__(self, AirthingsBLEDataUpdateCoordinator coordinator, AirthingsDevice airthings_device, SensorEntityDescription entity_description)
None async_setup_entry(HomeAssistant hass, AirthingsBLEConfigEntry entry, AddEntitiesCallback async_add_entities)
None async_migrate(HomeAssistant hass, str address, str sensor_name)
list[RegistryEntry] async_entries_for_device(EntityRegistry registry, str device_id, bool include_disabled_entities=False)