diff --git a/homeassistant/components/binary_sensor/ihc.py b/homeassistant/components/binary_sensor/ihc.py index 20937af6bfc..fb5b4c0bfc2 100644 --- a/homeassistant/components/binary_sensor/ihc.py +++ b/homeassistant/components/binary_sensor/ihc.py @@ -3,59 +3,39 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/binary_sensor.ihc/ """ -import voluptuous as vol - from homeassistant.components.binary_sensor import ( - BinarySensorDevice, PLATFORM_SCHEMA, DEVICE_CLASSES_SCHEMA) + BinarySensorDevice) from homeassistant.components.ihc import ( - validate_name, IHC_DATA, IHC_CONTROLLER, IHC_INFO) -from homeassistant.components.ihc.const import CONF_INVERTING + IHC_DATA, IHC_CONTROLLER, IHC_INFO) +from homeassistant.components.ihc.const import ( + CONF_INVERTING) from homeassistant.components.ihc.ihcdevice import IHCDevice from homeassistant.const import ( - CONF_NAME, CONF_TYPE, CONF_ID, CONF_BINARY_SENSORS) -import homeassistant.helpers.config_validation as cv + CONF_TYPE) DEPENDENCIES = ['ihc'] -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_BINARY_SENSORS, default=[]): - vol.All(cv.ensure_list, [ - vol.All({ - vol.Required(CONF_ID): cv.positive_int, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_TYPE): DEVICE_CLASSES_SCHEMA, - vol.Optional(CONF_INVERTING, default=False): cv.boolean, - }, validate_name) - ]) -}) - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC binary sensor platform.""" - ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] - info = hass.data[IHC_DATA][IHC_INFO] + if discovery_info is None: + return devices = [] - if discovery_info: - for name, device in discovery_info.items(): - ihc_id = device['ihc_id'] - product_cfg = device['product_cfg'] - product = device['product'] - sensor = IHCBinarySensor(ihc_controller, name, ihc_id, info, - product_cfg.get(CONF_TYPE), - product_cfg[CONF_INVERTING], - product) - devices.append(sensor) - else: - binary_sensors = config[CONF_BINARY_SENSORS] - for sensor_cfg in binary_sensors: - ihc_id = sensor_cfg[CONF_ID] - name = sensor_cfg[CONF_NAME] - sensor_type = sensor_cfg.get(CONF_TYPE) - inverting = sensor_cfg[CONF_INVERTING] - sensor = IHCBinarySensor(ihc_controller, name, ihc_id, info, - sensor_type, inverting) - devices.append(sensor) + for name, device in discovery_info.items(): + ihc_id = device['ihc_id'] + product_cfg = device['product_cfg'] + product = device['product'] + # Find controller that corresponds with device id + ctrl_id = device['ctrl_id'] + ihc_key = IHC_DATA.format(ctrl_id) + info = hass.data[ihc_key][IHC_INFO] + ihc_controller = hass.data[ihc_key][IHC_CONTROLLER] + sensor = IHCBinarySensor(ihc_controller, name, ihc_id, info, + product_cfg.get(CONF_TYPE), + product_cfg[CONF_INVERTING], + product) + devices.append(sensor) add_entities(devices) diff --git a/homeassistant/components/ihc/__init__.py b/homeassistant/components/ihc/__init__.py index 9b00f3bd789..052921ad37a 100644 --- a/homeassistant/components/ihc/__init__.py +++ b/homeassistant/components/ihc/__init__.py @@ -9,16 +9,18 @@ import os.path import xml.etree.ElementTree import voluptuous as vol - +from homeassistant.components.binary_sensor import ( + DEVICE_CLASSES_SCHEMA) from homeassistant.components.ihc.const import ( ATTR_IHC_ID, ATTR_VALUE, CONF_AUTOSETUP, CONF_BINARY_SENSOR, CONF_DIMMABLE, - CONF_INFO, CONF_INVERTING, CONF_LIGHT, CONF_NODE, CONF_SENSOR, CONF_SWITCH, - CONF_XPATH, SERVICE_SET_RUNTIME_VALUE_BOOL, + CONF_INFO, CONF_INVERTING, CONF_LIGHT, CONF_NODE, CONF_NOTE, CONF_POSITION, + CONF_SENSOR, CONF_SWITCH, CONF_XPATH, SERVICE_SET_RUNTIME_VALUE_BOOL, SERVICE_SET_RUNTIME_VALUE_FLOAT, SERVICE_SET_RUNTIME_VALUE_INT) from homeassistant.config import load_yaml_config_file from homeassistant.const import ( - CONF_ID, CONF_NAME, CONF_PASSWORD, CONF_TYPE, CONF_UNIT_OF_MEASUREMENT, - CONF_URL, CONF_USERNAME, TEMP_CELSIUS) + CONF_BINARY_SENSORS, CONF_ID, CONF_LIGHTS, CONF_NAME, CONF_PASSWORD, + CONF_SENSORS, CONF_SWITCHES, CONF_TYPE, CONF_UNIT_OF_MEASUREMENT, CONF_URL, + CONF_USERNAME, TEMP_CELSIUS) from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import HomeAssistantType @@ -26,21 +28,87 @@ from homeassistant.helpers.typing import HomeAssistantType REQUIREMENTS = ['ihcsdk==2.2.0'] DOMAIN = 'ihc' -IHC_DATA = 'ihc' +IHC_DATA = 'ihc{}' IHC_CONTROLLER = 'controller' IHC_INFO = 'info' AUTO_SETUP_YAML = 'ihc_auto_setup.yaml' -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_URL): cv.string, - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_AUTOSETUP, default=True): cv.boolean, - vol.Optional(CONF_INFO, default=True): cv.boolean, - }), + +def validate_name(config): + """Validate device name.""" + if CONF_NAME in config: + return config + ihcid = config[CONF_ID] + name = 'ihc_{}'.format(ihcid) + config[CONF_NAME] = name + return config + + +DEVICE_SCHEMA = vol.Schema({ + vol.Required(CONF_ID): cv.positive_int, + vol.Optional(CONF_NAME): cv.string, + vol.Optional(CONF_POSITION): cv.string, + vol.Optional(CONF_NOTE): cv.string }, extra=vol.ALLOW_EXTRA) + +SWITCH_SCHEMA = DEVICE_SCHEMA.extend({ +}) + +BINARY_SENSOR_SCHEMA = DEVICE_SCHEMA.extend({ + vol.Optional(CONF_TYPE): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_INVERTING, default=False): cv.boolean, +}) + +LIGHT_SCHEMA = DEVICE_SCHEMA.extend({ + vol.Optional(CONF_DIMMABLE, default=False): cv.boolean, +}) + +SENSOR_SCHEMA = DEVICE_SCHEMA.extend({ + vol.Optional(CONF_UNIT_OF_MEASUREMENT, + default=TEMP_CELSIUS): cv.string, +}) + +IHC_SCHEMA = vol.Schema({ + vol.Required(CONF_URL): cv.string, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_AUTOSETUP, default=True): cv.boolean, + vol.Optional(CONF_INFO, default=True): cv.boolean, + vol.Optional(CONF_BINARY_SENSORS, default=[]): + vol.All(cv.ensure_list, [ + vol.All( + BINARY_SENSOR_SCHEMA, + validate_name) + ]), + vol.Optional(CONF_LIGHTS, default=[]): + vol.All(cv.ensure_list, [ + vol.All( + LIGHT_SCHEMA, + validate_name) + ]), + vol.Optional(CONF_SENSORS, default=[]): + vol.All(cv.ensure_list, [ + vol.All( + SENSOR_SCHEMA, + validate_name) + ]), + vol.Optional(CONF_SWITCHES, default=[]): + vol.All(cv.ensure_list, [ + vol.All( + SWITCH_SCHEMA, + validate_name) + ]), +}, extra=vol.ALLOW_EXTRA) + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema(vol.All( + cv.ensure_list, + [IHC_SCHEMA] + )), +}, extra=vol.ALLOW_EXTRA) + + AUTO_SETUP_SCHEMA = vol.Schema({ vol.Optional(CONF_BINARY_SENSOR, default=[]): vol.All(cv.ensure_list, [ @@ -98,35 +166,79 @@ IHC_PLATFORMS = ('binary_sensor', 'light', 'sensor', 'switch') def setup(hass, config): + """Set up the IHC platform.""" + conf = config.get(DOMAIN) + for index, controller_conf in enumerate(conf): + if not ihc_setup(hass, config, controller_conf, index): + return False + + return True + + +def ihc_setup(hass, config, conf, controller_id): """Set up the IHC component.""" from ihcsdk.ihccontroller import IHCController - conf = config[DOMAIN] + url = conf[CONF_URL] username = conf[CONF_USERNAME] password = conf[CONF_PASSWORD] - ihc_controller = IHCController(url, username, password) + ihc_controller = IHCController(url, username, password) if not ihc_controller.authenticate(): _LOGGER.error("Unable to authenticate on IHC controller") return False if (conf[CONF_AUTOSETUP] and - not autosetup_ihc_products(hass, config, ihc_controller)): + not autosetup_ihc_products(hass, config, ihc_controller, + controller_id)): return False - - hass.data[IHC_DATA] = { + # Manual configuration + get_manual_configuration(hass, config, conf, ihc_controller, + controller_id) + # Store controler configuration + ihc_key = IHC_DATA.format(controller_id) + hass.data[ihc_key] = { IHC_CONTROLLER: ihc_controller, IHC_INFO: conf[CONF_INFO]} - setup_service_functions(hass, ihc_controller) return True -def autosetup_ihc_products(hass: HomeAssistantType, config, ihc_controller): +def get_manual_configuration(hass, config, conf, ihc_controller, + controller_id): + """Get manual configuration for IHC devices.""" + for component in IHC_PLATFORMS: + discovery_info = {} + if component in conf: + component_setup = conf.get(component) + for sensor_cfg in component_setup: + name = sensor_cfg[CONF_NAME] + device = { + 'ihc_id': sensor_cfg[CONF_ID], + 'ctrl_id': controller_id, + 'product': { + 'name': name, + 'note': sensor_cfg.get(CONF_NOTE) or '', + 'position': sensor_cfg.get(CONF_POSITION) or ''}, + 'product_cfg': { + 'type': sensor_cfg.get(CONF_TYPE), + 'inverting': sensor_cfg.get(CONF_INVERTING), + 'dimmable': sensor_cfg.get(CONF_DIMMABLE), + 'unit': sensor_cfg.get(CONF_UNIT_OF_MEASUREMENT) + } + } + discovery_info[name] = device + if discovery_info: + discovery.load_platform(hass, component, DOMAIN, + discovery_info, config) + + +def autosetup_ihc_products(hass: HomeAssistantType, config, ihc_controller, + controller_id): """Auto setup of IHC products from the IHC project file.""" project_xml = ihc_controller.get_project() if not project_xml: - _LOGGER.error("Unable to read project from ICH controller") + _LOGGER.error("Unable to read project from IHC controller") return False project = xml.etree.ElementTree.fromstring(project_xml) @@ -143,14 +255,15 @@ def autosetup_ihc_products(hass: HomeAssistantType, config, ihc_controller): groups = project.findall('.//group') for component in IHC_PLATFORMS: component_setup = auto_setup_conf[component] - discovery_info = get_discovery_info(component_setup, groups) + discovery_info = get_discovery_info(component_setup, groups, + controller_id) if discovery_info: discovery.load_platform(hass, component, DOMAIN, discovery_info, config) return True -def get_discovery_info(component_setup, groups): +def get_discovery_info(component_setup, groups, controller_id): """Get discovery info for specified IHC component.""" discovery_data = {} for group in groups: @@ -167,6 +280,7 @@ def get_discovery_info(component_setup, groups): name = '{}_{}'.format(groupname, ihc_id) device = { 'ihc_id': ihc_id, + 'ctrl_id': controller_id, 'product': { 'name': product.attrib['name'], 'note': product.attrib['note'], @@ -205,13 +319,3 @@ def setup_service_functions(hass: HomeAssistantType, ihc_controller): hass.services.register(DOMAIN, SERVICE_SET_RUNTIME_VALUE_FLOAT, set_runtime_value_float, schema=SET_RUNTIME_VALUE_FLOAT_SCHEMA) - - -def validate_name(config): - """Validate device name.""" - if CONF_NAME in config: - return config - ihcid = config[CONF_ID] - name = 'ihc_{}'.format(ihcid) - config[CONF_NAME] = name - return config diff --git a/homeassistant/components/ihc/const.py b/homeassistant/components/ihc/const.py index b06746c8e7a..d6e4d0e0d4d 100644 --- a/homeassistant/components/ihc/const.py +++ b/homeassistant/components/ihc/const.py @@ -10,6 +10,9 @@ CONF_BINARY_SENSOR = 'binary_sensor' CONF_LIGHT = 'light' CONF_SENSOR = 'sensor' CONF_SWITCH = 'switch' +CONF_NAME = 'name' +CONF_POSITION = 'position' +CONF_NOTE = 'note' ATTR_IHC_ID = 'ihc_id' ATTR_VALUE = 'value' diff --git a/homeassistant/components/light/ihc.py b/homeassistant/components/light/ihc.py index da90a53c848..f80c9b2fd6f 100644 --- a/homeassistant/components/light/ihc.py +++ b/homeassistant/components/light/ihc.py @@ -3,53 +3,39 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.ihc/ """ -import voluptuous as vol +import logging from homeassistant.components.ihc import ( - validate_name, IHC_DATA, IHC_CONTROLLER, IHC_INFO) -from homeassistant.components.ihc.const import CONF_DIMMABLE + IHC_DATA, IHC_CONTROLLER, IHC_INFO) +from homeassistant.components.ihc.const import ( + CONF_DIMMABLE) from homeassistant.components.ihc.ihcdevice import IHCDevice from homeassistant.components.light import ( - ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, PLATFORM_SCHEMA, Light) -from homeassistant.const import CONF_ID, CONF_NAME, CONF_LIGHTS -import homeassistant.helpers.config_validation as cv + ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) DEPENDENCIES = ['ihc'] -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_LIGHTS, default=[]): - vol.All(cv.ensure_list, [ - vol.All({ - vol.Required(CONF_ID): cv.positive_int, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_DIMMABLE, default=False): cv.boolean, - }, validate_name) - ]) -}) +_LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC lights platform.""" - ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] - info = hass.data[IHC_DATA][IHC_INFO] + if discovery_info is None: + return devices = [] - if discovery_info: - for name, device in discovery_info.items(): - ihc_id = device['ihc_id'] - product_cfg = device['product_cfg'] - product = device['product'] - light = IhcLight(ihc_controller, name, ihc_id, info, - product_cfg[CONF_DIMMABLE], product) - devices.append(light) - else: - lights = config[CONF_LIGHTS] - for light in lights: - ihc_id = light[CONF_ID] - name = light[CONF_NAME] - dimmable = light[CONF_DIMMABLE] - device = IhcLight(ihc_controller, name, ihc_id, info, dimmable) - devices.append(device) - + for name, device in discovery_info.items(): + ihc_id = device['ihc_id'] + product_cfg = device['product_cfg'] + product = device['product'] + # Find controller that corresponds with device id + ctrl_id = device['ctrl_id'] + ihc_key = IHC_DATA.format(ctrl_id) + info = hass.data[ihc_key][IHC_INFO] + ihc_controller = hass.data[ihc_key][IHC_CONTROLLER] + dimmable = product_cfg[CONF_DIMMABLE] + light = IhcLight(ihc_controller, name, ihc_id, info, + dimmable, product) + devices.append(light) add_entities(devices) diff --git a/homeassistant/components/sensor/ihc.py b/homeassistant/components/sensor/ihc.py index f5140838a7a..f5a45599bb7 100644 --- a/homeassistant/components/sensor/ihc.py +++ b/homeassistant/components/sensor/ihc.py @@ -3,56 +3,34 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.ihc/ """ -import voluptuous as vol - from homeassistant.components.ihc import ( - validate_name, IHC_DATA, IHC_CONTROLLER, IHC_INFO) + IHC_DATA, IHC_CONTROLLER, IHC_INFO) from homeassistant.components.ihc.ihcdevice import IHCDevice -from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( - CONF_ID, CONF_NAME, CONF_UNIT_OF_MEASUREMENT, CONF_SENSORS, - TEMP_CELSIUS) -import homeassistant.helpers.config_validation as cv + CONF_UNIT_OF_MEASUREMENT) from homeassistant.helpers.entity import Entity DEPENDENCIES = ['ihc'] -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_SENSORS, default=[]): - vol.All(cv.ensure_list, [ - vol.All({ - vol.Required(CONF_ID): cv.positive_int, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_UNIT_OF_MEASUREMENT, - default=TEMP_CELSIUS): cv.string - }, validate_name) - ]) -}) - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC sensor platform.""" - ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] - info = hass.data[IHC_DATA][IHC_INFO] + if discovery_info is None: + return devices = [] - if discovery_info: - for name, device in discovery_info.items(): - ihc_id = device['ihc_id'] - product_cfg = device['product_cfg'] - product = device['product'] - sensor = IHCSensor(ihc_controller, name, ihc_id, info, - product_cfg[CONF_UNIT_OF_MEASUREMENT], - product) - devices.append(sensor) - else: - sensors = config[CONF_SENSORS] - for sensor_cfg in sensors: - ihc_id = sensor_cfg[CONF_ID] - name = sensor_cfg[CONF_NAME] - unit = sensor_cfg[CONF_UNIT_OF_MEASUREMENT] - sensor = IHCSensor(ihc_controller, name, ihc_id, info, unit) - devices.append(sensor) - + for name, device in discovery_info.items(): + ihc_id = device['ihc_id'] + product_cfg = device['product_cfg'] + product = device['product'] + # Find controller that corresponds with device id + ctrl_id = device['ctrl_id'] + ihc_key = IHC_DATA.format(ctrl_id) + info = hass.data[ihc_key][IHC_INFO] + ihc_controller = hass.data[ihc_key][IHC_CONTROLLER] + unit = product_cfg[CONF_UNIT_OF_MEASUREMENT] + sensor = IHCSensor(ihc_controller, name, ihc_id, info, + unit, product) + devices.append(sensor) add_entities(devices) diff --git a/homeassistant/components/switch/ihc.py b/homeassistant/components/switch/ihc.py index 4ddafa228a7..e217d109cbc 100644 --- a/homeassistant/components/switch/ihc.py +++ b/homeassistant/components/switch/ihc.py @@ -3,47 +3,30 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.ihc/ """ -import voluptuous as vol - from homeassistant.components.ihc import ( - validate_name, IHC_DATA, IHC_CONTROLLER, IHC_INFO) + IHC_DATA, IHC_CONTROLLER, IHC_INFO) from homeassistant.components.ihc.ihcdevice import IHCDevice -from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA -from homeassistant.const import CONF_ID, CONF_NAME, CONF_SWITCHES -import homeassistant.helpers.config_validation as cv +from homeassistant.components.switch import SwitchDevice DEPENDENCIES = ['ihc'] -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_SWITCHES, default=[]): - vol.All(cv.ensure_list, [ - vol.All({ - vol.Required(CONF_ID): cv.positive_int, - vol.Optional(CONF_NAME): cv.string, - }, validate_name) - ]) -}) - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC switch platform.""" - ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] - info = hass.data[IHC_DATA][IHC_INFO] + if discovery_info is None: + return devices = [] - if discovery_info: - for name, device in discovery_info.items(): - ihc_id = device['ihc_id'] - product = device['product'] - switch = IHCSwitch(ihc_controller, name, ihc_id, info, product) - devices.append(switch) - else: - switches = config[CONF_SWITCHES] - for switch in switches: - ihc_id = switch[CONF_ID] - name = switch[CONF_NAME] - sensor = IHCSwitch(ihc_controller, name, ihc_id, info) - devices.append(sensor) + for name, device in discovery_info.items(): + ihc_id = device['ihc_id'] + product = device['product'] + # Find controller that corresponds with device id + ctrl_id = device['ctrl_id'] + ihc_key = IHC_DATA.format(ctrl_id) + info = hass.data[ihc_key][IHC_INFO] + ihc_controller = hass.data[ihc_key][IHC_CONTROLLER] + switch = IHCSwitch(ihc_controller, name, ihc_id, info, product) + devices.append(switch) add_entities(devices)