Skip to content

Commit

Permalink
Merge pull request #152 from tijsverkoyen/improvement-0612
Browse files Browse the repository at this point in the history
Improvement 06/12
  • Loading branch information
tijsverkoyen authored Jun 14, 2024
2 parents 3cdc07a + b8aa516 commit 716c8b4
Show file tree
Hide file tree
Showing 192 changed files with 1,219 additions and 2,854 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ Action Switch.
* **Measuring Only Binary Sensor**. If on, the relay will always be on.
* **Disable Report Instant Usage Re-enabling Switch**, a toggle to disable the automatic re-enabling of the
Report Instant Usage property. This is useful if you don't need Electrical Power reporting.
* **Switching Only Binary Sensor**

__Remark:__ The totals are not available as they are not (yet) exposed by the API.

Expand All @@ -312,6 +313,7 @@ This is the energy metering linked to a generic zigbee smart plug. The smart plu
automatically be enabled.
* **Disable Report Instant Usage Re-enabling Switch**, a toggle to disable the automatic re-enabling of the
Report Instant Usage property. This is useful if you don't need Electrical Power reporting.
* **Switching Only Binary Sensor**

__Remark:__ The totals are not available as they are not (yet) exposed by the API.

Expand Down Expand Up @@ -527,6 +529,16 @@ __Remark:__ This device is not documented/supported by Niko.
* **Disable Report Instant Usage Re-enabling Switch**, a toggle to disable the automatic re-enabling of the
Report Instant Usage property. This is useful if you don't need Electrical Power reporting.
### Peakmode Action
This action is exposed as a button.
#### Entities
It has some extra entities that can be used in automations:
* **Basic State Binary Sensor**, The state is according the state of all assigned players as configured for that action.
## Not yet supported
* Sonos Speaker
Expand Down
45 changes: 32 additions & 13 deletions custom_components/nhc2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD, CONF_ADDRESS, CONF_PORT
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD, CONF_ADDRESS, CONF_PORT, \
EVENT_HOMEASSISTANT_STOP
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers import device_registry, issue_registry
from homeassistant.core import HomeAssistant

from .config_flow import Nhc2FlowHandler # noqa pylint_disable=unused-import
from .const import DOMAIN, KEY_GATEWAY, BRAND
from .nhccoco.helpers import extract_versions
from .nhccoco.const import MQTT_RC_CODES
from .nhccoco.coco import CoCo

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -76,7 +79,7 @@ async def async_setup(hass, config):

async def async_setup_entry(hass, entry):
"""Create a NHC2 gateway."""
from .nhccoco.coco import CoCo

coco = CoCo(
address=entry.data[CONF_HOST],
username=entry.data[CONF_USERNAME],
Expand All @@ -88,8 +91,8 @@ async def on_hass_stop(event):
"""Close connection when hass stops."""
coco.disconnect()

def get_process_sysinfo(dev_reg):
def process_sysinfo(nhc2_sysinfo):
def process_sysinfo(dev_reg):
def do_process_sysinfo(nhc2_sysinfo):
coco_image, nhc_version = extract_versions(nhc2_sysinfo)
_LOGGER.debug('systeminfo.published: NhcVersion: %s - CocoImage %s', nhc_version, coco_image)

Expand All @@ -108,12 +111,21 @@ async def get_or_create_device():

hass.add_job(get_or_create_device())

for platform in FORWARD_PLATFORMS:
hass.add_job(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
return do_process_sysinfo

def reload_entities():
def do_reload_entities():
if coco.entries_initialized:
for platform in FORWARD_PLATFORMS:
hass.add_job(
hass.config_entries.async_forward_entry_unload(entry, platform)
)

hass.add_job(
hass.config_entries.async_forward_entry_setups(entry, FORWARD_PLATFORMS)
)

return process_sysinfo
return do_reload_entities

def on_connection_refused(connection_result):
# Possible values for connection_result:
Expand All @@ -125,7 +137,7 @@ def on_connection_refused(connection_result):

_LOGGER.error(MQTT_RC_CODES[connection_result])

if connection_result == 5:
if connection_result in (4, 5):
coco.disconnect()
issue_registry.create_issue(
hass,
Expand All @@ -140,10 +152,17 @@ def on_connection_refused(connection_result):
hass.data.setdefault(KEY_GATEWAY, {})[entry.entry_id] = coco
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)

dev_reg = device_registry.async_get(hass)
coco.set_systeminfo_callback(process_sysinfo(dev_reg))
coco.set_devices_list_callback(reload_entities())

_LOGGER.debug('Connecting to %s with %s', entry.data[CONF_HOST], entry.data[CONF_USERNAME])
coco.connect(on_connection_refused)

dev_reg = device_registry.async_get(hass)
coco.get_systeminfo(get_process_sysinfo(dev_reg))
return True


async def async_remove_config_entry_device(
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: device_registry.DeviceEntry
) -> bool:
return True
15 changes: 15 additions & 0 deletions custom_components/nhc2/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
Nhc2GenericEnergyhomeElectricalPowerProductionThresholdExceededEntity
from .entities.generic_energyhome_report_instant_usage import Nhc2GenericEnergyhomeReportInstantUsageEntity
from .entities.generic_inverter_report_instant_usage import Nhc2GenericInverterReportInstantUsageEntity
from .entities.generic_smartplug_switching_only import Nhc2GenericSmartplugSwitchingOnlyEntity
from .entities.generic_smartplug_report_instant_usage import Nhc2GenericSmartplugReportInstantUsageEntity
from .entities.heatingcooling_action_cooling_mode import Nhc2HeatingcoolingActionCoolingModeEntity
from .entities.heatingcooling_action_heating_mode import Nhc2HeatingcoolingActionHeatingModeEntity
Expand All @@ -38,9 +39,11 @@
from .entities.motor_action_moving import Nhc2MotorActionMovingEntity
from .entities.naso_smartplug_feedback_enabled import Nhc2NasoSmartplugFeedbackEnabledEntity
from .entities.naso_smartplug_measuring_only import Nhc2NasoSmartplugMeasuringOnlyEntity
from .entities.naso_smartplug_switching_only import Nhc2NasoSmartplugSwitchingOnlyEntity
from .entities.naso_smartplug_report_instant_usage import Nhc2NasoSmartplugReportInstantUsageEntity
from .entities.overallcomfort_action_start_active import Nhc2OverallcomfortActionStartActiveEntity
from .entities.overallcomfort_action_all_started import Nhc2OverallcomfortActionAllStartedEntity
from .entities.peakmode_action_basicstate import Nhc2PeakmodeActionBasicStateEntity
from .entities.playerstatus_action_basicstate import Nhc2PlayerstatusActionBasicStateEntity
from .entities.timeschedule_action_active import Nhc2TimeschedulActionActiveEntity
from .nhccoco.devices.accesscontrol_action import CocoAccesscontrolAction
Expand All @@ -61,6 +64,7 @@
from .nhccoco.devices.hvacthermostat_hvac import CocoHvacthermostatHvac
from .nhccoco.devices.naso_smartplug import CocoNasoSmartplug
from .nhccoco.devices.overallcomfort_action import CocoOverallcomfortAction
from .nhccoco.devices.peakmode_action import CocoPeakmodeAction
from .nhccoco.devices.playerstatus_action import CocoPlayerstatusAction
from .nhccoco.devices.rolldownshutter_action import CocoRolldownshutterAction
from .nhccoco.devices.sunblind_action import CocoSunblindAction
Expand Down Expand Up @@ -214,6 +218,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities.append(Nhc2NasoSmartplugReportInstantUsageEntity(device_instance, hub, gateway))
entities.append(Nhc2NasoSmartplugFeedbackEnabledEntity(device_instance, hub, gateway))
entities.append(Nhc2NasoSmartplugMeasuringOnlyEntity(device_instance, hub, gateway))
entities.append(Nhc2NasoSmartplugSwitchingOnlyEntity(device_instance, hub, gateway))

async_add_entities(entities)

Expand All @@ -223,6 +228,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities = []
for device_instance in device_instances:
entities.append(Nhc2GenericSmartplugReportInstantUsageEntity(device_instance, hub, gateway))
entities.append(Nhc2GenericSmartplugSwitchingOnlyEntity(device_instance, hub, gateway))

async_add_entities(entities)

Expand Down Expand Up @@ -293,3 +299,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities.append(Nhc2GenericInverterReportInstantUsageEntity(device_instance, hub, gateway))

async_add_entities(entities)

device_instances = gateway.get_device_instances(CocoPeakmodeAction)
_LOGGER.info('→ Found %s Peakmode Actions (undocumented)', len(device_instances))
if len(device_instances) > 0:
entities = []
for device_instance in device_instances:
entities.append(Nhc2PeakmodeActionBasicStateEntity(device_instance, hub, gateway))

async_add_entities(entities)
11 changes: 11 additions & 0 deletions custom_components/nhc2/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
from .entities.alloff_action_button import Nhc2AlloffActionButtonEntity
from .entities.comfort_action_button import Nhc2ComfortActionButtonEntity
from .entities.electricalheating_action_button import Nhc2ElectricalHeatingActionButtonEntity
from .entities.peakmode_action_button import Nhc2PeakmodeActionButtonEntity
from .nhccoco.devices.alloff_action import CocoAlloffAction
from .nhccoco.devices.comfort_action import CocoComfortAction
from .nhccoco.devices.electricalheating_action import CocoElectricalheatingAction
from .nhccoco.devices.peakmode_action import CocoPeakmodeAction

from .const import DOMAIN, KEY_GATEWAY

Expand Down Expand Up @@ -53,3 +55,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities.append(Nhc2ElectricalHeatingActionButtonEntity(device_instance, hub, gateway))

async_add_entities(entities)

device_instances = gateway.get_device_instances(CocoPeakmodeAction)
_LOGGER.info('→ Found %s Peakmode Actions (undocumented)', len(device_instances))
if len(device_instances) > 0:
entities = []
for device_instance in device_instances:
entities.append(Nhc2PeakmodeActionButtonEntity(device_instance, hub, gateway))

async_add_entities(entities)
4 changes: 3 additions & 1 deletion custom_components/nhc2/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from .nhccoco.devices.thermostat_thermostat import CocoThermostatThermostat
from .nhccoco.devices.touchswitch_hvac import CocoTouchswitchHvac
from .nhccoco.devices.virtual_hvac import CocoVirtualHvac
from .nhccoco.devices.virtual_thermostat import CocoVirtualThermostat

from .const import DOMAIN, KEY_GATEWAY

Expand Down Expand Up @@ -52,7 +53,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(entities)

device_instances = gateway.get_device_instances(CocoThermostatThermostat)
_LOGGER.info('→ Found %s NHC Touch Switch', len(device_instances))
device_instances += gateway.get_device_instances(CocoVirtualThermostat)
_LOGGER.info('→ Found %s NHC Touch Switch, Virtual Thermostat', len(device_instances))
if len(device_instances) > 0:
entities = []
for device_instance in device_instances:
Expand Down
16 changes: 3 additions & 13 deletions custom_components/nhc2/entities/accesscontrol_action_basicstate.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
from homeassistant.components.sensor import SensorEntity, SensorDeviceClass

from ..nhccoco.devices.accesscontrol_action import CocoAccesscontrolAction
from .nhc_entity import NHCBaseEntity


class Nhc2AccesscontrolActionBasicStateEntity(SensorEntity):
class Nhc2AccesscontrolActionBasicStateEntity(NHCBaseEntity, SensorEntity):
_attr_has_entity_name = True

def __init__(self, device_instance: CocoAccesscontrolAction, hub, gateway):
"""Initialize a enum sensor."""
self._device = device_instance
self._hub = hub
self._gateway = gateway
super().__init__(device_instance, hub, gateway)

self._device.after_change_callbacks.append(self.on_change)

self._attr_available = self._device.is_online
self._attr_unique_id = device_instance.uuid + '_basic_state'
self._attr_should_poll = False
self._attr_device_info = self._device.device_info(self._hub)

self._attr_device_class = SensorDeviceClass.ENUM
self._attr_options = self._device.possible_basic_states
self._attr_native_value = self._device.basic_state
self._attr_state_class = None

@property
def name(self) -> str:
Expand All @@ -31,6 +24,3 @@ def name(self) -> str:
@property
def state(self) -> str:
return self._device.basic_state

def on_change(self):
self.schedule_update_ha_state()
Original file line number Diff line number Diff line change
@@ -1,38 +1,27 @@
from homeassistant.components.switch import SwitchEntity

from ..nhccoco.devices.accesscontrol_action import CocoAccesscontrolAction
from .nhc_entity import NHCBaseEntity


class Nhc2AccesscontrolActionBasicStateSwitchEntity(SwitchEntity):
class Nhc2AccesscontrolActionBasicStateSwitchEntity(NHCBaseEntity, SwitchEntity):
_attr_has_entity_name = True
_attr_name = None

def __init__(self, device_instance: CocoAccesscontrolAction, hub, gateway):
"""Initialize a switch."""
self._device = device_instance
self._hub = hub
self._gateway = gateway

self._device.after_change_callbacks.append(self.on_change)

self._attr_available = self._device.is_online
self._attr_unique_id = device_instance.uuid
self._attr_should_poll = False
self._attr_device_info = self._device.device_info(self._hub)
super().__init__(device_instance, hub, gateway)

@property
def is_on(self) -> bool:
return self._device.is_basic_state_on

def on_change(self):
self.schedule_update_ha_state()

async def async_turn_on(self):
if not self.is_on:
self._device.press(self._gateway)
self.on_change()
self.schedule_update_ha_state()

async def async_turn_off(self):
if self.is_on:
self._device.press(self._gateway)
self.on_change()
self.schedule_update_ha_state()
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,19 @@
from homeassistant.helpers.entity import EntityCategory

from ..nhccoco.devices.accesscontrol_action import CocoAccesscontrolAction
from .nhc_entity import NHCBaseEntity


class Nhc2AccesscontrolActionCallAnsweredEntity(BinarySensorEntity):
class Nhc2AccesscontrolActionCallAnsweredEntity(NHCBaseEntity, BinarySensorEntity):
_attr_has_entity_name = True

def __init__(self, device_instance: CocoAccesscontrolAction, hub, gateway):
"""Initialize a binary sensor."""
self._device = device_instance
self._hub = hub
self._gateway = gateway
super().__init__(device_instance, hub, gateway)

self._device.after_change_callbacks.append(self.on_change)

self._attr_available = self._device.is_online
self._attr_unique_id = device_instance.uuid + '_call_answered'
self._attr_should_poll = False
self._attr_device_info = self._device.device_info(self._hub)

self._attr_state = self._device.is_call_answered
self._attr_state_class = None
self._attr_entity_category = EntityCategory.DIAGNOSTIC

@property
Expand All @@ -31,6 +24,3 @@ def name(self) -> str:
@property
def is_on(self) -> bool:
return self._device.is_call_answered

def on_change(self):
self.schedule_update_ha_state()
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,19 @@
from homeassistant.helpers.entity import EntityCategory

from ..nhccoco.devices.accesscontrol_action import CocoAccesscontrolAction
from .nhc_entity import NHCBaseEntity


class Nhc2AccesscontrolActionCallPendingEntity(BinarySensorEntity):
class Nhc2AccesscontrolActionCallPendingEntity(NHCBaseEntity, BinarySensorEntity):
_attr_has_entity_name = True

def __init__(self, device_instance: CocoAccesscontrolAction, hub, gateway):
"""Initialize a binary sensor."""
self._device = device_instance
self._hub = hub
self._gateway = gateway
super().__init__(device_instance, hub, gateway)

self._device.after_change_callbacks.append(self.on_change)

self._attr_available = self._device.is_online
self._attr_unique_id = device_instance.uuid + '_call_pending'
self._attr_should_poll = False
self._attr_device_info = self._device.device_info(self._hub)

self._attr_state = self._device.is_call_pending
self._attr_state_class = None
self._attr_entity_category = EntityCategory.DIAGNOSTIC

@property
Expand All @@ -31,6 +24,3 @@ def name(self) -> str:
@property
def is_on(self) -> bool:
return self._device.is_call_pending

def on_change(self):
self.schedule_update_ha_state()
Loading

0 comments on commit 716c8b4

Please sign in to comment.