# Sends the robovac to the trash can to be emptied. import appdaemon.plugins.hass.hassapi as hass kEntity = "vacuum.roborock_vacuum_a19" # Coordinates of the trash can: kTrashcanX = 35600 kTrashcanY = 19000 kMinBatteryToEmpty = 50 # Percentage kMinBatteryToReturn = 20 # Percentage class Vacuum(hass.Hass): def AppName(self): return "app.vacuum" def AppState(self): """Can return one of ['clean', 'dirty', 'forced return', 'waiting dump'].""" # Read app state from "writeback_safe" namespace for persistence. # App remains in default namespace because vacuum lives there. state = self.get_state(self.AppName(), namespace="writeback_safe") if state == None: self.SetAppState("clean") return "clean" return state def SetAppState(self, state): # Write to our user namespace("writeback_safe") for persistence. self.set_state(self.AppName(), state=state, namespace="writeback_safe") self.set_state(self.AppName(), state=state) def initialize(self): self.AppState() self.listen_state(self.Update, kEntity, attribute="battery_level") self.listen_state(self.Update, kEntity, attribute="status") self.listen_state(self.Update, "sensor.tv_state") self.listen_state(self.Update, "person.greg") def GoToTrashCan(self): """Sends the vacuum to the trash can coordinates.""" self.log("Going to trash can") self.call_service( "xiaomi_miio/vacuum_goto", entity_id=kEntity, x_coord=kTrashcanX, y_coord=kTrashcanY ) def ReturnToCharger(self): """Sends the vacuum back to it's base.""" self.log("Returning to Charger") self.call_service( "vacuum/return_to_base", entity_id=kEntity ) def Update(self, entity, attribute, old, new, kwargs): """Callback for status or battery_level changes.""" self.EvalStateMachine() def EvalStateMachine(self): # One of ['clean', 'dirty', waiting dump'] app_state = self.AppState() is_tv_on = self.get_state("sensor.tv_state") == "on" is_greg_home = self.get_state("person.greg") == "home" try: battery_level = int(self.get_state(kEntity, attribute="battery_level")) except ValueError: return try: status = self.get_state(kEntity, attribute="status").lower() except AttributeError: return # There are multiple cases here, like "segment cleaning". if 'cleaning' in status: self.SetAppState("dirty") return if ((status == 'charging' or status == 'returning home') and app_state == "waiting dump"): self.SetAppState("clean") if (status == 'charging' and battery_level >= kMinBatteryToEmpty and app_state == 'dirty' and is_greg_home and not is_tv_on): self.SetAppState("waiting dump") self.GoToTrashCan() if app_state == "waiting_dump" and battery_level <= kMinBatteryToReturn: self.SetAppState("dirty") self.ReturnToCharger()