mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add Kaiterra integration (#26661)
* add Kaiterra integration * fix: split to multiple platforms * fix lint issues * fix formmating * fix: docstrings * fix: pylint issues * Apply suggestions from code review Co-Authored-By: Martin Hjelmare <marhje52@kth.se> * Adjust code based on suggestions * Update homeassistant/components/kaiterra/sensor.py Co-Authored-By: Martin Hjelmare <marhje52@kth.se>
This commit is contained in:
parent
f82f30dc62
commit
fbe85a2eb2
@ -318,6 +318,7 @@ omit =
|
|||||||
homeassistant/components/itunes/media_player.py
|
homeassistant/components/itunes/media_player.py
|
||||||
homeassistant/components/joaoapps_join/*
|
homeassistant/components/joaoapps_join/*
|
||||||
homeassistant/components/juicenet/*
|
homeassistant/components/juicenet/*
|
||||||
|
homeassistant/components/kaiterra/*
|
||||||
homeassistant/components/kankun/switch.py
|
homeassistant/components/kankun/switch.py
|
||||||
homeassistant/components/keba/*
|
homeassistant/components/keba/*
|
||||||
homeassistant/components/keenetic_ndms2/device_tracker.py
|
homeassistant/components/keenetic_ndms2/device_tracker.py
|
||||||
|
@ -146,6 +146,7 @@ homeassistant/components/iqvia/* @bachya
|
|||||||
homeassistant/components/irish_rail_transport/* @ttroy50
|
homeassistant/components/irish_rail_transport/* @ttroy50
|
||||||
homeassistant/components/izone/* @Swamp-Ig
|
homeassistant/components/izone/* @Swamp-Ig
|
||||||
homeassistant/components/jewish_calendar/* @tsvi
|
homeassistant/components/jewish_calendar/* @tsvi
|
||||||
|
homeassistant/components/kaiterra/* @Michsior14
|
||||||
homeassistant/components/keba/* @dannerph
|
homeassistant/components/keba/* @dannerph
|
||||||
homeassistant/components/knx/* @Julius2342
|
homeassistant/components/knx/* @Julius2342
|
||||||
homeassistant/components/kodi/* @armills
|
homeassistant/components/kodi/* @armills
|
||||||
|
92
homeassistant/components/kaiterra/__init__.py
Normal file
92
homeassistant/components/kaiterra/__init__.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
"""Support for Kaiterra devices."""
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_API_KEY,
|
||||||
|
CONF_DEVICES,
|
||||||
|
CONF_DEVICE_ID,
|
||||||
|
CONF_SCAN_INTERVAL,
|
||||||
|
CONF_TYPE,
|
||||||
|
CONF_NAME,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
AVAILABLE_AQI_STANDARDS,
|
||||||
|
AVAILABLE_UNITS,
|
||||||
|
AVAILABLE_DEVICE_TYPES,
|
||||||
|
CONF_AQI_STANDARD,
|
||||||
|
CONF_PREFERRED_UNITS,
|
||||||
|
DOMAIN,
|
||||||
|
DEFAULT_AQI_STANDARD,
|
||||||
|
DEFAULT_PREFERRED_UNIT,
|
||||||
|
DEFAULT_SCAN_INTERVAL,
|
||||||
|
KAITERRA_COMPONENTS,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .api_data import KaiterraApiData
|
||||||
|
|
||||||
|
KAITERRA_DEVICE_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||||
|
vol.Required(CONF_TYPE): vol.In(AVAILABLE_DEVICE_TYPES),
|
||||||
|
vol.Optional(CONF_NAME): cv.string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
KAITERRA_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_API_KEY): cv.string,
|
||||||
|
vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, [KAITERRA_DEVICE_SCHEMA]),
|
||||||
|
vol.Optional(CONF_AQI_STANDARD, default=DEFAULT_AQI_STANDARD): vol.In(
|
||||||
|
AVAILABLE_AQI_STANDARDS
|
||||||
|
),
|
||||||
|
vol.Optional(CONF_PREFERRED_UNITS, default=DEFAULT_PREFERRED_UNIT): vol.All(
|
||||||
|
cv.ensure_list, [vol.In(AVAILABLE_UNITS)]
|
||||||
|
),
|
||||||
|
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): cv.time_period,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({DOMAIN: KAITERRA_SCHEMA}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass, config):
|
||||||
|
"""Set up the Kaiterra components."""
|
||||||
|
|
||||||
|
conf = config[DOMAIN]
|
||||||
|
scan_interval = conf[CONF_SCAN_INTERVAL]
|
||||||
|
devices = conf[CONF_DEVICES]
|
||||||
|
session = async_get_clientsession(hass)
|
||||||
|
api = hass.data[DOMAIN] = KaiterraApiData(hass, conf, session)
|
||||||
|
|
||||||
|
await api.async_update()
|
||||||
|
|
||||||
|
async def _update(now=None):
|
||||||
|
"""Periodic update."""
|
||||||
|
await api.async_update()
|
||||||
|
|
||||||
|
async_track_time_interval(hass, _update, scan_interval)
|
||||||
|
|
||||||
|
# Load platforms for each device
|
||||||
|
for device in devices:
|
||||||
|
device_name, device_id = (
|
||||||
|
device.get(CONF_NAME) or device[CONF_TYPE],
|
||||||
|
device[CONF_DEVICE_ID],
|
||||||
|
)
|
||||||
|
for component in KAITERRA_COMPONENTS:
|
||||||
|
hass.async_create_task(
|
||||||
|
async_load_platform(
|
||||||
|
hass,
|
||||||
|
component,
|
||||||
|
DOMAIN,
|
||||||
|
{CONF_NAME: device_name, CONF_DEVICE_ID: device_id},
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
115
homeassistant/components/kaiterra/air_quality.py
Normal file
115
homeassistant/components/kaiterra/air_quality.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
"""Support for Kaiterra Air Quality Sensors."""
|
||||||
|
from homeassistant.components.air_quality import AirQualityEntity
|
||||||
|
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
from homeassistant.const import CONF_DEVICE_ID, CONF_NAME
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
DOMAIN,
|
||||||
|
ATTR_VOC,
|
||||||
|
ATTR_AQI_LEVEL,
|
||||||
|
ATTR_AQI_POLLUTANT,
|
||||||
|
DISPATCHER_KAITERRA,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the air_quality kaiterra sensor."""
|
||||||
|
if discovery_info is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
api = hass.data[DOMAIN]
|
||||||
|
name = discovery_info[CONF_NAME]
|
||||||
|
device_id = discovery_info[CONF_DEVICE_ID]
|
||||||
|
|
||||||
|
async_add_entities([KaiterraAirQuality(api, name, device_id)])
|
||||||
|
|
||||||
|
|
||||||
|
class KaiterraAirQuality(AirQualityEntity):
|
||||||
|
"""Implementation of a Kaittera air quality sensor."""
|
||||||
|
|
||||||
|
def __init__(self, api, name, device_id):
|
||||||
|
"""Initialize the sensor."""
|
||||||
|
self._api = api
|
||||||
|
self._name = f"{name} Air Quality"
|
||||||
|
self._device_id = device_id
|
||||||
|
|
||||||
|
def _data(self, key):
|
||||||
|
return self._device.get(key, {}).get("value")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _device(self):
|
||||||
|
return self._api.data.get(self._device_id, {})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""Return that the sensor should not be polled."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return the availability of the sensor."""
|
||||||
|
return self._api.data.get(self._device_id) is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the sensor."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def air_quality_index(self):
|
||||||
|
"""Return the Air Quality Index (AQI)."""
|
||||||
|
return self._data("aqi")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def air_quality_index_level(self):
|
||||||
|
"""Return the Air Quality Index level."""
|
||||||
|
return self._data("aqi_level")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def air_quality_index_pollutant(self):
|
||||||
|
"""Return the Air Quality Index level."""
|
||||||
|
return self._data("aqi_pollutant")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def particulate_matter_2_5(self):
|
||||||
|
"""Return the particulate matter 2.5 level."""
|
||||||
|
return self._data("rpm25c")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def particulate_matter_10(self):
|
||||||
|
"""Return the particulate matter 10 level."""
|
||||||
|
return self._data("rpm10c")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def volatile_organic_compounds(self):
|
||||||
|
"""Return the VOC (Volatile Organic Compounds) level."""
|
||||||
|
return self._data("rtvoc")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Return the sensor's unique id."""
|
||||||
|
return f"{self._device_id}_air_quality"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
"""Return the device state attributes."""
|
||||||
|
data = {}
|
||||||
|
attributes = [
|
||||||
|
(ATTR_VOC, self.volatile_organic_compounds),
|
||||||
|
(ATTR_AQI_LEVEL, self.air_quality_index_level),
|
||||||
|
(ATTR_AQI_POLLUTANT, self.air_quality_index_pollutant),
|
||||||
|
]
|
||||||
|
|
||||||
|
for attr, value in attributes:
|
||||||
|
if value is not None:
|
||||||
|
data[attr] = value
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Register callback."""
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass, DISPATCHER_KAITERRA, self.async_write_ha_state
|
||||||
|
)
|
109
homeassistant/components/kaiterra/api_data.py
Normal file
109
homeassistant/components/kaiterra/api_data.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
"""Data for all Kaiterra devices."""
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
|
|
||||||
|
from aiohttp.client_exceptions import ClientResponseError
|
||||||
|
|
||||||
|
from kaiterra_async_client import KaiterraAPIClient, AQIStandard, Units
|
||||||
|
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
|
from homeassistant.const import CONF_API_KEY, CONF_DEVICES, CONF_DEVICE_ID, CONF_TYPE
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
AQI_SCALE,
|
||||||
|
AQI_LEVEL,
|
||||||
|
CONF_AQI_STANDARD,
|
||||||
|
CONF_PREFERRED_UNITS,
|
||||||
|
DISPATCHER_KAITERRA,
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER = getLogger(__name__)
|
||||||
|
|
||||||
|
POLLUTANTS = {"rpm25c": "PM2.5", "rpm10c": "PM10", "rtvoc": "TVOC"}
|
||||||
|
|
||||||
|
|
||||||
|
class KaiterraApiData:
|
||||||
|
"""Get data from Kaiterra API."""
|
||||||
|
|
||||||
|
def __init__(self, hass, config, session):
|
||||||
|
"""Initialize the API data object."""
|
||||||
|
|
||||||
|
api_key = config[CONF_API_KEY]
|
||||||
|
aqi_standard = config[CONF_AQI_STANDARD]
|
||||||
|
devices = config[CONF_DEVICES]
|
||||||
|
units = config[CONF_PREFERRED_UNITS]
|
||||||
|
|
||||||
|
self._hass = hass
|
||||||
|
self._api = KaiterraAPIClient(
|
||||||
|
session,
|
||||||
|
api_key=api_key,
|
||||||
|
aqi_standard=AQIStandard.from_str(aqi_standard),
|
||||||
|
preferred_units=[Units.from_str(unit) for unit in units],
|
||||||
|
)
|
||||||
|
self._devices_ids = [device[CONF_DEVICE_ID] for device in devices]
|
||||||
|
self._devices = [
|
||||||
|
f"/{device[CONF_TYPE]}s/{device[CONF_DEVICE_ID]}" for device in devices
|
||||||
|
]
|
||||||
|
self._scale = AQI_SCALE[aqi_standard]
|
||||||
|
self._level = AQI_LEVEL[aqi_standard]
|
||||||
|
self._update_listeners = []
|
||||||
|
self.data = {}
|
||||||
|
|
||||||
|
async def async_update(self) -> None:
|
||||||
|
"""Get the data from Kaiterra API."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
with async_timeout.timeout(10):
|
||||||
|
data = await self._api.get_latest_sensor_readings(self._devices)
|
||||||
|
except (ClientResponseError, asyncio.TimeoutError):
|
||||||
|
_LOGGER.debug("Couldn't fetch data")
|
||||||
|
self.data = {}
|
||||||
|
async_dispatcher_send(self._hass, DISPATCHER_KAITERRA)
|
||||||
|
|
||||||
|
_LOGGER.debug("New data retrieved: %s", data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.data = {}
|
||||||
|
for i, device in enumerate(data):
|
||||||
|
if not device:
|
||||||
|
self.data[self._devices_ids[i]] = {}
|
||||||
|
continue
|
||||||
|
|
||||||
|
aqi, main_pollutant = None, None
|
||||||
|
for sensor_name, sensor in device.items():
|
||||||
|
points = sensor.get("points")
|
||||||
|
|
||||||
|
if not points:
|
||||||
|
continue
|
||||||
|
|
||||||
|
point = points[0]
|
||||||
|
sensor["value"] = point.get("value")
|
||||||
|
|
||||||
|
if "aqi" not in point:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sensor["aqi"] = point["aqi"]
|
||||||
|
if not aqi or aqi < point["aqi"]:
|
||||||
|
aqi = point["aqi"]
|
||||||
|
main_pollutant = POLLUTANTS.get(sensor_name)
|
||||||
|
|
||||||
|
level = None
|
||||||
|
for j in range(1, len(self._scale)):
|
||||||
|
if aqi <= self._scale[j]:
|
||||||
|
level = self._level[j - 1]
|
||||||
|
break
|
||||||
|
|
||||||
|
device["aqi"] = {"value": aqi}
|
||||||
|
device["aqi_level"] = {"value": level}
|
||||||
|
device["aqi_pollutant"] = {"value": main_pollutant}
|
||||||
|
|
||||||
|
self.data[self._devices_ids[i]] = device
|
||||||
|
|
||||||
|
async_dispatcher_send(self._hass, DISPATCHER_KAITERRA)
|
||||||
|
except IndexError as err:
|
||||||
|
_LOGGER.error("Parsing error %s", err)
|
||||||
|
async_dispatcher_send(self._hass, DISPATCHER_KAITERRA)
|
57
homeassistant/components/kaiterra/const.py
Normal file
57
homeassistant/components/kaiterra/const.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
"""Consts for Kaiterra integration."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
DOMAIN = "kaiterra"
|
||||||
|
|
||||||
|
DISPATCHER_KAITERRA = "kaiterra_update"
|
||||||
|
|
||||||
|
AQI_SCALE = {
|
||||||
|
"cn": [0, 50, 100, 150, 200, 300, 400, 500],
|
||||||
|
"in": [0, 50, 100, 200, 300, 400, 500],
|
||||||
|
"us": [0, 50, 100, 150, 200, 300, 500],
|
||||||
|
}
|
||||||
|
AQI_LEVEL = {
|
||||||
|
"cn": [
|
||||||
|
"Good",
|
||||||
|
"Satisfactory",
|
||||||
|
"Moderate",
|
||||||
|
"Unhealthy for sensitive groups",
|
||||||
|
"Unhealthy",
|
||||||
|
"Very unhealthy",
|
||||||
|
"Hazardous",
|
||||||
|
],
|
||||||
|
"in": [
|
||||||
|
"Good",
|
||||||
|
"Satisfactory",
|
||||||
|
"Moderately polluted",
|
||||||
|
"Poor",
|
||||||
|
"Very poor",
|
||||||
|
"Severe",
|
||||||
|
],
|
||||||
|
"us": [
|
||||||
|
"Good",
|
||||||
|
"Moderate",
|
||||||
|
"Unhealthy for sensitive groups",
|
||||||
|
"Unhealthy",
|
||||||
|
"Very unhealthy",
|
||||||
|
"Hazardous",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTR_VOC = "volatile_organic_compounds"
|
||||||
|
ATTR_AQI_LEVEL = "air_quality_index_level"
|
||||||
|
ATTR_AQI_POLLUTANT = "air_quality_index_pollutant"
|
||||||
|
|
||||||
|
AVAILABLE_AQI_STANDARDS = ["us", "cn", "in"]
|
||||||
|
AVAILABLE_UNITS = ["x", "%", "C", "F", "mg/m³", "µg/m³", "ppm", "ppb"]
|
||||||
|
AVAILABLE_DEVICE_TYPES = ["laseregg", "sensedge"]
|
||||||
|
|
||||||
|
CONF_AQI_STANDARD = "aqi_standard"
|
||||||
|
CONF_PREFERRED_UNITS = "preferred_units"
|
||||||
|
|
||||||
|
DEFAULT_AQI_STANDARD = "us"
|
||||||
|
DEFAULT_PREFERRED_UNIT = []
|
||||||
|
DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
|
||||||
|
|
||||||
|
KAITERRA_COMPONENTS = ["sensor", "air_quality"]
|
8
homeassistant/components/kaiterra/manifest.json
Normal file
8
homeassistant/components/kaiterra/manifest.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"domain": "kaiterra",
|
||||||
|
"name": "Kaiterra",
|
||||||
|
"documentation": "https://www.home-assistant.io/components/kaiterra",
|
||||||
|
"requirements": ["kaiterra-async-client==0.0.2"],
|
||||||
|
"codeowners": ["@Michsior14"],
|
||||||
|
"dependencies": []
|
||||||
|
}
|
95
homeassistant/components/kaiterra/sensor.py
Normal file
95
homeassistant/components/kaiterra/sensor.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
"""Support for Kaiterra Temperature ahn Humidity Sensors."""
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
from homeassistant.const import CONF_DEVICE_ID, CONF_NAME, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||||
|
|
||||||
|
from .const import DOMAIN, DISPATCHER_KAITERRA
|
||||||
|
|
||||||
|
SENSORS = [
|
||||||
|
{"name": "Temperature", "prop": "rtemp", "device_class": "temperature"},
|
||||||
|
{"name": "Humidity", "prop": "rhumid", "device_class": "humidity"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the kaiterra temperature and humidity sensor."""
|
||||||
|
if discovery_info is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
api = hass.data[DOMAIN]
|
||||||
|
name = discovery_info[CONF_NAME]
|
||||||
|
device_id = discovery_info[CONF_DEVICE_ID]
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
[KaiterraSensor(api, name, device_id, sensor) for sensor in SENSORS]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class KaiterraSensor(Entity):
|
||||||
|
"""Implementation of a Kaittera sensor."""
|
||||||
|
|
||||||
|
def __init__(self, api, name, device_id, sensor):
|
||||||
|
"""Initialize the sensor."""
|
||||||
|
self._api = api
|
||||||
|
self._name = f'{name} {sensor["name"]}'
|
||||||
|
self._device_id = device_id
|
||||||
|
self._kind = sensor["name"].lower()
|
||||||
|
self._property = sensor["prop"]
|
||||||
|
self._device_class = sensor["device_class"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _sensor(self):
|
||||||
|
"""Return the sensor data."""
|
||||||
|
return self._api.data.get(self._device_id, {}).get(self._property, {})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""Return that the sensor should not be polled."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return the availability of the sensor."""
|
||||||
|
return self._api.data.get(self._device_id) is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self):
|
||||||
|
"""Return the device class."""
|
||||||
|
return self._device_class
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state."""
|
||||||
|
return self._sensor.get("value")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Return the sensor's unique id."""
|
||||||
|
return f"{self._device_id}_{self._kind}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return the unit the value is expressed in."""
|
||||||
|
if not self._sensor.get("units"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
value = self._sensor["units"].value
|
||||||
|
|
||||||
|
if value == "F":
|
||||||
|
return TEMP_FAHRENHEIT
|
||||||
|
if value == "C":
|
||||||
|
return TEMP_CELSIUS
|
||||||
|
return value
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Register callback."""
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass, DISPATCHER_KAITERRA, self.async_write_ha_state
|
||||||
|
)
|
@ -707,6 +707,9 @@ jsonrpc-async==0.6
|
|||||||
# homeassistant.components.kodi
|
# homeassistant.components.kodi
|
||||||
jsonrpc-websocket==0.6
|
jsonrpc-websocket==0.6
|
||||||
|
|
||||||
|
# homeassistant.components.kaiterra
|
||||||
|
kaiterra-async-client==0.0.2
|
||||||
|
|
||||||
# homeassistant.components.keba
|
# homeassistant.components.keba
|
||||||
keba-kecontact==0.2.0
|
keba-kecontact==0.2.0
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user