diff --git a/pyW215/pyW215.py b/pyW215/pyW215.py index 67075f0..3d22d9f 100644 --- a/pyW215/pyW215.py +++ b/pyW215/pyW215.py @@ -58,16 +58,13 @@ def __init__(self, ip, password, user = "admin", if self.use_legacy_protocol: _LOGGER.info("Enabled support for legacy firmware.") self._error_report = False - self.model_name = self.SOAPAction(Action="GetDeviceSettings", responseElement="ModelName", params = "") - - def moduleParameters(self, module): - """Returns moduleID XML. - - :type module: str - :param module: module number/ID - :return XML string with moduleID - """ - return '''{}'''.format(module) + self.model_name = self.get_soap_value(Action="GetDeviceSettings", responseElement="ModelName", params = "") + self.modules = { + 'socket': '1', + 'power': '2', + 'temperature': '3' + } + self.refresh_modules() def controlParameters(self, module, status): """Returns control parameters as XML. @@ -80,10 +77,10 @@ def controlParameters(self, module, status): """ if self.use_legacy_protocol : return '''{}Socket 1Socket 1 - {}1'''.format(self.moduleParameters(module), status) + {}1'''.format(module, status) else: return '''{}Socket 1Socket 1 - {}'''.format(self.moduleParameters(module), status) + {}'''.format(module, status) def radioParameters(self, radio): """Returns RadioID as XML. @@ -166,7 +163,10 @@ def SOAPAction(self, Action, responseElement, params = "", recursive = False): return return_value xmlData = response.read().decode() - root = ET.fromstring(xmlData) + return ET.fromstring(xmlData) + + def get_soap_value(self, Action, responseElement, params = ""): + root = self.SOAPAction(Action, responseElement, params) # Get value from device try: @@ -183,6 +183,24 @@ def SOAPAction(self, Action, responseElement, params = "", recursive = False): self._error_report = False return value + def get_soap_element(self, Action, responseElement, params = ""): + root = self.SOAPAction(Action, responseElement, params) + + # Get value from device + try: + value = root.find('.//{http://purenetworks.com/HNAP1/}%s' % (responseElement)) + except AttributeError: + _LOGGER.warning("Unable to find %s in response." % responseElement) + return None + + if value is None and self._error_report is False: + _LOGGER.warning("Could not find %s in response." % responseElement) + self._error_report = True + return None + + self._error_report = False + return value.getchildren() + def fetchMyCgi(self): """Fetches statistics from my_cgi.cgi""" try: @@ -195,6 +213,23 @@ def fetchMyCgi(self): lines = response.readlines() return {line.decode().split(':')[0].strip(): line.decode().split(':')[1].strip() for line in lines} + def refresh_modules(self): + if self.use_legacy_protocol: + # unsupported + return + try: + profiles = self.get_soap_element('GetModuleProfile', 'ModuleProfileList', params = "") + for profile in profiles: + id = profile.find('{http://purenetworks.com/HNAP1/}ModuleID').text + subtype = profile.find('{http://purenetworks.com/HNAP1/}ModuleSubType').text + if subtype == 'Electrical Power Meter': + self.modules['power'] = '{}'.format(id) + if subtype == 'Temperature Monitor': + self.modules['temperature'] = '{}'.format(id) + except: + # use default module ids + return + @property def current_consumption(self): """Get the current power consumption in Watt.""" @@ -207,7 +242,7 @@ def current_consumption(self): return 'N/A' else: try: - res = self.SOAPAction('GetCurrentPowerConsumption', 'CurrentConsumption', self.moduleParameters("2")) + res = self.get_soap_value('GetCurrentPowerConsumption', 'CurrentConsumption', self.modules['power']) except: return 'N/A' @@ -231,7 +266,7 @@ def total_consumption(self): res = 'N/A' try: - res = self.SOAPAction("GetPMWarningThreshold", "TotalConsumption", self.moduleParameters("2")) + res = self.get_soap_value("GetPMWarningThreshold", "TotalConsumption", self.modules['power']) except: return 'N/A' @@ -249,7 +284,7 @@ def total_consumption(self): def temperature(self): """Get the device temperature in celsius.""" try: - res = self.SOAPAction('GetCurrentTemperature', 'CurrentTemperature', self.moduleParameters("3")) + res = self.get_soap_value('GetCurrentTemperature', 'CurrentTemperature', self.modules['temperature']) except: res = 'N/A' @@ -258,7 +293,7 @@ def temperature(self): @property def state(self): """Get the device state (i.e. ON or OFF).""" - response = self.SOAPAction('GetSocketSettings', 'OPStatus', self.moduleParameters("1")) + response = self.get_soap_value('GetSocketSettings', 'OPStatus', self.modules['socket']) if response is None: return 'unknown' elif response.lower() == 'true': @@ -277,9 +312,9 @@ def state(self, value): :param value: Future state (either ON or OFF) """ if value.upper() == ON: - return self.SOAPAction('SetSocketSettings', 'SetSocketSettingsResult', self.controlParameters("1", "true")) + return self.get_soap_value('SetSocketSettings', 'SetSocketSettingsResult', self.controlParameters(self.modules['socket'], "true")) elif value.upper() == OFF: - return self.SOAPAction('SetSocketSettings', 'SetSocketSettingsResult', self.controlParameters("1", "false")) + return self.get_soap_value('SetSocketSettings', 'SetSocketSettingsResult', self.controlParameters(self.modules['socket'], "false")) else: raise TypeError("State %s is not valid." % str(value))