From 87da2ff1d7c42d19e30d2045b8da741f2d85eb30 Mon Sep 17 00:00:00 2001 From: florincosta Date: Mon, 5 Jun 2017 09:56:21 +0300 Subject: [PATCH] Add raspihats switch (#7665) --- homeassistant/components/switch/raspihats.py | 172 +++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 homeassistant/components/switch/raspihats.py diff --git a/homeassistant/components/switch/raspihats.py b/homeassistant/components/switch/raspihats.py new file mode 100644 index 00000000000..145697ef7c5 --- /dev/null +++ b/homeassistant/components/switch/raspihats.py @@ -0,0 +1,172 @@ +""" +Configure a switch using a digital output from a raspihats board. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.raspihats/ +""" +import logging +import voluptuous as vol +from homeassistant.const import ( + CONF_NAME, DEVICE_DEFAULT_NAME +) +import homeassistant.helpers.config_validation as cv +from homeassistant.components.switch import PLATFORM_SCHEMA +from homeassistant.helpers.entity import ToggleEntity +from homeassistant.components.raspihats import ( + CONF_I2C_HATS, CONF_BOARD, CONF_ADDRESS, CONF_CHANNELS, CONF_INDEX, + CONF_INVERT_LOGIC, CONF_INITIAL_STATE, I2C_HAT_NAMES, I2C_HATS_MANAGER, + I2CHatsException +) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['raspihats'] + +_CHANNELS_SCHEMA = vol.Schema([{ + vol.Required(CONF_INDEX): cv.positive_int, + vol.Required(CONF_NAME): cv.string, + vol.Optional(CONF_INVERT_LOGIC, default=False): cv.boolean, + vol.Optional(CONF_INITIAL_STATE, default=None): cv.boolean, +}]) + +_I2C_HATS_SCHEMA = vol.Schema([{ + vol.Required(CONF_BOARD): vol.In(I2C_HAT_NAMES), + vol.Required(CONF_ADDRESS): vol.Coerce(int), + vol.Required(CONF_CHANNELS): _CHANNELS_SCHEMA +}]) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_I2C_HATS): _I2C_HATS_SCHEMA, +}) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the raspihats switch devices.""" + I2CHatSwitch.I2C_HATS_MANAGER = hass.data[I2C_HATS_MANAGER] + switches = [] + i2c_hat_configs = config.get(CONF_I2C_HATS) + for i2c_hat_config in i2c_hat_configs: + board = i2c_hat_config[CONF_BOARD] + address = i2c_hat_config[CONF_ADDRESS] + try: + I2CHatSwitch.I2C_HATS_MANAGER.register_board(board, address) + for channel_config in i2c_hat_config[CONF_CHANNELS]: + switches.append( + I2CHatSwitch( + board, + address, + channel_config[CONF_INDEX], + channel_config[CONF_NAME], + channel_config[CONF_INVERT_LOGIC], + channel_config[CONF_INITIAL_STATE] + ) + ) + except I2CHatsException as ex: + _LOGGER.error( + "Failed to register " + board + "I2CHat@" + hex(address) + " " + + str(ex) + ) + add_devices(switches) + + +class I2CHatSwitch(ToggleEntity): + """Represents a switch that uses a I2C-HAT digital output.""" + + I2C_HATS_MANAGER = None + + def __init__( + self, + board, + address, + channel, + name, + invert_logic, + initial_state): + """Initialize switch.""" + self._board = board + self._address = address + self._channel = channel + self._name = name or DEVICE_DEFAULT_NAME + self._invert_logic = invert_logic + if initial_state is not None: + if self._invert_logic: + state = not initial_state + else: + state = initial_state + self.I2C_HATS_MANAGER.write_dq( + self._address, + self._channel, + state + ) + + def online_callback(): + """Callback fired when board is online.""" + self.schedule_update_ha_state() + + self.I2C_HATS_MANAGER.register_online_callback( + self._address, + self._channel, + online_callback + ) + + def _log_message(self, message): + string = self._name + " " + string += self._board + "I2CHat@" + hex(self._address) + " " + string += "channel:" + str(self._channel) + message + return string + + @property + def name(self): + """Return the name of the switch.""" + return self._name + + @property + def should_poll(self): + """Polling not needed.""" + return False + + @property + def is_on(self): + """Return true if device is on.""" + try: + state = self.I2C_HATS_MANAGER.read_dq( + self._address, + self._channel + ) + return state != self._invert_logic + except I2CHatsException as ex: + _LOGGER.error( + self._log_message("Is ON check failed, " + str(ex)) + ) + return False + + def turn_on(self): + """Turn the device on.""" + try: + state = True if self._invert_logic is False else False + self.I2C_HATS_MANAGER.write_dq( + self._address, + self._channel, + state + ) + self.schedule_update_ha_state() + except I2CHatsException as ex: + _LOGGER.error( + self._log_message("Turn ON failed, " + str(ex)) + ) + + def turn_off(self): + """Turn the device off.""" + try: + state = False if self._invert_logic is False else True + self.I2C_HATS_MANAGER.write_dq( + self._address, + self._channel, + state + ) + self.schedule_update_ha_state() + except I2CHatsException as ex: + _LOGGER.error( + self._log_message("Turn OFF failed, " + str(ex)) + )