Skip to content

Commit e669218

Browse files
Fix "object has no attribute headers" errors (#15)
* Always initialise headers and ssl_context fields * Add freezegun to requirements-test.txt * Add tests to verify that init() calls the expected set of endpoints * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent d1152fb commit e669218

File tree

3 files changed

+250
-2
lines changed

3 files changed

+250
-2
lines changed

pydaikin/daikin_base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ class Appliance(DaikinPowerMixin): # pylint: disable=too-many-public-methods
3232
"""Daikin main appliance class."""
3333

3434
base_url: str
35-
headers: Optional[dict]
35+
headers: Optional[dict] = None
3636
session: Optional[ClientSession]
37-
ssl_context: Optional[SSLContext]
37+
ssl_context: Optional[SSLContext] = None
3838

3939
TRANSLATIONS = {}
4040

requirements-test.txt

+2
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ black==24.2.0
22
flake8==7.0.0
33
isort==v5.10.1
44
pylint==3.0.3
5+
freezegun==1.5.1
6+
aresponses==3.0.0

tests/test_init.py

+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
"""Verify that init() calls the expected set of endpoints for each Daikin device."""
2+
3+
from aiohttp import ClientSession
4+
import pytest
5+
import pytest_asyncio
6+
7+
from pydaikin.daikin_airbase import DaikinAirBase
8+
from pydaikin.daikin_brp069 import DaikinBRP069
9+
from pydaikin.daikin_brp072c import DaikinBRP072C
10+
from pydaikin.daikin_skyfi import DaikinSkyFi
11+
12+
13+
@pytest_asyncio.fixture
14+
async def client_session():
15+
client_session = ClientSession()
16+
yield client_session
17+
await client_session.close()
18+
19+
20+
@pytest.mark.asyncio
21+
async def test_daikinBRP069(aresponses, client_session):
22+
aresponses.add(
23+
path_pattern="/common/get_datetime",
24+
method_pattern="GET",
25+
response="ret=OK,sta=2,cur=2023/8/27 21:54:1,reg=eu,dst=1,zone=313",
26+
)
27+
aresponses.add(
28+
path_pattern="/common/basic_info",
29+
method_pattern="GET",
30+
response="ret=OK,type=aircon,reg=eu,dst=1,ver=1_2_54,rev=203DE8C,pow=1,err=0,location=0,name=%4e%6f%74%74%65,icon=3,method=home only,port=30050,id=,pw=,lpw_flag=0,adp_kind=3,pv=3.20,cpv=3,cpv_minor=20,led=1,en_setzone=1,mac=409F38D107AC,adp_mode=run,en_hol=0,ssid1=Pinguino Curioso,radio1=-35,grp_name=,en_grp=0",
31+
)
32+
aresponses.add(
33+
path_pattern="/aircon/get_sensor_info",
34+
method_pattern="GET",
35+
response="ret=OK,htemp=25.0,hhum=-,otemp=21.0,err=0,cmpfreq=40",
36+
)
37+
aresponses.add(
38+
path_pattern="/common/get_remote_method",
39+
method_pattern="GET",
40+
response="ret=OK,method=home only,notice_ip_int=3600,notice_sync_int=60",
41+
)
42+
aresponses.add(
43+
path_pattern="/aircon/get_model_info",
44+
method_pattern="GET",
45+
response="ret=OK,model=0000,type=N,pv=3.20,cpv=3,cpv_minor=20,mid=NA,humd=0,s_humd=0,acled=0,land=0,elec=1,temp=1,temp_rng=0,m_dtct=1,ac_dst=--,disp_dry=0,dmnd=1,en_scdltmr=1,en_frate=1,en_fdir=1,s_fdir=3,en_rtemp_a=0,en_spmode=7,en_ipw_sep=1,en_mompow=0,hmlmt_l=10.0",
46+
)
47+
aresponses.add(
48+
path_pattern="/aircon/get_control_info",
49+
method_pattern="GET",
50+
response="ret=OK,pow=1,mode=2,adv=,stemp=M,shum=50,dt1=25.0,dt2=M,dt3=25.0,dt4=25.0,dt5=25.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=2,b_stemp=M,b_shum=50,alert=255,f_rate=A,f_dir=0,b_f_rate=5,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=3,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=2,dfd4=0,dfd5=0,dfd6=2,dfd7=0,dfdh=0,dmnd_run=0,en_demand=0",
51+
)
52+
aresponses.add(
53+
path_pattern="/aircon/get_target",
54+
method_pattern="GET",
55+
response="ret=OK,target=0",
56+
)
57+
aresponses.add(
58+
path_pattern="/aircon/get_price",
59+
method_pattern="GET",
60+
response="ret=OK,price_int=27,price_dec=0",
61+
)
62+
aresponses.add(
63+
path_pattern="/common/get_holiday",
64+
method_pattern="GET",
65+
response="ret=OK,en_hol=0",
66+
)
67+
aresponses.add(
68+
path_pattern="/common/get_notify",
69+
method_pattern="GET",
70+
response="ret=OK,auto_off_flg=0,auto_off_tm=- -",
71+
)
72+
aresponses.add(
73+
path_pattern="/aircon/get_day_power_ex",
74+
method_pattern="GET",
75+
response="ret=OK,curr_day_heat=0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0,prev_1day_heat=0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0,curr_day_cool=0/0/0/0/0/0/0/0/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0/0,prev_1day_cool=0/1/0/1/0/1/0/1/0/2/3/2/3/1/0/0/0/0/5/1/0/1/1/0",
76+
)
77+
aresponses.add(
78+
path_pattern="/aircon/get_week_power",
79+
method_pattern="GET",
80+
response="ret=OK,today_runtime=38,datas=5700/4000/6100/3900/2200/3400/400",
81+
)
82+
aresponses.add(
83+
path_pattern="/aircon/get_year_power",
84+
method_pattern="GET",
85+
response="ret=OK,previous_year=7/0/1/0/1/21/57/24/2/0/0/2,this_year=4/0/0/0/1/18/40/53",
86+
)
87+
aresponses.add(
88+
path_pattern="/common/get_datetime",
89+
method_pattern="GET",
90+
response="ret=OK,sta=2,cur=2023/8/27 21:54:1,reg=eu,dst=1,zone=313",
91+
)
92+
93+
device = DaikinBRP069('ip', session=client_session)
94+
95+
await device.init()
96+
97+
aresponses.assert_all_requests_matched()
98+
aresponses.assert_no_unused_routes()
99+
100+
101+
@pytest.mark.asyncio
102+
async def test_daikinBRP072C(aresponses, client_session):
103+
aresponses.add(
104+
path_pattern="/common/register_terminal",
105+
method_pattern="GET",
106+
response="ret=OK",
107+
)
108+
aresponses.add(
109+
path_pattern="/common/get_datetime",
110+
method_pattern="GET",
111+
response="ret=OK,sta=2,cur=2023/8/27 21:54:1,reg=eu,dst=1,zone=313",
112+
)
113+
aresponses.add(
114+
path_pattern="/common/basic_info",
115+
method_pattern="GET",
116+
response="ret=OK,type=aircon,reg=eu,dst=1,ver=1_2_54,rev=203DE8C,pow=1,err=0,location=0,name=%4e%6f%74%74%65,icon=3,method=home only,port=30050,id=,pw=,lpw_flag=0,adp_kind=3,pv=3.20,cpv=3,cpv_minor=20,led=1,en_setzone=1,mac=409F38D107AC,adp_mode=run,en_hol=0,ssid1=Pinguino Curioso,radio1=-35,grp_name=,en_grp=0",
117+
)
118+
aresponses.add(
119+
path_pattern="/aircon/get_sensor_info",
120+
method_pattern="GET",
121+
response="ret=OK,htemp=25.0,hhum=-,otemp=21.0,err=0,cmpfreq=40",
122+
)
123+
aresponses.add(
124+
path_pattern="/common/get_remote_method",
125+
method_pattern="GET",
126+
response="ret=OK,method=home only,notice_ip_int=3600,notice_sync_int=60",
127+
)
128+
aresponses.add(
129+
path_pattern="/aircon/get_model_info",
130+
method_pattern="GET",
131+
response="ret=OK,model=0000,type=N,pv=3.20,cpv=3,cpv_minor=20,mid=NA,humd=0,s_humd=0,acled=0,land=0,elec=1,temp=1,temp_rng=0,m_dtct=1,ac_dst=--,disp_dry=0,dmnd=1,en_scdltmr=1,en_frate=1,en_fdir=1,s_fdir=3,en_rtemp_a=0,en_spmode=7,en_ipw_sep=1,en_mompow=0,hmlmt_l=10.0",
132+
)
133+
aresponses.add(
134+
path_pattern="/aircon/get_control_info",
135+
method_pattern="GET",
136+
response="ret=OK,pow=1,mode=2,adv=,stemp=M,shum=50,dt1=25.0,dt2=M,dt3=25.0,dt4=25.0,dt5=25.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=2,b_stemp=M,b_shum=50,alert=255,f_rate=A,f_dir=0,b_f_rate=5,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=3,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=2,dfd4=0,dfd5=0,dfd6=2,dfd7=0,dfdh=0,dmnd_run=0,en_demand=0",
137+
)
138+
aresponses.add(
139+
path_pattern="/aircon/get_target",
140+
method_pattern="GET",
141+
response="ret=OK,target=0",
142+
)
143+
aresponses.add(
144+
path_pattern="/aircon/get_price",
145+
method_pattern="GET",
146+
response="ret=OK,price_int=27,price_dec=0",
147+
)
148+
aresponses.add(
149+
path_pattern="/common/get_holiday",
150+
method_pattern="GET",
151+
response="ret=OK,en_hol=0",
152+
)
153+
aresponses.add(
154+
path_pattern="/common/get_notify",
155+
method_pattern="GET",
156+
response="ret=OK,auto_off_flg=0,auto_off_tm=- -",
157+
)
158+
aresponses.add(
159+
path_pattern="/aircon/get_day_power_ex",
160+
method_pattern="GET",
161+
response="ret=OK,curr_day_heat=0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0,prev_1day_heat=0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0,curr_day_cool=0/0/0/0/0/0/0/0/0/0/1/0/0/0/0/0/0/0/0/0/0/0/0/0,prev_1day_cool=0/1/0/1/0/1/0/1/0/2/3/2/3/1/0/0/0/0/5/1/0/1/1/0",
162+
)
163+
aresponses.add(
164+
path_pattern="/aircon/get_week_power",
165+
method_pattern="GET",
166+
response="ret=OK,today_runtime=38,datas=5700/4000/6100/3900/2200/3400/400",
167+
)
168+
aresponses.add(
169+
path_pattern="/aircon/get_year_power",
170+
method_pattern="GET",
171+
response="ret=OK,previous_year=7/0/1/0/1/21/57/24/2/0/0/2,this_year=4/0/0/0/1/18/40/53",
172+
)
173+
aresponses.add(
174+
path_pattern="/common/get_datetime",
175+
method_pattern="GET",
176+
response="ret=OK,sta=2,cur=2023/8/27 21:54:1,reg=eu,dst=1,zone=313",
177+
)
178+
179+
device = DaikinBRP072C('ip', session=client_session, key="xxxkeyxxx")
180+
181+
await device.init()
182+
183+
aresponses.assert_all_requests_matched()
184+
aresponses.assert_no_unused_routes()
185+
186+
187+
@pytest.mark.asyncio
188+
async def test_daikinSkiFi(aresponses, client_session):
189+
aresponses.add(
190+
path_pattern="/zones.cgi",
191+
method_pattern="GET",
192+
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",
193+
)
194+
aresponses.add(
195+
path_pattern="/ac.cgi",
196+
method_pattern="GET",
197+
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",
198+
)
199+
200+
device = DaikinSkyFi('ip', session=client_session, password="xxxpasswordxxx")
201+
202+
await device.init()
203+
204+
aresponses.assert_all_requests_matched()
205+
aresponses.assert_no_unused_routes()
206+
207+
208+
@pytest.mark.asyncio
209+
async def test_daikinAirBase(aresponses, client_session):
210+
aresponses.add(
211+
path_pattern="/skyfi/common/get_datetime",
212+
method_pattern="GET",
213+
response="ret=OK,sta=2,cur=2023/8/27 21:54:1,reg=eu,dst=1,zone=313",
214+
)
215+
aresponses.add(
216+
path_pattern="/skyfi/common/basic_info",
217+
method_pattern="GET",
218+
response="ret=OK,type=aircon,reg=eu,dst=1,ver=1_2_54,rev=203DE8C,pow=1,err=0,location=0,name=%4e%6f%74%74%65,icon=3,method=home only,port=30050,id=,pw=,lpw_flag=0,adp_kind=3,pv=3.20,cpv=3,cpv_minor=20,led=1,en_setzone=1,mac=409F38D107AC,adp_mode=run,en_hol=0,ssid1=Pinguino Curioso,radio1=-35,grp_name=,en_grp=0",
219+
)
220+
aresponses.add(
221+
path_pattern="/skyfi/aircon/get_control_info",
222+
method_pattern="GET",
223+
response="ret=OK,pow=1,mode=2,adv=,stemp=M,shum=50,dt1=25.0,dt2=M,dt3=25.0,dt4=25.0,dt5=25.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=2,b_stemp=M,b_shum=50,alert=255,f_rate=A,f_dir=0,b_f_rate=5,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=3,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=2,dfd4=0,dfd5=0,dfd6=2,dfd7=0,dfdh=0,dmnd_run=0,en_demand=0",
224+
)
225+
aresponses.add(
226+
path_pattern="/skyfi/aircon/get_model_info",
227+
method_pattern="GET",
228+
response="ret=OK,model=0000,type=N,pv=3.20,cpv=3,cpv_minor=20,mid=NA,humd=0,s_humd=0,acled=0,land=0,elec=1,temp=1,temp_rng=0,m_dtct=1,ac_dst=--,disp_dry=0,dmnd=1,en_scdltmr=1,en_frate=1,en_fdir=1,s_fdir=3,en_rtemp_a=0,en_spmode=7,en_ipw_sep=1,en_mompow=0,hmlmt_l=10.0",
229+
)
230+
aresponses.add(
231+
path_pattern="/skyfi/aircon/get_sensor_info",
232+
method_pattern="GET",
233+
response="ret=OK,htemp=25.0,hhum=-,otemp=21.0,err=0,cmpfreq=40",
234+
)
235+
aresponses.add(
236+
path_pattern="/skyfi/aircon/get_zone_setting",
237+
method_pattern="GET",
238+
response="ret=OK",
239+
)
240+
241+
device = DaikinAirBase('ip', session=client_session)
242+
243+
await device.init()
244+
245+
aresponses.assert_all_requests_matched()
246+
aresponses.assert_no_unused_routes()

0 commit comments

Comments
 (0)