mirror of
https://github.com/home-assistant/core.git
synced 2026-06-29 01:55:20 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1887a94ca0 |
Generated
+1
@@ -1986,6 +1986,7 @@ CLAUDE.md @home-assistant/core
|
||||
/tests/components/waterfurnace/ @sdague @masterkoppa
|
||||
/homeassistant/components/watergate/ @adam-the-hero
|
||||
/tests/components/watergate/ @adam-the-hero
|
||||
/homeassistant/components/watson_tts/ @rutkai
|
||||
/homeassistant/components/watts/ @theobld-ww @devender-verma-ww @ssi-spyro
|
||||
/tests/components/watts/ @theobld-ww @devender-verma-ww @ssi-spyro
|
||||
/homeassistant/components/watttime/ @bachya
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
"azure_event_hub",
|
||||
"azure_service_bus",
|
||||
"azure_storage",
|
||||
"microsoft_face_detect",
|
||||
"microsoft_face_identify",
|
||||
"microsoft_face",
|
||||
"microsoft",
|
||||
"onedrive",
|
||||
"onedrive_for_business",
|
||||
|
||||
@@ -12,7 +12,7 @@ from homeassistant.components.number import (
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory, UnitOfRatio
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -40,7 +40,7 @@ DISPLAY_BRIGHTNESS = AirGradientNumberEntityDescription(
|
||||
native_min_value=0,
|
||||
native_max_value=100,
|
||||
native_step=1,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda config: config.display_brightness,
|
||||
set_value_fn=lambda client, value: client.set_display_brightness(value),
|
||||
)
|
||||
@@ -52,7 +52,7 @@ LED_BAR_BRIGHTNESS = AirGradientNumberEntityDescription(
|
||||
native_min_value=0,
|
||||
native_max_value=100,
|
||||
native_step=1,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda config: config.led_bar_brightness,
|
||||
set_value_fn=lambda client, value: client.set_led_bar_brightness(value),
|
||||
)
|
||||
|
||||
@@ -19,10 +19,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -56,21 +57,21 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="pm01",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.pm01,
|
||||
),
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="pm02",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.pm02,
|
||||
),
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="pm10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.pm10,
|
||||
),
|
||||
@@ -84,7 +85,7 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.relative_humidity,
|
||||
),
|
||||
@@ -112,7 +113,7 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.rco2,
|
||||
),
|
||||
@@ -143,7 +144,7 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
key="pm02_raw",
|
||||
translation_key="raw_pm02",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda status: status.raw_pm02,
|
||||
@@ -189,7 +190,7 @@ CONFIG_LED_BAR_SENSOR_TYPES: tuple[AirGradientConfigSensorEntityDescription, ...
|
||||
AirGradientConfigSensorEntityDescription(
|
||||
key="led_bar_brightness",
|
||||
translation_key="led_bar_brightness",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
value_fn=lambda config: config.led_bar_brightness,
|
||||
),
|
||||
@@ -215,9 +216,9 @@ CONFIG_DISPLAY_SENSOR_TYPES: tuple[AirGradientConfigSensorEntityDescription, ...
|
||||
AirGradientConfigSensorEntityDescription(
|
||||
key="display_brightness",
|
||||
translation_key="display_brightness",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
value_fn=lambda config: config.led_bar_brightness,
|
||||
value_fn=lambda config: config.display_brightness,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -58,7 +59,7 @@ SENSOR_TYPES: tuple[AirobotSensorEntityDescription, ...] = (
|
||||
AirobotSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.hum_air,
|
||||
),
|
||||
@@ -74,7 +75,7 @@ SENSOR_TYPES: tuple[AirobotSensorEntityDescription, ...] = (
|
||||
AirobotSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.co2,
|
||||
supported_fn=lambda status: status.has_co2_sensor,
|
||||
|
||||
@@ -11,12 +11,14 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -47,7 +49,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"humidity": SensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
@@ -68,7 +70,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"battery": SensorEntityDescription(
|
||||
key="battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
@@ -76,20 +78,20 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"co2": SensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"voc": SensorEntityDescription(
|
||||
key="voc",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"light": SensorEntityDescription(
|
||||
key="light",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key="light",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
@@ -124,14 +126,14 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"pm1": SensorEntityDescription(
|
||||
key="pm1",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"pm25": SensorEntityDescription(
|
||||
key="pm25",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
|
||||
@@ -12,13 +12,14 @@ from homeassistant.const import (
|
||||
ATTR_LATITUDE,
|
||||
ATTR_LONGITUDE,
|
||||
ATTR_STATE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_COUNTRY,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_SHOW_ON_MAP,
|
||||
CONF_STATE,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -93,12 +94,12 @@ POLLUTANT_LEVELS = {
|
||||
}
|
||||
|
||||
POLLUTANT_UNITS = {
|
||||
"co": UnitOfRatio.PARTS_PER_MILLION,
|
||||
"n2": UnitOfRatio.PARTS_PER_BILLION,
|
||||
"o3": UnitOfRatio.PARTS_PER_BILLION,
|
||||
"p1": UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
"p2": UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
"s2": UnitOfRatio.PARTS_PER_BILLION,
|
||||
"co": CONCENTRATION_PARTS_PER_MILLION,
|
||||
"n2": CONCENTRATION_PARTS_PER_BILLION,
|
||||
"o3": CONCENTRATION_PARTS_PER_BILLION,
|
||||
"p1": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
"p2": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
"s2": CONCENTRATION_PARTS_PER_BILLION,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -56,21 +57,21 @@ SENSOR_DESCRIPTIONS = (
|
||||
key="battery_level",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: status["battery"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="carbon_dioxide",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["co2"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements[
|
||||
"humidity"
|
||||
@@ -79,21 +80,21 @@ SENSOR_DESCRIPTIONS = (
|
||||
AirVisualProMeasurementDescription(
|
||||
key="particulate_matter_0_1",
|
||||
translation_key="pm01",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["pm0_1"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="particulate_matter_1_0",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["pm1_0"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="particulate_matter_2_5",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["pm2_5"],
|
||||
),
|
||||
@@ -109,7 +110,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
AirVisualProMeasurementDescription(
|
||||
key="voc",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["voc"],
|
||||
),
|
||||
|
||||
@@ -35,13 +35,13 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfInformation,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -141,7 +141,7 @@ WEBSERVER_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
key=AZD_CPU_USAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="cpu_usage",
|
||||
),
|
||||
@@ -172,19 +172,19 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
key=AZD_AQ_PM_1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
key=AZD_AQ_PM_2P5,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
key=AZD_AQ_PM_10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
@@ -196,20 +196,20 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key=AZD_HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
key=AZD_THERMOSTAT_BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
key=AZD_THERMOSTAT_COVERAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="thermostat_coverage",
|
||||
),
|
||||
|
||||
@@ -18,7 +18,13 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import LIGHT_LUX, UnitOfDensity, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
@@ -91,25 +97,25 @@ SENSORS: Final = (
|
||||
AmazonSensorEntityDescription(
|
||||
key="Humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
key="PM10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
key="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
key="CO",
|
||||
device_class=SensorDeviceClass.CO,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
|
||||
@@ -12,11 +12,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -44,7 +45,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="BME280_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "BME280"},
|
||||
),
|
||||
@@ -69,7 +70,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="BME680_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "BME680"},
|
||||
),
|
||||
@@ -128,7 +129,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="HTU21D_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "HTU21D"},
|
||||
),
|
||||
@@ -144,21 +145,21 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
translation_key="pm_10",
|
||||
key="SDS_P1",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
suggested_display_precision=2,
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
translation_key="pm_25",
|
||||
key="SDS_P2",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
suggested_display_precision=2,
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="SHT3X_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "SHT3X"},
|
||||
),
|
||||
@@ -193,7 +194,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
translation_key="co2",
|
||||
key="CCS_CO2",
|
||||
suggested_display_precision=2,
|
||||
@@ -202,7 +203,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
key="CCS_TVOC",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
suggested_display_precision=2,
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
@@ -214,7 +215,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
translation_key="co2",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
key="SCD4x_co2",
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "SCD4x"},
|
||||
|
||||
@@ -10,14 +10,15 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_MAC,
|
||||
DEGREE,
|
||||
UnitOfDensity,
|
||||
PERCENTAGE,
|
||||
UnitOfIrradiance,
|
||||
UnitOfLength,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumetricFlux,
|
||||
@@ -93,7 +94,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=2,
|
||||
@@ -133,7 +134,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
@@ -187,14 +188,14 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_24H,
|
||||
translation_key="pm25_24h_average",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
suggested_display_precision=1,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
|
||||
@@ -23,9 +23,10 @@ from homeassistant.const import (
|
||||
ATTR_MODEL,
|
||||
ATTR_NAME,
|
||||
ATTR_SW_VERSION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -61,7 +62,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="humidity",
|
||||
name="Humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"pressure": AranetSensorEntityDescription(
|
||||
@@ -82,7 +83,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="co2",
|
||||
name="Carbon Dioxide",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"radiation_rate": AranetSensorEntityDescription(
|
||||
@@ -114,7 +115,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="battery",
|
||||
name="Battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
|
||||
@@ -12,7 +12,12 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import UnitOfDensity, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -30,7 +35,7 @@ class ArveDeviceEntityDescription(SensorEntityDescription):
|
||||
SENSORS: tuple[ArveDeviceEntityDescription, ...] = (
|
||||
ArveDeviceEntityDescription(
|
||||
key="CO2",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
value_fn=lambda arve_data: arve_data.co2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -43,21 +48,21 @@ SENSORS: tuple[ArveDeviceEntityDescription, ...] = (
|
||||
),
|
||||
ArveDeviceEntityDescription(
|
||||
key="Humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
value_fn=lambda arve_data: arve_data.humidity,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ArveDeviceEntityDescription(
|
||||
key="PM10",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
value_fn=lambda arve_data: arve_data.pm10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ArveDeviceEntityDescription(
|
||||
key="PM25",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
value_fn=lambda arve_data: arve_data.pm25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
|
||||
@@ -16,9 +16,12 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_CONNECTIONS,
|
||||
ATTR_SW_VERSION,
|
||||
CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
PERCENTAGE,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -58,7 +61,7 @@ class AwairSensorEntityDescription(SensorEntityDescription):
|
||||
|
||||
SENSOR_TYPE_SCORE = AwairSensorEntityDescription(
|
||||
key=API_SCORE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key="score",
|
||||
unique_id_tag="score", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -68,7 +71,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_HUMID,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
unique_id_tag="HUMID", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -90,7 +93,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_VOC,
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
unique_id_tag="VOC", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -104,7 +107,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_CO2,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
unique_id_tag="CO2", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -120,7 +123,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_ABS_HUMID,
|
||||
device_class=SensorDeviceClass.ABSOLUTE_HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfDensity.GRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
unique_id_tag="absolute_humidity",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
@@ -131,14 +134,14 @@ SENSOR_TYPES_DUST: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_PM25,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
unique_id_tag="PM25", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AwairSensorEntityDescription(
|
||||
key=API_PM10,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
unique_id_tag="PM10", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"""The BlinkStick integration."""
|
||||
@@ -0,0 +1,87 @@
|
||||
"""Support for BlinkStick lights."""
|
||||
|
||||
# mypy: ignore-errors
|
||||
from typing import Any
|
||||
|
||||
# from blinkstick import blinkstick
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_HS_COLOR,
|
||||
PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA,
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import color as color_util
|
||||
|
||||
CONF_SERIAL = "serial"
|
||||
|
||||
DEFAULT_NAME = "Blinkstick"
|
||||
|
||||
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SERIAL): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up BlinkStick device specified by serial number."""
|
||||
|
||||
name = config[CONF_NAME]
|
||||
serial = config[CONF_SERIAL]
|
||||
|
||||
stick = blinkstick.find_by_serial(serial)
|
||||
|
||||
add_entities([BlinkStickLight(stick, name)], True)
|
||||
|
||||
|
||||
class BlinkStickLight(LightEntity):
|
||||
"""Representation of a BlinkStick light."""
|
||||
|
||||
_attr_color_mode = ColorMode.HS
|
||||
_attr_supported_color_modes = {ColorMode.HS}
|
||||
|
||||
def __init__(self, stick, name):
|
||||
"""Initialize the light."""
|
||||
self._stick = stick
|
||||
self._attr_name = name
|
||||
|
||||
def update(self) -> None:
|
||||
"""Read back the device state."""
|
||||
rgb_color = self._stick.get_color()
|
||||
hsv = color_util.color_RGB_to_hsv(*rgb_color)
|
||||
self._attr_hs_color = hsv[:2]
|
||||
self._attr_brightness = int(hsv[2])
|
||||
self._attr_is_on = self.brightness is not None and self.brightness > 0
|
||||
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
if ATTR_HS_COLOR in kwargs:
|
||||
self._attr_hs_color = kwargs[ATTR_HS_COLOR]
|
||||
|
||||
brightness: int = kwargs.get(ATTR_BRIGHTNESS, 255)
|
||||
self._attr_brightness = brightness
|
||||
self._attr_is_on = bool(brightness)
|
||||
|
||||
assert self.hs_color
|
||||
rgb_color = color_util.color_hsv_to_RGB(
|
||||
self.hs_color[0], self.hs_color[1], brightness / 255 * 100
|
||||
)
|
||||
self._stick.set_color(red=rgb_color[0], green=rgb_color[1], blue=rgb_color[2])
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
self._stick.turn_off()
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"domain": "blinksticklight",
|
||||
"name": "BlinkStick",
|
||||
"codeowners": [],
|
||||
"disabled": "This integration is disabled because it uses non-open source code to operate.",
|
||||
"documentation": "https://www.home-assistant.io/integrations/blinksticklight",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["blinkstick"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["BlinkStick==1.2.0"]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
extend = "../../../pyproject.toml"
|
||||
|
||||
lint.extend-ignore = [
|
||||
"F821"
|
||||
]
|
||||
@@ -13,9 +13,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -57,13 +58,13 @@ SENSOR_DESCRIPTIONS: dict[str, SHCSensorEntityDescription] = {
|
||||
HUMIDITY_SENSOR: SHCSensorEntityDescription(
|
||||
key=HUMIDITY_SENSOR,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda device: device.humidity,
|
||||
),
|
||||
PURITY_SENSOR: SHCSensorEntityDescription(
|
||||
key=PURITY_SENSOR,
|
||||
translation_key=PURITY_SENSOR,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
value_fn=lambda device: device.purity,
|
||||
),
|
||||
AIR_QUALITY_SENSOR: SHCSensorEntityDescription(
|
||||
@@ -111,7 +112,7 @@ SENSOR_DESCRIPTIONS: dict[str, SHCSensorEntityDescription] = {
|
||||
key=VALVE_TAPPET_SENSOR,
|
||||
translation_key=VALVE_TAPPET_SENSOR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda device: device.position,
|
||||
attributes_fn=lambda device: {
|
||||
"valve_tappet_state": device.valvestate.name,
|
||||
|
||||
@@ -10,12 +10,12 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
UnitOfDensity,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -37,25 +37,25 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="pm10",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="pm2_5",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="pm1",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["bsblan"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["python-bsblan==6.1.4"],
|
||||
"requirements": ["python-bsblan==6.1.3"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"name": "bsb-lan*",
|
||||
|
||||
@@ -18,13 +18,15 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
REVOLUTIONS_PER_MINUTE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfConductivity,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
@@ -32,7 +34,6 @@ from homeassistant.const import (
|
||||
UnitOfMass,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
@@ -62,7 +63,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(BTHomeSensorDeviceClass.BATTERY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.BATTERY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
@@ -95,7 +96,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Current (Ampere)
|
||||
@@ -181,7 +182,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(BTHomeSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Illuminance (lux)
|
||||
@@ -215,7 +216,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(BTHomeSensorDeviceClass.MOISTURE, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.MOISTURE}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.MOISTURE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Packet Id (-)
|
||||
@@ -233,7 +234,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.PM10}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# PM2.5 (μg/m3)
|
||||
@@ -243,7 +244,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.PM25}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Power (Watt)
|
||||
@@ -356,7 +357,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Voltage (volt)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"""The clementine component."""
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "clementine",
|
||||
"name": "Clementine Music Player",
|
||||
"codeowners": [],
|
||||
"documentation": "https://www.home-assistant.io/integrations/clementine",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["clementineremote"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["python-clementine-remote==1.0.1"]
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
"""Support for Clementine Music Player as media player."""
|
||||
|
||||
from datetime import timedelta
|
||||
import time
|
||||
from typing import override
|
||||
|
||||
from clementineremote import ClementineRemote
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA,
|
||||
MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
MediaPlayerState,
|
||||
MediaType,
|
||||
)
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, CONF_NAME, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
DEFAULT_NAME = "Clementine Remote"
|
||||
DEFAULT_PORT = 5500
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=5)
|
||||
|
||||
PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_ACCESS_TOKEN): cv.positive_int,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Clementine platform."""
|
||||
|
||||
host = config[CONF_HOST]
|
||||
port = config[CONF_PORT]
|
||||
token = config.get(CONF_ACCESS_TOKEN)
|
||||
|
||||
client = ClementineRemote(host, port, token, reconnect=True)
|
||||
|
||||
add_entities([ClementineDevice(client, config[CONF_NAME])])
|
||||
|
||||
|
||||
class ClementineDevice(MediaPlayerEntity):
|
||||
"""Representation of Clementine Player."""
|
||||
|
||||
_attr_media_content_type = MediaType.MUSIC
|
||||
_attr_supported_features = (
|
||||
MediaPlayerEntityFeature.PAUSE
|
||||
| MediaPlayerEntityFeature.VOLUME_STEP
|
||||
| MediaPlayerEntityFeature.PREVIOUS_TRACK
|
||||
| MediaPlayerEntityFeature.VOLUME_SET
|
||||
| MediaPlayerEntityFeature.NEXT_TRACK
|
||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||
| MediaPlayerEntityFeature.PLAY
|
||||
)
|
||||
_attr_volume_step = 0.04
|
||||
|
||||
def __init__(self, client, name):
|
||||
"""Initialize the Clementine device."""
|
||||
self._client = client
|
||||
self._attr_name = name
|
||||
|
||||
def update(self) -> None:
|
||||
"""Retrieve the latest data from the Clementine Player."""
|
||||
try:
|
||||
client = self._client
|
||||
|
||||
if client.state == "Playing":
|
||||
self._attr_state = MediaPlayerState.PLAYING
|
||||
elif client.state == "Paused":
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
elif client.state == "Disconnected":
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
else:
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
|
||||
if client.last_update and (time.time() - client.last_update > 40):
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
|
||||
volume = float(client.volume) if client.volume else 0.0
|
||||
self._attr_volume_level = volume / 100.0
|
||||
if client.active_playlist_id in client.playlists:
|
||||
self._attr_source = client.playlists[client.active_playlist_id]["name"]
|
||||
else:
|
||||
self._attr_source = "Unknown"
|
||||
self._attr_source_list = [s["name"] for s in client.playlists.values()]
|
||||
|
||||
if client.current_track:
|
||||
self._attr_media_title = client.current_track["title"]
|
||||
self._attr_media_artist = client.current_track["track_artist"]
|
||||
self._attr_media_album_name = client.current_track["track_album"]
|
||||
self._attr_media_image_hash = client.current_track["track_id"]
|
||||
else:
|
||||
self._attr_media_image_hash = None
|
||||
|
||||
except Exception:
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
raise
|
||||
|
||||
@override
|
||||
def select_source(self, source: str) -> None:
|
||||
"""Select input source."""
|
||||
client = self._client
|
||||
sources = [s for s in client.playlists.values() if s["name"] == source]
|
||||
if len(sources) == 1:
|
||||
client.change_song(sources[0]["id"], 0)
|
||||
|
||||
@override
|
||||
async def async_get_media_image(self) -> tuple[bytes | None, str | None]:
|
||||
"""Fetch media image of current playing image."""
|
||||
if self._client.current_track:
|
||||
image = bytes(self._client.current_track["art"])
|
||||
return (image, "image/png")
|
||||
|
||||
return None, None
|
||||
|
||||
@override
|
||||
def mute_volume(self, mute: bool) -> None:
|
||||
"""Send mute command."""
|
||||
self._client.set_volume(0)
|
||||
|
||||
@override
|
||||
def set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level."""
|
||||
self._client.set_volume(int(100 * volume))
|
||||
|
||||
def media_play_pause(self) -> None:
|
||||
"""Simulate play pause media player."""
|
||||
if self.state == MediaPlayerState.PLAYING:
|
||||
self.media_pause()
|
||||
else:
|
||||
self.media_play()
|
||||
|
||||
@override
|
||||
def media_play(self) -> None:
|
||||
"""Send play command."""
|
||||
self._attr_state = MediaPlayerState.PLAYING
|
||||
self._client.play()
|
||||
|
||||
@override
|
||||
def media_pause(self) -> None:
|
||||
"""Send media pause command to media player."""
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
self._client.pause()
|
||||
|
||||
@override
|
||||
def media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
self._client.next()
|
||||
|
||||
@override
|
||||
def media_previous_track(self) -> None:
|
||||
"""Send the previous track command."""
|
||||
self._client.previous()
|
||||
@@ -13,11 +13,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
UnitOfDensity,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -116,7 +117,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
CompitParameter.BOILER_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.BOILER_TEMPERATURE.value,
|
||||
@@ -203,14 +204,14 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
CompitParameter.CO2_PERCENT: SensorEntityDescription(
|
||||
key=CompitParameter.CO2_PERCENT.value,
|
||||
translation_key="co2_percent",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
CompitParameter.COLLECTOR_POWER: SensorEntityDescription(
|
||||
key=CompitParameter.COLLECTOR_POWER.value,
|
||||
@@ -289,7 +290,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
translation_key="fuel_level",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
CompitParameter.HEATING1_TARGET_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.HEATING1_TARGET_TEMPERATURE.value,
|
||||
@@ -332,7 +333,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
CompitParameter.LOWER_SOURCE_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.LOWER_SOURCE_TEMPERATURE.value,
|
||||
@@ -400,14 +401,14 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PM4_LEVEL_MEASURED: SensorEntityDescription(
|
||||
key=CompitParameter.PM4_LEVEL_MEASURED.value,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
device_class=SensorDeviceClass.PM4,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PM10_LEVEL: SensorEntityDescription(
|
||||
key=CompitParameter.PM10_LEVEL.value,
|
||||
@@ -421,7 +422,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
key=CompitParameter.PM10_MEASURED.value,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PM25_LEVEL: SensorEntityDescription(
|
||||
key=CompitParameter.PM25_LEVEL.value,
|
||||
@@ -435,7 +436,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
key=CompitParameter.PM25_MEASURED.value,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PROTECTION_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.PROTECTION_TEMPERATURE.value,
|
||||
|
||||
@@ -35,13 +35,15 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import (
|
||||
ATTR_TEMPERATURE,
|
||||
ATTR_VOLTAGE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -136,7 +138,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="PPB",
|
||||
old_unique_id_suffix="ppb",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
),
|
||||
DeconzSensorDescription[AirQuality](
|
||||
key="air_quality_formaldehyde",
|
||||
@@ -147,7 +149,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="CH2O",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
DeconzSensorDescription[AirQuality](
|
||||
key="air_quality_co2",
|
||||
@@ -158,7 +160,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="CO2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
DeconzSensorDescription[AirQuality](
|
||||
key="air_quality_pm2_5",
|
||||
@@ -169,7 +171,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
DeconzSensorDescription[CarbonDioxide](
|
||||
key="carbon_dioxide",
|
||||
@@ -179,7 +181,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=CarbonDioxide,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
),
|
||||
DeconzSensorDescription[Consumption](
|
||||
key="consumption",
|
||||
@@ -208,7 +210,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=Formaldehyde,
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
),
|
||||
DeconzSensorDescription[GenericStatus](
|
||||
key="status",
|
||||
@@ -225,7 +227,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=Humidity,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
DeconzSensorDescription[LightLevel](
|
||||
@@ -246,7 +248,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=Moisture,
|
||||
device_class=SensorDeviceClass.MOISTURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
DeconzSensorDescription[ParticulateMatter](
|
||||
@@ -258,7 +260,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
DeconzSensorDescription[Power](
|
||||
key="power",
|
||||
@@ -308,7 +310,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
old_unique_id_suffix="battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
DeconzSensorDescription[SensorResources](
|
||||
|
||||
@@ -12,10 +12,11 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
)
|
||||
@@ -51,7 +52,7 @@ async def async_setup_entry(
|
||||
12,
|
||||
SensorDeviceClass.BATTERY,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
UnitOfRatio.PERCENTAGE,
|
||||
PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_name="Battery",
|
||||
),
|
||||
@@ -62,7 +63,7 @@ async def async_setup_entry(
|
||||
54,
|
||||
SensorDeviceClass.HUMIDITY,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
UnitOfRatio.PERCENTAGE,
|
||||
PERCENTAGE,
|
||||
),
|
||||
DemoSensor(
|
||||
"sensor_3",
|
||||
@@ -71,7 +72,7 @@ async def async_setup_entry(
|
||||
54,
|
||||
SensorDeviceClass.CO,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
UnitOfRatio.PARTS_PER_MILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
DemoSensor(
|
||||
"sensor_4",
|
||||
@@ -80,7 +81,7 @@ async def async_setup_entry(
|
||||
54,
|
||||
SensorDeviceClass.CO2,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
UnitOfRatio.PARTS_PER_MILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
DemoSensor(
|
||||
"battery_4",
|
||||
@@ -89,7 +90,7 @@ async def async_setup_entry(
|
||||
99,
|
||||
SensorDeviceClass.BATTERY,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
UnitOfRatio.PERCENTAGE,
|
||||
PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_name="Battery",
|
||||
),
|
||||
|
||||
@@ -12,10 +12,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
TEMPERATURE,
|
||||
EntityCategory,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
UnitOfVolumeFlowRate,
|
||||
@@ -140,7 +141,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=BATTERY,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
suggested_display_precision=0,
|
||||
value_fn=lambda device: device.drop_api.battery(),
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -157,7 +158,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=INLET_TDS,
|
||||
translation_key=INLET_TDS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
value_fn=lambda device: device.drop_api.inlet_tds(),
|
||||
@@ -165,7 +166,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=OUTLET_TDS,
|
||||
translation_key=OUTLET_TDS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
value_fn=lambda device: device.drop_api.outlet_tds(),
|
||||
@@ -173,7 +174,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=CARTRIDGE_1_LIFE,
|
||||
translation_key=CARTRIDGE_1_LIFE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
@@ -182,7 +183,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=CARTRIDGE_2_LIFE,
|
||||
translation_key=CARTRIDGE_2_LIFE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
@@ -191,7 +192,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=CARTRIDGE_3_LIFE,
|
||||
translation_key=CARTRIDGE_3_LIFE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
|
||||
@@ -11,7 +11,12 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import UnitOfDensity, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -37,14 +42,14 @@ SENSOR_TYPES: tuple[EcobeeSensorEntityDescription, ...] = (
|
||||
),
|
||||
EcobeeSensorEntityDescription(
|
||||
key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
runtime_key=None,
|
||||
),
|
||||
EcobeeSensorEntityDescription(
|
||||
key="co2PPM",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
runtime_key="actualCO2",
|
||||
@@ -52,7 +57,7 @@ SENSOR_TYPES: tuple[EcobeeSensorEntityDescription, ...] = (
|
||||
EcobeeSensorEntityDescription(
|
||||
key="vocPPM",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
runtime_key="actualVOC",
|
||||
),
|
||||
|
||||
@@ -9,16 +9,17 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_URL,
|
||||
PERCENTAGE,
|
||||
UnitOfApparentPower,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfFrequency,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
@@ -157,19 +158,19 @@ SENSORS: dict[str | None, SensorEntityDescription] = {
|
||||
"μg/m³": SensorEntityDescription(
|
||||
key="concentration|microgram_per_cubic_meter",
|
||||
translation_key="concentration",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"ppm": SensorEntityDescription(
|
||||
key="concentration|microgram_parts_per_million",
|
||||
translation_key="concentration",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"%": SensorEntityDescription(
|
||||
key="percent",
|
||||
translation_key="percent",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -8,7 +8,12 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import UnitOfPressure, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -21,7 +26,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
key="co2",
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
@@ -35,7 +40,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
key="humidity",
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
|
||||
@@ -13,11 +13,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
Platform,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -38,20 +39,20 @@ MAIN_SENSOR_TYPES: dict[str, SensorEntityDescription] = {
|
||||
"com.fibaro.smokeSensor": SensorEntityDescription(
|
||||
key="com.fibaro.smokeSensor",
|
||||
name="Smoke",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
icon="mdi:fire",
|
||||
),
|
||||
"CO2": SensorEntityDescription(
|
||||
key="CO2",
|
||||
name="CO2",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"com.fibaro.humiditySensor": SensorEntityDescription(
|
||||
key="com.fibaro.humiditySensor",
|
||||
name="Humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -16,10 +16,12 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_TEMPERATURE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_TOKEN,
|
||||
CONF_USERNAME,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -42,7 +44,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="pm",
|
||||
name=ATTR_PM2_5,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
icon="mdi:cloud",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
@@ -54,25 +56,25 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="hum",
|
||||
name=ATTR_HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:water-percent",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="co2",
|
||||
name=ATTR_CARBON_DIOXIDE,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
icon="mdi:molecule-co2",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="voc",
|
||||
name=ATTR_VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
icon="mdi:cloud",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="allpollu",
|
||||
name=ATTR_FOOBOT_INDEX,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:percent",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -13,7 +13,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
StateType,
|
||||
)
|
||||
from homeassistant.const import UnitOfRatio, UnitOfTemperature, UnitOfVolumeFlowRate
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumeFlowRate,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -49,14 +54,14 @@ _T2 = FreshrSensorEntityDescription(
|
||||
_CO2 = FreshrSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda r: r.co2,
|
||||
)
|
||||
_HUM = FreshrSensorEntityDescription(
|
||||
key="hum",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda r: r.hum,
|
||||
)
|
||||
|
||||
@@ -14,7 +14,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigSubentry
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, UnitOfRatio
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -121,7 +125,7 @@ AIR_QUALITY_SENSOR_TYPES: tuple[AirQualitySensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement_fn=lambda x: x.pollutants.co.concentration.units,
|
||||
exists_fn=lambda x: "co" in {p.code for p in x.pollutants},
|
||||
value_fn=lambda x: x.pollutants.co.concentration.value,
|
||||
suggested_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
suggested_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
AirQualitySensorEntityDescription(
|
||||
key="nh3",
|
||||
|
||||
@@ -19,9 +19,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -43,13 +44,13 @@ SENSOR_DESCRIPTIONS = {
|
||||
(DeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{DeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(DeviceClass.BATTERY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{DeviceClass.BATTERY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(
|
||||
@@ -68,13 +69,13 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{DeviceClass.PM25}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(DeviceClass.CO2, Units.CONCENTRATION_PARTS_PER_MILLION): SensorEntityDescription(
|
||||
key=f"{DeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_NAME,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
UnitOfDensity,
|
||||
PERCENTAGE,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
@@ -22,7 +24,6 @@ from homeassistant.const import (
|
||||
UnitOfPower,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
@@ -56,7 +57,7 @@ HM_STATE_HA_CAST = {
|
||||
SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
"HUMIDITY": SensorEntityDescription(
|
||||
key="HUMIDITY",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -128,7 +129,7 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"CONCENTRATION": SensorEntityDescription(
|
||||
key="CONCENTRATION",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -203,15 +204,15 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"VALVE_STATE": SensorEntityDescription(
|
||||
key="VALVE_STATE",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
"CARRIER_SENSE_LEVEL": SensorEntityDescription(
|
||||
key="CARRIER_SENSE_LEVEL",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
"DUTY_CYCLE_LEVEL": SensorEntityDescription(
|
||||
key="DUTY_CYCLE_LEVEL",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
"BRIGHTNESS": SensorEntityDescription(
|
||||
key="BRIGHTNESS",
|
||||
@@ -220,37 +221,37 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_1": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_1",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_2_5": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_2_5",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_10": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_10",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_1_24H_AVERAGE": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_1_24H_AVERAGE",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_2_5_24H_AVERAGE": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_2_5_24H_AVERAGE",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_10_24H_AVERAGE": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_10_24H_AVERAGE",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioimmich"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["aioimmich==0.15.1"]
|
||||
"requirements": ["aioimmich==0.15.0"]
|
||||
}
|
||||
|
||||
@@ -17,9 +17,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -38,13 +39,13 @@ SENSOR_DESCRIPTIONS = {
|
||||
(DeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{DeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(DeviceClass.BATTERY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{DeviceClass.BATTERY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(
|
||||
@@ -60,7 +61,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(DeviceClass.CO2, Units.CONCENTRATION_PARTS_PER_MILLION): SensorEntityDescription(
|
||||
key=f"{DeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(DeviceClass.PRESSURE, Units.PRESSURE_HPA): SensorEntityDescription(
|
||||
|
||||
@@ -12,7 +12,11 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -42,14 +46,14 @@ INTELLICLIMA_SENSORS: tuple[IntelliClimaSensorEntityDescription, ...] = (
|
||||
key="humidity",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda device_data: float(device_data.rh),
|
||||
),
|
||||
IntelliClimaSensorEntityDescription(
|
||||
key="voc",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
value_fn=lambda device_data: float(device_data.voc_state),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -14,14 +14,15 @@ from homeassistant.components.sensor import (
|
||||
SensorEntity,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_DOMAIN,
|
||||
CONF_ENTITIES,
|
||||
CONF_SOURCE,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -66,8 +67,8 @@ UNIT_OF_MEASUREMENT_MAPPING = {
|
||||
pypck.lcn_defs.VarUnit.METERPERSECOND: UnitOfSpeed.METERS_PER_SECOND,
|
||||
pypck.lcn_defs.VarUnit.VOLT: UnitOfElectricPotential.VOLT,
|
||||
pypck.lcn_defs.VarUnit.AMPERE: UnitOfElectricCurrent.AMPERE,
|
||||
pypck.lcn_defs.VarUnit.PPM: UnitOfRatio.PARTS_PER_MILLION,
|
||||
pypck.lcn_defs.VarUnit.PERCENT: UnitOfRatio.PERCENTAGE,
|
||||
pypck.lcn_defs.VarUnit.PPM: CONCENTRATION_PARTS_PER_MILLION,
|
||||
pypck.lcn_defs.VarUnit.PERCENT: PERCENTAGE,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from homeassistant.components.number import (
|
||||
NumberMode,
|
||||
)
|
||||
from homeassistant.components.script import scripts_with_entity
|
||||
from homeassistant.const import UnitOfRatio, UnitOfTemperature, UnitOfTime
|
||||
from homeassistant.const import PERCENTAGE, UnitOfTemperature, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -41,13 +41,13 @@ NUMBER_DESC: dict[ThinQProperty, NumberEntityDescription] = {
|
||||
),
|
||||
ThinQProperty.LIGHT_STATUS: NumberEntityDescription(
|
||||
key=ThinQProperty.LIGHT_STATUS,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.LIGHT_STATUS,
|
||||
),
|
||||
ThinQProperty.TARGET_HUMIDITY: NumberEntityDescription(
|
||||
key=ThinQProperty.TARGET_HUMIDITY,
|
||||
device_class=NumberDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.TARGET_HUMIDITY,
|
||||
),
|
||||
ThinQProperty.TARGET_TEMPERATURE: NumberEntityDescription(
|
||||
|
||||
@@ -18,9 +18,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
UnitOfDensity,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
UnitOfEnergy,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -37,25 +37,25 @@ AIR_QUALITY_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.PM1: SensorEntityDescription(
|
||||
key=ThinQProperty.PM1,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.PM2: SensorEntityDescription(
|
||||
key=ThinQProperty.PM2,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.PM10: SensorEntityDescription(
|
||||
key=ThinQProperty.PM10,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.HUMIDITY: SensorEntityDescription(
|
||||
key=ThinQProperty.HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ThinQProperty.MONITORING_ENABLED: SensorEntityDescription(
|
||||
@@ -106,12 +106,12 @@ FILTER_INFO_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
),
|
||||
ThinQProperty.FILTER_REMAIN_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.FILTER_REMAIN_PERCENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.FILTER_LIFETIME,
|
||||
),
|
||||
ThinQProperty.TOP_FILTER_REMAIN_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.TOP_FILTER_REMAIN_PERCENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.TOP_FILTER_REMAIN_PERCENT,
|
||||
),
|
||||
}
|
||||
@@ -119,7 +119,7 @@ HUMIDITY_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
ThinQProperty.CURRENT_HUMIDITY: SensorEntityDescription(
|
||||
key=ThinQProperty.CURRENT_HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
}
|
||||
@@ -215,7 +215,7 @@ RECIPE_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
),
|
||||
ThinQProperty.BEER_REMAIN: SensorEntityDescription(
|
||||
key=ThinQProperty.BEER_REMAIN,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.BEER_REMAIN,
|
||||
),
|
||||
}
|
||||
@@ -227,7 +227,7 @@ REFRIGERATION_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
),
|
||||
ThinQProperty.FRESH_AIR_FILTER_REMAIN_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.FRESH_AIR_FILTER_REMAIN_PERCENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.FRESH_AIR_FILTER,
|
||||
),
|
||||
}
|
||||
@@ -318,17 +318,17 @@ WATER_FILTER_INFO_SENSOR_DESC: dict[ThinQProperty, SensorEntityDescription] = {
|
||||
),
|
||||
ThinQProperty.WATER_FILTER_1_REMAIN_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.WATER_FILTER_1_REMAIN_PERCENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.WATER_FILTER_1_REMAIN_PERCENT,
|
||||
),
|
||||
ThinQProperty.WATER_FILTER_2_REMAIN_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.WATER_FILTER_2_REMAIN_PERCENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.WATER_FILTER_2_REMAIN_PERCENT,
|
||||
),
|
||||
ThinQProperty.WATER_FILTER_3_REMAIN_PERCENT: SensorEntityDescription(
|
||||
key=ThinQProperty.WATER_FILTER_3_REMAIN_PERCENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key=ThinQProperty.WATER_FILTER_3_REMAIN_PERCENT,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import (
|
||||
ATTR_LATITUDE,
|
||||
ATTR_LONGITUDE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONF_SHOW_ON_MAP,
|
||||
UnitOfDensity,
|
||||
PERCENTAGE,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -36,7 +36,7 @@ SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -55,13 +55,13 @@ SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="P1",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="P2",
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -16,10 +16,10 @@ from homeassistant.components.number import (
|
||||
NumberMode,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
Platform,
|
||||
UnitOfLength,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -354,7 +354,7 @@ DISCOVERY_SCHEMAS = [
|
||||
platform=Platform.NUMBER,
|
||||
entity_description=MatterNumberEntityDescription(
|
||||
key="pump_setpoint",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
translation_key="pump_setpoint",
|
||||
native_max_value=100,
|
||||
native_min_value=0.5,
|
||||
@@ -516,7 +516,7 @@ DISCOVERY_SCHEMAS = [
|
||||
entity_description=MatterRangeNumberEntityDescription(
|
||||
key="speaker_setpoint",
|
||||
translation_key="speaker_setpoint",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
command=lambda value: clusters.LevelControl.Commands.MoveToLevel(
|
||||
level=int(value)
|
||||
),
|
||||
|
||||
@@ -31,9 +31,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
TextSelectorConfig(type=TextSelectorType.EMAIL, autocomplete="username")
|
||||
),
|
||||
vol.Required(CONF_PASSWORD): TextSelector(
|
||||
TextSelectorConfig(
|
||||
type=TextSelectorType.PASSWORD, autocomplete="current-password"
|
||||
)
|
||||
TextSelectorConfig(type=TextSelectorType.PASSWORD)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -10,7 +10,13 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import LIGHT_LUX, UnitOfPower, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfPower,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -36,14 +42,14 @@ SENSOR_TYPES = {
|
||||
14: SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
key="carbon_dioxide",
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
16: SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
key="humidity",
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
"""Support for Microsoft face recognition."""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Coroutine
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
import aiohttp
|
||||
from aiohttp.hdrs import CONTENT_TYPE
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import camera
|
||||
from homeassistant.const import ATTR_NAME, CONF_API_KEY, CONF_TIMEOUT, CONTENT_TYPE_JSON
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util import slugify
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_CAMERA_ENTITY = "camera_entity"
|
||||
ATTR_GROUP = "group"
|
||||
ATTR_PERSON = "person"
|
||||
|
||||
CONF_AZURE_REGION = "azure_region"
|
||||
|
||||
DEFAULT_TIMEOUT = 10
|
||||
DOMAIN = "microsoft_face"
|
||||
DATA_MICROSOFT_FACE: HassKey[MicrosoftFace] = HassKey(DOMAIN)
|
||||
|
||||
FACE_API_URL = "api.cognitive.microsoft.com/face/v1.0/{0}"
|
||||
|
||||
SERVICE_CREATE_GROUP = "create_group"
|
||||
SERVICE_CREATE_PERSON = "create_person"
|
||||
SERVICE_DELETE_GROUP = "delete_group"
|
||||
SERVICE_DELETE_PERSON = "delete_person"
|
||||
SERVICE_FACE_PERSON = "face_person"
|
||||
SERVICE_TRAIN_GROUP = "train_group"
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Optional(CONF_AZURE_REGION, default="westus"): cv.string,
|
||||
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
|
||||
}
|
||||
)
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
SCHEMA_GROUP_SERVICE = vol.Schema({vol.Required(ATTR_NAME): cv.string})
|
||||
|
||||
SCHEMA_PERSON_SERVICE = SCHEMA_GROUP_SERVICE.extend(
|
||||
{vol.Required(ATTR_GROUP): cv.slugify}
|
||||
)
|
||||
|
||||
SCHEMA_FACE_SERVICE = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_PERSON): cv.string,
|
||||
vol.Required(ATTR_GROUP): cv.slugify,
|
||||
vol.Required(ATTR_CAMERA_ENTITY): cv.entity_id,
|
||||
}
|
||||
)
|
||||
|
||||
SCHEMA_TRAIN_SERVICE = vol.Schema({vol.Required(ATTR_GROUP): cv.slugify})
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up Microsoft Face."""
|
||||
component = EntityComponent[MicrosoftFaceGroupEntity](
|
||||
logging.getLogger(__name__), DOMAIN, hass
|
||||
)
|
||||
entities: dict[str, MicrosoftFaceGroupEntity] = {}
|
||||
domain_config: dict[str, Any] = config[DOMAIN]
|
||||
azure_region: str = domain_config[CONF_AZURE_REGION]
|
||||
api_key: str = domain_config[CONF_API_KEY]
|
||||
timeout: int = domain_config[CONF_TIMEOUT]
|
||||
face = MicrosoftFace(
|
||||
hass,
|
||||
azure_region,
|
||||
api_key,
|
||||
timeout,
|
||||
component,
|
||||
entities,
|
||||
)
|
||||
|
||||
try:
|
||||
# read exists group/person from cloud and create entities
|
||||
await face.update_store()
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't load data from face api: %s", err)
|
||||
return False
|
||||
|
||||
hass.data[DATA_MICROSOFT_FACE] = face
|
||||
|
||||
async def async_create_group(service: ServiceCall) -> None:
|
||||
"""Create a new person group."""
|
||||
name = service.data[ATTR_NAME]
|
||||
g_id = slugify(name)
|
||||
|
||||
try:
|
||||
await face.call_api("put", f"persongroups/{g_id}", {"name": name})
|
||||
face.store[g_id] = {}
|
||||
old_entity = entities.pop(g_id, None)
|
||||
if old_entity:
|
||||
await component.async_remove_entity(old_entity.entity_id)
|
||||
|
||||
entities[g_id] = MicrosoftFaceGroupEntity(face, g_id, name)
|
||||
await component.async_add_entities([entities[g_id]])
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't create group '%s' with error: %s", g_id, err)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_CREATE_GROUP, async_create_group, schema=SCHEMA_GROUP_SERVICE
|
||||
)
|
||||
|
||||
async def async_delete_group(service: ServiceCall) -> None:
|
||||
"""Delete a person group."""
|
||||
g_id = slugify(service.data[ATTR_NAME])
|
||||
|
||||
try:
|
||||
await face.call_api("delete", f"persongroups/{g_id}")
|
||||
face.store.pop(g_id)
|
||||
|
||||
entity = entities.pop(g_id)
|
||||
await component.async_remove_entity(entity.entity_id)
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't delete group '%s' with error: %s", g_id, err)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_DELETE_GROUP, async_delete_group, schema=SCHEMA_GROUP_SERVICE
|
||||
)
|
||||
|
||||
async def async_train_group(service: ServiceCall) -> None:
|
||||
"""Train a person group."""
|
||||
g_id = service.data[ATTR_GROUP]
|
||||
|
||||
try:
|
||||
await face.call_api("post", f"persongroups/{g_id}/train")
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't train group '%s' with error: %s", g_id, err)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_TRAIN_GROUP, async_train_group, schema=SCHEMA_TRAIN_SERVICE
|
||||
)
|
||||
|
||||
async def async_create_person(service: ServiceCall) -> None:
|
||||
"""Create a person in a group."""
|
||||
name = service.data[ATTR_NAME]
|
||||
g_id = service.data[ATTR_GROUP]
|
||||
|
||||
try:
|
||||
user_data = await face.call_api(
|
||||
"post", f"persongroups/{g_id}/persons", {"name": name}
|
||||
)
|
||||
|
||||
face.store[g_id][name] = user_data["personId"]
|
||||
entities[g_id].async_write_ha_state()
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't create person '%s' with error: %s", name, err)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_CREATE_PERSON, async_create_person, schema=SCHEMA_PERSON_SERVICE
|
||||
)
|
||||
|
||||
async def async_delete_person(service: ServiceCall) -> None:
|
||||
"""Delete a person in a group."""
|
||||
name = service.data[ATTR_NAME]
|
||||
g_id = service.data[ATTR_GROUP]
|
||||
p_id = face.store[g_id].get(name)
|
||||
|
||||
try:
|
||||
await face.call_api("delete", f"persongroups/{g_id}/persons/{p_id}")
|
||||
|
||||
face.store[g_id].pop(name)
|
||||
entities[g_id].async_write_ha_state()
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't delete person '%s' with error: %s", p_id, err)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_DELETE_PERSON, async_delete_person, schema=SCHEMA_PERSON_SERVICE
|
||||
)
|
||||
|
||||
async def async_face_person(service: ServiceCall) -> None:
|
||||
"""Add a new face picture to a person."""
|
||||
g_id = service.data[ATTR_GROUP]
|
||||
p_id = face.store[g_id].get(service.data[ATTR_PERSON])
|
||||
|
||||
camera_entity = service.data[ATTR_CAMERA_ENTITY]
|
||||
|
||||
try:
|
||||
image = await camera.async_get_image(hass, camera_entity)
|
||||
|
||||
await face.call_api(
|
||||
"post",
|
||||
f"persongroups/{g_id}/persons/{p_id}/persistedFaces",
|
||||
image.content,
|
||||
binary=True,
|
||||
)
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error(
|
||||
"Can't add an image of a person '%s' with error: %s", p_id, err
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_FACE_PERSON, async_face_person, schema=SCHEMA_FACE_SERVICE
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class MicrosoftFaceGroupEntity(Entity):
|
||||
"""Person-Group state/data Entity."""
|
||||
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, api: MicrosoftFace, g_id: str, name: str) -> None:
|
||||
"""Initialize person/group entity."""
|
||||
self.entity_id = f"{DOMAIN}.{g_id}"
|
||||
self._api = api
|
||||
self._id = g_id
|
||||
self._attr_name = name
|
||||
|
||||
@property
|
||||
@override
|
||||
def state(self) -> int:
|
||||
"""Return the state of the entity."""
|
||||
return len(self._api.store[self._id])
|
||||
|
||||
@property
|
||||
@override
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return device specific state attributes."""
|
||||
return dict(self._api.store[self._id])
|
||||
|
||||
|
||||
class MicrosoftFace:
|
||||
"""Microsoft Face api for Home Assistant."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
server_loc: str,
|
||||
api_key: str,
|
||||
timeout: int,
|
||||
component: EntityComponent[MicrosoftFaceGroupEntity],
|
||||
entities: dict[str, MicrosoftFaceGroupEntity],
|
||||
) -> None:
|
||||
"""Initialize Microsoft Face api."""
|
||||
self.hass = hass
|
||||
self.websession = async_get_clientsession(hass)
|
||||
self.timeout = timeout
|
||||
self._api_key = api_key
|
||||
self._server_url = f"https://{server_loc}.{FACE_API_URL}"
|
||||
self._store: dict[str, dict[str, Any]] = {}
|
||||
self._component = component
|
||||
self._entities = entities
|
||||
|
||||
@property
|
||||
def store(self) -> dict[str, dict[str, Any]]:
|
||||
"""Store group/person data and IDs."""
|
||||
return self._store
|
||||
|
||||
async def update_store(self) -> None:
|
||||
"""Load all group/person data into local store."""
|
||||
groups = await self.call_api("get", "persongroups")
|
||||
|
||||
remove_tasks: list[Coroutine[Any, Any, None]] = []
|
||||
new_entities = []
|
||||
for group in groups:
|
||||
g_id = group["personGroupId"]
|
||||
self._store[g_id] = {}
|
||||
old_entity = self._entities.pop(g_id, None)
|
||||
if old_entity:
|
||||
remove_tasks.append(
|
||||
self._component.async_remove_entity(old_entity.entity_id)
|
||||
)
|
||||
|
||||
self._entities[g_id] = MicrosoftFaceGroupEntity(self, g_id, group["name"])
|
||||
new_entities.append(self._entities[g_id])
|
||||
|
||||
persons = await self.call_api("get", f"persongroups/{g_id}/persons")
|
||||
|
||||
for person in persons:
|
||||
self._store[g_id][person["name"]] = person["personId"]
|
||||
|
||||
if remove_tasks:
|
||||
await asyncio.gather(*remove_tasks)
|
||||
await self._component.async_add_entities(new_entities)
|
||||
|
||||
async def call_api(self, method, function, data=None, binary=False, params=None):
|
||||
"""Make an api call."""
|
||||
headers = {"Ocp-Apim-Subscription-Key": self._api_key}
|
||||
url = self._server_url.format(function)
|
||||
|
||||
payload = None
|
||||
if binary:
|
||||
headers[CONTENT_TYPE] = "application/octet-stream"
|
||||
payload = data
|
||||
else:
|
||||
headers[CONTENT_TYPE] = CONTENT_TYPE_JSON
|
||||
if data is not None:
|
||||
payload = json.dumps(data).encode()
|
||||
else:
|
||||
payload = None
|
||||
|
||||
try:
|
||||
async with asyncio.timeout(self.timeout):
|
||||
response = await self.websession.request(
|
||||
method, url, data=payload, headers=headers, params=params
|
||||
)
|
||||
|
||||
answer = await response.json()
|
||||
|
||||
_LOGGER.debug("Read from microsoft face api: %s", answer)
|
||||
if response.status < 300:
|
||||
return answer
|
||||
|
||||
_LOGGER.warning(
|
||||
"Error %d microsoft face api %s", response.status, response.url
|
||||
)
|
||||
raise HomeAssistantError(answer["error"]["message"])
|
||||
|
||||
except aiohttp.ClientError:
|
||||
_LOGGER.warning("Can't connect to microsoft face api")
|
||||
|
||||
except TimeoutError:
|
||||
_LOGGER.warning("Timeout from microsoft face api %s", response.url)
|
||||
|
||||
raise HomeAssistantError("Network error on microsoft face api.")
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"services": {
|
||||
"create_group": {
|
||||
"service": "mdi:account-multiple-plus"
|
||||
},
|
||||
"create_person": {
|
||||
"service": "mdi:account-plus"
|
||||
},
|
||||
"delete_group": {
|
||||
"service": "mdi:account-multiple-remove"
|
||||
},
|
||||
"delete_person": {
|
||||
"service": "mdi:account-remove"
|
||||
},
|
||||
"face_person": {
|
||||
"service": "mdi:face-man"
|
||||
},
|
||||
"train_group": {
|
||||
"service": "mdi:account-multiple-check"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"domain": "microsoft_face",
|
||||
"name": "Microsoft Face",
|
||||
"codeowners": [],
|
||||
"dependencies": ["camera"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/microsoft_face",
|
||||
"iot_class": "cloud_push",
|
||||
"quality_scale": "legacy"
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
create_group:
|
||||
fields:
|
||||
name:
|
||||
required: true
|
||||
example: family
|
||||
selector:
|
||||
text:
|
||||
create_person:
|
||||
fields:
|
||||
group:
|
||||
required: true
|
||||
example: family
|
||||
selector:
|
||||
text:
|
||||
name:
|
||||
required: true
|
||||
example: Hans
|
||||
selector:
|
||||
text:
|
||||
delete_group:
|
||||
fields:
|
||||
name:
|
||||
required: true
|
||||
example: family
|
||||
selector:
|
||||
text:
|
||||
delete_person:
|
||||
fields:
|
||||
group:
|
||||
required: true
|
||||
example: family
|
||||
selector:
|
||||
text:
|
||||
name:
|
||||
required: true
|
||||
example: Hans
|
||||
selector:
|
||||
text:
|
||||
face_person:
|
||||
fields:
|
||||
camera_entity:
|
||||
required: true
|
||||
example: camera.door
|
||||
selector:
|
||||
text:
|
||||
group:
|
||||
required: true
|
||||
example: family
|
||||
selector:
|
||||
text:
|
||||
person:
|
||||
required: true
|
||||
example: Hans
|
||||
selector:
|
||||
text:
|
||||
train_group:
|
||||
fields:
|
||||
group:
|
||||
required: true
|
||||
example: family
|
||||
selector:
|
||||
text:
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"services": {
|
||||
"create_group": {
|
||||
"description": "Creates a new person group.",
|
||||
"fields": {
|
||||
"name": {
|
||||
"description": "Name of the group.",
|
||||
"name": "[%key:common::config_flow::data::name%]"
|
||||
}
|
||||
},
|
||||
"name": "Create group"
|
||||
},
|
||||
"create_person": {
|
||||
"description": "Creates a new person in the group.",
|
||||
"fields": {
|
||||
"group": {
|
||||
"description": "Name of the group.",
|
||||
"name": "Group"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name of the person.",
|
||||
"name": "[%key:common::config_flow::data::name%]"
|
||||
}
|
||||
},
|
||||
"name": "Create person"
|
||||
},
|
||||
"delete_group": {
|
||||
"description": "Deletes a new person group.",
|
||||
"fields": {
|
||||
"name": {
|
||||
"description": "Name of the group.",
|
||||
"name": "[%key:common::config_flow::data::name%]"
|
||||
}
|
||||
},
|
||||
"name": "Delete group"
|
||||
},
|
||||
"delete_person": {
|
||||
"description": "Deletes a person in the group.",
|
||||
"fields": {
|
||||
"group": {
|
||||
"description": "Name of the group.",
|
||||
"name": "Group"
|
||||
},
|
||||
"name": {
|
||||
"description": "[%key:component::microsoft_face::services::create_person::fields::name::description%]",
|
||||
"name": "[%key:common::config_flow::data::name%]"
|
||||
}
|
||||
},
|
||||
"name": "Delete person"
|
||||
},
|
||||
"face_person": {
|
||||
"description": "Adds a new picture to a person.",
|
||||
"fields": {
|
||||
"camera_entity": {
|
||||
"description": "Camera to take a picture.",
|
||||
"name": "Camera entity"
|
||||
},
|
||||
"group": {
|
||||
"description": "Name of the group.",
|
||||
"name": "Group"
|
||||
},
|
||||
"person": {
|
||||
"description": "[%key:component::microsoft_face::services::create_person::fields::name::description%]",
|
||||
"name": "Person"
|
||||
}
|
||||
},
|
||||
"name": "Face person"
|
||||
},
|
||||
"train_group": {
|
||||
"description": "Trains a person group.",
|
||||
"fields": {
|
||||
"group": {
|
||||
"description": "Name of the group.",
|
||||
"name": "Group"
|
||||
}
|
||||
},
|
||||
"name": "Train group"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
"""The microsoft_face_detect component."""
|
||||
@@ -0,0 +1,125 @@
|
||||
"""Component that will help set the Microsoft face detect processing."""
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.image_processing import (
|
||||
ATTR_AGE,
|
||||
ATTR_GENDER,
|
||||
ATTR_GLASSES,
|
||||
PLATFORM_SCHEMA as IMAGE_PROCESSING_PLATFORM_SCHEMA,
|
||||
FaceInformation,
|
||||
ImageProcessingFaceEntity,
|
||||
)
|
||||
from homeassistant.components.microsoft_face import DATA_MICROSOFT_FACE, MicrosoftFace
|
||||
from homeassistant.const import CONF_ENTITY_ID, CONF_NAME, CONF_SOURCE
|
||||
from homeassistant.core import HomeAssistant, split_entity_id
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SUPPORTED_ATTRIBUTES = [ATTR_AGE, ATTR_GENDER, ATTR_GLASSES]
|
||||
|
||||
CONF_ATTRIBUTES = "attributes"
|
||||
DEFAULT_ATTRIBUTES = [ATTR_AGE, ATTR_GENDER]
|
||||
|
||||
|
||||
def validate_attributes(list_attributes):
|
||||
"""Validate face attributes."""
|
||||
for attr in list_attributes:
|
||||
if attr not in SUPPORTED_ATTRIBUTES:
|
||||
raise vol.Invalid(f"Invalid attribute {attr}")
|
||||
return list_attributes
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = IMAGE_PROCESSING_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_ATTRIBUTES, default=DEFAULT_ATTRIBUTES): vol.All(
|
||||
cv.ensure_list, validate_attributes
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Microsoft Face detection platform."""
|
||||
api = hass.data[DATA_MICROSOFT_FACE]
|
||||
attributes: list[str] = config[CONF_ATTRIBUTES]
|
||||
source: list[dict[str, str]] = config[CONF_SOURCE]
|
||||
|
||||
async_add_entities(
|
||||
MicrosoftFaceDetectEntity(
|
||||
camera[CONF_ENTITY_ID], api, attributes, camera.get(CONF_NAME)
|
||||
)
|
||||
for camera in source
|
||||
)
|
||||
|
||||
|
||||
class MicrosoftFaceDetectEntity(ImageProcessingFaceEntity):
|
||||
"""Microsoft Face API entity for identify."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
camera_entity: str,
|
||||
api: MicrosoftFace,
|
||||
attributes: list[str],
|
||||
name: str | None,
|
||||
) -> None:
|
||||
"""Initialize Microsoft Face."""
|
||||
super().__init__()
|
||||
|
||||
self._api = api
|
||||
self._attr_camera_entity = camera_entity
|
||||
self._attributes = attributes
|
||||
|
||||
if name:
|
||||
self._attr_name = name
|
||||
else:
|
||||
self._attr_name = f"MicrosoftFace {split_entity_id(camera_entity)[1]}"
|
||||
|
||||
@override
|
||||
async def async_process_image(self, image: bytes) -> None:
|
||||
"""Process image.
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
face_data = None
|
||||
try:
|
||||
face_data = await self._api.call_api(
|
||||
"post",
|
||||
"detect",
|
||||
image,
|
||||
binary=True,
|
||||
params={"returnFaceAttributes": ",".join(self._attributes)},
|
||||
)
|
||||
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't process image on microsoft face: %s", err)
|
||||
return
|
||||
|
||||
if not face_data:
|
||||
face_data = []
|
||||
|
||||
faces: list[FaceInformation] = []
|
||||
for face in face_data:
|
||||
face_attr = FaceInformation()
|
||||
for attr in self._attributes:
|
||||
if TYPE_CHECKING:
|
||||
assert attr in SUPPORTED_ATTRIBUTES
|
||||
if attr in face["faceAttributes"]:
|
||||
face_attr[attr] = face["faceAttributes"][attr] # type: ignore[literal-required]
|
||||
|
||||
if face_attr:
|
||||
faces.append(face_attr)
|
||||
|
||||
self.async_process_faces(faces, len(face_data))
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"domain": "microsoft_face_detect",
|
||||
"name": "Microsoft Face Detect",
|
||||
"codeowners": [],
|
||||
"dependencies": ["microsoft_face"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/microsoft_face_detect",
|
||||
"iot_class": "cloud_push",
|
||||
"quality_scale": "legacy"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
"""The microsoft_face_identify component."""
|
||||
@@ -0,0 +1,121 @@
|
||||
"""Component that will help set the Microsoft face for verify processing."""
|
||||
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.image_processing import (
|
||||
ATTR_CONFIDENCE,
|
||||
CONF_CONFIDENCE,
|
||||
PLATFORM_SCHEMA as IMAGE_PROCESSING_PLATFORM_SCHEMA,
|
||||
FaceInformation,
|
||||
ImageProcessingFaceEntity,
|
||||
)
|
||||
from homeassistant.components.microsoft_face import DATA_MICROSOFT_FACE, MicrosoftFace
|
||||
from homeassistant.const import ATTR_NAME, CONF_ENTITY_ID, CONF_NAME, CONF_SOURCE
|
||||
from homeassistant.core import HomeAssistant, split_entity_id
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_GROUP = "group"
|
||||
|
||||
PLATFORM_SCHEMA = IMAGE_PROCESSING_PLATFORM_SCHEMA.extend(
|
||||
{vol.Required(CONF_GROUP): cv.slugify}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Microsoft Face identify platform."""
|
||||
api = hass.data[DATA_MICROSOFT_FACE]
|
||||
face_group: str = config[CONF_GROUP]
|
||||
confidence: float = config[CONF_CONFIDENCE]
|
||||
source: list[dict[str, str]] = config[CONF_SOURCE]
|
||||
|
||||
async_add_entities(
|
||||
MicrosoftFaceIdentifyEntity(
|
||||
camera[CONF_ENTITY_ID],
|
||||
api,
|
||||
face_group,
|
||||
confidence,
|
||||
camera.get(CONF_NAME),
|
||||
)
|
||||
for camera in source
|
||||
)
|
||||
|
||||
|
||||
class MicrosoftFaceIdentifyEntity(ImageProcessingFaceEntity):
|
||||
"""Representation of the Microsoft Face API entity for identify."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
camera_entity: str,
|
||||
api: MicrosoftFace,
|
||||
face_group: str,
|
||||
confidence: float,
|
||||
name: str | None,
|
||||
) -> None:
|
||||
"""Initialize the Microsoft Face API."""
|
||||
super().__init__()
|
||||
|
||||
self._api = api
|
||||
self._attr_camera_entity = camera_entity
|
||||
self._attr_confidence = confidence
|
||||
self._face_group = face_group
|
||||
|
||||
if name:
|
||||
self._attr_name = name
|
||||
else:
|
||||
self._attr_name = f"MicrosoftFace {split_entity_id(camera_entity)[1]}"
|
||||
|
||||
@override
|
||||
async def async_process_image(self, image: bytes) -> None:
|
||||
"""Process image.
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
detect = []
|
||||
try:
|
||||
face_data = await self._api.call_api("post", "detect", image, binary=True)
|
||||
|
||||
if face_data:
|
||||
face_ids = [data["faceId"] for data in face_data]
|
||||
detect = await self._api.call_api(
|
||||
"post",
|
||||
"identify",
|
||||
{"faceIds": face_ids, "personGroupId": self._face_group},
|
||||
)
|
||||
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error("Can't process image on Microsoft face: %s", err)
|
||||
return
|
||||
|
||||
# Parse data
|
||||
known_faces: list[FaceInformation] = []
|
||||
total = 0
|
||||
for face in detect:
|
||||
total += 1
|
||||
if not face["candidates"]:
|
||||
continue
|
||||
|
||||
data = face["candidates"][0]
|
||||
name = ""
|
||||
for s_name, s_id in self._api.store[self._face_group].items():
|
||||
if data["personId"] == s_id:
|
||||
name = s_name
|
||||
break
|
||||
|
||||
known_faces.append(
|
||||
{ATTR_NAME: name, ATTR_CONFIDENCE: data["confidence"] * 100}
|
||||
)
|
||||
|
||||
self.async_process_faces(known_faces, total)
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"domain": "microsoft_face_identify",
|
||||
"name": "Microsoft Face Identify",
|
||||
"codeowners": [],
|
||||
"dependencies": ["microsoft_face"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/microsoft_face_identify",
|
||||
"iot_class": "cloud_push",
|
||||
"quality_scale": "legacy"
|
||||
}
|
||||
@@ -114,26 +114,20 @@ class MieleDataUpdateCoordinator(DataUpdateCoordinator[MieleCoordinatorData]):
|
||||
|
||||
async def callback_update_data(self, devices_json: dict[str, dict]) -> None:
|
||||
"""Handle data update from the API."""
|
||||
updated_devices = {
|
||||
devices = {
|
||||
device_id: MieleDevice(device) for device_id, device in devices_json.items()
|
||||
}
|
||||
self.async_set_updated_data(
|
||||
MieleCoordinatorData(
|
||||
devices={**self.data.devices, **updated_devices},
|
||||
actions=self.data.actions,
|
||||
)
|
||||
MieleCoordinatorData(devices=devices, actions=self.data.actions)
|
||||
)
|
||||
|
||||
async def callback_update_actions(self, actions_json: dict[str, dict]) -> None:
|
||||
"""Handle data update from the API."""
|
||||
updated_actions = {
|
||||
actions = {
|
||||
device_id: MieleAction(action) for device_id, action in actions_json.items()
|
||||
}
|
||||
self.async_set_updated_data(
|
||||
MieleCoordinatorData(
|
||||
devices=self.data.devices,
|
||||
actions={**self.data.actions, **updated_actions},
|
||||
)
|
||||
MieleCoordinatorData(devices=self.data.devices, actions=actions)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -11,10 +11,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -63,7 +65,7 @@ HEATER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="control_signal",
|
||||
translation_key="control_signal",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
)
|
||||
@@ -78,26 +80,26 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key=HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=BATTERY,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ECO2,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
translation_key="estimated_co2",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TVOC,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
translation_key="tvoc",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -107,7 +109,7 @@ LOCAL_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="control_signal",
|
||||
translation_key="control_signal",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
@@ -131,7 +133,7 @@ SOCKET_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key=HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
*HEATER_SENSOR_TYPES,
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/modbus",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["pymodbus"],
|
||||
"requirements": ["pymodbus==3.13.1"]
|
||||
"requirements": ["modbus-connection[pymodbus]==3.1.0", "pymodbus==3.13.1"]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"""Support for Modbus."""
|
||||
|
||||
import asyncio
|
||||
from collections import namedtuple
|
||||
from typing import Any
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, cast
|
||||
|
||||
from modbus_connection import ModbusConnection, ModbusError
|
||||
from modbus_connection.pymodbus import PymodbusConnection
|
||||
from pymodbus.client import (
|
||||
AsyncModbusSerialClient,
|
||||
AsyncModbusTcpClient,
|
||||
@@ -11,7 +13,6 @@ from pymodbus.client import (
|
||||
)
|
||||
from pymodbus.exceptions import ModbusException
|
||||
from pymodbus.framer import FramerType
|
||||
from pymodbus.pdu import ModbusPDU
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
@@ -53,7 +54,6 @@ from .const import (
|
||||
CONF_PARITY,
|
||||
CONF_STOPBITS,
|
||||
DEFAULT_HUB,
|
||||
DEVICE_ID,
|
||||
DOMAIN,
|
||||
PLATFORMS,
|
||||
RTUOVERTCP,
|
||||
@@ -71,58 +71,18 @@ DATA_MODBUS_HUBS: HassKey[dict[str, ModbusHub]] = HassKey(DOMAIN)
|
||||
|
||||
PRIMARY_RECONNECT_DELAY = 60
|
||||
|
||||
ConfEntry = namedtuple("ConfEntry", "call_type attr func_name value_attr_name") # noqa: PYI024
|
||||
RunEntry = namedtuple("RunEntry", "attr func value_attr_name") # noqa: PYI024
|
||||
PB_CALL = [
|
||||
ConfEntry(
|
||||
CALL_TYPE_COIL,
|
||||
"bits",
|
||||
"read_coils",
|
||||
"count",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_DISCRETE,
|
||||
"bits",
|
||||
"read_discrete_inputs",
|
||||
"count",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_REGISTER_HOLDING,
|
||||
"registers",
|
||||
"read_holding_registers",
|
||||
"count",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_REGISTER_INPUT,
|
||||
"registers",
|
||||
"read_input_registers",
|
||||
"count",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_WRITE_COIL,
|
||||
"bits",
|
||||
"write_coil",
|
||||
"value",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_WRITE_COILS,
|
||||
"count",
|
||||
"write_coils",
|
||||
"values",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_WRITE_REGISTER,
|
||||
"registers",
|
||||
"write_register",
|
||||
"value",
|
||||
),
|
||||
ConfEntry(
|
||||
CALL_TYPE_WRITE_REGISTERS,
|
||||
"count",
|
||||
"write_registers",
|
||||
"values",
|
||||
),
|
||||
]
|
||||
|
||||
@dataclass
|
||||
class ModbusResult:
|
||||
"""Result of a Modbus read or write call.
|
||||
|
||||
Reads populate exactly one of ``bits`` (coils/discrete inputs) or
|
||||
``registers`` (holding/input registers); writes leave both unset and the
|
||||
non-``None`` instance simply signals success.
|
||||
"""
|
||||
|
||||
bits: list[bool] | None = None
|
||||
registers: list[int] | None = None
|
||||
|
||||
|
||||
async def async_modbus_setup(
|
||||
@@ -242,7 +202,7 @@ async def async_modbus_setup(
|
||||
|
||||
|
||||
class ModbusHub:
|
||||
"""Thread safe wrapper class for pymodbus."""
|
||||
"""Thread safe wrapper class for modbus_connection."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, client_config: dict[str, Any]) -> None:
|
||||
"""Initialize the Modbus hub."""
|
||||
@@ -251,13 +211,13 @@ class ModbusHub:
|
||||
self._client: (
|
||||
AsyncModbusSerialClient | AsyncModbusTcpClient | AsyncModbusUdpClient | None
|
||||
) = None
|
||||
self._connection: ModbusConnection | None = None
|
||||
self._lock = asyncio.Lock()
|
||||
self.event_connected = asyncio.Event()
|
||||
self.hass = hass
|
||||
self.name = client_config[CONF_NAME]
|
||||
self._config_type = client_config[CONF_TYPE]
|
||||
self.config_delay = client_config[CONF_DELAY]
|
||||
self._pb_request: dict[str, RunEntry] = {}
|
||||
self._connect_task: asyncio.Task
|
||||
self._last_log_error: str = ""
|
||||
self._pb_class = {
|
||||
@@ -337,12 +297,7 @@ class ModbusHub:
|
||||
except ModbusException as exception_error:
|
||||
self._log_error(str(exception_error))
|
||||
return False
|
||||
|
||||
for entry in PB_CALL:
|
||||
func = getattr(self._client, entry.func_name)
|
||||
self._pb_request[entry.call_type] = RunEntry(
|
||||
entry.attr, func, entry.value_attr_name
|
||||
)
|
||||
self._connection = PymodbusConnection(self._client)
|
||||
|
||||
self._connect_task = self.hass.async_create_background_task(
|
||||
self.async_pb_connect(), "modbus-connect"
|
||||
@@ -368,46 +323,48 @@ class ModbusHub:
|
||||
except ModbusException as exception_error:
|
||||
self._log_error(str(exception_error))
|
||||
self._client = None
|
||||
self._connection = None
|
||||
_LOGGER.info(f"modbus {self.name} communication closed")
|
||||
|
||||
async def low_level_pb_call(
|
||||
self, slave: int | None, address: int, value: int | list[int], use_call: str
|
||||
) -> ModbusPDU | None:
|
||||
"""Call sync. pymodbus."""
|
||||
kwargs: dict[str, Any] = (
|
||||
{DEVICE_ID: slave} if slave is not None else {DEVICE_ID: 1}
|
||||
)
|
||||
entry = self._pb_request[use_call]
|
||||
|
||||
if use_call in {"write_registers", "write_coils"}:
|
||||
if not isinstance(value, list):
|
||||
value = [value]
|
||||
|
||||
kwargs[entry.value_attr_name] = value
|
||||
) -> ModbusResult | None:
|
||||
"""Call modbus_connection, mapping errors onto a None result."""
|
||||
unit = self._connection.for_unit(slave if slave is not None else 1) # type: ignore[union-attr]
|
||||
try:
|
||||
result: ModbusPDU = await entry.func(address, **kwargs)
|
||||
except ModbusException as exception_error:
|
||||
if use_call == CALL_TYPE_COIL:
|
||||
return ModbusResult(
|
||||
bits=await unit.read_coils(address, cast(int, value))
|
||||
)
|
||||
if use_call == CALL_TYPE_DISCRETE:
|
||||
return ModbusResult(
|
||||
bits=await unit.read_discrete_inputs(address, cast(int, value))
|
||||
)
|
||||
if use_call == CALL_TYPE_REGISTER_HOLDING:
|
||||
return ModbusResult(
|
||||
registers=await unit.read_holding_registers(
|
||||
address, cast(int, value)
|
||||
)
|
||||
)
|
||||
if use_call == CALL_TYPE_REGISTER_INPUT:
|
||||
return ModbusResult(
|
||||
registers=await unit.read_input_registers(address, cast(int, value))
|
||||
)
|
||||
if use_call == CALL_TYPE_WRITE_COIL:
|
||||
await unit.write_coil(address, bool(value))
|
||||
elif use_call == CALL_TYPE_WRITE_COILS:
|
||||
values = value if isinstance(value, list) else [value]
|
||||
await unit.write_coils(address, [bool(v) for v in values])
|
||||
elif use_call == CALL_TYPE_WRITE_REGISTER:
|
||||
await unit.write_register(address, cast(int, value))
|
||||
elif use_call == CALL_TYPE_WRITE_REGISTERS:
|
||||
values = value if isinstance(value, list) else [value]
|
||||
await unit.write_registers(address, values)
|
||||
except ModbusError as exception_error:
|
||||
error = f"Error: device: {slave} address: {address} -> {exception_error!s}"
|
||||
self._log_error(error)
|
||||
return None
|
||||
if not result:
|
||||
error = (
|
||||
f"Error: device: {slave} address: {address} -> pymodbus returned None"
|
||||
)
|
||||
self._log_error(error)
|
||||
return None
|
||||
if not hasattr(result, entry.attr):
|
||||
error = f"Error: device: {slave} address: {address} -> {result!s}"
|
||||
self._log_error(error)
|
||||
return None
|
||||
if result.isError():
|
||||
error = (
|
||||
f"Error: device: {slave} address: {address}"
|
||||
" -> pymodbus returned isError True"
|
||||
)
|
||||
self._log_error(error)
|
||||
return None
|
||||
return result
|
||||
return ModbusResult()
|
||||
|
||||
async def async_pb_call(
|
||||
self,
|
||||
@@ -415,9 +372,9 @@ class ModbusHub:
|
||||
address: int,
|
||||
value: int | list[int],
|
||||
use_call: str,
|
||||
) -> ModbusPDU | None:
|
||||
"""Convert async to sync pymodbus call."""
|
||||
if not self._client:
|
||||
) -> ModbusResult | None:
|
||||
"""Serialize a single Modbus request/response cycle."""
|
||||
if not self._connection:
|
||||
return None
|
||||
async with self._lock:
|
||||
result = await self.low_level_pb_call(unit, address, value, use_call)
|
||||
|
||||
@@ -4,7 +4,7 @@ from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from pymonoprice import Monoprice, get_monoprice
|
||||
from serialx import SerialException
|
||||
from serial import SerialException
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PORT, Platform
|
||||
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
from typing import Any, override
|
||||
|
||||
from pymonoprice import get_monoprice
|
||||
from serialx import SerialException
|
||||
from serial import SerialException
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["pymonoprice"],
|
||||
"requirements": ["pymonoprice==0.6.1"]
|
||||
"requirements": ["pymonoprice==0.5"]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
from serialx import SerialException
|
||||
from serial import SerialException
|
||||
|
||||
from homeassistant import core
|
||||
from homeassistant.components.media_player import (
|
||||
|
||||
@@ -19,12 +19,13 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import (
|
||||
ATTR_LATITUDE,
|
||||
ATTR_LONGITUDE,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfPower,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
@@ -162,7 +163,7 @@ NETATMO_WEATHER_SENSOR_DESCRIPTIONS: Final[list[NetatmoSensorEntityDescription]]
|
||||
NetatmoSensorEntityDescription(
|
||||
key="co2",
|
||||
netatmo_name="co2",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
),
|
||||
@@ -189,7 +190,7 @@ NETATMO_WEATHER_SENSOR_DESCRIPTIONS: Final[list[NetatmoSensorEntityDescription]]
|
||||
NetatmoSensorEntityDescription(
|
||||
key="humidity",
|
||||
netatmo_name="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
),
|
||||
@@ -220,7 +221,7 @@ NETATMO_WEATHER_SENSOR_DESCRIPTIONS: Final[list[NetatmoSensorEntityDescription]]
|
||||
key="battery_percent",
|
||||
netatmo_name="battery",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
),
|
||||
@@ -335,7 +336,7 @@ PUBLIC_WEATHER_STATION_TYPES: tuple[
|
||||
),
|
||||
NetatmoPublicWeatherSensorEntityDescription(
|
||||
key="humidity",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
value_fn=lambda area: area.get_latest_humidities(),
|
||||
@@ -407,7 +408,7 @@ NETATMO_CLIMATE_BATTERY_SENSOR_DESCRIPTIONS: Final[
|
||||
key="battery",
|
||||
netatmo_name="battery",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
)
|
||||
@@ -418,7 +419,7 @@ NETATMO_OPENING_SENSOR_DESCRIPTIONS: Final[list[NetatmoSensorEntityDescription]]
|
||||
key="battery",
|
||||
netatmo_name="battery",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
is_sticky=True,
|
||||
|
||||
@@ -80,7 +80,6 @@ class NetgearRouterEntity(Entity):
|
||||
manufacturer="Netgear",
|
||||
name=router.device_name,
|
||||
model=router.model,
|
||||
serial_number=router.serial_number,
|
||||
sw_version=router.firmware_version,
|
||||
hw_version=router.hardware_version,
|
||||
configuration_url=configuration_url,
|
||||
|
||||
@@ -25,8 +25,6 @@ from .const import (
|
||||
DOMAIN,
|
||||
OVERRIDE_TYPE_CONSTANT,
|
||||
OVERRIDE_TYPE_NOW,
|
||||
SERIAL_LENGTH,
|
||||
SERIAL_PREFIX_LENGTH,
|
||||
)
|
||||
|
||||
DATA_NOBO_HUB_IMPL = "nobo_hub_flow_implementation"
|
||||
@@ -51,20 +49,7 @@ class NoboHubConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle the initial step."""
|
||||
if self._discovered_hubs is None:
|
||||
# Wait 5s — real-world gaps up to ~4s have been observed.
|
||||
discovered = dict(await nobo.async_discover_hubs(autodiscover_wait=5.0))
|
||||
# Hide hubs that already have a config entry. Include matching on IP
|
||||
# as serial prefix is not unique.
|
||||
configured = {
|
||||
(entry.data[CONF_IP_ADDRESS], entry.unique_id[:SERIAL_PREFIX_LENGTH])
|
||||
for entry in self._async_current_entries(include_ignore=False)
|
||||
if entry.unique_id
|
||||
}
|
||||
self._discovered_hubs = {
|
||||
ip: prefix
|
||||
for ip, prefix in discovered.items()
|
||||
if (ip, prefix) not in configured
|
||||
}
|
||||
self._discovered_hubs = dict(await nobo.async_discover_hubs())
|
||||
|
||||
if not self._discovered_hubs:
|
||||
# No hubs auto discovered
|
||||
@@ -242,7 +227,7 @@ class NoboHubConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
async def _test_connection(self, serial: str, ip_address: str) -> str:
|
||||
if len(serial) != SERIAL_LENGTH or not serial.isdigit():
|
||||
if not len(serial) == 12 or not serial.isdigit():
|
||||
raise NoboHubConnectError("invalid_serial")
|
||||
try:
|
||||
socket.inet_aton(ip_address)
|
||||
|
||||
@@ -9,11 +9,6 @@ CONF_OVERRIDE_TYPE = "override_type"
|
||||
OVERRIDE_TYPE_CONSTANT = "constant"
|
||||
OVERRIDE_TYPE_NOW = "now"
|
||||
|
||||
# Hub serial: 9-digit batch prefix + 3-digit per-hub suffix. Discovery
|
||||
# broadcasts only the prefix; the user supplies the suffix.
|
||||
SERIAL_PREFIX_LENGTH = 9
|
||||
SERIAL_LENGTH = SERIAL_PREFIX_LENGTH + 3
|
||||
|
||||
NOBO_MANUFACTURER = "Glen Dimplex Nordic AS"
|
||||
ATTR_HARDWARE_VERSION: Final = "hardware_version"
|
||||
ATTR_SOFTWARE_VERSION: Final = "software_version"
|
||||
|
||||
@@ -64,7 +64,11 @@ rules:
|
||||
docs-use-cases: todo
|
||||
dynamic-devices: todo
|
||||
entity-category: todo
|
||||
entity-device-class: done
|
||||
entity-device-class:
|
||||
status: todo
|
||||
comment: >
|
||||
Custom device class on global override select being dropped in
|
||||
PR #170135.
|
||||
entity-disabled-by-default: todo
|
||||
entity-translations: todo
|
||||
exception-translations: todo
|
||||
|
||||
@@ -53,6 +53,7 @@ class NoboGlobalSelector(NoboBaseEntity, SelectEntity):
|
||||
"""Global override selector for Nobø Ecohub."""
|
||||
|
||||
_attr_translation_key = "global_override"
|
||||
_attr_device_class = "nobo_hub__override"
|
||||
_modes = {
|
||||
nobo.API.OVERRIDE_MODE_NORMAL: "none",
|
||||
nobo.API.OVERRIDE_MODE_AWAY: "away",
|
||||
|
||||
@@ -4,9 +4,10 @@ from typing import Any, override
|
||||
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfMass,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
)
|
||||
@@ -138,7 +139,7 @@ class OmniLogicPumpSpeedSensor(OmnilogicSensor):
|
||||
pump_speed = self.coordinator.data[self._item_id][self._state_key]
|
||||
|
||||
if pump_type == "VARIABLE":
|
||||
self._attr_native_unit_of_measurement = UnitOfRatio.PERCENTAGE
|
||||
self._attr_native_unit_of_measurement = PERCENTAGE
|
||||
state = pump_speed
|
||||
elif pump_type == "DUAL":
|
||||
self._attr_native_unit_of_measurement = None
|
||||
@@ -278,7 +279,7 @@ SENSOR_TYPES: dict[tuple[int, str], list[dict[str, Any]]] = {
|
||||
"kind": "filter_pump_speed",
|
||||
"device_class": None,
|
||||
"icon": "mdi:speedometer",
|
||||
"unit": UnitOfRatio.PERCENTAGE,
|
||||
"unit": PERCENTAGE,
|
||||
"guard_condition": [
|
||||
{"Filter-Type": "FMT_SINGLE_SPEED"},
|
||||
],
|
||||
@@ -291,7 +292,7 @@ SENSOR_TYPES: dict[tuple[int, str], list[dict[str, Any]]] = {
|
||||
"kind": "pump_speed",
|
||||
"device_class": None,
|
||||
"icon": "mdi:speedometer",
|
||||
"unit": UnitOfRatio.PERCENTAGE,
|
||||
"unit": PERCENTAGE,
|
||||
"guard_condition": [
|
||||
{"Type": "PMP_SINGLE_SPEED"},
|
||||
],
|
||||
@@ -304,7 +305,7 @@ SENSOR_TYPES: dict[tuple[int, str], list[dict[str, Any]]] = {
|
||||
"kind": "chlorinator",
|
||||
"device_class": None,
|
||||
"icon": "mdi:gauge",
|
||||
"unit": UnitOfRatio.PERCENTAGE,
|
||||
"unit": PERCENTAGE,
|
||||
"guard_condition": [
|
||||
{
|
||||
"Shared-Type": "BOW_SHARED_EQUIPMENT",
|
||||
@@ -321,7 +322,7 @@ SENSOR_TYPES: dict[tuple[int, str], list[dict[str, Any]]] = {
|
||||
"kind": "salt_level",
|
||||
"device_class": None,
|
||||
"icon": "mdi:gauge",
|
||||
"unit": UnitOfRatio.PARTS_PER_MILLION,
|
||||
"unit": CONCENTRATION_PARTS_PER_MILLION,
|
||||
"guard_condition": [
|
||||
{
|
||||
"Shared-Type": "BOW_SHARED_EQUIPMENT",
|
||||
|
||||
@@ -9,9 +9,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -49,12 +50,12 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="tds",
|
||||
translation_key="tds",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="battery",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -62,7 +63,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="rssi",
|
||||
translation_key="rssi",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
import contextlib
|
||||
from datetime import timedelta
|
||||
from enum import IntEnum
|
||||
import io
|
||||
@@ -187,7 +188,9 @@ async def _async_upload_image(call: ServiceCall) -> None:
|
||||
current = asyncio.current_task()
|
||||
if (prev := entry.runtime_data.upload_task) is not None and not prev.done():
|
||||
prev.cancel()
|
||||
await asyncio.wait({prev})
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
with contextlib.suppress(asyncio.CancelledError):
|
||||
await prev
|
||||
entry.runtime_data.upload_task = current
|
||||
|
||||
try:
|
||||
|
||||
@@ -11,11 +11,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
UnitOfDensity,
|
||||
PERCENTAGE,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -44,21 +44,21 @@ SENSOR_DESCRIPTIONS: tuple[OpenSenseMapSensorEntityDescription, ...] = (
|
||||
OpenSenseMapSensorEntityDescription(
|
||||
key="pm2_5",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.pm2_5,
|
||||
),
|
||||
OpenSenseMapSensorEntityDescription(
|
||||
key="pm10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.pm10,
|
||||
),
|
||||
OpenSenseMapSensorEntityDescription(
|
||||
key="pm1_0",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.pm1_0,
|
||||
),
|
||||
@@ -72,7 +72,7 @@ SENSOR_DESCRIPTIONS: tuple[OpenSenseMapSensorEntityDescription, ...] = (
|
||||
OpenSenseMapSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.humidity,
|
||||
),
|
||||
|
||||
@@ -9,12 +9,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
DEGREE,
|
||||
PERCENTAGE,
|
||||
UV_INDEX,
|
||||
UnitOfDensity,
|
||||
UnitOfLength,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumetricFlux,
|
||||
@@ -107,7 +107,7 @@ WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -121,7 +121,7 @@ WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_CLOUDS,
|
||||
translation_key=ATTR_API_CLOUDS,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
@@ -174,43 +174,43 @@ AIRPOLLUTION_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_CO,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.CO,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_NO,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.NITROGEN_MONOXIDE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_NO2,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_O3,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.OZONE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_SO2,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_PM2_5,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=ATTR_API_AIRPOLLUTION_PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -13,8 +13,11 @@ from pyoverkiz.enums import (
|
||||
)
|
||||
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
Platform,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
@@ -23,7 +26,6 @@ from homeassistant.const import (
|
||||
UnitOfLength,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
@@ -163,19 +165,19 @@ OVERKIZ_UNIT_TO_HA: dict[str, str] = {
|
||||
),
|
||||
MeasuredValueType.FOSSIL_ENERGY_IN_WH: UnitOfEnergy.WATT_HOUR,
|
||||
MeasuredValueType.GRADIENT_IN_PERCENTAGE_PER_SECOND: (
|
||||
f"{UnitOfRatio.PERCENTAGE}/{UnitOfTime.SECONDS}"
|
||||
f"{PERCENTAGE}/{UnitOfTime.SECONDS}"
|
||||
),
|
||||
MeasuredValueType.LENGTH_IN_METER: UnitOfLength.METERS,
|
||||
MeasuredValueType.LINEAR_SPEED_IN_METER_PER_SECOND: UnitOfSpeed.METERS_PER_SECOND,
|
||||
MeasuredValueType.LUMINANCE_IN_LUX: LIGHT_LUX,
|
||||
MeasuredValueType.PARTS_PER_BILLION: UnitOfRatio.PARTS_PER_BILLION,
|
||||
MeasuredValueType.PARTS_PER_MILLION: UnitOfRatio.PARTS_PER_MILLION,
|
||||
MeasuredValueType.PARTS_PER_BILLION: CONCENTRATION_PARTS_PER_BILLION,
|
||||
MeasuredValueType.PARTS_PER_MILLION: CONCENTRATION_PARTS_PER_MILLION,
|
||||
MeasuredValueType.PARTS_PER_QUADRILLION: "ppq",
|
||||
MeasuredValueType.PARTS_PER_TRILLION: "ppt",
|
||||
MeasuredValueType.POWER_PER_SQUARE_METER: UnitOfIrradiance.WATTS_PER_SQUARE_METER,
|
||||
MeasuredValueType.PRESSURE_IN_HPA: UnitOfPressure.HPA,
|
||||
MeasuredValueType.PRESSURE_IN_MILLI_BAR: UnitOfPressure.MBAR,
|
||||
MeasuredValueType.RELATIVE_VALUE_IN_PERCENTAGE: UnitOfRatio.PERCENTAGE,
|
||||
MeasuredValueType.RELATIVE_VALUE_IN_PERCENTAGE: PERCENTAGE,
|
||||
MeasuredValueType.TEMPERATURE_IN_CELCIUS: UnitOfTemperature.CELSIUS,
|
||||
MeasuredValueType.TEMPERATURE_IN_KELVIN: UnitOfTemperature.KELVIN,
|
||||
MeasuredValueType.TIME_IN_SECOND: UnitOfTime.SECONDS,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["boto3", "botocore", "pyoverkiz", "s3transfer"],
|
||||
"requirements": ["pyoverkiz[nexity]==2.0.3"],
|
||||
"requirements": ["pyoverkiz[nexity]==2.0.2"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"name": "gateway*",
|
||||
|
||||
@@ -9,9 +9,9 @@ from homeassistant.components.number import (
|
||||
NumberEntityDescription,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
EntityCategory,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfRatio,
|
||||
UnitOfTime,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -46,7 +46,7 @@ NUMBER_DESCRIPTIONS: tuple[NumberEntityDescription, ...] = (
|
||||
key="cl_target",
|
||||
translation_key="cl_target",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key="ofa_ph_lower",
|
||||
@@ -78,13 +78,13 @@ NUMBER_DESCRIPTIONS: tuple[NumberEntityDescription, ...] = (
|
||||
key="ofa_cl_lower",
|
||||
translation_key="ofa_cl_lower",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key="ofa_cl_upper",
|
||||
translation_key="ofa_cl_upper",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key="time_off_ph_dosing",
|
||||
|
||||
@@ -11,9 +11,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
EntityCategory,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfRatio,
|
||||
UnitOfTime,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -51,7 +51,7 @@ SENSOR_DESCRIPTIONS: tuple[PooldoseSensorEntityDescription, ...] = (
|
||||
PooldoseSensorEntityDescription(
|
||||
key="cl",
|
||||
translation_key="cl",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
PooldoseSensorEntityDescription(
|
||||
key="flow_rate",
|
||||
|
||||
@@ -76,7 +76,6 @@ NODE_SENSORS: tuple[ProxmoxNodeBinarySensorEntityDescription, ...] = (
|
||||
),
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@ from homeassistant.helpers.selector import (
|
||||
SelectSelector,
|
||||
SelectSelectorConfig,
|
||||
SelectSelectorMode,
|
||||
TextSelector,
|
||||
TextSelectorConfig,
|
||||
TextSelectorType,
|
||||
)
|
||||
|
||||
from .common import sanitize_config_entry
|
||||
@@ -61,9 +58,7 @@ BASE_SCHEMA = vol.Schema(
|
||||
)
|
||||
),
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_USERNAME): TextSelector(
|
||||
TextSelectorConfig(type=TextSelectorType.TEXT, autocomplete="username")
|
||||
),
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
vol.Required(CONF_TOKEN, default=False): cv.boolean,
|
||||
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
|
||||
@@ -72,12 +67,7 @@ BASE_SCHEMA = vol.Schema(
|
||||
|
||||
PASSWORD_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_PASSWORD): TextSelector(
|
||||
TextSelectorConfig(
|
||||
type=TextSelectorType.PASSWORD,
|
||||
autocomplete="current-password",
|
||||
)
|
||||
),
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
}
|
||||
)
|
||||
TOKEN_SCHEMA = vol.Schema(
|
||||
|
||||
@@ -71,7 +71,7 @@ rules:
|
||||
dynamic-devices: done
|
||||
entity-category: done
|
||||
entity-device-class: done
|
||||
entity-disabled-by-default: done
|
||||
entity-disabled-by-default: todo
|
||||
entity-translations: done
|
||||
exception-translations: done
|
||||
icon-translations: done
|
||||
|
||||
@@ -71,9 +71,6 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = (
|
||||
key="node_max_cpu",
|
||||
translation_key="node_max_cpu",
|
||||
value_fn=lambda data: data.node["maxcpu"],
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxNodeSensorEntityDescription(
|
||||
key="node_disk",
|
||||
@@ -85,7 +82,6 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxNodeSensorEntityDescription(
|
||||
key="node_max_disk",
|
||||
@@ -97,7 +93,6 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxNodeSensorEntityDescription(
|
||||
key="node_memory",
|
||||
@@ -109,7 +104,6 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxNodeSensorEntityDescription(
|
||||
key="node_max_memory",
|
||||
@@ -158,7 +152,6 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = (
|
||||
),
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxNodeSensorEntityDescription(
|
||||
key="node_backup_duration",
|
||||
@@ -173,7 +166,6 @@ NODE_SENSORS: tuple[ProxmoxNodeSensorEntityDescription, ...] = (
|
||||
suggested_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -182,9 +174,6 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = (
|
||||
key="vm_max_cpu",
|
||||
translation_key="vm_max_cpu",
|
||||
value_fn=lambda data: data["cpus"],
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxVMSensorEntityDescription(
|
||||
key="vm_cpu",
|
||||
@@ -205,7 +194,6 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxVMSensorEntityDescription(
|
||||
key="vm_max_memory",
|
||||
@@ -247,7 +235,6 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxVMSensorEntityDescription(
|
||||
key="vm_max_disk",
|
||||
@@ -259,7 +246,6 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxVMSensorEntityDescription(
|
||||
key="vm_status",
|
||||
@@ -278,7 +264,6 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxVMSensorEntityDescription(
|
||||
key="vm_netout",
|
||||
@@ -290,7 +275,6 @@ VM_SENSORS: tuple[ProxmoxVMSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -299,9 +283,6 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = (
|
||||
key="container_max_cpu",
|
||||
translation_key="container_max_cpu",
|
||||
value_fn=lambda data: data["cpus"],
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxContainerSensorEntityDescription(
|
||||
key="container_cpu",
|
||||
@@ -322,7 +303,6 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxContainerSensorEntityDescription(
|
||||
key="container_max_memory",
|
||||
@@ -364,7 +344,6 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxContainerSensorEntityDescription(
|
||||
key="container_max_disk",
|
||||
@@ -376,7 +355,6 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxContainerSensorEntityDescription(
|
||||
key="container_status",
|
||||
@@ -395,7 +373,6 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProxmoxContainerSensorEntityDescription(
|
||||
key="container_netout",
|
||||
@@ -407,7 +384,6 @@ CONTAINER_SENSORS: tuple[ProxmoxContainerSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
UnitOfVolume,
|
||||
@@ -43,7 +43,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
PurpleAirSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda sensor: sensor.humidity,
|
||||
),
|
||||
@@ -74,7 +74,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
PurpleAirSensorEntityDescription(
|
||||
key="pm1.0_mass_concentration",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda sensor: sensor.pm1_0,
|
||||
),
|
||||
@@ -89,7 +89,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
PurpleAirSensorEntityDescription(
|
||||
key="pm10.0_mass_concentration",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda sensor: sensor.pm10_0,
|
||||
),
|
||||
@@ -104,7 +104,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
PurpleAirSensorEntityDescription(
|
||||
key="pm2.5_mass_concentration",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda sensor: sensor.pm2_5,
|
||||
),
|
||||
|
||||
@@ -20,12 +20,13 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -39,7 +40,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(QingpingSensorDeviceClass.BATTERY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{QingpingSensorDeviceClass.BATTERY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
@@ -49,13 +50,13 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{QingpingSensorDeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(QingpingSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{QingpingSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(QingpingSensorDeviceClass.ILLUMINANCE, Units.LIGHT_LUX): SensorEntityDescription(
|
||||
@@ -70,7 +71,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{QingpingSensorDeviceClass.PM10}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(
|
||||
@@ -79,7 +80,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{QingpingSensorDeviceClass.PM25}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(QingpingSensorDeviceClass.PRESSURE, Units.PRESSURE_MBAR): SensorEntityDescription(
|
||||
|
||||
@@ -34,7 +34,8 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
UnitOfRatio,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
UnitOfVolumeFlowRate,
|
||||
@@ -77,7 +78,7 @@ SENSORS: tuple[RensonSensorEntityDescription, ...] = (
|
||||
raw_format=True,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
RensonSensorEntityDescription(
|
||||
key="AIR_FIELD",
|
||||
@@ -85,7 +86,7 @@ SENSORS: tuple[RensonSensorEntityDescription, ...] = (
|
||||
field=AIR_QUALITY_FIELD,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
raw_format=True,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
RensonSensorEntityDescription(
|
||||
key="CURRENT_LEVEL_FIELD",
|
||||
@@ -144,7 +145,7 @@ SENSORS: tuple[RensonSensorEntityDescription, ...] = (
|
||||
raw_format=False,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
RensonSensorEntityDescription(
|
||||
key="MANUAL_LEVEL_FIELD",
|
||||
@@ -193,7 +194,7 @@ SENSORS: tuple[RensonSensorEntityDescription, ...] = (
|
||||
translation_key="co2_threshold",
|
||||
field=CO2_THRESHOLD_FIELD,
|
||||
raw_format=False,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
RensonSensorEntityDescription(
|
||||
@@ -201,7 +202,7 @@ SENSORS: tuple[RensonSensorEntityDescription, ...] = (
|
||||
translation_key="co2_hysteresis",
|
||||
field=CO2_HYSTERESIS_FIELD,
|
||||
raw_format=False,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
RensonSensorEntityDescription(
|
||||
@@ -220,7 +221,7 @@ SENSORS: tuple[RensonSensorEntityDescription, ...] = (
|
||||
raw_format=False,
|
||||
device_class=SensorDeviceClass.POWER_FACTOR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"loggers": ["roborock"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": [
|
||||
"python-roborock==5.22.0",
|
||||
"python-roborock==5.21.0",
|
||||
"vacuum-map-parser-roborock==0.1.5"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
from roborock.devices.traits.b01 import Q10PropertiesApi
|
||||
from roborock.devices.traits.b01.q10 import DoNotDisturbTrait
|
||||
from roborock.devices.traits.v1 import PropertiesApi
|
||||
from roborock.devices.traits.v1.common import RoborockSwitchBase
|
||||
from roborock.exceptions import RoborockException
|
||||
@@ -21,17 +19,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import (
|
||||
RoborockB01Q10UpdateCoordinator,
|
||||
RoborockConfigEntry,
|
||||
RoborockCoordinatorType,
|
||||
RoborockDataUpdateCoordinator,
|
||||
RoborockDataUpdateCoordinatorA01,
|
||||
)
|
||||
from .entity import (
|
||||
RoborockCoordinatedEntityA01,
|
||||
RoborockCoordinatedEntityB01Q10,
|
||||
RoborockEntityV1,
|
||||
)
|
||||
from .entity import RoborockCoordinatedEntityA01, RoborockEntityV1
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -86,13 +79,6 @@ class RoborockSwitchDescriptionA01(SwitchEntityDescription):
|
||||
data_protocol: RoborockDyadDataProtocol | RoborockZeoProtocol
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class RoborockSwitchDescriptionQ10(SwitchEntityDescription):
|
||||
"""Class to describe a Roborock Q10 switch entity."""
|
||||
|
||||
trait: Callable[[Q10PropertiesApi], DoNotDisturbTrait | None]
|
||||
|
||||
|
||||
A01_SWITCH_DESCRIPTIONS: list[RoborockSwitchDescriptionA01] = [
|
||||
RoborockSwitchDescriptionA01(
|
||||
key="sound_setting",
|
||||
@@ -103,16 +89,6 @@ A01_SWITCH_DESCRIPTIONS: list[RoborockSwitchDescriptionA01] = [
|
||||
]
|
||||
|
||||
|
||||
Q10_SWITCH_DESCRIPTIONS: list[RoborockSwitchDescriptionQ10] = [
|
||||
RoborockSwitchDescriptionQ10(
|
||||
key="do_not_disturb",
|
||||
translation_key="dnd_switch",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
trait=lambda traits: traits.do_not_disturb,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: RoborockConfigEntry,
|
||||
@@ -133,11 +109,10 @@ async def async_setup_entry(
|
||||
f"{description.key}_{coordinator.duid_slug}",
|
||||
coordinator,
|
||||
description,
|
||||
v1_trait,
|
||||
trait,
|
||||
)
|
||||
for description in SWITCH_DESCRIPTIONS
|
||||
if (v1_trait := description.trait(coordinator.properties_api))
|
||||
is not None
|
||||
if (trait := description.trait(coordinator.properties_api)) is not None
|
||||
)
|
||||
elif isinstance(coordinator, RoborockDataUpdateCoordinatorA01):
|
||||
entities.extend(
|
||||
@@ -148,17 +123,6 @@ async def async_setup_entry(
|
||||
for description in A01_SWITCH_DESCRIPTIONS
|
||||
if description.data_protocol in coordinator.request_protocols
|
||||
)
|
||||
elif isinstance(coordinator, RoborockB01Q10UpdateCoordinator):
|
||||
entities.extend(
|
||||
RoborockSwitchQ10(
|
||||
f"{description.key}_{coordinator.duid_slug}",
|
||||
coordinator,
|
||||
description,
|
||||
q10_trait,
|
||||
)
|
||||
for description in Q10_SWITCH_DESCRIPTIONS
|
||||
if (q10_trait := description.trait(coordinator.api)) is not None
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
for coordinator in coordinators.values():
|
||||
@@ -277,56 +241,3 @@ class RoborockSwitchA01(RoborockCoordinatedEntityA01, SwitchEntity):
|
||||
if status is None:
|
||||
return None
|
||||
return bool(status)
|
||||
|
||||
|
||||
class RoborockSwitchQ10(RoborockCoordinatedEntityB01Q10, SwitchEntity):
|
||||
"""A class to toggle a setting on a Roborock Q10 device."""
|
||||
|
||||
entity_description: RoborockSwitchDescriptionQ10
|
||||
coordinator: RoborockB01Q10UpdateCoordinator
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
unique_id: str,
|
||||
coordinator: RoborockB01Q10UpdateCoordinator,
|
||||
description: RoborockSwitchDescriptionQ10,
|
||||
trait: DoNotDisturbTrait,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
self.entity_description = description
|
||||
self._trait = trait
|
||||
super().__init__(unique_id, coordinator)
|
||||
|
||||
@override
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register a trait listener for push-based state updates."""
|
||||
await super().async_added_to_hass()
|
||||
self.async_on_remove(self._trait.add_update_listener(self.async_write_ha_state))
|
||||
|
||||
@override
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the switch."""
|
||||
try:
|
||||
await self._trait.disable()
|
||||
except RoborockException as err:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="update_options_failed",
|
||||
) from err
|
||||
|
||||
@override
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on the switch."""
|
||||
try:
|
||||
await self._trait.enable()
|
||||
except RoborockException as err:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="update_options_failed",
|
||||
) from err
|
||||
|
||||
@property
|
||||
@override
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return True if entity is on."""
|
||||
return self._trait.is_on
|
||||
|
||||
@@ -11,7 +11,7 @@ from homeassistant.components.number import (
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -48,7 +48,7 @@ DEVICE_NUMBER_TYPES = (
|
||||
key="calibration_hum",
|
||||
translation_key="calibration_humidity",
|
||||
device_class=NumberDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
remote_key="humidity",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
entity_registry_enabled_default=False,
|
||||
|
||||
@@ -14,11 +14,13 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -85,7 +87,7 @@ MOTION_SENSOR_TYPES: tuple[SensiboMotionSensorEntityDescription, ...] = (
|
||||
SensiboMotionSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.humidity,
|
||||
),
|
||||
@@ -179,7 +181,7 @@ AIRQ_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
|
||||
SensiboDeviceSensorEntityDescription(
|
||||
key="airq_tvoc",
|
||||
translation_key="airq_tvoc",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.tvoc,
|
||||
extra_fn=None,
|
||||
@@ -188,7 +190,7 @@ AIRQ_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
|
||||
key="airq_co2",
|
||||
translation_key="airq_co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.co2,
|
||||
extra_fn=None,
|
||||
@@ -200,7 +202,7 @@ ELEMENT_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
|
||||
SensiboDeviceSensorEntityDescription(
|
||||
key="pm25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.pm25,
|
||||
extra_fn=None,
|
||||
@@ -208,7 +210,7 @@ ELEMENT_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
|
||||
SensiboDeviceSensorEntityDescription(
|
||||
key="tvoc",
|
||||
translation_key="tvoc",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.tvoc,
|
||||
extra_fn=None,
|
||||
@@ -216,14 +218,14 @@ ELEMENT_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
|
||||
SensiboDeviceSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.co2,
|
||||
extra_fn=None,
|
||||
),
|
||||
SensiboDeviceSensorEntityDescription(
|
||||
key="ethanol",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="ethanol",
|
||||
value_fn=lambda data: data.etoh,
|
||||
|
||||
@@ -22,7 +22,11 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.sensor import sensor_device_info_to_hass_device_info
|
||||
@@ -38,13 +42,13 @@ SENSOR_DESCRIPTIONS: dict[
|
||||
): SensorEntityDescription(
|
||||
key=f"{SSDSensorDeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(SSDSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{SSDSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(SSDSensorDeviceClass.TEMPERATURE, Units.TEMP_CELSIUS): SensorEntityDescription(
|
||||
|
||||
@@ -10,7 +10,7 @@ from homeassistant.components.sensor import (
|
||||
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
||||
SensorEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_NAME, UnitOfDensity
|
||||
from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@@ -94,7 +94,7 @@ class ParticulateMatterSensor(SensorEntity):
|
||||
@override
|
||||
def native_unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return UnitOfDensity
|
||||
return CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
|
||||
def update(self) -> None:
|
||||
"""Read from sensor and update the state."""
|
||||
|
||||
@@ -15,15 +15,16 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfArea,
|
||||
UnitOfDensity,
|
||||
UnitOfEnergy,
|
||||
UnitOfMass,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
UnitOfVolumeFlowRate,
|
||||
@@ -239,7 +240,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.VOLUME,
|
||||
translation_key="audio_volume",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
deprecated=(
|
||||
lambda status: (
|
||||
("2025.10.0", "media_player")
|
||||
@@ -254,7 +255,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
Attribute.BATTERY: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
)
|
||||
@@ -287,7 +288,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
Attribute.CARBON_DIOXIDE: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.CARBON_DIOXIDE,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
@@ -309,7 +310,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
Attribute.CARBON_MONOXIDE_LEVEL: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.CARBON_MONOXIDE_LEVEL,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
@@ -355,7 +356,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.WATER_FILTER_USAGE,
|
||||
translation_key="water_filter_usage",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
]
|
||||
@@ -467,7 +468,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.DUST_LEVEL,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
],
|
||||
@@ -475,7 +476,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.FINE_DUST_LEVEL,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
],
|
||||
@@ -506,7 +507,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.EQUIVALENT_CARBON_DIOXIDE_MEASUREMENT,
|
||||
translation_key="equivalent_carbon_dioxide",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
@@ -527,7 +528,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
Attribute.FINE_DUST_LEVEL: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.FINE_DUST_LEVEL,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
)
|
||||
@@ -539,7 +540,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.FORMALDEHYDE_LEVEL,
|
||||
translation_key="formaldehyde",
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
]
|
||||
@@ -593,7 +594,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.INFRARED_LEVEL,
|
||||
translation_key="infrared_level",
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
]
|
||||
@@ -868,7 +869,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
Attribute.HUMIDITY: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.HUMIDITY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
@@ -1094,7 +1095,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.TVOC_LEVEL,
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
]
|
||||
@@ -1123,7 +1124,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
Attribute.VERY_FINE_DUST_LEVEL: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
key=Attribute.VERY_FINE_DUST_LEVEL,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
)
|
||||
@@ -1222,7 +1223,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
key=Attribute.HOOD_FILTER_USAGE,
|
||||
translation_key="hood_filter_usage",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
)
|
||||
]
|
||||
@@ -1318,7 +1319,7 @@ UNITS = {
|
||||
"ccf": UnitOfVolume.CENTUM_CUBIC_FEET,
|
||||
"lux": LIGHT_LUX,
|
||||
"mG": None,
|
||||
"μg/m^3": UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
"μg/m^3": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
"kPa": UnitOfPressure.KPA,
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,7 @@ from pysmlight.const import Devices
|
||||
from pysmlight.exceptions import SmlightAuthError, SmlightConnectionError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_RECONFIGURE,
|
||||
SOURCE_USER,
|
||||
ConfigFlow,
|
||||
ConfigFlowResult,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_USER, ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
@@ -87,17 +82,6 @@ class SmlightConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
if info.model not in Devices:
|
||||
return self.async_abort(reason="unsupported_device")
|
||||
|
||||
if self.source == SOURCE_RECONFIGURE:
|
||||
await self.async_set_unique_id(format_mac(info.MAC))
|
||||
self._abort_if_unique_id_mismatch()
|
||||
return self.async_update_reload_and_abort(
|
||||
self._get_reconfigure_entry(),
|
||||
data_updates={
|
||||
CONF_HOST: self._host,
|
||||
**user_input,
|
||||
},
|
||||
)
|
||||
|
||||
return await self._async_complete_entry(user_input)
|
||||
except SmlightConnectionError:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
@@ -200,45 +184,6 @@ class SmlightConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle reconfiguration of SMLIGHT device."""
|
||||
errors: dict[str, str] = {}
|
||||
entry = self._get_reconfigure_entry()
|
||||
|
||||
if user_input is not None:
|
||||
self._host = user_input[CONF_HOST]
|
||||
self.client = Api2(self._host, session=async_get_clientsession(self.hass))
|
||||
|
||||
check_input = {**entry.data, **user_input}
|
||||
try:
|
||||
await self._async_check_auth_required(check_input)
|
||||
info = await self.client.get_info()
|
||||
except SmlightConnectionError:
|
||||
errors["base"] = "cannot_connect"
|
||||
except SmlightAuthError:
|
||||
return await self.async_step_auth()
|
||||
else:
|
||||
if info.model not in Devices:
|
||||
return self.async_abort(reason="unsupported_device")
|
||||
|
||||
await self.async_set_unique_id(format_mac(info.MAC))
|
||||
self._abort_if_unique_id_mismatch()
|
||||
|
||||
return self.async_update_reload_and_abort(
|
||||
entry,
|
||||
data_updates=user_input,
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure",
|
||||
data_schema=self.add_suggested_values_to_schema(
|
||||
STEP_USER_DATA_SCHEMA, user_input or entry.data
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
@override
|
||||
async def async_step_dhcp(
|
||||
self, discovery_info: DhcpServiceInfo
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["pysmlight==0.5.0"],
|
||||
"requirements": ["pysmlight==0.4.0"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_slzb-06._tcp.local."
|
||||
|
||||
@@ -69,7 +69,7 @@ rules:
|
||||
entity-translations: done
|
||||
exception-translations: done
|
||||
icon-translations: done
|
||||
reconfiguration-flow: done
|
||||
reconfiguration-flow: todo
|
||||
repair-issues: done
|
||||
stale-devices:
|
||||
status: exempt
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user