-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
update fan to support HA base fan changes and support UI config flow
- Loading branch information
Showing
16 changed files
with
741 additions
and
325 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,56 @@ | ||
# AirScape Whole House Fan [![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs) | ||
# AirScape Whole House Fan [![hacs][hacsbadge]][hacs] | ||
|
||
A Home Assistant custom component to control Airscape Whole House Fans with Gen2 controls. | ||
[![Github Release][release-shield]][releases] | ||
![issues] | ||
|
||
To Add a fan update your configuration.yaml: | ||
A Home Assistant custom component to integrate [Airscape Whole House Fans][airscape-url] with Gen2 controls. | ||
|
||
```yaml | ||
fan: | ||
- platform: airscape | ||
name: Whole House | ||
host: "192.168.10.249" | ||
``` | ||
## Installation via HACS (recommended) | ||
|
||
There is one other attribute supported. Setting a minimum speed value will start up the WHF with that speed and prevent any automation from reducing the speed below the minimum. | ||
[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=quielb&repository=hass-airscape) | ||
|
||
```yaml | ||
fan: | ||
- platform: airscape | ||
name: Whole House | ||
host: "192.168.10.249" | ||
minimum: 4 | ||
``` | ||
1. Follow the link [here](https://hacs.xyz/docs/faq/custom_repositories/) | ||
2. Use the custom repo link https://github.com/quielb/hass-airscape | ||
3. Select the category type `integration` | ||
4. Then once it's there (still in HACS) click the INSTALL button | ||
5. Restart Home Assistant | ||
6. Once restarted, in the HA UI go to `Configuration` (the ⚙️ in the lower left) -> `Devices and Services` click `+ Add Integration` and search for `airscape` | ||
|
||
This component adds one custom service: | ||
## Using the Airscape component | ||
|
||
``` | ||
airscape.add_time | ||
``` | ||
The basic component operation of the component implements all the features of the fan component. This integration extends the basic fan adding additional functionality specific to an Airscape whole house fan. | ||
|
||
This allows for adding an hour of time to the timer on the fan. | ||
**Services** | ||
|
||
The Airscape component has several custom services that are controlled by the minimum speed configuration option: | ||
|
||
Service | Description | ||
-- | -- | ||
`airscape.turn_on_to_minimum` | Starts the fan and sets the speed to the minimum defined configuration option | ||
`airscape.speed_up` | Increase the fan speed by one step | ||
`airscape.slow_down` | Slow down the fan speed by one step. Will not go below the defined minimum fan speed configuration option | ||
|
||
**Controls** | ||
|
||
In addition to the standard fan controls there is one addition button. When used, the button will add one hour to the timer. | ||
|
||
**Sensors** | ||
|
||
The Airscape component adds several sensors to represent the data from the fan: | ||
|
||
Sensor | Description | ||
-- | -- | ||
Attic Temperature | Readings from Attic temp sensor | ||
CFM | Current CFM of fan | ||
Power | Power usage in Watts | ||
Timer Remaining | Number of minutes remaining on shutoff timer | ||
Inside | Reading from control panel wall plate (disabled by default) | ||
Outside | Readings from deprecated outdoor data collection kit (disabled by default) | ||
Door | Binary sensor to indicate if fan doors are in motion (disabled by default) | ||
|
||
[airscape-url]: https://airscapefans.com/ | ||
[hacs]: https://github.com/custom-components/hacs | ||
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge | ||
[releases]: https://github.com/quielb/hass-airscape/releases | ||
[release-shield]: https://img.shields.io/github/v/release/quielb/hass-airscape | ||
[issues]: https://img.shields.io/github/issues/quielb/hass-airscape |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,96 @@ | ||
"""The Airscape component.""" | ||
"""The airscape integration.""" | ||
|
||
DOMAIN = "airscape" | ||
AIRSCAPE_DOMAIN = "airscape" | ||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass | ||
import logging | ||
|
||
import airscape as whf | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_HOST, Platform | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.exceptions import ConfigEntryNotReady | ||
from homeassistant.helpers.device_registry import DeviceInfo, format_mac | ||
from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||
|
||
from .const import DOMAIN | ||
from .coordinator import AirscapeCoordinator | ||
|
||
PLATFORMS: list[Platform] = [ | ||
Platform.BINARY_SENSOR, | ||
Platform.BUTTON, | ||
Platform.FAN, | ||
Platform.SENSOR, | ||
] | ||
|
||
|
||
@dataclass | ||
class AirscapeData: | ||
"""AirScape Data Class.""" | ||
|
||
type AirscapeConfigEntry = ConfigEntry[AirscapeData] # noqa: F821 | ||
|
||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: AirscapeConfigEntry) -> bool: | ||
"""Set up airscape from a config entry.""" | ||
try: | ||
device = await hass.async_add_executor_job(whf.Fan, entry.data[CONF_HOST]) | ||
except (whf.exceptions.ConnectionError, whf.exceptions.Timeout) as err: | ||
raise ConfigEntryNotReady from err | ||
dataCoordinator = AirscapeCoordinator(hass, device) | ||
await dataCoordinator.async_config_entry_first_refresh() | ||
entry.runtime_data = dataCoordinator | ||
|
||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) | ||
entry.async_on_unload(entry.add_update_listener(async_reload_entry)) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: AirscapeConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) | ||
|
||
|
||
async def async_reload_entry(hass: HomeAssistant, entry: AirscapeConfigEntry) -> None: | ||
"""Handle an options update.""" | ||
await hass.config_entries.async_reload(entry.entry_id) | ||
|
||
|
||
class AirscapeDeviceEntity(CoordinatorEntity[AirscapeCoordinator]): | ||
"""Define an Airscape device entity.""" | ||
|
||
_attr_has_entity_name = True | ||
|
||
def __init__( | ||
self, entry: ConfigEntry, entity_description, enabled_default: bool = True | ||
) -> None: | ||
"""Initialize the Airscape Entity.""" | ||
self._entry_id = entry.entry_id | ||
self._attr_enabled_default = enabled_default | ||
self._coordinator = entry.runtime_data | ||
self._attr_device_info = DeviceInfo( | ||
configuration_url=f"http://{self._coordinator.data.get('ipaddr')}", | ||
identifiers={(DOMAIN, format_mac(self._coordinator.data.get("macaddr")))}, | ||
name=f"AirScape {self._coordinator.data['model']}", | ||
manufacturer="AirScape", | ||
model=self._coordinator.data["model"], | ||
sw_version=self._coordinator.data["softver"], | ||
connections={(DOMAIN, entry.entry_id)}, | ||
) | ||
self.entity_description = entity_description | ||
self._name = entity_description.name | ||
self._type = entity_description.key | ||
self._attr_unique_id = ( | ||
f"{format_mac(entry.runtime_data.data.get("macaddr"))}_{self._type}" | ||
) | ||
super().__init__(self._coordinator) | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo: | ||
"""Retrun device information.""" | ||
return self._attr_device_info |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
"""Platform for AirScpae Fan Binary Sensor.""" | ||
|
||
import logging | ||
|
||
from homeassistant.components.binary_sensor import ( | ||
BinarySensorEntity, | ||
BinarySensorEntityDescription, | ||
) | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.device_registry import format_mac | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from . import AirscapeDeviceEntity | ||
from .const import BINARYSENSOR_ENTITY | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
PLATFORM = "binary_sensor" | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Handle creation of entity.""" | ||
|
||
buttons = [ | ||
AirscapeBinarySensor(config_entry, BINARYSENSOR_ENTITY[binary_sensor]) | ||
for binary_sensor in BINARYSENSOR_ENTITY | ||
] | ||
async_add_entities(buttons, False) | ||
|
||
|
||
class AirscapeBinarySensor(BinarySensorEntity, AirscapeDeviceEntity): | ||
"""Implementation of Airscape Whole House Fan Sensor.""" | ||
|
||
def __init__( | ||
self, entry: ConfigEntry, entity_description: BinarySensorEntityDescription | ||
) -> None: | ||
"""Initilize an AirScape Binary Sensor.""" | ||
super().__init__(entry, entity_description) | ||
|
||
@property | ||
def is_on(self) -> bool: | ||
"""Return the statof of the Damper Doors.""" | ||
return bool(self._coordinator.data["doorinprocess"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
"""Platform for AirScape Fan Button.""" | ||
|
||
import logging | ||
|
||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.device_registry import format_mac | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from . import AirscapeDeviceEntity | ||
from .const import BUTTON_ENTITY | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
PLATFORM = "button" | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Handle creation of entity.""" | ||
|
||
buttons = [ | ||
AirscapeButton(config_entry, BUTTON_ENTITY[button]) for button in BUTTON_ENTITY | ||
] | ||
async_add_entities(buttons, False) | ||
|
||
|
||
class AirscapeButton(ButtonEntity, AirscapeDeviceEntity): | ||
"""Implementation of Airscape Whole House Fan Sensor.""" | ||
|
||
def __init__( | ||
self, entry: ConfigEntry, entity_description: ButtonEntityDescription | ||
) -> None: | ||
"""Initilize an AirScape button.""" | ||
super().__init__(entry, entity_description) | ||
|
||
def press(self) -> None: | ||
"""Press the button.""" | ||
if bool(self._coordinator.data["fanspd"]): | ||
self._coordinator.fan_api.add_time() |
Oops, something went wrong.