Fix spot area clean

Fix spot area clean
This commit is contained in:
Brian Martin
2019-02-15 22:27:47 -05:00
parent b0bf467aa4
commit 94a7844f78
2 changed files with 35 additions and 49 deletions
+32 -45
View File
@@ -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
View File
@@ -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():