Compare commits
2 commits
dev
...
frenck-202
Author | SHA1 | Date | |
---|---|---|---|
|
ed4aa93ee8 | ||
|
284fc94d31 |
74 changed files with 6381 additions and 885 deletions
|
@ -32,6 +32,7 @@ from .helpers import (
|
|||
entity,
|
||||
entity_registry,
|
||||
issue_registry,
|
||||
label_registry,
|
||||
recorder,
|
||||
restore_state,
|
||||
template,
|
||||
|
@ -298,6 +299,7 @@ async def async_load_base_functionality(hass: core.HomeAssistant) -> None:
|
|||
device_registry.async_load(hass),
|
||||
entity_registry.async_load(hass),
|
||||
issue_registry.async_load(hass),
|
||||
label_registry.async_load(hass),
|
||||
hass.async_add_executor_job(_cache_uname_processor),
|
||||
template.async_load_custom_templates(hass),
|
||||
restore_state.async_load(hass),
|
||||
|
|
|
@ -35,6 +35,7 @@ SECTIONS = (
|
|||
"core",
|
||||
"device_registry",
|
||||
"entity_registry",
|
||||
"label_registry",
|
||||
"script",
|
||||
"scene",
|
||||
)
|
||||
|
|
128
homeassistant/components/config/label_registry.py
Normal file
128
homeassistant/components/config/label_registry.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
"""Websocket API to interact with the label registry."""
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import websocket_api
|
||||
from homeassistant.components.websocket_api.connection import ActiveConnection
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.label_registry import LabelEntry, async_get
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant) -> bool:
|
||||
"""Register the Label Registry WS commands."""
|
||||
websocket_api.async_register_command(hass, websocket_list_labels)
|
||||
websocket_api.async_register_command(hass, websocket_create_label)
|
||||
websocket_api.async_register_command(hass, websocket_delete_label)
|
||||
websocket_api.async_register_command(hass, websocket_update_label)
|
||||
return True
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "config/label_registry/list",
|
||||
}
|
||||
)
|
||||
@callback
|
||||
def websocket_list_labels(
|
||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Handle list labels command."""
|
||||
registry = async_get(hass)
|
||||
connection.send_result(
|
||||
msg["id"],
|
||||
[_entry_dict(entry) for entry in registry.async_list_labels()],
|
||||
)
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "config/label_registry/create",
|
||||
vol.Required("name"): str,
|
||||
vol.Optional("color"): vol.Any(str, None),
|
||||
vol.Optional("description"): vol.Any(str, None),
|
||||
vol.Optional("icon"): vol.Any(str, None),
|
||||
}
|
||||
)
|
||||
@websocket_api.require_admin
|
||||
@callback
|
||||
def websocket_create_label(
|
||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Create label command."""
|
||||
registry = async_get(hass)
|
||||
|
||||
data = dict(msg)
|
||||
data.pop("type")
|
||||
data.pop("id")
|
||||
|
||||
try:
|
||||
entry = registry.async_create(**data)
|
||||
except ValueError as err:
|
||||
connection.send_error(msg["id"], "invalid_info", str(err))
|
||||
else:
|
||||
connection.send_result(msg["id"], _entry_dict(entry))
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "config/label_registry/delete",
|
||||
vol.Required("label_id"): str,
|
||||
}
|
||||
)
|
||||
@websocket_api.require_admin
|
||||
@callback
|
||||
def websocket_delete_label(
|
||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Delete label command."""
|
||||
registry = async_get(hass)
|
||||
|
||||
try:
|
||||
registry.async_delete(msg["label_id"])
|
||||
except KeyError:
|
||||
connection.send_error(msg["id"], "invalid_info", "Label ID doesn't exist")
|
||||
else:
|
||||
connection.send_message(websocket_api.result_message(msg["id"], "success"))
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "config/label_registry/update",
|
||||
vol.Required("label_id"): str,
|
||||
vol.Optional("color"): vol.Any(str, None),
|
||||
vol.Optional("description"): vol.Any(str, None),
|
||||
vol.Optional("icon"): vol.Any(str, None),
|
||||
vol.Optional("name"): str,
|
||||
}
|
||||
)
|
||||
@websocket_api.require_admin
|
||||
@callback
|
||||
def websocket_update_label(
|
||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Handle update label websocket command."""
|
||||
registry = async_get(hass)
|
||||
|
||||
data = dict(msg)
|
||||
data.pop("type")
|
||||
data.pop("id")
|
||||
|
||||
try:
|
||||
entry = registry.async_update(**data)
|
||||
except ValueError as err:
|
||||
connection.send_error(msg["id"], "invalid_info", str(err))
|
||||
else:
|
||||
connection.send_result(msg["id"], _entry_dict(entry))
|
||||
|
||||
|
||||
@callback
|
||||
def _entry_dict(entry: LabelEntry) -> dict[str, Any]:
|
||||
"""Convert entry to API format."""
|
||||
return {
|
||||
"color": entry.color,
|
||||
"description": entry.description,
|
||||
"icon": entry.icon,
|
||||
"label_id": entry.label_id,
|
||||
"name": entry.name,
|
||||
}
|
|
@ -509,6 +509,10 @@ ATTR_AREA_ID: Final = "area_id"
|
|||
# Contains one string, the device ID
|
||||
ATTR_DEVICE_ID: Final = "device_id"
|
||||
|
||||
# Label identifier. Also used as service calls target parameter in which case
|
||||
# it contains one string or a list of strings, each being an label id.
|
||||
ATTR_LABEL_ID: Final = "label_id"
|
||||
|
||||
# String with a friendly name for the entity
|
||||
ATTR_FRIENDLY_NAME: Final = "friendly_name"
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ from homeassistant.const import (
|
|||
ATTR_AREA_ID,
|
||||
ATTR_DEVICE_ID,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_LABEL_ID,
|
||||
CONF_ABOVE,
|
||||
CONF_ALIAS,
|
||||
CONF_ATTRIBUTE,
|
||||
|
@ -1229,6 +1230,9 @@ ENTITY_SERVICE_FIELDS = {
|
|||
vol.Optional(ATTR_AREA_ID): vol.Any(
|
||||
ENTITY_MATCH_NONE, vol.All(ensure_list, [vol.Any(dynamic_template, str)])
|
||||
),
|
||||
vol.Optional(ATTR_LABEL_ID): vol.Any(
|
||||
ENTITY_MATCH_NONE, vol.All(ensure_list, [vol.Any(dynamic_template, str)])
|
||||
),
|
||||
}
|
||||
|
||||
TARGET_SERVICE_FIELDS = {
|
||||
|
@ -1246,6 +1250,9 @@ TARGET_SERVICE_FIELDS = {
|
|||
vol.Optional(ATTR_AREA_ID): vol.Any(
|
||||
ENTITY_MATCH_NONE, vol.All(ensure_list, [vol.Any(dynamic_template, str)])
|
||||
),
|
||||
vol.Optional(ATTR_LABEL_ID): vol.Any(
|
||||
ENTITY_MATCH_NONE, vol.All(ensure_list, [vol.Any(dynamic_template, str)])
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ DATA_REGISTRY = "device_registry"
|
|||
EVENT_DEVICE_REGISTRY_UPDATED = "device_registry_updated"
|
||||
STORAGE_KEY = "core.device_registry"
|
||||
STORAGE_VERSION_MAJOR = 1
|
||||
STORAGE_VERSION_MINOR = 4
|
||||
STORAGE_VERSION_MINOR = 5
|
||||
SAVE_DELAY = 10
|
||||
CLEANUP_DELAY = 10
|
||||
|
||||
|
@ -238,6 +238,7 @@ class DeviceEntry:
|
|||
hw_version: str | None = attr.ib(default=None)
|
||||
id: str = attr.ib(factory=uuid_util.random_uuid_hex)
|
||||
identifiers: set[tuple[str, str]] = attr.ib(converter=set, factory=set)
|
||||
labels: set[str] = attr.ib(converter=set, factory=set)
|
||||
manufacturer: str | None = attr.ib(default=None)
|
||||
model: str | None = attr.ib(default=None)
|
||||
name_by_user: str | None = attr.ib(default=None)
|
||||
|
@ -378,6 +379,10 @@ class DeviceRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
|
|||
# Introduced in 2023.11
|
||||
for device in old_data["devices"]:
|
||||
device["serial_number"] = None
|
||||
if old_minor_version < 5:
|
||||
# Introduced in 2024.3
|
||||
for device in old_data["devices"]:
|
||||
device["labels"] = device.get("labels", [])
|
||||
|
||||
if old_major_version > 1:
|
||||
raise NotImplementedError
|
||||
|
@ -634,6 +639,7 @@ class DeviceRegistry:
|
|||
disabled_by: DeviceEntryDisabler | None | UndefinedType = UNDEFINED,
|
||||
entry_type: DeviceEntryType | None | UndefinedType = UNDEFINED,
|
||||
hw_version: str | None | UndefinedType = UNDEFINED,
|
||||
labels: set[str] | UndefinedType = UNDEFINED,
|
||||
manufacturer: str | None | UndefinedType = UNDEFINED,
|
||||
merge_connections: set[tuple[str, str]] | UndefinedType = UNDEFINED,
|
||||
merge_identifiers: set[tuple[str, str]] | UndefinedType = UNDEFINED,
|
||||
|
@ -728,11 +734,12 @@ class DeviceRegistry:
|
|||
("disabled_by", disabled_by),
|
||||
("entry_type", entry_type),
|
||||
("hw_version", hw_version),
|
||||
("labels", labels),
|
||||
("manufacturer", manufacturer),
|
||||
("model", model),
|
||||
("name", name),
|
||||
("name_by_user", name_by_user),
|
||||
("serial_number", serial_number),
|
||||
("name", name),
|
||||
("suggested_area", suggested_area),
|
||||
("sw_version", sw_version),
|
||||
("via_device_id", via_device_id),
|
||||
|
@ -822,6 +829,7 @@ class DeviceRegistry:
|
|||
tuple(iden) # type: ignore[misc]
|
||||
for iden in device["identifiers"]
|
||||
},
|
||||
labels=set(device["labels"]),
|
||||
manufacturer=device["manufacturer"],
|
||||
model=device["model"],
|
||||
name_by_user=device["name_by_user"],
|
||||
|
@ -865,6 +873,7 @@ class DeviceRegistry:
|
|||
"hw_version": entry.hw_version,
|
||||
"id": entry.id,
|
||||
"identifiers": list(entry.identifiers),
|
||||
"labels": list(entry.labels),
|
||||
"manufacturer": entry.manufacturer,
|
||||
"model": entry.model,
|
||||
"name_by_user": entry.name_by_user,
|
||||
|
@ -937,6 +946,15 @@ class DeviceRegistry:
|
|||
if area_id == device.area_id:
|
||||
self.async_update_device(dev_id, area_id=None)
|
||||
|
||||
@callback
|
||||
def async_clear_label_id(self, label_id: str) -> None:
|
||||
"""Clear label from registry entries."""
|
||||
for device_id, entry in self.devices.items():
|
||||
if label_id in entry.labels:
|
||||
labels = entry.labels.copy()
|
||||
labels.remove(label_id)
|
||||
self.async_update_device(device_id, labels=labels)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get(hass: HomeAssistant) -> DeviceRegistry:
|
||||
|
@ -957,6 +975,14 @@ def async_entries_for_area(registry: DeviceRegistry, area_id: str) -> list[Devic
|
|||
return [device for device in registry.devices.values() if device.area_id == area_id]
|
||||
|
||||
|
||||
@callback
|
||||
def async_entries_for_label(
|
||||
registry: DeviceRegistry, label_id: str
|
||||
) -> list[DeviceEntry]:
|
||||
"""Return entries that match an label."""
|
||||
return [device for device in registry.devices.values() if label_id in device.labels]
|
||||
|
||||
|
||||
@callback
|
||||
def async_entries_for_config_entry(
|
||||
registry: DeviceRegistry, config_entry_id: str
|
||||
|
|
|
@ -65,7 +65,7 @@ SAVE_DELAY = 10
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
STORAGE_VERSION_MAJOR = 1
|
||||
STORAGE_VERSION_MINOR = 12
|
||||
STORAGE_VERSION_MINOR = 13
|
||||
STORAGE_KEY = "core.entity_registry"
|
||||
|
||||
CLEANUP_INTERVAL = 3600 * 24
|
||||
|
@ -135,6 +135,7 @@ ReadOnlyEntityOptionsType = ReadOnlyDict[str, ReadOnlyDict[str, Any]]
|
|||
|
||||
DISPLAY_DICT_OPTIONAL = (
|
||||
("ai", "area_id"),
|
||||
("lb", "labels"),
|
||||
("di", "device_id"),
|
||||
("ic", "icon"),
|
||||
("tk", "translation_key"),
|
||||
|
@ -174,6 +175,7 @@ class RegistryEntry:
|
|||
converter=attr.converters.default_if_none(factory=uuid_util.random_uuid_hex), # type: ignore[misc]
|
||||
)
|
||||
has_entity_name: bool = attr.ib(default=False)
|
||||
labels: set[str] = attr.ib(factory=set)
|
||||
name: str | None = attr.ib(default=None)
|
||||
options: ReadOnlyEntityOptionsType = attr.ib(
|
||||
default=None, converter=_protect_entity_options
|
||||
|
@ -268,6 +270,7 @@ class RegistryEntry:
|
|||
"platform": self.platform,
|
||||
"translation_key": self.translation_key,
|
||||
"unique_id": self.unique_id,
|
||||
"labels": self.labels,
|
||||
}
|
||||
|
||||
@cached_property
|
||||
|
@ -348,7 +351,7 @@ class DeletedRegistryEntry:
|
|||
class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
|
||||
"""Store entity registry data."""
|
||||
|
||||
async def _async_migrate_func(
|
||||
async def _async_migrate_func( # noqa: C901
|
||||
self,
|
||||
old_major_version: int,
|
||||
old_minor_version: int,
|
||||
|
@ -429,6 +432,11 @@ class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
|
|||
for entity in data["entities"]:
|
||||
entity["previous_unique_id"] = None
|
||||
|
||||
if old_major_version == 1 and old_minor_version < 13:
|
||||
# Version 1.13 adds labels
|
||||
for entity in data["entities"]:
|
||||
entity["labels"] = []
|
||||
|
||||
if old_major_version > 1:
|
||||
raise NotImplementedError
|
||||
return data
|
||||
|
@ -853,9 +861,10 @@ class EntityRegistry:
|
|||
device_id: str | None | UndefinedType = UNDEFINED,
|
||||
disabled_by: RegistryEntryDisabler | None | UndefinedType = UNDEFINED,
|
||||
entity_category: EntityCategory | None | UndefinedType = UNDEFINED,
|
||||
has_entity_name: bool | UndefinedType = UNDEFINED,
|
||||
hidden_by: RegistryEntryHider | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
has_entity_name: bool | UndefinedType = UNDEFINED,
|
||||
labels: set[str] | UndefinedType = UNDEFINED,
|
||||
name: str | None | UndefinedType = UNDEFINED,
|
||||
new_entity_id: str | UndefinedType = UNDEFINED,
|
||||
new_unique_id: str | UndefinedType = UNDEFINED,
|
||||
|
@ -903,9 +912,10 @@ class EntityRegistry:
|
|||
("device_id", device_id),
|
||||
("disabled_by", disabled_by),
|
||||
("entity_category", entity_category),
|
||||
("has_entity_name", has_entity_name),
|
||||
("hidden_by", hidden_by),
|
||||
("icon", icon),
|
||||
("has_entity_name", has_entity_name),
|
||||
("labels", labels),
|
||||
("name", name),
|
||||
("options", options),
|
||||
("original_device_class", original_device_class),
|
||||
|
@ -980,9 +990,10 @@ class EntityRegistry:
|
|||
device_id: str | None | UndefinedType = UNDEFINED,
|
||||
disabled_by: RegistryEntryDisabler | None | UndefinedType = UNDEFINED,
|
||||
entity_category: EntityCategory | None | UndefinedType = UNDEFINED,
|
||||
has_entity_name: bool | UndefinedType = UNDEFINED,
|
||||
hidden_by: RegistryEntryHider | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
has_entity_name: bool | UndefinedType = UNDEFINED,
|
||||
labels: set[str] | UndefinedType = UNDEFINED,
|
||||
name: str | None | UndefinedType = UNDEFINED,
|
||||
new_entity_id: str | UndefinedType = UNDEFINED,
|
||||
new_unique_id: str | UndefinedType = UNDEFINED,
|
||||
|
@ -1004,9 +1015,10 @@ class EntityRegistry:
|
|||
device_id=device_id,
|
||||
disabled_by=disabled_by,
|
||||
entity_category=entity_category,
|
||||
has_entity_name=has_entity_name,
|
||||
hidden_by=hidden_by,
|
||||
icon=icon,
|
||||
has_entity_name=has_entity_name,
|
||||
labels=labels,
|
||||
name=name,
|
||||
new_entity_id=new_entity_id,
|
||||
new_unique_id=new_unique_id,
|
||||
|
@ -1098,12 +1110,13 @@ class EntityRegistry:
|
|||
if entity["entity_category"]
|
||||
else None,
|
||||
entity_id=entity["entity_id"],
|
||||
has_entity_name=entity["has_entity_name"],
|
||||
hidden_by=RegistryEntryHider(entity["hidden_by"])
|
||||
if entity["hidden_by"]
|
||||
else None,
|
||||
icon=entity["icon"],
|
||||
id=entity["id"],
|
||||
has_entity_name=entity["has_entity_name"],
|
||||
labels=set(entity["labels"]),
|
||||
name=entity["name"],
|
||||
options=entity["options"],
|
||||
original_device_class=entity["original_device_class"],
|
||||
|
@ -1156,10 +1169,11 @@ class EntityRegistry:
|
|||
"disabled_by": entry.disabled_by,
|
||||
"entity_category": entry.entity_category,
|
||||
"entity_id": entry.entity_id,
|
||||
"has_entity_name": entry.has_entity_name,
|
||||
"hidden_by": entry.hidden_by,
|
||||
"icon": entry.icon,
|
||||
"id": entry.id,
|
||||
"has_entity_name": entry.has_entity_name,
|
||||
"labels": list(entry.labels),
|
||||
"name": entry.name,
|
||||
"options": entry.options,
|
||||
"original_device_class": entry.original_device_class,
|
||||
|
@ -1230,6 +1244,15 @@ class EntityRegistry:
|
|||
if area_id == entry.area_id:
|
||||
self.async_update_entity(entity_id, area_id=None)
|
||||
|
||||
@callback
|
||||
def async_clear_label_id(self, label_id: str) -> None:
|
||||
"""Clear label from registry entries."""
|
||||
for entity_id, entry in self.entities.items():
|
||||
if label_id in entry.labels:
|
||||
labels = entry.labels.copy()
|
||||
labels.remove(label_id)
|
||||
self.async_update_entity(entity_id, labels=labels)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get(hass: HomeAssistant) -> EntityRegistry:
|
||||
|
@ -1264,6 +1287,14 @@ def async_entries_for_area(
|
|||
return [entry for entry in registry.entities.values() if entry.area_id == area_id]
|
||||
|
||||
|
||||
@callback
|
||||
def async_entries_for_label(
|
||||
registry: EntityRegistry, label_id: str
|
||||
) -> list[RegistryEntry]:
|
||||
"""Return entries that match an label."""
|
||||
return [entry for entry in registry.entities.values() if label_id in entry.labels]
|
||||
|
||||
|
||||
@callback
|
||||
def async_entries_for_config_entry(
|
||||
registry: EntityRegistry, config_entry_id: str
|
||||
|
|
242
homeassistant/helpers/label_registry.py
Normal file
242
homeassistant/helpers/label_registry.py
Normal file
|
@ -0,0 +1,242 @@
|
|||
"""Provide a way to label and categorize anything."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterable, MutableMapping
|
||||
import dataclasses
|
||||
from dataclasses import dataclass
|
||||
from typing import cast
|
||||
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import device_registry as dr, entity_registry as er
|
||||
from .typing import UNDEFINED, UndefinedType
|
||||
|
||||
DATA_REGISTRY = "label_registry"
|
||||
EVENT_LABEL_REGISTRY_UPDATED = "label_registry_updated"
|
||||
STORAGE_KEY = "core.label_registry"
|
||||
STORAGE_VERSION_MAJOR = 1
|
||||
SAVE_DELAY = 10
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class LabelEntry:
|
||||
"""Label Registry Entry."""
|
||||
|
||||
label_id: str
|
||||
name: str
|
||||
normalized_name: str
|
||||
description: str | None = None
|
||||
color: str | None = None
|
||||
icon: str | None = None
|
||||
|
||||
|
||||
class LabelRegistry:
|
||||
"""Class to hold a registry of labels."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Initialize the label registry."""
|
||||
self.hass = hass
|
||||
self.labels: MutableMapping[str, LabelEntry] = {}
|
||||
self._store = hass.helpers.storage.Store(
|
||||
STORAGE_VERSION_MAJOR,
|
||||
STORAGE_KEY,
|
||||
atomic_writes=True,
|
||||
)
|
||||
self._normalized_name_label_idx: dict[str, str] = {}
|
||||
self.children: dict[str, set[str]] = {}
|
||||
|
||||
@callback
|
||||
def async_get_label(self, label_id: str) -> LabelEntry | None:
|
||||
"""Get label by id."""
|
||||
return self.labels.get(label_id)
|
||||
|
||||
@callback
|
||||
def async_get_label_by_name(self, name: str) -> LabelEntry | None:
|
||||
"""Get label by name."""
|
||||
normalized_name = normalize_label_name(name)
|
||||
if normalized_name not in self._normalized_name_label_idx:
|
||||
return None
|
||||
return self.labels[self._normalized_name_label_idx[normalized_name]]
|
||||
|
||||
@callback
|
||||
def async_list_labels(self) -> Iterable[LabelEntry]:
|
||||
"""Get all labels."""
|
||||
return self.labels.values()
|
||||
|
||||
@callback
|
||||
def async_get_or_create(self, name: str) -> LabelEntry:
|
||||
"""Get or create an label."""
|
||||
if label := self.async_get_label_by_name(name):
|
||||
return label
|
||||
return self.async_create(name)
|
||||
|
||||
@callback
|
||||
def _generate_id(self, name: str) -> str:
|
||||
"""Initialize ID."""
|
||||
suggestion = suggestion_base = slugify(name)
|
||||
tries = 1
|
||||
while suggestion in self.labels:
|
||||
tries += 1
|
||||
suggestion = f"{suggestion_base}_{tries}"
|
||||
return suggestion
|
||||
|
||||
@callback
|
||||
def async_create(
|
||||
self,
|
||||
name: str,
|
||||
*,
|
||||
color: str | None = None,
|
||||
icon: str | None = None,
|
||||
description: str | None = None,
|
||||
) -> LabelEntry:
|
||||
"""Create a new label."""
|
||||
normalized_name = normalize_label_name(name)
|
||||
|
||||
if self.async_get_label_by_name(name):
|
||||
raise ValueError(f"The name {name} ({normalized_name}) is already in use")
|
||||
|
||||
label = LabelEntry(
|
||||
color=color,
|
||||
description=description,
|
||||
icon=icon,
|
||||
label_id=self._generate_id(name),
|
||||
name=name,
|
||||
normalized_name=normalized_name,
|
||||
)
|
||||
self.labels[label.label_id] = label
|
||||
self._normalized_name_label_idx[normalized_name] = label.label_id
|
||||
self.async_schedule_save()
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_LABEL_REGISTRY_UPDATED,
|
||||
{"action": "create", "label_id": label.label_id},
|
||||
)
|
||||
return label
|
||||
|
||||
@callback
|
||||
def async_delete(self, label_id: str) -> None:
|
||||
"""Delete label."""
|
||||
label = self.labels[label_id]
|
||||
|
||||
# Clean up all references
|
||||
dr.async_get(self.hass).async_clear_label_id(label_id)
|
||||
er.async_get(self.hass).async_clear_label_id(label_id)
|
||||
|
||||
del self.labels[label_id]
|
||||
del self._normalized_name_label_idx[label.normalized_name]
|
||||
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_LABEL_REGISTRY_UPDATED, {"action": "remove", "label_id": label_id}
|
||||
)
|
||||
|
||||
self.async_schedule_save()
|
||||
|
||||
@callback
|
||||
def async_update(
|
||||
self,
|
||||
label_id: str,
|
||||
color: str | None | UndefinedType = UNDEFINED,
|
||||
description: str | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
name: str | UndefinedType = UNDEFINED,
|
||||
) -> LabelEntry:
|
||||
"""Update name of label."""
|
||||
old = self.labels[label_id]
|
||||
changes = {
|
||||
attr_name: value
|
||||
for attr_name, value in (
|
||||
("color", color),
|
||||
("description", description),
|
||||
("icon", icon),
|
||||
)
|
||||
if value is not UNDEFINED and getattr(old, attr_name) != value
|
||||
}
|
||||
|
||||
normalized_name = None
|
||||
|
||||
if name is not UNDEFINED and name != old.name:
|
||||
normalized_name = normalize_label_name(name)
|
||||
if normalized_name != old.normalized_name and self.async_get_label_by_name(
|
||||
name
|
||||
):
|
||||
raise ValueError(
|
||||
f"The name {name} ({normalized_name}) is already in use"
|
||||
)
|
||||
|
||||
changes["name"] = name
|
||||
changes["normalized_name"] = normalized_name
|
||||
|
||||
if not changes:
|
||||
return old
|
||||
|
||||
new = self.labels[label_id] = dataclasses.replace(old, **changes) # type: ignore[arg-type]
|
||||
if normalized_name is not None:
|
||||
self._normalized_name_label_idx[
|
||||
normalized_name
|
||||
] = self._normalized_name_label_idx.pop(old.normalized_name)
|
||||
|
||||
self.async_schedule_save()
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_LABEL_REGISTRY_UPDATED, {"action": "update", "label_id": label_id}
|
||||
)
|
||||
|
||||
return new
|
||||
|
||||
async def async_load(self) -> None:
|
||||
"""Load the label registry."""
|
||||
data = await self._store.async_load()
|
||||
labels: MutableMapping[str, LabelEntry] = {}
|
||||
|
||||
if data is not None:
|
||||
for label in data["labels"]:
|
||||
normalized_name = normalize_label_name(label["name"])
|
||||
labels[label["label_id"]] = LabelEntry(
|
||||
color=label["color"],
|
||||
description=label["description"],
|
||||
icon=label["icon"],
|
||||
label_id=label["label_id"],
|
||||
name=label["name"],
|
||||
normalized_name=normalized_name,
|
||||
)
|
||||
self._normalized_name_label_idx[normalized_name] = label["label_id"]
|
||||
|
||||
self.labels = labels
|
||||
|
||||
@callback
|
||||
def async_schedule_save(self) -> None:
|
||||
"""Schedule saving the label registry."""
|
||||
self._store.async_delay_save(self._data_to_save, SAVE_DELAY)
|
||||
|
||||
@callback
|
||||
def _data_to_save(self) -> dict[str, list[dict[str, str | None]]]:
|
||||
"""Return data of label registry to store in a file."""
|
||||
return {
|
||||
"labels": [
|
||||
{
|
||||
"color": entry.color,
|
||||
"description": entry.description,
|
||||
"icon": entry.icon,
|
||||
"label_id": entry.label_id,
|
||||
"name": entry.name,
|
||||
}
|
||||
for entry in self.labels.values()
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@callback
|
||||
def async_get(hass: HomeAssistant) -> LabelRegistry:
|
||||
"""Get label registry."""
|
||||
return cast(LabelRegistry, hass.data[DATA_REGISTRY])
|
||||
|
||||
|
||||
async def async_load(hass: HomeAssistant) -> None:
|
||||
"""Load label registry."""
|
||||
assert DATA_REGISTRY not in hass.data
|
||||
hass.data[DATA_REGISTRY] = LabelRegistry(hass)
|
||||
await hass.data[DATA_REGISTRY].async_load()
|
||||
|
||||
|
||||
def normalize_label_name(label_name: str) -> str:
|
||||
"""Normalize an label name by removing whitespace and case folding."""
|
||||
return label_name.casefold().replace(" ", "")
|
|
@ -17,6 +17,7 @@ from homeassistant.const import (
|
|||
ATTR_AREA_ID,
|
||||
ATTR_DEVICE_ID,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_LABEL_ID,
|
||||
CONF_ENTITY_ID,
|
||||
CONF_SERVICE,
|
||||
CONF_SERVICE_DATA,
|
||||
|
@ -51,6 +52,7 @@ from . import (
|
|||
config_validation as cv,
|
||||
device_registry,
|
||||
entity_registry,
|
||||
label_registry,
|
||||
template,
|
||||
translation,
|
||||
)
|
||||
|
@ -200,6 +202,7 @@ class ServiceTargetSelector:
|
|||
entity_ids: str | list | None = service_call_data.get(ATTR_ENTITY_ID)
|
||||
device_ids: str | list | None = service_call_data.get(ATTR_DEVICE_ID)
|
||||
area_ids: str | list | None = service_call_data.get(ATTR_AREA_ID)
|
||||
label_ids: str | list | None = service_call_data.get(ATTR_LABEL_ID)
|
||||
|
||||
self.entity_ids = (
|
||||
set(cv.ensure_list(entity_ids)) if _has_match(entity_ids) else set()
|
||||
|
@ -208,11 +211,16 @@ class ServiceTargetSelector:
|
|||
set(cv.ensure_list(device_ids)) if _has_match(device_ids) else set()
|
||||
)
|
||||
self.area_ids = set(cv.ensure_list(area_ids)) if _has_match(area_ids) else set()
|
||||
self.label_ids = (
|
||||
set(cv.ensure_list(label_ids)) if _has_match(label_ids) else set()
|
||||
)
|
||||
|
||||
@property
|
||||
def has_any_selector(self) -> bool:
|
||||
"""Determine if any selectors are present."""
|
||||
return bool(self.entity_ids or self.device_ids or self.area_ids)
|
||||
return bool(
|
||||
self.entity_ids or self.device_ids or self.area_ids or self.label_ids
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass(slots=True)
|
||||
|
@ -222,16 +230,19 @@ class SelectedEntities:
|
|||
# Entities that were explicitly mentioned.
|
||||
referenced: set[str] = dataclasses.field(default_factory=set)
|
||||
|
||||
# Entities that were referenced via device/area ID.
|
||||
# Entities that were referenced via device/area/label ID.
|
||||
# Should not trigger a warning when they don't exist.
|
||||
indirectly_referenced: set[str] = dataclasses.field(default_factory=set)
|
||||
|
||||
# Referenced items that could not be found.
|
||||
missing_devices: set[str] = dataclasses.field(default_factory=set)
|
||||
missing_areas: set[str] = dataclasses.field(default_factory=set)
|
||||
missing_labels: set[str] = dataclasses.field(default_factory=set)
|
||||
|
||||
# Referenced devices
|
||||
referenced_devices: set[str] = dataclasses.field(default_factory=set)
|
||||
referenced_devices_by_labels: set[str] = dataclasses.field(default_factory=set)
|
||||
referenced_devices_by_areas: set[str] = dataclasses.field(default_factory=set)
|
||||
|
||||
def log_missing(self, missing_entities: set[str]) -> None:
|
||||
"""Log about missing items."""
|
||||
|
@ -240,6 +251,7 @@ class SelectedEntities:
|
|||
("areas", self.missing_areas),
|
||||
("devices", self.missing_devices),
|
||||
("entities", missing_entities),
|
||||
("labels", self.missing_labels),
|
||||
):
|
||||
if items:
|
||||
parts.append(f"{label} {', '.join(sorted(items))}")
|
||||
|
@ -470,12 +482,13 @@ def async_extract_referenced_entity_ids(
|
|||
|
||||
selected.referenced.update(entity_ids)
|
||||
|
||||
if not selector.device_ids and not selector.area_ids:
|
||||
if not selector.device_ids and not selector.area_ids and not selector.label_ids:
|
||||
return selected
|
||||
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
area_reg = area_registry.async_get(hass)
|
||||
label_reg = label_registry.async_get(hass)
|
||||
|
||||
for device_id in selector.device_ids:
|
||||
if device_id not in dev_reg.devices:
|
||||
|
@ -485,13 +498,29 @@ def async_extract_referenced_entity_ids(
|
|||
if area_id not in area_reg.areas:
|
||||
selected.missing_areas.add(area_id)
|
||||
|
||||
for label_id in selector.label_ids:
|
||||
if label_id not in label_reg.labels:
|
||||
selected.missing_labels.add(label_id)
|
||||
|
||||
# Find devices for targeted areas
|
||||
selected.referenced_devices.update(selector.device_ids)
|
||||
for device_entry in dev_reg.devices.values():
|
||||
if device_entry.area_id in selector.area_ids:
|
||||
selected.referenced_devices.add(device_entry.id)
|
||||
selected.referenced_devices_by_areas.add(device_entry.id)
|
||||
|
||||
if not selector.area_ids and not selected.referenced_devices:
|
||||
# Find devices for targeted labels
|
||||
selected.referenced_devices.update(selector.device_ids)
|
||||
for device_entry in dev_reg.devices.values():
|
||||
if device_entry.labels.intersection(selector.label_ids):
|
||||
selected.referenced_devices.add(device_entry.id)
|
||||
selected.referenced_devices_by_labels.add(device_entry.id)
|
||||
|
||||
if (
|
||||
not selector.area_ids
|
||||
and not selector.label_ids
|
||||
and not selected.referenced_devices
|
||||
):
|
||||
return selected
|
||||
|
||||
for ent_entry in ent_reg.entities.values():
|
||||
|
@ -507,10 +536,14 @@ def async_extract_referenced_entity_ids(
|
|||
# has no explicitly set area
|
||||
or (
|
||||
not ent_entry.area_id
|
||||
and ent_entry.device_id in selected.referenced_devices
|
||||
and ent_entry.device_id in selected.referenced_devices_by_areas
|
||||
)
|
||||
# The entity's device matches a targeted device
|
||||
or ent_entry.device_id in selector.device_ids
|
||||
# The entity's label matches a targeted label
|
||||
or ent_entry.labels.intersection(selector.label_ids)
|
||||
# The entity's device matches a device referenced by an label
|
||||
or ent_entry.device_id in selected.referenced_devices_by_labels
|
||||
):
|
||||
selected.indirectly_referenced.add(ent_entry.entity_id)
|
||||
|
||||
|
|
|
@ -78,7 +78,13 @@ from homeassistant.util.json import JSON_DECODE_EXCEPTIONS, json_loads
|
|||
from homeassistant.util.read_only_dict import ReadOnlyDict
|
||||
from homeassistant.util.thread import ThreadWithException
|
||||
|
||||
from . import area_registry, device_registry, entity_registry, location as loc_helper
|
||||
from . import (
|
||||
area_registry,
|
||||
device_registry,
|
||||
entity_registry,
|
||||
label_registry,
|
||||
location as loc_helper,
|
||||
)
|
||||
from .singleton import singleton
|
||||
from .typing import TemplateVarsType
|
||||
|
||||
|
@ -1451,6 +1457,81 @@ def area_devices(hass: HomeAssistant, area_id_or_name: str) -> Iterable[str]:
|
|||
return [entry.id for entry in entries]
|
||||
|
||||
|
||||
def labels(hass: HomeAssistant, lookup_value: Any = None) -> Iterable[str | None]:
|
||||
"""Return all labels, or those from a device ID or entity ID."""
|
||||
label_reg = label_registry.async_get(hass)
|
||||
if lookup_value is None:
|
||||
return [label.label_id for label in label_reg.async_list_labels()]
|
||||
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
# Import here, not at top-level to avoid circular import
|
||||
from . import config_validation as cv # pylint: disable=import-outside-toplevel
|
||||
|
||||
try:
|
||||
cv.entity_id(lookup_value)
|
||||
except vol.Invalid:
|
||||
pass
|
||||
else:
|
||||
if entity := ent_reg.async_get(str(lookup_value)):
|
||||
return list(entity.labels)
|
||||
|
||||
# Check if this could be a device ID
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
if device := dev_reg.async_get(str(lookup_value)):
|
||||
return list(device.labels)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def label_id(hass: HomeAssistant, lookup_value: Any) -> str | None:
|
||||
"""Get the label ID from an label name."""
|
||||
label_reg = label_registry.async_get(hass)
|
||||
if label := label_reg.async_get_label_by_name(str(lookup_value)):
|
||||
return label.label_id
|
||||
return None
|
||||
|
||||
|
||||
def label_name(hass: HomeAssistant, lookup_value: str) -> str | None:
|
||||
"""Get the label name from an label id."""
|
||||
label_reg = label_registry.async_get(hass)
|
||||
if label := label_reg.async_get_label(lookup_value):
|
||||
return label.name
|
||||
return None
|
||||
|
||||
|
||||
def label_devices(hass: HomeAssistant, label_id_or_name: str) -> Iterable[str]:
|
||||
"""Return device IDs for a given label ID or name."""
|
||||
_label_id: str | None
|
||||
# if label_name returns a value, we know the input was an ID, otherwise we
|
||||
# assume it's a name, and if it's neither, we return early
|
||||
if label_name(hass, label_id_or_name) is not None:
|
||||
_label_id = label_id_or_name
|
||||
else:
|
||||
_label_id = label_id(hass, label_id_or_name)
|
||||
if _label_id is None:
|
||||
return []
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
entries = device_registry.async_entries_for_label(dev_reg, _label_id)
|
||||
return [entry.id for entry in entries]
|
||||
|
||||
|
||||
def label_entities(hass: HomeAssistant, label_id_or_name: str) -> Iterable[str]:
|
||||
"""Return entities for a given label ID or name."""
|
||||
_label_id: str | None
|
||||
# if label_name returns a value, we know the input was an ID, otherwise we
|
||||
# assume it's a name, and if it's neither, we return early
|
||||
if label_name(hass, label_id_or_name) is not None:
|
||||
_label_id = label_id_or_name
|
||||
else:
|
||||
_label_id = label_id(hass, label_id_or_name)
|
||||
if _label_id is None:
|
||||
return []
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
entries = entity_registry.async_entries_for_label(ent_reg, _label_id)
|
||||
return [entry.entity_id for entry in entries]
|
||||
|
||||
|
||||
def closest(hass, *args):
|
||||
"""Find closest entity.
|
||||
|
||||
|
@ -2603,6 +2684,21 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
|
|||
self.globals["area_devices"] = hassfunction(area_devices)
|
||||
self.filters["area_devices"] = self.globals["area_devices"]
|
||||
|
||||
self.globals["labels"] = hassfunction(labels)
|
||||
self.filters["labels"] = self.globals["labels"]
|
||||
|
||||
self.globals["label_id"] = hassfunction(label_id)
|
||||
self.filters["label_id"] = self.globals["label_id"]
|
||||
|
||||
self.globals["label_name"] = hassfunction(label_name)
|
||||
self.filters["label_name"] = self.globals["label_name"]
|
||||
|
||||
self.globals["label_devices"] = hassfunction(label_devices)
|
||||
self.filters["label_devices"] = self.globals["label_devices"]
|
||||
|
||||
self.globals["label_entities"] = hassfunction(label_entities)
|
||||
self.filters["label_entities"] = self.globals["label_entities"]
|
||||
|
||||
self.globals["integration_entities"] = hassfunction(integration_entities)
|
||||
self.filters["integration_entities"] = self.globals["integration_entities"]
|
||||
|
||||
|
@ -2636,6 +2732,8 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
|
|||
"area_name",
|
||||
"relative_time",
|
||||
"today_at",
|
||||
"label_id",
|
||||
"label_name",
|
||||
]
|
||||
hass_filters = [
|
||||
"closest",
|
||||
|
@ -2644,6 +2742,8 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
|
|||
"area_id",
|
||||
"area_name",
|
||||
"has_value",
|
||||
"label_id",
|
||||
"label_name",
|
||||
]
|
||||
hass_tests = [
|
||||
"has_value",
|
||||
|
|
|
@ -688,6 +688,7 @@ voluptuous = "vol"
|
|||
"homeassistant.helpers.device_registry" = "dr"
|
||||
"homeassistant.helpers.entity_registry" = "er"
|
||||
"homeassistant.helpers.issue_registry" = "ir"
|
||||
"homeassistant.helpers.label_registry" = "lr"
|
||||
"homeassistant.util.dt" = "dt_util"
|
||||
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
|
|
|
@ -65,6 +65,7 @@ from homeassistant.helpers import (
|
|||
event,
|
||||
intent,
|
||||
issue_registry as ir,
|
||||
label_registry as lr,
|
||||
recorder as recorder_helper,
|
||||
restore_state,
|
||||
restore_state as rs,
|
||||
|
@ -281,6 +282,7 @@ async def async_test_home_assistant(event_loop, load_registries=True):
|
|||
dr.async_load(hass),
|
||||
er.async_load(hass),
|
||||
ir.async_load(hass),
|
||||
lr.async_load(hass),
|
||||
rs.async_load(hass),
|
||||
)
|
||||
hass.data[bootstrap.DATA_REGISTRIES_LOADED] = None
|
||||
|
|
|
@ -74,6 +74,7 @@ async def test_list_entities(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "Hello World",
|
||||
"options": {},
|
||||
"original_name": None,
|
||||
|
@ -92,6 +93,7 @@ async def test_list_entities(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": None,
|
||||
"options": {},
|
||||
"original_name": None,
|
||||
|
@ -137,6 +139,7 @@ async def test_list_entities(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "Hello World",
|
||||
"options": {},
|
||||
"original_name": None,
|
||||
|
@ -234,6 +237,7 @@ async def test_list_entities_for_display(
|
|||
"ei": "test_domain.test",
|
||||
"en": "Hello World",
|
||||
"ic": "mdi:icon",
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
"tk": "translations_galore",
|
||||
},
|
||||
|
@ -242,31 +246,37 @@ async def test_list_entities_for_display(
|
|||
"di": "device123",
|
||||
"ei": "test_domain.nameless",
|
||||
"en": None,
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
},
|
||||
{
|
||||
"ai": "area52",
|
||||
"di": "device123",
|
||||
"ei": "test_domain.renamed",
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
},
|
||||
{
|
||||
"ei": "test_domain.boring",
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
},
|
||||
{
|
||||
"ei": "test_domain.hidden",
|
||||
"lb": [],
|
||||
"hb": True,
|
||||
"pl": "test_platform",
|
||||
},
|
||||
{
|
||||
"dp": 0,
|
||||
"ei": "sensor.default_precision",
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
},
|
||||
{
|
||||
"dp": 0,
|
||||
"ei": "sensor.user_precision",
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
},
|
||||
],
|
||||
|
@ -308,6 +318,7 @@ async def test_list_entities_for_display(
|
|||
"di": "device123",
|
||||
"ei": "test_domain.test",
|
||||
"en": "Hello World",
|
||||
"lb": [],
|
||||
"pl": "test_platform",
|
||||
},
|
||||
],
|
||||
|
@ -352,6 +363,7 @@ async def test_get_entity(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "Hello World",
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -385,6 +397,7 @@ async def test_get_entity(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": None,
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -443,6 +456,7 @@ async def test_get_entities(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "Hello World",
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -466,6 +480,7 @@ async def test_get_entities(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": None,
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -535,6 +550,7 @@ async def test_update_entity(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": "user", # We exchange strings over the WS API, not enums
|
||||
"icon": "icon:after update",
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "after update",
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -610,6 +626,7 @@ async def test_update_entity(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": "user", # We exchange strings over the WS API, not enums
|
||||
"icon": "icon:after update",
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "after update",
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -650,6 +667,7 @@ async def test_update_entity(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": "user", # We exchange strings over the WS API, not enums
|
||||
"icon": "icon:after update",
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "after update",
|
||||
"options": {"sensor": {"unit_of_measurement": "beard_second"}},
|
||||
"original_device_class": None,
|
||||
|
@ -702,6 +720,7 @@ async def test_update_entity_require_restart(hass: HomeAssistant, client) -> Non
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": None,
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -812,6 +831,7 @@ async def test_update_entity_no_changes(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": "name of entity",
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
@ -901,6 +921,7 @@ async def test_update_entity_id(hass: HomeAssistant, client) -> None:
|
|||
"hidden_by": None,
|
||||
"icon": None,
|
||||
"id": ANY,
|
||||
"labels": [],
|
||||
"name": None,
|
||||
"options": {},
|
||||
"original_device_class": None,
|
||||
|
|
251
tests/components/config/test_label_registry.py
Normal file
251
tests/components/config/test_label_registry.py
Normal file
|
@ -0,0 +1,251 @@
|
|||
"""Test label registry API."""
|
||||
from collections.abc import Awaitable, Callable, Generator
|
||||
from typing import Any
|
||||
|
||||
from aiohttp import ClientWebSocketResponse
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.config import label_registry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import label_registry as lr
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def client_fixture(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: Callable[
|
||||
[HomeAssistant], Awaitable[Generator[ClientWebSocketResponse, Any, Any]]
|
||||
],
|
||||
) -> Generator[ClientWebSocketResponse, None, None]:
|
||||
"""Fixture that can interact with the config manager API."""
|
||||
hass.loop.run_until_complete(label_registry.async_setup(hass))
|
||||
return hass.loop.run_until_complete(hass_ws_client(hass))
|
||||
|
||||
|
||||
async def test_list_labels(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test list entries."""
|
||||
label_registry.async_create("mock 1")
|
||||
label_registry.async_create(
|
||||
name="mock 2",
|
||||
color="#00FF00",
|
||||
icon="mdi:two",
|
||||
description="This is the second label",
|
||||
)
|
||||
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
await client.send_json({"id": 1, "type": "config/label_registry/list"})
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert len(msg["result"]) == len(label_registry.labels)
|
||||
assert msg["result"][0] == {
|
||||
"color": None,
|
||||
"description": None,
|
||||
"icon": None,
|
||||
"label_id": "mock_1",
|
||||
"name": "mock 1",
|
||||
}
|
||||
assert msg["result"][1] == {
|
||||
"color": "#00FF00",
|
||||
"description": "This is the second label",
|
||||
"icon": "mdi:two",
|
||||
"label_id": "mock_2",
|
||||
"name": "mock 2",
|
||||
}
|
||||
|
||||
|
||||
async def test_create_label(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test create entry."""
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 1,
|
||||
"name": "MOCK",
|
||||
"type": "config/label_registry/create",
|
||||
}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
assert msg["result"] == {
|
||||
"color": None,
|
||||
"description": None,
|
||||
"icon": None,
|
||||
"label_id": "mock",
|
||||
"name": "MOCK",
|
||||
}
|
||||
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 2,
|
||||
"name": "MOCKERY",
|
||||
"type": "config/label_registry/create",
|
||||
"color": "#00FF00",
|
||||
"description": "This is the second label",
|
||||
"icon": "mdi:two",
|
||||
}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert len(label_registry.labels) == 2
|
||||
assert msg["result"] == {
|
||||
"color": "#00FF00",
|
||||
"description": "This is the second label",
|
||||
"icon": "mdi:two",
|
||||
"label_id": "mockery",
|
||||
"name": "MOCKERY",
|
||||
}
|
||||
|
||||
|
||||
async def test_create_label_with_name_already_in_use(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test create entry that should fail."""
|
||||
label_registry.async_create("mock")
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
await client.send_json(
|
||||
{"id": 1, "name": "mock", "type": "config/label_registry/create"}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert not msg["success"]
|
||||
assert msg["error"]["code"] == "invalid_info"
|
||||
assert msg["error"]["message"] == "The name mock (mock) is already in use"
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
|
||||
async def test_delete_label(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test delete entry."""
|
||||
label = label_registry.async_create("mock")
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
await client.send_json(
|
||||
{"id": 1, "label_id": label.label_id, "type": "config/label_registry/delete"}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert msg["success"]
|
||||
assert not label_registry.labels
|
||||
|
||||
|
||||
async def test_delete_non_existing_label(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test delete entry that should fail."""
|
||||
label_registry.async_create("mock")
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
await client.send_json(
|
||||
{"id": 1, "label_id": "omg_puppies", "type": "config/label_registry/delete"}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert not msg["success"]
|
||||
assert msg["error"]["code"] == "invalid_info"
|
||||
assert msg["error"]["message"] == "Label ID doesn't exist"
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
|
||||
async def test_update_label(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test update entry."""
|
||||
label = label_registry.async_create("mock")
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 1,
|
||||
"label_id": label.label_id,
|
||||
"name": "UPDATED",
|
||||
"icon": "mdi:test",
|
||||
"color": "#00FF00",
|
||||
"description": "This is an label description",
|
||||
"type": "config/label_registry/update",
|
||||
}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
assert msg["result"] == {
|
||||
"color": "#00FF00",
|
||||
"description": "This is an label description",
|
||||
"icon": "mdi:test",
|
||||
"label_id": "mock",
|
||||
"name": "UPDATED",
|
||||
}
|
||||
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 2,
|
||||
"label_id": label.label_id,
|
||||
"name": "UPDATED AGAIN",
|
||||
"icon": None,
|
||||
"color": None,
|
||||
"description": None,
|
||||
"type": "config/label_registry/update",
|
||||
}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
assert msg["result"] == {
|
||||
"color": None,
|
||||
"description": None,
|
||||
"icon": None,
|
||||
"label_id": "mock",
|
||||
"name": "UPDATED AGAIN",
|
||||
}
|
||||
|
||||
|
||||
async def test_update_with_name_already_in_use(
|
||||
hass: HomeAssistant,
|
||||
client: ClientWebSocketResponse,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test update entry."""
|
||||
label = label_registry.async_create("mock 1")
|
||||
label_registry.async_create("mock 2")
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 1,
|
||||
"label_id": label.label_id,
|
||||
"name": "mock 2",
|
||||
"type": "config/label_registry/update",
|
||||
}
|
||||
)
|
||||
|
||||
msg = await client.receive_json()
|
||||
|
||||
assert not msg["success"]
|
||||
assert msg["error"]["code"] == "invalid_info"
|
||||
assert msg["error"]["message"] == "The name mock 2 (mock2) is already in use"
|
||||
assert len(label_registry.labels) == 2
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -73,6 +75,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -116,6 +120,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -91,6 +93,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -81,6 +83,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -129,6 +133,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -177,6 +183,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -87,6 +89,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -138,6 +142,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -72,6 +72,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -159,6 +161,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -246,6 +250,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -333,6 +339,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'devolo',
|
||||
'model': 'dLAN pro 1200+ WiFi ac',
|
||||
'name': 'Mock Title',
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -76,6 +78,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -120,6 +124,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -115,6 +115,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -159,6 +161,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -65,6 +67,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
@ -105,6 +109,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -141,6 +147,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
|
|
@ -61,6 +61,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -97,6 +99,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light',
|
||||
'name': 'Frenck',
|
||||
|
@ -171,6 +175,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -207,6 +213,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light',
|
||||
'name': 'Frenck',
|
||||
|
@ -281,6 +289,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -317,6 +327,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light',
|
||||
'name': 'Frenck',
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
|
@ -72,6 +74,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
@ -116,6 +120,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
|
@ -158,6 +164,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
@ -202,6 +210,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
|
@ -244,6 +254,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
@ -288,6 +300,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
|
@ -327,6 +341,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
@ -371,6 +387,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
|
@ -413,6 +431,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -65,6 +67,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
@ -105,6 +109,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -141,6 +147,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Elgato',
|
||||
'model': 'Elgato Key Light Mini',
|
||||
'name': 'Frenck',
|
||||
|
|
|
@ -487,6 +487,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -512,6 +514,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'EnergyZero',
|
||||
'model': None,
|
||||
'name': 'Energy market price',
|
||||
|
@ -556,6 +560,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -581,6 +587,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'EnergyZero',
|
||||
'model': None,
|
||||
'name': 'Energy market price',
|
||||
|
@ -622,6 +630,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -647,6 +657,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'EnergyZero',
|
||||
'model': None,
|
||||
'name': 'Energy market price',
|
||||
|
@ -689,6 +701,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -714,6 +728,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'EnergyZero',
|
||||
'model': None,
|
||||
'name': 'Energy market price',
|
||||
|
@ -755,6 +771,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -780,6 +798,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'EnergyZero',
|
||||
'model': None,
|
||||
'name': 'Energy market price',
|
||||
|
@ -824,6 +844,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -849,6 +871,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'EnergyZero',
|
||||
'model': None,
|
||||
'name': 'Gas market price',
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': 'Mock Model',
|
||||
'name': 'Mock Title',
|
||||
|
|
|
@ -102,6 +102,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -78,6 +78,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -107,6 +109,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -136,6 +140,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -165,6 +171,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -194,6 +202,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -65,6 +67,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'HomeWizard',
|
||||
'model': 'HWE-P1',
|
||||
'name': 'Device',
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -74,6 +76,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'HomeWizard',
|
||||
'model': 'HWE-SKT',
|
||||
'name': 'Device',
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -179,6 +179,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -215,6 +217,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'HomeWizard',
|
||||
'model': 'HWE-SKT',
|
||||
'name': 'Device',
|
||||
|
@ -254,6 +258,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -290,6 +296,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'HomeWizard',
|
||||
'model': 'HWE-SKT',
|
||||
'name': 'Device',
|
||||
|
@ -329,6 +337,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -365,6 +375,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'HomeWizard',
|
||||
'model': 'HWE-SKT',
|
||||
'name': 'Device',
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2405',
|
||||
'name': '05.111111111111',
|
||||
|
@ -68,6 +70,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18S20',
|
||||
'name': '10.111111111111',
|
||||
|
@ -106,6 +110,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2406',
|
||||
'name': '12.111111111111',
|
||||
|
@ -135,6 +141,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -164,6 +172,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -226,6 +236,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2423',
|
||||
'name': '1D.111111111111',
|
||||
|
@ -264,6 +276,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2409',
|
||||
'name': '1F.111111111111',
|
||||
|
@ -290,6 +304,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2423',
|
||||
'name': '1D.111111111111',
|
||||
|
@ -328,6 +344,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS1822',
|
||||
'name': '22.111111111111',
|
||||
|
@ -366,6 +384,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2438',
|
||||
'name': '26.111111111111',
|
||||
|
@ -404,6 +424,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.111111111111',
|
||||
|
@ -442,6 +464,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.222222222222',
|
||||
|
@ -480,6 +504,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.222222222223',
|
||||
|
@ -518,6 +544,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2408',
|
||||
'name': '29.111111111111',
|
||||
|
@ -547,6 +575,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -576,6 +606,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -605,6 +637,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -634,6 +668,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -663,6 +699,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -692,6 +730,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -721,6 +761,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -750,6 +792,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -884,6 +928,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2760',
|
||||
'name': '30.111111111111',
|
||||
|
@ -922,6 +968,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2413',
|
||||
'name': '3A.111111111111',
|
||||
|
@ -951,6 +999,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -980,6 +1030,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1042,6 +1094,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS1825',
|
||||
'name': '3B.111111111111',
|
||||
|
@ -1080,6 +1134,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS28EA00',
|
||||
'name': '42.111111111111',
|
||||
|
@ -1118,6 +1174,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Embedded Data Systems',
|
||||
'model': 'EDS0068',
|
||||
'name': '7E.111111111111',
|
||||
|
@ -1156,6 +1214,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Embedded Data Systems',
|
||||
'model': 'EDS0066',
|
||||
'name': '7E.222222222222',
|
||||
|
@ -1194,6 +1254,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HobbyBoards_EF',
|
||||
'name': 'EF.111111111111',
|
||||
|
@ -1232,6 +1294,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HB_MOISTURE_METER',
|
||||
'name': 'EF.111111111112',
|
||||
|
@ -1270,6 +1334,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HB_HUB',
|
||||
'name': 'EF.111111111113',
|
||||
|
@ -1299,6 +1365,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1328,6 +1396,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1357,6 +1427,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1386,6 +1458,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2405',
|
||||
'name': '05.111111111111',
|
||||
|
@ -68,6 +70,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18S20',
|
||||
'name': '10.111111111111',
|
||||
|
@ -99,6 +103,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -152,6 +158,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2406',
|
||||
'name': '12.111111111111',
|
||||
|
@ -183,6 +191,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -214,6 +224,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -282,6 +294,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2423',
|
||||
'name': '1D.111111111111',
|
||||
|
@ -313,6 +327,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -344,6 +360,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -410,6 +428,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2409',
|
||||
'name': '1F.111111111111',
|
||||
|
@ -436,6 +456,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2423',
|
||||
'name': '1D.111111111111',
|
||||
|
@ -467,6 +489,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -498,6 +522,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -564,6 +590,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS1822',
|
||||
'name': '22.111111111111',
|
||||
|
@ -595,6 +623,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -648,6 +678,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2438',
|
||||
'name': '26.111111111111',
|
||||
|
@ -679,6 +711,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -710,6 +744,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -741,6 +777,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -772,6 +810,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -803,6 +843,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -834,6 +876,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -865,6 +909,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -896,6 +942,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -927,6 +975,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -958,6 +1008,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -989,6 +1041,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1192,6 +1246,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.111111111111',
|
||||
|
@ -1223,6 +1279,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1276,6 +1334,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.222222222222',
|
||||
|
@ -1307,6 +1367,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1360,6 +1422,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.222222222223',
|
||||
|
@ -1391,6 +1455,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1444,6 +1510,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2408',
|
||||
'name': '29.111111111111',
|
||||
|
@ -1482,6 +1550,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2760',
|
||||
'name': '30.111111111111',
|
||||
|
@ -1513,6 +1583,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1544,6 +1616,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1575,6 +1649,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1606,6 +1682,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1704,6 +1782,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2413',
|
||||
'name': '3A.111111111111',
|
||||
|
@ -1742,6 +1822,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS1825',
|
||||
'name': '3B.111111111111',
|
||||
|
@ -1773,6 +1855,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1826,6 +1910,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS28EA00',
|
||||
'name': '42.111111111111',
|
||||
|
@ -1857,6 +1943,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1910,6 +1998,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Embedded Data Systems',
|
||||
'model': 'EDS0068',
|
||||
'name': '7E.111111111111',
|
||||
|
@ -1941,6 +2031,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1972,6 +2064,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2003,6 +2097,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2034,6 +2130,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2132,6 +2230,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Embedded Data Systems',
|
||||
'model': 'EDS0066',
|
||||
'name': '7E.222222222222',
|
||||
|
@ -2163,6 +2263,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2194,6 +2296,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2262,6 +2366,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HobbyBoards_EF',
|
||||
'name': 'EF.111111111111',
|
||||
|
@ -2293,6 +2399,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2324,6 +2432,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2355,6 +2465,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2438,6 +2550,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HB_MOISTURE_METER',
|
||||
'name': 'EF.111111111112',
|
||||
|
@ -2469,6 +2583,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2500,6 +2616,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2531,6 +2649,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2562,6 +2682,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2660,6 +2782,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HB_HUB',
|
||||
'name': 'EF.111111111113',
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2405',
|
||||
'name': '05.111111111111',
|
||||
|
@ -59,6 +61,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -109,6 +113,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18S20',
|
||||
'name': '10.111111111111',
|
||||
|
@ -147,6 +153,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2406',
|
||||
'name': '12.111111111111',
|
||||
|
@ -176,6 +184,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -205,6 +215,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -234,6 +246,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -263,6 +277,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -349,6 +365,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2423',
|
||||
'name': '1D.111111111111',
|
||||
|
@ -387,6 +405,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2409',
|
||||
'name': '1F.111111111111',
|
||||
|
@ -413,6 +433,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2423',
|
||||
'name': '1D.111111111111',
|
||||
|
@ -451,6 +473,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS1822',
|
||||
'name': '22.111111111111',
|
||||
|
@ -489,6 +513,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2438',
|
||||
'name': '26.111111111111',
|
||||
|
@ -518,6 +544,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -568,6 +596,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.111111111111',
|
||||
|
@ -606,6 +636,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.222222222222',
|
||||
|
@ -644,6 +676,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS18B20',
|
||||
'name': '28.222222222223',
|
||||
|
@ -682,6 +716,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2408',
|
||||
'name': '29.111111111111',
|
||||
|
@ -711,6 +747,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -740,6 +778,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -769,6 +809,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -798,6 +840,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -827,6 +871,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -856,6 +902,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -885,6 +933,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -914,6 +964,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -943,6 +995,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -972,6 +1026,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1001,6 +1057,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1030,6 +1088,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1059,6 +1119,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1088,6 +1150,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1117,6 +1181,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1146,6 +1212,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1376,6 +1444,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2760',
|
||||
'name': '30.111111111111',
|
||||
|
@ -1414,6 +1484,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS2413',
|
||||
'name': '3A.111111111111',
|
||||
|
@ -1443,6 +1515,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1472,6 +1546,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1534,6 +1610,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS1825',
|
||||
'name': '3B.111111111111',
|
||||
|
@ -1572,6 +1650,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Maxim Integrated',
|
||||
'model': 'DS28EA00',
|
||||
'name': '42.111111111111',
|
||||
|
@ -1610,6 +1690,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Embedded Data Systems',
|
||||
'model': 'EDS0068',
|
||||
'name': '7E.111111111111',
|
||||
|
@ -1648,6 +1730,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Embedded Data Systems',
|
||||
'model': 'EDS0066',
|
||||
'name': '7E.222222222222',
|
||||
|
@ -1686,6 +1770,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HobbyBoards_EF',
|
||||
'name': 'EF.111111111111',
|
||||
|
@ -1724,6 +1810,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HB_MOISTURE_METER',
|
||||
'name': 'EF.111111111112',
|
||||
|
@ -1753,6 +1841,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1782,6 +1872,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1811,6 +1903,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1840,6 +1934,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1869,6 +1965,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1898,6 +1996,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1927,6 +2027,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1956,6 +2058,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2090,6 +2194,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Hobby Boards',
|
||||
'model': 'HB_HUB',
|
||||
'name': 'EF.111111111113',
|
||||
|
@ -2119,6 +2225,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2148,6 +2256,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2177,6 +2287,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2206,6 +2318,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -47,6 +49,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -76,6 +80,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -105,6 +111,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -134,6 +142,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -163,6 +173,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -192,6 +204,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -296,6 +310,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -325,6 +341,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -354,6 +372,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -383,6 +403,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -412,6 +434,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -441,6 +465,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -470,6 +496,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -499,6 +527,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -528,6 +558,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -654,6 +686,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -683,6 +717,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -712,6 +748,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -741,6 +779,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -812,6 +852,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -841,6 +883,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -870,6 +914,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -899,6 +945,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -928,6 +976,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -957,6 +1007,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -986,6 +1038,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1015,6 +1069,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1044,6 +1100,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1073,6 +1131,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1210,6 +1270,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -1239,6 +1301,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1268,6 +1332,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1297,6 +1363,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1326,6 +1394,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1355,6 +1425,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1384,6 +1456,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1488,6 +1562,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -1517,6 +1593,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1546,6 +1624,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1575,6 +1655,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1604,6 +1686,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1633,6 +1717,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1662,6 +1748,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1691,6 +1779,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1720,6 +1810,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1846,6 +1938,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -1875,6 +1969,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1904,6 +2000,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1933,6 +2031,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2004,6 +2104,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -2033,6 +2135,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2062,6 +2166,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2091,6 +2197,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2120,6 +2228,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2149,6 +2259,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2178,6 +2290,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2207,6 +2321,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2236,6 +2352,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2265,6 +2383,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -47,6 +49,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -96,6 +100,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -125,6 +131,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -154,6 +162,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -183,6 +193,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -254,6 +266,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -283,6 +297,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -312,6 +328,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -341,6 +359,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -412,6 +432,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -441,6 +463,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -470,6 +494,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -499,6 +525,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -570,6 +598,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -599,6 +629,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -648,6 +680,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -677,6 +711,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -706,6 +742,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -735,6 +773,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -806,6 +846,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -835,6 +877,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -864,6 +908,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -893,6 +939,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -964,6 +1012,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -993,6 +1043,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1022,6 +1074,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1051,6 +1105,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -47,6 +49,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -97,6 +101,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -126,6 +132,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -176,6 +184,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -214,6 +224,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -243,6 +255,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -293,6 +307,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -322,6 +338,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -375,6 +393,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -404,6 +424,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -457,6 +479,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -495,6 +519,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -524,6 +550,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -56,6 +58,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -91,6 +95,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -145,6 +151,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -180,6 +188,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -234,6 +244,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -269,6 +281,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -323,6 +337,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -361,6 +377,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -396,6 +414,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -450,6 +470,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -485,6 +507,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -539,6 +563,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -574,6 +600,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -49,6 +51,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -80,6 +84,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -111,6 +117,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -140,6 +148,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -169,6 +179,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -198,6 +210,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -309,6 +323,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -340,6 +356,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -380,6 +398,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -411,6 +431,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -442,6 +464,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -478,6 +502,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -509,6 +535,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -540,6 +568,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -571,6 +601,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -600,6 +632,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -631,6 +665,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -662,6 +698,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -693,6 +731,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -722,6 +762,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -751,6 +793,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -780,6 +824,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1022,6 +1068,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -1053,6 +1101,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1093,6 +1143,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1124,6 +1176,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1155,6 +1209,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1191,6 +1247,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1222,6 +1280,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1253,6 +1313,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1284,6 +1346,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1313,6 +1377,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1344,6 +1410,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1375,6 +1443,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1404,6 +1474,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1433,6 +1505,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1462,6 +1536,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1491,6 +1567,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1729,6 +1807,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -1760,6 +1840,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1800,6 +1882,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1831,6 +1915,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1862,6 +1948,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1898,6 +1986,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1929,6 +2019,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1960,6 +2052,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -1991,6 +2085,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2020,6 +2116,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2051,6 +2149,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2082,6 +2182,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2111,6 +2213,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2140,6 +2244,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2169,6 +2275,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2198,6 +2306,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2227,6 +2337,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2476,6 +2588,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -2507,6 +2621,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2538,6 +2654,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2569,6 +2687,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2598,6 +2718,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2627,6 +2749,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2656,6 +2780,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2767,6 +2893,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Captur ii',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -2798,6 +2926,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2838,6 +2968,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2869,6 +3001,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2900,6 +3034,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2936,6 +3072,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2967,6 +3105,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -2998,6 +3138,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3029,6 +3171,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3058,6 +3202,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3089,6 +3235,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3120,6 +3268,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3151,6 +3301,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3180,6 +3332,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3209,6 +3363,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3238,6 +3394,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3480,6 +3638,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -3511,6 +3671,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3551,6 +3713,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3582,6 +3746,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3613,6 +3779,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3649,6 +3817,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3680,6 +3850,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3711,6 +3883,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3742,6 +3916,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3771,6 +3947,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3802,6 +3980,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3833,6 +4013,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3862,6 +4044,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3891,6 +4075,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3920,6 +4106,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -3949,6 +4137,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4187,6 +4377,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Renault',
|
||||
'model': 'Zoe',
|
||||
'name': 'REG-NUMBER',
|
||||
|
@ -4218,6 +4410,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4258,6 +4452,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4289,6 +4485,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4320,6 +4518,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4356,6 +4556,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4387,6 +4589,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4418,6 +4622,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4449,6 +4655,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4478,6 +4686,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4509,6 +4719,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4540,6 +4752,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4569,6 +4783,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4598,6 +4814,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4627,6 +4845,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4656,6 +4876,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -4685,6 +4907,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': 'NB6VAC-FXC-r0',
|
||||
'name': 'SFR Box',
|
||||
|
@ -47,6 +49,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -76,6 +80,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -136,6 +142,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': 'NB6VAC-FXC-r0',
|
||||
'name': 'SFR Box',
|
||||
|
@ -165,6 +173,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -194,6 +204,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': 'NB6VAC-FXC-r0',
|
||||
'name': 'SFR Box',
|
||||
|
@ -47,6 +49,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': 'NB6VAC-FXC-r0',
|
||||
'name': 'SFR Box',
|
||||
|
@ -54,6 +56,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -83,6 +87,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -112,6 +118,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -149,6 +157,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -178,6 +188,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -207,6 +219,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -236,6 +250,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -267,6 +283,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -298,6 +316,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -329,6 +349,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -360,6 +382,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -391,6 +415,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -422,6 +448,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -460,6 +488,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -502,6 +532,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -73,6 +75,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -117,6 +121,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -161,6 +167,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -205,6 +213,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -249,6 +259,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -293,6 +305,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -337,6 +351,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -61,6 +61,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -93,6 +95,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Twente Milieu',
|
||||
'model': None,
|
||||
'name': 'Twente Milieu',
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -62,6 +64,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Twente Milieu',
|
||||
'model': None,
|
||||
'name': 'Twente Milieu',
|
||||
|
@ -103,6 +107,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -135,6 +141,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Twente Milieu',
|
||||
'model': None,
|
||||
'name': 'Twente Milieu',
|
||||
|
@ -176,6 +184,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -208,6 +218,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Twente Milieu',
|
||||
'model': None,
|
||||
'name': 'Twente Milieu',
|
||||
|
@ -249,6 +261,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -281,6 +295,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Twente Milieu',
|
||||
'model': None,
|
||||
'name': 'Twente Milieu',
|
||||
|
@ -322,6 +338,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -354,6 +372,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Twente Milieu',
|
||||
'model': None,
|
||||
'name': 'Twente Milieu',
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -54,6 +56,8 @@
|
|||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'Uptime',
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LV-PUR131S',
|
||||
'name': 'Air Purifier 131s',
|
||||
|
@ -52,6 +54,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -103,6 +107,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'Core200S',
|
||||
'name': 'Air Purifier 200s',
|
||||
|
@ -136,6 +142,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -193,6 +201,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C401S-WJP',
|
||||
'name': 'Air Purifier 400s',
|
||||
|
@ -227,6 +237,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -285,6 +297,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C601S-WUS',
|
||||
'name': 'Air Purifier 600s',
|
||||
|
@ -319,6 +333,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -377,6 +393,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100',
|
||||
'name': 'Dimmable Light',
|
||||
|
@ -411,6 +429,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWD16',
|
||||
'name': 'Dimmer Switch',
|
||||
|
@ -461,6 +481,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'wifi-switch-1.3',
|
||||
'name': 'Outlet',
|
||||
|
@ -495,6 +517,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100CW',
|
||||
'name': 'Temperature Light',
|
||||
|
@ -529,6 +553,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWL01',
|
||||
'name': 'Wall Switch',
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LV-PUR131S',
|
||||
'name': 'Air Purifier 131s',
|
||||
|
@ -52,6 +54,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'Core200S',
|
||||
'name': 'Air Purifier 200s',
|
||||
|
@ -86,6 +90,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C401S-WJP',
|
||||
'name': 'Air Purifier 400s',
|
||||
|
@ -120,6 +126,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C601S-WUS',
|
||||
'name': 'Air Purifier 600s',
|
||||
|
@ -154,6 +162,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100',
|
||||
'name': 'Dimmable Light',
|
||||
|
@ -187,6 +197,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -237,6 +249,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWD16',
|
||||
'name': 'Dimmer Switch',
|
||||
|
@ -270,6 +284,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -338,6 +354,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'wifi-switch-1.3',
|
||||
'name': 'Outlet',
|
||||
|
@ -372,6 +390,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100CW',
|
||||
'name': 'Temperature Light',
|
||||
|
@ -409,6 +429,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -470,6 +492,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWL01',
|
||||
'name': 'Wall Switch',
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LV-PUR131S',
|
||||
'name': 'Air Purifier 131s',
|
||||
|
@ -49,6 +51,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -78,6 +82,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -138,6 +144,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'Core200S',
|
||||
'name': 'Air Purifier 200s',
|
||||
|
@ -169,6 +177,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -217,6 +227,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C401S-WJP',
|
||||
'name': 'Air Purifier 400s',
|
||||
|
@ -248,6 +260,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -277,6 +291,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -308,6 +324,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -383,6 +401,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C601S-WUS',
|
||||
'name': 'Air Purifier 600s',
|
||||
|
@ -414,6 +434,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -443,6 +465,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -474,6 +498,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -549,6 +575,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100',
|
||||
'name': 'Dimmable Light',
|
||||
|
@ -583,6 +611,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWD16',
|
||||
'name': 'Dimmer Switch',
|
||||
|
@ -633,6 +663,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'wifi-switch-1.3',
|
||||
'name': 'Outlet',
|
||||
|
@ -664,6 +696,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -695,6 +729,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -726,6 +762,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -757,6 +795,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -788,6 +828,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -819,6 +861,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -943,6 +987,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100CW',
|
||||
'name': 'Temperature Light',
|
||||
|
@ -977,6 +1023,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWL01',
|
||||
'name': 'Wall Switch',
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LV-PUR131S',
|
||||
'name': 'Air Purifier 131s',
|
||||
|
@ -52,6 +54,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'Core200S',
|
||||
'name': 'Air Purifier 200s',
|
||||
|
@ -86,6 +90,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C401S-WJP',
|
||||
'name': 'Air Purifier 400s',
|
||||
|
@ -120,6 +126,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'LAP-C601S-WUS',
|
||||
'name': 'Air Purifier 600s',
|
||||
|
@ -154,6 +162,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100',
|
||||
'name': 'Dimmable Light',
|
||||
|
@ -188,6 +198,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWD16',
|
||||
'name': 'Dimmer Switch',
|
||||
|
@ -238,6 +250,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'wifi-switch-1.3',
|
||||
'name': 'Outlet',
|
||||
|
@ -267,6 +281,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -313,6 +329,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESL100CW',
|
||||
'name': 'Temperature Light',
|
||||
|
@ -347,6 +365,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'VeSync',
|
||||
'model': 'ESWL01',
|
||||
'name': 'Wall Switch',
|
||||
|
@ -376,6 +396,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -61,6 +63,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -101,6 +105,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -133,6 +139,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -178,6 +186,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -210,6 +220,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -250,6 +262,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -282,6 +296,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -322,6 +338,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -354,6 +372,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -394,6 +414,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -426,6 +448,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -466,6 +490,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -498,6 +524,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -538,6 +566,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -570,6 +600,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -610,6 +642,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -642,6 +676,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'name': 'home-assistant.io',
|
||||
|
@ -682,6 +718,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -65,6 +67,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -65,6 +67,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -73,6 +75,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
@ -121,6 +125,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -157,6 +163,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -75,6 +77,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
@ -219,6 +223,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -255,6 +261,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
@ -303,6 +311,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -339,6 +349,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGBW Light',
|
||||
|
@ -387,6 +399,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -423,6 +437,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGBW Light',
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -67,6 +69,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
@ -106,6 +110,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -142,6 +148,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
@ -182,6 +190,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -218,6 +228,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
@ -258,6 +270,8 @@
|
|||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
|
@ -294,6 +308,8 @@
|
|||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'WLED',
|
||||
'model': 'DIY light',
|
||||
'name': 'WLED RGB Light',
|
||||
|
|
|
@ -56,6 +56,7 @@ from homeassistant.helpers import (
|
|||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
issue_registry as ir,
|
||||
label_registry as lr,
|
||||
recorder as recorder_helper,
|
||||
)
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
@ -1614,6 +1615,12 @@ def issue_registry(hass: HomeAssistant) -> ir.IssueRegistry:
|
|||
return ir.async_get(hass)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def label_registry(hass: HomeAssistant) -> lr.LabelRegistry:
|
||||
"""Return the label registry from the current hass instance."""
|
||||
return lr.async_get(hass)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def snapshot(snapshot: SnapshotAssertion) -> SnapshotAssertion:
|
||||
"""Return snapshot assertion fixture with the Home Assistant extension."""
|
||||
|
|
|
@ -204,6 +204,7 @@ async def test_loading_from_storage(
|
|||
"hw_version": "hw_version",
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"labels": {"label1", "label2"},
|
||||
"manufacturer": "manufacturer",
|
||||
"model": "model",
|
||||
"name_by_user": "Test Friendly Name",
|
||||
|
@ -247,6 +248,7 @@ async def test_loading_from_storage(
|
|||
hw_version="hw_version",
|
||||
id="abcdefghijklm",
|
||||
identifiers={("serial", "123456ABCDEF")},
|
||||
labels={"label1", "label2"},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
name_by_user="Test Friendly Name",
|
||||
|
@ -282,12 +284,12 @@ async def test_loading_from_storage(
|
|||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
async def test_migration_1_1_to_1_4(
|
||||
async def test_migration_1_1_to_1_5(
|
||||
hass: HomeAssistant,
|
||||
hass_storage: dict[str, Any],
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test migration from version 1.1 to 1.4."""
|
||||
"""Test migration from version 1.1 to 1.5."""
|
||||
hass_storage[dr.STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"minor_version": 1,
|
||||
|
@ -371,6 +373,7 @@ async def test_migration_1_1_to_1_4(
|
|||
"hw_version": None,
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"labels": [],
|
||||
"manufacturer": "manufacturer",
|
||||
"model": "model",
|
||||
"name": "name",
|
||||
|
@ -389,6 +392,7 @@ async def test_migration_1_1_to_1_4(
|
|||
"hw_version": None,
|
||||
"id": "invalid-entry-type",
|
||||
"identifiers": [["serial", "mock-id-invalid-entry"]],
|
||||
"labels": [],
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name_by_user": None,
|
||||
|
@ -412,12 +416,12 @@ async def test_migration_1_1_to_1_4(
|
|||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
async def test_migration_1_2_to_1_4(
|
||||
async def test_migration_1_2_to_1_5(
|
||||
hass: HomeAssistant,
|
||||
hass_storage: dict[str, Any],
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test migration from version 1.2 to 1.3."""
|
||||
"""Test migration from version 1.2 to 1.5."""
|
||||
hass_storage[dr.STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"minor_version": 2,
|
||||
|
@ -500,6 +504,7 @@ async def test_migration_1_2_to_1_4(
|
|||
"hw_version": None,
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"labels": [],
|
||||
"manufacturer": "manufacturer",
|
||||
"model": "model",
|
||||
"name": "name",
|
||||
|
@ -518,6 +523,7 @@ async def test_migration_1_2_to_1_4(
|
|||
"hw_version": None,
|
||||
"id": "invalid-entry-type",
|
||||
"identifiers": [["serial", "mock-id-invalid-entry"]],
|
||||
"labels": [],
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name_by_user": None,
|
||||
|
@ -533,12 +539,12 @@ async def test_migration_1_2_to_1_4(
|
|||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
async def test_migration_1_3_to_1_4(
|
||||
async def test_migration_1_3_to_1_5(
|
||||
hass: HomeAssistant,
|
||||
hass_storage: dict[str, Any],
|
||||
mock_config_entry: MockConfigEntry,
|
||||
):
|
||||
"""Test migration from version 1.3 to 1.4."""
|
||||
"""Test migration from version 1.3 to 1.5."""
|
||||
hass_storage[dr.STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"minor_version": 3,
|
||||
|
@ -623,6 +629,7 @@ async def test_migration_1_3_to_1_4(
|
|||
"hw_version": "hw_version",
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"labels": [],
|
||||
"manufacturer": "manufacturer",
|
||||
"model": "model",
|
||||
"name": "name",
|
||||
|
@ -641,6 +648,134 @@ async def test_migration_1_3_to_1_4(
|
|||
"hw_version": None,
|
||||
"id": "invalid-entry-type",
|
||||
"identifiers": [["serial", "mock-id-invalid-entry"]],
|
||||
"labels": [],
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name_by_user": None,
|
||||
"name": None,
|
||||
"serial_number": None,
|
||||
"sw_version": None,
|
||||
"via_device_id": None,
|
||||
},
|
||||
],
|
||||
"deleted_devices": [],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
async def test_migration_1_4_to_1_5(
|
||||
hass: HomeAssistant,
|
||||
hass_storage: dict[str, Any],
|
||||
mock_config_entry: MockConfigEntry,
|
||||
):
|
||||
"""Test migration from version 1.4 to 1.5."""
|
||||
hass_storage[dr.STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"minor_version": 3,
|
||||
"key": dr.STORAGE_KEY,
|
||||
"data": {
|
||||
"devices": [
|
||||
{
|
||||
"area_id": None,
|
||||
"config_entries": [mock_config_entry.entry_id],
|
||||
"configuration_url": None,
|
||||
"connections": [["Zigbee", "01.23.45.67.89"]],
|
||||
"disabled_by": None,
|
||||
"entry_type": "service",
|
||||
"hw_version": "hw_version",
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"manufacturer": "manufacturer",
|
||||
"model": "model",
|
||||
"name": "name",
|
||||
"name_by_user": None,
|
||||
"serial_number": None,
|
||||
"sw_version": "version",
|
||||
"via_device_id": None,
|
||||
},
|
||||
{
|
||||
"area_id": None,
|
||||
"config_entries": [None],
|
||||
"configuration_url": None,
|
||||
"connections": [],
|
||||
"disabled_by": None,
|
||||
"entry_type": None,
|
||||
"hw_version": None,
|
||||
"id": "invalid-entry-type",
|
||||
"identifiers": [["serial", "mock-id-invalid-entry"]],
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name_by_user": None,
|
||||
"name": None,
|
||||
"serial_number": None,
|
||||
"sw_version": None,
|
||||
"via_device_id": None,
|
||||
},
|
||||
],
|
||||
"deleted_devices": [],
|
||||
},
|
||||
}
|
||||
|
||||
await dr.async_load(hass)
|
||||
registry = dr.async_get(hass)
|
||||
|
||||
# Test data was loaded
|
||||
entry = registry.async_get_or_create(
|
||||
config_entry_id=mock_config_entry.entry_id,
|
||||
connections={("Zigbee", "01.23.45.67.89")},
|
||||
identifiers={("serial", "123456ABCDEF")},
|
||||
)
|
||||
assert entry.id == "abcdefghijklm"
|
||||
|
||||
# Update to trigger a store
|
||||
entry = registry.async_get_or_create(
|
||||
config_entry_id=mock_config_entry.entry_id,
|
||||
connections={("Zigbee", "01.23.45.67.89")},
|
||||
identifiers={("serial", "123456ABCDEF")},
|
||||
sw_version="new_version",
|
||||
)
|
||||
assert entry.id == "abcdefghijklm"
|
||||
|
||||
# Check we store migrated data
|
||||
await flush_store(registry._store)
|
||||
|
||||
assert hass_storage[dr.STORAGE_KEY] == {
|
||||
"version": dr.STORAGE_VERSION_MAJOR,
|
||||
"minor_version": dr.STORAGE_VERSION_MINOR,
|
||||
"key": dr.STORAGE_KEY,
|
||||
"data": {
|
||||
"devices": [
|
||||
{
|
||||
"area_id": None,
|
||||
"config_entries": [mock_config_entry.entry_id],
|
||||
"configuration_url": None,
|
||||
"connections": [["Zigbee", "01.23.45.67.89"]],
|
||||
"disabled_by": None,
|
||||
"entry_type": "service",
|
||||
"hw_version": "hw_version",
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"labels": [],
|
||||
"manufacturer": "manufacturer",
|
||||
"model": "model",
|
||||
"name": "name",
|
||||
"name_by_user": None,
|
||||
"serial_number": None,
|
||||
"sw_version": "new_version",
|
||||
"via_device_id": None,
|
||||
},
|
||||
{
|
||||
"area_id": None,
|
||||
"config_entries": [None],
|
||||
"configuration_url": None,
|
||||
"connections": [],
|
||||
"disabled_by": None,
|
||||
"entry_type": None,
|
||||
"hw_version": None,
|
||||
"id": "invalid-entry-type",
|
||||
"identifiers": [["serial", "mock-id-invalid-entry"]],
|
||||
"labels": [],
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name_by_user": None,
|
||||
|
@ -1007,7 +1142,10 @@ async def test_loading_saving_data(
|
|||
assert len(device_registry.deleted_devices) == 1
|
||||
|
||||
orig_via = device_registry.async_update_device(
|
||||
orig_via.id, area_id="mock-area-id", name_by_user="mock-name-by-user"
|
||||
orig_via.id,
|
||||
area_id="mock-area-id",
|
||||
name_by_user="mock-name-by-user",
|
||||
labels={"mock-label1", "mock-label2"},
|
||||
)
|
||||
|
||||
# Now load written data in new registry
|
||||
|
@ -1115,6 +1253,7 @@ async def test_update(
|
|||
)
|
||||
new_identifiers = {("hue", "654"), ("bla", "321")}
|
||||
assert not entry.area_id
|
||||
assert not entry.labels
|
||||
assert not entry.name_by_user
|
||||
|
||||
with patch.object(device_registry, "async_schedule_save") as mock_save:
|
||||
|
@ -1125,6 +1264,7 @@ async def test_update(
|
|||
disabled_by=dr.DeviceEntryDisabler.USER,
|
||||
entry_type=dr.DeviceEntryType.SERVICE,
|
||||
hw_version="hw_version",
|
||||
labels={"label1", "label2"},
|
||||
manufacturer="Test Producer",
|
||||
model="Test Model",
|
||||
name_by_user="Test Friendly Name",
|
||||
|
@ -1148,6 +1288,7 @@ async def test_update(
|
|||
hw_version="hw_version",
|
||||
id=entry.id,
|
||||
identifiers={("bla", "321"), ("hue", "654")},
|
||||
labels={"label1", "label2"},
|
||||
manufacturer="Test Producer",
|
||||
model="Test Model",
|
||||
name_by_user="Test Friendly Name",
|
||||
|
@ -1192,6 +1333,7 @@ async def test_update(
|
|||
"entry_type": None,
|
||||
"hw_version": None,
|
||||
"identifiers": {("bla", "123"), ("hue", "456")},
|
||||
"labels": set(),
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name": None,
|
||||
|
@ -1996,6 +2138,7 @@ async def test_loading_invalid_configuration_url_from_storage(
|
|||
"hw_version": None,
|
||||
"id": "abcdefghijklm",
|
||||
"identifiers": [["serial", "123456ABCDEF"]],
|
||||
"labels": [],
|
||||
"manufacturer": None,
|
||||
"model": None,
|
||||
"name_by_user": None,
|
||||
|
@ -2031,3 +2174,87 @@ def test_deprecated_constants(
|
|||
) -> None:
|
||||
"""Test deprecated constants."""
|
||||
import_and_test_deprecated_constant_enum(caplog, dr, enum, "DISABLED_", "2025.1")
|
||||
|
||||
|
||||
async def test_removing_labels(
|
||||
hass: HomeAssistant, device_registry: dr.DeviceRegistry
|
||||
) -> None:
|
||||
"""Make sure we can clear labels."""
|
||||
config_entry = MockConfigEntry()
|
||||
config_entry.add_to_hass(hass)
|
||||
entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
identifiers={("bridgeid", "0123")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
entry = device_registry.async_update_device(entry.id, labels={"label1", "label2"})
|
||||
|
||||
device_registry.async_clear_label_id("label1")
|
||||
entry_cleared_label1 = device_registry.async_get_device({("bridgeid", "0123")})
|
||||
|
||||
device_registry.async_clear_label_id("label2")
|
||||
entry_cleared_label2 = device_registry.async_get_device({("bridgeid", "0123")})
|
||||
|
||||
assert entry_cleared_label1
|
||||
assert entry_cleared_label2
|
||||
assert entry != entry_cleared_label1
|
||||
assert entry != entry_cleared_label2
|
||||
assert entry_cleared_label1 != entry_cleared_label2
|
||||
assert entry.labels == {"label1", "label2"}
|
||||
assert entry_cleared_label1.labels == {"label2"}
|
||||
assert not entry_cleared_label2.labels
|
||||
|
||||
|
||||
async def test_entries_for_label(
|
||||
hass: HomeAssistant, device_registry: dr.DeviceRegistry
|
||||
) -> None:
|
||||
"""Test getting device entries by label."""
|
||||
config_entry = MockConfigEntry()
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:00")},
|
||||
identifiers={("bridgeid", "0000")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
entry_1 = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:23")},
|
||||
identifiers={("bridgeid", "0123")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
entry_1 = device_registry.async_update_device(entry_1.id, labels={"label1"})
|
||||
entry_2 = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:56")},
|
||||
identifiers={("bridgeid", "0456")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
entry_2 = device_registry.async_update_device(entry_2.id, labels={"label2"})
|
||||
entry_1_and_2 = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:89")},
|
||||
identifiers={("bridgeid", "0789")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
entry_1_and_2 = device_registry.async_update_device(
|
||||
entry_1_and_2.id, labels={"label1", "label2"}
|
||||
)
|
||||
|
||||
entries = dr.async_entries_for_label(device_registry, "label1")
|
||||
assert len(entries) == 2
|
||||
assert entries == [entry_1, entry_1_and_2]
|
||||
|
||||
entries = dr.async_entries_for_label(device_registry, "label2")
|
||||
assert len(entries) == 2
|
||||
assert entries == [entry_2, entry_1_and_2]
|
||||
|
||||
assert not dr.async_entries_for_label(device_registry, "unknown")
|
||||
assert not dr.async_entries_for_label(device_registry, "")
|
||||
|
|
|
@ -277,6 +277,9 @@ async def test_loading_saving_data(
|
|||
entity_registry.async_update_entity_options(
|
||||
orig_entry2.entity_id, "light", {"minimum_brightness": 20}
|
||||
)
|
||||
entity_registry.async_update_entity(
|
||||
orig_entry2.entity_id, labels={"label1", "label2"}
|
||||
)
|
||||
orig_entry2 = entity_registry.async_get(orig_entry2.entity_id)
|
||||
orig_entry3 = entity_registry.async_get_or_create("light", "hue", "ABCD")
|
||||
orig_entry4 = entity_registry.async_get_or_create("light", "hue", "EFGH")
|
||||
|
@ -314,6 +317,7 @@ async def test_loading_saving_data(
|
|||
assert new_entry2.icon == "hass:user-icon"
|
||||
assert new_entry2.hidden_by == er.RegistryEntryHider.INTEGRATION
|
||||
assert new_entry2.has_entity_name is True
|
||||
assert new_entry2.labels == {"label1", "label2"}
|
||||
assert new_entry2.name == "User Name"
|
||||
assert new_entry2.options == {"light": {"minimum_brightness": 20}}
|
||||
assert new_entry2.original_device_class == "mock-device-class"
|
||||
|
@ -1756,3 +1760,70 @@ async def test_async_migrate_entry_delete_other(
|
|||
await er.async_migrate_entries(hass, config_entry1.entry_id, _async_migrator)
|
||||
assert entries == {entry1.entity_id}
|
||||
assert not entity_registry.async_is_registered(entry2.entity_id)
|
||||
|
||||
|
||||
async def test_removing_labels(entity_registry: er.EntityRegistry) -> None:
|
||||
"""Make sure we can clear labels."""
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="5678",
|
||||
)
|
||||
entry = entity_registry.async_update_entity(
|
||||
entry.entity_id, labels={"label1", "label2"}
|
||||
)
|
||||
|
||||
entity_registry.async_clear_label_id("label1")
|
||||
entry_cleared_label1 = entity_registry.async_get(entry.entity_id)
|
||||
|
||||
entity_registry.async_clear_label_id("label2")
|
||||
entry_cleared_label2 = entity_registry.async_get(entry.entity_id)
|
||||
|
||||
assert entry_cleared_label1
|
||||
assert entry_cleared_label2
|
||||
assert entry != entry_cleared_label1
|
||||
assert entry != entry_cleared_label2
|
||||
assert entry_cleared_label1 != entry_cleared_label2
|
||||
assert entry.labels == {"label1", "label2"}
|
||||
assert entry_cleared_label1.labels == {"label2"}
|
||||
assert not entry_cleared_label2.labels
|
||||
|
||||
|
||||
async def test_entries_for_label(entity_registry: er.EntityRegistry) -> None:
|
||||
"""Test getting entity entries by label."""
|
||||
entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="000",
|
||||
)
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="123",
|
||||
)
|
||||
label_1 = entity_registry.async_update_entity(entry.entity_id, labels={"label1"})
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="456",
|
||||
)
|
||||
label_2 = entity_registry.async_update_entity(entry.entity_id, labels={"label2"})
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="789",
|
||||
)
|
||||
label_1_and_2 = entity_registry.async_update_entity(
|
||||
entry.entity_id, labels={"label1", "label2"}
|
||||
)
|
||||
|
||||
entries = er.async_entries_for_label(entity_registry, "label1")
|
||||
assert len(entries) == 2
|
||||
assert entries == [label_1, label_1_and_2]
|
||||
|
||||
entries = er.async_entries_for_label(entity_registry, "label2")
|
||||
assert len(entries) == 2
|
||||
assert entries == [label_2, label_1_and_2]
|
||||
|
||||
assert not er.async_entries_for_label(entity_registry, "unknown")
|
||||
assert not er.async_entries_for_label(entity_registry, "")
|
||||
|
|
460
tests/helpers/test_label_registry.py
Normal file
460
tests/helpers/test_label_registry.py
Normal file
|
@ -0,0 +1,460 @@
|
|||
"""Tests for the Label Registry."""
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
label_registry as lr,
|
||||
)
|
||||
from homeassistant.helpers.label_registry import (
|
||||
EVENT_LABEL_REGISTRY_UPDATED,
|
||||
STORAGE_KEY,
|
||||
STORAGE_VERSION_MAJOR,
|
||||
LabelRegistry,
|
||||
async_get,
|
||||
async_load,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry, async_capture_events, flush_store
|
||||
|
||||
|
||||
async def test_list_labels(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can read label."""
|
||||
labels = label_registry.async_list_labels()
|
||||
assert len(list(labels)) == len(label_registry.labels)
|
||||
|
||||
|
||||
async def test_create_label(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can create labels."""
|
||||
update_events = async_capture_events(hass, EVENT_LABEL_REGISTRY_UPDATED)
|
||||
label = label_registry.async_create(
|
||||
name="My Label",
|
||||
color="#FF0000",
|
||||
icon="mdi:test",
|
||||
description="This label is for testing",
|
||||
)
|
||||
|
||||
assert label.label_id == "my_label"
|
||||
assert label.name == "My Label"
|
||||
assert label.color == "#FF0000"
|
||||
assert label.icon == "mdi:test"
|
||||
assert label.description == "This label is for testing"
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(update_events) == 1
|
||||
assert update_events[0].data == {
|
||||
"action": "create",
|
||||
"label_id": label.label_id,
|
||||
}
|
||||
|
||||
|
||||
async def test_create_label_with_name_already_in_use(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can't create an label with a name already in use."""
|
||||
update_events = async_capture_events(hass, EVENT_LABEL_REGISTRY_UPDATED)
|
||||
label_registry.async_create("mock")
|
||||
|
||||
with pytest.raises(
|
||||
ValueError, match=re.escape("The name mock (mock) is already in use")
|
||||
):
|
||||
label_registry.async_create("mock")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
assert len(update_events) == 1
|
||||
|
||||
|
||||
async def test_create_label_with_id_already_in_use(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can't create an label with a name already in use."""
|
||||
label = label_registry.async_create("Label")
|
||||
|
||||
updated_label = label_registry.async_update(label.label_id, name="Renamed Label")
|
||||
assert updated_label.label_id == label.label_id
|
||||
|
||||
second_label = label_registry.async_create("Label")
|
||||
assert label.label_id != second_label.label_id
|
||||
assert second_label.label_id == "label_2"
|
||||
|
||||
|
||||
async def test_delete_label(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can delete an label."""
|
||||
update_events = async_capture_events(hass, EVENT_LABEL_REGISTRY_UPDATED)
|
||||
label = label_registry.async_create("Label")
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
label_registry.async_delete(label.label_id)
|
||||
|
||||
assert not label_registry.labels
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(update_events) == 2
|
||||
assert update_events[0].data == {
|
||||
"action": "create",
|
||||
"label_id": label.label_id,
|
||||
}
|
||||
assert update_events[1].data == {
|
||||
"action": "remove",
|
||||
"label_id": label.label_id,
|
||||
}
|
||||
|
||||
|
||||
async def test_delete_non_existing_label(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can't delete an label that doesn't exist."""
|
||||
label_registry.async_create("mock")
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
label_registry.async_delete("")
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
|
||||
async def test_update_label(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can update labels."""
|
||||
update_events = async_capture_events(hass, EVENT_LABEL_REGISTRY_UPDATED)
|
||||
label = label_registry.async_create("Mock")
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
assert label.label_id == "mock"
|
||||
assert label.name == "Mock"
|
||||
assert label.color is None
|
||||
assert label.icon is None
|
||||
assert label.description is None
|
||||
|
||||
updated_label = label_registry.async_update(
|
||||
label.label_id,
|
||||
name="Updated",
|
||||
color="#FFFFFF",
|
||||
icon="mdi:update",
|
||||
description="Updated description",
|
||||
)
|
||||
|
||||
assert updated_label != label
|
||||
assert updated_label.label_id == "mock"
|
||||
assert updated_label.name == "Updated"
|
||||
assert updated_label.color == "#FFFFFF"
|
||||
assert updated_label.icon == "mdi:update"
|
||||
assert updated_label.description == "Updated description"
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(update_events) == 2
|
||||
assert update_events[0].data == {
|
||||
"action": "create",
|
||||
"label_id": label.label_id,
|
||||
}
|
||||
assert update_events[1].data == {
|
||||
"action": "update",
|
||||
"label_id": label.label_id,
|
||||
}
|
||||
|
||||
|
||||
async def test_update_label_with_same_data(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can reapply the same data to the label and it won't update."""
|
||||
update_events = async_capture_events(hass, EVENT_LABEL_REGISTRY_UPDATED)
|
||||
label = label_registry.async_create(
|
||||
"mock",
|
||||
color="#FFFFFF",
|
||||
icon="mdi:test",
|
||||
description="Description",
|
||||
)
|
||||
|
||||
udpated_label = label_registry.async_update(
|
||||
label_id=label.label_id,
|
||||
name="mock",
|
||||
color="#FFFFFF",
|
||||
icon="mdi:test",
|
||||
description="Description",
|
||||
)
|
||||
assert label == udpated_label
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# No update event
|
||||
assert len(update_events) == 1
|
||||
assert update_events[0].data == {
|
||||
"action": "create",
|
||||
"label_id": label.label_id,
|
||||
}
|
||||
|
||||
|
||||
async def test_update_label_with_same_name_change_case(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can reapply the same name with a different case to the label."""
|
||||
label = label_registry.async_create("mock")
|
||||
|
||||
updated_label = label_registry.async_update(label.label_id, name="Mock")
|
||||
|
||||
assert updated_label.name == "Mock"
|
||||
assert updated_label.label_id == label.label_id
|
||||
assert updated_label.normalized_name == label.normalized_name
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
|
||||
async def test_update_label_with_name_already_in_use(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can't update an label with a name already in use."""
|
||||
label1 = label_registry.async_create("mock1")
|
||||
label2 = label_registry.async_create("mock2")
|
||||
|
||||
with pytest.raises(
|
||||
ValueError, match=re.escape("The name mock2 (mock2) is already in use")
|
||||
):
|
||||
label_registry.async_update(label1.label_id, name="mock2")
|
||||
|
||||
assert label1.name == "mock1"
|
||||
assert label2.name == "mock2"
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
|
||||
async def test_update_label_with_normalized_name_already_in_use(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can't update an label with a normalized name already in use."""
|
||||
label1 = label_registry.async_create("mock1")
|
||||
label2 = label_registry.async_create("M O C K 2")
|
||||
|
||||
with pytest.raises(
|
||||
ValueError, match=re.escape("The name mock2 (mock2) is already in use")
|
||||
):
|
||||
label_registry.async_update(label1.label_id, name="mock2")
|
||||
|
||||
assert label1.name == "mock1"
|
||||
assert label2.name == "M O C K 2"
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
|
||||
async def test_load_labels(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure that we can load/save data correctly."""
|
||||
label1 = label_registry.async_create(
|
||||
"Label One",
|
||||
color="#FF000",
|
||||
icon="mdi:one",
|
||||
description="This label is label one",
|
||||
)
|
||||
label2 = label_registry.async_create(
|
||||
"Label Two",
|
||||
color="#000FF",
|
||||
icon="mdi:two",
|
||||
description="This label is label two",
|
||||
)
|
||||
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
registry2 = LabelRegistry(hass)
|
||||
await flush_store(label_registry._store)
|
||||
await registry2.async_load()
|
||||
|
||||
assert len(registry2.labels) == 2
|
||||
assert list(label_registry.labels) == list(registry2.labels)
|
||||
|
||||
label1_registry2 = registry2.async_get_or_create("Label One")
|
||||
assert label1_registry2.label_id == label1.label_id
|
||||
assert label1_registry2.name == label1.name
|
||||
assert label1_registry2.color == label1.color
|
||||
assert label1_registry2.description == label1.description
|
||||
assert label1_registry2.icon == label1.icon
|
||||
assert label1_registry2.normalized_name == label1.normalized_name
|
||||
|
||||
label2_registry2 = registry2.async_get_or_create("Label Two")
|
||||
assert label2_registry2.name == label2.name
|
||||
assert label2_registry2.color == label2.color
|
||||
assert label2_registry2.description == label2.description
|
||||
assert label2_registry2.icon == label2.icon
|
||||
assert label2_registry2.normalized_name == label2.normalized_name
|
||||
|
||||
|
||||
@pytest.mark.parametrize("load_registries", [False])
|
||||
async def test_loading_label_from_storage(
|
||||
hass: HomeAssistant, hass_storage: Any
|
||||
) -> None:
|
||||
"""Test loading stored labels on start."""
|
||||
hass_storage[STORAGE_KEY] = {
|
||||
"version": STORAGE_VERSION_MAJOR,
|
||||
"data": {
|
||||
"labels": [
|
||||
{
|
||||
"color": "#FFFFFF",
|
||||
"description": None,
|
||||
"icon": "mdi:test",
|
||||
"label_id": "one",
|
||||
"name": "One",
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
await async_load(hass)
|
||||
registry = async_get(hass)
|
||||
|
||||
assert len(registry.labels) == 1
|
||||
|
||||
|
||||
async def test_getting_label(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure we can get the labels by name."""
|
||||
label = label_registry.async_get_or_create("Mock1")
|
||||
label2 = label_registry.async_get_or_create("mock1")
|
||||
label3 = label_registry.async_get_or_create("mock 1")
|
||||
|
||||
assert label == label2
|
||||
assert label == label3
|
||||
assert label2 == label3
|
||||
|
||||
get_label = label_registry.async_get_label_by_name("M o c k 1")
|
||||
assert get_label == label
|
||||
|
||||
get_label = label_registry.async_get_label(label.label_id)
|
||||
assert get_label == label
|
||||
|
||||
|
||||
async def test_async_get_label_by_name_not_found(
|
||||
hass: HomeAssistant, label_registry: lr.LabelRegistry
|
||||
) -> None:
|
||||
"""Make sure we return None for non-existent labels."""
|
||||
label_registry.async_create("Mock1")
|
||||
|
||||
assert len(label_registry.labels) == 1
|
||||
|
||||
assert label_registry.async_get_label_by_name("non_exist") is None
|
||||
|
||||
|
||||
async def test_labels_removed_from_devices(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Tests if label gets removed from devices when the label is removed."""
|
||||
config_entry = MockConfigEntry()
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
label1 = label_registry.async_create("label1")
|
||||
label2 = label_registry.async_create("label2")
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:23")},
|
||||
identifiers={("bridgeid", "0123")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
device_registry.async_update_device(entry.id, labels={label1.label_id})
|
||||
entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:56")},
|
||||
identifiers={("bridgeid", "0456")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
device_registry.async_update_device(entry.id, labels={label2.label_id})
|
||||
entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:89")},
|
||||
identifiers={("bridgeid", "0789")},
|
||||
manufacturer="manufacturer",
|
||||
model="model",
|
||||
)
|
||||
device_registry.async_update_device(
|
||||
entry.id, labels={label1.label_id, label2.label_id}
|
||||
)
|
||||
|
||||
entries = dr.async_entries_for_label(device_registry, label1.label_id)
|
||||
assert len(entries) == 2
|
||||
entries = dr.async_entries_for_label(device_registry, label2.label_id)
|
||||
assert len(entries) == 2
|
||||
|
||||
label_registry.async_delete(label1.label_id)
|
||||
|
||||
entries = dr.async_entries_for_label(device_registry, label1.label_id)
|
||||
assert len(entries) == 0
|
||||
entries = dr.async_entries_for_label(device_registry, label2.label_id)
|
||||
assert len(entries) == 2
|
||||
|
||||
label_registry.async_delete(label2.label_id)
|
||||
|
||||
entries = dr.async_entries_for_label(device_registry, label1.label_id)
|
||||
assert len(entries) == 0
|
||||
entries = dr.async_entries_for_label(device_registry, label2.label_id)
|
||||
assert len(entries) == 0
|
||||
|
||||
|
||||
async def test_labels_removed_from_entities(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Tests if label gets removed from entity when the label is removed."""
|
||||
label1 = label_registry.async_create("label1")
|
||||
label2 = label_registry.async_create("label2")
|
||||
assert len(label_registry.labels) == 2
|
||||
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="123",
|
||||
)
|
||||
entity_registry.async_update_entity(entry.entity_id, labels={label1.label_id})
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="456",
|
||||
)
|
||||
entity_registry.async_update_entity(entry.entity_id, labels={label2.label_id})
|
||||
entry = entity_registry.async_get_or_create(
|
||||
domain="light",
|
||||
platform="hue",
|
||||
unique_id="789",
|
||||
)
|
||||
entity_registry.async_update_entity(
|
||||
entry.entity_id, labels={label1.label_id, label2.label_id}
|
||||
)
|
||||
|
||||
entries = er.async_entries_for_label(entity_registry, label1.label_id)
|
||||
assert len(entries) == 2
|
||||
entries = er.async_entries_for_label(entity_registry, label2.label_id)
|
||||
assert len(entries) == 2
|
||||
|
||||
label_registry.async_delete(label1.label_id)
|
||||
|
||||
entries = er.async_entries_for_label(entity_registry, label1.label_id)
|
||||
assert len(entries) == 0
|
||||
entries = er.async_entries_for_label(entity_registry, label2.label_id)
|
||||
assert len(entries) == 2
|
||||
|
||||
label_registry.async_delete(label2.label_id)
|
||||
|
||||
entries = er.async_entries_for_label(entity_registry, label1.label_id)
|
||||
assert len(entries) == 0
|
||||
entries = er.async_entries_for_label(entity_registry, label2.label_id)
|
||||
assert len(entries) == 0
|
|
@ -233,6 +233,88 @@ def area_mock(hass):
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def label_mock(hass: HomeAssistant) -> None:
|
||||
"""Mock including label info."""
|
||||
hass.states.async_set("light.Bowl", STATE_ON)
|
||||
hass.states.async_set("light.Ceiling", STATE_OFF)
|
||||
hass.states.async_set("light.Kitchen", STATE_OFF)
|
||||
|
||||
device_has_label1 = dr.DeviceEntry(labels={"label1"})
|
||||
device_has_label2 = dr.DeviceEntry(labels={"label2"})
|
||||
device_has_labels = dr.DeviceEntry(labels={"label1", "label2"})
|
||||
device_no_labels = dr.DeviceEntry(id="device-no-labels")
|
||||
|
||||
mock_device_registry(
|
||||
hass,
|
||||
{
|
||||
device_has_label1.id: device_has_label1,
|
||||
device_has_label2.id: device_has_label2,
|
||||
device_has_labels.id: device_has_labels,
|
||||
device_no_labels.id: device_no_labels,
|
||||
},
|
||||
)
|
||||
|
||||
entity_with_my_label = er.RegistryEntry(
|
||||
entity_id="light.with_my_label",
|
||||
unique_id="with_my_label",
|
||||
platform="test",
|
||||
labels={"my-label"},
|
||||
)
|
||||
hidden_entity_with_my_label = er.RegistryEntry(
|
||||
entity_id="light.hidden_with_my_label",
|
||||
unique_id="hidden_with_my_label",
|
||||
platform="test",
|
||||
labels={"my-label"},
|
||||
hidden_by=er.RegistryEntryHider.USER,
|
||||
)
|
||||
config_entity_with_my_label = er.RegistryEntry(
|
||||
entity_id="light.config_with_my_label",
|
||||
unique_id="config_with_my_label",
|
||||
platform="test",
|
||||
labels={"my-label"},
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
)
|
||||
entity_with_label1_from_device = er.RegistryEntry(
|
||||
entity_id="light.with_label1_from_device",
|
||||
unique_id="with_label1_from_device",
|
||||
platform="test",
|
||||
device_id=device_has_label1.id,
|
||||
)
|
||||
entity_with_label1_and_label2_from_device = er.RegistryEntry(
|
||||
entity_id="light.with_label1_and_label2_from_device",
|
||||
unique_id="with_label1_and_label2_from_device",
|
||||
platform="test",
|
||||
labels={"label1"},
|
||||
device_id=device_has_label2.id,
|
||||
)
|
||||
entity_with_labels_from_device = er.RegistryEntry(
|
||||
entity_id="light.with_labels_from_device",
|
||||
unique_id="with_labels_from_device",
|
||||
platform="test",
|
||||
device_id=device_has_labels.id,
|
||||
)
|
||||
entity_with_no_labels = er.RegistryEntry(
|
||||
entity_id="light.no_labels",
|
||||
unique_id="no_labels",
|
||||
platform="test",
|
||||
device_id=device_no_labels.id,
|
||||
)
|
||||
|
||||
mock_registry(
|
||||
hass,
|
||||
{
|
||||
config_entity_with_my_label.entity_id: config_entity_with_my_label,
|
||||
entity_with_label1_and_label2_from_device.entity_id: entity_with_label1_and_label2_from_device,
|
||||
entity_with_label1_from_device.entity_id: entity_with_label1_from_device,
|
||||
entity_with_labels_from_device.entity_id: entity_with_labels_from_device,
|
||||
entity_with_my_label.entity_id: entity_with_my_label,
|
||||
entity_with_no_labels.entity_id: entity_with_no_labels,
|
||||
hidden_entity_with_my_label.entity_id: hidden_entity_with_my_label,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def test_call_from_config(hass: HomeAssistant) -> None:
|
||||
"""Test the sync wrapper of service.async_call_from_config."""
|
||||
calls = async_mock_service(hass, "test_domain", "test_service")
|
||||
|
@ -559,6 +641,39 @@ async def test_extract_entity_ids_from_devices(hass: HomeAssistant, area_mock) -
|
|||
)
|
||||
|
||||
|
||||
async def test_extract_entity_ids_from_labels(
|
||||
hass: HomeAssistant, label_mock: None
|
||||
) -> None:
|
||||
"""Test extract_entity_ids method with labels."""
|
||||
call = ServiceCall("light", "turn_on", {"label_id": "my-label"})
|
||||
|
||||
assert {
|
||||
"light.with_my_label",
|
||||
} == await service.async_extract_entity_ids(hass, call)
|
||||
|
||||
call = ServiceCall("light", "turn_on", {"label_id": "label1"})
|
||||
|
||||
assert {
|
||||
"light.with_label1_from_device",
|
||||
"light.with_labels_from_device",
|
||||
"light.with_label1_and_label2_from_device",
|
||||
} == await service.async_extract_entity_ids(hass, call)
|
||||
|
||||
call = ServiceCall("light", "turn_on", {"label_id": ["label2"]})
|
||||
|
||||
assert {
|
||||
"light.with_labels_from_device",
|
||||
"light.with_label1_and_label2_from_device",
|
||||
} == await service.async_extract_entity_ids(hass, call)
|
||||
|
||||
assert (
|
||||
await service.async_extract_entity_ids(
|
||||
hass, ServiceCall("light", "turn_on", {"label_id": ENTITY_MATCH_NONE})
|
||||
)
|
||||
== set()
|
||||
)
|
||||
|
||||
|
||||
async def test_async_get_all_descriptions(hass: HomeAssistant) -> None:
|
||||
"""Test async_get_all_descriptions."""
|
||||
group = hass.components.group
|
||||
|
@ -1500,6 +1615,45 @@ async def test_extract_from_service_area_id(hass: HomeAssistant, area_mock) -> N
|
|||
]
|
||||
|
||||
|
||||
async def test_extract_from_service_label_id(
|
||||
hass: HomeAssistant, label_mock: None
|
||||
) -> None:
|
||||
"""Test the extraction using label ID as reference."""
|
||||
entities = [
|
||||
MockEntity(name="with_my_label", entity_id="light.with_my_label"),
|
||||
MockEntity(name="no_labels", entity_id="light.no_labels"),
|
||||
MockEntity(
|
||||
name="with_labels_from_device", entity_id="light.with_labels_from_device"
|
||||
),
|
||||
]
|
||||
|
||||
call = ServiceCall("light", "turn_on", {"label_id": "my-label"})
|
||||
extracted = await service.async_extract_entities(hass, entities, call)
|
||||
assert len(extracted) == 1
|
||||
assert extracted[0].entity_id == "light.with_my_label"
|
||||
|
||||
call = ServiceCall("light", "turn_on", {"label_id": ["my-label", "label1"]})
|
||||
extracted = await service.async_extract_entities(hass, entities, call)
|
||||
assert len(extracted) == 2
|
||||
assert sorted(ent.entity_id for ent in extracted) == [
|
||||
"light.with_labels_from_device",
|
||||
"light.with_my_label",
|
||||
]
|
||||
|
||||
call = ServiceCall(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"label_id": ["my-label", "label1"], "device_id": "device-no-labels"},
|
||||
)
|
||||
extracted = await service.async_extract_entities(hass, entities, call)
|
||||
assert len(extracted) == 3
|
||||
assert sorted(ent.entity_id for ent in extracted) == [
|
||||
"light.no_labels",
|
||||
"light.with_labels_from_device",
|
||||
"light.with_my_label",
|
||||
]
|
||||
|
||||
|
||||
async def test_entity_service_call_warn_referenced(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
|
@ -1511,12 +1665,14 @@ async def test_entity_service_call_warn_referenced(
|
|||
"area_id": "non-existent-area",
|
||||
"entity_id": "non.existent",
|
||||
"device_id": "non-existent-device",
|
||||
"label_id": "non-existent-label",
|
||||
},
|
||||
)
|
||||
await service.entity_service_call(hass, {}, "", call)
|
||||
assert (
|
||||
"Referenced areas non-existent-area, devices non-existent-device, "
|
||||
"entities non.existent are missing or not currently available"
|
||||
"entities non.existent, labels non-existent-label "
|
||||
"are missing or not currently available"
|
||||
) in caplog.text
|
||||
|
||||
|
||||
|
@ -1531,13 +1687,15 @@ async def test_async_extract_entities_warn_referenced(
|
|||
"area_id": "non-existent-area",
|
||||
"entity_id": "non.existent",
|
||||
"device_id": "non-existent-device",
|
||||
"label_id": "non-existent-label",
|
||||
},
|
||||
)
|
||||
extracted = await service.async_extract_entities(hass, {}, call)
|
||||
assert len(extracted) == 0
|
||||
assert (
|
||||
"Referenced areas non-existent-area, devices non-existent-device, "
|
||||
"entities non.existent are missing or not currently available"
|
||||
"entities non.existent, labels non-existent-label "
|
||||
"are missing or not currently available"
|
||||
) in caplog.text
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ from homeassistant.helpers import (
|
|||
device_registry as dr,
|
||||
entity,
|
||||
entity_registry as er,
|
||||
label_registry as lr,
|
||||
template,
|
||||
)
|
||||
from homeassistant.helpers.entity_platform import EntityPlatform
|
||||
|
@ -4953,3 +4954,290 @@ async def test_lru_increases_with_many_entities(hass: HomeAssistant) -> None:
|
|||
assert template.CACHED_TEMPLATE_NO_COLLECT_LRU.get_size() == int(
|
||||
round(mock_entity_count * template.ENTITY_COUNT_GROWTH_FACTOR)
|
||||
)
|
||||
|
||||
|
||||
async def test_labels(
|
||||
hass: HomeAssistant,
|
||||
label_registry: lr.LabelRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test labels function."""
|
||||
|
||||
# Test no labels
|
||||
info = render_to_info(hass, "{{ labels() }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test one label
|
||||
label1 = label_registry.async_get_or_create("label1")
|
||||
info = render_to_info(hass, "{{ labels() }}")
|
||||
assert_result_info(info, [label1.label_id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test multiple label
|
||||
label2 = label_registry.async_get_or_create("label2")
|
||||
info = render_to_info(hass, "{{ labels() }}")
|
||||
assert_result_info(info, [label1.label_id, label2.label_id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test non-exsting entity ID
|
||||
info = render_to_info(hass, "{{ labels('sensor.fake') }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 'sensor.fake' | labels }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test non existing device ID (hex value)
|
||||
info = render_to_info(hass, "{{ labels('123abc') }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ '123abc' | labels }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Create a device & entity for testing
|
||||
config_entry = MockConfigEntry(domain="light")
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
entity_entry = entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"hue",
|
||||
"5678",
|
||||
config_entry=config_entry,
|
||||
device_id=device_entry.id,
|
||||
)
|
||||
|
||||
# Test entity, which has no labels
|
||||
info = render_to_info(hass, f"{{{{ labels('{entity_entry.entity_id}') }}}}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{entity_entry.entity_id}' | labels }}}}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test device, which has no labels
|
||||
info = render_to_info(hass, f"{{{{ labels('{device_entry.id}') }}}}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{device_entry.id}' | labels }}}}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Add labels to the entity & device
|
||||
label1 = label_registry.async_get_or_create("label1")
|
||||
label2 = label_registry.async_get_or_create("label2")
|
||||
device_entry = device_registry.async_update_device(
|
||||
device_entry.id, labels=[label1.label_id]
|
||||
)
|
||||
entity_entry = entity_registry.async_update_entity(
|
||||
entity_entry.entity_id, labels=[label2.label_id]
|
||||
)
|
||||
|
||||
# Test entity, which now has a label
|
||||
info = render_to_info(hass, f"{{{{ '{entity_entry.entity_id}' | labels }}}}")
|
||||
assert_result_info(info, [label2.label_id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ labels('{entity_entry.entity_id}') }}}}")
|
||||
assert_result_info(info, [label2.label_id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test device, which now has a label
|
||||
info = render_to_info(hass, f"{{{{ '{device_entry.id}' | labels }}}}")
|
||||
assert_result_info(info, [label1.label_id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ labels('{device_entry.id}') }}}}")
|
||||
assert_result_info(info, [label1.label_id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
|
||||
async def test_label_id(
|
||||
hass: HomeAssistant,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test label_id function."""
|
||||
# Test non existing label name
|
||||
info = render_to_info(hass, "{{ label_id('non-existing label') }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 'non-existing label' | label_id }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test wrong value type
|
||||
info = render_to_info(hass, "{{ label_id(42) }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 42 | label_id }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test with an actual label
|
||||
label = label_registry.async_get_or_create("existing label")
|
||||
info = render_to_info(hass, "{{ label_id('existing label') }}")
|
||||
assert_result_info(info, label.label_id)
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 'existing label' | label_id }}")
|
||||
assert_result_info(info, label.label_id)
|
||||
assert info.rate_limit is None
|
||||
|
||||
|
||||
async def test_label_name(
|
||||
hass: HomeAssistant,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test label_name function."""
|
||||
# Test non existing label ID
|
||||
info = render_to_info(hass, "{{ label_name('1234567890') }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ '1234567890' | label_name }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test wrong value type
|
||||
info = render_to_info(hass, "{{ label_name(42) }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 42 | label_name }}")
|
||||
assert_result_info(info, None)
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test non existing label ID
|
||||
label = label_registry.async_get_or_create("choo choo")
|
||||
info = render_to_info(hass, f"{{{{ label_name('{label.label_id}') }}}}")
|
||||
assert_result_info(info, label.name)
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{label.label_id}' | label_name }}}}")
|
||||
assert_result_info(info, label.name)
|
||||
assert info.rate_limit is None
|
||||
|
||||
|
||||
async def test_label_entities(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
label_registry: lr.LabelRegistry,
|
||||
) -> None:
|
||||
"""Test label_entities function."""
|
||||
|
||||
# Test non existing device id
|
||||
info = render_to_info(hass, "{{ label_entities('deadbeef') }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 'deadbeef' | label_entities }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test wrong value type
|
||||
info = render_to_info(hass, "{{ label_entities(42) }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 42 | label_entities }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Create a fake config entry with a entity
|
||||
config_entry = MockConfigEntry(domain="light")
|
||||
config_entry.add_to_hass(hass)
|
||||
entity_entry = entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"hue",
|
||||
"5678",
|
||||
config_entry=config_entry,
|
||||
)
|
||||
|
||||
# Add a label to the entity
|
||||
label = label_registry.async_get_or_create("Romantic Lights")
|
||||
entity_registry.async_update_entity(entity_entry.entity_id, labels={label.label_id})
|
||||
|
||||
# Get entities by label ID
|
||||
info = render_to_info(hass, f"{{{{ label_entities('{label.label_id}') }}}}")
|
||||
assert_result_info(info, ["light.hue_5678"])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{label.label_id}' | label_entities }}}}")
|
||||
assert_result_info(info, ["light.hue_5678"])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Get entities by label name
|
||||
info = render_to_info(hass, f"{{{{ label_entities('{label.name}') }}}}")
|
||||
assert_result_info(info, ["light.hue_5678"])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{label.name}' | label_entities }}}}")
|
||||
assert_result_info(info, ["light.hue_5678"])
|
||||
assert info.rate_limit is None
|
||||
|
||||
|
||||
async def test_label_devices(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
label_registry: ar.AreaRegistry,
|
||||
) -> None:
|
||||
"""Test label_devices function."""
|
||||
|
||||
# Test non existing device ID
|
||||
info = render_to_info(hass, "{{ label_devices('deadbeef') }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 'deadbeef' | label_devices }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Test wrong value type
|
||||
info = render_to_info(hass, "{{ label_devices(42) }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, "{{ 42 | label_devices }}")
|
||||
assert_result_info(info, [])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Create a fake config entry with a device
|
||||
config_entry = MockConfigEntry(domain="light")
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
|
||||
# Add a label to it
|
||||
label = label_registry.async_get_or_create("Romantic Lights")
|
||||
device_registry.async_update_device(device_entry.id, labels=[label.label_id])
|
||||
|
||||
# Get the devices from a label by its ID
|
||||
info = render_to_info(hass, f"{{{{ label_devices('{label.label_id}') }}}}")
|
||||
assert_result_info(info, [device_entry.id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{label.label_id}' | label_devices }}}}")
|
||||
assert_result_info(info, [device_entry.id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
# Get the devices from a label by its name
|
||||
info = render_to_info(hass, f"{{{{ label_devices('{label.name}') }}}}")
|
||||
assert_result_info(info, [device_entry.id])
|
||||
assert info.rate_limit is None
|
||||
|
||||
info = render_to_info(hass, f"{{{{ '{label.name}' | label_devices }}}}")
|
||||
assert_result_info(info, [device_entry.id])
|
||||
assert info.rate_limit is None
|
||||
|
|
|
@ -29,6 +29,7 @@ from homeassistant.helpers import (
|
|||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
issue_registry as ir,
|
||||
label_registry as lr,
|
||||
)
|
||||
|
||||
|
||||
|
@ -60,6 +61,10 @@ class EntityRegistryEntrySnapshot(dict):
|
|||
"""Tiny wrapper to represent an entity registry entry in snapshots."""
|
||||
|
||||
|
||||
class LabelRegistryEntrySnapshot(dict):
|
||||
"""Tiny wrapper to represent an label registry entry in snapshots."""
|
||||
|
||||
|
||||
class FlowResultSnapshot(dict):
|
||||
"""Tiny wrapper to represent a flow result in snapshots."""
|
||||
|
||||
|
@ -104,6 +109,8 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer):
|
|||
serializable_data = cls._serializable_entity_registry_entry(data)
|
||||
elif isinstance(data, ir.IssueEntry):
|
||||
serializable_data = cls._serializable_issue_registry_entry(data)
|
||||
elif isinstance(data, lr.LabelEntry):
|
||||
serializable_data = cls._serializable_issue_registry_entry(data)
|
||||
elif isinstance(data, dict) and "flow_id" in data and "handler" in data:
|
||||
serializable_data = cls._serializable_flow_result(data)
|
||||
elif isinstance(data, vol.Schema):
|
||||
|
@ -187,6 +194,13 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer):
|
|||
"""Prepare a Home Assistant issue registry entry for serialization."""
|
||||
return IssueRegistryItemSnapshot(data.to_json() | {"created": ANY})
|
||||
|
||||
@classmethod
|
||||
def _serializable_label_registry_entry(
|
||||
cls, data: lr.LabelEntry
|
||||
) -> SerializableData:
|
||||
"""Prepare a Home Assistant label registry entry for serialization."""
|
||||
return LabelRegistryEntrySnapshot(dataclasses.asdict(data))
|
||||
|
||||
@classmethod
|
||||
def _serializable_state(cls, data: State) -> SerializableData:
|
||||
"""Prepare a Home Assistant State for serialization."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue