Compare commits

..

7 Commits

Author SHA1 Message Date
Erik
0e00e15fa5 Update snapshots 2025-05-23 11:14:53 +02:00
Erik
3e19b5f6d5 Handle current entity id matches the automatic entity id 2025-05-23 11:14:22 +02:00
Erik
3f1d3bfc4a Update folder_watcher test 2025-05-23 11:14:20 +02:00
Erik
08a8bfaf8f Adjust test 2025-05-23 11:13:27 +02:00
Erik
31f8ea523f Fix logic and add additional tests 2025-05-23 11:13:26 +02:00
Erik
0924740cb4 Calculate suggested object id from entity properties 2025-05-23 11:13:26 +02:00
Erik
9f039002ff Add WS command to help reset custom entity_id 2025-05-12 08:10:43 +02:00
687 changed files with 16064 additions and 3281 deletions

View File

@@ -55,6 +55,7 @@ from homeassistant.helpers.deprecation import (
DeprecatedConstantEnum,
all_with_deprecated_constants,
check_if_deprecated_constant,
deprecated_function,
dir_with_deprecated_constants,
)
from homeassistant.helpers.entity import Entity, EntityDescription
@@ -85,10 +86,10 @@ from .prefs import CameraPreferences, DynamicStreamSettings # noqa: F401
from .webrtc import (
DATA_ICE_SERVERS,
CameraWebRTCProvider,
WebRTCAnswer, # noqa: F401
WebRTCAnswer,
WebRTCCandidate, # noqa: F401
WebRTCClientConfiguration,
WebRTCError, # noqa: F401
WebRTCError,
WebRTCMessage, # noqa: F401
WebRTCSendMessage,
async_get_supported_provider,
@@ -472,6 +473,9 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
self.async_update_token()
self._create_stream_lock: asyncio.Lock | None = None
self._webrtc_provider: CameraWebRTCProvider | None = None
self._supports_native_sync_webrtc = (
type(self).async_handle_web_rtc_offer != Camera.async_handle_web_rtc_offer
)
self._supports_native_async_webrtc = (
type(self).async_handle_async_webrtc_offer
!= Camera.async_handle_async_webrtc_offer
@@ -575,6 +579,15 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""
return None
async def async_handle_web_rtc_offer(self, offer_sdp: str) -> str | None:
"""Handle the WebRTC offer and return an answer.
This is used by cameras with CameraEntityFeature.STREAM
and StreamType.WEB_RTC.
Integrations can override with a native WebRTC implementation.
"""
async def async_handle_async_webrtc_offer(
self, offer_sdp: str, session_id: str, send_message: WebRTCSendMessage
) -> None:
@@ -587,6 +600,42 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
Integrations can override with a native WebRTC implementation.
"""
if self._supports_native_sync_webrtc:
try:
answer = await deprecated_function(
"async_handle_async_webrtc_offer",
breaks_in_ha_version="2025.6",
)(self.async_handle_web_rtc_offer)(offer_sdp)
except ValueError as ex:
_LOGGER.error("Error handling WebRTC offer: %s", ex)
send_message(
WebRTCError(
"webrtc_offer_failed",
str(ex),
)
)
except TimeoutError:
# This catch was already here and should stay through the deprecation
_LOGGER.error("Timeout handling WebRTC offer")
send_message(
WebRTCError(
"webrtc_offer_failed",
"Timeout handling WebRTC offer",
)
)
else:
if answer:
send_message(WebRTCAnswer(answer))
else:
_LOGGER.error("Error handling WebRTC offer: No answer")
send_message(
WebRTCError(
"webrtc_offer_failed",
"No answer on WebRTC offer",
)
)
return
if self._webrtc_provider:
await self._webrtc_provider.async_handle_async_webrtc_offer(
self, offer_sdp, session_id, send_message
@@ -715,7 +764,9 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
new_provider = None
# Skip all providers if the camera has a native WebRTC implementation
if not self._supports_native_async_webrtc:
if not (
self._supports_native_sync_webrtc or self._supports_native_async_webrtc
):
# Camera doesn't have a native WebRTC implementation
new_provider = await self._async_get_supported_webrtc_provider(
async_get_supported_provider
@@ -747,12 +798,17 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""Return the WebRTC client configuration and extend it with the registered ice servers."""
config = self._async_get_webrtc_client_configuration()
ice_servers = [
server
for servers in self.hass.data.get(DATA_ICE_SERVERS, [])
for server in servers()
]
config.configuration.ice_servers.extend(ice_servers)
if not self._supports_native_sync_webrtc:
# Until 2024.11, the frontend was not resolving any ice servers
# The async approach was added 2024.11 and new integrations need to use it
ice_servers = [
server
for servers in self.hass.data.get(DATA_ICE_SERVERS, [])
for server in servers()
]
config.configuration.ice_servers.extend(ice_servers)
config.get_candidates_upfront = self._supports_native_sync_webrtc
return config
@@ -782,7 +838,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""Return the camera capabilities."""
frontend_stream_types = set()
if CameraEntityFeature.STREAM in self.supported_features_compat:
if self._supports_native_async_webrtc:
if self._supports_native_sync_webrtc or self._supports_native_async_webrtc:
# The camera has a native WebRTC implementation
frontend_stream_types.add(StreamType.WEB_RTC)
else:

View File

@@ -111,11 +111,13 @@ class WebRTCClientConfiguration:
configuration: RTCConfiguration = field(default_factory=RTCConfiguration)
data_channel: str | None = None
get_candidates_upfront: bool = False
def to_frontend_dict(self) -> dict[str, Any]:
"""Return a dict that can be used by the frontend."""
data: dict[str, Any] = {
"configuration": self.configuration.to_dict(),
"getCandidatesUpfront": self.get_candidates_upfront,
}
if self.data_channel is not None:
data["dataChannel"] = self.data_channel

View File

@@ -43,7 +43,6 @@ VALID_REPAIR_TRANSLATION_KEYS = {
"no_subscription",
"warn_bad_custom_domain_configuration",
"reset_bad_custom_domain_configuration",
"subscription_expired",
}
@@ -405,12 +404,7 @@ class CloudClient(Interface):
) -> None:
"""Create a repair issue."""
if translation_key not in VALID_REPAIR_TRANSLATION_KEYS:
_LOGGER.error(
"Invalid translation key %s for repair issue %s",
translation_key,
identifier,
)
return
raise ValueError(f"Invalid translation key {translation_key}")
async_create_issue(
hass=self._hass,
domain=DOMAIN,

View File

@@ -73,10 +73,6 @@
"reset_bad_custom_domain_configuration": {
"title": "Custom domain ignored",
"description": "The DNS configuration for your custom domain ({custom_domains}) is not correct. This domain has now been ignored and will not be used for Home Assistant Cloud. If you want to use this domain, please fix the DNS configuration and restart Home Assistant. If you do not need this anymore, you can remove it from the account page."
},
"subscription_expired": {
"title": "Subscription has expired",
"description": "Your Home Assistant Cloud subscription has expired. Resubscribe at {account_url}."
}
},
"services": {

View File

@@ -8,5 +8,5 @@
"iot_class": "local_polling",
"loggers": ["aiocomelit"],
"quality_scale": "bronze",
"requirements": ["aiocomelit==0.12.1"]
"requirements": ["aiocomelit==0.12.0"]
}

View File

@@ -9,12 +9,13 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import websocket_api
from homeassistant.components.websocket_api import ERR_NOT_FOUND, require_admin
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import HomeAssistant, callback, split_entity_id
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
entity_registry as er,
)
from homeassistant.helpers.entity_component import async_get_entity_suggested_object_id
from homeassistant.helpers.json import json_dumps
@@ -22,6 +23,7 @@ from homeassistant.helpers.json import json_dumps
def async_setup(hass: HomeAssistant) -> bool:
"""Enable the Entity Registry views."""
websocket_api.async_register_command(hass, websocket_get_automatic_entity_ids)
websocket_api.async_register_command(hass, websocket_get_entities)
websocket_api.async_register_command(hass, websocket_get_entity)
websocket_api.async_register_command(hass, websocket_list_entities_for_display)
@@ -316,3 +318,43 @@ def websocket_remove_entity(
registry.async_remove(msg["entity_id"])
connection.send_message(websocket_api.result_message(msg["id"]))
@websocket_api.websocket_command(
{
vol.Required("type"): "config/entity_registry/get_automatic_entity_ids",
vol.Required("entity_ids"): cv.entity_ids,
}
)
@callback
def websocket_get_automatic_entity_ids(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Return the automatic entity IDs for the given entity IDs.
This is used to help user reset entity IDs which have been customized by the user.
"""
registry = er.async_get(hass)
entity_ids = msg["entity_ids"]
automatic_entity_ids: dict[str, str | None] = {}
for entity_id in entity_ids:
if not (entry := registry.entities.get(entity_id)):
automatic_entity_ids[entity_id] = None
continue
if (
suggested := async_get_entity_suggested_object_id(hass, entity_id)
) == split_entity_id(entry.entity_id)[1]:
# No need to generate a new entity ID
automatic_entity_ids[entity_id] = None
continue
automatic_entity_ids[entity_id] = registry.async_generate_entity_id(
entry.domain,
suggested or f"{entry.platform}_{entry.unique_id}",
)
connection.send_message(
websocket_api.result_message(msg["id"], automatic_entity_ids)
)

View File

@@ -14,7 +14,7 @@
],
"quality_scale": "internal",
"requirements": [
"aiodhcpwatcher==1.2.0",
"aiodhcpwatcher==1.1.1",
"aiodiscover==2.7.0",
"cached-ipaddress==0.10.0"
]

View File

@@ -107,7 +107,7 @@
"ac_module_temperature_sensor_faulty_l2": "AC module temperature sensor faulty (L2)",
"dc_component_measured_in_grid_too_high": "DC component measured in the grid too high",
"fixed_voltage_mode_out_of_range": "Fixed voltage mode has been selected instead of MPP voltage mode and the fixed voltage has been set to too low or too high a value",
"safety_cut_out_triggered": "Safety cut-out via option card or RECERBO has triggered",
"safety_cut_out_triggered": "Safety cut out via option card or RECERBO has triggered",
"no_communication_between_power_stage_and_control_system": "No communication possible between power stage set and control system",
"hardware_id_problem": "Hardware ID problem",
"unique_id_conflict": "Unique ID conflict",
@@ -148,7 +148,7 @@
"update_file_does_not_match_device": "Update file does not match the device, update file too old",
"write_or_read_error_occurred": "Write or read error occurred",
"file_could_not_be_opened": "File could not be opened",
"log_file_cannot_be_saved": "Log file cannot be saved (e.g. USB flash drive is write-protected or full)",
"log_file_cannot_be_saved": "Log file cannot be saved (e.g. USB flash drive is write protected or full)",
"initialisation_error_file_system_error_on_usb": "Initialization error in file system on USB flash drive",
"error_during_logging_data_recording": "Error during recording of logging data",
"error_during_update_process": "Error occurred during update process",
@@ -166,7 +166,7 @@
"invalid_device_type": "Invalid device type",
"insulation_measurement_triggered": "Insulation measurement triggered",
"inverter_settings_changed_restart_required": "Inverter settings have been changed, inverter restart required",
"wired_shut_down_triggered": "Wired shutdown triggered",
"wired_shut_down_triggered": "Wired shut down triggered",
"grid_frequency_exceeded_limit_reconnecting": "The grid frequency has exceeded a limit value when reconnecting",
"mains_voltage_dependent_power_reduction": "Mains voltage-dependent power reduction",
"too_little_dc_power_for_feed_in_operation": "Too little DC power for feed-in operation",

View File

@@ -14,78 +14,49 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.storage import Store
from homeassistant.util.hass_dict import HassKey
DATA_STORAGE: HassKey[dict[str, UserStore]] = HassKey("frontend_storage")
DATA_STORAGE: HassKey[tuple[dict[str, Store], dict[str, dict]]] = HassKey(
"frontend_storage"
)
STORAGE_VERSION_USER_DATA = 1
@callback
def _initialize_frontend_storage(hass: HomeAssistant) -> None:
"""Set up frontend storage."""
if DATA_STORAGE in hass.data:
return
hass.data[DATA_STORAGE] = ({}, {})
async def async_setup_frontend_storage(hass: HomeAssistant) -> None:
"""Set up frontend storage."""
_initialize_frontend_storage(hass)
websocket_api.async_register_command(hass, websocket_set_user_data)
websocket_api.async_register_command(hass, websocket_get_user_data)
websocket_api.async_register_command(hass, websocket_subscribe_user_data)
async def async_user_store(hass: HomeAssistant, user_id: str) -> UserStore:
async def async_user_store(
hass: HomeAssistant, user_id: str
) -> tuple[Store, dict[str, Any]]:
"""Access a user store."""
stores = hass.data.setdefault(DATA_STORAGE, {})
_initialize_frontend_storage(hass)
stores, data = hass.data[DATA_STORAGE]
if (store := stores.get(user_id)) is None:
store = stores[user_id] = UserStore(hass, user_id)
await store.async_load()
return store
class UserStore:
"""User store for frontend data."""
def __init__(self, hass: HomeAssistant, user_id: str) -> None:
"""Initialize the user store."""
self._store = _UserStore(hass, user_id)
self.data: dict[str, Any] = {}
self.subscriptions: dict[str | None, list[Callable[[], None]]] = {}
async def async_load(self) -> None:
"""Load the data from the store."""
self.data = await self._store.async_load() or {}
async def async_set_item(self, key: str, value: Any) -> None:
"""Set an item item and save the store."""
self.data[key] = value
await self._store.async_save(self.data)
for cb in self.subscriptions.get(None, []):
cb()
for cb in self.subscriptions.get(key, []):
cb()
@callback
def async_subscribe(
self, key: str | None, on_update_callback: Callable[[], None]
) -> Callable[[], None]:
"""Save the data to the store."""
self.subscriptions.setdefault(key, []).append(on_update_callback)
def unsubscribe() -> None:
"""Unsubscribe from the store."""
self.subscriptions[key].remove(on_update_callback)
return unsubscribe
class _UserStore(Store[dict[str, Any]]):
"""User store for frontend data."""
def __init__(self, hass: HomeAssistant, user_id: str) -> None:
"""Initialize the user store."""
super().__init__(
store = stores[user_id] = Store(
hass,
STORAGE_VERSION_USER_DATA,
f"frontend.user_data_{user_id}",
)
if user_id not in data:
data[user_id] = await store.async_load() or {}
def with_user_store(
return store, data[user_id]
def with_store(
orig_func: Callable[
[HomeAssistant, ActiveConnection, dict[str, Any], UserStore],
[HomeAssistant, ActiveConnection, dict[str, Any], Store, dict[str, Any]],
Coroutine[Any, Any, None],
],
) -> Callable[
@@ -94,17 +65,17 @@ def with_user_store(
"""Decorate function to provide data."""
@wraps(orig_func)
async def with_user_store_func(
async def with_store_func(
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
) -> None:
"""Provide user specific data and store to function."""
user_id = connection.user.id
store = await async_user_store(hass, user_id)
store, user_data = await async_user_store(hass, user_id)
await orig_func(hass, connection, msg, store)
await orig_func(hass, connection, msg, store, user_data)
return with_user_store_func
return with_store_func
@websocket_api.websocket_command(
@@ -115,57 +86,41 @@ def with_user_store(
}
)
@websocket_api.async_response
@with_user_store
@with_store
async def websocket_set_user_data(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict[str, Any],
store: UserStore,
store: Store,
data: dict[str, Any],
) -> None:
"""Handle set user data command."""
await store.async_set_item(msg["key"], msg["value"])
connection.send_result(msg["id"])
"""Handle set global data command.
Async friendly.
"""
data[msg["key"]] = msg["value"]
await store.async_save(data)
connection.send_message(websocket_api.result_message(msg["id"]))
@websocket_api.websocket_command(
{vol.Required("type"): "frontend/get_user_data", vol.Optional("key"): str}
)
@websocket_api.async_response
@with_user_store
@with_store
async def websocket_get_user_data(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict[str, Any],
store: UserStore,
store: Store,
data: dict[str, Any],
) -> None:
"""Handle get user data command."""
data = store.data
connection.send_result(
msg["id"], {"value": data.get(msg["key"]) if "key" in msg else data}
)
"""Handle get global data command.
@websocket_api.websocket_command(
{vol.Required("type"): "frontend/subscribe_user_data", vol.Optional("key"): str}
)
@websocket_api.async_response
@with_user_store
async def websocket_subscribe_user_data(
hass: HomeAssistant,
connection: ActiveConnection,
msg: dict[str, Any],
store: UserStore,
) -> None:
"""Handle subscribe to user data command."""
key: str | None = msg.get("key")
def on_data_update() -> None:
"""Handle user data update."""
data = store.data
connection.send_event(
msg["id"], {"value": data.get(key) if key is not None else data}
Async friendly.
"""
connection.send_message(
websocket_api.result_message(
msg["id"], {"value": data.get(msg["key"]) if "key" in msg else data}
)
connection.subscriptions[msg["id"]] = store.async_subscribe(key, on_data_update)
on_data_update()
connection.send_result(msg["id"])
)

View File

@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/google",
"iot_class": "cloud_polling",
"loggers": ["googleapiclient"],
"requirements": ["gcal-sync==7.0.1", "oauth2client==4.1.3", "ical==9.2.2"]
"requirements": ["gcal-sync==7.0.0", "oauth2client==4.1.3", "ical==9.2.1"]
}

View File

@@ -8,8 +8,7 @@ import jwt
import voluptuous as vol
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult
from homeassistant.helpers import config_entry_oauth2_flow, device_registry as dr
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
from homeassistant.helpers import config_entry_oauth2_flow
from .const import DOMAIN
@@ -59,22 +58,3 @@ class OAuth2FlowHandler(
)
self._abort_if_unique_id_configured()
return await super().async_oauth_create_entry(data)
async def async_step_dhcp(
self, discovery_info: DhcpServiceInfo
) -> ConfigFlowResult:
"""Handle a DHCP discovery."""
device_registry = dr.async_get(self.hass)
if device_entry := device_registry.async_get_device(
identifiers={
(DOMAIN, discovery_info.hostname),
(DOMAIN, discovery_info.hostname.split("-")[-1]),
}
):
device_registry.async_update_device(
device_entry.id,
new_connections={
(dr.CONNECTION_NETWORK_MAC, discovery_info.macaddress)
},
)
return await super().async_step_dhcp(discovery_info)

View File

@@ -110,14 +110,14 @@ class AutomowerLawnMowerEntity(AutomowerAvailableEntity, LawnMowerEntity):
mower_attributes = self.mower_attributes
if mower_attributes.mower.state in PAUSED_STATES:
return LawnMowerActivity.PAUSED
if (mower_attributes.mower.state == "RESTRICTED") or (
mower_attributes.mower.activity in DOCKED_ACTIVITIES
):
return LawnMowerActivity.DOCKED
if mower_attributes.mower.state in MowerStates.IN_OPERATION:
if mower_attributes.mower.activity == MowerActivities.GOING_HOME:
return LawnMowerActivity.RETURNING
return LawnMowerActivity.MOWING
if (mower_attributes.mower.state == "RESTRICTED") or (
mower_attributes.mower.activity in DOCKED_ACTIVITIES
):
return LawnMowerActivity.DOCKED
return LawnMowerActivity.ERROR
@property

View File

@@ -10,7 +10,7 @@
"iot_class": "local_push",
"loggers": ["xknx", "xknxproject"],
"requirements": [
"xknx==3.8.0",
"xknx==3.6.0",
"xknxproject==3.8.2",
"knx-frontend==2025.4.1.91934"
],

View File

@@ -19,6 +19,7 @@ from homeassistant.const import (
CONF_PORT,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType
@@ -43,6 +44,21 @@ CONFIG_SCHEMA = vol.Schema(CONFIG_DATA)
USER_SCHEMA = vol.Schema(USER_DATA)
def get_config_entry(
hass: HomeAssistant, data: ConfigType
) -> config_entries.ConfigEntry | None:
"""Check config entries for already configured entries based on the ip address/port."""
return next(
(
entry
for entry in hass.config_entries.async_entries(DOMAIN)
if entry.data[CONF_IP_ADDRESS] == data[CONF_IP_ADDRESS]
and entry.data[CONF_PORT] == data[CONF_PORT]
),
None,
)
async def validate_connection(data: ConfigType) -> str | None:
"""Validate if a connection to LCN can be established."""
error = None
@@ -104,20 +120,19 @@ class LcnFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if user_input is None:
return self.async_show_form(step_id="user", data_schema=USER_SCHEMA)
self._async_abort_entries_match(
{
CONF_IP_ADDRESS: user_input[CONF_IP_ADDRESS],
CONF_PORT: user_input[CONF_PORT],
}
)
errors = None
if get_config_entry(self.hass, user_input):
errors = {CONF_BASE: "already_configured"}
elif (error := await validate_connection(user_input)) is not None:
errors = {CONF_BASE: error}
if (error := await validate_connection(user_input)) is not None:
if errors is not None:
return self.async_show_form(
step_id="user",
data_schema=self.add_suggested_values_to_schema(
USER_SCHEMA, user_input
),
errors={CONF_BASE: error},
errors=errors,
)
data: dict = {
@@ -137,21 +152,15 @@ class LcnFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if user_input is not None:
user_input[CONF_HOST] = reconfigure_entry.data[CONF_HOST]
self._async_abort_entries_match(
{
CONF_IP_ADDRESS: user_input[CONF_IP_ADDRESS],
CONF_PORT: user_input[CONF_PORT],
}
)
await self.hass.config_entries.async_unload(reconfigure_entry.entry_id)
if (error := await validate_connection(user_input)) is not None:
errors = {CONF_BASE: error}
if (error := await validate_connection(user_input)) is None:
if errors is None:
return self.async_update_reload_and_abort(
reconfigure_entry, data_updates=user_input
)
errors = {CONF_BASE: error}
await self.hass.config_entries.async_setup(reconfigure_entry.entry_id)
return self.async_show_form(

View File

@@ -66,11 +66,11 @@
"error": {
"authentication_error": "Authentication failed. Wrong username or password.",
"license_error": "Maximum number of connections was reached. An additional licence key is required.",
"connection_refused": "Unable to connect to PCHK. Check IP and port."
"connection_refused": "Unable to connect to PCHK. Check IP and port.",
"already_configured": "PCHK connection using the same ip address/port is already configured."
},
"abort": {
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]",
"already_configured": "PCHK connection using the same ip address/port is already configured."
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]"
}
},
"issues": {

View File

@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
"iot_class": "local_polling",
"loggers": ["ical"],
"requirements": ["ical==9.2.2"]
"requirements": ["ical==9.2.1"]
}

View File

@@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/local_todo",
"iot_class": "local_polling",
"requirements": ["ical==9.2.2"]
"requirements": ["ical==9.2.1"]
}

View File

@@ -23,8 +23,6 @@ from .const import MieleAppliance
from .coordinator import MieleConfigEntry
from .entity import MieleEntity
PARALLEL_UPDATES = 0
_LOGGER = logging.getLogger(__name__)

View File

@@ -17,8 +17,6 @@ from .const import DOMAIN, PROCESS_ACTION, MieleActions, MieleAppliance
from .coordinator import MieleConfigEntry
from .entity import MieleEntity
PARALLEL_UPDATES = 1
_LOGGER = logging.getLogger(__name__)

View File

@@ -26,8 +26,6 @@ from .const import DEVICE_TYPE_TAGS, DISABLED_TEMP_ENTITIES, DOMAIN, MieleApplia
from .coordinator import MieleConfigEntry, MieleDataUpdateCoordinator
from .entity import MieleEntity
PARALLEL_UPDATES = 1
_LOGGER = logging.getLogger(__name__)

View File

@@ -27,8 +27,6 @@ from .const import DOMAIN, POWER_OFF, POWER_ON, VENTILATION_STEP, MieleAppliance
from .coordinator import MieleConfigEntry, MieleDataUpdateCoordinator
from .entity import MieleEntity
PARALLEL_UPDATES = 1
_LOGGER = logging.getLogger(__name__)
SPEED_RANGE = (1, 4)

View File

@@ -32,9 +32,6 @@
"core_target_temperature": {
"default": "mdi:thermometer-probe"
},
"target_temperature": {
"default": "mdi:thermometer-check"
},
"drying_step": {
"default": "mdi:water-outline"
},

View File

@@ -23,8 +23,6 @@ from .const import AMBIENT_LIGHT, DOMAIN, LIGHT, LIGHT_OFF, LIGHT_ON, MieleAppli
from .coordinator import MieleConfigEntry
from .entity import MieleDevice, MieleEntity
PARALLEL_UPDATES = 1
_LOGGER = logging.getLogger(__name__)

View File

@@ -32,23 +32,18 @@ rules:
Handled by a setting in manifest.json as there is no account information in API
# Silver
action-exceptions:
status: done
comment: No custom actions are defined
action-exceptions: todo
config-entry-unloading: done
docs-configuration-parameters:
status: exempt
comment: No configuration parameters
docs-installation-parameters:
status: exempt
comment: |
Integration uses account linking via Nabu casa so no installation parameters are needed.
docs-installation-parameters: todo
entity-unavailable: done
integration-owner: done
log-when-unavailable:
status: done
comment: Handled by DataUpdateCoordinator
parallel-updates: done
log-when-unavailable: todo
parallel-updates:
status: exempt
comment: Handled by coordinator
reauthentication-flow: done
test-coverage: todo

View File

@@ -39,8 +39,6 @@ from .const import (
from .coordinator import MieleConfigEntry, MieleDataUpdateCoordinator
from .entity import MieleEntity
PARALLEL_UPDATES = 0
_LOGGER = logging.getLogger(__name__)
DISABLED_TEMPERATURE = -32768
@@ -384,7 +382,6 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
MieleAppliance.OVEN,
MieleAppliance.OVEN_MICROWAVE,
MieleAppliance.STEAM_OVEN_COMBI,
MieleAppliance.STEAM_OVEN_MK2,
),
description=MieleSensorDescription(
key="state_core_target_temperature",
@@ -401,29 +398,6 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
),
),
),
MieleSensorDefinition(
types=(
MieleAppliance.WASHING_MACHINE,
MieleAppliance.WASHER_DRYER,
MieleAppliance.OVEN,
MieleAppliance.OVEN_MICROWAVE,
MieleAppliance.STEAM_OVEN_MICRO,
MieleAppliance.STEAM_OVEN_COMBI,
MieleAppliance.STEAM_OVEN_MK2,
),
description=MieleSensorDescription(
key="state_target_temperature",
translation_key="target_temperature",
zone=1,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
value_fn=(
lambda value: cast(int, value.state_target_temperature[0].temperature)
/ 100.0
),
),
),
MieleSensorDefinition(
types=(
MieleAppliance.OVEN,

View File

@@ -876,9 +876,6 @@
"core_temperature": {
"name": "Core temperature"
},
"target_temperature": {
"name": "Target temperature"
},
"core_target_temperature": {
"name": "Core target temperature"
}

View File

@@ -28,8 +28,6 @@ from .const import (
from .coordinator import MieleConfigEntry
from .entity import MieleEntity
PARALLEL_UPDATES = 1
_LOGGER = logging.getLogger(__name__)

View File

@@ -24,8 +24,6 @@ from .const import DOMAIN, PROCESS_ACTION, PROGRAM_ID, MieleActions, MieleApplia
from .coordinator import MieleConfigEntry
from .entity import MieleEntity
PARALLEL_UPDATES = 1
_LOGGER = logging.getLogger(__name__)
# The following const classes define program speeds and programs for the vacuum cleaner.

View File

@@ -18,7 +18,7 @@
"sections": {
"auth": {
"name": "Authentication",
"description": "Depending on whether the server is configured to support access control, some topics may be read/write protected so that only users with the correct credentials can subscribe or publish to them. To publish/subscribe to protected topics, you can provide a username and password. Home Assistant will automatically generate an access token to authenticate with ntfy.",
"description": "Depending on whether the server is configured to support access control, some topics may be read/write protected so that only users with the correct credentials can subscribe or publish to them. To publish/subscribe to protected topics, you can provide a username and password.",
"data": {
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"

View File

@@ -32,8 +32,6 @@ from .const import (
PLACEHOLDER_WEBHOOK_URL,
)
AUTH_TOKEN_URL = "https://intercom.help/plaato/en/articles/5004720-auth_token"
class PlaatoConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handles a Plaato config flow."""
@@ -155,10 +153,7 @@ class PlaatoConfigFlow(ConfigFlow, domain=DOMAIN):
step_id="api_method",
data_schema=data_schema,
errors=errors,
description_placeholders={
PLACEHOLDER_DEVICE_TYPE: device_type.name,
"auth_token_url": AUTH_TOKEN_URL,
},
description_placeholders={PLACEHOLDER_DEVICE_TYPE: device_type.name},
)
async def _get_webhook_id(self):

View File

@@ -11,7 +11,7 @@
},
"api_method": {
"title": "Select API method",
"description": "To be able to query the API an 'auth token' is required which can be obtained by following [these instructions]({auth_token_url})\n\nSelected device: **{device_type}** \n\nIf you prefer to use the built-in webhook method (Airlock only) please check the box below and leave 'Auth token' blank",
"description": "To be able to query the API an 'auth token' is required which can be obtained by following [these instructions](https://plaato.zendesk.com/hc/en-us/articles/360003234717-Auth-token)\n\n Selected device: **{device_type}** \n\nIf you prefer to use the built-in webhook method (Airlock only) please check the box below and leave 'Auth token' blank",
"data": {
"use_webhook": "Use webhook",
"token": "Auth token"

View File

@@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["ical"],
"quality_scale": "silver",
"requirements": ["ical==9.2.2"]
"requirements": ["ical==9.2.1"]
}

View File

@@ -33,11 +33,7 @@ from homeassistant.const import (
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback
from homeassistant.helpers import device_registry as dr, issue_registry as ir
from homeassistant.helpers.debounce import Debouncer
from homeassistant.helpers.device_registry import (
CONNECTION_BLUETOOTH,
CONNECTION_NETWORK_MAC,
format_mac,
)
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .bluetooth import async_connect_scanner
@@ -164,11 +160,6 @@ class ShellyCoordinatorBase[_DeviceT: BlockDevice | RpcDevice](
"""Sleep period of the device."""
return self.config_entry.data.get(CONF_SLEEP_PERIOD, 0)
@property
def connections(self) -> set[tuple[str, str]]:
"""Connections of the device."""
return {(CONNECTION_NETWORK_MAC, self.mac)}
def async_setup(self, pending_platforms: list[Platform] | None = None) -> None:
"""Set up the coordinator."""
self._pending_platforms = pending_platforms
@@ -176,7 +167,7 @@ class ShellyCoordinatorBase[_DeviceT: BlockDevice | RpcDevice](
device_entry = dev_reg.async_get_or_create(
config_entry_id=self.config_entry.entry_id,
name=self.name,
connections=self.connections,
connections={(CONNECTION_NETWORK_MAC, self.mac)},
identifiers={(DOMAIN, self.mac)},
manufacturer="Shelly",
model=get_shelly_model_name(self.model, self.sleep_period, self.device),
@@ -532,14 +523,6 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
"""
return format_mac(bluetooth_mac_from_primary_mac(self.mac)).upper()
@property
def connections(self) -> set[tuple[str, str]]:
"""Connections of the device."""
connections = super().connections
if not self.sleep_period:
connections.add((CONNECTION_BLUETOOTH, self.bluetooth_source))
return connections
async def async_device_online(self, source: str) -> None:
"""Handle device going online."""
if not self.sleep_period:

View File

@@ -34,7 +34,7 @@
}
},
"confirm_discovery": {
"description": "Do you want to set up the {model} at {host}?\n\nBattery-powered devices that are password-protected must be woken up before continuing with setting up.\nBattery-powered devices that are not password-protected will be added when the device wakes up, you can now manually wake the device up using a button on it or wait for the next data update from the device."
"description": "Do you want to set up the {model} at {host}?\n\nBattery-powered devices that are password protected must be woken up before continuing with setting up.\nBattery-powered devices that are not password protected will be added when the device wakes up, you can now manually wake the device up using a button on it or wait for the next data update from the device."
},
"reconfigure": {
"description": "Update configuration for {device_name}.\n\nBefore setup, battery-powered devices must be woken up, you can now wake the device up using a button on it.",

View File

@@ -1,136 +0,0 @@
"""Offer sun based automation rules."""
from __future__ import annotations
from datetime import datetime, timedelta
from typing import cast
import voluptuous as vol
from homeassistant.const import CONF_CONDITION, SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.condition import (
ConditionCheckerType,
condition_trace_set_result,
condition_trace_update_result,
trace_condition_function,
)
from homeassistant.helpers.sun import get_astral_event_date
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
from homeassistant.util import dt as dt_util
CONDITION_SCHEMA = vol.All(
vol.Schema(
{
**cv.CONDITION_BASE_SCHEMA,
vol.Required(CONF_CONDITION): "sun",
vol.Optional("before"): cv.sun_event,
vol.Optional("before_offset"): cv.time_period,
vol.Optional("after"): vol.All(
vol.Lower, vol.Any(SUN_EVENT_SUNSET, SUN_EVENT_SUNRISE)
),
vol.Optional("after_offset"): cv.time_period,
}
),
cv.has_at_least_one_key("before", "after"),
)
def sun(
hass: HomeAssistant,
before: str | None = None,
after: str | None = None,
before_offset: timedelta | None = None,
after_offset: timedelta | None = None,
) -> bool:
"""Test if current time matches sun requirements."""
utcnow = dt_util.utcnow()
today = dt_util.as_local(utcnow).date()
before_offset = before_offset or timedelta(0)
after_offset = after_offset or timedelta(0)
sunrise = get_astral_event_date(hass, SUN_EVENT_SUNRISE, today)
sunset = get_astral_event_date(hass, SUN_EVENT_SUNSET, today)
has_sunrise_condition = SUN_EVENT_SUNRISE in (before, after)
has_sunset_condition = SUN_EVENT_SUNSET in (before, after)
after_sunrise = today > dt_util.as_local(cast(datetime, sunrise)).date()
if after_sunrise and has_sunrise_condition:
tomorrow = today + timedelta(days=1)
sunrise = get_astral_event_date(hass, SUN_EVENT_SUNRISE, tomorrow)
after_sunset = today > dt_util.as_local(cast(datetime, sunset)).date()
if after_sunset and has_sunset_condition:
tomorrow = today + timedelta(days=1)
sunset = get_astral_event_date(hass, SUN_EVENT_SUNSET, tomorrow)
# Special case: before sunrise OR after sunset
# This will handle the very rare case in the polar region when the sun rises/sets
# but does not set/rise.
# However this entire condition does not handle those full days of darkness
# or light, the following should be used instead:
#
# condition:
# condition: state
# entity_id: sun.sun
# state: 'above_horizon' (or 'below_horizon')
#
if before == SUN_EVENT_SUNRISE and after == SUN_EVENT_SUNSET:
wanted_time_before = cast(datetime, sunrise) + before_offset
condition_trace_update_result(wanted_time_before=wanted_time_before)
wanted_time_after = cast(datetime, sunset) + after_offset
condition_trace_update_result(wanted_time_after=wanted_time_after)
return utcnow < wanted_time_before or utcnow > wanted_time_after
if sunrise is None and has_sunrise_condition:
# There is no sunrise today
condition_trace_set_result(False, message="no sunrise today")
return False
if sunset is None and has_sunset_condition:
# There is no sunset today
condition_trace_set_result(False, message="no sunset today")
return False
if before == SUN_EVENT_SUNRISE:
wanted_time_before = cast(datetime, sunrise) + before_offset
condition_trace_update_result(wanted_time_before=wanted_time_before)
if utcnow > wanted_time_before:
return False
if before == SUN_EVENT_SUNSET:
wanted_time_before = cast(datetime, sunset) + before_offset
condition_trace_update_result(wanted_time_before=wanted_time_before)
if utcnow > wanted_time_before:
return False
if after == SUN_EVENT_SUNRISE:
wanted_time_after = cast(datetime, sunrise) + after_offset
condition_trace_update_result(wanted_time_after=wanted_time_after)
if utcnow < wanted_time_after:
return False
if after == SUN_EVENT_SUNSET:
wanted_time_after = cast(datetime, sunset) + after_offset
condition_trace_update_result(wanted_time_after=wanted_time_after)
if utcnow < wanted_time_after:
return False
return True
def async_condition_from_config(config: ConfigType) -> ConditionCheckerType:
"""Wrap action method with sun based condition."""
before = config.get("before")
after = config.get("after")
before_offset = config.get("before_offset")
after_offset = config.get("after_offset")
@trace_condition_function
def sun_if(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool:
"""Validate time based if-condition."""
return sun(hass, before, after, before_offset, after_offset)
return sun_if

View File

@@ -469,7 +469,6 @@ class ResultStream:
use_file_cache: bool
language: str
options: dict
supports_streaming_input: bool
_manager: SpeechManager
@@ -485,10 +484,7 @@ class ResultStream:
@callback
def async_set_message(self, message: str) -> None:
"""Set message to be generated.
This method will leverage a disk cache to speed up generation.
"""
"""Set message to be generated."""
self._result_cache.set_result(
self._manager.async_cache_message_in_memory(
engine=self.engine,
@@ -501,10 +497,7 @@ class ResultStream:
@callback
def async_set_message_stream(self, message_stream: AsyncGenerator[str]) -> None:
"""Set a stream that will generate the message.
This method can result in faster first byte when generating long responses.
"""
"""Set a stream that will generate the message."""
self._result_cache.set_result(
self._manager.async_cache_message_stream_in_memory(
engine=self.engine,
@@ -733,10 +726,6 @@ class SpeechManager:
if (engine_instance := get_engine_instance(self.hass, engine)) is None:
raise HomeAssistantError(f"Provider {engine} not found")
supports_streaming_input = (
isinstance(engine_instance, TextToSpeechEntity)
and engine_instance.async_supports_streaming_input()
)
language, options = self.process_options(engine_instance, language, options)
if use_file_cache is None:
use_file_cache = self.use_file_cache
@@ -752,7 +741,6 @@ class SpeechManager:
engine=engine,
language=language,
options=options,
supports_streaming_input=supports_streaming_input,
_manager=self,
)
self.token_to_stream[token] = result_stream

View File

@@ -89,13 +89,6 @@ class TextToSpeechEntity(RestoreEntity, cached_properties=CACHED_PROPERTIES_WITH
"""Return a mapping with the default options."""
return self._attr_default_options
@classmethod
def async_supports_streaming_input(cls) -> bool:
"""Return if the TTS engine supports streaming input."""
return (
cls.async_stream_tts_audio is not TextToSpeechEntity.async_stream_tts_audio
)
@callback
def async_get_supported_voices(self, language: str) -> list[Voice] | None:
"""Return a list of supported voices for a language."""

View File

@@ -21,7 +21,7 @@
"tls": "Enable this if you use a secure connection to your Velbus interface, like a Signum.",
"host": "The IP address or hostname of the Velbus interface.",
"port": "The port number of the Velbus interface.",
"password": "The password of the Velbus interface, this is only needed if the interface is password-protected."
"password": "The password of the Velbus interface, this is only needed if the interface is password protected."
},
"description": "TCP/IP configuration, in case you use a Signum, VelServ, velbus-tcp or any other Velbus to TCP/IP interface."
},
@@ -58,7 +58,7 @@
"services": {
"sync_clock": {
"name": "Sync clock",
"description": "Syncs the clock of the Velbus modules to the Home Assistant clock, this is the same as the 'sync clock' from VelbusLink.",
"description": "Syncs the Velbus modules clock to the Home Assistant clock, this is the same as the 'sync clock' from VelbusLink.",
"fields": {
"interface": {
"name": "Interface",
@@ -104,7 +104,7 @@
},
"set_memo_text": {
"name": "Set memo text",
"description": "Sets the memo text to the display of modules like VMBGPO, VMBGPOD. Be sure the pages of the modules are configured to display the memo text.",
"description": "Sets the memo text to the display of modules like VMBGPO, VMBGPOD Be sure the page(s) of the module is configured to display the memo text.",
"fields": {
"interface": {
"name": "[%key:component::velbus::services::sync_clock::fields::interface::name%]",

View File

@@ -278,39 +278,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# and we'll handle the clean up below.
await driver_events.setup(driver)
if (old_unique_id := entry.unique_id) is not None and old_unique_id != (
new_unique_id := str(driver.controller.home_id)
):
device_registry = dr.async_get(hass)
controller_model = "Unknown model"
if (
(own_node := driver.controller.own_node)
and (
controller_device_entry := device_registry.async_get_device(
identifiers={get_device_id(driver, own_node)}
)
)
and (model := controller_device_entry.model)
):
controller_model = model
async_create_issue(
hass,
DOMAIN,
f"migrate_unique_id.{entry.entry_id}",
data={
"config_entry_id": entry.entry_id,
"config_entry_title": entry.title,
"controller_model": controller_model,
"new_unique_id": new_unique_id,
"old_unique_id": old_unique_id,
},
is_fixable=True,
severity=IssueSeverity.ERROR,
translation_key="migrate_unique_id",
)
else:
async_delete_issue(hass, DOMAIN, f"migrate_unique_id.{entry.entry_id}")
# If the listen task is already failed, we need to raise ConfigEntryNotReady
if listen_task.done():
listen_error, error_message = _get_listen_task_error(listen_task)

View File

@@ -57,47 +57,6 @@ class DeviceConfigFileChangedFlow(RepairsFlow):
)
class MigrateUniqueIDFlow(RepairsFlow):
"""Handler for an issue fixing flow."""
def __init__(self, data: dict[str, str]) -> None:
"""Initialize."""
self.description_placeholders: dict[str, str] = {
"config_entry_title": data["config_entry_title"],
"controller_model": data["controller_model"],
"new_unique_id": data["new_unique_id"],
"old_unique_id": data["old_unique_id"],
}
self._config_entry_id: str = data["config_entry_id"]
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> data_entry_flow.FlowResult:
"""Handle the first step of a fix flow."""
return await self.async_step_confirm()
async def async_step_confirm(
self, user_input: dict[str, str] | None = None
) -> data_entry_flow.FlowResult:
"""Handle the confirm step of a fix flow."""
if user_input is not None:
config_entry = self.hass.config_entries.async_get_entry(
self._config_entry_id
)
# If config entry was removed, we can ignore the issue.
if config_entry is not None:
self.hass.config_entries.async_update_entry(
config_entry,
unique_id=self.description_placeholders["new_unique_id"],
)
return self.async_create_entry(data={})
return self.async_show_form(
step_id="confirm",
description_placeholders=self.description_placeholders,
)
async def async_create_fix_flow(
hass: HomeAssistant, issue_id: str, data: dict[str, str] | None
) -> RepairsFlow:
@@ -106,7 +65,4 @@ async def async_create_fix_flow(
if issue_id.split(".")[0] == "device_config_file_changed":
assert data
return DeviceConfigFileChangedFlow(data)
if issue_id.split(".")[0] == "migrate_unique_id":
assert data
return MigrateUniqueIDFlow(data)
return ConfirmRepairFlow()

View File

@@ -273,17 +273,6 @@
"invalid_server_version": {
"description": "The version of Z-Wave Server you are currently running is too old for this version of Home Assistant. Please update the Z-Wave Server to the latest version to fix this issue.",
"title": "Newer version of Z-Wave Server needed"
},
"migrate_unique_id": {
"fix_flow": {
"step": {
"confirm": {
"description": "A Z-Wave controller of model {controller_model} with a different ID ({new_unique_id}) than the previously connected controller ({old_unique_id}) was connected to the {config_entry_title} configuration entry.\n\nReasons for a different controller ID could be:\n\n1. The controller was factory reset, with a 3rd party application.\n2. A controller Non Volatile Memory (NVM) backup was restored to the controller, with a 3rd party application.\n3. A different controller was connected to this configuration entry.\n\nIf a different controller was connected, you should instead set up a new configuration entry for the new controller.\n\nIf you are sure that the current controller is the correct controller you can confirm this by pressing Submit, and the configuration entry will remember the new controller ID.",
"title": "An unknown controller was detected"
}
}
},
"title": "An unknown controller was detected"
}
},
"services": {

View File

@@ -866,17 +866,17 @@ class Config:
# pylint: disable-next=import-outside-toplevel
from .components.frontend import storage as frontend_store
owner_store = await frontend_store.async_user_store(
_, owner_data = await frontend_store.async_user_store(
self.hass, owner.id
)
if (
"language" in owner_store.data
and "language" in owner_store.data["language"]
"language" in owner_data
and "language" in owner_data["language"]
):
with suppress(vol.InInvalid):
data["language"] = cv.language(
owner_store.data["language"]["language"]
owner_data["language"]["language"]
)
# pylint: disable-next=broad-except
except Exception:

View File

@@ -42,6 +42,8 @@ from homeassistant.const import (
ENTITY_MATCH_ANY,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
SUN_EVENT_SUNRISE,
SUN_EVENT_SUNSET,
WEEKDAYS,
)
from homeassistant.core import HomeAssistant, State, callback
@@ -58,6 +60,7 @@ from homeassistant.util import dt as dt_util
from homeassistant.util.async_ import run_callback_threadsafe
from . import config_validation as cv, entity_registry as er
from .sun import get_astral_event_date
from .template import Template, render_complex
from .trace import (
TraceElement,
@@ -82,6 +85,7 @@ _PLATFORM_ALIASES = {
"numeric_state": None,
"or": None,
"state": None,
"sun": None,
"template": None,
"time": None,
"trigger": None,
@@ -651,6 +655,105 @@ def state_from_config(config: ConfigType) -> ConditionCheckerType:
return if_state
def sun(
hass: HomeAssistant,
before: str | None = None,
after: str | None = None,
before_offset: timedelta | None = None,
after_offset: timedelta | None = None,
) -> bool:
"""Test if current time matches sun requirements."""
utcnow = dt_util.utcnow()
today = dt_util.as_local(utcnow).date()
before_offset = before_offset or timedelta(0)
after_offset = after_offset or timedelta(0)
sunrise = get_astral_event_date(hass, SUN_EVENT_SUNRISE, today)
sunset = get_astral_event_date(hass, SUN_EVENT_SUNSET, today)
has_sunrise_condition = SUN_EVENT_SUNRISE in (before, after)
has_sunset_condition = SUN_EVENT_SUNSET in (before, after)
after_sunrise = today > dt_util.as_local(cast(datetime, sunrise)).date()
if after_sunrise and has_sunrise_condition:
tomorrow = today + timedelta(days=1)
sunrise = get_astral_event_date(hass, SUN_EVENT_SUNRISE, tomorrow)
after_sunset = today > dt_util.as_local(cast(datetime, sunset)).date()
if after_sunset and has_sunset_condition:
tomorrow = today + timedelta(days=1)
sunset = get_astral_event_date(hass, SUN_EVENT_SUNSET, tomorrow)
# Special case: before sunrise OR after sunset
# This will handle the very rare case in the polar region when the sun rises/sets
# but does not set/rise.
# However this entire condition does not handle those full days of darkness
# or light, the following should be used instead:
#
# condition:
# condition: state
# entity_id: sun.sun
# state: 'above_horizon' (or 'below_horizon')
#
if before == SUN_EVENT_SUNRISE and after == SUN_EVENT_SUNSET:
wanted_time_before = cast(datetime, sunrise) + before_offset
condition_trace_update_result(wanted_time_before=wanted_time_before)
wanted_time_after = cast(datetime, sunset) + after_offset
condition_trace_update_result(wanted_time_after=wanted_time_after)
return utcnow < wanted_time_before or utcnow > wanted_time_after
if sunrise is None and has_sunrise_condition:
# There is no sunrise today
condition_trace_set_result(False, message="no sunrise today")
return False
if sunset is None and has_sunset_condition:
# There is no sunset today
condition_trace_set_result(False, message="no sunset today")
return False
if before == SUN_EVENT_SUNRISE:
wanted_time_before = cast(datetime, sunrise) + before_offset
condition_trace_update_result(wanted_time_before=wanted_time_before)
if utcnow > wanted_time_before:
return False
if before == SUN_EVENT_SUNSET:
wanted_time_before = cast(datetime, sunset) + before_offset
condition_trace_update_result(wanted_time_before=wanted_time_before)
if utcnow > wanted_time_before:
return False
if after == SUN_EVENT_SUNRISE:
wanted_time_after = cast(datetime, sunrise) + after_offset
condition_trace_update_result(wanted_time_after=wanted_time_after)
if utcnow < wanted_time_after:
return False
if after == SUN_EVENT_SUNSET:
wanted_time_after = cast(datetime, sunset) + after_offset
condition_trace_update_result(wanted_time_after=wanted_time_after)
if utcnow < wanted_time_after:
return False
return True
def sun_from_config(config: ConfigType) -> ConditionCheckerType:
"""Wrap action method with sun based condition."""
before = config.get("before")
after = config.get("after")
before_offset = config.get("before_offset")
after_offset = config.get("after_offset")
@trace_condition_function
def sun_if(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool:
"""Validate time based if-condition."""
return sun(hass, before, after, before_offset, after_offset)
return sun_if
def template(
hass: HomeAssistant, value_template: Template, variables: TemplateVarsType = None
) -> bool:
@@ -951,10 +1054,8 @@ async def async_validate_condition_config(
return config
platform = await _async_get_condition_platform(hass, config)
if platform is not None:
if hasattr(platform, "async_validate_condition_config"):
return await platform.async_validate_condition_config(hass, config)
return cast(ConfigType, platform.CONDITION_SCHEMA(config))
if platform is not None and hasattr(platform, "async_validate_condition_config"):
return await platform.async_validate_condition_config(hass, config)
if platform is None and condition in ("numeric_state", "state"):
validator = cast(
Callable[[HomeAssistant, ConfigType], ConfigType],

View File

@@ -1084,13 +1084,10 @@ def renamed(
return validator
type ValueSchemas = dict[Hashable, VolSchemaType | Callable[[Any], dict[str, Any]]]
def key_value_schemas(
key: str,
value_schemas: ValueSchemas,
default_schema: VolSchemaType | Callable[[Any], dict[str, Any]] | None = None,
value_schemas: dict[Hashable, VolSchemaType | Callable[[Any], dict[str, Any]]],
default_schema: VolSchemaType | None = None,
default_description: str | None = None,
) -> Callable[[Any], dict[Hashable, Any]]:
"""Create a validator that validates based on a value for specific key.
@@ -1738,41 +1735,25 @@ CONDITION_SHORTHAND_SCHEMA = vol.Schema(
}
)
BUILT_IN_CONDITIONS: ValueSchemas = {
"and": AND_CONDITION_SCHEMA,
"device": DEVICE_CONDITION_SCHEMA,
"not": NOT_CONDITION_SCHEMA,
"numeric_state": NUMERIC_STATE_CONDITION_SCHEMA,
"or": OR_CONDITION_SCHEMA,
"state": STATE_CONDITION_SCHEMA,
"template": TEMPLATE_CONDITION_SCHEMA,
"time": TIME_CONDITION_SCHEMA,
"trigger": TRIGGER_CONDITION_SCHEMA,
"zone": ZONE_CONDITION_SCHEMA,
}
# This is first round of validation, we don't want to mutate the config here already,
# just ensure basics as condition type and alias are there.
def _base_condition_validator(value: Any) -> Any:
vol.Schema(
{
**CONDITION_BASE_SCHEMA,
CONF_CONDITION: vol.All(str, vol.NotIn(BUILT_IN_CONDITIONS)),
},
extra=vol.ALLOW_EXTRA,
)(value)
return value
CONDITION_SCHEMA: vol.Schema = vol.Schema(
vol.Any(
vol.All(
expand_condition_shorthand,
key_value_schemas(
CONF_CONDITION,
BUILT_IN_CONDITIONS,
_base_condition_validator,
{
"and": AND_CONDITION_SCHEMA,
"device": DEVICE_CONDITION_SCHEMA,
"not": NOT_CONDITION_SCHEMA,
"numeric_state": NUMERIC_STATE_CONDITION_SCHEMA,
"or": OR_CONDITION_SCHEMA,
"state": STATE_CONDITION_SCHEMA,
"sun": SUN_CONDITION_SCHEMA,
"template": TEMPLATE_CONDITION_SCHEMA,
"time": TIME_CONDITION_SCHEMA,
"trigger": TRIGGER_CONDITION_SCHEMA,
"zone": ZONE_CONDITION_SCHEMA,
},
),
),
dynamic_template_condition,
@@ -1799,11 +1780,20 @@ CONDITION_ACTION_SCHEMA: vol.Schema = vol.Schema(
expand_condition_shorthand,
key_value_schemas(
CONF_CONDITION,
BUILT_IN_CONDITIONS,
vol.Any(
dynamic_template_condition_action,
_base_condition_validator,
),
{
"and": AND_CONDITION_SCHEMA,
"device": DEVICE_CONDITION_SCHEMA,
"not": NOT_CONDITION_SCHEMA,
"numeric_state": NUMERIC_STATE_CONDITION_SCHEMA,
"or": OR_CONDITION_SCHEMA,
"state": STATE_CONDITION_SCHEMA,
"sun": SUN_CONDITION_SCHEMA,
"template": TEMPLATE_CONDITION_SCHEMA,
"time": TIME_CONDITION_SCHEMA,
"trigger": TRIGGER_CONDITION_SCHEMA,
"zone": ZONE_CONDITION_SCHEMA,
},
dynamic_template_condition_action,
"a list of conditions or a valid template",
),
)
@@ -1862,7 +1852,7 @@ def _base_trigger_list_flatten(triggers: list[Any]) -> list[Any]:
return flatlist
# This is first round of validation, we don't want to mutate the config here already,
# This is first round of validation, we don't want to process the config here already,
# just ensure basics as platform and ID are there.
def _base_trigger_validator(value: Any) -> Any:
_base_trigger_validator_schema(value)

View File

@@ -29,20 +29,27 @@ from homeassistant.core import (
from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import async_get_integration, bind_hass
from homeassistant.setup import async_prepare_setup_platform
from homeassistant.util.hass_dict import HassKey
from . import config_validation as cv, discovery, entity, service
from .entity_platform import EntityPlatform
from . import (
config_validation as cv,
device_registry as dr,
discovery,
entity,
entity_registry as er,
service,
)
from .entity_platform import EntityPlatform, async_calculate_suggested_object_id
from .typing import ConfigType, DiscoveryInfoType, VolDictType, VolSchemaType
DEFAULT_SCAN_INTERVAL = timedelta(seconds=15)
DATA_INSTANCES = "entity_components"
DATA_INSTANCES: HassKey[dict[str, EntityComponent]] = HassKey("entity_components")
@bind_hass
async def async_update_entity(hass: HomeAssistant, entity_id: str) -> None:
"""Trigger an update for an entity."""
domain = entity_id.partition(".")[0]
entity_comp: EntityComponent[entity.Entity] | None
entity_comp = hass.data.get(DATA_INSTANCES, {}).get(domain)
if entity_comp is None:
@@ -60,6 +67,37 @@ async def async_update_entity(hass: HomeAssistant, entity_id: str) -> None:
await entity_obj.async_update_ha_state(True)
@callback
def async_get_entity_suggested_object_id(
hass: HomeAssistant, entity_id: str
) -> str | None:
"""Get the suggested object id for an entity.
Raises HomeAssistantError if the entity is not in the registry.
"""
entity_registry = er.async_get(hass)
if not (entity_entry := entity_registry.async_get(entity_id)):
raise HomeAssistantError(f"Entity {entity_id} is not in the registry.")
domain = entity_id.partition(".")[0]
if entity_entry.suggested_object_id:
return entity_entry.suggested_object_id
if entity_entry.name:
return entity_entry.name
entity_comp = hass.data.get(DATA_INSTANCES, {}).get(domain)
entity_obj = entity_comp.get_entity(entity_id) if entity_comp else None
if entity_obj:
device: dr.DeviceEntry | None = None
if device_id := entity_entry.device_id:
device = dr.async_get(hass).async_get(device_id)
return async_calculate_suggested_object_id(entity_obj, device)
return entity_entry.calculated_object_id
class EntityComponent[_EntityT: entity.Entity = entity.Entity]:
"""The EntityComponent manages platforms that manage entities.
@@ -95,7 +133,7 @@ class EntityComponent[_EntityT: entity.Entity = entity.Entity]:
self.async_add_entities = domain_platform.async_add_entities
self.add_entities = domain_platform.add_entities
self._entities: dict[str, entity.Entity] = domain_platform.domain_entities
hass.data.setdefault(DATA_INSTANCES, {})[domain] = self
hass.data.setdefault(DATA_INSTANCES, {})[domain] = self # type: ignore[assignment]
@property
def entities(self) -> Iterable[_EntityT]:

View File

@@ -764,7 +764,7 @@ class EntityPlatform:
already_exists = True
return (already_exists, restored)
async def _async_add_entity( # noqa: C901
async def _async_add_entity(
self,
entity: Entity,
update_before_add: bool,
@@ -843,31 +843,18 @@ class EntityPlatform:
else:
device = None
if not registered_entity_id:
# Do not bother working out a suggested_object_id
# if the entity is already registered as it will
# be ignored.
#
# An entity may suggest the entity_id by setting entity_id itself
suggested_entity_id: str | None = entity.entity_id
if suggested_entity_id is not None:
suggested_object_id = split_entity_id(entity.entity_id)[1]
else:
if device and entity.has_entity_name:
device_name = device.name_by_user or device.name
if entity.use_device_name:
suggested_object_id = device_name
else:
suggested_object_id = (
f"{device_name} {entity.suggested_object_id}"
)
if not suggested_object_id:
suggested_object_id = entity.suggested_object_id
# An entity may suggest the entity_id by setting entity_id itself
calculated_object_id: str | None = None
suggested_entity_id: str | None = entity.entity_id
if suggested_entity_id is not None:
suggested_object_id = split_entity_id(entity.entity_id)[1]
else:
calculated_object_id = async_calculate_suggested_object_id(
entity, device
)
if self.entity_namespace is not None:
suggested_object_id = (
f"{self.entity_namespace} {suggested_object_id}"
)
if self.entity_namespace is not None and suggested_object_id is not None:
suggested_object_id = f"{self.entity_namespace} {suggested_object_id}"
disabled_by: RegistryEntryDisabler | None = None
if not entity.entity_registry_enabled_default:
@@ -881,6 +868,7 @@ class EntityPlatform:
self.domain,
self.platform_name,
entity.unique_id,
calculated_object_id=calculated_object_id,
capabilities=entity.capability_attributes,
config_entry=self.config_entry,
config_subentry_id=config_subentry_id,
@@ -1124,6 +1112,27 @@ class EntityPlatform:
await asyncio.gather(*tasks)
@callback
def async_calculate_suggested_object_id(
entity: Entity, device: dev_reg.DeviceEntry | None
) -> str | None:
"""Calculate the suggested object ID for an entity."""
calculated_object_id: str | None = None
if device and entity.has_entity_name:
device_name = device.name_by_user or device.name
if entity.use_device_name:
calculated_object_id = device_name
else:
calculated_object_id = f"{device_name} {entity.suggested_object_id}"
if not calculated_object_id:
calculated_object_id = entity.suggested_object_id
if (platform := entity.platform) and platform.entity_namespace is not None:
calculated_object_id = f"{platform.entity_namespace} {calculated_object_id}"
return calculated_object_id
current_platform: ContextVar[EntityPlatform | None] = ContextVar(
"current_platform", default=None
)

View File

@@ -79,7 +79,7 @@ EVENT_ENTITY_REGISTRY_UPDATED: EventType[EventEntityRegistryUpdatedData] = Event
_LOGGER = logging.getLogger(__name__)
STORAGE_VERSION_MAJOR = 1
STORAGE_VERSION_MINOR = 16
STORAGE_VERSION_MINOR = 17
STORAGE_KEY = "core.entity_registry"
CLEANUP_INTERVAL = 3600 * 24
@@ -195,9 +195,11 @@ class RegistryEntry:
name: str | None = attr.ib(default=None)
options: ReadOnlyEntityOptionsType = attr.ib(converter=_protect_entity_options)
# As set by integration
calculated_object_id: str | None = attr.ib()
original_device_class: str | None = attr.ib()
original_icon: str | None = attr.ib()
original_name: str | None = attr.ib()
suggested_object_id: str | None = attr.ib()
supported_features: int = attr.ib()
translation_key: str | None = attr.ib()
unit_of_measurement: str | None = attr.ib()
@@ -337,6 +339,7 @@ class RegistryEntry:
{
"aliases": list(self.aliases),
"area_id": self.area_id,
"calculated_object_id": self.calculated_object_id,
"categories": self.categories,
"capabilities": self.capabilities,
"config_entry_id": self.config_entry_id,
@@ -359,6 +362,7 @@ class RegistryEntry:
"original_icon": self.original_icon,
"original_name": self.original_name,
"platform": self.platform,
"suggested_object_id": self.suggested_object_id,
"supported_features": self.supported_features,
"translation_key": self.translation_key,
"unique_id": self.unique_id,
@@ -548,6 +552,12 @@ class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
for entity in data["deleted_entities"]:
entity["config_subentry_id"] = None
if old_minor_version < 17:
# Version 1.17 adds calculated_object_id and suggested_object_id
for entity in data["entities"]:
entity["calculated_object_id"] = None
entity["suggested_object_id"] = None
if old_major_version > 1:
raise NotImplementedError
return data
@@ -836,6 +846,7 @@ class EntityRegistry(BaseRegistry):
unique_id: str,
*,
# To influence entity ID generation
calculated_object_id: str | None = None,
suggested_object_id: str | None = None,
# To disable or hide an entity if it gets created
disabled_by: RegistryEntryDisabler | None = None,
@@ -908,7 +919,7 @@ class EntityRegistry(BaseRegistry):
entity_id = self.async_generate_entity_id(
domain,
suggested_object_id or f"{platform}_{unique_id}",
suggested_object_id or calculated_object_id or f"{platform}_{unique_id}",
)
if (
@@ -942,6 +953,8 @@ class EntityRegistry(BaseRegistry):
original_icon=none_if_undefined(original_icon),
original_name=none_if_undefined(original_name),
platform=platform,
calculated_object_id=calculated_object_id,
suggested_object_id=suggested_object_id,
supported_features=none_if_undefined(supported_features) or 0,
translation_key=none_if_undefined(translation_key),
unique_id=unique_id,
@@ -1350,6 +1363,7 @@ class EntityRegistry(BaseRegistry):
entities[entity["entity_id"]] = RegistryEntry(
aliases=set(entity["aliases"]),
area_id=entity["area_id"],
calculated_object_id=entity["calculated_object_id"],
categories=entity["categories"],
capabilities=entity["capabilities"],
config_entry_id=entity["config_entry_id"],
@@ -1378,6 +1392,7 @@ class EntityRegistry(BaseRegistry):
original_icon=entity["original_icon"],
original_name=entity["original_name"],
platform=entity["platform"],
suggested_object_id=entity["suggested_object_id"],
supported_features=entity["supported_features"],
translation_key=entity["translation_key"],
unique_id=entity["unique_id"],

View File

@@ -1,6 +1,6 @@
# Automatically generated by gen_requirements_all.py, do not edit
aiodhcpwatcher==1.2.0
aiodhcpwatcher==1.1.1
aiodiscover==2.7.0
aiodns==3.4.0
aiohasupervisor==0.3.1

10
requirements_all.txt generated
View File

@@ -211,10 +211,10 @@ aiobafi6==0.9.0
aiobotocore==2.21.1
# homeassistant.components.comelit
aiocomelit==0.12.1
aiocomelit==0.12.0
# homeassistant.components.dhcp
aiodhcpwatcher==1.2.0
aiodhcpwatcher==1.1.1
# homeassistant.components.dhcp
aiodiscover==2.7.0
@@ -983,7 +983,7 @@ gardena-bluetooth==1.6.0
gassist-text==0.0.12
# homeassistant.components.google
gcal-sync==7.0.1
gcal-sync==7.0.0
# homeassistant.components.geniushub
geniushub-client==0.7.1
@@ -1197,7 +1197,7 @@ ibmiotf==0.3.4
# homeassistant.components.local_calendar
# homeassistant.components.local_todo
# homeassistant.components.remote_calendar
ical==9.2.2
ical==9.2.1
# homeassistant.components.caldav
icalendar==6.1.0
@@ -3101,7 +3101,7 @@ xbox-webapi==2.1.0
xiaomi-ble==0.38.0
# homeassistant.components.knx
xknx==3.8.0
xknx==3.6.0
# homeassistant.components.knx
xknxproject==3.8.2

View File

@@ -18,7 +18,7 @@ pre-commit==4.0.0
pydantic==2.11.3
pylint==3.3.7
pylint-per-file-ignores==1.4.0
pipdeptree==2.26.1
pipdeptree==2.25.1
pytest-asyncio==0.26.0
pytest-aiohttp==1.1.0
pytest-cov==6.0.0

View File

@@ -199,10 +199,10 @@ aiobafi6==0.9.0
aiobotocore==2.21.1
# homeassistant.components.comelit
aiocomelit==0.12.1
aiocomelit==0.12.0
# homeassistant.components.dhcp
aiodhcpwatcher==1.2.0
aiodhcpwatcher==1.1.1
# homeassistant.components.dhcp
aiodiscover==2.7.0
@@ -837,7 +837,7 @@ gardena-bluetooth==1.6.0
gassist-text==0.0.12
# homeassistant.components.google
gcal-sync==7.0.1
gcal-sync==7.0.0
# homeassistant.components.geniushub
geniushub-client==0.7.1
@@ -1018,7 +1018,7 @@ ibeacon-ble==1.2.0
# homeassistant.components.local_calendar
# homeassistant.components.local_todo
# homeassistant.components.remote_calendar
ical==9.2.2
ical==9.2.1
# homeassistant.components.caldav
icalendar==6.1.0
@@ -2509,7 +2509,7 @@ xbox-webapi==2.1.0
xiaomi-ble==0.38.0
# homeassistant.components.knx
xknx==3.8.0
xknx==3.6.0
# homeassistant.components.knx
xknxproject==3.8.2

View File

@@ -24,7 +24,7 @@ RUN --mount=from=ghcr.io/astral-sh/uv:0.7.1,source=/uv,target=/bin/uv \
--no-cache \
-c /usr/src/homeassistant/homeassistant/package_constraints.txt \
-r /usr/src/homeassistant/requirements.txt \
stdlib-list==0.10.0 pipdeptree==2.26.1 tqdm==4.67.1 ruff==0.11.0 \
stdlib-list==0.10.0 pipdeptree==2.25.1 tqdm==4.67.1 ruff==0.11.0 \
PyTurboJPEG==1.7.5 go2rtc-client==0.1.2 ha-ffmpeg==3.2.2 hassil==2.2.3 home-assistant-intents==2025.5.7 mutagen==1.47.0 pymicro-vad==1.0.1 pyspeex-noise==1.0.2
LABEL "name"="hassfest"

View File

@@ -651,6 +651,7 @@ class RegistryEntryWithDefaults(er.RegistryEntry):
"""Helper to create a registry entry with defaults."""
capabilities: Mapping[str, Any] | None = attr.ib(default=None)
calculated_object_id: str | None = attr.ib(default=None)
config_entry_id: str | None = attr.ib(default=None)
config_subentry_id: str | None = attr.ib(default=None)
created_at: datetime = attr.ib(factory=dt_util.utcnow)
@@ -669,6 +670,7 @@ class RegistryEntryWithDefaults(er.RegistryEntry):
original_device_class: str | None = attr.ib(default=None)
original_icon: str | None = attr.ib(default=None)
original_name: str | None = attr.ib(default=None)
suggested_object_id: str | None = attr.ib(default=None)
supported_features: int = attr.ib(default=0)
translation_key: str | None = attr.ib(default=None)
unit_of_measurement: str | None = attr.ib(default=None)

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Timer running',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Timer running',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'timer_running',
'unique_id': 'aa:bb:cc:dd:ee:ff_timer_running',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Reset timer',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Reset timer',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'reset_timer',
'unique_id': 'aa:bb:cc:dd:ee:ff_reset_timer',
@@ -51,6 +53,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Start/stop timer',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -74,6 +77,7 @@
'original_name': 'Start/stop timer',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'start_stop',
'unique_id': 'aa:bb:cc:dd:ee:ff_start_stop',
@@ -98,6 +102,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Tare',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -121,6 +126,7 @@
'original_name': 'Tare',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'tare',
'unique_id': 'aa:bb:cc:dd:ee:ff_tare',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Battery',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Battery',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff_battery',
@@ -56,6 +58,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Volume flow rate',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -84,6 +87,7 @@
'original_name': 'Volume flow rate',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff_flow_rate',
@@ -111,6 +115,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'LUNAR-DDEEFF Weight',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -136,6 +141,7 @@
'original_name': 'Weight',
'platform': 'acaia',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff_weight',

File diff suppressed because it is too large Load Diff

View File

@@ -245,6 +245,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -268,6 +269,7 @@
'original_name': None,
'platform': 'accuweather',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <WeatherEntityFeature: 1>,
'translation_key': None,
'unique_id': '0123456',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Calibrate CO2 sensor',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Calibrate CO2 sensor',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co2_calibration',
'unique_id': '84fce612f5b8-co2_calibration',
@@ -51,6 +53,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Test LED bar',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -74,6 +77,7 @@
'original_name': 'Test LED bar',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'led_bar_test',
'unique_id': '84fce612f5b8-led_bar_test',
@@ -98,6 +102,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Calibrate CO2 sensor',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -121,6 +126,7 @@
'original_name': 'Calibrate CO2 sensor',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co2_calibration',
'unique_id': '84fce612f5b8-co2_calibration',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Display brightness',
'capabilities': dict({
'max': 100,
'min': 0,
@@ -32,6 +33,7 @@
'original_name': 'Display brightness',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'display_brightness',
'unique_id': '84fce612f5b8-display_brightness',
@@ -61,6 +63,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient LED bar brightness',
'capabilities': dict({
'max': 100,
'min': 0,
@@ -89,6 +92,7 @@
'original_name': 'LED bar brightness',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'led_bar_brightness',
'unique_id': '84fce612f5b8-led_bar_brightness',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient CO2 automatic baseline duration',
'capabilities': dict({
'options': list([
'1',
@@ -36,6 +37,7 @@
'original_name': 'CO2 automatic baseline duration',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co2_automatic_baseline_calibration',
'unique_id': '84fce612f5b8-co2_automatic_baseline_calibration',
@@ -68,6 +70,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Configuration source',
'capabilities': dict({
'options': list([
'cloud',
@@ -96,6 +99,7 @@
'original_name': 'Configuration source',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'configuration_control',
'unique_id': '84fce612f5b8-configuration_control',
@@ -124,6 +128,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Display PM standard',
'capabilities': dict({
'options': list([
'ugm3',
@@ -152,6 +157,7 @@
'original_name': 'Display PM standard',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'display_pm_standard',
'unique_id': '84fce612f5b8-display_pm_standard',
@@ -180,6 +186,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Display temperature unit',
'capabilities': dict({
'options': list([
'c',
@@ -208,6 +215,7 @@
'original_name': 'Display temperature unit',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'display_temperature_unit',
'unique_id': '84fce612f5b8-display_temperature_unit',
@@ -236,6 +244,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient LED bar mode',
'capabilities': dict({
'options': list([
'off',
@@ -265,6 +274,7 @@
'original_name': 'LED bar mode',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'led_bar_mode',
'unique_id': '84fce612f5b8-led_bar_mode',
@@ -294,6 +304,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient NOx index learning offset',
'capabilities': dict({
'options': list([
'12',
@@ -325,6 +336,7 @@
'original_name': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'nox_index_learning_time_offset',
'unique_id': '84fce612f5b8-nox_index_learning_time_offset',
@@ -356,6 +368,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient VOC index learning offset',
'capabilities': dict({
'options': list([
'12',
@@ -387,6 +400,7 @@
'original_name': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'voc_index_learning_time_offset',
'unique_id': '84fce612f5b8-voc_index_learning_time_offset',
@@ -418,6 +432,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient CO2 automatic baseline duration',
'capabilities': dict({
'options': list([
'1',
@@ -450,6 +465,7 @@
'original_name': 'CO2 automatic baseline duration',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co2_automatic_baseline_calibration',
'unique_id': '84fce612f5b8-co2_automatic_baseline_calibration',
@@ -482,6 +498,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Configuration source',
'capabilities': dict({
'options': list([
'cloud',
@@ -510,6 +527,7 @@
'original_name': 'Configuration source',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'configuration_control',
'unique_id': '84fce612f5b8-configuration_control',
@@ -538,6 +556,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient NOx index learning offset',
'capabilities': dict({
'options': list([
'12',
@@ -569,6 +588,7 @@
'original_name': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'nox_index_learning_time_offset',
'unique_id': '84fce612f5b8-nox_index_learning_time_offset',
@@ -600,6 +620,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient VOC index learning offset',
'capabilities': dict({
'options': list([
'12',
@@ -631,6 +652,7 @@
'original_name': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'voc_index_learning_time_offset',
'unique_id': '84fce612f5b8-voc_index_learning_time_offset',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Carbon dioxide',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Carbon dioxide',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-co2',
@@ -56,6 +58,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Carbon dioxide automatic baseline calibration',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -79,6 +82,7 @@
'original_name': 'Carbon dioxide automatic baseline calibration',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co2_automatic_baseline_calibration_days',
'unique_id': '84fce612f5b8-co2_automatic_baseline_calibration_days',
@@ -105,6 +109,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Display brightness',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -128,6 +133,7 @@
'original_name': 'Display brightness',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'display_brightness',
'unique_id': '84fce612f5b8-display_brightness',
@@ -153,6 +159,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Display PM standard',
'capabilities': dict({
'options': list([
'ugm3',
@@ -181,6 +188,7 @@
'original_name': 'Display PM standard',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'display_pm_standard',
'unique_id': '84fce612f5b8-display_pm_standard',
@@ -210,6 +218,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Display temperature unit',
'capabilities': dict({
'options': list([
'c',
@@ -238,6 +247,7 @@
'original_name': 'Display temperature unit',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'display_temperature_unit',
'unique_id': '84fce612f5b8-display_temperature_unit',
@@ -267,6 +277,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -292,6 +303,7 @@
'original_name': 'Humidity',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-humidity',
@@ -319,6 +331,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient LED bar brightness',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -342,6 +355,7 @@
'original_name': 'LED bar brightness',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'led_bar_brightness',
'unique_id': '84fce612f5b8-led_bar_brightness',
@@ -367,6 +381,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient LED bar mode',
'capabilities': dict({
'options': list([
'off',
@@ -396,6 +411,7 @@
'original_name': 'LED bar mode',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'led_bar_mode',
'unique_id': '84fce612f5b8-led_bar_mode',
@@ -426,6 +442,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient NOx index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -451,6 +468,7 @@
'original_name': 'NOx index',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'nitrogen_index',
'unique_id': '84fce612f5b8-nitrogen_index',
@@ -476,6 +494,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient NOx index learning offset',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -499,6 +518,7 @@
'original_name': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'nox_learning_offset',
'unique_id': '84fce612f5b8-nox_learning_offset',
@@ -525,6 +545,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient PM0.3',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -550,6 +571,7 @@
'original_name': 'PM0.3',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'pm003_count',
'unique_id': '84fce612f5b8-pm003',
@@ -576,6 +598,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient PM1',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -601,6 +624,7 @@
'original_name': 'PM1',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-pm01',
@@ -628,6 +652,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient PM10',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -653,6 +678,7 @@
'original_name': 'PM10',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-pm10',
@@ -680,6 +706,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient PM2.5',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -705,6 +732,7 @@
'original_name': 'PM2.5',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-pm02',
@@ -732,6 +760,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Raw NOx',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -757,6 +786,7 @@
'original_name': 'Raw NOx',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'raw_nitrogen',
'unique_id': '84fce612f5b8-nox_raw',
@@ -783,6 +813,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Raw PM2.5',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -808,6 +839,7 @@
'original_name': 'Raw PM2.5',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'raw_pm02',
'unique_id': '84fce612f5b8-pm02_raw',
@@ -835,6 +867,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Raw VOC',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -860,6 +893,7 @@
'original_name': 'Raw VOC',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'raw_total_volatile_organic_component',
'unique_id': '84fce612f5b8-tvoc_raw',
@@ -886,6 +920,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -911,6 +946,7 @@
'original_name': 'Signal strength',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-signal_strength',
@@ -938,6 +974,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -963,6 +1000,7 @@
'original_name': 'Temperature',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-temperature',
@@ -990,6 +1028,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient VOC index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1015,6 +1054,7 @@
'original_name': 'VOC index',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_volatile_organic_component_index',
'unique_id': '84fce612f5b8-tvoc',
@@ -1040,6 +1080,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient VOC index learning offset',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1063,6 +1104,7 @@
'original_name': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'tvoc_learning_offset',
'unique_id': '84fce612f5b8-tvoc_learning_offset',
@@ -1089,6 +1131,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Carbon dioxide automatic baseline calibration',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1112,6 +1155,7 @@
'original_name': 'Carbon dioxide automatic baseline calibration',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co2_automatic_baseline_calibration_days',
'unique_id': '84fce612f5b8-co2_automatic_baseline_calibration_days',
@@ -1138,6 +1182,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient NOx index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1163,6 +1208,7 @@
'original_name': 'NOx index',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'nitrogen_index',
'unique_id': '84fce612f5b8-nitrogen_index',
@@ -1188,6 +1234,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient NOx index learning offset',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1211,6 +1258,7 @@
'original_name': 'NOx index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'nox_learning_offset',
'unique_id': '84fce612f5b8-nox_learning_offset',
@@ -1237,6 +1285,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Raw NOx',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1262,6 +1311,7 @@
'original_name': 'Raw NOx',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'raw_nitrogen',
'unique_id': '84fce612f5b8-nox_raw',
@@ -1288,6 +1338,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Raw VOC',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1313,6 +1364,7 @@
'original_name': 'Raw VOC',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'raw_total_volatile_organic_component',
'unique_id': '84fce612f5b8-tvoc_raw',
@@ -1339,6 +1391,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1364,6 +1417,7 @@
'original_name': 'Signal strength',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-signal_strength',
@@ -1391,6 +1445,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient VOC index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1416,6 +1471,7 @@
'original_name': 'VOC index',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_volatile_organic_component_index',
'unique_id': '84fce612f5b8-tvoc',
@@ -1441,6 +1497,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient VOC index learning offset',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1464,6 +1521,7 @@
'original_name': 'VOC index learning offset',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'tvoc_learning_offset',
'unique_id': '84fce612f5b8-tvoc_learning_offset',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Post data to Airgradient',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Post data to Airgradient',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'post_data_to_airgradient',
'unique_id': '84fce612f5b8-post_data_to_airgradient',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airgradient Firmware',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Firmware',
'platform': 'airgradient',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '84fce612f5b8-update',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Carbon monoxide',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -32,6 +33,7 @@
'original_name': 'Carbon monoxide',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'co',
'unique_id': '123-456-co',
@@ -61,6 +63,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Common air quality index',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -87,6 +90,7 @@
'original_name': 'Common air quality index',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'caqi',
'unique_id': '123-456-caqi',
@@ -116,6 +120,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -144,6 +149,7 @@
'original_name': 'Humidity',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-humidity',
@@ -172,6 +178,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Nitrogen dioxide',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -200,6 +207,7 @@
'original_name': 'Nitrogen dioxide',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-no2',
@@ -230,6 +238,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Ozone',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -258,6 +267,7 @@
'original_name': 'Ozone',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-o3',
@@ -288,6 +298,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home PM1',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -316,6 +327,7 @@
'original_name': 'PM1',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-pm1',
@@ -344,6 +356,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home PM10',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -372,6 +385,7 @@
'original_name': 'PM10',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-pm10',
@@ -402,6 +416,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home PM2.5',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -430,6 +445,7 @@
'original_name': 'PM2.5',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-pm25',
@@ -460,6 +476,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -488,6 +505,7 @@
'original_name': 'Pressure',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-pressure',
@@ -516,6 +534,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Sulphur dioxide',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -544,6 +563,7 @@
'original_name': 'Sulphur dioxide',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-so2',
@@ -574,6 +594,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Home Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -602,6 +623,7 @@
'original_name': 'Temperature',
'platform': 'airly',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '123-456-temperature',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Zone 1 Damper',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Damper',
'platform': 'airtouch5',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 7>,
'translation_key': 'damper',
'unique_id': 'zone_1_open_percentage',
@@ -54,6 +56,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Zone 2 Damper',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -77,6 +80,7 @@
'original_name': 'Damper',
'platform': 'airtouch5',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CoverEntityFeature: 7>,
'translation_key': 'damper',
'unique_id': 'zone_2_open_percentage',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airzone 2:1 Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Humidity',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_2:1_humidity',
@@ -56,6 +58,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airzone 2:1 Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -81,6 +84,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_2:1_temp',
@@ -108,6 +112,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airzone DHW Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -133,6 +138,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_dhw_temp',
@@ -160,6 +166,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Airzone WebServer RSSI',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -185,6 +192,7 @@
'original_name': 'RSSI',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'rssi',
'unique_id': 'airzone_unique_id_ws_wifi-rssi',
@@ -212,6 +220,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Aux Heat Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -237,6 +246,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_4:1_temp',
@@ -264,6 +274,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Despacho Battery',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -289,6 +300,7 @@
'original_name': 'Battery',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:4_thermostat-battery',
@@ -316,6 +328,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Despacho Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -341,6 +354,7 @@
'original_name': 'Humidity',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:4_humidity',
@@ -368,6 +382,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Despacho Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -393,6 +408,7 @@
'original_name': 'Signal strength',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'thermostat_signal',
'unique_id': 'airzone_unique_id_1:4_thermostat-signal',
@@ -419,6 +435,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Despacho Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -444,6 +461,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:4_temp',
@@ -471,6 +489,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'DKN Plus Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -496,6 +515,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_3:1_temp',
@@ -523,6 +543,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #1 Battery',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -548,6 +569,7 @@
'original_name': 'Battery',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:3_thermostat-battery',
@@ -575,6 +597,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #1 Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -600,6 +623,7 @@
'original_name': 'Humidity',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:3_humidity',
@@ -627,6 +651,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #1 Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -652,6 +677,7 @@
'original_name': 'Signal strength',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'thermostat_signal',
'unique_id': 'airzone_unique_id_1:3_thermostat-signal',
@@ -678,6 +704,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #1 Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -703,6 +730,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:3_temp',
@@ -730,6 +758,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #2 Battery',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -755,6 +784,7 @@
'original_name': 'Battery',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:5_thermostat-battery',
@@ -782,6 +812,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #2 Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -807,6 +838,7 @@
'original_name': 'Humidity',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:5_humidity',
@@ -834,6 +866,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #2 Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -859,6 +892,7 @@
'original_name': 'Signal strength',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'thermostat_signal',
'unique_id': 'airzone_unique_id_1:5_thermostat-signal',
@@ -885,6 +919,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm #2 Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -910,6 +945,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:5_temp',
@@ -937,6 +973,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm Ppal Battery',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -962,6 +999,7 @@
'original_name': 'Battery',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:2_thermostat-battery',
@@ -989,6 +1027,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm Ppal Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1014,6 +1053,7 @@
'original_name': 'Humidity',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:2_humidity',
@@ -1041,6 +1081,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm Ppal Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1066,6 +1107,7 @@
'original_name': 'Signal strength',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'thermostat_signal',
'unique_id': 'airzone_unique_id_1:2_thermostat-signal',
@@ -1092,6 +1134,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Dorm Ppal Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1117,6 +1160,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:2_temp',
@@ -1144,6 +1188,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Salon Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1169,6 +1214,7 @@
'original_name': 'Humidity',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:1_humidity',
@@ -1196,6 +1242,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Salon Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1221,6 +1268,7 @@
'original_name': 'Temperature',
'platform': 'airzone',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'airzone_unique_id_1:1_temp',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Absolute pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -35,6 +36,7 @@
'original_name': 'Absolute pressure',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'absolute_pressure',
'unique_id': 'AA:AA:AA:AA:AA:AA_baromabsin',
@@ -64,6 +66,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Daily rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -95,6 +98,7 @@
'original_name': 'Daily rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'daily_rain',
'unique_id': 'AA:AA:AA:AA:AA:AA_dailyrainin',
@@ -124,6 +128,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Dew point',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -152,6 +157,7 @@
'original_name': 'Dew point',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'dew_point',
'unique_id': 'AA:AA:AA:AA:AA:AA_dewPoint',
@@ -181,6 +187,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Feels like',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -209,6 +216,7 @@
'original_name': 'Feels like',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'feels_like',
'unique_id': 'AA:AA:AA:AA:AA:AA_feelsLike',
@@ -238,6 +246,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Hourly rain',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -269,6 +278,7 @@
'original_name': 'Hourly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hourly_rain',
'unique_id': 'AA:AA:AA:AA:AA:AA_hourlyrainin',
@@ -298,6 +308,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -326,6 +337,7 @@
'original_name': 'Humidity',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'AA:AA:AA:AA:AA:AA_humidity',
@@ -355,6 +367,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Irradiance',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -383,6 +396,7 @@
'original_name': 'Irradiance',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'AA:AA:AA:AA:AA:AA_solarradiation',
@@ -412,6 +426,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Last rain',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -435,6 +450,7 @@
'original_name': 'Last rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_rain',
'unique_id': 'AA:AA:AA:AA:AA:AA_lastRain',
@@ -462,6 +478,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Max daily gust',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -493,6 +510,7 @@
'original_name': 'Max daily gust',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'max_daily_gust',
'unique_id': 'AA:AA:AA:AA:AA:AA_maxdailygust',
@@ -522,6 +540,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Monthly rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -553,6 +572,7 @@
'original_name': 'Monthly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'monthly_rain',
'unique_id': 'AA:AA:AA:AA:AA:AA_monthlyrainin',
@@ -582,6 +602,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Relative pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -613,6 +634,7 @@
'original_name': 'Relative pressure',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'relative_pressure',
'unique_id': 'AA:AA:AA:AA:AA:AA_baromrelin',
@@ -642,6 +664,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -670,6 +693,7 @@
'original_name': 'Temperature',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'AA:AA:AA:AA:AA:AA_tempf',
@@ -699,6 +723,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A UV index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -727,6 +752,7 @@
'original_name': 'UV index',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'uv_index',
'unique_id': 'AA:AA:AA:AA:AA:AA_uv',
@@ -755,6 +781,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Weekly rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -786,6 +813,7 @@
'original_name': 'Weekly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'weekly_rain',
'unique_id': 'AA:AA:AA:AA:AA:AA_weeklyrainin',
@@ -815,6 +843,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Wind direction',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT_ANGLE: 'measurement_angle'>,
}),
@@ -843,6 +872,7 @@
'original_name': 'Wind direction',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wind_direction',
'unique_id': 'AA:AA:AA:AA:AA:AA_winddir',
@@ -872,6 +902,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Wind gust',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -903,6 +934,7 @@
'original_name': 'Wind gust',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wind_gust',
'unique_id': 'AA:AA:AA:AA:AA:AA_windgustmph',
@@ -932,6 +964,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station A Wind speed',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -963,6 +996,7 @@
'original_name': 'Wind speed',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'AA:AA:AA:AA:AA:AA_windspeedmph',
@@ -992,6 +1026,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Absolute pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1023,6 +1058,7 @@
'original_name': 'Absolute pressure',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'absolute_pressure',
'unique_id': 'CC:CC:CC:CC:CC:CC_baromabsin',
@@ -1052,6 +1088,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Daily rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -1083,6 +1120,7 @@
'original_name': 'Daily rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'daily_rain',
'unique_id': 'CC:CC:CC:CC:CC:CC_dailyrainin',
@@ -1112,6 +1150,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Dew point',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1140,6 +1179,7 @@
'original_name': 'Dew point',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'dew_point',
'unique_id': 'CC:CC:CC:CC:CC:CC_dewPoint',
@@ -1169,6 +1209,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Feels like',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1197,6 +1238,7 @@
'original_name': 'Feels like',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'feels_like',
'unique_id': 'CC:CC:CC:CC:CC:CC_feelsLike',
@@ -1226,6 +1268,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Hourly rain',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1257,6 +1300,7 @@
'original_name': 'Hourly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hourly_rain',
'unique_id': 'CC:CC:CC:CC:CC:CC_hourlyrainin',
@@ -1286,6 +1330,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1314,6 +1359,7 @@
'original_name': 'Humidity',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'CC:CC:CC:CC:CC:CC_humidity',
@@ -1343,6 +1389,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Irradiance',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1371,6 +1418,7 @@
'original_name': 'Irradiance',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'CC:CC:CC:CC:CC:CC_solarradiation',
@@ -1400,6 +1448,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Last rain',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1423,6 +1472,7 @@
'original_name': 'Last rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_rain',
'unique_id': 'CC:CC:CC:CC:CC:CC_lastRain',
@@ -1450,6 +1500,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Max daily gust',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1481,6 +1532,7 @@
'original_name': 'Max daily gust',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'max_daily_gust',
'unique_id': 'CC:CC:CC:CC:CC:CC_maxdailygust',
@@ -1510,6 +1562,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Monthly rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -1541,6 +1594,7 @@
'original_name': 'Monthly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'monthly_rain',
'unique_id': 'CC:CC:CC:CC:CC:CC_monthlyrainin',
@@ -1570,6 +1624,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Relative pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1601,6 +1656,7 @@
'original_name': 'Relative pressure',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'relative_pressure',
'unique_id': 'CC:CC:CC:CC:CC:CC_baromrelin',
@@ -1630,6 +1686,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1658,6 +1715,7 @@
'original_name': 'Temperature',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'CC:CC:CC:CC:CC:CC_tempf',
@@ -1687,6 +1745,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C UV index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1715,6 +1774,7 @@
'original_name': 'UV index',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'uv_index',
'unique_id': 'CC:CC:CC:CC:CC:CC_uv',
@@ -1743,6 +1803,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Weekly rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -1774,6 +1835,7 @@
'original_name': 'Weekly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'weekly_rain',
'unique_id': 'CC:CC:CC:CC:CC:CC_weeklyrainin',
@@ -1803,6 +1865,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Wind direction',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT_ANGLE: 'measurement_angle'>,
}),
@@ -1831,6 +1894,7 @@
'original_name': 'Wind direction',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wind_direction',
'unique_id': 'CC:CC:CC:CC:CC:CC_winddir',
@@ -1860,6 +1924,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Wind gust',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1891,6 +1956,7 @@
'original_name': 'Wind gust',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wind_gust',
'unique_id': 'CC:CC:CC:CC:CC:CC_windgustmph',
@@ -1920,6 +1986,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station C Wind speed',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -1951,6 +2018,7 @@
'original_name': 'Wind speed',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'CC:CC:CC:CC:CC:CC_windspeedmph',
@@ -1980,6 +2048,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Absolute pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2011,6 +2080,7 @@
'original_name': 'Absolute pressure',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'absolute_pressure',
'unique_id': 'DD:DD:DD:DD:DD:DD_baromabsin',
@@ -2039,6 +2109,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Daily rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -2070,6 +2141,7 @@
'original_name': 'Daily rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'daily_rain',
'unique_id': 'DD:DD:DD:DD:DD:DD_dailyrainin',
@@ -2098,6 +2170,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Dew point',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2126,6 +2199,7 @@
'original_name': 'Dew point',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'dew_point',
'unique_id': 'DD:DD:DD:DD:DD:DD_dewPoint',
@@ -2154,6 +2228,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Feels like',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2182,6 +2257,7 @@
'original_name': 'Feels like',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'feels_like',
'unique_id': 'DD:DD:DD:DD:DD:DD_feelsLike',
@@ -2210,6 +2286,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Hourly rain',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2241,6 +2318,7 @@
'original_name': 'Hourly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hourly_rain',
'unique_id': 'DD:DD:DD:DD:DD:DD_hourlyrainin',
@@ -2269,6 +2347,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2297,6 +2376,7 @@
'original_name': 'Humidity',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DD:DD:DD:DD:DD:DD_humidity',
@@ -2325,6 +2405,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Irradiance',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2353,6 +2434,7 @@
'original_name': 'Irradiance',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DD:DD:DD:DD:DD:DD_solarradiation',
@@ -2381,6 +2463,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Max daily gust',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2412,6 +2495,7 @@
'original_name': 'Max daily gust',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'max_daily_gust',
'unique_id': 'DD:DD:DD:DD:DD:DD_maxdailygust',
@@ -2440,6 +2524,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Monthly rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -2471,6 +2556,7 @@
'original_name': 'Monthly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'monthly_rain',
'unique_id': 'DD:DD:DD:DD:DD:DD_monthlyrainin',
@@ -2499,6 +2585,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Relative pressure',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2530,6 +2617,7 @@
'original_name': 'Relative pressure',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'relative_pressure',
'unique_id': 'DD:DD:DD:DD:DD:DD_baromrelin',
@@ -2558,6 +2646,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2586,6 +2675,7 @@
'original_name': 'Temperature',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DD:DD:DD:DD:DD:DD_tempf',
@@ -2614,6 +2704,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D UV index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2642,6 +2733,7 @@
'original_name': 'UV index',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'uv_index',
'unique_id': 'DD:DD:DD:DD:DD:DD_uv',
@@ -2669,6 +2761,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Weekly rain',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -2700,6 +2793,7 @@
'original_name': 'Weekly rain',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'weekly_rain',
'unique_id': 'DD:DD:DD:DD:DD:DD_weeklyrainin',
@@ -2728,6 +2822,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Wind direction',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT_ANGLE: 'measurement_angle'>,
}),
@@ -2756,6 +2851,7 @@
'original_name': 'Wind direction',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wind_direction',
'unique_id': 'DD:DD:DD:DD:DD:DD_winddir',
@@ -2784,6 +2880,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Wind gust',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2815,6 +2912,7 @@
'original_name': 'Wind gust',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wind_gust',
'unique_id': 'DD:DD:DD:DD:DD:DD_windgustmph',
@@ -2843,6 +2941,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Station D Wind speed',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -2874,6 +2973,7 @@
'original_name': 'Wind speed',
'platform': 'ambient_network',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DD:DD:DD:DD:DD:DD_windspeedmph',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics core_samba',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'core_samba',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'addons',
'unique_id': 'addon_core_samba_active_installations',
@@ -55,6 +57,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics hacs (custom)',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -80,6 +83,7 @@
'original_name': 'hacs (custom)',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'custom_integrations',
'unique_id': 'custom_hacs_active_installations',
@@ -106,6 +110,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics myq',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -131,6 +136,7 @@
'original_name': 'myq',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'core_integrations',
'unique_id': 'core_myq_active_installations',
@@ -157,6 +163,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics spotify',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -182,6 +189,7 @@
'original_name': 'spotify',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'core_integrations',
'unique_id': 'core_spotify_active_installations',
@@ -208,6 +216,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics Total active installations',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -233,6 +242,7 @@
'original_name': 'Total active installations',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_active_installations',
'unique_id': 'total_active_installations',
@@ -259,6 +269,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics Total reported integrations',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -284,6 +295,7 @@
'original_name': 'Total reported integrations',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_reports_integrations',
'unique_id': 'total_reports_integrations',
@@ -310,6 +322,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Homeassistant Analytics YouTube',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -335,6 +348,7 @@
'original_name': 'YouTube',
'platform': 'analytics_insights',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'core_integrations',
'unique_id': 'core_youtube_active_installations',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'My water heater Energy usage',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -32,6 +33,7 @@
'original_name': 'Energy usage',
'platform': 'aosmith',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_usage',
'unique_id': 'energy_usage_junctionId',
@@ -59,6 +61,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'My water heater Hot water availability',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -82,6 +85,7 @@
'original_name': 'Hot water availability',
'platform': 'aosmith',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hot_water_availability',
'unique_id': 'hot_water_availability_junctionId',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'My water heater',
'capabilities': dict({
'max_temp': 130,
'min_temp': 95,
@@ -30,6 +31,7 @@
'original_name': None,
'platform': 'aosmith',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <WaterHeaterEntityFeature: 5>,
'translation_key': None,
'unique_id': 'junctionId',
@@ -62,6 +64,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'My water heater',
'capabilities': dict({
'max_temp': 130,
'min_temp': 95,
@@ -93,6 +96,7 @@
'original_name': None,
'platform': 'aosmith',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <WaterHeaterEntityFeature: 7>,
'translation_key': None,
'unique_id': 'junctionId',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title DC 1 short circuit error status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'DC 1 short circuit error status',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'dc_1_short_circuit_error_status',
'unique_id': 'MY_SERIAL_NUMBER_dc_1_short_circuit_error_status',
@@ -52,6 +54,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title DC 2 short circuit error status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -75,6 +78,7 @@
'original_name': 'DC 2 short circuit error status',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'dc_2_short_circuit_error_status',
'unique_id': 'MY_SERIAL_NUMBER_dc_2_short_circuit_error_status',
@@ -100,6 +104,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Off-grid status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -123,6 +128,7 @@
'original_name': 'Off-grid status',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'off_grid_status',
'unique_id': 'MY_SERIAL_NUMBER_off_grid_status',
@@ -148,6 +154,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Output fault status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -171,6 +178,7 @@
'original_name': 'Output fault status',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'output_fault_status',
'unique_id': 'MY_SERIAL_NUMBER_output_fault_status',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Max output',
'capabilities': dict({
'max': 1000,
'min': 0,
@@ -32,6 +33,7 @@
'original_name': 'Max output',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'max_output',
'unique_id': 'MY_SERIAL_NUMBER_output_limit',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Lifetime production of P1',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Lifetime production of P1',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lifetime_production_p1',
'unique_id': 'MY_SERIAL_NUMBER_lifetime_production_p1',
@@ -56,6 +58,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Lifetime production of P2',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -81,6 +84,7 @@
'original_name': 'Lifetime production of P2',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lifetime_production_p2',
'unique_id': 'MY_SERIAL_NUMBER_lifetime_production_p2',
@@ -108,6 +112,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Power of P1',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -133,6 +138,7 @@
'original_name': 'Power of P1',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_power_p1',
'unique_id': 'MY_SERIAL_NUMBER_total_power_p1',
@@ -160,6 +166,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Power of P2',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -185,6 +192,7 @@
'original_name': 'Power of P2',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_power_p2',
'unique_id': 'MY_SERIAL_NUMBER_total_power_p2',
@@ -212,6 +220,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Production of today',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -237,6 +246,7 @@
'original_name': 'Production of today',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'today_production',
'unique_id': 'MY_SERIAL_NUMBER_today_production',
@@ -264,6 +274,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Production of today from P1',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -289,6 +300,7 @@
'original_name': 'Production of today from P1',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'today_production_p1',
'unique_id': 'MY_SERIAL_NUMBER_today_production_p1',
@@ -316,6 +328,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Production of today from P2',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -341,6 +354,7 @@
'original_name': 'Production of today from P2',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'today_production_p2',
'unique_id': 'MY_SERIAL_NUMBER_today_production_p2',
@@ -368,6 +382,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Total lifetime production',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -393,6 +408,7 @@
'original_name': 'Total lifetime production',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lifetime_production',
'unique_id': 'MY_SERIAL_NUMBER_lifetime_production',
@@ -420,6 +436,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Total power',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -445,6 +462,7 @@
'original_name': 'Total power',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'total_power',
'unique_id': 'MY_SERIAL_NUMBER_total_power',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Mock Title Inverter status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Inverter status',
'platform': 'apsystems',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'inverter_status',
'unique_id': 'MY_SERIAL_NUMBER_inverter_status',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'AquaCell name Battery',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Battery',
'platform': 'aquacell',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DSN-battery',
@@ -53,6 +55,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'AquaCell name Salt left side percentage',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -78,6 +81,7 @@
'original_name': 'Salt left side percentage',
'platform': 'aquacell',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'salt_left_side_percentage',
'unique_id': 'DSN-salt_left_side_percentage',
@@ -104,6 +108,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'AquaCell name Salt left side time remaining',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -127,6 +132,7 @@
'original_name': 'Salt left side time remaining',
'platform': 'aquacell',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'salt_left_side_time_remaining',
'unique_id': 'DSN-salt_left_side_time_remaining',
@@ -153,6 +159,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'AquaCell name Salt right side percentage',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -178,6 +185,7 @@
'original_name': 'Salt right side percentage',
'platform': 'aquacell',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'salt_right_side_percentage',
'unique_id': 'DSN-salt_right_side_percentage',
@@ -204,6 +212,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'AquaCell name Salt right side time remaining',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -227,6 +236,7 @@
'original_name': 'Salt right side time remaining',
'platform': 'aquacell',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'salt_right_side_time_remaining',
'unique_id': 'DSN-salt_right_side_time_remaining',
@@ -253,6 +263,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'AquaCell name Wi-Fi strength',
'capabilities': dict({
'options': list([
'high',
@@ -282,6 +293,7 @@
'original_name': 'Wi-Fi strength',
'platform': 'aquacell',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wi_fi_strength',
'unique_id': 'DSN-wi_fi_strength',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor Air quality index',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Air quality index',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_AQI',
@@ -40,6 +42,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor Carbon dioxide',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -65,6 +68,7 @@
'original_name': 'Carbon dioxide',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_CO2',
@@ -76,6 +80,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -101,6 +106,7 @@
'original_name': 'Humidity',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_Humidity',
@@ -112,6 +118,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor PM10',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -137,6 +144,7 @@
'original_name': 'PM10',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_PM10',
@@ -148,6 +156,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor PM2.5',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -173,6 +182,7 @@
'original_name': 'PM2.5',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_PM25',
@@ -184,6 +194,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -209,6 +220,7 @@
'original_name': 'Temperature',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_Temperature',
@@ -220,6 +232,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Test Sensor Total volatile organic compounds',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -245,6 +258,7 @@
'original_name': 'Total volatile organic compounds',
'platform': 'arve',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'tvoc',
'unique_id': 'test-serial-number_TVOC',

View File

@@ -37,7 +37,7 @@ from tests.common import (
mock_platform,
)
from tests.components.stt.common import MockSTTProvider, MockSTTProviderEntity
from tests.components.tts.common import MockTTSEntity, MockTTSProvider
from tests.components.tts.common import MockTTSProvider
_TRANSCRIPT = "test transcript"
@@ -68,15 +68,6 @@ async def mock_tts_provider() -> MockTTSProvider:
return provider
@pytest.fixture
def mock_tts_entity() -> MockTTSEntity:
"""Test TTS entity."""
entity = MockTTSEntity("en")
entity._attr_unique_id = "test_tts"
entity._attr_supported_languages = ["en-US"]
return entity
@pytest.fixture
async def mock_stt_provider() -> MockSTTProvider:
"""Mock STT provider."""
@@ -207,7 +198,6 @@ async def init_supporting_components(
mock_stt_provider: MockSTTProvider,
mock_stt_provider_entity: MockSTTProviderEntity,
mock_tts_provider: MockTTSProvider,
mock_tts_entity: MockTTSEntity,
mock_wake_word_provider_entity: MockWakeWordEntity,
mock_wake_word_provider_entity2: MockWakeWordEntity2,
config_flow_fixture,
@@ -219,7 +209,7 @@ async def init_supporting_components(
) -> bool:
"""Set up test config entry."""
await hass.config_entries.async_forward_entry_setups(
config_entry, [Platform.STT, Platform.TTS, Platform.WAKE_WORD]
config_entry, [Platform.STT, Platform.WAKE_WORD]
)
return True
@@ -240,14 +230,6 @@ async def init_supporting_components(
"""Set up test stt platform via config entry."""
async_add_entities([mock_stt_provider_entity])
async def async_setup_entry_tts_platform(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up test tts platform via config entry."""
async_add_entities([mock_tts_entity])
async def async_setup_entry_wake_word_platform(
hass: HomeAssistant,
config_entry: ConfigEntry,
@@ -271,7 +253,6 @@ async def init_supporting_components(
"test.tts",
MockTTSPlatform(
async_get_engine=AsyncMock(return_value=mock_tts_provider),
async_setup_entry=async_setup_entry_tts_platform,
),
)
mock_platform(

View File

@@ -74,17 +74,17 @@
}),
dict({
'data': dict({
'engine': 'tts.test',
'language': 'en_US',
'engine': 'test',
'language': 'en-US',
'tts_input': "Sorry, I couldn't understand that",
'voice': None,
'voice': 'james_earl_jones',
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': dict({
'tts_output': dict({
'media_id': "media-source://tts/tts.test?message=Sorry,+I+couldn't+understand+that&language=en_US&tts_options=%7B%7D",
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&tts_options=%7B%22voice%22:%22james_earl_jones%22%7D",
'mime_type': 'audio/mpeg',
'token': 'test_token.mp3',
'url': '/api/tts_proxy/test_token.mp3',
@@ -395,17 +395,17 @@
}),
dict({
'data': dict({
'engine': 'tts.test',
'language': 'en_US',
'engine': 'test',
'language': 'en-US',
'tts_input': "Sorry, I couldn't understand that",
'voice': None,
'voice': 'james_earl_jones',
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': dict({
'tts_output': dict({
'media_id': "media-source://tts/tts.test?message=Sorry,+I+couldn't+understand+that&language=en_US&tts_options=%7B%7D",
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&tts_options=%7B%22voice%22:%22james_earl_jones%22%7D",
'mime_type': 'audio/mpeg',
'token': 'test_token.mp3',
'url': '/api/tts_proxy/test_token.mp3',

View File

@@ -1,158 +1,4 @@
# serializer version: 1
# name: test_chat_log_tts_streaming[to_stream_tts0]
list([
dict({
'data': dict({
'conversation_id': 'mock-ulid',
'language': 'en',
'pipeline': <ANY>,
'tts_output': dict({
'mime_type': 'audio/mpeg',
'token': 'mocked-token.mp3',
'url': '/api/tts_proxy/mocked-token.mp3',
}),
}),
'type': <PipelineEventType.RUN_START: 'run-start'>,
}),
dict({
'data': dict({
'conversation_id': 'mock-ulid',
'device_id': None,
'engine': 'test-agent',
'intent_input': 'Set a timer',
'language': 'en',
'prefer_local_intents': False,
}),
'type': <PipelineEventType.INTENT_START: 'intent-start'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'role': 'assistant',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': 'hello,',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': ' ',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': 'how',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': ' ',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': 'are',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': ' ',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': 'you',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'chat_log_delta': dict({
'content': '?',
}),
}),
'type': <PipelineEventType.INTENT_PROGRESS: 'intent-progress'>,
}),
dict({
'data': dict({
'intent_output': dict({
'continue_conversation': True,
'conversation_id': <ANY>,
'response': dict({
'card': dict({
}),
'data': dict({
'failed': list([
]),
'success': list([
]),
'targets': list([
]),
}),
'language': 'en',
'response_type': 'action_done',
'speech': dict({
'plain': dict({
'extra_data': None,
'speech': 'hello, how are you?',
}),
}),
}),
}),
'processed_locally': False,
}),
'type': <PipelineEventType.INTENT_END: 'intent-end'>,
}),
dict({
'data': dict({
'engine': 'tts.test',
'language': 'en_US',
'tts_input': 'hello, how are you?',
'voice': None,
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': dict({
'tts_output': dict({
'media_id': 'media-source://tts/tts.test?message=hello,+how+are+you?&language=en_US&tts_options=%7B%7D',
'mime_type': 'audio/mpeg',
'token': 'mocked-token.mp3',
'url': '/api/tts_proxy/mocked-token.mp3',
}),
}),
'type': <PipelineEventType.TTS_END: 'tts-end'>,
}),
dict({
'data': None,
'type': <PipelineEventType.RUN_END: 'run-end'>,
}),
])
# ---
# name: test_pipeline_language_used_instead_of_conversation_language
list([
dict({

View File

@@ -71,16 +71,16 @@
# ---
# name: test_audio_pipeline.5
dict({
'engine': 'tts.test',
'language': 'en_US',
'engine': 'test',
'language': 'en-US',
'tts_input': "Sorry, I couldn't understand that",
'voice': None,
'voice': 'james_earl_jones',
})
# ---
# name: test_audio_pipeline.6
dict({
'tts_output': dict({
'media_id': "media-source://tts/tts.test?message=Sorry,+I+couldn't+understand+that&language=en_US&tts_options=%7B%7D",
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&tts_options=%7B%22voice%22:%22james_earl_jones%22%7D",
'mime_type': 'audio/mpeg',
'token': 'test_token.mp3',
'url': '/api/tts_proxy/test_token.mp3',
@@ -162,16 +162,16 @@
# ---
# name: test_audio_pipeline_debug.5
dict({
'engine': 'tts.test',
'language': 'en_US',
'engine': 'test',
'language': 'en-US',
'tts_input': "Sorry, I couldn't understand that",
'voice': None,
'voice': 'james_earl_jones',
})
# ---
# name: test_audio_pipeline_debug.6
dict({
'tts_output': dict({
'media_id': "media-source://tts/tts.test?message=Sorry,+I+couldn't+understand+that&language=en_US&tts_options=%7B%7D",
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&tts_options=%7B%22voice%22:%22james_earl_jones%22%7D",
'mime_type': 'audio/mpeg',
'token': 'test_token.mp3',
'url': '/api/tts_proxy/test_token.mp3',
@@ -265,16 +265,16 @@
# ---
# name: test_audio_pipeline_with_enhancements.5
dict({
'engine': 'tts.test',
'language': 'en_US',
'engine': 'test',
'language': 'en-US',
'tts_input': "Sorry, I couldn't understand that",
'voice': None,
'voice': 'james_earl_jones',
})
# ---
# name: test_audio_pipeline_with_enhancements.6
dict({
'tts_output': dict({
'media_id': "media-source://tts/tts.test?message=Sorry,+I+couldn't+understand+that&language=en_US&tts_options=%7B%7D",
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&tts_options=%7B%22voice%22:%22james_earl_jones%22%7D",
'mime_type': 'audio/mpeg',
'token': 'test_token.mp3',
'url': '/api/tts_proxy/test_token.mp3',
@@ -378,16 +378,16 @@
# ---
# name: test_audio_pipeline_with_wake_word_no_timeout.7
dict({
'engine': 'tts.test',
'language': 'en_US',
'engine': 'test',
'language': 'en-US',
'tts_input': "Sorry, I couldn't understand that",
'voice': None,
'voice': 'james_earl_jones',
})
# ---
# name: test_audio_pipeline_with_wake_word_no_timeout.8
dict({
'tts_output': dict({
'media_id': "media-source://tts/tts.test?message=Sorry,+I+couldn't+understand+that&language=en_US&tts_options=%7B%7D",
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&tts_options=%7B%22voice%22:%22james_earl_jones%22%7D",
'mime_type': 'audio/mpeg',
'token': 'test_token.mp3',
'url': '/api/tts_proxy/test_token.mp3',

View File

@@ -40,7 +40,6 @@ from . import MANY_LANGUAGES, process_events
from .conftest import (
MockSTTProvider,
MockSTTProviderEntity,
MockTTSEntity,
MockTTSProvider,
MockWakeWordEntity,
make_10ms_chunk,
@@ -63,12 +62,6 @@ async def load_homeassistant(hass: HomeAssistant) -> None:
assert await async_setup_component(hass, "homeassistant", {})
@pytest.fixture
async def disable_tts_entity(mock_tts_entity: tts.TextToSpeechEntity) -> None:
"""Disable the TTS entity."""
mock_tts_entity._attr_entity_registry_enabled_default = False
@pytest.mark.usefixtures("init_components")
async def test_load_pipelines(hass: HomeAssistant) -> None:
"""Make sure that we can load/save data correctly."""
@@ -290,7 +283,6 @@ async def test_migrate_pipeline_store(
@pytest.mark.usefixtures("init_supporting_components")
@pytest.mark.usefixtures("disable_tts_entity")
async def test_create_default_pipeline(hass: HomeAssistant) -> None:
"""Test async_create_default_pipeline."""
assert await async_setup_component(hass, "assist_pipeline", {})
@@ -438,7 +430,6 @@ async def test_default_pipeline_no_stt_tts(
],
)
@pytest.mark.usefixtures("init_supporting_components")
@pytest.mark.usefixtures("disable_tts_entity")
async def test_default_pipeline(
hass: HomeAssistant,
mock_stt_provider_entity: MockSTTProviderEntity,
@@ -483,7 +474,6 @@ async def test_default_pipeline(
@pytest.mark.usefixtures("init_supporting_components")
@pytest.mark.usefixtures("disable_tts_entity")
async def test_default_pipeline_unsupported_stt_language(
hass: HomeAssistant, mock_stt_provider_entity: MockSTTProviderEntity
) -> None:
@@ -514,7 +504,6 @@ async def test_default_pipeline_unsupported_stt_language(
@pytest.mark.usefixtures("init_supporting_components")
@pytest.mark.usefixtures("disable_tts_entity")
async def test_default_pipeline_unsupported_tts_language(
hass: HomeAssistant, mock_tts_provider: MockTTSProvider
) -> None:
@@ -836,7 +825,7 @@ def test_pipeline_run_equality(hass: HomeAssistant, init_components) -> None:
async def test_tts_audio_output(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_tts_entity: MockTTSProvider,
mock_tts_provider: MockTTSProvider,
init_components,
pipeline_data: assist_pipeline.pipeline.PipelineData,
mock_chat_session: chat_session.ChatSession,
@@ -880,7 +869,7 @@ async def test_tts_audio_output(
== 1
)
with patch.object(mock_tts_entity, "get_tts_audio") as mock_get_tts_audio:
with patch.object(mock_tts_provider, "get_tts_audio") as mock_get_tts_audio:
await pipeline_input.execute()
for event in events:
@@ -892,14 +881,14 @@ async def test_tts_audio_output(
# Ensure that no unsupported options were passed in
assert mock_get_tts_audio.called
options = mock_get_tts_audio.call_args_list[0].kwargs["options"]
extra_options = set(options).difference(mock_tts_entity.supported_options)
extra_options = set(options).difference(mock_tts_provider.supported_options)
assert len(extra_options) == 0, extra_options
async def test_tts_wav_preferred_format(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_tts_entity: MockTTSEntity,
mock_tts_provider: MockTTSProvider,
init_components,
mock_chat_session: chat_session.ChatSession,
pipeline_data: assist_pipeline.pipeline.PipelineData,
@@ -931,7 +920,7 @@ async def test_tts_wav_preferred_format(
await pipeline_input.validate()
# Make the TTS provider support preferred format options
supported_options = list(mock_tts_entity.supported_options or [])
supported_options = list(mock_tts_provider.supported_options or [])
supported_options.extend(
[
tts.ATTR_PREFERRED_FORMAT,
@@ -942,8 +931,8 @@ async def test_tts_wav_preferred_format(
)
with (
patch.object(mock_tts_entity, "_supported_options", supported_options),
patch.object(mock_tts_entity, "get_tts_audio") as mock_get_tts_audio,
patch.object(mock_tts_provider, "_supported_options", supported_options),
patch.object(mock_tts_provider, "get_tts_audio") as mock_get_tts_audio,
):
await pipeline_input.execute()
@@ -966,7 +955,7 @@ async def test_tts_wav_preferred_format(
async def test_tts_dict_preferred_format(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_tts_entity: MockTTSEntity,
mock_tts_provider: MockTTSProvider,
init_components,
mock_chat_session: chat_session.ChatSession,
pipeline_data: assist_pipeline.pipeline.PipelineData,
@@ -1003,7 +992,7 @@ async def test_tts_dict_preferred_format(
await pipeline_input.validate()
# Make the TTS provider support preferred format options
supported_options = list(mock_tts_entity.supported_options or [])
supported_options = list(mock_tts_provider.supported_options or [])
supported_options.extend(
[
tts.ATTR_PREFERRED_FORMAT,
@@ -1014,8 +1003,8 @@ async def test_tts_dict_preferred_format(
)
with (
patch.object(mock_tts_entity, "_supported_options", supported_options),
patch.object(mock_tts_entity, "get_tts_audio") as mock_get_tts_audio,
patch.object(mock_tts_provider, "_supported_options", supported_options),
patch.object(mock_tts_provider, "get_tts_audio") as mock_get_tts_audio,
):
await pipeline_input.execute()
@@ -1556,143 +1545,3 @@ async def test_pipeline_language_used_instead_of_conversation_language(
mock_async_converse.call_args_list[0].kwargs.get("language")
== pipeline.language
)
@pytest.mark.parametrize(
"to_stream_tts",
[
[
"hello,",
" ",
"how",
" ",
"are",
" ",
"you",
"?",
]
],
)
async def test_chat_log_tts_streaming(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
init_components,
mock_chat_session: chat_session.ChatSession,
snapshot: SnapshotAssertion,
mock_tts_entity: MockTTSEntity,
pipeline_data: assist_pipeline.pipeline.PipelineData,
to_stream_tts: list[str],
) -> None:
"""Test that chat log events are streamed to the TTS entity."""
events: list[assist_pipeline.PipelineEvent] = []
pipeline_store = pipeline_data.pipeline_store
pipeline_id = pipeline_store.async_get_preferred_item()
pipeline = assist_pipeline.pipeline.async_get_pipeline(hass, pipeline_id)
await assist_pipeline.pipeline.async_update_pipeline(
hass, pipeline, conversation_engine="test-agent"
)
pipeline = assist_pipeline.pipeline.async_get_pipeline(hass, pipeline_id)
pipeline_input = assist_pipeline.pipeline.PipelineInput(
intent_input="Set a timer",
session=mock_chat_session,
run=assist_pipeline.pipeline.PipelineRun(
hass,
context=Context(),
pipeline=pipeline,
start_stage=assist_pipeline.PipelineStage.INTENT,
end_stage=assist_pipeline.PipelineStage.TTS,
event_callback=events.append,
),
)
received_tts = []
async def async_stream_tts_audio(
request: tts.TTSAudioRequest,
) -> tts.TTSAudioResponse:
"""Mock stream TTS audio."""
async def gen_data():
async for msg in request.message_gen:
received_tts.append(msg)
yield msg.encode()
return tts.TTSAudioResponse(
extension="mp3",
data_gen=gen_data(),
)
mock_tts_entity.async_stream_tts_audio = async_stream_tts_audio
with patch(
"homeassistant.components.assist_pipeline.pipeline.conversation.async_get_agent_info",
return_value=conversation.AgentInfo(id="test-agent", name="Test Agent"),
):
await pipeline_input.validate()
async def mock_converse(
hass: HomeAssistant,
text: str,
conversation_id: str | None,
context: Context,
language: str | None = None,
agent_id: str | None = None,
device_id: str | None = None,
extra_system_prompt: str | None = None,
):
"""Mock converse."""
conversation_input = conversation.ConversationInput(
text=text,
context=context,
conversation_id=conversation_id,
device_id=device_id,
language=language,
agent_id=agent_id,
extra_system_prompt=extra_system_prompt,
)
async def stream_llm_response():
yield {"role": "assistant"}
for chunk in to_stream_tts:
yield {"content": chunk}
with (
chat_session.async_get_chat_session(hass, conversation_id) as session,
conversation.async_get_chat_log(
hass,
session,
conversation_input,
) as chat_log,
):
async for _content in chat_log.async_add_delta_content_stream(
agent_id, stream_llm_response()
):
pass
intent_response = intent.IntentResponse(language)
intent_response.async_set_speech("".join(to_stream_tts))
return conversation.ConversationResult(
response=intent_response,
conversation_id=chat_log.conversation_id,
continue_conversation=chat_log.continue_conversation,
)
with patch(
"homeassistant.components.assist_pipeline.pipeline.conversation.async_converse",
mock_converse,
):
await pipeline_input.execute()
stream = tts.async_get_stream(hass, events[0].data["tts_output"]["token"])
assert stream is not None
tts_result = "".join(
[chunk.decode() async for chunk in stream.async_stream_result()]
)
streamed_text = "".join(to_stream_tts)
assert tts_result == streamed_text
assert len(received_tts) == 1
assert "".join(received_tts) == streamed_text
assert process_events(events) == snapshot

View File

@@ -1153,9 +1153,9 @@ async def test_get_pipeline(
"name": "Home Assistant",
"stt_engine": "stt.mock_stt",
"stt_language": "en-US",
"tts_engine": "tts.test",
"tts_language": "en_US",
"tts_voice": None,
"tts_engine": "test",
"tts_language": "en-US",
"tts_voice": "james_earl_jones",
"wake_word_entity": None,
"wake_word_id": None,
"prefer_local_intents": False,
@@ -1179,9 +1179,9 @@ async def test_get_pipeline(
# It found these defaults
"stt_engine": "stt.mock_stt",
"stt_language": "en-US",
"tts_engine": "tts.test",
"tts_language": "en_US",
"tts_voice": None,
"tts_engine": "test",
"tts_language": "en-US",
"tts_voice": "james_earl_jones",
"wake_word_entity": None,
"wake_word_id": None,
"prefer_local_intents": False,
@@ -1266,9 +1266,9 @@ async def test_list_pipelines(
"name": "Home Assistant",
"stt_engine": "stt.mock_stt",
"stt_language": "en-US",
"tts_engine": "tts.test",
"tts_language": "en_US",
"tts_voice": None,
"tts_engine": "test",
"tts_language": "en-US",
"tts_voice": "james_earl_jones",
"wake_word_entity": None,
"wake_word_id": None,
"prefer_local_intents": False,

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Charged month',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Charged month',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charged_month',
'unique_id': '1_battery_charged_month',
@@ -56,6 +58,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Charged today',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -81,6 +84,7 @@
'original_name': 'Charged today',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charged_today',
'unique_id': '1_battery_charged_today',
@@ -108,6 +112,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Charged total',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -133,6 +138,7 @@
'original_name': 'Charged total',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charged_total',
'unique_id': '1_battery_charged_total',
@@ -160,6 +166,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Discharged month',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -185,6 +192,7 @@
'original_name': 'Discharged month',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'discharged_month',
'unique_id': '1_battery_discharged_month',
@@ -212,6 +220,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Discharged today',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -237,6 +246,7 @@
'original_name': 'Discharged today',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'discharged_today',
'unique_id': '1_battery_discharged_today',
@@ -264,6 +274,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Discharged total',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -289,6 +300,7 @@
'original_name': 'Discharged total',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'discharged_total',
'unique_id': '1_battery_discharged_total',
@@ -316,6 +328,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery Flow now',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -341,6 +354,7 @@
'original_name': 'Flow now',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'flow_now',
'unique_id': '1_battery_flow_now',
@@ -368,6 +382,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Battery State of charge',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -393,6 +408,7 @@
'original_name': 'State of charge',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'state_of_charge',
'unique_id': '1_battery_state_of_charge',
@@ -420,6 +436,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Inverter test-serial-1 Energy AC output total',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -445,6 +462,7 @@
'original_name': 'Energy AC output total',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'out_ac_energy_total',
'unique_id': 'test-serial-1_out_ac_energy_total',
@@ -472,6 +490,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Inverter test-serial-1 Power AC output',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -497,6 +516,7 @@
'original_name': 'Power AC output',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'out_ac_power',
'unique_id': 'test-serial-1_out_ac_power',
@@ -524,6 +544,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Inverter test-serial-2 Energy AC output total',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -549,6 +570,7 @@
'original_name': 'Energy AC output total',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'out_ac_energy_total',
'unique_id': 'test-serial-2_out_ac_energy_total',
@@ -576,6 +598,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Inverter test-serial-2 Power AC output',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -601,6 +624,7 @@
'original_name': 'Power AC output',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'out_ac_power',
'unique_id': 'test-serial-2_out_ac_power',
@@ -628,6 +652,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Solar Energy production month',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -653,6 +678,7 @@
'original_name': 'Energy production month',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_production_month',
'unique_id': '1_solar_energy_production_month',
@@ -680,6 +706,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Solar Energy production today',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
@@ -705,6 +732,7 @@
'original_name': 'Energy production today',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_production_today',
'unique_id': '1_solar_energy_production_today',
@@ -732,6 +760,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Solar Energy production total',
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
@@ -757,6 +786,7 @@
'original_name': 'Energy production total',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'energy_production_total',
'unique_id': '1_solar_energy_production_total',
@@ -784,6 +814,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Solar Power production',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -809,6 +840,7 @@
'original_name': 'Power production',
'platform': 'autarco',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'power_production',
'unique_id': '1_solar_power_production',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home DayNight 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'DayNight 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:VideoSource/tnsaxis:DayNightVision-1',
@@ -52,6 +54,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Object Analytics Device1Scenario8',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -75,6 +78,7 @@
'original_name': 'Object Analytics Device1Scenario8',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/ObjectAnalytics/Device1Scenario8-Device1Scenario8',
@@ -100,6 +104,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Sound 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -123,6 +128,7 @@
'original_name': 'Sound 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:AudioSource/tnsaxis:TriggerLevel-1',
@@ -148,6 +154,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home PIR sensor',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -171,6 +178,7 @@
'original_name': 'PIR sensor',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/tnsaxis:IO/Port-0',
@@ -196,6 +204,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home PIR 0',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -219,6 +228,7 @@
'original_name': 'PIR 0',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/tnsaxis:Sensor/PIR-0',
@@ -244,6 +254,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Fence Guard Profile 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -267,6 +278,7 @@
'original_name': 'Fence Guard Profile 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/FenceGuard/Camera1Profile1-Camera1Profile1',
@@ -292,6 +304,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Motion Guard Profile 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -315,6 +328,7 @@
'original_name': 'Motion Guard Profile 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/MotionGuard/Camera1Profile1-Camera1Profile1',
@@ -340,6 +354,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Loitering Guard Profile 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -363,6 +378,7 @@
'original_name': 'Loitering Guard Profile 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/LoiteringGuard/Camera1Profile1-Camera1Profile1',
@@ -388,6 +404,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home VMD4 Profile 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -411,6 +428,7 @@
'original_name': 'VMD4 Profile 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/VMD/Camera1Profile1-Camera1Profile1',
@@ -436,6 +454,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Object Analytics Scenario 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -459,6 +478,7 @@
'original_name': 'Object Analytics Scenario 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/ObjectAnalytics/Device1Scenario1-Device1Scenario1',
@@ -484,6 +504,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home VMD4 Camera1Profile9',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -507,6 +528,7 @@
'original_name': 'VMD4 Camera1Profile9',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tnsaxis:CameraApplicationPlatform/VMD/Camera1Profile9-Camera1Profile9',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': None,
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CameraEntityFeature: 2>,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-camera',
@@ -54,6 +56,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -77,6 +80,7 @@
'original_name': None,
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <CameraEntityFeature: 2>,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-camera',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home IR Light 0',
'capabilities': dict({
'supported_color_modes': list([
<ColorMode.BRIGHTNESS: 'brightness'>,
@@ -31,6 +32,7 @@
'original_name': 'IR Light 0',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/tnsaxis:Light/Status-0',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Doorbell',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Doorbell',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/Trigger/Relay-0',
@@ -52,6 +54,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Relay 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -75,6 +78,7 @@
'original_name': 'Relay 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/Trigger/Relay-1',
@@ -100,6 +104,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Doorbell',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -123,6 +128,7 @@
'original_name': 'Doorbell',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/Trigger/Relay-0',
@@ -148,6 +154,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'home Relay 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -171,6 +178,7 @@
'original_name': 'Relay 1',
'platform': 'axis',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:40:8c:12:34:56-tns1:Device/Trigger/Relay-1',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'CI latest build',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'latest_build',
'unique_id': 'testorg_1234_9876_latest_build',
@@ -63,6 +65,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build finish time',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -86,6 +89,7 @@
'original_name': 'CI latest build finish time',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'finish_time',
'unique_id': 'testorg_1234_9876_finish_time',
@@ -111,6 +115,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build ID',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -134,6 +139,7 @@
'original_name': 'CI latest build ID',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'build_id',
'unique_id': 'testorg_1234_9876_build_id',
@@ -158,6 +164,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build queue time',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -181,6 +188,7 @@
'original_name': 'CI latest build queue time',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'queue_time',
'unique_id': 'testorg_1234_9876_queue_time',
@@ -206,6 +214,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build reason',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -229,6 +238,7 @@
'original_name': 'CI latest build reason',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'reason',
'unique_id': 'testorg_1234_9876_reason',
@@ -253,6 +263,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build result',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -276,6 +287,7 @@
'original_name': 'CI latest build result',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'result',
'unique_id': 'testorg_1234_9876_result',
@@ -300,6 +312,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build source branch',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -323,6 +336,7 @@
'original_name': 'CI latest build source branch',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'source_branch',
'unique_id': 'testorg_1234_9876_source_branch',
@@ -347,6 +361,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build source version',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -370,6 +385,7 @@
'original_name': 'CI latest build source version',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'source_version',
'unique_id': 'testorg_1234_9876_source_version',
@@ -394,6 +410,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build start time',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -417,6 +434,7 @@
'original_name': 'CI latest build start time',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'start_time',
'unique_id': 'testorg_1234_9876_start_time',
@@ -442,6 +460,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'testproject CI latest build URL',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -465,6 +484,7 @@
'original_name': 'CI latest build URL',
'platform': 'azure_devops',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'url',
'unique_id': 'testorg_1234_9876_url',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Backup Backup Manager state',
'capabilities': dict({
'options': list([
'idle',
@@ -35,6 +36,7 @@
'original_name': 'Backup Manager state',
'platform': 'backup',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'backup_manager_state',
'unique_id': 'backup_manager_state',
@@ -67,6 +69,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Backup Last attempted automatic backup',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -90,6 +93,7 @@
'original_name': 'Last attempted automatic backup',
'platform': 'backup',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_attempted_automatic_backup',
'unique_id': 'last_attempted_automatic_backup',
@@ -115,6 +119,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Backup Last successful automatic backup',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -138,6 +143,7 @@
'original_name': 'Last successful automatic backup',
'platform': 'backup',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'last_successful_automatic_backup',
'unique_id': 'last_successful_automatic_backup',
@@ -163,6 +169,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Backup Next scheduled automatic backup',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -186,6 +193,7 @@
'original_name': 'Next scheduled automatic backup',
'platform': 'backup',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'next_scheduled_automatic_backup',
'unique_id': 'next_scheduled_automatic_backup',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Circulation pump',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Circulation pump',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'circ_pump',
'unique_id': 'FakeSpa-Circ Pump-c0ffee',
@@ -52,6 +54,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 1',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -75,6 +78,7 @@
'original_name': 'Filter cycle 1',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_1',
'unique_id': 'FakeSpa-Filter1-c0ffee',
@@ -100,6 +104,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 2',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -123,6 +128,7 @@
'original_name': 'Filter cycle 2',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_2',
'unique_id': 'FakeSpa-Filter2-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa',
'capabilities': dict({
'hvac_modes': list([
<HVACMode.HEAT: 'heat'>,
@@ -38,6 +39,7 @@
'original_name': None,
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ClimateEntityFeature: 401>,
'translation_key': 'balboa',
'unique_id': 'FakeSpa-Climate-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Fault',
'capabilities': dict({
'event_types': list([
'clock_failed',
@@ -48,6 +49,7 @@
'original_name': 'Fault',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'fault',
'unique_id': 'FakeSpa-fault-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Pump 1',
'capabilities': dict({
'preset_modes': None,
}),
@@ -29,6 +30,7 @@
'original_name': 'Pump 1',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <FanEntityFeature: 49>,
'translation_key': 'pump',
'unique_id': 'FakeSpa-Pump 1-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Light',
'capabilities': dict({
'supported_color_modes': list([
<ColorMode.ONOFF: 'onoff'>,
@@ -31,6 +32,7 @@
'original_name': 'Light',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'only_light',
'unique_id': 'FakeSpa-Light-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Temperature range',
'capabilities': dict({
'options': list([
'low',
@@ -32,6 +33,7 @@
'original_name': 'Temperature range',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'temperature_range',
'unique_id': 'FakeSpa-TempHiLow-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 2 enabled',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Filter cycle 2 enabled',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_cycle_2_enabled',
'unique_id': 'FakeSpa-filter_cycle_2_enabled-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 1 end',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Filter cycle 1 end',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_cycle_end',
'unique_id': 'FakeSpa-filter_cycle_1_end-c0ffee',
@@ -51,6 +53,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 1 start',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -74,6 +77,7 @@
'original_name': 'Filter cycle 1 start',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_cycle_start',
'unique_id': 'FakeSpa-filter_cycle_1_start-c0ffee',
@@ -98,6 +102,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 2 end',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -121,6 +126,7 @@
'original_name': 'Filter cycle 2 end',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_cycle_end',
'unique_id': 'FakeSpa-filter_cycle_2_end-c0ffee',
@@ -145,6 +151,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'FakeSpa Filter cycle 2 start',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -168,6 +175,7 @@
'original_name': 'Filter cycle 2 start',
'platform': 'balboa',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'filter_cycle_start',
'unique_id': 'FakeSpa-filter_cycle_2_start-c0ffee',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Tempo Disc THD EEFF Battery',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -29,6 +30,7 @@
'original_name': 'Battery',
'platform': 'bluemaestro',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff-battery',
@@ -56,6 +58,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Tempo Disc THD EEFF Dew point',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -81,6 +84,7 @@
'original_name': 'Dew point',
'platform': 'bluemaestro',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'dew_point',
'unique_id': 'aa:bb:cc:dd:ee:ff-dew_point',
@@ -108,6 +112,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Tempo Disc THD EEFF Humidity',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -133,6 +138,7 @@
'original_name': 'Humidity',
'platform': 'bluemaestro',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff-humidity',
@@ -160,6 +166,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Tempo Disc THD EEFF Signal strength',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -185,6 +192,7 @@
'original_name': 'Signal strength',
'platform': 'bluemaestro',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff-signal_strength',
@@ -212,6 +220,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'Tempo Disc THD EEFF Temperature',
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
@@ -237,6 +246,7 @@
'original_name': 'Temperature',
'platform': 'bluemaestro',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'aa:bb:cc:dd:ee:ff-temperature',

View File

@@ -4,6 +4,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Charging status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -27,6 +28,7 @@
'original_name': 'Charging status',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charging_status',
'unique_id': 'WBY00000000REXI01-charging_status',
@@ -52,6 +54,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Check control messages',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -75,6 +78,7 @@
'original_name': 'Check control messages',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'check_control_messages',
'unique_id': 'WBY00000000REXI01-check_control_messages',
@@ -100,6 +104,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Condition-based services',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -123,6 +128,7 @@
'original_name': 'Condition-based services',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'condition_based_services',
'unique_id': 'WBY00000000REXI01-condition_based_services',
@@ -154,6 +160,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Connection status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -177,6 +184,7 @@
'original_name': 'Connection status',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'connection_status',
'unique_id': 'WBY00000000REXI01-connection_status',
@@ -202,6 +210,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Door lock state',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -225,6 +234,7 @@
'original_name': 'Door lock state',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'door_lock_state',
'unique_id': 'WBY00000000REXI01-door_lock_state',
@@ -251,6 +261,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Lids',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -274,6 +285,7 @@
'original_name': 'Lids',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lids',
'unique_id': 'WBY00000000REXI01-lids',
@@ -306,6 +318,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Pre-entry climatization',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -329,6 +342,7 @@
'original_name': 'Pre-entry climatization',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'is_pre_entry_climatization_enabled',
'unique_id': 'WBY00000000REXI01-is_pre_entry_climatization_enabled',
@@ -353,6 +367,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i3 (+ REX) Windows',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -376,6 +391,7 @@
'original_name': 'Windows',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'windows',
'unique_id': 'WBY00000000REXI01-windows',
@@ -403,6 +419,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Charging status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -426,6 +443,7 @@
'original_name': 'Charging status',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charging_status',
'unique_id': 'WBA00000000DEMO02-charging_status',
@@ -451,6 +469,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Check control messages',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -474,6 +493,7 @@
'original_name': 'Check control messages',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'check_control_messages',
'unique_id': 'WBA00000000DEMO02-check_control_messages',
@@ -500,6 +520,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Condition-based services',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -523,6 +544,7 @@
'original_name': 'Condition-based services',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'condition_based_services',
'unique_id': 'WBA00000000DEMO02-condition_based_services',
@@ -559,6 +581,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Connection status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -582,6 +605,7 @@
'original_name': 'Connection status',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'connection_status',
'unique_id': 'WBA00000000DEMO02-connection_status',
@@ -607,6 +631,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Door lock state',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -630,6 +655,7 @@
'original_name': 'Door lock state',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'door_lock_state',
'unique_id': 'WBA00000000DEMO02-door_lock_state',
@@ -656,6 +682,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Lids',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -679,6 +706,7 @@
'original_name': 'Lids',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lids',
'unique_id': 'WBA00000000DEMO02-lids',
@@ -710,6 +738,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Pre-entry climatization',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -733,6 +762,7 @@
'original_name': 'Pre-entry climatization',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'is_pre_entry_climatization_enabled',
'unique_id': 'WBA00000000DEMO02-is_pre_entry_climatization_enabled',
@@ -757,6 +787,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'i4 eDrive40 Windows',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -780,6 +811,7 @@
'original_name': 'Windows',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'windows',
'unique_id': 'WBA00000000DEMO02-windows',
@@ -810,6 +842,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Charging status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -833,6 +866,7 @@
'original_name': 'Charging status',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charging_status',
'unique_id': 'WBA00000000DEMO01-charging_status',
@@ -858,6 +892,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Check control messages',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -881,6 +916,7 @@
'original_name': 'Check control messages',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'check_control_messages',
'unique_id': 'WBA00000000DEMO01-check_control_messages',
@@ -907,6 +943,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Condition-based services',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -930,6 +967,7 @@
'original_name': 'Condition-based services',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'condition_based_services',
'unique_id': 'WBA00000000DEMO01-condition_based_services',
@@ -966,6 +1004,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Connection status',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -989,6 +1028,7 @@
'original_name': 'Connection status',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'connection_status',
'unique_id': 'WBA00000000DEMO01-connection_status',
@@ -1014,6 +1054,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Door lock state',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1037,6 +1078,7 @@
'original_name': 'Door lock state',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'door_lock_state',
'unique_id': 'WBA00000000DEMO01-door_lock_state',
@@ -1063,6 +1105,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Lids',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1086,6 +1129,7 @@
'original_name': 'Lids',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lids',
'unique_id': 'WBA00000000DEMO01-lids',
@@ -1118,6 +1162,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Pre-entry climatization',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1141,6 +1186,7 @@
'original_name': 'Pre-entry climatization',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'is_pre_entry_climatization_enabled',
'unique_id': 'WBA00000000DEMO01-is_pre_entry_climatization_enabled',
@@ -1165,6 +1211,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'iX xDrive50 Windows',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1188,6 +1235,7 @@
'original_name': 'Windows',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'windows',
'unique_id': 'WBA00000000DEMO01-windows',
@@ -1218,6 +1266,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'M340i xDrive Check control messages',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1241,6 +1290,7 @@
'original_name': 'Check control messages',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'check_control_messages',
'unique_id': 'WBA00000000DEMO03-check_control_messages',
@@ -1268,6 +1318,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'M340i xDrive Condition-based services',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1291,6 +1342,7 @@
'original_name': 'Condition-based services',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'condition_based_services',
'unique_id': 'WBA00000000DEMO03-condition_based_services',
@@ -1330,6 +1382,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'M340i xDrive Door lock state',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1353,6 +1406,7 @@
'original_name': 'Door lock state',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'door_lock_state',
'unique_id': 'WBA00000000DEMO03-door_lock_state',
@@ -1379,6 +1433,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'M340i xDrive Lids',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1402,6 +1457,7 @@
'original_name': 'Lids',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'lids',
'unique_id': 'WBA00000000DEMO03-lids',
@@ -1433,6 +1489,7 @@
'aliases': set({
}),
'area_id': None,
'calculated_object_id': 'M340i xDrive Windows',
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
@@ -1456,6 +1513,7 @@
'original_name': 'Windows',
'platform': 'bmw_connected_drive',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'windows',
'unique_id': 'WBA00000000DEMO03-windows',

Some files were not shown because too many files have changed in this diff Show More