diff --git a/sucks/__init__.py b/sucks/__init__.py index f8b7c4e..2b32ba5 100644 --- a/sucks/__init__.py +++ b/sucks/__init__.py @@ -6,9 +6,11 @@ from collections import OrderedDict from threading import Event import threading import sched - +import random +import ssl import requests import stringcase + from sleekxmpp import ClientXMPP, Callback, MatchXPath from sleekxmpp.xmlstream import ET from sleekxmpp.exceptions import XMPPError @@ -17,8 +19,6 @@ from paho.mqtt.client import Client as ClientMQTT from paho.mqtt import publish as MQTTPublish from paho.mqtt import subscribe as MQTTSubscribe -import ssl - _LOGGER = logging.getLogger(__name__) # These consts define all of the vocabulary used by this library when presenting various states and components. @@ -856,7 +856,7 @@ class EcoVacsIOTMQ(ClientMQTT): class EcoVacsXMPP(ClientXMPP): def __init__(self, user, domain, resource, secret, continent, vacuum, server_address=None ): - ClientXMPP.__init__(self, user + '@' + domain, '0/' + resource + '/' + secret) + ClientXMPP.__init__(self, "{}@{}/{}".format(user, domain,resource), '0/' + resource + '/' + secret) #Init with resource to bind it self.user = user self.domain = domain self.resource = resource @@ -922,12 +922,24 @@ class EcoVacsXMPP(ClientXMPP): def _wrap_command(self, ctl, recipient): q = self.make_iq_query(xmlns=u'com:ctl', ito=recipient, ifrom=self._my_address()) - q['type'] = 'set' + q['type'] = 'set' + if not "id" in ctl.attrib: + ctl.attrib["id"] = self.getReqID() #If no ctl id provided, add an id to the ctl. This was required for the ozmo930 and shouldn't hurt others for child in q.xml: if child.tag.endswith('query'): child.append(ctl) return q + def getReqID(self, customid="0"): #Generate a somewhat random string for request id, with minium 8 chars. Works similar to ecovacs app. + if customid != "0": + return "{}".format(customid) #return provided id as string + else: + rtnval = str(random.randint(1,50)) + while len(str(rtnval)) <= 8: + rtnval = "{}{}".format(rtnval,random.randint(0,50)) + + return "{}".format(rtnval) #return as string + def _my_address(self): if not self.vacuum['iotmq']: return self.user + '@' + self.domain + '/' + self.boundjid.resource @@ -995,10 +1007,8 @@ class VacBotCommand: class Clean(VacBotCommand): def __init__(self, mode='auto', speed='normal', iotmq=False, action='start',terminal=False, **kwargs): if kwargs == {}: - if not iotmq: - super().__init__('Clean', {'clean': {'type': CLEAN_MODE_TO_ECOVACS[mode], 'speed': FAN_SPEED_TO_ECOVACS[speed]}}) - else: - super().__init__('Clean', {'clean': {'type': CLEAN_MODE_TO_ECOVACS[mode], 'speed': FAN_SPEED_TO_ECOVACS[speed],'act': CLEAN_ACTION_TO_ECOVACS[action]}}) + #Looks like action is needed for some bots, shouldn't affect older models + super().__init__('Clean', {'clean': {'type': CLEAN_MODE_TO_ECOVACS[mode], 'speed': FAN_SPEED_TO_ECOVACS[speed],'act': CLEAN_ACTION_TO_ECOVACS[action]}}) else: initcmd = {'type': CLEAN_MODE_TO_ECOVACS[mode], 'speed': FAN_SPEED_TO_ECOVACS[speed]} for kkey, kvalue in kwargs.items(): diff --git a/tests/test_commands.py b/tests/test_commands.py index bbdd4a9..c40baf4 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -43,11 +43,11 @@ def test_custom_command_noargs(): def test_clean_command(): c = Clean() assert_equals(ElementTree.tostring(c.to_xml()), - b'') # protocol has attribs in other order + b'') # protocol has attribs in other order c = Clean('edge', 'high') assert_equals(ElementTree.tostring(c.to_xml()), - b'') # protocol has attribs in other order + b'') # protocol has attribs in other order c = Clean(iotmq=True) assert_equals(ElementTree.tostring(c.to_xml()), @@ -93,13 +93,13 @@ def test_spotarea_command(): def test_edge_command(): c = Edge() assert_equals(ElementTree.tostring(c.to_xml()), - b'') # protocol has attribs in other order + b'') # protocol has attribs in other order def test_spot_command(): c = Spot() assert_equals(ElementTree.tostring(c.to_xml()), - b'') # protocol has attribs in other order + b'') # protocol has attribs in other order def test_charge_command(): @@ -111,7 +111,7 @@ def test_charge_command(): def test_stop_command(): c = Stop() assert_equals(ElementTree.tostring(c.to_xml()), - b'') + b'') def test_play_sound_command(): diff --git a/tests/test_ecovacs_xmpp.py b/tests/test_ecovacs_xmpp.py index 1bd6b23..7f5331a 100644 --- a/tests/test_ecovacs_xmpp.py +++ b/tests/test_ecovacs_xmpp.py @@ -13,6 +13,20 @@ def test_wrap_command(): c = str(x._wrap_command(Clean().to_xml(), 'E0000000001234567890@126.ecorobot.net/atom')) assert_true(search(r'from="20170101abcdefabcdefa@ecouser.net/abcdef12"', c)) assert_true(search(r'to="E0000000001234567890@126.ecorobot.net/atom"', c)) + assert_true(search(r'td="Clean" id="',c)) #Check that an id was added to ctl + + cwithid = Clean().to_xml() + cwithid.attrib["id"] = "12345678" + c = str(x._wrap_command(cwithid, 'E0000000001234567890@126.ecorobot.net/atom')) + assert_true(search(r'td="Clean" id="12345678',c)) #Check that customid was added to ctl + +def test_getReqID(): + x = make_ecovacs_xmpp() + rid = x.getReqID("12345678") + assert_equals(rid, "12345678") #Check returned ID is the same as provided + + rid2 = x.getReqID() + assert_true(len(rid2) >= 8) #Check returned random ID is at least 8 chars def test_subscribe_to_ctls(): response = None