Roborock S6 MaxV

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

Roborock S6 MaxV

Beitrag von Cyrelian »

Hallo zusammen,

ich habe mir vor einigen Tagen ein neues Spielzeug zugelegt und direkt mal in openHAB eingebunden.
Wichtig vorweg: Der Roborock muss mit der Xiaomi MiHome App verwendet werden. Wenn er über die Roborock App verwendet wird, dann kann das Xiaomi Mi IO Binding nicht mit dem Roborock "sprechen" ;)

Und so sieht die Konfig aus:

ITEMS:

Code: Alles auswählen

/* -------------  Xiaomi Roborock --------------------
 */
// Gruppen
Group                      gRoborockVac           "Roborock S6 MaxV"                <s6max>            (gSystem)         ["Equipment"]
Group                      gRoborockVacStat       "Gerätezustand"                   <status>           (gRoborockVac)
Group                      gRoborockVacUsage      "Wartung / Verbrauchsmaterial"    <line-increase>    (gRoborockVac)
Group                      gRoborockVacDND        "Nicht-Stören Einstellungen"      <moon>             (gRoborockVac)
Group                      gRoborockVacHistory    "Reinigungsverlauf"               <calendar>         (gRoborockVac)
Group                      gRoborockVacNetwork    "Netzwerk Details"                <network>          (gRoborockVac)
Group:Switch:OR(ON,OFF)    gRoborockVacRooms      "Räume"                           <network>          (gRoborockVac)

// Räume
Switch    RoborockVacRoom1    "Wohnzimmer saugen"      <sofa>            (gRoborockVacRooms)
Switch    RoborockVacRoom2    "Badezimmer saugen"      <bath>            (gRoborockVacRooms)
Switch    RoborockVacRoom3    "Flur saugen"            <corridor>        (gRoborockVacRooms)
Switch    RoborockVacRoom4    "Schlafzimmer saugen"    <bedroomadult>    (gRoborockVacRooms)
Switch    RoborockVacRoom5    "Küche saugen"           <kitchen>         (gRoborockVacRooms)
Switch    RoborockVacRoom6    "Gästeklo saugen"        <toilet>          (gRoborockVacRooms)
Switch    RoborockVacRoom7    "Büro saugen"            <office>          (gRoborockVacRooms)

//Control
String    RoborockVac_Control    "Steuerung"                                     <s6max>    (gRoborockVac)        {channel="miio:vacuum:XXXXXXX:actions#control"}
Number    RoborockVac_Fan        "Saugleistung [MAP(roborock_status.map):%s]"    <s6max>    (gRoborockVac)        {channel="miio:vacuum:XXXXXXX:actions#fan"}
String    RoborockVac_Command    "Robo Befehl"                                  <s6max>    (gRoborockVac)         {channel="miio:vacuum:XXXXXXX:actions#commands"}	//actionCommand.sendCommand("get_room_mapping") /
String    RoborockVac_Segment    "Einzelraumreinigung"                           <s6max>    (gRoborockVac)        {channel="miio:vacuum:XXXXXXX:actions#segment"}	//{\"result\":[[18,\"169001026039\"],[21,\"169001026079\"],[22,\"169001026081\"],[16,\"169001026082\"],[17,\"169001026078\"],[19,\"169001026080\"],[20,\"169001026083\"]],\"id\":12298}"
Switch    RoborockVac_Test       "Test"                                          <s6max>    (gRoborockVacStat)

//Status
String    RoborockVac_State             "Status:[MAP(roborock_status.map):%s]"          <chart>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#state"}
Number    RoborockVac_StateID           "Status ID: [%s]"                               <chart>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#state_id"}
Number    RoborockVac_Battery           "Battery Level [%1.0f %%]"                      <battery>    (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#battery"}
Number    RoborockVac_Area              "Gereinigte Fläche [%1.0f m²]"                  <zoom>       (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#clean_area"}
Number    RoborockVac_Time              "Reinigungszeit [%1.0f Min.]"                   <time>       (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#clean_time"}
String    RoborockVac_Error             "Fehler: [MAP(roborock_error.map):%s]"          <error>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#error_code"}
Number    RoborockVac_ErrorID           "Fehler ID: [MAP(roborock_error.map):%s]"       <error>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#error_id"}
Number    RoborockVac_FanPower          "Saugleistung [MAP(roborock_status.map):%s]"    <fan>        (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#fan_power"}
Number    RoborockVac_CleanStats        "Reinigungsstatus [%1.0f]"                      <switch>     (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#in_cleaning"}
Switch    RoborockVac_DND               "DND aktiviert"                                 <switch>     (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#dnd_enabled"}
Switch    RoborockVac_Mop               "Mop Forbidden"                                 <status>     (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#mop_forbidden_enable"}
Switch    RoborockVac_WaterBoxState     "Wassertank montiert"                           <water>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#water_box_status"}
Switch    RoborockVac_LockState         "Lock State"                                    <status>     (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#lock_status"}
Number    RoborockVac_WaterBoxMode      "Wassermenge [MAP(roborock_status.map):%s]"     <water>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#water_box_mode"}
Switch    RoborockVac_WaterBoxCState    "carriage mounted"                              <water>      (gRoborockVacStat)    {channel="miio:vacuum:XXXXXXX:status#water_box_carriage_status"}


//Verbrauch
Number    RoborockVac_MainT      "Hauptbürste tauschen in [%1.0f Std.]"     <line-increase>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#main_brush_time"}
Number    RoborockVac_MainP      "Hauptbürste [%1.0f %%]"                   <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#main_brush_percent"}
Number    RoborockVac_SideT      "Seitenbürste tauschen in [%1.0f Std.]"    <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#side_brush_time"}
Number    RoborockVac_SideP      "Seitenbürste [%1.0f %%]"                  <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#side_brush_percent"}
Number    RoborockVac_FilterT    "Filter tauschen in [%1.0f Std.]"          <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#filter_time"}
Number    RoborockVac_FilterP    "Filter [%1.0f %%]"                        <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#filter_percent"}
Number    RoborockVac_SensorT    "Sensor reinigen in [%1.0f Std.]"          <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#sensor_dirt_time"}
Number    RoborockVac_SensorP    "Sensor [%1.0f%%]"                         <line-decrease>    (gRoborockVacUsage)    {channel="miio:vacuum:XXXXXXX:consumables#sensor_dirt_percent"}

//DND - Do not Disturb
Switch    RoborockVac_DND_Function    "DND Funktion"              <moon>       (gRoborockVacDND)    {channel="miio:vacuum:XXXXXXX:dnd#dnd_function"}
String    RoborockVac_DND_Start       "DND Startzeit [%s] Uhr"    <time>       (gRoborockVacDND)    {channel="miio:vacuum:XXXXXXX:dnd#dnd_start"}
String    RoborockVac_DND_End         "DND Endzeit [%s] Uhr"      <time-on>    (gRoborockVacDND)    {channel="miio:vacuum:XXXXXXX:dnd#dnd_end"}

// Statistik
Number    RoborockVac_HistArea     "Gereinigte Fläche (Gesamt) [%1.0f m²]"    <zoom>      (gRoborockVacHistory)    {channel="miio:vacuum:XXXXXXX:history#total_clean_area"}
Number    RoborockVac_HistTime     "Reinigungszeit (Gesamt) [%1.0f Min.]"     <time>      (gRoborockVacHistory)    {channel="miio:vacuum:XXXXXXX:history#total_clean_time"}
Number    RoborockVac_HistCount    "Reinigungsvorgänge [%1.0f]"               <office>    (gRoborockVacHistory)    {channel="miio:vacuum:XXXXXXX:history#total_clean_count"}

// Cleaning Details
DateTime       RoborockVac_CleanLastStart       "Letzte Ausführung (Start) [%1$td.%1$tm %1$tH:%1$tM Uhr]"    <time>    {channel="miio:vacuum:XXXXXXX:cleaning#last_clean_start_time"}
DateTime       RoborockVac_CleanLastEnd         "Letzte Ausführung (Ende) [%1$td.%1$tm %1$tH:%1$tM Uhr]"     <time>    {channel="miio:vacuum:XXXXXXX:cleaning#last_clean_end_time"}
Number:Area    RoborockVac_CleanLastArea        "Letzte gereiniget Fläche"                                   <time>    {channel="miio:vacuum:XXXXXXX:cleaning#last_clean_area"}
Number:Time    RoborockVac_CleanLastDuration    "Dauer der letzten Reinigung"                                <time>    {channel="miio:vacuum:XXXXXXX:cleaning#last_clean_duration"}
Number         RoborockVac_CleanLastError       "Letzer Fehler"                                              <time>    {channel="miio:vacuum:XXXXXXX:cleaning#last_clean_error"}
Number         RoborockVac_CleanLastFinish      "Finish"                                                     <time>    {channel="miio:vacuum:XXXXXXX:cleaning#last_clean_finish"}
Image          RoborockVac_CleanMap             "MAP"                                                        <map>     {channel="miio:vacuum:XXXXXXX:cleaning#map"}

//Netzwerk
String    RoborockVac_NetSSID     "Network SSID [%s]"       <network>    (gRoborockVacNetwork)    {channel="miio:vacuum:XXXXXXX:network#ssid"}
String    RoborockVac_NetBSSID    "Network BSSID [%s]"      <network>    (gRoborockVacNetwork)    {channel="miio:vacuum:XXXXXXX:network#bssid"}
Number    RoborockVac_NetRSSI     "Network RSSI [%1.0f]"    <network>    (gRoborockVacNetwork)    {channel="miio:vacuum:XXXXXXX:network#rssi"}
Number    RoborockVac_NetLife     "Uptime [%1.0f]"          <time>       (gRoborockVacNetwork)    {channel="miio:vacuum:XXXXXXX:network#life"}
TRANSFORM:

roborock_error.map

Code: Alles auswählen

0=keine Fehler
1=Fehler Laserdistanzsensor
2=Fehler Kollisionssensor
3=Räder ohne Haftung
4=Fehler Absturzsensors
5=Hauptbürste blockert
6=Seitenbürste blockiert
7=Räder blockiert
8=Staubsauger festgefahren
9=Staubbehälter fehlt
10=Filter blockiert
11=Magnetisches Feld erkannt
12=Akkustand niedrig
13=Ladefehler
14=Akkufehler
15=Wandsensoren verschmutzt
16=Unebene Oberfläche
17=Fehler Seitenbürste
18=Fehler Sauggebläse
19=Ladestation ohne Strom
20=Unknown Error
21=Fehler Laserdrucksensor
22=Fehler Ladesensor
23=Problem beim andocken
24=No-go zone or invisible wall detected
254=Staubbehälter voll
255=Internal error
-1=Unknown Error

No\ error=keine Fehler
Laser\ distance\ sensor\ error=Fehler Laserdistanzsensor
Collision\ sensor\ error=Fehler Kollisionssensor
Wheels\ on\ top\ of\ void,\ move\ robot=Räder ohne Haftung, Roboter bewegen
Clean\ hovering\ sensors,\ move\ robot=Schwebesensoren reinigen
Clean\ main\ brush=Hauptbürste reinigen
Clean\ side\ brush=Seitenbürste reinigen
Main\ wheel\ stuck?=Hauptrad blockiert?
Device\ stuck,\ clean\ area=Staubsauger festgefahren
Dust\ collector\ missing=Staubbehälter fehlt
Clean\ filter=Filter reinigen
Stuck\ in\ magnetic\ barrier=in Magnetschranke festgefahren
Low\ battery=Akkustand niedrig
Charging\ fault=Ladefehler
Battery\ fault=Akkufehler
Wall\ sensors\ dirty,\ wipe\ them=Wandsensoren verschmutzt
Place\ me\ on\ flat\ surface=auf flachem Untergrund platzieren
Side\ brushes\ problem,\ reboot\ me=Fehler Seitenbürste
Suction\ fan\ problem=Fehler Sauggebläse
Unpowered\ charging\ station=Ladestation ohne Strom
Unknown\ Error=unbekannter Fehler
Unknown=unbekannt ⁉
NULL=unbekannt ⁉
-=-Fehler bei der Initialisierung-
roborock_status.map

Code: Alles auswählen

0=abgebrochen ✘
1=erledigt ✔

101=Leise
102=Normal
103=Turbo
104=Max
105=Gentle
106=Benutzerdef.(Auto)
-1=(Auto)

200=aus ✘
201=wenig
202=mittel
203=viel
204=Benutzerdef.(Auto)

Idle=Standby…
Sleeping=Ruhemodus
Cleaning=Aktiv ⤨
Paused=Pause
Returning\ Dock=FERTIG ✔
Charging=Aufladen ↻
Charging\ Error=Ladefehler ✘

Initiating=Initiiere
Remote\ Control=Fernbedienung
Manual\ Mode=manueller Modus
Charging\ Error=Ladefehler
Spot\ Cleaning=punktuelle Reinigung
In\ Error=Fehler
Shutting\ Down=Herunterfahren
Updating=Aktualisierung
Docking=Andocken
Zone\ Clean=Zonenreinigung
Room\ Clean=Raumreinigung
Full=Voll
Fully\ Charged=Voll
Unknown=unbekannt ⁉
NULL=unbekannt ⁉
-=-Fehler bei der Initialisierung-

//0	unbekannt ⁉
//1	Initiiere
2=Ruhemodus
3=Standby…
4=Fernbedienung
5=Aktiv ⤨
6=FERTIG ✔
7=manueller Modus
8=Aufladen ↻
9=Ladefehler
10=Pause
11=punktuelle Reinigung
12r=Fehler
13=Herunterfahren
14=Aktualisierung
15=Andocken
16=Go To
17=Zonenreinigung
18=Raumreinigung
100=Voll
RULE:

Code: Alles auswählen

val HashMap<String,String> Raeume = newHashMap("RoborockVacRoom1" -> "app_segment_clean[16]", // Büro
                                               "RoborockVacRoom2" -> "app_segment_clean[17]", // ?
                                               "RoborockVacRoom3" -> "app_segment_clean[18]", // ?
                                               "RoborockVacRoom4" -> "app_segment_clean[19]", // ?
                                               "RoborockVacRoom5" -> "app_segment_clean[20]", // ?
                                               "RoborockVacRoom6" -> "app_segment_clean[21]", // Wohnzimmer
                                               "RoborockVacRoom7" -> "app_segment_clean[22]") // ?

rule "Roborock room cleaning"
when
    Item RoborockVac_State changed from "Returning Dock" to "Charging" or   // Roboter ist zurück in der Station
    Item RoborockVac_Test changed to ON                                    // Testschalter  EIN
then
    if(gRoborockVacRooms.members.filter[s|s.state == ON].size == 0) {      // Letzter Raum schon gesaugt
        logInfo("rules", logPrefix + "Alle Räume gesaugt!")
        if(RoborockVac_Test.state != OFF)                                  // Falls Schalter nicht OFF
            RoborockVac_Test.postUpdate(OFF)                               // auf OFF
            return;
    }
    val vacRoom = gRoborockVacRooms.members.filter[s|s.state == ON].sortBy[name].head // 1. Element der Liste
    //logInfo("rules", logPrefix + "{}. Raum ({}) gewählt",Raeume,vacRoom.name)
    val String strRaum = Raeume.get(vacRoom.name)                           // Variable initialisieren
    logInfo("vacuum","Raumzone {} gewählt",strRaum)
    logInfo("rules", logPrefix + "Raumzone {} gewählt",strRaum)
    RoborockVac_Command.sendCommand(strRaum)                                // Raum saugen
    vacRoom.postUpdate(OFF)
    RoborockVac_Test.postUpdate(OFF)
end
Die Rule kommt von Udo viewtopic.php?f=15&t=3791. Ich hatte diese mal implementiert, aber für mich ist diese nicht wirklich brauchbar, da der Robi nach jedem Raum wieder is "Dock" fährt um dann direkt wieder loszufahren. Da werde ich nochmal etwas anderes bauen. Ansosten funktioniert die Rule TOP.

SITEMAP:

Code: Alles auswählen

Frame label="Roborock" icon="s6max" {
		Text label="Roborock" icon="s6max" {
		Frame label="Steuerung" {
			Switch item=RoborockVac_Control label="Steuerung []" mappings=[vacuum="Reinigen", pause="Pause",spot="Spot", dock="Laden"]
			Switch item=RoborockVac_Fan label="Saugleistung []" mappings=[101="Leise", 102="Normal", 103="Turbo",104="Max", -1="Custom"]
		}
		Frame label="Status" {
			Default item=RoborockVac_CleanLastStart
			Default item=RoborockVac_CleanLastEnd
			Default item=RoborockVac_CleanLastArea
			Default item=RoborockVac_CleanLastDuration
			Default item=RoborockVac_Battery
			Group	item=gRoborockVacStat
			Group	item=gRoborockVacNetwork
		}
		Frame label="Einstellungen" {
				Group	item=gRoborockVacRooms
				Group	item=gRoborockVacDND 
			}
		Frame label="Statistik" {
			Group	item=gRoborockVacUsage
			Group	item=gRoborockVacHistory
			}
		Frame label="Map"{
			Image 	item=RoborockVac_CleanMap	
			}
		}
	}
Bildschirmfoto 2021-05-07 um 13.22.51.png
Vielleicht hilft das dem einen oder anderen von Euch weiter. Für Ideen und Anregungen bin ich immer offen.
CYA
Cyrelian
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

mbw83
Beiträge: 5
Registriert: 29. Jun 2021 10:06

Re: Roborock S6 MaxV

Beitrag von mbw83 »

Basierend auf deinem Beitrag habe ich unseren Roborock S6 MaxV auch in OpenHAB eingebunden.
Unserer steht zum Laden unter einem Regal und der Roboter ist daher nicht wirklich zugänglich. Mich hat daher von Anfang an genervt, dass wir, um den Staubbehälter zu leeren, irgendwelche "Handstände" machen müssen (also z.B. eine Reinigung starten, die dann sofort abgebrochen wird oder mit dem Joystick mühevoll den Roborter rausfahren). Daher habe ich uns eine Rule (bzw. genau genommen sogar mehrere) geschrieben, die nach Abschluss einer Reinigung, wenn der Roboter wieder auf dem Weg zur Ladestation ist, prüft ob seit der letzten Leerung des Staubbehälters mehr als 100m² (das ist einstellbar) vergangen sind. Falls dem so ist wird der Roborock automatisch zum Mülleimer gefahren, wenn er dort angekommen ist schickt er eine Telegram Nachricht und wenn er dann nach der Leerung des Staubbehälters wieder zurück zur Ladestation geschickt wird merkt er sich die aktuell gereinigte Gesamtfläche und nach weiteren 100m² Reinigung geht der Spaß von vorne los ;) Leider gibt es (scheinbar) keinen Zustand für "Staubbehälter entfernt", der Roboter wechselt in diesem Fall in den Zustand 3 (Standby), das tut er aber auch wenn er an einen Punkt gefahren wurde und da angekommen ist.

Des weiteren habe ich auch die Rule von Udo (viewtopic.php?f=15&t=3791), die, wie du schon sagst, etwas "unpraktisch" ist umgebaut.


Daher habe ich die Items um ein paar Dinge erweitert:

Code: Alles auswählen

// Gruppen
Group:Switch:OR(ON,OFF)    gRoborockVacPositions  "Position anfahren"               <position>         (gRoborockVac)
Group                      gSettingsRoborock      "Roborock Einstellungen"   		<vacuumrobot>      (gSettings)

// Positionen
Switch    RoborockVacPos0    "In die Ladestation"		<chargingstation> (gRoborockVacPositions)
Switch    RoborockVacPos1    "Vor die Ladestation"		<zoom>            (gRoborockVacPositions)
Switch    RoborockVacPosDustBin    "Zum Mülleimer"        	<trash>           (gRoborockVacPositions)

// Control
Switch    RoborockVac_StartRoomCleaning "Einzelraumreinigung starten"            <vacuumrobot>    (gRoborockVac)

// Einstellungen
Switch		RoborockVac_EmptyRegullary	"Regelmäßig zum Mülleimer fahren"	<switch>	(gSettingsRoborock)
Number		RoborockVac_EmptyEvery		"Alle x m² leeren [%d m²]"			<zoom>		(gSettingsRoborock)
Number		RoborockVac_EmptyLast		"Zuletzt entleert bei [%d m²]"		<trash>		(gSettingsRoborock)
Switch		setTelegramRoborockCleanDustBin	"Telegram Nachricht senden"	<mail>		(gSettingsRoborock)
Fangen wir mal mit der "neuen" Rule um Räume kontinuierlich zu saugen an. Diese sieht bei mir wie folgt aus (die RoborockVacRoom Items habe ich natürlich auch in der entsprechenden items-Datei umbenannt bzw. erweitert):

Code: Alles auswählen

// IDs der Räume; wurden einfach durch Try&Error ermittelt											   
val HashMap<String,String> RaumId = newHashMap( "RoborockVacRoom1" -> "22", // Wohnzimmer
                                                "RoborockVacRoom2" -> "17", // Essbereich
                                                "RoborockVacRoom3" -> "21", // Küche
                                                "RoborockVacRoom4" -> "16", // Gang
                                                "RoborockVacRoom5" -> "19", // Eingangsbereich
                                                "RoborockVacRoom6" -> "18", // Schlafzimmer
                                                "RoborockVacRoom7" -> "23", // Kinderzimmer
                                                "RoborockVacRoom8" -> "24", // Bad
                                                "RoborockVacRoom9" -> "20") // ???
                                                
// Neue Rule: Dem Roboter direkt alle gwünschten Räume mitgeben, nicht nach und nach jeden Raum einzeln anfahren
rule "Roborock continous room cleaning"
when
    Item RoborockVac_StartRoomCleaning changed to ON                                    // Testschalter  EIN
then
    if(gRoborockVacRooms.members.filter[s|s.state == ON].size == 0) {      // Keine Räume zum saugen
        logInfo("rules", "Alle Räume gesaugt!")
        if(RoborockVac_StartRoomCleaning.state != OFF)                                  // Falls Schalter nicht OFF
            RoborockVac_StartRoomCleaning.postUpdate(OFF)                               // auf OFF
            return;
    }
	
	// IDs der gewünschten Räume aus unserer HashMap holen
	var String strRaumIds = ""
	gRoborockVacRooms.members.filter[s|s.state == ON].sortBy[name].forEach [ item | strRaumIds += RaumId.get(item.name) + ", "]
	
	if (strRaumIds.length <= 2)
	{
		logError(logName, "Keine Räume gewählt")
		RoborockVac_StartRoomCleaning.postUpdate(OFF)                               // Schalter auf OFF
		return;
	}

	// letztes Komma wieder abschneiden
	strRaumIds = strRaumIds.substring(0, strRaumIds.length-2)
	
	// Command zusammenbauen
	val strCommand = "app_segment_clean[" + strRaumIds + "]"
	logInfo(logName, "Command > {} < will be sent",strCommand)
	
	// Command an den Roborock senden und unseren Aktivierungsschalter wieder ausschalten
    RoborockVac_Command.sendCommand(strCommand)                                // Räume saugen
    RoborockVac_StartRoomCleaning.postUpdate(OFF)
end
So, dann jetzt der ausführlichere Teil um Positionen (automatisch) anzufahren. Erstmal habe ich das Tool von marcel_verpaalen (zu finden auf dieser Seite) verwendet um die benötigten Koordinaten zu ermitteln. Dann wurden ganz oben in der Rule (also in der Nähe der HashMap mit den Räumen) folgende Variablen hinzugefügt:

Code: Alles auswählen

// "Klassen"variablen; werden benötigt um die Telegram Nachricht erst zu senden, wenn der Roboter angekommen ist und um den Merker für die letzte Reinigung zurückzusetzen
var boolean bRoborockWasSentToDustBin = false
var boolean bRoborockIsMovingToDustBin = false

// Koordinaten fuer die entsprechenden Positionen
val HashMap<String,String> Coordinates = newHashMap( "RoborockVacPos1" -> "25890,25620",           // Einfach etwas rausfahren
                                                     "RoborockVacPosDustBin" -> "26000,18500")     // Vor den Mülleimer
Dann gibt es eine Rule um den Roboter von Hand aus der Sitemap zu einer bestimmten Position fahren zu können:

Code: Alles auswählen

// Roborock an eine bestimmte Position fahren
rule "Roborock go to position"
when
    Member of gRoborockVacPositions changed to ON
then
	logInfo(logName, "Button > {} < was pressed",triggeringItem.name)

	// Wenn es Pos0 ist => wir wollen in die Ladestation fahren
	if (triggeringItem.name == "RoborockVacPos0")
	{	
		// entsprechende Variable updaten
		RoborockVac_Control.sendCommand("dock")
	}
	else
	{
		// Gewünschte Position aus unserer HashMap holen
		val String vacPos = Coordinates.get(triggeringItem.name)

		// Command zusammenbauen
		val strCommand = "app_goto_target[" + vacPos + "]"
		logInfo(logName, "Command > {} < will be sent",strCommand)
		
		// Command an den Roborock senden
		RoborockVac_Command.sendCommand(strCommand)
	}
	
	// Aktivierungsschalter wieder ausschalten
	triggeringItem.postUpdate(OFF)
end
Für Position0 gibt es keine Koordinaten, dafür verwende ich einfach den "Standardbefehl" um den Roboter zum Laden zu fahren. Dieses Item ist quasi überflüssig, weil das ja auch über den entsprechenden Sitemap Eintrag
alteSteuerung.PNG
funktionieren würde. Wir fanden es aber praktischer diesen Eintrag auch an der entsprechenden Stelle in unserer Sitemap zu haben.

Nachdem diese Rule funktioniert hat, habe ich noch die Regeln implementiert um den Roboter automatisch zum Mülleimer zu fahren, eine Nachricht senden zu lassen und den Status nach der (vermeintlichen) Leerung zurückzusetzen. Wie ich ganz am Anfang ja schon mal erwähnt hatte gibt es (wohl) keinen expliziten Status für "Staubbehälter entfernt".

Code: Alles auswählen

// Roborock alle x m² zum Mülleimer fahren
rule "Roborock move to dust bin"
when
	Item RoborockVac_StateID changed from 5 to 6 or				// von "Reinigung" auf "zurück zur Ladestation"
	Item RoborockVac_StateID changed from 11 to 6 or			// von "Punktreinigung" auf "zurück zur Ladestation"
	Item RoborockVac_StateID changed from 17 to 6 or			// von "Zonenreinigung" auf "zurück zur Ladestation"
	Item RoborockVac_StateID changed from 18 to 6   			// von "Raumreinigung" auf "zurück zur Ladestation"
then
	// Wenn die Einstellung nicht aktiv ist kann direkt beendet werden
	// oder wir keine insgesamt gereinigte Fläche haben
	if (RoborockVac_EmptyRegullary.state != ON || RoborockVac_HistArea.state == NULL)
	{
		return;
	}
		
	var boolean bMustEmpty = false
		
	// Wenn wir keine Information haben wann zuletzt geleert wurde => jetzt leeren
	if (RoborockVac_EmptyLast.state == NULL)
	{
		bMustEmpty = true
	}
	
	// Wenn wir keine Information haben wann immer geleert werden soll => jetzt leeren
	else if (RoborockVac_EmptyEvery.state == NULL)
	{
		bMustEmpty = true
	}
	else
	{
		// Wenn die aktuell gereinigte Fläche größer ist als die bei der letzten Leerung plus dem Abstand zwischen zwei Leerungen
		var float fCurArea = (RoborockVac_HistArea.state as DecimalType).floatValue
		var float fLastArea = (RoborockVac_EmptyLast.state as DecimalType).floatValue
		var float fEmptyEvery = (RoborockVac_EmptyEvery.state as DecimalType).floatValue
		
		// Zum Mülleimer fahren
		if (fCurArea > fLastArea + fEmptyEvery)
		{
			bMustEmpty = true
		}
	}
	
	if (bMustEmpty)
	{
		logInfo(logName, "Roborock: Staubbehaelter muss geleert werden, fahre zum Muelleimer")
		RoborockVacPosDustBin.postUpdate(ON)
		
		// Merker setzen, damit dann, wenn der Roborock am Ziel angekommen ist, eine Telegram Message geschickt wird
		bRoborockIsMovingToDustBin = true
	}
end

rule "Roborock send message when dustbin reached"
when
	Item RoborockVac_StateID changed from 16 to 3		// von "Fahre zum Ziel" auf Standby
then
	if (bRoborockIsMovingToDustBin == true)
	{
		// Wenn eine Telegram Nachricht geschickt werden soll
		if (setTelegramRoborockCleanDustBin.state == ON)
		{
			//logInfo(logName, "Roborock: Telegram Nachricht wird gesendet")
		
			val telegramAction = getActions("telegram","telegram:telegramBot:XXXXXXXXXX")
			telegramAction.sendTelegram(XXXXXXXX, "Roborock: Bitte Staubbehälter leeren")
		}
	
		bRoborockIsMovingToDustBin = false
	}
end

rule "Roborock was sent to dustbin"
when
	Item RoborockVacPosDustBin changed to ON
then
	// Wir merken uns, dass der Roboter manuell oder automatisch zum Mülleimer gefahren wurde
	bRoborockWasSentToDustBin = true
end

// Merken wann der Roborock zuletzt geleert wurde
rule "Roborock remember last clean"
when
	//Item RoborockVac_StateID changed from 3 to 8 or		// von Standby auf Laden (nur sicherheitshalber)
	Item RoborockVac_StateID changed from 3 to 6		// von Standby auf "zurück zur Ladestation"
then
	// Nur wenn wir zum Mülleimer gefahren sind (Roborock geht auch auf Standby, wenn er ein anderes Ziel (z.B. vor der Ladestation) erreicht hat)
	if (bRoborockWasSentToDustBin == true)
	{
		logInfo(logName, "Roborock: Staubbehaelter wurde geleert bei {} m2", RoborockVac_HistArea.state)

		// aktuelle gereinigte Fläche holen und uns diese merken
		RoborockVac_EmptyLast.postUpdate(RoborockVac_HistArea.state)
		
		bRoborockWasSentToDustBin = false;
	}
end
Die Sitemap habe ich beim Roborock mit diesen Punkten erweitert:

Code: Alles auswählen

Group	item=gRoborockVacPositions
{
	Frame label="Positionen"
	{
		Switch item=RoborockVacPos0 mappings=[ON="Click"]
		Switch item=RoborockVacPos1 mappings=[ON="Click"]
		Switch item=RoborockVacPosDustBin mappings=[ON="Click"]
	}
}
und bei unseren Einstellungen:

Code: Alles auswählen

Group item=gSettingsRoborock label="Robby 2.0"
{
	Frame label="Regelmäßig leeren"
	{
		Switch item=RoborockVac_EmptyRegullary
		Setpoint item=RoborockVac_EmptyEvery minValue=10 maxValue=1000 step=5 visibility=[RoborockVac_EmptyRegullary==ON]
		Switch item=setTelegramRoborockCleanDustBin icon="vacuumrobot"
	}
}
Des weiteren habe ich auch den Punkt für die Raumreinigung umgebaut:

Code: Alles auswählen

Group	item=gRoborockVacRooms
{
	Frame label="Räume"
	{
		Default item=RoborockVacRoom1    // "Wohnzimmer saugen"     
		Default item=RoborockVacRoom2    // "Essbereich saugen"     
		Default item=RoborockVacRoom3    // "Küche saugen"          
		Default item=RoborockVacRoom4    // "Gang saugen"           
		Default item=RoborockVacRoom5    // "Eingangsbereich saugen"
		Default item=RoborockVacRoom6    // "Schlafzimmer saugen"   
		Default item=RoborockVacRoom7    // "Kinderzimmer saugen"   
		Default item=RoborockVacRoom8    // "Bad saugen"            		
		//Default item=RoborockVacRoom9    //"???"
	}
	
	Frame label="Sonstiges"
	{
		Switch item=RoborockVac_StartRoomCleaning label="Reinigung starten" mappings=[ON="Click"]
	}
}
Das sieht dann wie folgt aus:
sitemap.png
Vielleicht helfen diese Erweiterungen irgendwem weiter. Bei Fragen (oder falls ich irgendwelche Variablen/Sachen vergessen habe) einfach melden.

Grüße
mbw83
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

Re: Roborock S6 MaxV

Beitrag von Cyrelian »

Hi mbw83,

sehr coole Erweiterungen.

CU
Cyrelian

timtschuk
Beiträge: 10
Registriert: 28. Mai 2020 10:06

Re: Roborock S6 MaxV

Beitrag von timtschuk »

Hallo,
ich habe eigentlich alle Werte übernommen wie in deinem (mbw83) Artikel beschrieben, allerdings bekommen ich eine Fehlermeldung beim speichern der rule:
The field Tmp_roborockRules.RaumId refers to the missing type Object
The field Tmp_roborockRules.Coordinates refers to the missing type Object

Code: Alles auswählen

// IDs der Räume; wurden einfach durch Try&Error ermittelt											   
val HashMap<String,String> RaumId = newHashMap( "RoborockVacRoom1" -> "22", // Wohnzimmer
                                                "RoborockVacRoom2" -> "17", // Essbereich
                                                "RoborockVacRoom3" -> "21", // Küche
                                                "RoborockVacRoom4" -> "16", // Gang
                                                "RoborockVacRoom5" -> "19", // Eingangsbereich
                                                "RoborockVacRoom6" -> "18", // Schlafzimmer
                                                "RoborockVacRoom7" -> "23", // Kinderzimmer
                                                "RoborockVacRoom8" -> "24", // Bad
                                                "RoborockVacRoom9" -> "20") // ???
// Koordinaten fuer die entsprechenden Positionen
val HashMap<String,String> Coordinates = newHashMap( "RoborockVacPos1" -> "25650,27932",           // Einfach etwas rausfahren
                                                     "RoborockVacPosDustBin" -> "23550,27932")     // Vor den Mülleimer
                                             
																			
// "Klassen"variablen; werden benötigt um die Telegram Nachricht erst zu senden, wenn der Roboter angekommen ist und um den Merker für die letzte Reinigung zurückzusetzen
var boolean bRoborockWasSentToDustBin = false
var boolean bRoborockIsMovingToDustBin = false

                                                
// Neue Rule: Dem Roboter direkt alle gwünschten Räume mitgeben, nicht nach und nach jeden Raum einzeln anfahren
rule "Roborock continous room cleaning"
when
    Item RoborockVac_StartRoomCleaning changed to ON                                    // Testschalter  EIN
then
    if(gRoborockVacRooms.members.filter[s|s.state == ON].size == 0) {      // Keine Räume zum saugen
        logInfo("rules", "Alle Räume gesaugt!")
        if(RoborockVac_StartRoomCleaning.state != OFF)                                  // Falls Schalter nicht OFF
            RoborockVac_StartRoomCleaning.postUpdate(OFF)                               // auf OFF
            return;
    }
	
	// IDs der gewünschten Räume aus unserer HashMap holen
	var String strRaumIds = ""
	gRoborockVacRooms.members.filter[s|s.state == ON].sortBy[name].forEach [ item | strRaumIds += RaumId.get(item.name) + ", "]
	
	if (strRaumIds.length <= 2)
	{
		logError(logName, "Keine Räume gewählt")
		RoborockVac_StartRoomCleaning.postUpdate(OFF)                               // Schalter auf OFF
		return;
	}

	// letztes Komma wieder abschneiden
	strRaumIds = strRaumIds.substring(0, strRaumIds.length-2)
	
	// Command zusammenbauen
	val strCommand = "app_segment_clean[" + strRaumIds + "]"
	logInfo(logName, "Command > {} < will be sent",strCommand)
	
	// Command an den Roborock senden und unseren Aktivierungsschalter wieder ausschalten
    RoborockVac_Command.sendCommand(strCommand)                                // Räume saugen
    RoborockVac_StartRoomCleaning.postUpdate(OFF)
end

// Roborock an eine bestimmte Position fahren
rule "Roborock go to position"
when
    Member of gRoborockVacPositions changed to ON
then
	logInfo(logName, "Button > {} < was pressed",triggeringItem.name)

	// Wenn es Pos0 ist => wir wollen in die Ladestation fahren
	if (triggeringItem.name == "RoborockVacPos0")
	{	
		// entsprechende Variable updaten
		RoborockVac_Control.sendCommand("dock")
	}
	else
	{
		// Gewünschte Position aus unserer HashMap holen
		val String vacPos = Coordinates.get(triggeringItem.name)

		// Command zusammenbauen
		val strCommand = "app_goto_target[" + vacPos + "]"
		logInfo(logName, "Command > {} < will be sent",strCommand)
		
		// Command an den Roborock senden
		RoborockVac_Command.sendCommand(strCommand)
	}
	
	// Aktivierungsschalter wieder ausschalten
	triggeringItem.postUpdate(OFF)
end

// Roborock alle x m² zum Mülleimer fahren
rule "Roborock move to dust bin"
when
	Item RoborockVac_StateID changed from 5 to 6 or				// von "Reinigung" auf "zurück zur Ladestation"
	Item RoborockVac_StateID changed from 11 to 6 or			// von "Punktreinigung" auf "zurück zur Ladestation"
	Item RoborockVac_StateID changed from 17 to 6 or			// von "Zonenreinigung" auf "zurück zur Ladestation"
	Item RoborockVac_StateID changed from 18 to 6   			// von "Raumreinigung" auf "zurück zur Ladestation"
then
	// Wenn die Einstellung nicht aktiv ist kann direkt beendet werden
	// oder wir keine insgesamt gereinigte Fläche haben
	if (RoborockVac_EmptyRegullary.state != ON || RoborockVac_HistArea.state == NULL)
	{
		return;
	}
		
	var boolean bMustEmpty = false
		
	// Wenn wir keine Information haben wann zuletzt geleert wurde => jetzt leeren
	if (RoborockVac_EmptyLast.state == NULL)
	{
		bMustEmpty = true
	}
	
	// Wenn wir keine Information haben wann immer geleert werden soll => jetzt leeren
	else if (RoborockVac_EmptyEvery.state == NULL)
	{
		bMustEmpty = true
	}
	else
	{
		// Wenn die aktuell gereinigte Fläche größer ist als die bei der letzten Leerung plus dem Abstand zwischen zwei Leerungen
		var float fCurArea = (RoborockVac_HistArea.state as DecimalType).floatValue
		var float fLastArea = (RoborockVac_EmptyLast.state as DecimalType).floatValue
		var float fEmptyEvery = (RoborockVac_EmptyEvery.state as DecimalType).floatValue
		
		// Zum Mülleimer fahren
		if (fCurArea > fLastArea + fEmptyEvery)
		{
			bMustEmpty = true
		}
	}
	
	if (bMustEmpty)
	{
		logInfo(logName, "Roborock: Staubbehaelter muss geleert werden, fahre zum Muelleimer")
		RoborockVacPosDustBin.postUpdate(ON)
		
		// Merker setzen, damit dann, wenn der Roborock am Ziel angekommen ist, eine Telegram Message geschickt wird
		bRoborockIsMovingToDustBin = true
	}
end

rule "Roborock send message when dustbin reached"
when
	Item RoborockVac_StateID changed from 16 to 3		// von "Fahre zum Ziel" auf Standby
then
	if (bRoborockIsMovingToDustBin == true)
	{
		// Wenn eine Telegram Nachricht geschickt werden soll
		if (setTelegramRoborockCleanDustBin.state == ON)
		{
			//logInfo(logName, "Roborock: Telegram Nachricht wird gesendet")
		
			val telegramAction = getActions("telegram","telegram:telegramBot:XXXXXXXXXX")
			telegramAction.sendTelegram(XXXXXXXX, "Roborock: Bitte Staubbehälter leeren")
		}
	
		bRoborockIsMovingToDustBin = false
	}
end

rule "Roborock was sent to dustbin"
when
	Item RoborockVacPosDustBin changed to ON
then
	// Wir merken uns, dass der Roboter manuell oder automatisch zum Mülleimer gefahren wurde
	bRoborockWasSentToDustBin = true
end

// Merken wann der Roborock zuletzt geleert wurde
rule "Roborock remember last clean"
when
	//Item RoborockVac_StateID changed from 3 to 8 or		// von Standby auf Laden (nur sicherheitshalber)
	Item RoborockVac_StateID changed from 3 to 6		// von Standby auf "zurück zur Ladestation"
then
	// Nur wenn wir zum Mülleimer gefahren sind (Roborock geht auch auf Standby, wenn er ein anderes Ziel (z.B. vor der Ladestation) erreicht hat)
	if (bRoborockWasSentToDustBin == true)
	{
		logInfo(logName, "Roborock: Staubbehaelter wurde geleert bei {} m2", RoborockVac_HistArea.state)

		// aktuelle gereinigte Fläche holen und uns diese merken
		RoborockVac_EmptyLast.postUpdate(RoborockVac_HistArea.state)
		
		bRoborockWasSentToDustBin = false;
	}
end
Kann mir jemand sagen wo der Fehler ist?

mbw83
Beiträge: 5
Registriert: 29. Jun 2021 10:06

Re: Roborock S6 MaxV

Beitrag von mbw83 »

Hast du ganz oben in der rule ein

Code: Alles auswählen

import java.util.HashMap
Ich glaube nämlich, dass ich dieses Problem auch hatte und durch diesen import gelöst habe.

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Roborock S6 MaxV

Beitrag von udo1toni »

Kann es sein, dass Du die Rule über die UI eingegeben hast? Diese Rules müssen zwingend in einer *.rules Datei gespeichert werden. Die Fehlermeldung besagt, dass die zwei Objekte RaumId und Coordinates nicht vorhanden sind. Dies sind die beiden HashMaps.

Der Import für die Funktionalität HashMap fehlt auch noch, das hat mbw83 ja schon gepostet.

Noch ein kleiner Hinweis: Bitte die Variablendefinition nach Möglichkeit mit Objekten vornehmen (also im vorliegenden Fall Boolean statt boolean).

Weiterhin ist es nicht notwendig, auf == true zu prüfen. Es reicht

Code: Alles auswählen

if(bRoborockIsMovingToDustBin)
aus, wenn bRoborockIsMovingToDustBin true sein muss. Soll bRoborockIsMovingToDustBin auf false geprüft werden, geht das so:

Code: Alles auswählen

if(!bRoborockIsMovingToDustBin)
if() ist erfüllt, wenn der Term in den Klammern ein logisches true ergibt. ! ist die logische Funktion not(), aus true wird also false und umgekehrt. Wenn man schon Boolean (oder boolean) Variablen verwendet, sollte man auch davon nutznießen ;)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

timtschuk
Beiträge: 10
Registriert: 28. Mai 2020 10:06

Re: Roborock S6 MaxV

Beitrag von timtschuk »

Super, danke das Hat den Fehler behoben.

Leider fehlt noch etwas:

Script execution of rule with UID 'roborock-2' failed: The name 'logName' cannot be resolved to an item or type; line 64, column 10, length 7 in roborock

Kann es sein das du das item angelegt hast? Ich konnte es in deiner Items Datei nicht finden.
Könntest du das hier auch noch mal Teilen?

mbw83
Beiträge: 5
Registriert: 29. Jun 2021 10:06

Re: Roborock S6 MaxV

Beitrag von mbw83 »

@udo1toni
Danke für deine Inputs, ich habe das bei mir entsprechend umgebaut. Frag mich nicht, warum ich das mit den boolschen Variablen so gemacht habe wie ich es gemacht habe, eigentlich verwende ich im "richtigen" Leben die boolschen Variablen schon so wie von dir vorgeschlagen.

@timtschuk
oh sorry, das ist mir wohl auch durchgerutscht. Ich habe auch ganz oben, in der Nähe des imports bzw der beiden boolschen Variablen noch folgendes definiert:

Code: Alles auswählen

val logName = "roborock"
Alternativ kannst natürlich logName innerhalb der rule auch durch einen x-beliebigen String ersetzen.

Quautiputzli
Beiträge: 317
Registriert: 29. Okt 2020 19:53
Answers: 2

Re: Roborock S6 MaxV

Beitrag von Quautiputzli »

Hallo, ich habe nun auch einen Xiami Saugroboter.
Ich nutze OpenHAB 3. Ich bekomme auch alle Daten mit dem Binding herein, verstehe allerdings nicht wie das mit den einzelnen Räumen bzw. Segmenten laufen soll. Müssen die erst in der App angelegt werden? Ich kann in der App schon Zonen markieren, die dann gesaugt werden, beim nächsten Start der App sind die allerdings wieder weg.

Ich wäre um Hilfe dankbar.

Servus
Servus

mbw83
Beiträge: 5
Registriert: 29. Jun 2021 10:06

Re: Roborock S6 MaxV

Beitrag von mbw83 »

Ja die Aufteilung der einzelnen Räume muss in der Xiaomi App angelegt werden. Zusätzlich muss im Menü unter Karten verwalten die Kartenspeicherung aktiviert werden.

Antworten