Fix spot area clean
Fix spot area clean
This commit is contained in:
+32
-45
@@ -27,13 +27,14 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
CLEAN_MODE_AUTO = 'auto'
|
CLEAN_MODE_AUTO = 'auto'
|
||||||
CLEAN_MODE_EDGE = 'edge'
|
CLEAN_MODE_EDGE = 'edge'
|
||||||
CLEAN_MODE_SPOT = 'spot'
|
CLEAN_MODE_SPOT = 'spot'
|
||||||
CLEAN_MODE_SPOT_AREA = 'spotarea'
|
CLEAN_MODE_SPOT_AREA = 'spot_area'
|
||||||
CLEAN_MODE_SINGLE_ROOM = 'single_room'
|
CLEAN_MODE_SINGLE_ROOM = 'single_room'
|
||||||
CLEAN_MODE_STOP = 'stop'
|
CLEAN_MODE_STOP = 'stop'
|
||||||
|
|
||||||
CLEAN_ACTION_START = 'start'
|
CLEAN_ACTION_START = 'start'
|
||||||
CLEAN_ACTION_PAUSE = 'pause'
|
CLEAN_ACTION_PAUSE = 'pause'
|
||||||
CLEAN_ACTION_RESUME = 'resume'
|
CLEAN_ACTION_RESUME = 'resume'
|
||||||
|
CLEAN_ACTION_STOP = 'stop'
|
||||||
|
|
||||||
FAN_SPEED_NORMAL = 'normal'
|
FAN_SPEED_NORMAL = 'normal'
|
||||||
FAN_SPEED_HIGH = 'high'
|
FAN_SPEED_HIGH = 'high'
|
||||||
@@ -67,13 +68,21 @@ CLEAN_ACTION_TO_ECOVACS = {
|
|||||||
CLEAN_ACTION_START: 's',
|
CLEAN_ACTION_START: 's',
|
||||||
CLEAN_ACTION_PAUSE: 'p',
|
CLEAN_ACTION_PAUSE: 'p',
|
||||||
CLEAN_ACTION_RESUME: 'r',
|
CLEAN_ACTION_RESUME: 'r',
|
||||||
|
CLEAN_ACTION_STOP: 'h',
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEAN_ACTION_FROM_ECOVACS = {
|
||||||
|
's': CLEAN_ACTION_START,
|
||||||
|
'p': CLEAN_ACTION_PAUSE,
|
||||||
|
'r': CLEAN_ACTION_RESUME,
|
||||||
|
'h': CLEAN_ACTION_STOP,
|
||||||
}
|
}
|
||||||
|
|
||||||
CLEAN_MODE_FROM_ECOVACS = {
|
CLEAN_MODE_FROM_ECOVACS = {
|
||||||
'auto': CLEAN_MODE_AUTO,
|
'auto': CLEAN_MODE_AUTO,
|
||||||
'border': CLEAN_MODE_EDGE,
|
'border': CLEAN_MODE_EDGE,
|
||||||
'spot': CLEAN_MODE_SPOT,
|
'spot': CLEAN_MODE_SPOT,
|
||||||
'SpotArea': CLEAN_MODE_SPOT_AREA,
|
'spot_area': CLEAN_MODE_SPOT_AREA,
|
||||||
'singleroom': CLEAN_MODE_SINGLE_ROOM,
|
'singleroom': CLEAN_MODE_SINGLE_ROOM,
|
||||||
'stop': CLEAN_MODE_STOP,
|
'stop': CLEAN_MODE_STOP,
|
||||||
'going': CHARGE_MODE_RETURNING
|
'going': CHARGE_MODE_RETURNING
|
||||||
@@ -397,12 +406,15 @@ class VacBot():
|
|||||||
self.iot.subscribe_to_ctls(self._handle_ctl)
|
self.iot.subscribe_to_ctls(self._handle_ctl)
|
||||||
self.mqtt = EcoVacsMQTT(user, domain, resource, secret, continent, vacuum, server_address)
|
self.mqtt = EcoVacsMQTT(user, domain, resource, secret, continent, vacuum, server_address)
|
||||||
self.mqtt.subscribe_to_ctls(self._handle_ctl)
|
self.mqtt.subscribe_to_ctls(self._handle_ctl)
|
||||||
self.xmpp = EcoVacsXMPP(user, domain, resource, secret, continent, vacuum, server_address)
|
#self.xmpp = EcoVacsXMPP(user, domain, resource, secret, continent, vacuum, server_address)
|
||||||
self.xmpp.subscribe_to_ctls(self._handle_ctl)
|
#Uncomment line to allow unencrypted plain auth
|
||||||
|
#self.xmpp['feature_mechanisms'].unencrypted_plain = True
|
||||||
|
#self.xmpp.subscribe_to_ctls(self._handle_ctl)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.xmpp = EcoVacsXMPP(user, domain, resource, secret, continent, vacuum, server_address)
|
self.xmpp = EcoVacsXMPP(user, domain, resource, secret, continent, vacuum, server_address)
|
||||||
|
#Uncomment line to allow unencrypted plain auth
|
||||||
|
#self.xmpp['feature_mechanisms'].unencrypted_plain = True
|
||||||
self.xmpp.subscribe_to_ctls(self._handle_ctl)
|
self.xmpp.subscribe_to_ctls(self._handle_ctl)
|
||||||
|
|
||||||
|
|
||||||
@@ -413,6 +425,7 @@ class VacBot():
|
|||||||
else:
|
else:
|
||||||
self.mqtt.connect_and_wait_until_ready()
|
self.mqtt.connect_and_wait_until_ready()
|
||||||
self.mqtt.schedule(30, self.send_ping)
|
self.mqtt.schedule(30, self.send_ping)
|
||||||
|
#self.xmpp.connect_and_wait_until_ready()
|
||||||
|
|
||||||
if self._monitor:
|
if self._monitor:
|
||||||
# Do a first ping, which will also fetch initial statuses if the ping succeeds
|
# Do a first ping, which will also fetch initial statuses if the ping succeeds
|
||||||
@@ -459,19 +472,15 @@ class VacBot():
|
|||||||
type = event['type']
|
type = event['type']
|
||||||
try:
|
try:
|
||||||
type = CLEAN_MODE_FROM_ECOVACS[type]
|
type = CLEAN_MODE_FROM_ECOVACS[type]
|
||||||
|
if self.vacuum['iot']: #Was able to parse additional status from the IOT, may apply to XMPP too
|
||||||
|
statustype = event['st']
|
||||||
|
statustype = CLEAN_ACTION_FROM_ECOVACS[statustype]
|
||||||
|
if statustype == CLEAN_ACTION_STOP or statustype == CLEAN_ACTION_PAUSE:
|
||||||
|
type = statustype
|
||||||
except KeyError:
|
except KeyError:
|
||||||
_LOGGER.warning("Unknown cleaning status '" + type + "'")
|
_LOGGER.warning("Unknown cleaning status '" + type + "'")
|
||||||
self.clean_status = type
|
self.clean_status = type
|
||||||
self.vacuum_status = type
|
self.vacuum_status = type
|
||||||
|
|
||||||
if self.vacuum['iot']: #Was able to parse additional status from the IOT, may apply to XMPP too
|
|
||||||
cleaning = event.get('st', None)
|
|
||||||
if cleaning == 'p':
|
|
||||||
self.clean_status = 'paused'
|
|
||||||
elif cleaning == 'h':
|
|
||||||
self.clean_status = 'standby'
|
|
||||||
else:
|
|
||||||
self.clean_status = 'cleaning'
|
|
||||||
|
|
||||||
fan = event.get('speed', None)
|
fan = event.get('speed', None)
|
||||||
if fan is not None:
|
if fan is not None:
|
||||||
@@ -541,13 +550,13 @@ class VacBot():
|
|||||||
try:
|
try:
|
||||||
if not self.vacuum['iot']:
|
if not self.vacuum['iot']:
|
||||||
self.xmpp.send_ping(self._vacuum_address())
|
self.xmpp.send_ping(self._vacuum_address())
|
||||||
elif self.vacuum['iot']:
|
elif self.vacuum['iot']:
|
||||||
if not self.mqtt.send_ping():
|
if not self.mqtt.send_ping():
|
||||||
raise RuntimeError()
|
raise RuntimeError()
|
||||||
|
|
||||||
#self.xmpp.send_ping(EcoVacsAPI.REALM) #IOT vacuums are using the realm instead
|
#self.xmpp.send_ping(EcoVacsAPI.REALM) #IOT vacuums are using the realm instead
|
||||||
#Some devices may utilize this, but it appears to
|
#Some devices may utilize this, but it appears to
|
||||||
# just be an oversight in the app communidcations. IOT should probably be using MQTT pings (which are automatic when connected)
|
# just be an oversight in the app communications. IOT should probably be using MQTT pings (which are automatic when connected)
|
||||||
|
|
||||||
|
|
||||||
except XMPPError as err:
|
except XMPPError as err:
|
||||||
@@ -618,6 +627,7 @@ class VacBot():
|
|||||||
self.xmpp.disconnect(wait=wait)
|
self.xmpp.disconnect(wait=wait)
|
||||||
else:
|
else:
|
||||||
self.mqtt._disconnect()
|
self.mqtt._disconnect()
|
||||||
|
#self.xmpp.disconnect(wait=wait)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -793,7 +803,7 @@ class EcoVacsMQTT(ClientMQTT):
|
|||||||
self.ctl_subscribers.append(function)
|
self.ctl_subscribers.append(function)
|
||||||
|
|
||||||
def _handle_ctl(self, client, userdata, message):
|
def _handle_ctl(self, client, userdata, message):
|
||||||
_LOGGER.debug("EcoVacs MQTT Received Message on Topic: {} - Message: {}".format(message.topic, str(message.payload.decode("utf-8"))))
|
#_LOGGER.debug("EcoVacs MQTT Received Message on Topic: {} - Message: {}".format(message.topic, str(message.payload.decode("utf-8"))))
|
||||||
as_dict = self._ctl_to_dict(message.topic, str(message.payload.decode("utf-8")))
|
as_dict = self._ctl_to_dict(message.topic, str(message.payload.decode("utf-8")))
|
||||||
if as_dict is not None:
|
if as_dict is not None:
|
||||||
for s in self.ctl_subscribers:
|
for s in self.ctl_subscribers:
|
||||||
@@ -843,7 +853,6 @@ class EcoVacsMQTT(ClientMQTT):
|
|||||||
_LOGGER.debug("*** MQTT sending ping ***")
|
_LOGGER.debug("*** MQTT sending ping ***")
|
||||||
rc = self._send_simple_command(MQTTPublish.paho.PINGREQ)
|
rc = self._send_simple_command(MQTTPublish.paho.PINGREQ)
|
||||||
if rc == MQTTPublish.paho.MQTT_ERR_SUCCESS:
|
if rc == MQTTPublish.paho.MQTT_ERR_SUCCESS:
|
||||||
_LOGGER.debug("*** MQTT ping acknowledged ***")
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -868,33 +877,9 @@ class EcoVacsMQTT(ClientMQTT):
|
|||||||
self.wait_until_ready()
|
self.wait_until_ready()
|
||||||
|
|
||||||
|
|
||||||
# def send_command(self, xml, recipient): #MQTT doesn't seem to care about commands we send today, but leaving in case of futures
|
|
||||||
# #c = self._wrap_command(xml, recipient)
|
|
||||||
# #_LOGGER.debug('Sending command {0}'.format(c))
|
|
||||||
# txml = '"<ctl td="Move"><move action="backward" /></ctl>'
|
|
||||||
# _LOGGER.debug('Sending command {0}'.format(txml))
|
|
||||||
# self.publish('iot/atr/Move/' + self.vacuum['did'] + '/' + self.vacuum['class'] + '/' + self.vacuum['resource'] + '/x', txml)
|
|
||||||
# #<ctl td="Move"><move action="backward" /></ctl>
|
|
||||||
|
|
||||||
# def _wrap_command(self, ctl, recipient):
|
|
||||||
# q = self.make_iq_query(xmlns=u'com:ctl', ito=recipient, ifrom=self._my_address())
|
|
||||||
# q['type'] = 'set'
|
|
||||||
# for child in q.xml:
|
|
||||||
# if child.tag.endswith('query'):
|
|
||||||
# child.append(ctl)
|
|
||||||
# return q
|
|
||||||
|
|
||||||
# def _my_address(self):
|
|
||||||
# if not self.vacuum['iot']:
|
|
||||||
# return self.user + '@' + self.domain + '/' + self.boundjid.resource
|
|
||||||
# else:
|
|
||||||
# return self.user + '@' + self.domain + '/' + self.resource
|
|
||||||
|
|
||||||
|
|
||||||
class EcoVacsXMPP(ClientXMPP):
|
class EcoVacsXMPP(ClientXMPP):
|
||||||
def __init__(self, user, domain, resource, secret, continent, vacuum, server_address=None ):
|
def __init__(self, user, domain, resource, secret, continent, vacuum, server_address=None ):
|
||||||
ClientXMPP.__init__(self, user + '@' + domain, '0/' + resource + '/' + secret)
|
ClientXMPP.__init__(self, user + '@' + domain, '0/' + resource + '/' + secret)
|
||||||
|
|
||||||
self.user = user
|
self.user = user
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.resource = resource
|
self.resource = resource
|
||||||
@@ -909,6 +894,7 @@ class EcoVacsXMPP(ClientXMPP):
|
|||||||
self.ctl_subscribers = []
|
self.ctl_subscribers = []
|
||||||
self.ready_flag = Event()
|
self.ready_flag = Event()
|
||||||
|
|
||||||
|
|
||||||
def wait_until_ready(self):
|
def wait_until_ready(self):
|
||||||
self.ready_flag.wait()
|
self.ready_flag.wait()
|
||||||
|
|
||||||
@@ -979,6 +965,7 @@ class EcoVacsXMPP(ClientXMPP):
|
|||||||
q.send()
|
q.send()
|
||||||
|
|
||||||
def connect_and_wait_until_ready(self):
|
def connect_and_wait_until_ready(self):
|
||||||
|
|
||||||
self.connect(self.server_address)
|
self.connect(self.server_address)
|
||||||
self.process()
|
self.process()
|
||||||
self.wait_until_ready()
|
self.wait_until_ready()
|
||||||
@@ -1059,9 +1046,9 @@ class Stop(Clean):
|
|||||||
class SpotArea(Clean):
|
class SpotArea(Clean):
|
||||||
def __init__(self, action='start', namedarea='', customarea='', cleanings='1'):
|
def __init__(self, action='start', namedarea='', customarea='', cleanings='1'):
|
||||||
if namedarea != '': #For cleaning specified map area
|
if namedarea != '': #For cleaning specified map area
|
||||||
super().__init__('spotarea', 'normal', act=CLEAN_ACTION_TO_ECOVACS[action], mid=namedarea)
|
super().__init__('spot_area', 'normal', act=CLEAN_ACTION_TO_ECOVACS[action], mid=namedarea)
|
||||||
elif customarea != '': #For cleaning custom map area, and specify deep amount 1x/2x
|
elif customarea != '': #For cleaning custom map area, and specify deep amount 1x/2x
|
||||||
super().__init__('spotarea' ,'normal',act=CLEAN_ACTION_TO_ECOVACS[action], p=customarea, deep=cleanings)
|
super().__init__('spot_area' ,'normal',act=CLEAN_ACTION_TO_ECOVACS[action], p=customarea, deep=cleanings)
|
||||||
else:
|
else:
|
||||||
#no valid entries
|
#no valid entries
|
||||||
raise ValueError("must provide namedarea or customarea for spotarea clean")
|
raise ValueError("must provide namedarea or customarea for spotarea clean")
|
||||||
|
|||||||
+3
-4
@@ -179,11 +179,10 @@ def edge(frequency, minutes):
|
|||||||
return CliAction(Edge(), wait=TimeWait(minutes * 60))
|
return CliAction(Edge(), wait=TimeWait(minutes * 60))
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help='spotcleans provided room(s) for the specified number of minutes')
|
@cli.command(help='spotcleans provided room(s)')
|
||||||
@click.argument('room', type=click.STRING)
|
@click.argument('room', type=click.STRING)
|
||||||
@click.argument('minutes', type=click.FLOAT)
|
def spotclean(room):
|
||||||
def spotclean(room, minutes):
|
return CliAction(SpotArea('start', room), wait=StatusWait('charge_status', 'returning'))
|
||||||
return CliAction(SpotArea('start', room), wait=TimeWait(minutes * 60))
|
|
||||||
|
|
||||||
@cli.command(help='returns to charger')
|
@cli.command(help='returns to charger')
|
||||||
def charge():
|
def charge():
|
||||||
|
|||||||
Reference in New Issue
Block a user