2121 WIFI_SCAN ,
2222 TIMER ,
2323 SCHEDULE ,
24+ SHADE ,
25+ INFO ,
26+ STATE ,
27+ SYSTEM_CONFIG ,
28+ BLIND_CONFIGURATION ,
2429)
2530
2631_LOGGER = logging .getLogger (__name__ )
@@ -35,6 +40,7 @@ def __init__(self, host: str, session: aiohttp.client.ClientSession = None) -> N
3540 self ._host = host
3641 self ._session = session
3742 self ._device_details = None
43+ self ._info = None
3844 self ._wifi_networks = None
3945 self ._settings = None
4046 self ._catch_all = {}
@@ -47,15 +53,26 @@ def __init__(self, host: str, session: aiohttp.client.ClientSession = None) -> N
4753 self ._motion = None
4854 self ._schedule = None
4955 self ._timer = None
56+ self ._state = {}
57+ self ._blind_config = None
58+ self ._system_config = None
59+
5060 self .uri = URL .build (scheme = "http" , host = self ._host ).join (URL (API ))
5161
5262 async def get_device_info (self ) -> None :
5363 """Get the details from the dingz."""
5464 url = URL (self .uri ).join (URL (DEVICE_INFO ))
5565 response = await make_call (self , uri = url )
56- self ._device_details = response
66+ # response is: "mac" => { device_details }
67+ self ._device_details = next (iter (response .values ()))
5768
5869 async def get_info (self ) -> None :
70+ """Get general information fro the dingz."""
71+ url = URL (self .uri ).join (URL (INFO ))
72+ response = await make_call (self , uri = url )
73+ self ._info = response
74+
75+ async def get_all_info (self ) -> None :
5976 """Get everything from the dingz unit."""
6077 for endpoint in [
6178 PUCK ,
@@ -118,6 +135,21 @@ async def get_light(self) -> None:
118135 self ._intensity = response ["intensity" ]
119136 self ._hour_of_day = response ["state" ]
120137
138+ async def get_state (self ) -> None :
139+ url = URL (self .uri ).join (URL (STATE ))
140+ response = await make_call (self , uri = url )
141+ self ._state = response
142+
143+ async def get_blind_config (self ) -> None :
144+ url = URL (self .uri ).join (URL (BLIND_CONFIGURATION ))
145+ response = await make_call (self , uri = url )
146+ self ._blind_config = response
147+
148+ async def get_system_config (self ) -> None :
149+ url = URL (self .uri ).join (URL (SYSTEM_CONFIG ))
150+ response = await make_call (self , uri = url )
151+ self ._system_config = response
152+
121153 async def enabled (self ) -> bool :
122154 """Return true if front LED is on."""
123155 url = URL (self .uri ).join (URL (FRONT_LED_GET ))
@@ -136,6 +168,59 @@ async def turn_off(self) -> None:
136168 url = URL (self .uri ).join (URL (FRONT_LED_SET ))
137169 await make_call (self , uri = url , method = "POST" , data = data )
138170
171+ async def operate_shade (self , shade_no , blind = None , lamella = None ) -> None :
172+ """operate the lamella and blind
173+ blind: 0 fully closed, 100 fully open
174+ lamella: 0 lamellas closed, 100 lamellas open
175+ """
176+
177+ # With newer versions of dingz, we can just leave
178+ # either lamella or blind None (i.e. do not chang)
179+ # but currently we need to lookup the current state
180+ # of the shade first.
181+ if blind is None or lamella is None :
182+ await self .get_state ()
183+
184+ if blind is None :
185+ blind = self .current_blind_level (shade_no )
186+
187+ if lamella is None :
188+ if self .is_shade_opened (shade_no ):
189+ # if the shade is currently completely opened (i.e. up), the lamella
190+ # value is not really relevant (has no effect). We assume the
191+ # lamella value to be 0, ie. closed.
192+ # i.e. we set lamella to 45, raise blind to the top, and then back down again
193+ # => de we expect the lamella to be set to 45 again, or does it get resetted to 0?
194+ lamella = 0
195+ else :
196+ lamella = self .current_lamella_level (shade_no )
197+
198+ url = URL (self .uri ).join (URL ("%s/%s" % (SHADE , shade_no )))
199+ params = {"blind" : str (blind ), "lamella" : str (lamella )}
200+ await make_call (self , uri = url , method = "POST" , parameters = params )
201+
202+ async def shade_up (self , shade_no ) -> None :
203+ await self .shade_command (shade_no , "up" )
204+
205+ async def shade_down (self , shade_no ) -> None :
206+ await self .shade_command (shade_no , "down" )
207+
208+ async def shade_stop (self , shade_no ) -> None :
209+ await self .shade_command (shade_no , "stop" )
210+
211+ async def lamella_open (self , shade_no ) -> None :
212+ await self .operate_shade (shade_no , lamella = 100 )
213+
214+ async def lamella_close (self , shade_no ) -> None :
215+ await self .operate_shade (shade_no , lamella = 0 )
216+
217+ async def lamella_stop (self , shade_no ) -> None :
218+ await self .shade_stop (shade_no )
219+
220+ async def shade_command (self , shade_no , verb ):
221+ url = URL (self .uri ).join (URL ("%s/%s/%s" % (SHADE , shade_no , verb )))
222+ await make_call (self , uri = url , method = "POST" )
223+
139224 async def set_timer (self , data ) -> None :
140225 """Set a timer."""
141226 print (data )
@@ -147,6 +232,10 @@ async def stop_timer(self, data) -> None:
147232 url = URL (self .uri ).join (URL (TIMER ))
148233 await make_call (self , uri = url , method = "POST" , data = data )
149234
235+ @property
236+ def dingz_name (self ) -> str :
237+ return self ._system_config ["dingz_name" ]
238+
150239 @property
151240 def device_details (self ) -> str :
152241 """Return the current device details."""
@@ -178,7 +267,7 @@ def wifi_networks(self) -> str:
178267 return self ._wifi_networks
179268
180269 @property
181- def everything (self ) -> str :
270+ def everything (self ) -> dict :
182271 """Return the all available device details."""
183272 return self ._catch_all
184273
@@ -212,6 +301,76 @@ def intensity(self) -> float:
212301 """Return the current light intensity in lux."""
213302 return round (self ._intensity , 1 )
214303
304+ @property
305+ def version (self ) -> str :
306+ return self ._info ["version" ]
307+
308+ @property
309+ def type (self ) -> str :
310+ return self ._info ["type" ]
311+
312+ @property
313+ def mac (self ) -> str :
314+ return self ._info ["mac" ]
315+
316+ @property
317+ def front_hw_model (self ) -> str :
318+ return self ._device_details ["front_hw_model" ]
319+
320+ @property
321+ def puck_hw_model (self ) -> str :
322+ return self ._device_details ["puck_hw_model" ]
323+
324+ @property
325+ def front_sn (self ) -> str :
326+ return self ._device_details ["front_sn" ]
327+
328+ @property
329+ def puck_sn (self ) -> str :
330+ return self ._device_details ["puck_sn" ]
331+
332+ @property
333+ def hw_version (self ) -> str :
334+ return self ._device_details ["hw_version" ]
335+
336+ @property
337+ def fw_version (self ) -> str :
338+ return self ._device_details ["fw_version" ]
339+
340+ def _shade_current_state (self , shade_no : int ):
341+ return self ._state ["blinds" ][shade_no ]
342+
343+ def current_blind_level (self , shade_no ):
344+ return self ._shade_current_state (shade_no )["position" ]
345+
346+ def current_lamella_level (self , shade_no ):
347+ return self ._shade_current_state (shade_no )["lamella" ]
348+
349+ def is_shade_closed (self , shade_no ):
350+ # when closed, we care if the lamellas are opened or not
351+ return (
352+ self .current_blind_level (shade_no ) == 0
353+ and self .current_lamella_level (shade_no ) == 0
354+ )
355+
356+ def is_shade_opened (self , shade_no ):
357+ return self .current_blind_level (shade_no ) == 100
358+
359+ def is_lamella_closed (self , shade_no ):
360+ return self .current_lamella_level (shade_no ) == 0
361+
362+ def is_lamella_opened (self , shade_no ):
363+ return self .current_lamella_level (shade_no ) == 100
364+
365+ def is_blind_opening (self , shade_no ):
366+ return self ._shade_current_state (shade_no )["moving" ] == "up"
367+
368+ def is_blind_closing (self , shade_no ):
369+ return self ._shade_current_state (shade_no )["moving" ] == "down"
370+
371+ def blind_name (self , shade_no ):
372+ return self ._blind_config ["blinds" ][shade_no ]["name" ]
373+
215374 # See "Using Asyncio in Python" by Caleb Hattingh for implementation
216375 # details.
217376 async def close (self ) -> None :
0 commit comments