<gh_stars>0
"""
Support for Haiku with SenseME ceiling fan and lights.

For more details about this platform, please refer to the documentation at
https://github.com/mikelawrence/homeassistant-custom-components
"""
import logging
import voluptuous as vol
from datetime import timedelta

from homeassistant.const import (CONF_INCLUDE, CONF_NAME, CONF_FRIENDLY_NAME)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.event import track_time_interval
from homeassistant.util import Throttle
from homeassistant.components.fan import (DIRECTION_FORWARD, DIRECTION_REVERSE)

# SenseMe Python library by <NAME>
REQUIREMENTS = ['https://github.com/TomFaulkner/SenseMe/archive/d3ead08f0a5db1326abfdb678fbe3f6d170c42dd.zip#SenseMe==0.1.6']

# delay between SenseMe background updates (in seconds)
SENSEME_UPDATE_DELAY = 30.0

# Fan has light default value
HAS_LIGHT_DEFAULT = True

# Component update rate
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)

DOMAIN = 'senseme'

DATA_HUBS = 'fans'

CONF_HAS_LIGHT = 'has_light'
CONF_IP_ADDRESS = 'ip_address'

FAN_SCHEMA = vol.Schema({
    vol.Required(CONF_NAME): cv.string,
    vol.Optional(CONF_FRIENDLY_NAME): cv.string,
    vol.Optional(CONF_IP_ADDRESS): cv.string,
    vol.Optional(CONF_HAS_LIGHT, default=HAS_LIGHT_DEFAULT): cv.boolean})

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Optional(CONF_INCLUDE, default=[]): vol.All(
            cv.ensure_list, [FAN_SCHEMA]),
    })
}, extra=vol.ALLOW_EXTRA)

_LOGGER = logging.getLogger(__name__)


def setup(hass, config):
    """Set up the Haiku SenseME platform."""
    from senseme import SenseMe
    hubs = []
    device_list = config[DOMAIN].get(CONF_INCLUDE)
    if len(device_list) > 0:
    	for device in device_list:
                newDevice = SenseMe(ip=device.get('ip_address'), name=device.get('name'),
                        monitor_frequency=SENSEME_UPDATE_DELAY,
                        monitor=True)
                hubs.append(SenseMeHub(newDevice,
                        device.get('friendly_name'),
                        device['has_light']))

    # SenseME fan and light platforms use hub to communicate with the fan
    hass.data[DATA_HUBS] = hubs

    # Add fan and light platform
    load_platform(hass, 'fan', DOMAIN, {}, config)
    load_platform(hass, 'light', DOMAIN, {}, config)

    return True


def conv_bright_ha_to_lib(brightness) -> int:
    """Convert HA brightness scale 0-255 to library scale 0-16."""
    if brightness == 255:   # this will end up as 16 which is max
        brightness = 256
    return int(brightness / 16)


def conv_bright_lib_to_ha(brightness) -> int:
    """Convert library brightness scale 0-16 to HA scale 0-255."""
    brightness = int(brightness) * 16
    if brightness > 255:    # force big numbers into 8-bit int range
        brightness = 255
    return brightness


class SenseMeHub(object):
    """Data object and access to Haiku with SenseME fan."""

    def __init__(self, device, friendly_name, has_light):
        """Initialize the data object."""
        self._device = device
        self._fan_on = None
        self._fan_speed = None
        self._whoosh_on = None
        self._fan_direction = None
        self._light_on = None
        self._light_brightness = None
        self._friendly_name = friendly_name
        self._light_exists = has_light


    @property
    def name(self) -> str:
        """Gets name of fan."""
        return self._device.name


    @property
    def friendly_name(self) -> str:
        """Gets friendly name of fan."""
        if self._friendly_name:
            # friendly name is defined
            return self._friendly_name
        else:
            # friendly name is not defined
            return self._device.name


    @property
    def ip(self) -> str:
        """Gets IP address of fan."""
        return self._device.ip


    @property
    def light_exists(self) -> bool:
        """Gets light exists state."""
        return self._light_exists


    @property
    def fan_on(self) -> bool:
        """Gets fan on state."""
        return self._fan_on


    @fan_on.setter
    def fan_on(self, fan_on):
        """Sets fan on state."""
        if fan_on:                  # fan was turned on
            self.fan_speed = '4'
        else:                       # fan was turned off
            self.fan_speed = 'off'


    @property
    def fan_speed(self) -> str:
        """Gets fan speed."""
        return self._fan_speed


    @fan_speed.setter
    def fan_speed(self, fan_speed):
        """Sets fan speed."""
        if fan_speed == None:       # default fan speed when not specified
            fan_speed = '4'
        self._fan_speed = fan_speed
        if fan_speed == 'off':      # fan speed set to off
            self._device.speed = 0
            # turning fan off also affects whoosh state
            self._fan_on = False
            self._whoosh_on = False
        else:                       # fan speed set to a number
            self._device.speed = int(fan_speed)
            self._fan_on = True


    @property
    def fan_direction(self) -> str:
        """Gets fan direction state."""
        return self._fan_direction


    @fan_direction.setter
    def fan_direction(self, fan_direction):
        """Sets fan direction state."""
        self._fan_direction = fan_direction
        direction = 'FWD'
        if fan_direction != DIRECTION_FORWARD:
            direction = 'REV'
        self._device._send_command(
            '<%s;FAN;DIR;SET;%s>' % (self._device.name, direction))
        self._device._update_cache('FAN;DIR', direction)


    @property
    def whoosh_on(self) -> bool:
        """Gets whoosh on state."""
        return self._whoosh_on


    @whoosh_on.setter
    def whoosh_on(self, whoosh_on):
        """Sets whoosh on state."""
        self._device.whoosh = whoosh_on
        self._whoosh_on = whoosh_on


    @property
    def light_on(self) -> bool:
        """Gets current light state."""
        return self._light_on


    @light_on.setter
    def light_on(self, light_on):
        """Sets light state."""
        # changing light on state using brightness
        if light_on:               # light was turned on
            self.light_brightness = 255
        else:                      # light was turned off
            self.light_brightness = 0


    @property
    def light_brightness(self) -> int:
        """Gets light brightness."""
        return self._light_brightness


    @light_brightness.setter
    def light_brightness(self, light_brightness):
        """Sets light brightness."""
        self._device.brightness = conv_bright_ha_to_lib(light_brightness)
        self._light_brightness = light_brightness
        # changing brightness also affects light on state
        if light_brightness == 0:
            self._light_on = False
        else:
            self._light_on = True


    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self) -> None:
        """Get the latest status from fan."""
        self._fan_on = self._device.get_attribute("FAN;PWR") == 'ON'
        self._fan_speed = self._device.get_attribute("FAN;SPD;ACTUAL")
        if self._fan_speed == '0':
            self._fan_speed = 'off'
        if self._device.get_attribute("FAN;DIR") == 'FWD':
            self._fan_direction = DIRECTION_FORWARD
        else:
            self._fan_direction = DIRECTION_REVERSE
        self._whoosh_on = self._device.get_attribute(
            "FAN;WHOOSH;STATUS") == 'ON'
        if self._light_exists:
            self._light_on = self._device.get_attribute("LIGHT;PWR") == 'ON'
            self._light_brightness = conv_bright_lib_to_ha(
                self._device.get_attribute("LIGHT;LEVEL;ACTUAL"))
        _LOGGER.debug("SenseMe: Updated fan '%s'." % self._device.name)
        return True

"""
Support for Haiku with SenseME ceiling fan and lights.

For more details about this platform, please refer to the documentation at
https://github.com/mikelawrence/homeassistant-custom-components
"""
import logging
import voluptuous as vol
from datetime import timedelta

from homeassistant.const import (CONF_INCLUDE, CONF_NAME, CONF_FRIENDLY_NAME)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.event import track_time_interval
from homeassistant.util import Throttle
from homeassistant.components.fan import (DIRECTION_FORWARD, DIRECTION_REVERSE)

# SenseMe Python library by <NAME>
REQUIREMENTS = ['https://github.com/TomFaulkner/SenseMe/archive/d3ead08f0a5db1326abfdb678fbe3f6d170c42dd.zip#SenseMe==0.1.6']

# delay between SenseMe background updates (in seconds)
SENSEME_UPDATE_DELAY = 30.0

# Fan has light default value
HAS_LIGHT_DEFAULT = True

# Component update rate
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)

DOMAIN = 'senseme'

DATA_HUBS = 'fans'

CONF_HAS_LIGHT = 'has_light'
CONF_IP_ADDRESS = 'ip_address'

FAN_SCHEMA = vol.Schema({
    vol.Required(CONF_NAME): cv.string,
    vol.Optional(CONF_FRIENDLY_NAME): cv.string,
    vol.Optional(CONF_IP_ADDRESS): cv.string,
    vol.Optional(CONF_HAS_LIGHT, default=HAS_LIGHT_DEFAULT): cv.boolean})

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Optional(CONF_INCLUDE, default=[]): vol.All(
            cv.ensure_list, [FAN_SCHEMA]),
    })
}, extra=vol.ALLOW_EXTRA)

_LOGGER = logging.getLogger(__name__)


def setup(hass, config):
    """Set up the Haiku SenseME platform."""
    from senseme import SenseMe
    hubs = []
    device_list = config[DOMAIN].get(CONF_INCLUDE)
    if len(device_list) > 0:
    	for device in device_list:
                newDevice = SenseMe(ip=device.get('ip_address'), name=device.get('name'),
                        monitor_frequency=SENSEME_UPDATE_DELAY,
                        monitor=True)
                hubs.append(SenseMeHub(newDevice,
                        device.get('friendly_name'),
                        device['has_light']))

    # SenseME fan and light platforms use hub to communicate with the fan
    hass.data[DATA_HUBS] = hubs

    # Add fan and light platform
    load_platform(hass, 'fan', DOMAIN, {}, config)
    load_platform(hass, 'light', DOMAIN, {}, config)

    return True


def conv_bright_ha_to_lib(brightness) -> int:
    """Convert HA brightness scale 0-255 to library scale 0-16."""
    if brightness == 255:   # this will end up as 16 which is max
        brightness = 256
    return int(brightness / 16)


def conv_bright_lib_to_ha(brightness) -> int:
    """Convert library brightness scale 0-16 to HA scale 0-255."""
    brightness = int(brightness) * 16
    if brightness > 255:    # force big numbers into 8-bit int range
        brightness = 255
    return brightness


class SenseMeHub(object):
    """Data object and access to Haiku with SenseME fan."""

    def __init__(self, device, friendly_name, has_light):
        """Initialize the data object."""
        self._device = device
        self._fan_on = None
        self._fan_speed = None
        self._whoosh_on = None
        self._fan_direction = None
        self._light_on = None
        self._light_brightness = None
        self._friendly_name = friendly_name
        self._light_exists = has_light


    @property
    def name(self) -> str:
        """Gets name of fan."""
        return self._device.name


    @property
    def friendly_name(self) -> str:
        """Gets friendly name of fan."""
        if self._friendly_name:
            # friendly name is defined
            return self._friendly_name
        else:
            # friendly name is not defined
            return self._device.name


    @property
    def ip(self) -> str:
        """Gets IP address of fan."""
        return self._device.ip


    @property
    def light_exists(self) -> bool:
        """Gets light exists state."""
        return self._light_exists


    @property
    def fan_on(self) -> bool:
        """Gets fan on state."""
        return self._fan_on


    @fan_on.setter
    def fan_on(self, fan_on):
        """Sets fan on state."""
        if fan_on:                  # fan was turned on
            self.fan_speed = '4'
        else:                       # fan was turned off
            self.fan_speed = 'off'


    @property
    def fan_speed(self) -> str:
        """Gets fan speed."""
        return self._fan_speed


    @fan_speed.setter
    def fan_speed(self, fan_speed):
        """Sets fan speed."""
        if fan_speed == None:       # default fan speed when not specified
            fan_speed = '4'
        self._fan_speed = fan_speed
        if fan_speed == 'off':      # fan speed set to off
            self._device.speed = 0
            # turning fan off also affects whoosh state
            self._fan_on = False
            self._whoosh_on = False
        else:                       # fan speed set to a number
            self._device.speed = int(fan_speed)
            self._fan_on = True


    @property
    def fan_direction(self) -> str:
        """Gets fan direction state."""
        return self._fan_direction


    @fan_direction.setter
    def fan_direction(self, fan_direction):
        """Sets fan direction state."""
        self._fan_direction = fan_direction
        direction = 'FWD'
        if fan_direction != DIRECTION_FORWARD:
            direction = 'REV'
        self._device._send_command(
            '<%s;FAN;DIR;SET;%s>' % (self._device.name, direction))
        self._device._update_cache('FAN;DIR', direction)


    @property
    def whoosh_on(self) -> bool:
        """Gets whoosh on state."""
        return self._whoosh_on


    @whoosh_on.setter
    def whoosh_on(self, whoosh_on):
        """Sets whoosh on state."""
        self._device.whoosh = whoosh_on
        self._whoosh_on = whoosh_on


    @property
    def light_on(self) -> bool:
        """Gets current light state."""
        return self._light_on


    @light_on.setter
    def light_on(self, light_on):
        """Sets light state."""
        # changing light on state using brightness
        if light_on:               # light was turned on
            self.light_brightness = 255
        else:                      # light was turned off
            self.light_brightness = 0


    @property
    def light_brightness(self) -> int:
        """Gets light brightness."""
        return self._light_brightness


    @light_brightness.setter
    def light_brightness(self, light_brightness):
        """Sets light brightness."""
        self._device.brightness = conv_bright_ha_to_lib(light_brightness)
        self._light_brightness = light_brightness
        # changing brightness also affects light on state
        if light_brightness == 0:
            self._light_on = False
        else:
            self._light_on = True


    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self) -> None:
        """Get the latest status from fan."""
        self._fan_on = self._device.get_attribute("FAN;PWR") == 'ON'
        self._fan_speed = self._device.get_attribute("FAN;SPD;ACTUAL")
        if self._fan_speed == '0':
            self._fan_speed = 'off'
        if self._device.get_attribute("FAN;DIR") == 'FWD':
            self._fan_direction = DIRECTION_FORWARD
        else:
            self._fan_direction = DIRECTION_REVERSE
        self._whoosh_on = self._device.get_attribute(
            "FAN;WHOOSH;STATUS") == 'ON'
        if self._light_exists:
            self._light_on = self._device.get_attribute("LIGHT;PWR") == 'ON'
            self._light_brightness = conv_bright_lib_to_ha(
                self._device.get_attribute("LIGHT;LEVEL;ACTUAL"))
        _LOGGER.debug("SenseMe: Updated fan '%s'." % self._device.name)
        return True
Support for Haiku with SenseME ceiling fan and lights.  For more details about this platform, please refer to the documentation at https://github.com/mikelawrence/homeassistant-custom-components # SenseMe Python library by <NAME> #SenseMe==0.1.6'] # delay between SenseMe background updates (in seconds) # Fan has light default value # Component update rate Set up the Haiku SenseME platform. # SenseME fan and light platforms use hub to communicate with the fan # Add fan and light platform Convert HA brightness scale 0-255 to library scale 0-16. # this will end up as 16 which is max Convert library brightness scale 0-16 to HA scale 0-255. # force big numbers into 8-bit int range Data object and access to Haiku with SenseME fan. Initialize the data object. Gets name of fan. Gets friendly name of fan. # friendly name is defined # friendly name is not defined Gets IP address of fan. Gets light exists state. Gets fan on state. Sets fan on state. # fan was turned on # fan was turned off Gets fan speed. Sets fan speed. # default fan speed when not specified # fan speed set to off # turning fan off also affects whoosh state # fan speed set to a number Gets fan direction state. Sets fan direction state. Gets whoosh on state. Sets whoosh on state. Gets current light state. Sets light state. # changing light on state using brightness # light was turned on # light was turned off Gets light brightness. Sets light brightness. # changing brightness also affects light on state Get the latest status from fan.