Skip to content

Commit

Permalink
Add eq3btsmart integration (home-assistant#109291)
Browse files Browse the repository at this point in the history
Co-authored-by: Sid <[email protected]>
Co-authored-by: J. Nick Koston <[email protected]>
  • Loading branch information
3 people authored Mar 29, 2024
1 parent 4adbf7c commit 282cbfc
Show file tree
Hide file tree
Showing 23 changed files with 965 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@ omit =
homeassistant/components/epson/__init__.py
homeassistant/components/epson/media_player.py
homeassistant/components/epsonworkforce/sensor.py
homeassistant/components/eq3btsmart/__init__.py
homeassistant/components/eq3btsmart/climate.py
homeassistant/components/eq3btsmart/const.py
homeassistant/components/eq3btsmart/entity.py
homeassistant/components/eq3btsmart/models.py
homeassistant/components/escea/__init__.py
homeassistant/components/escea/climate.py
homeassistant/components/escea/discovery.py
Expand Down
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ homeassistant.components.energy.*
homeassistant.components.energyzero.*
homeassistant.components.enigma2.*
homeassistant.components.enphase_envoy.*
homeassistant.components.eq3btsmart.*
homeassistant.components.esphome.*
homeassistant.components.event.*
homeassistant.components.evil_genius_labs.*
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/epson/ @pszafer
/tests/components/epson/ @pszafer
/homeassistant/components/epsonworkforce/ @ThaStealth
/homeassistant/components/eq3btsmart/ @eulemitkeule @dbuezas
/tests/components/eq3btsmart/ @eulemitkeule @dbuezas
/homeassistant/components/escea/ @lazdavila
/tests/components/escea/ @lazdavila
/homeassistant/components/esphome/ @OttoWinter @jesserockz @kbx81 @bdraco
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/brands/eq3.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"domain": "eq3",
"name": "eQ-3",
"integrations": ["maxcube"]
"integrations": ["maxcube", "eq3btsmart"]
}
145 changes: 145 additions & 0 deletions homeassistant/components/eq3btsmart/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""Support for EQ3 devices."""

import asyncio
import logging
from typing import TYPE_CHECKING

from eq3btsmart import Thermostat
from eq3btsmart.exceptions import Eq3Exception
from eq3btsmart.thermostat_config import ThermostatConfig

from homeassistant.components import bluetooth
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.dispatcher import async_dispatcher_send

from .const import DOMAIN, SIGNAL_THERMOSTAT_CONNECTED, SIGNAL_THERMOSTAT_DISCONNECTED
from .models import Eq3Config, Eq3ConfigEntryData

PLATFORMS = [
Platform.CLIMATE,
]

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Handle config entry setup."""

mac_address: str | None = entry.unique_id

if TYPE_CHECKING:
assert mac_address is not None

eq3_config = Eq3Config(
mac_address=mac_address,
)

device = bluetooth.async_ble_device_from_address(
hass, mac_address.upper(), connectable=True
)

if device is None:
raise ConfigEntryNotReady(
f"[{eq3_config.mac_address}] Device could not be found"
)

thermostat = Thermostat(
thermostat_config=ThermostatConfig(
mac_address=mac_address,
),
ble_device=device,
)

eq3_config_entry = Eq3ConfigEntryData(eq3_config=eq3_config, thermostat=thermostat)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = eq3_config_entry

entry.async_on_unload(entry.add_update_listener(update_listener))
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

entry.async_create_background_task(
hass, _async_run_thermostat(hass, entry), entry.entry_id
)

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Handle config entry unload."""

if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
eq3_config_entry: Eq3ConfigEntryData = hass.data[DOMAIN].pop(entry.entry_id)
await eq3_config_entry.thermostat.async_disconnect()

return unload_ok


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Handle config entry update."""

await hass.config_entries.async_reload(entry.entry_id)


async def _async_run_thermostat(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Run the thermostat."""

eq3_config_entry: Eq3ConfigEntryData = hass.data[DOMAIN][entry.entry_id]
thermostat = eq3_config_entry.thermostat
mac_address = eq3_config_entry.eq3_config.mac_address
scan_interval = eq3_config_entry.eq3_config.scan_interval

await _async_reconnect_thermostat(hass, entry)

while True:
try:
await thermostat.async_get_status()
except Eq3Exception as e:
if not thermostat.is_connected:
_LOGGER.error(
"[%s] eQ-3 device disconnected",
mac_address,
)
async_dispatcher_send(
hass,
f"{SIGNAL_THERMOSTAT_DISCONNECTED}_{mac_address}",
)
await _async_reconnect_thermostat(hass, entry)
continue

_LOGGER.error(
"[%s] Error updating eQ-3 device: %s",
mac_address,
e,
)

await asyncio.sleep(scan_interval)


async def _async_reconnect_thermostat(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Reconnect the thermostat."""

eq3_config_entry: Eq3ConfigEntryData = hass.data[DOMAIN][entry.entry_id]
thermostat = eq3_config_entry.thermostat
mac_address = eq3_config_entry.eq3_config.mac_address
scan_interval = eq3_config_entry.eq3_config.scan_interval

while True:
try:
await thermostat.async_connect()
except Eq3Exception:
await asyncio.sleep(scan_interval)
continue

_LOGGER.debug(
"[%s] eQ-3 device connected",
mac_address,
)

async_dispatcher_send(
hass,
f"{SIGNAL_THERMOSTAT_CONNECTED}_{mac_address}",
)

return
Loading

0 comments on commit 282cbfc

Please sign in to comment.