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,12 +168,69 @@ 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 )
142227 url = URL (self .uri ).join (URL (TIMER ))
143228 await make_call (self , uri = url , method = "POST" , json_data = data )
144229
230+ @property
231+ def dingz_name (self ) -> str :
232+ return self ._system_config ["dingz_name" ]
233+
145234 @property
146235 def device_details (self ) -> str :
147236 """Return the current device details."""
@@ -173,7 +262,7 @@ def wifi_networks(self) -> str:
173262 return self ._wifi_networks
174263
175264 @property
176- def everything (self ) -> str :
265+ def everything (self ) -> dict :
177266 """Return the all available device details."""
178267 return self ._catch_all
179268
@@ -207,6 +296,76 @@ def intensity(self) -> float:
207296 """Return the current light intensity in lux."""
208297 return round (self ._intensity , 1 )
209298
299+ @property
300+ def version (self ) -> str :
301+ return self ._info ["version" ]
302+
303+ @property
304+ def type (self ) -> str :
305+ return self ._info ["type" ]
306+
307+ @property
308+ def mac (self ) -> str :
309+ return self ._info ["mac" ]
310+
311+ @property
312+ def front_hw_model (self ) -> str :
313+ return self ._device_details ["front_hw_model" ]
314+
315+ @property
316+ def puck_hw_model (self ) -> str :
317+ return self ._device_details ["puck_hw_model" ]
318+
319+ @property
320+ def front_sn (self ) -> str :
321+ return self ._device_details ["front_sn" ]
322+
323+ @property
324+ def puck_sn (self ) -> str :
325+ return self ._device_details ["puck_sn" ]
326+
327+ @property
328+ def hw_version (self ) -> str :
329+ return self ._device_details ["hw_version" ]
330+
331+ @property
332+ def fw_version (self ) -> str :
333+ return self ._device_details ["fw_version" ]
334+
335+ def _shade_current_state (self , shade_no : int ):
336+ return self ._state ["blinds" ][shade_no ]
337+
338+ def current_blind_level (self , shade_no ):
339+ return self ._shade_current_state (shade_no )["position" ]
340+
341+ def current_lamella_level (self , shade_no ):
342+ return self ._shade_current_state (shade_no )["lamella" ]
343+
344+ def is_shade_closed (self , shade_no ):
345+ # when closed, we care if the lamellas are opened or not
346+ return (
347+ self .current_blind_level (shade_no ) == 0
348+ and self .current_lamella_level (shade_no ) == 0
349+ )
350+
351+ def is_shade_opened (self , shade_no ):
352+ return self .current_blind_level (shade_no ) == 100
353+
354+ def is_lamella_closed (self , shade_no ):
355+ return self .current_lamella_level (shade_no ) == 0
356+
357+ def is_lamella_opened (self , shade_no ):
358+ return self .current_lamella_level (shade_no ) == 100
359+
360+ def is_blind_opening (self , shade_no ):
361+ return self ._shade_current_state (shade_no )["moving" ] == "up"
362+
363+ def is_blind_closing (self , shade_no ):
364+ return self ._shade_current_state (shade_no )["moving" ] == "down"
365+
366+ def blind_name (self , shade_no ):
367+ return self ._blind_config ["blinds" ][shade_no ]["name" ]
368+
210369 # See "Using Asyncio in Python" by Caleb Hattingh for implementation
211370 # details.
212371 async def close (self ) -> None :
0 commit comments