""" Support for Sonoff smart home devices, such as smart switches (e.g. Sonoff Basic), plugs (e.g. Sonoff S20), and wall switches (e.g. Sonoff Touch), when these devices are in "LAN Mode", directly over the local network. For more details about this platform, please refer to the documentation at https://github.com/beveradb/sonoff-lan-mode-homeassistant """ import logging import homeassistant.helpers.config_validation as cv import voluptuous as vol from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) from homeassistant.const import CONF_HOST, CONF_NAME, CONF_ICON REQUIREMENTS = ['pysonofflan>=0.3.0'] _LOGGER = logging.getLogger('homeassistant.components.switch.sonoff_lan_mode') DEFAULT_NAME = 'Sonoff Switch' DEFAULT_ICON = 'mdi:flash' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_ICON, default=DEFAULT_ICON) : cv.string }) async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Sonoff LAN Mode Switch platform.""" host = config.get(CONF_HOST) name = config.get(CONF_NAME) icon = config.get(CONF_ICON) async_add_entities([HassSonoffSwitch(hass, host, name, icon)], True) class HassSonoffSwitch(SwitchDevice): """Home Assistant representation of a Sonoff LAN Mode device.""" def __init__(self, hass, host, name, icon): from pysonofflan import SonoffSwitch _LOGGER.setLevel(logging.DEBUG) self._name = name self._icon = icon self._state = None self._available = False self._shared_state = {} self._sonoff_device = SonoffSwitch( host=host, callback_after_update=self.device_update_callback, shared_state=self._shared_state, logger=_LOGGER, loop=hass.loop, ping_interval=145 ) _LOGGER.debug("HassSonoffSwitch __init__ finished creating " "SonoffSwitch") @property def icon(self): """Return the icon to use in the frontend, if any.""" return self._icon @property def name(self): _LOGGER.debug("HassSonoffSwitch returning _name: %s" % self._name) return self._name @property def available(self) -> bool: """Return if switch is available.""" _LOGGER.debug("HassSonoffSwitch returning _available: %s" % self._available) return self._available @property def is_on(self): """Return true if switch is on.""" _LOGGER.debug("HassSonoffSwitch returning _state: %s" % self._state) return self._state async def turn_on(self, **kwargs): """Turn the switch on.""" _LOGGER.info("Sonoff LAN Mode switch %s switching on" % self._name) await self._sonoff_device.turn_on() async def turn_off(self, **kwargs): """Turn the switch off.""" _LOGGER.info("Sonoff LAN Mode switch %s switching off" % self._name) await self._sonoff_device.turn_off() async def device_update_callback(self, callback_self): """Handle state updates announced by the device itself.""" _LOGGER.info( "Sonoff LAN Mode switch %s received updated state from " "the device: %s, available: %s" % (self._name, self._sonoff_device.state, self._sonoff_device.available) ) await self.async_update() @property def should_poll(self) -> bool: return False async def async_update(self): """Update the device state.""" _LOGGER.debug("HassSonoffSwitch async_update called") try: if self._sonoff_device.basic_info is None: _LOGGER.debug( "Sonoff device basic info still none, waiting for init " "message") return self._available = self._sonoff_device.available self._state = \ self._sonoff_device.state == \ self._sonoff_device.SWITCH_STATE_ON self.async_schedule_update_ha_state() except Exception as ex: if self._available: _LOGGER.warning( "Could not read state for %s: %s", self.name, ex)