Skip to content

Commit

Permalink
Merge pull request #34 from PeteRager/0.0.5
Browse files Browse the repository at this point in the history
Add support for ventilation switch, allergenMode and fix startup issue
  • Loading branch information
PeteRager authored Jul 19, 2021
2 parents d87d9c6 + da405d6 commit e80cf24
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 4 deletions.
23 changes: 22 additions & 1 deletion custom_components/lennoxs30/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
)

CONF_FAST_POLL_INTERVAL = "fast_scan_interval"
CONF_ALLERGEN_DEFENDER_SWITCH = "allergen_defender_switch"
DEFAULT_POLL_INTERVAL: int = 10
DEFAULT_FAST_POLL_INTERVAL: float = 0.75
MAX_ERRORS = 5
Expand All @@ -54,6 +55,7 @@
vol.Optional(
CONF_FAST_POLL_INTERVAL, default=DEFAULT_FAST_POLL_INTERVAL
): cv.positive_float,
vol.Optional(CONF_ALLERGEN_DEFENDER_SWITCH, default=False): cv.boolean,
}
)
},
Expand All @@ -77,11 +79,21 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
else:
fast_poll_interval = DEFAULT_FAST_POLL_INTERVAL

allergenDefenderSwitch = config.get(DOMAIN).get(CONF_ALLERGEN_DEFENDER_SWITCH)

_LOGGER.debug(
f"async_setup starting scan_interval [{poll_interval}] fast_scan_interval[{fast_poll_interval}]"
)

manager = Manager(hass, config, email, password, poll_interval, fast_poll_interval)
manager = Manager(
hass,
config,
email,
password,
poll_interval,
fast_poll_interval,
allergenDefenderSwitch,
)
try:
await manager.s30_initalize()
except S30Exception as e:
Expand Down Expand Up @@ -115,6 +127,7 @@ def __init__(
password: str,
poll_interval: int,
fast_poll_interval: float,
allergenDefenderSwitch: bool,
):
self._reinitialize: bool = False
self._err_cnt: int = 0
Expand All @@ -128,6 +141,7 @@ def __init__(
self._api: s30api_async = s30api_async(email, password)
self._shutdown = False
self._retrieve_task = None
self._allergenDefenderSwitch = allergenDefenderSwitch

async def async_shutdown(self, event: Event) -> None:
_LOGGER.debug("async_shutdown started")
Expand Down Expand Up @@ -160,6 +174,10 @@ async def s30_initalize(self):
self._hass.helpers.discovery.load_platform(
"sensor", DOMAIN, self, self._config
)
self._hass.helpers.discovery.load_platform(
"switch", DOMAIN, self, self._config
)

self._climate_entities_initialized = True
self.updateState(DS_CONNECTED)

Expand Down Expand Up @@ -199,6 +217,9 @@ async def configuration_initialization(self) -> None:
await asyncio.sleep(self._fast_poll_interval)
await self.messagePump()
for lsystem in self._api.getSystems():
# Issue #33 - system configuration isn't complete until we've received the name from Lennox.
if lsystem.name == None:
continue
numZones = len(lsystem.getZoneList())
_LOGGER.debug(
"__init__:async_setup wait for zones system ["
Expand Down
2 changes: 1 addition & 1 deletion custom_components/lennoxs30/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def extra_state_attributes(self) -> dict[str, Any]:
attrs["fan"] = FAN_OFF
attrs["humOperation"] = self._zone.humOperation
attrs["tempOperation"] = self._zone.tempOperation
attrs["ventilation"] = self._zone.ventilation
return attrs

def update(self):
Expand Down Expand Up @@ -277,7 +278,6 @@ def hvac_modes(self):
modes.append(HVAC_MODE_HEAT_COOL)
return modes


async def async_trigger_fast_poll(self) -> None:
self._manager._mp_wakeup_event.set()

Expand Down
4 changes: 2 additions & 2 deletions custom_components/lennoxs30/manifest.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"domain": "lennoxs30",
"name": "Lennox S30 Cloud Integration",
"version": "0.0.4",
"version": "0.0.5",
"documentation": "https://github.com/PeteRager/lennoxs30",
"issuetracker" : "https://github.com/PeteRager/lennoxs30/issues",
"dependencies": [],
"requirements": ["lennoxs30api==0.0.5"],
"requirements": ["lennoxs30api==0.0.6"],
"codeowners": ["@PeteRager"],
"iot_class": "cloud_polling"
}
187 changes: 187 additions & 0 deletions custom_components/lennoxs30/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
"""Support for Lennoxs30 ventilation and allergend defender switches"""
from typing import Any
from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_FAHRENHEIT
from . import Manager
from homeassistant.core import HomeAssistant
import logging

from lennoxs30api import lennox_system

from homeassistant.components.switch import SwitchEntity, PLATFORM_SCHEMA

_LOGGER = logging.getLogger(__name__)

DOMAIN = "lennoxs30"


async def async_setup_platform(
hass, config, add_entities, discovery_info: Manager = None
) -> bool:
_LOGGER.debug("switch:async_setup_platform enter")
# Discovery info is the API that we passed in.
if discovery_info is None:
_LOGGER.error(
"switch:async_setup_platform expecting API in discovery_info, found None"
)
return False
theType = str(type(discovery_info))
if "Manager" not in theType:
_LOGGER.error(
f"switch:async_setup_platform expecting Manaager in discovery_info, found [{theType}]"
)
return False

switch_list = []
manager: Manager = discovery_info
for system in manager._api.getSystems():
_LOGGER.info(
f"async_setup_platform ventilation [{system.supports_ventilation()}]"
)
if system.supports_ventilation():
_LOGGER.info(f"Create S30 ventilation switch system [{system.sysId}]")
switch = S30VentilationSwitch(hass, manager, system)
switch_list.append(switch)
if manager._allergenDefenderSwitch == True:
_LOGGER.info(f"Create S30 allergenDefender switch system [{system.sysId}]")
switch = S30AllergenDefenderSwitch(hass, manager, system)
switch_list.append(switch)

if len(switch_list) != 0:
add_entities(switch_list, True)
_LOGGER.debug(
f"switch:async_setup_platform exit - created [{len(switch_list)}] switch entitites"
)
return True
else:
_LOGGER.info(f"switch:async_setup_platform exit - no ventilators founds")
return False


class S30VentilationSwitch(SwitchEntity):
"""Class for Lennox S30 thermostat."""

def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
self._hass = hass
self._manager = manager
self._system = system
self._system.registerOnUpdateCallback(self.update_callback)
self._myname = self._system.name + "_ventilation"

def update_callback(self):
_LOGGER.info(f"update_callback myname [{self._myname}]")
self.schedule_update_ha_state()

@property
def unique_id(self) -> str:
# HA fails with dashes in IDs
return (self._system.sysId + "_VST").replace("-", "")

@property
def extra_state_attributes(self):
"""Return the state attributes."""
attrs: dict[str, Any] = {}
attrs["ventilationRemainingTime"] = self._system.ventilationRemainingTime
attrs["ventilatingUntilTime"] = self._system.ventilatingUntilTime
attrs["diagVentilationRuntime"] = self._system.diagVentilationRuntime
return attrs

def update(self):
"""Update data from the thermostat API."""
return True

@property
def should_poll(self):
"""No polling needed."""
return False

@property
def name(self):
return self._myname

@property
def is_on(self):
return self._system.ventilationMode == "on"

async def async_turn_on(self, **kwargs):
try:
await self._system.ventilation_on()
self._manager._mp_wakeup_event.set()
except Exception as e:
if hasattr(e, "message"):
_LOGGER.error("ventilation_on:async_turn_on - error:" + e.message)
else:
_LOGGER.error("ventilation_on:async_turn_on - error:" + str(e))

async def async_turn_off(self, **kwargs):
try:
await self._system.ventilation_off()
self._manager._mp_wakeup_event.set()
except Exception as e:
if hasattr(e, "message"):
_LOGGER.error("ventilation_off:async_turn_off - error:" + e.message)
else:
_LOGGER.error("ventilation_off:async_turn_off - error:" + str(e))


class S30AllergenDefenderSwitch(SwitchEntity):
"""Class for Lennox S30 thermostat."""

def __init__(self, hass: HomeAssistant, manager: Manager, system: lennox_system):
self._hass = hass
self._manager = manager
self._system = system
self._system.registerOnUpdateCallback(self.update_callback)
self._myname = self._system.name + "_allergen_defender"

def update_callback(self):
_LOGGER.info(f"update_callback myname [{self._myname}]")
self.schedule_update_ha_state()

@property
def unique_id(self) -> str:
# HA fails with dashes in IDs
return (self._system.sysId + "_ADST").replace("-", "")

@property
def extra_state_attributes(self):
"""Return the state attributes."""
return {}

def update(self):
"""Update data from the thermostat API."""
return True

@property
def should_poll(self):
"""No polling needed."""
return False

@property
def name(self):
return self._myname

@property
def is_on(self):
return self._system.allergenDefender == True

async def async_turn_on(self, **kwargs):
try:
await self._system.allergenDefender_on()
self._manager._mp_wakeup_event.set()
except Exception as e:
if hasattr(e, "message"):
_LOGGER.error("allergenDefender_on:async_turn_on - error:" + e.message)
else:
_LOGGER.error("allergenDefender_on:async_turn_on - error:" + str(e))

async def async_turn_off(self, **kwargs):
try:
await self._system.allergenDefender_off()
self._manager._mp_wakeup_event.set()
except Exception as e:
if hasattr(e, "message"):
_LOGGER.error(
"allergenDefender_off:async_turn_off - error:" + e.message
)
else:
_LOGGER.error("allergenDefender_off:async_turn_off - error:" + str(e))

0 comments on commit e80cf24

Please sign in to comment.