Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
# E203 whitespace before ':' (disabled to improve interop with black)
# E501 line length > 79 characters
extend-ignore = E203,E501
15 changes: 15 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: pre-commit

on:
pull_request:
push:
branches-ignore:
- master

jobs:
all-hooks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: pre-commit/action@v3.0.1
5 changes: 5 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[settings]
; Align trailing comma behavior to black's behavior.
include_trailing_comma=True
; Vertical hanging indent.
multi_line_output=3
19 changes: 19 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-json
- id: check-merge-conflict
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 25.1.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 7.3.0
hooks:
- id: flake8
- repo: https://github.com/pycqa/isort
rev: 6.0.1
hooks:
- id: isort
4 changes: 2 additions & 2 deletions API_info.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Night mode:

Sensors:
```
"equipmentStatus": the running state of the system, 1=cooling, 2=overcool dehumidifying, 3=heating, 4=fan, 5=idle,
"equipmentStatus": the running state of the system, 1=cooling, 2=overcool dehumidifying, 3=heating, 4=fan, 5=idle,
“tempIndoor”: current indoor temperature, in C (thermostat measurement)
“humIndoor”: current indoor humidity, in % (thermostat measurement)
“tempOutdoor”: current outdoor temperature, in C (cloud-based)
Expand Down Expand Up @@ -197,7 +197,7 @@ Sensors:
"aq[In/Out]doorValue": AQI score
"aqIndoorParticlesLevel": TBD
"aqIndoorVOCLevel": TBD
"ctOutdoorAirTemperature": outdoor unit air temperature (measurement); needs to be divided by 10 and converted from Farenheit to Celcius. i.e., ((ctOutdoorAirTemperature / 10) - 32) * 5 / 9
"ctOutdoorAirTemperature": outdoor unit air temperature (measurement); needs to be divided by 10 and converted from Farenheit to Celcius. i.e., ((ctOutdoorAirTemperature / 10) - 32) * 5 / 9
"ctOutdoorPower": outdoor unit power usage; multiply by 10 for Watts
"ctIndoorPower": indoor unit power usage; usage TBD
"ctIFCIndoorBlowerAirflow; furnace blower aiflow in CFM"
Expand Down
73 changes: 25 additions & 48 deletions custom_components/daikinskyport/__init__.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,23 @@
"""Daikin Skyport integration."""
import os

from datetime import timedelta
from async_timeout import timeout
from requests.exceptions import RequestException
from typing import Any

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import discovery
from homeassistant.const import (
CONF_PASSWORD,
CONF_EMAIL,
CONF_NAME,
Platform
)
from homeassistant.exceptions import ConfigEntryNotReady

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_NAME, CONF_PASSWORD, Platform
from homeassistant.core import HomeAssistant
from homeassistant.util import Throttle
from homeassistant.helpers.json import save_json
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.util import Throttle

from .daikinskyport import DaikinSkyport, ExpiredTokenError
from .const import (
_LOGGER,
DOMAIN,
MANUFACTURER,
CONF_ACCESS_TOKEN,
CONF_REFRESH_TOKEN,
COORDINATOR,
DOMAIN,
MANUFACTURER,
)
from .daikinskyport import DaikinSkyport, ExpiredTokenError

MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
UNDO_UPDATE_LISTENER = "undo_update_listener"
Expand All @@ -41,6 +26,7 @@

PLATFORMS = [Platform.SENSOR, Platform.WEATHER, Platform.CLIMATE, Platform.SWITCH]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up DaikinSkyport as config entry."""
if hass.data.get(DOMAIN) is None:
Expand All @@ -50,10 +36,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
email: str = entry.data[CONF_EMAIL]
password: str = entry.data[CONF_PASSWORD]
try:
name: str = entry.options[CONF_NAME]
except (NameError, KeyError):
name: str = entry.data[CONF_NAME]
try:
access_token: str = entry.data[CONF_ACCESS_TOKEN]
refresh_token: str = entry.data[CONF_REFRESH_TOKEN]
except (NameError, KeyError):
Expand All @@ -66,29 +48,25 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"ACCESS_TOKEN": access_token,
"REFRESH_TOKEN": refresh_token,
}

assert entry.unique_id is not None
unique_id = entry.unique_id

_LOGGER.debug("Using email: %s", email)


coordinator = DaikinSkyportData(
hass, config, unique_id, entry
)
coordinator = DaikinSkyportData(hass, config, unique_id, entry)

try:
await coordinator._async_update_data()
except ExpiredTokenError as ex:
_LOGGER.warn("Unable to refresh auth token.")
_LOGGER.warn(f"Unable to refresh auth token: {ex}")
raise ConfigEntryNotReady("Unable to refresh token.")

if coordinator.daikinskyport.thermostats is None:
_LOGGER.error("No Daikin Skyport devices found to set up")
return False

# entry.async_on_unload(entry.add_update_listener(update_listener))

# entry.async_on_unload(entry.add_update_listener(update_listener))

for platform in PLATFORMS:
if entry.options.get(platform, True):
Expand All @@ -98,26 +76,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

hass.data[DOMAIN][entry.entry_id] = {
COORDINATOR: coordinator,
UNDO_UPDATE_LISTENER: undo_listener
UNDO_UPDATE_LISTENER: undo_listener,
}

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
_LOGGER.debug("Unload Entry: %s", str(entry))
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENER]()

if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)


return unload_ok


Expand All @@ -127,21 +105,21 @@ async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update listener."""
_LOGGER.debug("Update listener: %s", str(entry))


# await hass.config_entries.async_reload(entry.entry_id)


class DaikinSkyportData:
"""Get the latest data and update the states."""

def __init__(
self,
hass: HomeAssistant,
config,
unique_id: str,
entry: ConfigEntry) -> None:
self, hass: HomeAssistant, config, unique_id: str, entry: ConfigEntry
) -> None:
"""Init the Daikin Skyport data object."""
self.platforms = []
try:
Expand All @@ -156,13 +134,13 @@ def __init__(
identifiers={(DOMAIN, unique_id)},
manufacturer=MANUFACTURER,
name=self.name,
)
)

@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def _async_update_data(self):
"""Update data via library."""
try:
current = await self.hass.async_add_executor_job(self.daikinskyport.update)
await self.hass.async_add_executor_job(self.daikinskyport.update)
_LOGGER.debug("Daikin Skyport _async_update_data")
except ExpiredTokenError:
_LOGGER.debug("Daikin Skyport tokens expired")
Expand All @@ -188,4 +166,3 @@ async def async_refresh(self) -> bool:
return True
_LOGGER.error("Error refreshing Daikin Skyport tokens")
return False

Loading