Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b81abe9
Added IHC platform
dingusdk Dec 3, 2017
4f6abc6
Updated requirements for IHC platform
dingusdk Dec 3, 2017
9afff5a
Exclude IHC from test
dingusdk Dec 3, 2017
97986c4
Correcting flake8 issues
dingusdk Dec 3, 2017
28e26c7
Fixing more flake8 issues
dingusdk Dec 3, 2017
db2fa5a
Fixed flake8 issues
dingusdk Dec 3, 2017
ce17c41
Fixing pylint issues
dingusdk Dec 3, 2017
1b2a18f
Fixed flake8 issues
dingusdk Dec 3, 2017
471bbf0
Changes from PR review.
dingusdk Jan 7, 2018
c6a9d50
STATE_UNKNOWN changed to None
dingusdk Jan 7, 2018
0b2a95f
Spelling mistake in comment
dingusdk Jan 7, 2018
4f3d821
Merge branch 'dev' into ihc-platform
dingusdk Jan 7, 2018
35308e7
Added IHC platform
dingusdk Dec 3, 2017
38108ec
Updated requirements for IHC platform
dingusdk Dec 3, 2017
3a14261
Exclude IHC from test
dingusdk Dec 3, 2017
d533156
Correcting flake8 issues
dingusdk Dec 3, 2017
241770b
Fixing more flake8 issues
dingusdk Dec 3, 2017
84fc69e
Fixed flake8 issues
dingusdk Dec 3, 2017
8b4ed8b
Fixing pylint issues
dingusdk Dec 3, 2017
0edc3a4
Fixed flake8 issues
dingusdk Dec 3, 2017
df3fbed
Changes from PR review.
dingusdk Jan 7, 2018
ec971d1
STATE_UNKNOWN changed to None
dingusdk Jan 7, 2018
be1a9aa
Spelling mistake in comment
dingusdk Jan 7, 2018
f93a617
Merge branch 'ihc-platform' of https://github.com/dingusdk/home-assis…
dingusdk Jan 7, 2018
12c6dfa
Updated requirements_all.txt with gen_requirements_app.py
dingusdk Jan 7, 2018
7bb0bfd
Pylint fix: No space allowed around keyword argument assignment
dingusdk Jan 7, 2018
1aa6a2a
PR review changes
dingusdk Jan 8, 2018
0fda18d
Moved auto setup from platforms to ihc component
dingusdk Jan 13, 2018
ba0ff92
Do no auto setup if there are no IHC products found
dingusdk Jan 13, 2018
5cfee95
Changes from PR review
dingusdk Jan 20, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ omit =
homeassistant/components/homematic.py
homeassistant/components/*/homematic.py

homeassistant/components/ihc/*
homeassistant/components/*/ihc.py

homeassistant/components/insteon_local.py
homeassistant/components/*/insteon_local.py

Expand Down
168 changes: 168 additions & 0 deletions homeassistant/components/binary_sensor/ihc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
"""
IHC binary sensor platform.
"""
# pylint: disable=too-many-arguments, too-many-instance-attributes, bare-except, missing-docstring
import logging
import voluptuous as vol

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please group and sort imports according to PEP8.
https://www.python.org/dev/peps/pep-0008/#imports

Sort the imports 🔡 within each group standard library, 3rd party and homeassistant.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

import homeassistant.helpers.config_validation as cv
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA, DEVICE_CLASSES_SCHEMA)
from homeassistant.const import STATE_UNKNOWN, CONF_NAME, CONF_TYPE, CONF_ID, CONF_BINARY_SENSORS

from homeassistant.components.ihc.const import CONF_AUTOSETUP, CONF_INVERTING
from homeassistant.components.ihc import get_ihc_platform
from homeassistant.components.ihc.ihcdevice import IHCDevice

DEPENDENCIES = ['ihc']

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_AUTOSETUP, default='False'): cv.boolean,
vol.Optional(CONF_BINARY_SENSORS) :
[{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a validator here that makes sure there is a default name if not set by the user.

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

Use the validator here:

[vol.All({...}, validate_name)]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for this I am new to python (and voluptuous) - this is really nice.

vol.Required(CONF_ID): cv.positive_int,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_TYPE): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_INVERTING): cv.boolean,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default to False.

vol.Optional(CONF_INVERTING, default=False): cv.boolean,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}]
})


PRODUCTAUTOSETUP = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PRODUCT_AUTO_SETUP

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The product auto setup has been completely changed and simplified. The configuration has been moved out of the code to a separate configuration file. This also allow the end user to modify the auto configuration (something I have had as a request from some of the users)

# Magnet contact
{'xpath': './/product_dataline[@product_identifier="_0x2109"]',
'node': 'dataline_input',
'type': 'opening',
'inverting': True},
# Pir sensors
{'xpath': './/product_dataline[@product_identifier="_0x210e"]',
'node': 'dataline_input',
'type': 'motion',
'inverting': False},
# Pir sensors twilight sensor
{'xpath': './/product_dataline[@product_identifier="_0x0"]',
'node': 'dataline_input',
'type': 'motion',
'inverting': False},
# Pir sensors alarm
{'xpath': './/product_dataline[@product_identifier="_0x210f"]',
'node': 'dataline_input',
'type': 'motion',
'inverting': False},
# Smoke detector
{'xpath': './/product_dataline[@product_identifier="_0x210a"]',
'node': 'dataline_input',
'type': 'smoke',
'inverting': False},
# leak detector
{'xpath': './/product_dataline[@product_identifier="_0x210c"]',
'node': 'dataline_input',
'type': 'moisture',
'inverting': False},
# light detector
{'xpath': './/product_dataline[@product_identifier="_0x2110"]',
'node': 'dataline_input',
'type': 'light',
'inverting': False},
]

_LOGGER = logging.getLogger(__name__)
_IHCBINARYSENSORS = {}

@MartinHjelmare MartinHjelmare Dec 21, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably store this in hass.data in a dict under IHC_DATA key instead. See below for further comments about hass.data #10916 (comment).

@dingusdk dingusdk Jan 7, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The product auto setup has been moved to a separate yaml file.
I have removed the IHCBINARYSENSORS, because it is a bad idea to be able to overwrite/change existing devices. (And it prevents using the same IHC resource for more than one device in home assistant)


# pylint: disable=unused-argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this. It's globally disabled already.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the IHC binary setsor platform."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

ihcplatform = get_ihc_platform(hass)

@MartinHjelmare MartinHjelmare Dec 21, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just access the correct key in hass.data.

ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to

    ihc = hass.data[IHC_DATA]

the get_ihc_platform is not needed (as you also say further down), this was because I did not have the dependency setup and then binary sensor could be loaded before the ihc component

devices = []
if config.get(CONF_AUTOSETUP):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use dict.get if you don't need to.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

auto_setup(ihcplatform, devices)

binarysensors = config.get(CONF_BINARY_SENSORS)
if binarysensors:

@MartinHjelmare MartinHjelmare Dec 21, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, since we now default to empty list.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

_LOGGER.info("Adding IHC Binary Sensors")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this since you log below when adding the individual sensors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

for binarysensor in binarysensors:
ihcid = binarysensor[CONF_ID]
name = binarysensor[CONF_NAME] if CONF_NAME in binarysensor else "ihc_" + str(ihcid)
sensortype = binarysensor[CONF_TYPE] if CONF_TYPE in binarysensor else None
inverting = binarysensor[CONF_INVERTING] if CONF_INVERTING in binarysensor else False
add_sensor(devices, ihcplatform.ihc, int(ihcid), name, sensortype, True, inverting)

add_devices(devices)
# Start notification after devices has been added
for device in devices:
device.ihc.add_notify_event(device.get_ihcid(), device.on_ihc_change, True)

def auto_setup(ihcplatform, devices):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could move this to the ihc component and make it reusable for all ihc platforms. Why doesn't the sensor platform have a add_sensor_from_node function?

If needed you can store the devices in hass.data in a platform specific key (hass.data[IHC_DATA]['ihc_binary_sensor_devices']). You can create the constant for the key like this and then use string formatting to add the platform when needed:

IHC_PLATFORM_DEVICES = 'ihc_{}_devices'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Product auto setup completely changed - see my comment on PRODUCTAUTOSETUP

"""auto setup ihc binary sensors from ihc project."""
_LOGGER.info("Auto setup - IHC Binary sensors")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug level at most.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

def setup_product(ihcid, name, product, productcfg):
add_sensor_from_node(devices, ihcplatform.ihc, ihcid, name,
product, productcfg['type'],
productcfg['inverting'])
ihcplatform.autosetup(PRODUCTAUTOSETUP, setup_product)


class IHCBinarySensor(IHCDevice, BinarySensorDevice):
"""IHC Binary Sensor."""
def __init__(self, ihccontroller, name, ihcid, sensortype: str, inverting: bool,
ihcname: str, ihcnote: str, ihcposition: str):
IHCDevice.__init__(self, ihccontroller, name, ihcid, ihcname, ihcnote, ihcposition)
self._state = STATE_UNKNOWN

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Init state as None.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used STATE_UNKNOWN because I looked at binary_sensor/maxcube. I can see other platforms also using None, so I have changed it (I guess you know better than me)

self._sensor_type = sensortype
self.inverting = inverting

@property
def should_poll(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move this to the main device class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"""Return the polling state."""
return False

@property
def device_class(self):
"""Return the class of this sensor."""
return self._sensor_type

@property
def is_on(self):
"""Return true if the binary sensor is on/open."""
return self._state

def update(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this if not needed.

@dingusdk dingusdk Jan 7, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def update function removed

pass

def on_ihc_change(self, ihcid, value):
"""Callback when ihc resource changes."""
try:
if self.inverting:
self._state = not value
else:
self._state = value
self.schedule_update_ha_state()
except:
pass


def add_sensor_from_node(devices, ihccontroller, ihcid: int, name: str,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should be able to move this function to the ihc component and make it reusable by all ihc platforms.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (Product auto setup completely changed - see other comment)

product, sensortype, inverting: bool) -> IHCBinarySensor:
"""Add a sensor from the ihc project node."""
ihcname = product.attrib['name']
ihcnote = product.attrib['note']
ihcposition = product.attrib['position']
return add_sensor(devices, ihccontroller, ihcid, name, sensortype, False,
inverting, ihcname, ihcnote, ihcposition)

def add_sensor(devices, ihccontroller, ihcid: int, name: str,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this function to the ihc component, and make the function reusable for all the different ihc platforms by passing in the dict that should store the entities and the device class that should make the entities.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the function.

sensortype: str = None, overwrite: bool = False,
inverting: bool = False, ihcname: str = "",
ihcnote: str = "", ihcposition: str = "") -> IHCBinarySensor:
"""Add a new a sensor."""
if ihcid in _IHCBINARYSENSORS:
sensor = _IHCBINARYSENSORS[ihcid]
if overwrite:
sensor.set_name(name)
_LOGGER.info("IHC sensor set name: " + name + " " + str(ihcid))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug level max. Use the "old style string formatting" for log statements. For all other cases we use new style string formatting. Never string concatenation. https://home-assistant.io/developers/development_guidelines/#log-messages

_LOGGER.debug("IHC sensor set name: %s %s", name, ihcid)

@dingusdk dingusdk Jan 7, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed this logging (because you can no longer overwrite existing, and it was for debugging)

else:
sensor = IHCBinarySensor(ihccontroller, name, ihcid, sensortype,
inverting, ihcname, ihcnote, ihcposition)
_IHCBINARYSENSORS[ihcid] = sensor
devices.append(sensor)
_LOGGER.info("IHC sensor added: " + name + " " + str(ihcid))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, how to use string formatting in the logger.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return sensor
125 changes: 125 additions & 0 deletions homeassistant/components/ihc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""
IHC platform.
"""
# pylint: disable=too-many-arguments, too-many-instance-attributes, bare-except
import time
import logging
import os.path
import asyncio
import xml.etree.ElementTree
import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.const import CONF_URL, CONF_USERNAME, CONF_PASSWORD
from homeassistant.config import load_yaml_config_file

from homeassistant.components.ihc import const

REQUIREMENTS = ['ihcsdk==2.1.0']
DOMAIN = 'ihc'

CONF_INFO = 'info'

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.Required(CONF_INFO): cv.boolean
}),
}, extra=vol.ALLOW_EXTRA)

_LOGGER = logging.getLogger(__name__)

def setup(hass, config):
"""Setyp the IHC platform."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""Set up the IHC component."""

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

from ihcsdk.ihccontroller import IHCController
url = config[DOMAIN].get(CONF_URL)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please cache the first lookup in a variable to be able to reuse it multiple times below.

conf = config[DOMAIN]
url = conf.get(CONF_URL)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

username = config[DOMAIN].get(CONF_USERNAME)
password = config[DOMAIN].get(CONF_PASSWORD)
ihc = IHCController(url, username, password)
ihc.info = config[DOMAIN].get(CONF_INFO)

if not ihc.authenticate():
_LOGGER.error("Unable to authenticate on ihc controller. Username/password may be wrong")
return False

hass.data[DOMAIN] = IHCPlatform(ihc)

@MartinHjelmare MartinHjelmare Dec 21, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the key IHC_DATA which you define as a constant at the top of the module among the other constants.

IHC_DATA = 'ihc'
IHC_CONTROLLER = 'ihc_controller'
...
hass.data[IHC_DATA][IHC_CONTROLLER] = ControllerWrapper(ihc)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to

    IHC_DATA = 'ihc'
    ...
    ihc = Ihc(hass, ihc_controller)
    hass.data[IHC_DATA] = ihc

(Similar to how the MQTT component is doing it)


#Service functions

def set_runtime_value_bool(call):
"""Set a IHC runtime bool value service function """
ihcid = int(call.data.get('ihcid', 0))
value = bool(call.data.get('value', 0))
ihc.set_runtime_value_bool(ihcid, value)

def set_runtime_value_int(call):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking, instead of creating three services, maybe one service is enough that takes a type in the service data. But that might just make things more complex. You decide.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is important to have the type correct when your set a runtime value on the IHC controller. For example if you try to set a float value with an int, it will fail. So I prefer having separate functions for each type. And now when service data is validated (see below). it is even better.

"""Set a IHC runtime integer value service function """
ihcid = int(call.data.get('ihcid', 0))
value = int(call.data.get('value', 0))
ihc.set_runtime_value_int(ihcid, value)

def set_runtime_value_float(call):
"""Set a IHC runtime float value service function """
ihcid = int(call.data.get('ihcid', 0))
value = float(call.data.get('value', 0))
ihc.set_runtime_value_float(ihcid, value)

descriptions = load_yaml_config_file(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this. See below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

os.path.join(os.path.dirname(__file__), 'services.yaml'))

hass.services.register(DOMAIN, const.SERVICE_SET_RUNTIME_VALUE_BOOL,
set_runtime_value_bool,
descriptions[const.SERVICE_SET_RUNTIME_VALUE_BOOL])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add service validation schemas for the services. The validation should validate the passed service data dict.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

hass.services.register(DOMAIN, const.SERVICE_SET_RUNTIME_VALUE_INT,
set_runtime_value_int,
descriptions[const.SERVICE_SET_RUNTIME_VALUE_INT])
hass.services.register(DOMAIN, const.SERVICE_SET_RUNTIME_VALUE_FLOAT,
set_runtime_value_float,
descriptions[const.SERVICE_SET_RUNTIME_VALUE_FLOAT])

#hass.http.register_view(IHCSetupView())
return True



class IHCPlatform:
"""Wraps the IHCController for caching of ihc project and autosetup"""
def __init__(self, ihccontroller):
self.ihc = ihccontroller
project = self.ihc.get_project()
self._project = xml.etree.ElementTree.fromstring(project)
self._groups = self._project.findall(r'.//group')

def get_project_xml(self):
"""Get the cached ihc project as xml"""
return self._project

def get_groups_xml(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need this method, since it's only used in this class. Just access the attribute _groups directly when needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"""Get the groups from the ihc project and cache the result"""
return self._groups

def autosetup(self, productautosetup, callback):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename productautosetup to product_auto_setup, to make it more legible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"""Do autosetup of a component usign the specified productautosetup"""
groups = self.get_groups_xml()
for group in groups:
groupname = group.attrib['name']
for productcfg in productautosetup:
products = group.findall(productcfg['xpath'])
for product in products:
nodes = product.findall(productcfg['node'])
for node in nodes:
if 'setting' in node.attrib and node.attrib['setting'] == 'yes':
continue
ihcid = int(node.attrib['id'].strip('_'), 0)
name = groupname + "_" + str(ihcid)
callback(ihcid, name, product, productcfg)

def get_ihc_platform(hass) -> IHCPlatform:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this function, it's not needed. Platforms that depend on the ihc component will not be set up until the component is setup.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed it. I think this was because I was missing the dependency to the Ihc component, so sometimes a platform would load before the ihc component.

"""Get the ihc platform instance from the hass configuration
This is a singleton object.
"""
while not DOMAIN in hass.data:
time.sleep(0.1)
return hass.data[DOMAIN]
11 changes: 11 additions & 0 deletions homeassistant/components/ihc/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
IHC platform constants
"""

CONF_AUTOSETUP = 'autosetup'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CONF_AUTO_SETUP = 'auto_setup'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

CONF_INVERTING = 'inverting'


SERVICE_SET_RUNTIME_VALUE_BOOL = "set_runtime_value_bool"
SERVICE_SET_RUNTIME_VALUE_INT = "set_runtime_value_int"
SERVICE_SET_RUNTIME_VALUE_FLOAT = "set_runtime_value_float"
36 changes: 36 additions & 0 deletions homeassistant/components/ihc/ihcdevice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# pylint: disable=missing-docstring, too-many-arguments

class IHCDevice:
"""Base class for all ihc devices"""
def __init__(self, ihccontroller, name, ihcid, ihcname: str, ihcnote: str, ihcposition: str):
self.ihc = ihccontroller
self._name = name
self._ihcid = ihcid

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self._ihc_id = ihc_id

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

self.ihcname = ihcname

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.ihc_name = ihc_name

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

self.ihcnote = ihcnote

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

self.ihcposition = ihcposition

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@property
def name(self):
"""Return the device name"""
return self._name

def get_ihcid(self) -> int:
"""Return the ihc resource id."""
return self._ihcid

def set_name(self, name):
"""Set the name"""
self._name = name

@property
def device_state_attributes(self):
"""Return the state attributes."""
if not self.ihc.info:
return {}
return {
'ihcid': self._ihcid,
'ihcname' : self.ihcname,
'ihcnote' : self.ihcnote,
'ihcposition' : self.ihcposition
}
26 changes: 26 additions & 0 deletions homeassistant/components/ihc/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Describes the format for available ihc services

set_runtime_value_bool:
description: Set a boolean runtime value on the ihc controller
fields:
ihcid:
description: The integer ihc resource id
value:
description: The boolean value to set

set_runtime_value_int:
description: Set a integer runtime value on the ihc controller

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Set an integer"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

fields:
ihcid:
description: The integer ihc resource id
value:
description: The integer value to set

set_runtime_value_float:
description: Set a float runtime value on the ihc controller
fields:
ihcid:
description: The integer ihc resource id
value:
description: The float value to set

Loading