Skip to content

Commit

Permalink
Add cover and fan. Fix for dimmers.
Browse files Browse the repository at this point in the history
* fix brightness level 0 bug

* add cover support

* add fan support
  • Loading branch information
filipvh committed Dec 9, 2020
1 parent 2a62bb0 commit ed36881
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 12 deletions.
12 changes: 11 additions & 1 deletion custom_components/nhc2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .const import DOMAIN, KEY_GATEWAY, CONF_SWITCHES_AS_LIGHTS
from .helpers import extract_versions

REQUIREMENTS = ['nhc2-coco==1.1.3']
REQUIREMENTS = ['nhc2-coco==1.3.3']

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -105,6 +105,16 @@ def process_sysinfo(nhc2_sysinfo):
entry, 'switch')
)

hass.async_create_task(
hass.config_entries.async_forward_entry_setup(
entry, 'cover')
)

hass.async_create_task(
hass.config_entries.async_forward_entry_setup(
entry, 'fan')
)

return process_sysinfo

hass.data.setdefault(KEY_GATEWAY, {})[entry.entry_id] = coco
Expand Down
6 changes: 6 additions & 0 deletions custom_components/nhc2/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
LIGHT = 'Light'
SWITCH = 'Switch'
COVER = 'Cover'
FAN = 'Fan'
CONF_SWITCHES_AS_LIGHTS = 'switches_as_lights'
DEFAULT_PORT = 8883
KEY_MANUAL = 'MANUAL_IP_HOST'

ROLL_DOWN_SHUTTER = 'rolldownshutter'
SUN_BLIND = 'sunblind'
GATE = 'gate'
VENETIAN_BLIND = 'venetianblind'
29 changes: 23 additions & 6 deletions custom_components/nhc2/cover.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""Support for NHC2 switches."""
"""Support for NHC2 covers."""
import logging

from homeassistant.components.cover import CoverEntity, SUPPORT_OPEN, SUPPORT_CLOSE, SUPPORT_STOP, SUPPORT_SET_POSITION, \
ATTR_POSITION
ATTR_POSITION, DEVICE_CLASS_SHUTTER, DEVICE_CLASS_BLIND, DEVICE_CLASS_GATE
from nhc2_coco import CoCo
from nhc2_coco.coco_device_class import CoCoDeviceClass
from nhc2_coco.coco_shutter import CoCoShutter

from .const import DOMAIN, KEY_GATEWAY, BRAND, COVER
from .const import DOMAIN, KEY_GATEWAY, BRAND, COVER, ROLL_DOWN_SHUTTER, SUN_BLIND, GATE, VENETIAN_BLIND
from .helpers import nhc2_entity_processor

KEY_GATEWAY = KEY_GATEWAY
Expand All @@ -31,25 +31,42 @@ async def async_setup_entry(hass, config_entry, async_add_entities):


class NHC2HassCover(CoverEntity):
"""Representation of an NHC2 Switch."""
"""Representation of an NHC2 Cover."""

def __init__(self, nhc2shutter: CoCoShutter):
"""Initialize a switch."""
self._nhc2shutter = nhc2shutter
self._position = nhc2shutter.position
self._is_closed = (nhc2shutter.position == 0)
nhc2shutter.on_change = self._on_change

@property
def current_cover_position(self):
"""Return current position of cover. 0 is closed, 100 is open."""
return self._nhc2shutter.position
return self._position

@property
def device_class(self):
model = self._nhc2shutter.model
if model == ROLL_DOWN_SHUTTER:
return DEVICE_CLASS_SHUTTER
if model == SUN_BLIND:
return DEVICE_CLASS_BLIND
if model == GATE:
return DEVICE_CLASS_GATE
if model == VENETIAN_BLIND:
return DEVICE_CLASS_SHUTTER
# If model not known, we choose 'generic' by returning None
return None

@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP | SUPPORT_SET_POSITION

def _on_change(self):
self._is_closed = (self._nhc2shutter == 0)
self._is_closed = (self._nhc2shutter.position == 0)
self._position = self._nhc2shutter.position
self.schedule_update_ha_state()

def open_cover(self, **kwargs) -> None:
Expand Down
211 changes: 211 additions & 0 deletions custom_components/nhc2/fan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
"""Support for NHC2 lights."""
import logging
from typing import Any

from homeassistant.components.fan import SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM, FanEntity, SUPPORT_SET_SPEED
from nhc2_coco import CoCo
from nhc2_coco.coco_device_class import CoCoDeviceClass
from nhc2_coco.coco_fan import CoCoFan
from nhc2_coco.coco_fan_speed import CoCoFanSpeed
from nhc2_coco.coco_switched_fan import CoCoSwitchedFan

from .const import DOMAIN, KEY_GATEWAY, BRAND, FAN
from .helpers import nhc2_entity_processor

KEY_GATEWAY = KEY_GATEWAY
KEY_ENTITY = 'nhc2_fans'

SPEED_BOOST = 'boost'

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Load NHC2 lights based on a config entry."""
hass.data.setdefault(KEY_ENTITY, {})[config_entry.entry_id] = []
gateway: CoCo = hass.data[KEY_GATEWAY][config_entry.entry_id]
_LOGGER.debug('Platform is starting')
gateway.get_devices(CoCoDeviceClass.FANS,
nhc2_entity_processor(hass,
config_entry,
async_add_entities,
KEY_ENTITY,
lambda x: NHC2HassFan(x))
)
gateway.get_devices(CoCoDeviceClass.SWITCHED_FANS,
nhc2_entity_processor(hass,
config_entry,
async_add_entities,
KEY_ENTITY,
lambda x: NHC2HassSwitchedFan(x))
)


class NHC2HassFan(FanEntity):
"""Representation of an NHC2 Fan."""

def __init__(self, nhc2fan: CoCoFan):
"""Initialize a light."""
self._nhc2fan = nhc2fan
self._fan_speed = self._convert_fan_speed_nhc22hass(nhc2fan.fan_speed)
nhc2fan.on_change = self._on_change

def set_speed(self, speed: str) -> None:
nhc2speed = self._convert_fan_speed_hass2nhc2(speed)
self._nhc2fan.change_speed(nhc2speed)

def set_direction(self, direction: str) -> None:
pass

def turn_on(self, speed: str = None, **kwargs) -> None:
if speed is not None:
self.set_speed(speed)

def turn_off(self, **kwargs: Any) -> None:
pass

def _on_change(self):
self._fan_speed = self._convert_fan_speed_nhc22hass(self._nhc2fan.fan_speed)
self.schedule_update_ha_state()

@property
def speed(self) -> str:
"""Return the current speed."""
return self._fan_speed

@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return [SPEED_LOW,
SPEED_MEDIUM,
SPEED_HIGH,
SPEED_BOOST]

@property
def unique_id(self):
"""Return the lights UUID."""
return self._nhc2fan.uuid

@property
def uuid(self):
"""Return the lights UUID."""
return self._nhc2fan.uuid

@property
def should_poll(self):
"""Return false, since the light will push state."""
return False

@property
def name(self):
"""Return the lights name."""
return self._nhc2fan.name

@property
def available(self):
"""Return true if the light is online."""
return self._nhc2fan.online

@property
def device_info(self):
"""Return the device info."""
return {
'identifiers': {
(DOMAIN, self.unique_id)
},
'name': self.name,
'manufacturer': BRAND,
'model': FAN,
'via_hub': (DOMAIN, self._nhc2fan.profile_creation_id),
}

@property
def supported_features(self):
"""Return supported features."""
return SUPPORT_SET_SPEED

# Helper functions

def _convert_fan_speed_nhc22hass(self, fan_speed: CoCoFanSpeed) -> str:
if fan_speed == CoCoFanSpeed.HIGH:
return SPEED_HIGH
if fan_speed == CoCoFanSpeed.LOW:
return SPEED_LOW
if fan_speed == CoCoFanSpeed.MEDIUM:
return SPEED_MEDIUM
if fan_speed == CoCoFanSpeed.BOOST:
return SPEED_BOOST

def _convert_fan_speed_hass2nhc2(self, fan_speed: str) -> CoCoFanSpeed:
if fan_speed == SPEED_HIGH:
return CoCoFanSpeed.HIGH
if fan_speed == SPEED_LOW:
return CoCoFanSpeed.LOW
if fan_speed == SPEED_MEDIUM:
return CoCoFanSpeed.MEDIUM
if fan_speed == SPEED_BOOST:
return CoCoFanSpeed.BOOST


class NHC2HassSwitchedFan(FanEntity):
"""Representation of an NHC2 Fan."""

def __init__(self, nhc2switched_fan: CoCoSwitchedFan):
"""Initialize a light."""
self._nhc2switched_fan = nhc2switched_fan
self._is_on = nhc2switched_fan.is_on
nhc2switched_fan.on_change = self._on_change

def set_speed(self, speed: str) -> None:
pass

def set_direction(self, direction: str) -> None:
pass

def turn_on(self, speed: str = None, **kwargs) -> None:
self._nhc2switched_fan.turn_on()

def turn_off(self, **kwargs: Any) -> None:
self._nhc2switched_fan.turn_off()

def _on_change(self):
self._is_on = self._nhc2switched_fan.is_on
self.schedule_update_ha_state()

@property
def unique_id(self):
"""Return the lights UUID."""
return self._nhc2switched_fan.uuid

@property
def uuid(self):
"""Return the lights UUID."""
return self._nhc2switched_fan.uuid

@property
def should_poll(self):
"""Return false, since the light will push state."""
return False

@property
def name(self):
"""Return the lights name."""
return self._nhc2switched_fan.name

@property
def available(self):
"""Return true if the light is online."""
return self._nhc2switched_fan.online

@property
def device_info(self):
"""Return the device info."""
return {
'identifiers': {
(DOMAIN, self.unique_id)
},
'name': self.name,
'manufacturer': BRAND,
'model': FAN,
'via_hub': (DOMAIN, self._nhc2switched_fan.profile_creation_id),
}
17 changes: 13 additions & 4 deletions custom_components/nhc2/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
gateway: CoCo = hass.data[KEY_GATEWAY][config_entry.entry_id]
_LOGGER.debug('Platform is starting')
gateway.get_devices(CoCoDeviceClass.LIGHTS,
nhc2_entity_processor(hass, config_entry, async_add_entities,
KEY_ENTITY, lambda x: NHC2HassLight(x))
nhc2_entity_processor(hass,
config_entry,
async_add_entities,
KEY_ENTITY,
lambda x: NHC2HassLight(x))
)


Expand All @@ -34,15 +37,21 @@ def __init__(self, nhc2light: CoCoLight, optimistic=True):
self._optimistic = optimistic
self._is_on = nhc2light.is_on
if self._nhc2light.support_brightness:
self._brightness = round(self._nhc2light.brightness * 2.55)
if self._is_on is False:
self._brightness = 0
else:
self._brightness = round(self._nhc2light.brightness * 2.55)
else:
self._brightness = None
nhc2light.on_change = self._on_change

def _on_change(self):
self._is_on = self._nhc2light.is_on
if self._nhc2light.support_brightness:
self._brightness = round(self._nhc2light.brightness * 2.55)
if self._is_on is False:
self._brightness = 0
else:
self._brightness = round(self._nhc2light.brightness * 2.55)
self.schedule_update_ha_state()

def turn_off(self, **kwargs) -> None:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/nhc2/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "nhc2",
"name": "Niko Home Control II",
"requirements": ["nhc2-coco==1.1.3"],
"requirements": ["nhc2-coco==1.3.3"],
"config_flow": true,
"issue_tracker": "https://github.com/filipvh/hass-nhc2/issues",
"documentation": "https://github.com/filipvh/hass-nhc2/blob/master/README.md",
Expand Down

0 comments on commit ed36881

Please sign in to comment.