Xiaomi Smart WiFi Socket and Smart Power Strip integration (#9138)

* Xiaomi Smart WiFi Socket and Smart Power Strip integration

* Comment updated.

* Blank line removed.

* Typo fixed.

* Version of python-mirobo bumped.

* Version of python-mirobo bumped: Lightweight API changes.

* Additional API changes.

* Library version properly pinned again.

* Platform not ready behavior fixed.
Expose the device model as sensor attribute.
Device initialized log message added. Provides device model, firmware and hardware version.

* Component renamed: switch.xiaomi_plug -> switch.xiaomi_miio

* Revise based on review: Unused code removed. Filename updated.
This commit is contained in:
Sebastian Muszynski 2017-10-09 07:11:11 +02:00 committed by Paulus Schoutsen
parent 80140732c3
commit 603765fe92
3 changed files with 170 additions and 0 deletions

View file

@ -589,6 +589,7 @@ omit =
homeassistant/components/switch/telnet.py
homeassistant/components/switch/transmission.py
homeassistant/components/switch/wake_on_lan.py
homeassistant/components/switch/xiaomi_miio.py
homeassistant/components/telegram_bot/*
homeassistant/components/thingspeak.py
homeassistant/components/tts/amazon_polly.py

View file

@ -0,0 +1,168 @@
"""
Support for Xiaomi Smart WiFi Socket and Smart Power Strip.
For more details about this platform, please refer to the documentation
https://home-assistant.io/components/switch.xiaomi_miio/
"""
import asyncio
from functools import partial
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA, )
from homeassistant.const import (CONF_NAME, CONF_HOST, CONF_TOKEN, )
from homeassistant.exceptions import PlatformNotReady
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'Xiaomi Miio Switch'
PLATFORM = 'xiaomi_miio'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
REQUIREMENTS = ['python-mirobo==0.2.0']
ATTR_POWER = 'power'
ATTR_TEMPERATURE = 'temperature'
ATTR_LOAD_POWER = 'load_power'
ATTR_MODEL = 'model'
SUCCESS = ['ok']
# pylint: disable=unused-argument
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the switch from config."""
from mirobo import Plug, DeviceException
host = config.get(CONF_HOST)
name = config.get(CONF_NAME)
token = config.get(CONF_TOKEN)
_LOGGER.info("Initializing with host %s (token %s...)", host, token[:5])
try:
plug = Plug(host, token)
device_info = plug.info()
_LOGGER.info("%s %s %s initialized",
device_info.raw['model'],
device_info.raw['fw_ver'],
device_info.raw['hw_ver'])
xiaomi_plug_switch = XiaomiPlugSwitch(name, plug, device_info)
except DeviceException:
raise PlatformNotReady
async_add_devices([xiaomi_plug_switch], update_before_add=True)
class XiaomiPlugSwitch(SwitchDevice):
"""Representation of a Xiaomi Plug."""
def __init__(self, name, plug, device_info):
"""Initialize the plug switch."""
self._name = name
self._icon = 'mdi:power-socket'
self._device_info = device_info
self._plug = plug
self._state = None
self._state_attrs = {
ATTR_TEMPERATURE: None,
ATTR_LOAD_POWER: None,
ATTR_MODEL: self._device_info.raw['model'],
}
self._skip_update = False
@property
def should_poll(self):
"""Poll the plug."""
return True
@property
def name(self):
"""Return the name of the device if any."""
return self._name
@property
def icon(self):
"""Return the icon to use for device if any."""
return self._icon
@property
def available(self):
"""Return true when state is known."""
return self._state is not None
@property
def device_state_attributes(self):
"""Return the state attributes of the device."""
return self._state_attrs
@property
def is_on(self):
"""Return true if switch is on."""
return self._state
@asyncio.coroutine
def _try_command(self, mask_error, func, *args, **kwargs):
"""Call a plug command handling error messages."""
from mirobo import DeviceException
try:
result = yield from self.hass.async_add_job(
partial(func, *args, **kwargs))
_LOGGER.debug("Response received from plug: %s", result)
return result == SUCCESS
except DeviceException as exc:
_LOGGER.error(mask_error, exc)
return False
@asyncio.coroutine
def async_turn_on(self, **kwargs):
"""Turn the plug on."""
result = yield from self._try_command(
"Turning the plug on failed.", self._plug.on)
if result:
self._state = True
self._skip_update = True
@asyncio.coroutine
def async_turn_off(self, **kwargs):
"""Turn the plug off."""
result = yield from self._try_command(
"Turning the plug off failed.", self._plug.off)
if result:
self._state = False
self._skip_update = True
@asyncio.coroutine
def async_update(self):
"""Fetch state from the device."""
from mirobo import DeviceException
# On state change the device doesn't provide the new state immediately.
if self._skip_update:
self._skip_update = False
return
try:
state = yield from self.hass.async_add_job(self._plug.status)
_LOGGER.debug("Got new state: %s", state)
self._state = state.is_on
self._state_attrs.update({
ATTR_TEMPERATURE: state.temperature,
ATTR_LOAD_POWER: state.load_power,
})
except DeviceException as ex:
_LOGGER.error("Got exception while fetching the state: %s", ex)

View file

@ -773,6 +773,7 @@ python-juicenet==0.0.5
# python-lirc==1.2.3
# homeassistant.components.light.xiaomi_miio
# homeassistant.components.switch.xiaomi_miio
# homeassistant.components.vacuum.xiaomi_miio
python-mirobo==0.2.0