Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. Roborock S5 "cleaning area" per Tastendruck?

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    Roborock S5 "cleaning area" per Tastendruck?

    This topic has been deleted. Only users with topic management privileges can see it.
    • AlCalzone
      AlCalzone Developer @Mor9oth last edited by

      @Mor9oth Gute Ideen. Eventuell komme ich morgen dazu - aber keine Garantie!

      M 1 Reply Last reply Reply Quote 0
      • M
        Mor9oth @AlCalzone last edited by

        @AlCalzone Freut mich sehr 👍

        1 Reply Last reply Reply Quote 0
        • 0
          0018 @AlCalzone last edited by

          @AlCalzone sagte in Roborock S5 "cleaning area" per Tastendruck?:
          Beispiel: Sauger steht bei dir normalerweise rechts, dann 180 => 0, 270 => 90, 90 => 270, 0 => 180.

          Ja genau, mein Sauger steht rechts vom Dock. Habe jetzt nachdem ich die Daten angepasst habe, leider das Problem das meine Bereiche nicht mehr mit den Koordinaten aus der Valetudo Map
          übereinstimmen. Muss ich hier auch noch was drehen? Den die Zonenkordination sind ja dann auch gedreht oder?

          AlCalzone 1 Reply Last reply Reply Quote 0
          • AlCalzone
            AlCalzone Developer @0018 last edited by

            @0018 Inwiefern stimmt es nicht mehr überein?

            0 1 Reply Last reply Reply Quote 0
            • 0
              0018 @AlCalzone last edited by 0018

              @AlCalzone Damit das ganze besser zu erklären ist hier mit Screenshots.

              1. So sieht meine Karte in Valetudo und die dazugehörigen Koordinaten der Zone1 aus:
                Karte Valetudo

              2. Aus meiner Sicht steht mein Robo rechts vom Dock, daher folgende Anpassung deines Scriptes:

              const rooms: Record<string, Rectangle[]> = {
                  "Test": [[26397, 22791, 29302, 24138]],
              };
              

              ab Zeile 119:

                  // Valetudo zählt von oben links nach unten rechts, d.h. die Y-Koordinaten
                  // sind entgegengesetzt der mathematischen Definition
                  let c2r = [robot[0] - charger[0], charger[1] - robot[1]];
                  const angle = Math.atan2(c2r[1], c2r[0]) * 180 / Math.PI;
                  log("angle = " + angle);
                  if (angle <= 45 && angle >= -45) {
                      log("Sauger steht rechts");
                      return 0;
                  } else if (angle > 45 && angle < 135) {
                      log("Sauger steht oben");
                      return 90;
                  } else if (angle < -45 && angle > -135) {
                      log("Sauger steht unten");
                      return 270;
                  } else {
                      return 180;
                  }
              }
              
              1. Wenn ich dann die Zonnenreinigung starte, sieht das auf der Vaeltuda Map dann wie folgt aus:
                Robot180

              2. Als test mal mit dem Standard:

                  // Valetudo zählt von oben links nach unten rechts, d.h. die Y-Koordinaten
                  // sind entgegengesetzt der mathematischen Definition
                  let c2r = [robot[0] - charger[0], charger[1] - robot[1]];
                  const angle = Math.atan2(c2r[1], c2r[0]) * 180 / Math.PI;
                  log("angle = " + angle);
                  if (angle <= 45 && angle >= -45) {
                      log("Sauger steht rechts");
                      return 180;
                  } else if (angle > 45 && angle < 135) {
                      log("Sauger steht oben");
                      return 270;
                  } else if (angle < -45 && angle > -135) {
                      log("Sauger steht unten");
                      return 90;
                  } else {
                      return 0;
                  }
              }
              

              ergibt folgendes Ergebniss:
              Robot0

              Habe auch schon 90 + 270 probiert, leider auch ohne Erfolg.
              Im Script habe ich mal den Angle mit geloggt und bei den Versuchen kommt immer ähnliches raus....

              javascript.0	2019-12-09 21:12:16.299	info	(2094) script.js.common.4_MiRobot.MiRobot_Zone_neu: angle = -2.981461219982192
              javascript.0	2019-12-09 21:06:13.153	info	(2094) script.js.common.4_MiRobot.MiRobot_Zone_neu: angle = 2.8912695962205643
              javascript.0	2019-12-09 20:56:30.228	info	(2094) script.js.common.4_MiRobot.MiRobot_Zone_neu: angle = -1.461310090881229
              

              Vielleicht siehst du ja auf Anhieb woran es liegt?

              AlCalzone 1 Reply Last reply Reply Quote 0
              • AlCalzone
                AlCalzone Developer @0018 last edited by AlCalzone

                @0018 sagte in Roborock S5 "cleaning area" per Tastendruck?:

                Vielleicht siehst du ja auf Anhieb woran es liegt?

                Auf dem 1. Bild im Dock sieht es für mich so aus als zeigt der Sauger nach links, d.h. Winkel 0°. Hast du die Koordinaten direkt aus Valetudo? Dann müssen ggf. die Y-Koordinaten aller Zonen invertiert werden, da Valetudo anscheinend anders zählt als der Sauger selbst:

                y(für Skript) = 51200 - y(Valetudo)
                
                0 1 Reply Last reply Reply Quote 0
                • 0
                  0018 @AlCalzone last edited by

                  @AlCalzone Ja, die Koordinaten sind direkt aus Valetudo unter http://IPdesSaugers/zone
                  Habe jetzt die Y-Koordinaten nach Vorgabe umgerechnet und jetzt stimmen die Zonen überein.
                  Der Tipp mit

                  // @ts-ignore 
                  

                  hat auch funktioniert. Scheint also auf den ersten Blick erstmal alles zu passen. Ich werde es jetzt die nächsten Wochen mal testen.

                  Vielen Dank!

                  1 Reply Last reply Reply Quote 1
                  • Chris_71
                    Chris_71 @AlCalzone last edited by

                    @AlCalzone Erstmal danke für dein Script
                    Leider scheint es bei mir nicht zu funktionieren, laut Log bleibt es bei
                    script.js.Xiaomi_Sauger.Zonenreinigung_Kartenrotation: Teste Kartenorientierung... stehen.
                    Ich nutze den mihome-vacuum 1.9.2 mit Valetudo RE 0.8.1, der Datenpunkt mapRotated bleibt auf unkown(-1).

                    AlCalzone 1 Reply Last reply Reply Quote 0
                    • AlCalzone
                      AlCalzone Developer @Chris_71 last edited by

                      @Chris_71 Hast du die Zugangsdaten und Hostnamen bzw. IP korrekt eingetragen?
                      Kannst du mit diesen Zugangsdaten im Browser die folgende Adresse öffnen?

                      http://<Adresse-Des-Saugers>/api/map/latest
                      
                      Chris_71 1 Reply Last reply Reply Quote 0
                      • 0
                        0018 last edited by

                        @Chris_71 sagte in Roborock S5 "cleaning area" per Tastendruck?:

                        Valetudo RE 0.8.1

                        Ich glaube das liegt an Valetudo RE 0.8.1. Dort bekommt man über /api/map/latest nichts mehr angezeigt, sondern es wird eine Datei ohne Endung heruntergeladen. Der Inhalt ist mit dem Notepad++ nicht lesbar.

                        Seit meinem Update von Valetudo auf Valetudo RE 0.8.1 habe ich das gleiche Problem. Siehe auch hier von @base im Beitrag hier

                        AlCalzone 1 Reply Last reply Reply Quote 0
                        • AlCalzone
                          AlCalzone Developer @0018 last edited by

                          @0018 Kannst du vielleicht mal im Browser schauen, welche Adresse diese Version lädt, um an die Map zu kommen?

                          1 Reply Last reply Reply Quote 0
                          • Chris_71
                            Chris_71 @AlCalzone last edited by

                            @AlCalzone Da passiert das gleiche das auch @0018 geschrieben hat.
                            Eine Karte kann man über /api/simple_map abrufen (PNG-Datei).

                            AlCalzone 1 Reply Last reply Reply Quote 0
                            • AlCalzone
                              AlCalzone Developer @Chris_71 last edited by AlCalzone

                              @Chris_71 dann muss man die Karte anders decoden. Ich brauche nicht die Pixel sondern die Koordinaten von sauger und Station um die rotation zu erkennen

                              @Meistertr hast du ne Idee wie sich das genau geändert hat?

                              1 Reply Last reply Reply Quote 0
                              • M
                                Mor9oth last edited by

                                @AlCalzone: Hey! Ich hoffe, du kannst mir helfen! Ich nutze dein Script und plötzlich, seit ca. einer Woche, funktioniert es nicht mehr. Ich bekomme plötzlich im Log:

                                State value to set for "mihome-vacuum.0.info.water_box" has to be type "string" but received type "boolean"
                                

                                sobald ich einen der Räume ansteuere. (per Sprache oder per Alexa (Gerät/Button).

                                Geändert habe ich nichts. Die relevanten Adapter scheinen auch alle richtig angebunden zu sein. Siehe Screenshot:
                                Screenshot Capture - 2021-08-04 - 12-00-28.png

                                Die Verbindung zum Roborock habe ich mit dem "Find" erfolgreich getestet. Muss ich was am script verändern, um die Raumsteuerung wieder zum Laufen zu bringen?

                                Dein Script lief bei mir Jahre so:

                                // Hier den State eintragen, der den aktuellen Sauger-Status angibt
                                
                                const idVacuumState = "mihome-vacuum.0.info.state";
                                
                                 
                                
                                // Koordiaten zählen von unten links (0,0) nach oben rechts (51200,51200)
                                
                                // Die folgenden Koordinaten gehen von nicht rotierter Karte (Winkel 0) aus
                                
                                const rooms: Record<string, Rectangle[]> = {
                                
                                	"Küche": [[21386,18786,23486,22936]],
                                
                                	"Flur": [[18323,22873,23623,24523]],
                                
                                	"Wohnzimmer": [[23470,18841,27620,24341]],
                                
                                	"Schlafzimmer": [[18235,24479,22285,28829]],
                                
                                	"Bad": [[18273,19241,20723,23091]],
                                
                                    "Arbeitszimmer": [[22413,24357,27463,28657]],
                                
                                    "Wohnbereich": [[23470,18841,27620,24341],[21386,18786,23486,22936]],
                                
                                    "Wohnung": [[23470,18841,27620,24341],[21386,18786,23486,22936],[18323,22873,23623,24523],[18273,19241,20723,23091],[18235,24479,22285,28829]]
                                    
                                };
                                
                                 
                                
                                // ===============================================================================
                                
                                
                                type Rectangle = [number, number, number, number];
                                
                                
                                 
                                
                                for (const room of Object.keys(rooms) as (keyof typeof rooms)[]) {
                                
                                	createState(`Staubsauger.${room}`, {
                                
                                		type: "boolean",
                                
                                		read: true,
                                
                                		write: true,
                                
                                		role: "switch",
                                
                                		name: `${room} saugen`,
                                
                                	});
                                
                                	on({ id: `javascript.${instance}.Staubsauger.${room}`, val: true, ack: false }, async () => {
                                
                                		if (getState(idVacuumState).val !== 8) await cancelCurrentAction();
                                
                                		
                                
                                		cleanRoom(room);
                                
                                	});
                                
                                }
                                
                                 
                                
                                createState(`Staubsauger.stop`, {
                                
                                	type: "boolean",
                                
                                	read: true,
                                
                                	write: true,
                                
                                	role: "switch",
                                
                                	name: `Staubsauger anhalten`,
                                
                                });
                                
                                on({ id: `javascript.${instance}.Staubsauger.stop`, val: true, ack: false }, () => {
                                
                                	stopCleanup();
                                
                                });
                                
                                 
                                
                                // Reset all control states when the vacuum starts charging
                                
                                on({ id: idVacuumState, val: 8 /* charging */ }, (obj) => {
                                
                                	for (const room of Object.keys(rooms) as (keyof typeof rooms)[]) {
                                
                                		setState(`Staubsauger.${room}`, false, true);
                                
                                	}
                                
                                	setState(`Staubsauger.stop`, false, true);
                                
                                });
                                
                                 
                                
                                async function cancelCurrentAction(): Promise<void> {
                                
                                	setState("mihome-vacuum.0.control.pause", true);
                                
                                	// wait for the "paused" status before going home
                                
                                	await waitForPauseOrSleep();
                                
                                }
                                
                                 
                                
                                async function stopCleanup(): Promise<void> {
                                
                                	log(`Saugvorgang abgebrochen!`);
                                
                                	setState(`Staubsauger.stop`, true, true);
                                
                                 
                                
                                	if (getState(idVacuumState).val !== 8) {
                                
                                		await cancelCurrentAction();
                                
                                 
                                
                                		await setStateAsync('mihome-vacuum.0.control.home', true);
                                
                                		// wait for the "charging" status before resolving
                                
                                		await waitFor(idVacuumState, 8);
                                
                                	}
                                
                                 
                                
                                	log(`Staubsauger ist in der Basis`);
                                
                                 
                                
                                	setState(`Staubsauger.stop`, false, true);
                                
                                }
                                
                                 
                                
                                async function cleanRoom(room: keyof typeof rooms): Promise<void> {
                                
                                	log(`Saugvorgang für ${room} gestartet!`);
                                
                                	setState(`Staubsauger.${room}`, true, true);
                                
                                 
                                
                                	const roomCoords = rooms[room];
                                
                                 
                                
                                	const coords = roomCoords[0];
                                
                                	const targetCoords = [
                                
                                		((coords[0] + coords[2]) / 2).toFixed(0),
                                
                                		((coords[1] + coords[3]) / 2).toFixed(0),
                                
                                	]
                                
                                 
                                
                                	// go to center of first zone
                                
                                	const gotoString = targetCoords.join(",");
                                
                                	await setStateAsync("mihome-vacuum.0.control.goTo", gotoString);
                                
                                	log(`Fahre zur Mitte von ${room}`);
                                
                                	await wait(10000);
                                
                                	await waitForPauseOrSleep();
                                
                                 
                                
                                	if (getState("Staubsauger.stop").val) return;
                                
                                 
                                
                                	const zoneCleanString = roomCoords.map(zone => {
                                
                                		return "[" + zone.concat(1).map(coord => coord.toString()).join(",") + "]";
                                
                                	}).join(",");
                                
                                 
                                
                                	log("Starte Zonenreinigung...");
                                
                                	await setStateAsync("mihome-vacuum.0.control.zoneClean", zoneCleanString);
                                
                                	// wait for the cleanup to finish
                                
                                	await waitFor(idVacuumState, 6);
                                
                                }
                                
                                 
                                
                                async function waitForPauseOrSleep(): Promise<void> {
                                
                                	log("Warte auf Zustand schlafen oder Pause...");
                                
                                	switch (getState(idVacuumState).val) {
                                
                                		case 3:
                                
                                		case 10:
                                
                                			log(" => Zustand bereits aktiv!");
                                
                                			return;
                                
                                		default:
                                
                                			await Promise.race([
                                
                                				waitFor(idVacuumState, 10),
                                
                                				waitFor(idVacuumState, 3),
                                
                                			]);
                                
                                			log(" => Zustand erreicht!");
                                
                                	}
                                
                                }
                                
                                 
                                
                                function wait(ms: number): Promise<void> {
                                
                                	return new Promise(resolve => {
                                
                                		setTimeout(resolve, ms);
                                
                                	});
                                
                                }
                                
                                 
                                
                                function waitFor(stateID: string, value: any): Promise<void> {
                                
                                	return new Promise(resolve => {
                                
                                		const handler = (obj: iobJS.ChangedStateObject) => {
                                
                                			if (obj.newState.val === value) {
                                
                                				unsubscribe(handler);
                                
                                				resolve();
                                
                                			}
                                
                                		}
                                
                                		subscribe(stateID, handler);
                                
                                	})
                                
                                }
                                
                                 
                                
                                function setStateAsync(id: string, state: any): Promise<void> {
                                
                                	return new Promise(res => {
                                
                                		setState(id, state, () => res());
                                
                                	});
                                
                                }
                                
                                AlCalzone 1 Reply Last reply Reply Quote 0
                                • AlCalzone
                                  AlCalzone Developer @Mor9oth last edited by

                                  @mor9oth sagte in Roborock S5 "cleaning area" per Tastendruck?:

                                  State value to set for "mihome-vacuum.0.info.water_box" has to be type "string" but received type "boolean"

                                  Der State wird im Skript nicht verwendet. Das muss woanders her kommen.

                                  M 1 Reply Last reply Reply Quote 0
                                  • M
                                    Mor9oth @AlCalzone last edited by

                                    @alcalzone Ok, danke für das Feedback! Dann suche ich mal weiter ^^

                                    1 Reply Last reply Reply Quote 0
                                    • First post
                                      Last post

                                    Support us

                                    ioBroker
                                    Community Adapters
                                    Donate

                                    675
                                    Online

                                    31.8k
                                    Users

                                    79.9k
                                    Topics

                                    1.3m
                                    Posts

                                    javascript
                                    9
                                    57
                                    7976
                                    Loading More Posts
                                    • Oldest to Newest
                                    • Newest to Oldest
                                    • Most Votes
                                    Reply
                                    • Reply as topic
                                    Log in to reply
                                    Community
                                    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                    The ioBroker Community 2014-2023
                                    logo