4848import json
4949import re
5050import subprocess
51- import time
5251
5352from framework .core .logModule import logModule
5453from framework .core .powerModules .abstractPowerModule import PowerModuleInterface
@@ -75,7 +74,7 @@ def __init__( self, log:logModule, ip:str, outlet:str = None, **kwargs ):
7574 self .ip = ip
7675 self ._username = kwargs .get ("username" , None )
7776 self ._password = kwargs .get ("password" , None )
78- if outlet :
77+ if outlet is not None :
7978 self ._outlet = str (outlet )
8079 self ._device_type = None
8180 self ._encryption_type = None
@@ -111,7 +110,7 @@ def _performCommand(self, command, json = False, append_args:list = []):
111110 command_list .append ("--encrypt-type" )
112111 command_list .append (self ._encryption_type )
113112 else :
114- if self ._outlet :
113+ if self ._outlet is not None :
115114 command_list .append ("--type" )
116115 command_list .append ("strip" )
117116 else :
@@ -133,16 +132,16 @@ def powerOff(self):
133132 bool: True if the operation is successful, False otherwise.
134133 """
135134 self ._get_state ()
136- if self .is_off :
135+ if not self ._is_on :
137136 return True
138- if self ._outlet :
137+ if self ._outlet is not None :
139138 self ._performCommand ("off" , append_args = ["--index" , str (self ._outlet )])
140139 else :
141140 self ._performCommand ("off" )
142141 self ._get_state ()
143- if self .is_off == False :
142+ if self ._is_on :
144143 self ._log .error (" Power Off Failed" )
145- return self .is_off
144+ return not self ._is_on
146145
147146 def powerOn (self ):
148147 """
@@ -152,21 +151,33 @@ def powerOn(self):
152151 bool: True if the operation is successful, False otherwise.
153152 """
154153 self ._get_state ()
155- if self .is_on :
154+ if self ._is_on :
156155 return True
157- if self ._outlet :
156+ if self ._outlet is not None :
158157 self ._performCommand ("on" , append_args = ["--index" , str (self ._outlet )])
159- self ._performCommand ("on" )
158+ else :
159+ self ._performCommand ("on" )
160160 self ._get_state ()
161- if self .is_on == False :
161+ if self ._is_on == False :
162162 self ._log .error (" Power On Failed" )
163- return self .is_on
163+ return self ._is_on
164164
165165 def _get_state (self ):
166166 """Get the state of the device.
167167 """
168168 result = self ._performCommand ("state" )
169- if self ._outlet :
169+ if self ._outlet is not None :
170+ # == Children ==
171+ #
172+ # == Smart Plug 1 (P304M) ==
173+ # == Primary features ==
174+ # State(state): True
175+ if result .find ('Children' ) > 1 : # smart extension plug with multiple outlets
176+ all_states = re .findall (r"^\s*State\s*\(state\)\s*:\s*(True|False)\s*$" ,
177+ result , flags = re .IGNORECASE | re .MULTILINE )
178+ self ._is_on = all_states [int (self ._outlet )] == 'True'
179+ self ._log .debug (f"Slot state: { 'ON' if self ._is_on else 'OFF' } " )
180+ return
170181 # We have a strip look at the status of the strip, and check the index and the device state
171182 #Device state: ON
172183 #== Plugs ==
@@ -233,6 +244,12 @@ def _discover_device(self):
233244 self ._device_type = info .get ("mic_type" , "UNKNOWN" )
234245 else :
235246 self ._device_type = "UNKNOWN"
247+ elif result .get ("get_child_device_list" , {}).get ('child_device_list' , []):
248+ child_devices = result .get ("get_child_device_list" , {}).get ('child_device_list' , [])
249+ if len (child_devices ) >= int (self ._outlet ) + 1 :
250+ self ._device_type = child_devices [int (self ._outlet )].get ("type" , "UNKNOWN" )
251+ elif result .get ('get_device_info' ):
252+ self ._device_type = result .get ("get_device_info" ).get ("type" , "UNKNOWN" )
236253 else :
237254 self ._device_type = "UNKNOWN"
238255 self ._encryption_type = self ._get_encryption_type ()
@@ -249,28 +266,30 @@ def _get_encryption_type(self):
249266 return None
250267
251268 def getPowerLevel (self ):
252- if self ._outlet :
253- # TODO: implement this for a powerstrip
254- # result = self._performCommand("emeter",
255- # json=True,
256- # append_args=["--index", str(self._outlet)])
257- raise RuntimeError ("Power monitoring is not yet supported for Tapo strips" )
269+ if self ._outlet is not None :
270+ args = [
271+ "--module" , 'energy' , 'get_current_power' ,
272+ "--index" , self ._outlet
273+ ]
258274 else :
259- result = self ._performCommand ("emeter" , json = True )
260-
261- if not result :
262- raise ValueError ("Received empty response from Tapo device for power monitoring" )
263-
264- try :
265- result = json .loads (result )
266- except json .JSONDecodeError as e :
267- raise ValueError (f"Failed to parse JSON from Tapo device response: { e } " )
268-
269- millewatt = result .get ('power_mw' )
270- if millewatt :
271- try :
272- power = int (millewatt ) / 1000
273- return power
274- except :
275- raise ValueError (f"Invalid value for power_mw: { millewatt } " )
276- raise KeyError ("The dictionary returned by the Tapo device does not contain a valid 'power_mw' value." )
275+ args = [
276+ "--module" , 'energy' , 'get_current_power'
277+ ]
278+ result = self ._performCommand ("command" ,
279+ json = True ,
280+ append_args = args
281+ )
282+
283+ if not result :
284+ raise ValueError ("Received empty response from Tapo device for power monitoring" )
285+
286+ try :
287+ result = json .loads (result )
288+ except json .JSONDecodeError as e :
289+ raise ValueError (f"Failed to parse JSON from Tapo device response: { e } " )
290+
291+ watt = result .get ("get_current_power" , {}).get ('current_power' , None )
292+ if watt is not None :
293+ return watt
294+
295+ raise KeyError ("The dictionary returned by the Tapo device does not contain a valid 'power_mw' value." )
0 commit comments