Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Roborock S5 "cleaning area" per Tastendruck?

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    14
    1
    343

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    603

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    1.8k

Roborock S5 "cleaning area" per Tastendruck?

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
javascript
57 Beiträge 9 Kommentatoren 10.7k Aufrufe 15 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • AlCalzoneA 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 Offline
    0 Offline
    0018
    schrieb am zuletzt editiert von
    #48

    @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!

    Mfg
    0018

    1 Antwort Letzte Antwort
    1
    • AlCalzoneA AlCalzone

      @kaiserm Also wie versprochen:

      Hier die Variante, die bei mir im Einsatz ist (inklusive Test der Kartenorientierung via Valetudo). Muss als TypeScript angelegt werden und benötigt das zusätzliche Paket "axios":

      import axios from "axios";
      
      // Hier den Hostnamen und Zugangsdaten eintragen, unter dem Valetudo erreichbar ist
      const roboHostname = "rockrobo.fritz.box";
      const valetudoAuth = {
      	username: 'valetudo-username',
      	password: 'valetudo-password'
      }
      // Hier den State eintragen, der den aktuellen Sauger-Status angibt
      const idVacuumState = "mihome-vacuum.0.info.state";
      
      const center: Point = [25600, 25600];
      // 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": [[21600, 29100, 23500, 33100]],
          "Flur": [[18400, 24000, 22200, 27100], [19500, 27100, 21600, 30400]],
          "Wohnzimmer": [[17600, 20000, 21600, 24000], [21600, 19200, 24200, 23200]],
          "Schlafzimmer": [[24100, 23200, 26100, 27400], [22100, 23800, 24100, 27400]],
          "Bad": [[21500, 27500, 23200, 29000]],
      };
      
      // ===============================================================================
      
      type Rectangle = [number, number, number, number];
      type Point = [number, number];
      
      /** rotates a rectangle by 90° around the absolute origin */
      function rotate90([x1, y1, x2, y2]: Rectangle): Rectangle {
          return [-y2, x1, -y1, x2];
      }
      
      /** rotates a rectangle by 180° around the absolute origin */
      function rotate180([x1, y1, x2, y2]: Rectangle): Rectangle {
          return [-x2, -y2, -x1, -y1];
      }
      
      /** Rotates a rectangle around the given center by the given angle */
      function rotate(rect: Rectangle, center: Point, angle: number) {
          rect = [rect[0] - center[0], rect[1] - center[1], rect[2] - center[0], rect[3] - center[1]];
          if (angle % 180 === 90) {
              rect = rotate90(rect);
              angle -= 90;
          }
          if (angle === 180) {
              rect = rotate180(rect);
          }
          rect = [rect[0] + center[0], rect[1] + center[1], rect[2] + center[0], rect[3] + center[1]];
          return rect;
      }
      
      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();
      
              if (getMapRotation() === -1 /* unbekannt */) {
                  // We need to test the map rotation
                  const rotation = await testMapRotation();
                  log(`Die Karte ist ${rotation !== 0 ? `um ${rotation}° ` : "nicht "}rotiert.`);
                  await rememberMapRotation(rotation);
              }
      
              // Now that we know how the map is rotated, we can clean the room
              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();
      });
      
      const idMapRotated = "Staubsauger.info.mapRotated";
      createState(idMapRotated, {
          type: "number",
          read: true,
          write: false,
          role: "indicator",
          states: {
              "-1": "unknown",
              "0": "Robo links vom Dock",
              "90": "Robo unten vom Dock",
              "180": "Robo rechts vom Dock",
              "270": "Robo oben vom Dock",
          },
          name: `Wie die Karte rotiert ist`,
      });
      
      /** 
       * Bestimmt die Kartenrotation wenn der Staubsauger neben dem Dock steht
       * 0 Grad bedeutet, der Sauger steht links
       */
      async function testMapRotation(): Promise<number> {
          log("Teste Kartenorientierung...");
          const { data: { charger, robot } } = await axios({
              url: `http://${roboHostname}/api/map/latest`,
              auth: valetudoAuth
          });
      
          // 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;
          if (angle <= 45 && angle >= -45) {
              // Sauger steht rechts
              return 180;
          } else if (angle > 45 && angle < 135) {
              // Sauger steht oben
              return 270;
          } else if (angle < -45 && angle > -135) {
              // Sauger steht unten
              return 90;
          } else {
              return 0;
          }
      }
      
      function rememberMapRotation(rotation: number): Promise<void> {
          return setStateAsync(idMapRotated, rotation);
      }
      function getMapRotation(): number {
          return getState(idMapRotated).val;
      }
      
      // "Forget" map rotation when the vacuum starts charging
      on({ id: idVacuumState, val: 8 /* charging */ }, (obj) => {
          setState(idMapRotated, -1 /* unknown */);
          // And reset all control states
          for (const room of Object.keys(rooms) as (keyof typeof rooms)[]) {
              setState(`Staubsauger.${room}`, false, true);
          }
          setState(`Staubsauger.stop`, false, true);
      });
      
      async function beginCleanup(): Promise<void> {
      }
      
      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 mapRotation = getMapRotation();
          const originalCoords = rooms[room];
          log(`original coordinates: ${JSON.stringify(originalCoords)}`);
          const roomCoords = rooms[room].map(rect => rotate(rect, center, mapRotation));
          log(`rotated coordinates: ${JSON.stringify(roomCoords)}`);
      
          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());
          });
      }
      

      Wenn du die automatische Rotation nicht benötigst oder kein Valetudo hast, wäre folgendes die vereinfachte Variante:

      // 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": [[21600, 29100, 23500, 33100]],
      	"Flur": [[18400, 24000, 22200, 27100], [19500, 27100, 21600, 30400]],
      	"Wohnzimmer": [[17600, 20000, 21600, 24000], [21600, 19200, 24200, 23200]],
      	"Schlafzimmer": [[24100, 23200, 26100, 27400], [22100, 23800, 24100, 27400]],
      	"Bad": [[21500, 27500, 23200, 29000]],
      };
      
      // ===============================================================================
      
      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());
      	});
      }
      

      Beide Varianten legen für jeden Raum und für Stop einen State an, den du dann jeweils mit einer Alexa-Routine ansprechen kannst.

      Chris_71C Offline
      Chris_71C Offline
      Chris_71
      schrieb am zuletzt editiert von
      #49

      @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).

      AlCalzoneA 1 Antwort Letzte Antwort
      0
      • Chris_71C Chris_71

        @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).

        AlCalzoneA Offline
        AlCalzoneA Offline
        AlCalzone
        Developer
        schrieb am zuletzt editiert von
        #50

        @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
        

        Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

        Chris_71C 1 Antwort Letzte Antwort
        0
        • 0 Offline
          0 Offline
          0018
          schrieb am zuletzt editiert von
          #51

          @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

          Mfg
          0018

          AlCalzoneA 1 Antwort Letzte Antwort
          0
          • 0 0018

            @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

            AlCalzoneA Offline
            AlCalzoneA Offline
            AlCalzone
            Developer
            schrieb am zuletzt editiert von
            #52

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

            Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

            1 Antwort Letzte Antwort
            0
            • AlCalzoneA AlCalzone

              @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_71C Offline
              Chris_71C Offline
              Chris_71
              schrieb am zuletzt editiert von
              #53

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

              AlCalzoneA 1 Antwort Letzte Antwort
              0
              • Chris_71C Chris_71

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

                AlCalzoneA Offline
                AlCalzoneA Offline
                AlCalzone
                Developer
                schrieb am zuletzt editiert von AlCalzone
                #54

                @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?

                Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

                1 Antwort Letzte Antwort
                0
                • M Offline
                  M Offline
                  Mor9oth
                  schrieb am zuletzt editiert von
                  #55

                  @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());
                  
                  	});
                  
                  }
                  
                  AlCalzoneA 1 Antwort Letzte Antwort
                  0
                  • M Mor9oth

                    @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());
                    
                    	});
                    
                    }
                    
                    AlCalzoneA Offline
                    AlCalzoneA Offline
                    AlCalzone
                    Developer
                    schrieb am zuletzt editiert von
                    #56

                    @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.

                    Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

                    M 1 Antwort Letzte Antwort
                    0
                    • AlCalzoneA AlCalzone

                      @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 Offline
                      M Offline
                      Mor9oth
                      schrieb am zuletzt editiert von
                      #57

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

                      1 Antwort Letzte Antwort
                      0
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate

                      978

                      Online

                      32.6k

                      Benutzer

                      81.9k

                      Themen

                      1.3m

                      Beiträge
                      Community
                      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                      ioBroker Community 2014-2025
                      logo
                      • Anmelden

                      • Du hast noch kein Konto? Registrieren

                      • Anmelden oder registrieren, um zu suchen
                      • Erster Beitrag
                        Letzter Beitrag
                      0
                      • Home
                      • Aktuell
                      • Tags
                      • Ungelesen 0
                      • Kategorien
                      • Unreplied
                      • Beliebt
                      • GitHub
                      • Docu
                      • Hilfe