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,24 @@ 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+ """Get the state."""
140+ url = URL (self .uri ).join (URL (STATE ))
141+ response = await make_call (self , uri = url )
142+ self ._state = response
143+
144+ async def get_blind_config (self ) -> None :
145+ """Get the configuration of a dingz blind part."""
146+ url = URL (self .uri ).join (URL (BLIND_CONFIGURATION ))
147+ response = await make_call (self , uri = url )
148+ self ._blind_config = response
149+
150+ async def get_system_config (self ) -> None :
151+ """Get the system configuration of a dingz."""
152+ url = URL (self .uri ).join (URL (SYSTEM_CONFIG ))
153+ response = await make_call (self , uri = url )
154+ self ._system_config = response
155+
121156 async def enabled (self ) -> bool :
122157 """Return true if front LED is on."""
123158 url = URL (self .uri ).join (URL (FRONT_LED_GET ))
@@ -136,12 +171,83 @@ async def turn_off(self) -> None:
136171 url = URL (self .uri ).join (URL (FRONT_LED_SET ))
137172 await make_call (self , uri = url , method = "POST" , data = data )
138173
174+ async def operate_shade (self , shade_no , blind = None , lamella = None ) -> None :
175+ """Operate the lamella and blind.
176+
177+ blind: 0 fully closed, 100 fully open
178+ lamella: 0 lamellas closed, 100 lamellas open
179+ """
180+
181+ # With newer versions of dingz, we can just leave
182+ # either lamella or blind None (i.e. do not chang)
183+ # but currently we need to lookup the current state
184+ # of the shade first.
185+ if blind is None or lamella is None :
186+ await self .get_state ()
187+
188+ if blind is None :
189+ blind = self .current_blind_level (shade_no )
190+
191+ if lamella is None :
192+ if self .is_shade_opened (shade_no ):
193+ # If the shade is currently completely opened (i.e. up), the lamella
194+ # value is not really relevant (has no effect). We assume the
195+ # lamella value to be 0, ie. closed.
196+ # i.e. we set lamella to 45, raise blind to the top, and then back down again
197+ # => de we expect the lamella to be set to 45 again, or does it get resetted to 0?
198+ lamella = 0
199+ else :
200+ lamella = self .current_lamella_level (shade_no )
201+
202+ url = URL (self .uri ).join (URL ("%s/%s" % (SHADE , shade_no )))
203+ params = {"blind" : str (blind ), "lamella" : str (lamella )}
204+ await make_call (self , uri = url , method = "POST" , parameters = params )
205+
206+ async def shade_up (self , shade_no ) -> None :
207+ """Move the shade up."""
208+ await self .shade_command (shade_no , "up" )
209+
210+ async def shade_down (self , shade_no ) -> None :
211+ """Move the shade down."""
212+ await self .shade_command (shade_no , "down" )
213+
214+ async def shade_stop (self , shade_no ) -> None :
215+ """Stop the shade."""
216+ await self .shade_command (shade_no , "stop" )
217+
218+ async def lamella_open (self , shade_no ) -> None :
219+ """Open the lamella."""
220+ await self .operate_shade (shade_no , lamella = 100 )
221+
222+ async def lamella_close (self , shade_no ) -> None :
223+ """Close the lamella."""
224+ await self .operate_shade (shade_no , lamella = 0 )
225+
226+ async def lamella_stop (self , shade_no ) -> None :
227+ """Stop the lamella."""
228+ await self .shade_stop (shade_no )
229+
230+ async def shade_command (self , shade_no , verb ):
231+ """Create a command for the shade."""
232+ url = URL (self .uri ).join (URL ("%s/%s/%s" % (SHADE , shade_no , verb )))
233+ await make_call (self , uri = url , method = "POST" )
234+
139235 async def set_timer (self , data ) -> None :
140236 """Set a timer."""
141237 print (data )
142238 url = URL (self .uri ).join (URL (TIMER ))
143239 await make_call (self , uri = url , method = "POST" , json_data = data )
144240
241+ async def stop_timer (self , data ) -> None :
242+ """Stop a timer."""
243+ url = URL (self .uri ).join (URL (TIMER ))
244+ await make_call (self , uri = url , method = "POST" , data = data )
245+
246+ @property
247+ def dingz_name (self ) -> str :
248+ """Get the name of a dingz."""
249+ return self ._system_config ["dingz_name" ]
250+
145251 @property
146252 def device_details (self ) -> str :
147253 """Return the current device details."""
@@ -173,7 +279,7 @@ def wifi_networks(self) -> str:
173279 return self ._wifi_networks
174280
175281 @property
176- def everything (self ) -> str :
282+ def everything (self ) -> dict :
177283 """Return the all available device details."""
178284 return self ._catch_all
179285
@@ -207,6 +313,95 @@ def intensity(self) -> float:
207313 """Return the current light intensity in lux."""
208314 return round (self ._intensity , 1 )
209315
316+ @property
317+ def version (self ) -> str :
318+ """Return the version of a dingz."""
319+ return self ._info ["version" ]
320+
321+ @property
322+ def type (self ) -> str :
323+ """Return the type of a dingz."""
324+ return self ._info ["type" ]
325+
326+ @property
327+ def mac (self ) -> str :
328+ """Return the MAC address of a dingz."""
329+ return self ._info ["mac" ]
330+
331+ @property
332+ def front_hw_model (self ) -> str :
333+ """Get the hardware model of a dingz."""
334+ return self ._device_details ["front_hw_model" ]
335+
336+ @property
337+ def puck_hw_model (self ) -> str :
338+ """Get the hardware model of a dingz puck."""
339+ return self ._device_details ["puck_hw_model" ]
340+
341+ @property
342+ def front_serial_number (self ) -> str :
343+ """Get the serial_number of the a dingz front."""
344+ return self ._device_details ["front_sn" ]
345+
346+ @property
347+ def puck_serial_number (self ) -> str :
348+ """Get the serial number of a dingz puck."""
349+ return self ._device_details ["puck_sn" ]
350+
351+ @property
352+ def hw_version (self ) -> str :
353+ """Get the hardware version of a dingz."""
354+ return self ._device_details ["hw_version" ]
355+
356+ @property
357+ def fw_version (self ) -> str :
358+ """Get the firmware version of a dingz."""
359+ return self ._device_details ["fw_version" ]
360+
361+ def _shade_current_state (self , shade_no : int ):
362+ """Get the configuration of the shade."""
363+ return self ._state ["blinds" ][shade_no ]
364+
365+ def current_blind_level (self , shade_no ):
366+ """Get the current blind level."""
367+ return self ._shade_current_state (shade_no )["position" ]
368+
369+ def current_lamella_level (self , shade_no ):
370+ """Get the current lamella level."""
371+ return self ._shade_current_state (shade_no )["lamella" ]
372+
373+ def is_shade_closed (self , shade_no ):
374+ """Get the closed state of a shade."""
375+ # When closed, we care if the lamellas are opened or not
376+ return (
377+ self .current_blind_level (shade_no ) == 0
378+ and self .current_lamella_level (shade_no ) == 0
379+ )
380+
381+ def is_shade_opened (self , shade_no ):
382+ """Get the open state of a shade."""
383+ return self .current_blind_level (shade_no ) == 100
384+
385+ def is_lamella_closed (self , shade_no ):
386+ """Get the closed state of a lamella."""
387+ return self .current_lamella_level (shade_no ) == 0
388+
389+ def is_lamella_opened (self , shade_no ):
390+ """Get the open state of lamella."""
391+ return self .current_lamella_level (shade_no ) == 100
392+
393+ def is_blind_opening (self , shade_no ):
394+ """Get the state of the blind if opening."""
395+ return self ._shade_current_state (shade_no )["moving" ] == "up"
396+
397+ def is_blind_closing (self , shade_no ):
398+ """Get the state of the blind if closing."""
399+ return self ._shade_current_state (shade_no )["moving" ] == "down"
400+
401+ def blind_name (self , shade_no ):
402+ """Get the name of the blind."""
403+ return self ._blind_config ["blinds" ][shade_no ]["name" ]
404+
210405 # See "Using Asyncio in Python" by Caleb Hattingh for implementation
211406 # details.
212407 async def close (self ) -> None :
0 commit comments