From 28da7c29dccaa72d20ed023651de5b7f8873fb93 Mon Sep 17 00:00:00 2001 From: Jason Arends Date: Sat, 22 Dec 2018 21:10:44 -0600 Subject: [PATCH 1/3] handle responses without a 'td' attrib - closes #57 --- sucks/__init__.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/sucks/__init__.py b/sucks/__init__.py index 1c01489..8091107 100644 --- a/sucks/__init__.py +++ b/sucks/__init__.py @@ -452,6 +452,7 @@ def subscribe_to_ctls(self, function): def _handle_ctl(self, message): the_good_part = message.get_payload()[0][0] + _LOGGER.debug('Message payload: ' + ET.tostring(the_good_part, method='xml').decode()) as_dict = self._ctl_to_dict(the_good_part) if as_dict is not None: for s in self.ctl_subscribers: @@ -461,11 +462,29 @@ def _ctl_to_dict(self, xml): result = xml.attrib.copy() if 'td' not in result: # This happens for commands with no response data, such as PlaySound - return + # Handle response data with no 'td' - result['event'] = result.pop('td') - if xml: - result.update(xml[0].attrib) + # return + if 'type' in result: # single element with type and val + result['event'] = "LifeSpan" # seems to always ben LifeSpan type + + else: + if len(xml) > 0: # case where there is child element + if 'clean' in xml[0].tag: + result['event'] = "CleanReport" + elif 'charge' in xml[0].tag: + result['event'] = "ChargeState" + elif 'battery' in xml[0].tag: + result['event'] = "BatteryInfo" + else: + return + result.update(xml[0].attrib) + else: # for non-'type' result with no child element, e.g., result of PlaySound + return + else: # response includes 'td' + result['event'] = result.pop('td') + if xml: + result.update(xml[0].attrib) for key in result: result[key] = stringcase.snakecase(result[key]) From 0c093097092b89e982e39d94e78581296a47dad3 Mon Sep 17 00:00:00 2001 From: Jason Arends Date: Sat, 22 Dec 2018 21:34:55 -0600 Subject: [PATCH 2/3] removed debug line and cleaned up - closes #57 --- sucks/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sucks/__init__.py b/sucks/__init__.py index 8091107..36ac356 100644 --- a/sucks/__init__.py +++ b/sucks/__init__.py @@ -452,7 +452,6 @@ def subscribe_to_ctls(self, function): def _handle_ctl(self, message): the_good_part = message.get_payload()[0][0] - _LOGGER.debug('Message payload: ' + ET.tostring(the_good_part, method='xml').decode()) as_dict = self._ctl_to_dict(the_good_part) if as_dict is not None: for s in self.ctl_subscribers: @@ -464,11 +463,11 @@ def _ctl_to_dict(self, xml): # This happens for commands with no response data, such as PlaySound # Handle response data with no 'td' - # return if 'type' in result: # single element with type and val - result['event'] = "LifeSpan" # seems to always ben LifeSpan type + result['event'] = "LifeSpan" # seems to always be LifeSpan type + # don't need to update attrib since there's no child - else: + else: # non-'type' result with child element that has attribs if len(xml) > 0: # case where there is child element if 'clean' in xml[0].tag: result['event'] = "CleanReport" From 43fa091e6137ede4679df2b0f345258acbd85c87 Mon Sep 17 00:00:00 2001 From: Jason Arends Date: Tue, 25 Dec 2018 23:34:57 -0600 Subject: [PATCH 3/3] Tests added for case where response does not contain td attrib which is normally used to tell the type of data in the tag. For LifeSpan responses there is no td, nor child element, but it includes 'type' attrib Status responses have a child element with the tag name indicating the type. --- tests/test_ecovacs_xmpp.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_ecovacs_xmpp.py b/tests/test_ecovacs_xmpp.py index ba79d4c..8e6b243 100644 --- a/tests/test_ecovacs_xmpp.py +++ b/tests/test_ecovacs_xmpp.py @@ -50,7 +50,22 @@ def test_xml_to_dict(): assert_dict_equal( x._ctl_to_dict(make_ctl('# ')), {'event': 'life_span', 'type': 'brush', 'val': '099', 'total': '365'}) + # set of xml responses without the td attrib + assert_dict_equal( + x._ctl_to_dict(make_ctl('')), + {'event': 'life_span', 'type': 'dust_case_heap', 'val': '050', 'total': '365'}) + + assert_dict_equal( + x._ctl_to_dict(make_ctl('')), + {'event': 'battery_info', 'power': '099', 'ret': 'ok', 'errno': ''}) + assert_dict_equal( + x._ctl_to_dict(make_ctl('')), + {'event': 'clean_report', 'type': 'stop', 'speed': 'strong', 'st':'h', 't': '', 'a': '', 'ret':'ok', 'errno': ''}) + + assert_dict_equal( + x._ctl_to_dict(make_ctl('')), + {'event': 'charge_state', 'type': 'slot_charging', 'ret': 'ok', 'errno': ''}) def make_ecovacs_xmpp(): return EcoVacsXMPP('20170101abcdefabcdefa', 'ecouser.net', 'abcdef12', 'A1b2C3d4efghijklmNOPQrstuvwxyz12', 'na')