diff --git a/homeassistant/components/ihc/__init__.py b/homeassistant/components/ihc/__init__.py index 7c556bf3713..4c5c9d72497 100644 --- a/homeassistant/components/ihc/__init__.py +++ b/homeassistant/components/ihc/__init__.py @@ -1,13 +1,10 @@ """Support for IHC devices.""" import logging -import os.path -from defusedxml import ElementTree from ihcsdk.ihccontroller import IHCController import voluptuous as vol from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA -from homeassistant.config import load_yaml_config_file from homeassistant.const import ( CONF_ID, CONF_NAME, @@ -17,13 +14,13 @@ from homeassistant.const import ( CONF_URL, CONF_USERNAME, TEMP_CELSIUS, - Platform, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import ConfigType +from .auto_setup import autosetup_ihc_products from .const import ( CONF_AUTOSETUP, CONF_BINARY_SENSOR, @@ -31,30 +28,21 @@ from .const import ( CONF_INFO, CONF_INVERTING, CONF_LIGHT, - CONF_NODE, CONF_NOTE, CONF_OFF_ID, CONF_ON_ID, CONF_POSITION, CONF_SENSOR, CONF_SWITCH, - CONF_XPATH, DOMAIN, IHC_CONTROLLER, + IHC_PLATFORMS, ) from .service_functions import setup_service_functions _LOGGER = logging.getLogger(__name__) -AUTO_SETUP_YAML = "ihc_auto_setup.yaml" - IHC_INFO = "info" -PLATFORMS = ( - Platform.BINARY_SENSOR, - Platform.LIGHT, - Platform.SENSOR, - Platform.SWITCH, -) def validate_name(config): @@ -130,62 +118,6 @@ CONFIG_SCHEMA = vol.Schema( ) -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=TEMP_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 setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the IHC integration.""" conf = config[DOMAIN] @@ -224,7 +156,7 @@ def ihc_setup(hass, config, conf, controller_id): def get_manual_configuration(hass, config, conf, ihc_controller, controller_id): """Get manual configuration for IHC devices.""" - for platform in PLATFORMS: + for platform in IHC_PLATFORMS: discovery_info = {} if platform in conf: platform_setup = conf.get(platform) @@ -250,59 +182,3 @@ def get_manual_configuration(hass, config, conf, ihc_controller, controller_id): discovery_info[name] = device if discovery_info: discovery.load_platform(hass, platform, DOMAIN, discovery_info, config) - - -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 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: - 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}" - device = { - "ihc_id": ihc_id, - "ctrl_id": controller_id, - "product": { - "name": product.get("name") or "", - "note": product.get("note") or "", - "position": product.get("position") or "", - }, - "product_cfg": product_cfg, - } - discovery_data[name] = device - return discovery_data diff --git a/homeassistant/components/ihc/auto_setup.py b/homeassistant/components/ihc/auto_setup.py new file mode 100644 index 00000000000..f782cd590c0 --- /dev/null +++ b/homeassistant/components/ihc/auto_setup.py @@ -0,0 +1,140 @@ +"""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, TEMP_CELSIUS +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=TEMP_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: + 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}" + device = { + "ihc_id": ihc_id, + "ctrl_id": controller_id, + "product": { + "name": product.get("name") or "", + "note": product.get("note") or "", + "position": product.get("position") or "", + }, + "product_cfg": product_cfg, + } + discovery_data[name] = device + return discovery_data diff --git a/homeassistant/components/ihc/const.py b/homeassistant/components/ihc/const.py index 9deaa0dbbc4..2f3651c7bb7 100644 --- a/homeassistant/components/ihc/const.py +++ b/homeassistant/components/ihc/const.py @@ -1,9 +1,12 @@ """IHC component constants.""" +from homeassistant.const import Platform ATTR_IHC_ID = "ihc_id" ATTR_VALUE = "value" ATTR_CONTROLLER_ID = "controller_id" +AUTO_SETUP_YAML = "ihc_auto_setup.yaml" + CONF_AUTOSETUP = "auto_setup" CONF_BINARY_SENSOR = "binary_sensor" CONF_DIMMABLE = "dimmable" @@ -22,6 +25,12 @@ CONF_XPATH = "xpath" DOMAIN = "ihc" IHC_CONTROLLER = "controller" +IHC_PLATFORMS = ( + Platform.BINARY_SENSOR, + Platform.LIGHT, + Platform.SENSOR, + Platform.SWITCH, +) SERVICE_SET_RUNTIME_VALUE_BOOL = "set_runtime_value_bool" SERVICE_SET_RUNTIME_VALUE_FLOAT = "set_runtime_value_float"