Skip to content

Commit

Permalink
Fix for Skyfi making less frequent requests (#30)
Browse files Browse the repository at this point in the history
* more and better debug-logging

* add a sleep of 0.3 after each request

* add string representation of ApplianceValues

* update tests with complete coverage for SkyFi
  • Loading branch information
fredrike authored Sep 18, 2024
1 parent 65f828f commit fe46ffd
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 25 deletions.
11 changes: 8 additions & 3 deletions pydaikin/daikin_skyfi.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Pydaikin appliance, represent a Daikin device."""

from asyncio import sleep
import logging
from urllib.parse import unquote

Expand Down Expand Up @@ -49,6 +50,8 @@ class DaikinSkyFi(Appliance):
},
}

MAX_CONCURRENT_REQUESTS = 1

def __init__(
self,
device_id: str,
Expand Down Expand Up @@ -96,7 +99,7 @@ def support_swing_mode(self):
@staticmethod
def parse_response(response_body):
"""Parse response from Daikin and map it to general Daikin format."""
_LOGGER.debug("Parsing %s", response_body)
_LOGGER.debug("Parsing response %s", response_body)
response = dict([e.split('=') for e in response_body.split('&')])
if response.get('fanflags') == '3':
response['fanspeed'] = str(int(response['fanspeed']) + 4)
Expand All @@ -114,7 +117,9 @@ async def _get_resource(self, path: str, params: dict | None = None):
params = {}
# ensure password is the first parameter
params = {**{"pass": self._password}, **params}
return await super()._get_resource(path, params)
ret = await super()._get_resource(path, params)
await sleep(0.3)
return ret

def represent(self, key):
"""Return translated value from key."""
Expand Down Expand Up @@ -162,7 +167,7 @@ async def set(self, settings):
def zones(self):
"""Return list of zones."""
if 'nz' not in self.values:
return False
return False # pragma: no cover
return [
v
for i, v in enumerate(
Expand Down
4 changes: 4 additions & 0 deletions pydaikin/response.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"Function to parse responses coming in, used by multiple classes"
import logging
import re
from urllib.parse import unquote

_LOGGER = logging.getLogger(__name__)


def parse_response(response_body):
"""Parse response from Daikin."""
_LOGGER.debug("Parsing response: %s", response_body)
response = dict(
(match.group(1), match.group(2))
for match in re.finditer(r'(\w+)=([^=]*)(?:,|$)', response_body)
Expand Down
3 changes: 3 additions & 0 deletions pydaikin/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def __iter__(self):
def __len__(self):
return len(self._data)

def __str__(self):
return f"{self._data}"

# --- Custom methods to use smart updates ---
def get(
self, key: str, default=None, *, invalidate: bool = True
Expand Down
22 changes: 0 additions & 22 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from pydaikin.daikin_airbase import DaikinAirBase
from pydaikin.daikin_brp069 import DaikinBRP069
from pydaikin.daikin_brp072c import DaikinBRP072C
from pydaikin.daikin_skyfi import DaikinSkyFi


@pytest_asyncio.fixture
Expand Down Expand Up @@ -184,27 +183,6 @@ async def test_daikinBRP072C(aresponses, client_session):
aresponses.assert_no_unused_routes()


@pytest.mark.asyncio
async def test_daikinSkiFi(aresponses, client_session):
aresponses.add(
path_pattern="/zones.cgi",
method_pattern="GET",
response="nz=8&zone1=Zone%201&zone2=Zone%202&zone3=Zone%203&zone4=Zone%204&zone5=Zone%205&zone6=Zone%206&zone7=Zone%207&zone8=Zone%208",
)
aresponses.add(
path_pattern="/ac.cgi",
method_pattern="GET",
response="opmode=0&units=.&settemp=24.0&fanspeed=3&fanflags=1&acmode=16&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=0&flt=0&test=0&errdata=146&sensors=1",
)

device = DaikinSkyFi('ip', session=client_session, password="xxxpasswordxxx")

await device.init()

aresponses.assert_all_requests_matched()
aresponses.assert_no_unused_routes()


@pytest.mark.asyncio
async def test_daikinAirBase(aresponses, client_session):
aresponses.add(
Expand Down
88 changes: 88 additions & 0 deletions tests/test_skyfi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Verify that init() calls the expected set of endpoints for each Daikin device."""

import pytest

from pydaikin.daikin_skyfi import DaikinSkyFi

from .test_init import client_session

assert client_session


@pytest.mark.asyncio
async def test_daikinSkiFi(aresponses, client_session):
aresponses.add(
path_pattern="/zones.cgi",
method_pattern="GET",
response="nz=8&zone1=Zone%201&zone2=Zone%202&zone3=Zone%203&zone4=Zone%204&zone5=Zone%205&zone6=Zone%206&zone7=Zone%207&zone8=Zone%208",
)
aresponses.add(
path_pattern="/ac.cgi",
method_pattern="GET",
response="opmode=0&units=.&settemp=24.0&fanspeed=3&fanflags=3&acmode=16&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=0&flt=0&test=0&errdata=146&sensors=1",
)

device = DaikinSkyFi('ip', session=client_session, password="xxxpasswordxxx")

await device.init()

aresponses.assert_all_requests_matched()
aresponses.assert_no_unused_routes()

assert device["mode"] == '16'
assert device.support_away_mode is False
assert device.support_fan_rate is True
assert device.support_swing_mode is False
assert device.represent("zone1") == ("zone1", "Zone 1")
assert device.represent("zone") == ('zone', '00000000')
assert device.inside_temperature == 23.0
assert device.target_temperature == 24.0
assert device.outside_temperature == 0

assert device.represent("mode") == ('mode', 'off')

aresponses.add(
path_pattern="/ac.cgi",
method_pattern="GET",
response="opmode=0&units=.&settemp=20.0&fanspeed=3&fanflags=1&acmode=16&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=0&flt=0&test=0&errdata=146&sensors=1",
)
aresponses.add(
path_pattern="/set.cgi",
method_pattern="GET",
response="opmode=1&units=.&settemp=20.0&fanspeed=3&fanflags=1&acmode=8&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=0&flt=0&test=0&errdata=146&sensors=1",
)

await device.set({"mode": "cool"})
aresponses.assert_all_requests_matched()
assert device.represent("mode") == ('mode', 'cool')
assert device.target_temperature == 20.0

aresponses.add(
path_pattern="/ac.cgi",
method_pattern="GET",
response="opmode=1&units=.&settemp=20.0&fanspeed=3&fanflags=1&acmode=8&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=0&flt=0&test=0&errdata=146&sensors=1",
)
aresponses.add(
path_pattern="/set.cgi",
method_pattern="GET",
response="opmode=0&units=.&settemp=20.0&fanspeed=3&fanflags=1&acmode=8&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=0&flt=0&test=0&errdata=146&sensors=1",
)
await device.set({"mode": "off"})
assert device.zones == [
('Zone 1', '0'),
('Zone 2', '0'),
('Zone 3', '0'),
('Zone 4', '0'),
('Zone 5', '0'),
('Zone 6', '0'),
('Zone 7', '0'),
('Zone 8', '0'),
]

await device.set_zone(0, "zone_onoff_", 1)
aresponses.add(
path_pattern="/setzone.cgi",
method_pattern="GET",
response="opmode=0&units=.&settemp=20.0&fanspeed=3&fanflags=1&acmode=8&tonact=0&toffact=0&prog=0&time=23:36&day=6&roomtemp=23&outsidetemp=0&louvre=1&zone=128&flt=0&test=0&errdata=146&sensors=1",
)
await device.set_zone(0, "zone_onoff", 1)

0 comments on commit fe46ffd

Please sign in to comment.