diff --git a/.coveragerc b/.coveragerc index ca9a6422f1b..acf72eb254c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -526,6 +526,8 @@ omit = homeassistant/components/pencom/switch.py homeassistant/components/philips_js/media_player.py homeassistant/components/pi_hole/sensor.py + homeassistant/components/pi4ioe5v9xxxx/binary_sensor.py + homeassistant/components/pi4ioe5v9xxxx/switch.py homeassistant/components/picotts/tts.py homeassistant/components/piglow/light.py homeassistant/components/pilight/* diff --git a/CODEOWNERS b/CODEOWNERS index 3983ae7364b..26b8e8b158b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -281,6 +281,7 @@ homeassistant/components/panel_iframe/* @home-assistant/frontend homeassistant/components/pcal9535a/* @Shulyaka homeassistant/components/persistent_notification/* @home-assistant/core homeassistant/components/philips_js/* @elupus +homeassistant/components/pi4ioe5v9xxxx/* @antonverburg homeassistant/components/pi_hole/* @fabaff @johnluetke homeassistant/components/pilight/* @trekky12 homeassistant/components/plaato/* @JohNan diff --git a/homeassistant/components/pi4ioe5v9xxxx/__init__.py b/homeassistant/components/pi4ioe5v9xxxx/__init__.py new file mode 100644 index 00000000000..516cfc32575 --- /dev/null +++ b/homeassistant/components/pi4ioe5v9xxxx/__init__.py @@ -0,0 +1 @@ +"""Support for controlling IO expanders from Digital.com (PI4IOE5V9570, PI4IOE5V9674, PI4IOE5V9673, PI4IOE5V96224, PI4IOE5V96248).""" diff --git a/homeassistant/components/pi4ioe5v9xxxx/binary_sensor.py b/homeassistant/components/pi4ioe5v9xxxx/binary_sensor.py new file mode 100644 index 00000000000..89f293d1e0d --- /dev/null +++ b/homeassistant/components/pi4ioe5v9xxxx/binary_sensor.py @@ -0,0 +1,80 @@ +"""Support for binary sensor using RPi GPIO.""" +import logging + +from pi4ioe5v9xxxx import pi4ioe5v9xxxx # pylint: disable=import-error +import voluptuous as vol + +from homeassistant.components.binary_sensor import PLATFORM_SCHEMA, BinarySensorDevice +from homeassistant.const import DEVICE_DEFAULT_NAME +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +CONF_INVERT_LOGIC = "invert_logic" +CONF_PINS = "pins" +CONF_I2CBUS = "i2c_bus" +CONF_I2CADDR = "i2c_address" +CONF_BITS = "bits" + +DEFAULT_INVERT_LOGIC = False +DEFAULT_BITS = 24 +DEFAULT_BUS = 1 +DEFAULT_ADDR = 0x20 + + +_SENSORS_SCHEMA = vol.Schema({cv.positive_int: cv.string}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + vol.Required(CONF_PINS): _SENSORS_SCHEMA, + vol.Optional(CONF_I2CBUS, default=DEFAULT_BUS): cv.positive_int, + vol.Optional(CONF_I2CADDR, default=DEFAULT_ADDR): cv.positive_int, + vol.Optional(CONF_BITS, default=DEFAULT_BITS): cv.positive_int, + vol.Optional(CONF_INVERT_LOGIC, default=DEFAULT_INVERT_LOGIC): cv.boolean, + } +) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the IO expander devices.""" + pins = config[CONF_PINS] + binary_sensors = [] + + pi4ioe5v9xxxx.setup( + i2c_bus=config[CONF_I2CBUS], + i2c_addr=config[CONF_I2CADDR], + bits=config[CONF_BITS], + read_mode=True, + invert=False, + ) + for pin_num, pin_name in pins.items(): + binary_sensors.append( + Pi4ioe5v9BinarySensor(pin_name, pin_num, config[CONF_INVERT_LOGIC]) + ) + add_entities(binary_sensors, True) + + +class Pi4ioe5v9BinarySensor(BinarySensorDevice): + """Represent a binary sensor that uses pi4ioe5v9xxxx IO expander in read mode.""" + + def __init__(self, name, pin, invert_logic): + """Initialize the pi4ioe5v9xxxx sensor.""" + self._name = name or DEVICE_DEFAULT_NAME + self._pin = pin + self._invert_logic = invert_logic + self._state = pi4ioe5v9xxxx.pin_from_memory(self._pin) + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def is_on(self): + """Return the state of the entity.""" + return self._state != self._invert_logic + + def update(self): + """Update the IO state.""" + pi4ioe5v9xxxx.hw_to_memory() + self._state = pi4ioe5v9xxxx.pin_from_memory(self._pin) diff --git a/homeassistant/components/pi4ioe5v9xxxx/manifest.json b/homeassistant/components/pi4ioe5v9xxxx/manifest.json new file mode 100644 index 00000000000..749c5d095a0 --- /dev/null +++ b/homeassistant/components/pi4ioe5v9xxxx/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "pi4ioe5v9xxxx", + "name": "pi4ioe5v9xxxx IO Expander", + "documentation": "https://www.home-assistant.io/integrations/pi4ioe5v9xxxx", + "requirements": ["pi4ioe5v9xxxx==0.0.2"], + "dependencies": [], + "codeowners": ["@antonverburg"] +} diff --git a/homeassistant/components/pi4ioe5v9xxxx/switch.py b/homeassistant/components/pi4ioe5v9xxxx/switch.py new file mode 100644 index 00000000000..5a889cfc318 --- /dev/null +++ b/homeassistant/components/pi4ioe5v9xxxx/switch.py @@ -0,0 +1,92 @@ +"""Allows to configure a switch using RPi GPIO.""" +import logging + +from pi4ioe5v9xxxx import pi4ioe5v9xxxx # pylint: disable=import-error +import voluptuous as vol + +from homeassistant.components.switch import PLATFORM_SCHEMA +from homeassistant.const import DEVICE_DEFAULT_NAME +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import ToggleEntity + +_LOGGER = logging.getLogger(__name__) + +CONF_PINS = "pins" +CONF_INVERT_LOGIC = "invert_logic" +CONF_I2CBUS = "i2c_bus" +CONF_I2CADDR = "i2c_address" +CONF_BITS = "bits" + +DEFAULT_INVERT_LOGIC = False +DEFAULT_BITS = 24 +DEFAULT_BUS = 1 +DEFAULT_ADDR = 0x20 + +_SWITCHES_SCHEMA = vol.Schema({cv.positive_int: cv.string}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + vol.Required(CONF_PINS): _SWITCHES_SCHEMA, + vol.Optional(CONF_I2CBUS, default=DEFAULT_BUS): cv.positive_int, + vol.Optional(CONF_I2CADDR, default=DEFAULT_ADDR): cv.positive_int, + vol.Optional(CONF_BITS, default=DEFAULT_BITS): cv.positive_int, + vol.Optional(CONF_INVERT_LOGIC, default=DEFAULT_INVERT_LOGIC): cv.boolean, + } +) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the swiches devices.""" + pins = config.get(CONF_PINS) + switches = [] + + pi4ioe5v9xxxx.setup( + i2c_bus=config[CONF_I2CBUS], + i2c_addr=config[CONF_I2CADDR], + bits=config[CONF_BITS], + read_mode=False, + invert=False, + ) + for pin, name in pins.items(): + switches.append(Pi4ioe5v9Switch(name, pin, config[CONF_INVERT_LOGIC])) + add_entities(switches) + + +class Pi4ioe5v9Switch(ToggleEntity): + """Representation of a pi4ioe5v9 IO expansion IO.""" + + def __init__(self, name, pin, invert_logic): + """Initialize the pin.""" + self._name = name or DEVICE_DEFAULT_NAME + self._pin = pin + self._invert_logic = invert_logic + self._state = False + + @property + def name(self): + """Return the name of the switch.""" + return self._name + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def is_on(self): + """Return true if device is on.""" + return self._state + + def turn_on(self, **kwargs): + """Turn the device on.""" + pi4ioe5v9xxxx.pin_to_memory(self._pin, not self._invert_logic) + pi4ioe5v9xxxx.memory_to_hw() + self._state = True + self.schedule_update_ha_state() + + def turn_off(self, **kwargs): + """Turn the device off.""" + pi4ioe5v9xxxx.pin_to_memory(self._pin, self._invert_logic) + pi4ioe5v9xxxx.memory_to_hw() + self._state = False + self.schedule_update_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 65a7af01b2b..13f994e5752 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1014,6 +1014,9 @@ pencompy==0.0.3 # homeassistant.components.unifi_direct pexpect==4.6.0 +# homeassistant.components.pi4ioe5v9xxxx +pi4ioe5v9xxxx==0.0.2 + # homeassistant.components.rpi_pfio pifacecommon==4.2.2