1
mirror of https://github.com/home-assistant/core synced 2024-08-31 05:57:13 +02:00
ha-core/homeassistant/components/tag/__init__.py
2021-03-18 14:43:52 +01:00

123 lines
3.8 KiB
Python

"""The Tag integration."""
from __future__ import annotations
import logging
import uuid
import voluptuous as vol
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import collection
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.storage import Store
from homeassistant.loader import bind_hass
import homeassistant.util.dt as dt_util
from .const import DEVICE_ID, DOMAIN, EVENT_TAG_SCANNED, TAG_ID
_LOGGER = logging.getLogger(__name__)
LAST_SCANNED = "last_scanned"
STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1
TAGS = "tags"
CREATE_FIELDS = {
vol.Optional(TAG_ID): cv.string,
vol.Optional(CONF_NAME): vol.All(str, vol.Length(min=1)),
vol.Optional("description"): cv.string,
vol.Optional(LAST_SCANNED): cv.datetime,
}
UPDATE_FIELDS = {
vol.Optional(CONF_NAME): vol.All(str, vol.Length(min=1)),
vol.Optional("description"): cv.string,
vol.Optional(LAST_SCANNED): cv.datetime,
}
class TagIDExistsError(HomeAssistantError):
"""Raised when an item is not found."""
def __init__(self, item_id: str):
"""Initialize tag ID exists error."""
super().__init__(f"Tag with ID {item_id} already exists.")
self.item_id = item_id
class TagIDManager(collection.IDManager):
"""ID manager for tags."""
def generate_id(self, suggestion: str) -> str:
"""Generate an ID."""
if self.has_id(suggestion):
raise TagIDExistsError(suggestion)
return suggestion
class TagStorageCollection(collection.StorageCollection):
"""Tag collection stored in storage."""
CREATE_SCHEMA = vol.Schema(CREATE_FIELDS)
UPDATE_SCHEMA = vol.Schema(UPDATE_FIELDS)
async def _process_create_data(self, data: dict) -> dict:
"""Validate the config is valid."""
data = self.CREATE_SCHEMA(data)
if not data[TAG_ID]:
data[TAG_ID] = str(uuid.uuid4())
# make last_scanned JSON serializeable
if LAST_SCANNED in data:
data[LAST_SCANNED] = data[LAST_SCANNED].isoformat()
return data
@callback
def _get_suggested_id(self, info: dict) -> str:
"""Suggest an ID based on the config."""
return info[TAG_ID]
async def _update_data(self, data: dict, update_data: dict) -> dict:
"""Return a new updated data object."""
data = {**data, **self.UPDATE_SCHEMA(update_data)}
# make last_scanned JSON serializeable
if LAST_SCANNED in update_data:
data[LAST_SCANNED] = data[LAST_SCANNED].isoformat()
return data
async def async_setup(hass: HomeAssistant, config: dict):
"""Set up the Tag component."""
hass.data[DOMAIN] = {}
id_manager = TagIDManager()
hass.data[DOMAIN][TAGS] = storage_collection = TagStorageCollection(
Store(hass, STORAGE_VERSION, STORAGE_KEY),
logging.getLogger(f"{__name__}.storage_collection"),
id_manager,
)
await storage_collection.async_load()
collection.StorageCollectionWebsocket(
storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS
).async_setup(hass)
return True
@bind_hass
async def async_scan_tag(hass, tag_id, device_id, context=None):
"""Handle when a tag is scanned."""
if DOMAIN not in hass.config.components:
raise HomeAssistantError("tag component has not been set up.")
hass.bus.async_fire(
EVENT_TAG_SCANNED, {TAG_ID: tag_id, DEVICE_ID: device_id}, context=context
)
helper = hass.data[DOMAIN][TAGS]
if tag_id in helper.data:
await helper.async_update_item(tag_id, {LAST_SCANNED: dt_util.utcnow()})
else:
await helper.async_create_item({TAG_ID: tag_id, LAST_SCANNED: dt_util.utcnow()})
_LOGGER.debug("Tag: %s scanned by device: %s", tag_id, device_id)