core/homeassistant/components/ihc/auto_setup.py

148 lines
5.1 KiB
Python

"""Handle auto setup of IHC products from the ihc project file."""
import logging
import os.path
from defusedxml import ElementTree
import voluptuous as vol
from homeassistant.config import load_yaml_config_file
from homeassistant.const import CONF_TYPE, CONF_UNIT_OF_MEASUREMENT, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from .const import (
AUTO_SETUP_YAML,
CONF_BINARY_SENSOR,
CONF_DIMMABLE,
CONF_INVERTING,
CONF_LIGHT,
CONF_NODE,
CONF_SENSOR,
CONF_SWITCH,
CONF_XPATH,
DOMAIN,
IHC_PLATFORMS,
)
_LOGGER = logging.getLogger(__name__)
AUTO_SETUP_SCHEMA = vol.Schema(
{
vol.Optional(CONF_BINARY_SENSOR, default=[]): vol.All(
cv.ensure_list,
[
vol.All(
{
vol.Required(CONF_NODE): cv.string,
vol.Required(CONF_XPATH): cv.string,
vol.Optional(CONF_INVERTING, default=False): cv.boolean,
vol.Optional(CONF_TYPE): cv.string,
}
)
],
),
vol.Optional(CONF_LIGHT, default=[]): vol.All(
cv.ensure_list,
[
vol.All(
{
vol.Required(CONF_NODE): cv.string,
vol.Required(CONF_XPATH): cv.string,
vol.Optional(CONF_DIMMABLE, default=False): cv.boolean,
}
)
],
),
vol.Optional(CONF_SENSOR, default=[]): vol.All(
cv.ensure_list,
[
vol.All(
{
vol.Required(CONF_NODE): cv.string,
vol.Required(CONF_XPATH): cv.string,
vol.Optional(
CONF_UNIT_OF_MEASUREMENT, default=UnitOfTemperature.CELSIUS
): cv.string,
}
)
],
),
vol.Optional(CONF_SWITCH, default=[]): vol.All(
cv.ensure_list,
[
vol.All(
{
vol.Required(CONF_NODE): cv.string,
vol.Required(CONF_XPATH): cv.string,
}
)
],
),
}
)
def autosetup_ihc_products(hass: HomeAssistant, config, ihc_controller, controller_id):
"""Auto setup of IHC products from the IHC project file."""
if not (project_xml := ihc_controller.get_project()):
_LOGGER.error("Unable to read project from IHC controller")
return False
project = ElementTree.fromstring(project_xml)
# If an auto setup file exist in the configuration it will override
yaml_path = hass.config.path(AUTO_SETUP_YAML)
if not os.path.isfile(yaml_path):
yaml_path = os.path.join(os.path.dirname(__file__), AUTO_SETUP_YAML)
yaml = load_yaml_config_file(yaml_path)
try:
auto_setup_conf = AUTO_SETUP_SCHEMA(yaml)
except vol.Invalid as exception:
_LOGGER.error("Invalid IHC auto setup data: %s", exception)
return False
groups = project.findall(".//group")
for platform in IHC_PLATFORMS:
platform_setup = auto_setup_conf[platform]
discovery_info = get_discovery_info(platform_setup, groups, controller_id)
if discovery_info:
discovery.load_platform(hass, platform, DOMAIN, discovery_info, config)
return True
def get_discovery_info(platform_setup, groups, controller_id):
"""Get discovery info for specified IHC platform."""
discovery_data = {}
for group in groups:
groupname = group.attrib["name"]
for product_cfg in platform_setup:
products = group.findall(product_cfg[CONF_XPATH])
for product in products:
product_id = int(product.attrib["id"].strip("_"), 0)
nodes = product.findall(product_cfg[CONF_NODE])
for node in nodes:
if "setting" in node.attrib and node.attrib["setting"] == "yes":
continue
ihc_id = int(node.attrib["id"].strip("_"), 0)
name = f"{groupname}_{ihc_id}"
# make the model number look a bit nicer - strip leading _
model = product.get("product_identifier", "").lstrip("_")
device = {
"ihc_id": ihc_id,
"ctrl_id": controller_id,
"product": {
"id": product_id,
"name": product.get("name") or "",
"note": product.get("note") or "",
"position": product.get("position") or "",
"model": model,
"group": groupname,
},
"product_cfg": product_cfg,
}
discovery_data[name] = device
return discovery_data