Skip to content

Commit

Permalink
Fixed status update delay; separated daikin_api.py
Browse files Browse the repository at this point in the history
  • Loading branch information
rospogrigio committed Jul 13, 2021
1 parent 298588d commit 36e9355
Show file tree
Hide file tree
Showing 4 changed files with 3 additions and 179 deletions.
174 changes: 1 addition & 173 deletions custom_components/daikin_residential/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
"""Platform for the Daikin AC."""
import asyncio
import datetime
import functools
import logging
import requests
import json
import time
import voluptuous as vol

from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry

# from homeassistant.exceptions import ConfigEntryNotReady
# import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util import Throttle

from .const import DOMAIN, DAIKIN_API, DAIKIN_DEVICES

from .daikin_base import Appliance
from .daikin_api import DaikinApi

_LOGGER = logging.getLogger(__name__)

Expand All @@ -34,10 +27,8 @@
TOKENSET_FILE = "tokenset.json"

MIN_TIME_BETWEEN_UPDATES = datetime.timedelta(seconds=15)
REQUEST_DELAY_TIME_s = 5

COMPONENT_TYPES = ["climate", "sensor", "switch"]
# COMPONENT_TYPES = ["sensor", "switch"]


CONFIG_SCHEMA = vol.Schema(vol.All({DOMAIN: vol.Schema({})}), extra=vol.ALLOW_EXTRA)
Expand Down Expand Up @@ -91,166 +82,3 @@ async def async_unload_entry(hass, config_entry):
async def daikin_api_setup(hass, host, key, uuid, password):
"""Create a Daikin instance only once."""
return


class DaikinApi:
"""Daikin Residential API."""

def __init__(self, hass):
"""Initialize a new Daikin Residential API."""
# super()
self.hass = hass
self.tokenSet = None
self._delay_next_request = False
tokenFile = self.hass.config.path(TOKENSET_FILE)
_LOGGER.info("Initialing Daikin Residential API (%s)...", tokenFile)
try:
with open(tokenFile) as jsonFile:
jsonObject = json.load(jsonFile)
self.tokenSet = jsonObject
jsonFile.close()
except IOError:
_LOGGER.error("tokenset.json file not found in config folder.")
raise Exception("tokenset.json file not found in config folder.")

_LOGGER.info("Initialized Daikin Residential API")
_LOGGER.debug(
"Daikin Residential API token is [%s]", self.tokenSet["access_token"]
)

async def doBearerRequest(self, resourceUrl, options=None, refreshed=False):
if self.tokenSet is None:
raise Exception(
"Please provide a TokenSet or use the Proxy server to Authenticate once"
)

if not resourceUrl.startswith("http"):
resourceUrl = "https://api.prod.unicloud.edc.dknadmin.be" + resourceUrl

headers = {
"user-agent": "Daikin/1.6.1.4681 CFNetwork/1209 Darwin/20.2.0",
"x-api-key": "xw6gvOtBHq5b1pyceadRp6rujSNSZdjx2AqT03iC",
"Authorization": "Bearer " + self.tokenSet["access_token"],
"Content-Type": "application/json",
}

_LOGGER.debug("BEARER REQUEST URL: %s", resourceUrl)
_LOGGER.debug("BEARER REQUEST HEADERS: %s", headers)
if options is not None and "method" in options and options["method"] == "PATCH":
_LOGGER.debug("BEARER REQUEST JSON: %s", options["json"])
func = functools.partial(
requests.patch,
resourceUrl,
headers=headers,
data=options["json"],
)
#res = requests.patch(resourceUrl, headers=headers, data=options["json"])
else:
func = functools.partial(
requests.get,
resourceUrl,
headers=headers,
)
#res = requests.get(resourceUrl, headers=headers)
try:
res = await self.hass.async_add_executor_job(func)
except Exception as e:
_LOGGER.error("REQUEST FAILED: %s", e)
_LOGGER.debug("BEARER RESPONSE CODE: %s", res.status_code)

if res.status_code == 200:
try:
return res.json()
except Exception:
return res.text
if res.status_code == 204:
return True

if not refreshed and res.status_code == 401:
_LOGGER.info("TOKEN EXPIRED: will refresh it (%s)", res.status_code)
await self.refreshAccessToken()
return await self.doBearerRequest(resourceUrl, options, True)

raise Exception("Communication failed! Status: " + str(res.status_code))

async def refreshAccessToken(self):
"""Attempt to refresh the Access Token."""
url = "https://cognito-idp.eu-west-1.amazonaws.com"

headers = {
"Content-Type": "application/x-amz-json-1.1",
"x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth",
"x-amz-user-agent": "aws-amplify/0.1.x react-native",
"User-Agent": "Daikin/1.6.1.4681 CFNetwork/1220.1 Darwin/20.3.0",
}
ref_json = {
"ClientId": "7rk39602f0ds8lk0h076vvijnb",
"AuthFlow": "REFRESH_TOKEN_AUTH",
"AuthParameters": {"REFRESH_TOKEN": self.tokenSet["refresh_token"]},
}
try:
func = functools.partial(
requests.post,
url,
headers=headers,
json=ref_json,
)
res = await self.hass.async_add_executor_job(func)
#res = requests.post(url, headers=headers, json=ref_json)
except Exception as e:
_LOGGER.error("REQUEST FAILED: %s", e)
_LOGGER.info("REFRESHACCESSTOKEN RESPONSE CODE: %s", res.status_code)
_LOGGER.debug("REFRESHACCESSTOKEN RESPONSE: %s", res.json())
res_json = res.json()

if (
res_json["AuthenticationResult"] is not None
and res_json["AuthenticationResult"]["AccessToken"] is not None
and res_json["AuthenticationResult"]["TokenType"] == "Bearer"
):
self.tokenSet["access_token"] = res_json["AuthenticationResult"][
"AccessToken"
]
self.tokenSet["id_token"] = res_json["AuthenticationResult"]["IdToken"]
self.tokenSet["expires_at"] = int(
datetime.datetime.now().timestamp()
) + int(res_json["AuthenticationResult"]["ExpiresIn"])
_LOGGER.debug("NEW TOKENSET: %s", self.tokenSet)
tokenFile = self.hass.config.path(TOKENSET_FILE)
with open(tokenFile, "w") as outfile:
json.dump(self.tokenSet, outfile)

# self.emit('token_update', self.tokenSet);
return self.tokenSet
raise Exception(
"Token refresh was not successful! Status: " + str(res.status_code)
)

async def getApiInfo(self):
"""Get Daikin API Info."""
return await self.doBearerRequest("/v1/info")

async def getCloudDeviceDetails(self):
"""Get pure Device Data from the Daikin cloud devices."""
return await self.doBearerRequest("/v1/gateway-devices")

async def getCloudDevices(self):
"""Get array of DaikinResidentialDevice objects and get their data."""
devices = await self.getCloudDeviceDetails()
res = {}
for dev in devices or []:
res[dev["id"]] = Appliance(dev, self)
return res

@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self, **kwargs):
"""Pull the latest data from Daikin."""
_LOGGER.debug("API UPDATE")
if self._delay_next_request:
_LOGGER.debug("SLEEPING FOR %i secs.", REQUEST_DELAY_TIME_s)
time.sleep(REQUEST_DELAY_TIME_s)
self._delay_next_request = False

json_data = await self.getCloudDeviceDetails()
for dev_data in json_data or []:
self.hass.data[DOMAIN][DAIKIN_DEVICES][dev_data["id"]].setJsonData(dev_data)
2 changes: 0 additions & 2 deletions custom_components/daikin_residential/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,8 @@ async def async_set_preset_mode(self, preset_mode):
"""Set preset mode."""
curr_mode = self.preset_mode
if curr_mode != PRESET_NONE:
print("SETTING OFF {}".format(curr_mode))
await self._device.set_preset_mode_status(curr_mode, ATTR_STATE_OFF)
if preset_mode != PRESET_NONE:
print("SETTING ON {}".format(preset_mode))
await self._device.set_preset_mode_status(preset_mode, ATTR_STATE_ON)

@property
Expand Down
4 changes: 2 additions & 2 deletions custom_components/daikin_residential/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from homeassistant import config_entries

from .__init__ import DaikinApi
from .daikin_api import DaikinApi
from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -37,7 +37,7 @@ async def _create_entry(self):

await self.async_set_unique_id("DaikinResidentialController")

return self.async_create_entry(title="daikin", data={})
return self.async_create_entry(title="Daikin", data={})

async def _attempt_connection(self):
"""Create device."""
Expand Down
2 changes: 0 additions & 2 deletions custom_components/daikin_residential/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ async def set_data(self, managementPoint, dataPoint, dataPointPath="", value=Non
try:
self._validateData(dataPoint + dataPointPath, dataPointDef, value)
except Exception as error:
print(error)
_LOGGER.error("FAILED to validate set_data params: %s", format(error))
return

Expand All @@ -355,7 +354,6 @@ async def set_data(self, managementPoint, dataPoint, dataPointPath="", value=Non

_LOGGER.debug("Path: " + setPath + " , options: %s", setOptions)

self.api._delay_next_request = True
res = await self.api.doBearerRequest(setPath, setOptions)
_LOGGER.debug("RES IS {}".format(res))
if res is True:
Expand Down

0 comments on commit 36e9355

Please sign in to comment.