Vorwort

In diesem Beitrag zeige ich Dir, wie du deinen iRobot Roboter bequem anhand der Räume steuern kannst. Die Steuerung über die iRobot App bietet inzwischen die Möglichkeit, den jeweiligen Roboter mit einem Fingerzeig in den jeweiligen Raum fahren zu lassen. Über ioBroker ist dies bisher leider nur über Umwege möglich. Hier setzt mein Skript an und bietet Dir komfortabel die Möglichkeit, den Roboter in verschiedene Räume und sogar Zonen zu senden.

Des Weiteren zeigt das Skript folgende Daten an:

  • die gereinigte Fläche des Durchgangs
  • welches Wischtuch z.B. beim Braava installiert ist
  • ob der Wassertank des Braava gefüllt ist oder nicht

Damit das Skript ordnungsgemäß arbeiten kann, ist der Roomba Adapter in ioBroker notwendig. Des Weiteren sind ein paar Vorbereitungen notwendig – die aber relativ schnell, einfach und einmalig erledigt werden können.

Vorbereitungen

Installiere bitte den Roomba Adapter in ioBroker und richte den Adapter ein. Wie dies funktioniert, ist hier beschrieben.

Erstelle Dir ein neues Skript im common Bereich mit dem Namen “iRobot-Control”. In das leere Skript kopierst Du Dir den nachfolgenden Inhalt. Startest das Skript aber noch nicht, da noch 2 Zeilen anzupassen sind – Zeile 32 und 33.

Skript

/*
 * @copyright 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur erweiterten Steuerung der iRobot Roboter.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 * 
 * Ansprüche gegenüber Dritten bestehen nicht. 
 * 
 * Skript Name:		iRobot-Control
 * Skript Version:	1.2
 * Erstell-Datum:	14. Oktober 2021
 * 
 */

// Datenpunkte neu erstellen
var ueberschreiben = false;

// Hauptdatenpunkt unterhalb javascript
var datenpunkt = "iRobot."; // Abschließender Punkt !!! WICHTIG !!!

// Instanzen der Geräte
var datenpunkt_instanz = "roomba."; // Abschließender Punkt | !!! BITTE NICHT ÄNDERN !!!
var instanz_geraet = [0, 1]; // Installierte Instanz | Bsp: 0 für Roomba, 1 für Braava
var instanz_name = ["Roomba", "Braava"]; // Keine Leerzeichen | Namen der Geräte ohne Leerzeichen

function abonniere_datenpunkte() {
    for (let i = 0; i < instanz_geraet.length; i++) {
        // Abonniere Datenpunkt zu Details des Roboters
        on({ id: datenpunkt_instanz + instanz_geraet[i] + ".device._rawData", change: "any" }, function (obj) {
            // Hole Datenpunkt
            var j = JSON.parse(obj.state.val);

            // Aktualisiere alle Datenpunkte
            var tmp_id = obj.id.split(".");
            var id = tmp_id[1];
            aktualisiere_datenpunkte(id, j);
        });
        // Abonniere eigene Datenpunkte zur Steuerung
        on({ id: "javascript.0." + datenpunkt + instanz_name[i] + ".Steuerung", change: "any" }, function (obj) {
            if (obj.state.val != "" || obj.state.val != null) {
                var tmp_id = obj.id.split(".");
                robot_steuerung(instanz_name.indexOf(tmp_id[tmp_id.length - 2]), obj.state.val, "Skript-Control");
            }
        });
        // Abonniere eigene Datenpunkte für geplante Bereiche
        on({ id: "javascript.0." + datenpunkt + instanz_name[i] + ".Geplante_Bereiche", change: "any" }, function (obj) {
            if (obj.state.val != "" || obj.state.val != null) {
                var tmp_id = obj.id.split(".");
                robot_auftrag(instanz_name.indexOf(tmp_id[tmp_id.length - 2]), obj.state.val);
            }
        });
    }
}

// Reinigungsauftrag
function robot_auftrag(idRoboter, bereiche) {
    // Basis JSON Objekt
    let j_kommando = {
        command: "start",
        ordered: 1,
        pmap_id: null,
        regions: [],
        user_pmapv_id: null
    };

    var array_bereiche = bereiche.split(",");
    // Lese alle vorhandenen Räume ein
    var vorhandene_bereiche = $('state[id=javascript.0.' + datenpunkt + instanz_name[idRoboter] + '.*.*.name]');
    vorhandene_bereiche.each(function (id, i) {
        // Trenne den Datenpunkt
        var tmp_id = id.split(".");
        // lesbarer Name des Bereichs
        var bereich_name = getState(id).val;
        // ID des Bereichs (Raum oder Zone)
        var bereich_id = tmp_id[tmp_id.length - 2];
        // Typ -> Zone oder Raum
        var typ = tmp_id[tmp_id.length - 3];
        // Karte
        var karte = getState(datenpunkt + instanz_name[idRoboter] + ".Bereiche." + tmp_id[tmp_id.length - 4] + ".pmap_id").val;
        // Version der Karte
        var version = getState(datenpunkt + instanz_name[idRoboter] + ".Bereiche." + tmp_id[tmp_id.length - 4] + ".user_pmapv_id").val;

        for (let i = 0; i < array_bereiche.length; i++) {
            // Sortiere die Räume und Zonen ein
            if (bereich_name == array_bereiche[i].trim()) {
                j_kommando.pmap_id = karte;
                j_kommando.user_pmapv_id = version;

                if (typ == "Raeume") {
                    let tmp = { region_id: bereich_id.toString(), type: "rid" };
                    j_kommando.regions.push(tmp);
                }
                if (typ == "Zonen") {
                    let tmp = { region_id: bereich_id.toString(), type: "zid" };
                    j_kommando.regions.push(tmp);
                }
            }
        }
    });
    let kommando = JSON.stringify(j_kommando);
    setState(datenpunkt_instanz + idRoboter + ".commands._runCommand", kommando);
}

// Roboter Steuerung
/**
* @param {string | number} id
* @param {string} kommando
* @param {string} app
*/
function robot_steuerung(id, kommando, app) {
    let j_command = { command: kommando, time: Date.now() / 1000 | 0, initiator: app };
    let command = JSON.stringify(j_command);

    // Prüfe, von wem das Kommando kam
    if (app == "Skript-Control") {
        setState("roomba." + id + ".commands._runCommand", command);
    } else {
        setState(datenpunkt + instanz_name[id] + ".Steuerung", kommando, true);
    }
}

// Lege neuen Raum an
function neuer_raum(geraet, pmap_id, region_id, region_type, user_pmapv_id) {
    // Bereiche
    createState(datenpunkt + geraet + ".Bereiche." + pmap_id, '', { name: 'ID der Karte', type: 'string', role: 'state' }, function () { });
    createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".pmap_id", pmap_id, { name: "ID der Karte", type: 'string', role: 'value' }, function () { });
    createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".user_pmapv_id", user_pmapv_id, { name: "Version der Karte", type: 'string', role: 'value' }, function () { });

    // Raum
    if (region_type == "rid") {
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id, '', { name: 'ID des Raumes', type: 'string', role: 'state' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id + '.region_id', region_id, { name: 'ID Des Raumes', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id + '.name', '', { name: 'Eigener Name des Raumes', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Raeume.' + region_id + '.erstellt', hole_datum(), { name: 'Datum des Hinzufügens', type: 'string', role: 'value' }, function () { });
        log("iRobot-Control: Neuer Raum für " + geraet + " gefunden und angelegt! ID: " + region_id);
    }

    // Schmutzzone
    if (region_type == "zid") {
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Zonen.' + region_id, '', { name: 'ID der Zone', type: 'string', role: 'state' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".Zonen." + region_id + '.region_id', region_id, { name: 'ID der Zone', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + ".Zonen." + region_id + '.name', '', { name: 'Eigener Name der Zone', type: 'string', role: 'value' }, function () { });
        createState(datenpunkt + geraet + ".Bereiche." + pmap_id + '.Zonen.' + region_id + '.erstellt', hole_datum(), { name: 'Datum des Hinzufügens', type: 'string', role: 'value' }, function () { });
        log("iRobot-Control: Neue Zone für " + geraet + " gefunden und angelegt! ID: " + region_id);
    }
}

// Aktualisiere alle Datenpunkte
function aktualisiere_datenpunkte(id, j) {
    // Generelle Datenpunkte
    // Gereinigte Quadratmeter
    setState(datenpunkt + instanz_name[id] + ".Quadratmeter", parseFloat((j.bbrun.sqft / 10.764).toFixed(2)), true);
    // Prüfe Wassertank des Braava
    if (j.cleanMissionStatus.notReady === 31) {
        setState(datenpunkt + instanz_name[id] + ".Wassertank", true, true);
    } else {
        setState(datenpunkt + instanz_name[id] + ".Wassertank", false, true);
    }
    // Wischtuch des Braava
    if (j.detectedPad != null) {
        setState(datenpunkt + instanz_name[id] + ".Wischtuch", j.detectedPad, true);
    }

    // Aktuelle Räume im Auftrag
    setState(datenpunkt + instanz_name[id] + ".Durchgang_Raeume", generiere_raumliste(id, j.lastCommand.pmap_id, j.lastCommand.regions), true);

    // Prüfe, ob kein Training stattfindet
    if (j.lastCommand.regions != null) {
        var region_id = j.lastCommand.regions[0].region_id;
        var region_type = j.lastCommand.regions[0].type;
        var pmap_id = j.lastCommand.pmap_id;
        var user_pmapv_id = j.lastCommand.user_pmapv_id;

        // Region Räume
        if (region_type == "rid") {
            // Prüfe, ob Raum existiert
            if (!existsState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".Raeume." + region_id + ".region_id")) {
                // Raum existiert nicht. Raum anlegen
                neuer_raum(instanz_name[id], pmap_id, region_id, region_type, user_pmapv_id);
            } else {
                if (user_pmapv_id != null) {
                    setState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".user_pmapv_id", user_pmapv_id, true);
                }
            }
        }
        // Region Zonen
        if (region_type == "zid") {
            // Prüfe, ob Raum existiert
            if (!existsState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".Zonen." + region_id + ".region_id")) {
                // Raum existiert nicht. Raum anlegen
                neuer_raum(instanz_name[id], pmap_id, region_id, region_type, user_pmapv_id);
            } else {
                if (user_pmapv_id != null) {
                    setState(datenpunkt + instanz_name[id] + ".Bereiche." + pmap_id + ".user_pmapv_id", user_pmapv_id, true);
                }
            }
        }
    }
}

// Generiere Raumliste
function generiere_raumliste(id, karte, raeume) {
    if (raeume == null) {
        return "Keine Räume im Auftrag";
    } else {
        // Lege Array an
        var raumliste_name = new Array();
        // Irritiere über die übermittelten Räume
        for (let i = 0; i < raeume.length; i++) {
            var name = "";
            if (raeume[i].type == "rid") {
                if (existsState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Raeume." + raeume[i].region_id + ".name")) {
                    name = getState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Raeume." + raeume[i].region_id + ".name").val;
                    if (name == "" || name == null) {
                        name = "Namenloser Raum mit der ID: " + raeume[i].region_id;
                    }
                } else {
                    // Raum noch nicht vorhanden
                    name = "Nicht definierter Raum (ID: " + raeume[i].region_id + ")";
                }
            }
            if (raeume[i].type == "zid") {
                if (existsState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Zonen." + raeume[i].region_id + ".name")) {
                    name = getState(datenpunkt + instanz_name[id] + ".Bereiche." + karte + ".Zonen." + raeume[i].region_id + ".name").val;
                    if (name == "" || name == null) {
                        name = "Namenlose Zone mit der ID: " + raeume[i].region_id;
                    }
                } else {
                    // Raum noch nicht vorhanden
                    name = "Nicht definierte Zone (ID: " + raeume[i].region_id + ")";
                }
            }
            if (name != "") {
                raumliste_name.push(name);
            }
        }
        // Gebe Raumliste zurück
        if (raumliste_name.length === 0) {
            return "Keine Räume im Autrag!";
        } else {
            return raumliste_name.join(", ");
        }
    }
}

// Datum 
function hole_datum() {
    let datum = new Date();
    let tag = '0' + datum.getDate();
    let monat = '0' + (datum.getMonth() + 1);
    let jahr = datum.getFullYear();
    let stunde = '0' + datum.getHours();
    let minute = '0' + datum.getMinutes();
    let sekunde = '0' + datum.getSeconds();
    return tag.substr(-2) + '.' + monat.substr(-2) + '.' + jahr + ' ' + stunde.substr(-2) + ':' + minute.substr(-2) + ':' + sekunde.substr(-2);
}

// Werte für die Datenpunkte
// iRobot Objekte
var objekt = [
    "Steuerung",
    "Quadratmeter",
    "Wassertank",
    "Wischtuch",
    "Durchgang_Raeume",
    "Geplante_Bereiche"
];

// Beschreibung der Objekte
var beschreibung = [
    "Steuerung des Roboters",
    "Gereinigte Quadratmeter",
    "Wassertank des Braava",
    "Montiertes Wischtuch des Braava",
    "Räume des aktuellen Durchgangs",
    "Geplante Bereiche für den Durchgang"
];

// Einheiten der Objekte
var einheiten = [
    "",
    "qm²",
    "",
    "",
    "",
    ""
    ,];

// Typen der Objekte
var typen = [
    "string",
    "number",
    "boolean",
    "string",
    "string"
];

// Rollen der Objekte
var rolle = [
    "action",
    "value",
    "inidcator",
    "value",
    "value",
    "string"
];

// Erstelle die benötigten Datenpunkte
function datenpunkte_erstellen() {
    for (let g = 0; g < instanz_geraet.length; g++) {
        for (let i = 0; i < objekt.length; i++) {
            createState(datenpunkt + instanz_name[g] + "." + objekt[i], null, ueberschreiben, {
                name: beschreibung[i],
                desc: beschreibung[i],
                type: typen[i],
                role: rolle[i],
                unit: einheiten[i]
            });
        }
    }
    log("iRobot-Control: Datenpunkte werden im Hintergrund erstellt. Bitte warte 30 Sekunden!");
    setTimeout(abonniere_datenpunkte, 30000);
}

function irobot_erster_start() {
    log("iRobot-Control: Erster Start des Skriptes! Datenpunkte werden erstellt!");
    // Datenpunkte werden erstellt
    if (existsState(datenpunkt_instanz + "0.device._rawData")) {
        datenpunkte_erstellen();
    } else {
        stopScript("");
        log("iRobot-Control: Fehler: Roomba Adapter scheint nicht installiert zu sein!", "error");
    }
}

// Erster Start und Initialisierung
irobot_erster_start();

Konfiguration

Damit nun das Skript weiss, welche iRobot Geräte (bei mehr als 2 Instanzen) bei Dir vorhanden sind, musst Du Zeile 32 und 33 wie folgt anpassen.

Zeile 32: Hier sind die Instanzen des Roomba Adapters gemeint. Bei einem Gerät ist es die 0. Bei mehr als einer Instanz sind diese mit Komma getrennt anzugeben.

Zeile 33: Hier gibts Du die Namen der Geräte an, damit Du sie leichter zuordnen kannst.

Ab hier kannst Du das Skript starten und es werden einige Datenpunkte unterhalb javascript.0.iRobot erzeugt. Pro Gerät, welches Du angegeben hast, wie folgt:

DatenpunktBezeichnung
Bereiche (Ordner)Beinhaltet die Bereiche, die gefunden wurden (s.u.)
Duchgang_RaeumeRäume des aktuellen Durchgangs
Geplante_BereicheGeplante Bereiche für den Durchgang
QuadratmeterGereinigte Quadratmeter
SteuerungSteuerung des Roboters (mehr Befehle möglich)
WassertankWassertank des Braava (sonst “null”)
WischtuchWischtuch des Braava (sonst “null”)

Räume dem Skript hinzufügen

Da das Skript nun gestartet ist und die einzelnen Datenpunkte oberhalb bereits erstellt worden sind, kannst Du beginnen, die einzelnen Räume dem Skript zuzuweisen.

Starte mit der Roomba App auf dem Smartphone einen Reinigungsauftrag für ein Gerät (beim Roomba ohne Nachwischen). Sobald der Roboter losgefahren ist (maximal 60 Sekunden später), kannst Du im Log von ioBroker erkennen, dass das Skript eine ID und einen Bereich (Zone oder Raum) ausgibt.

Robot-Control: Neuer Raum für Roomba gefunden und angelegt! ID: 4

Hieran kannst Du erkennen, das es sich um einen neuen Raum handelt, den das Skript noch nicht kennt.

Der Roboter kann in der Zwischenzeit zur Basis zurückkehren.

Nun begibst Du Dich in den Objekt-Browser von ioBroker und navigierst zu:

javascript.0.iRobot.<Name-des-Roboters>.Bereiche.<Karte-ID>.<Bereich>.<ID des Raumes> (Bereich: Raeume oder Zone; ID des Raumes: ID aus dem Log)

Hier solltest du ein Layout wie folgt sehen:

Objekte des Skriptes
Objekte des Skriptes

Dort gibt es nun den Ordner mit der gefundenen ID – hier 4. Diesen Ordner kannst Du nun der Übersicht halber einem Raum aus der ioBroker Liste zuweisen (nur für die Optik). Viel wichtiger ist hier der Datenpunkt “name“. Das ist später der eigentliche Name, den das Skript verwendet. Anklicken, Namen festlegen, Wert setzen, Fertig. Der erste Raum ist nun angelegt.
Tipp: Am Besten verwendest Du die gleichen Namen, wie in der App.

Nun solltest Du (innerhalb von 60 Sekunden) sehen, das der Datenpunkt “Durchgang_Raeume” auch den von dir festgelegten Raum darstellt.

Datenpunkt des aktuellen Durchgangs
Datenpunkt des aktuellen Durchgangs

Diesen Schritt kannst Du nun für jeden Raum wiederholen. Bitte bedenke, dass das Skript während der Einrichtung immer nur einen Raum identifiziert. Dies macht es Dir leichter, die einzelnen Räume zu benennen, da man bei mehreren ID’s wahrscheinlich durcheinander kommt 😉

Anwendung des Skripts – Räume und Zonen steuern

Nachdem Du nun alle Räume und Zonen dem Skript mitgeteilt hast, kann es an die eigentliche Verwendung gehen – das Steuern des Roboters über die Raumnamen.

Hier ist der jeweilige Datenpunkt javascript.0.iRobot.<Name-des-Roboters>.Geplante_Bereiche wichtig, denn hier kannst du – jeweils durch ein Komma getrennt, deine Räume und Zonen zur gleichen Zeit eintragen und der Roboter beginnt mit der Reinigung. Auch die Priorisierung ist möglich. Der Raum oder die Zone, die zuerst angegeben ist, wird zuerst gereinigt. Einfach, oder?

Beispiel:

Du möchtest Küche, Couchtisch und Esszimmer reinigen. So schreibst Du diesen Wert (String) einfach in den Datenpunkt. Dies kann natürlich auch über ein kleines Skript erfolgen, welches in etwa so aussieht:

// Reinigung von Küche, Couchtisch und Esszimmer jeden Tag zur goldenen Abendstunde
schedule({ astro: "goldenHour" }, function () {
    setState("javascript.0.iRobot.Roomba.Geplante_Bereiche", "Küche, Couchtisch, Esszimmer", true);
});

Weitere Zeiten zum Thema “Astro” findest Du hier.

Natürlich lassen sich alle Datenpunkte auch in VIS oder JarVIS steuern und anzeigen.

Hier ein Beispiel für JarVIS und den Roomba i7:

Roomba i7 in JarVIS
Roomba i7 in JarVIS

Anwendung des Skripts – iRobot steuern

Wie eingangs erwähnt, bietet mein Skript noch einige Steuerbefehle mehr. Diese laufen über den Datenpunkt javascript.0.iRobot.<Name-des-Roboters>.Steuerung

Dieser Wert wird immer mit dem des Roomba Adapter abgeglichen – heisst, wenn der Adapter “stop” meldet, aktualisiert sich dieser Datenpunkt auch. Wir können diesen Datenpunkt aber auch selber nutzen, um den iRobot zu steuern. Dies funktioniert mit folgenden Befehlen, die der Roomba Adapter zwar unterstützt aber nicht selbst anbietet:

WertBezeichnung
startStarten des iRobot
stopStoppen des iRobot
pausePausieren des iRobot
resumeFortsetzen des iRobot
dockiRobot zur Aufladestation senden
trainiRobot auf einen Kartierungslauf schicken
findiRobot suchen – ein Ton ertönt
evaciRobot an der Absaugstation absaugen lassen (nur für Modelle mit Absaugstation)
Mögliche Steuerbefehle

Anwendung des Skript – erweiterte Datenpunkte

Der Roomba Adapter bietet zwar die Ausgabe der erledigten Quadratmeter – dies funktioniert aber leider inzwischen – oder bei neueren Modellen – nicht mehr. Mein Skript zeigt Dir folgende Werte an:

DatenpunktBeschreibung
QuadratmeterGereinigte Quadratmeter des Durchlaufs
Wassertankfalse bei vollem Behälter – true bei leerem Behälter
WischtuchInstalliertes Wischtuch der Braava Modelle
Erweiterte Datenpunkte

Kategorien:

7 Kommentare

  1. Hallo,

    ich wollte Dein Skript ausprobieren, es kommt allerdings beim Skriptstart zu einer Fehlermeldung bei mir:
    “javascript.0
    2021-10-14 09:13:23.654 error at processImmediate (internal/timers.js:461:21)
    javascript.0
    2021-10-14 09:13:23.654 error at Immediate._onImmediate (/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js:5706:41)
    javascript.0
    2021-10-14 09:13:23.654 error at Object.stateChange (/opt/iobroker/node_modules/iobroker.javascript/main.js:525:29)
    javascript.0
    2021-10-14 09:13:23.654 error at Object.callback (/opt/iobroker/node_modules/iobroker.javascript/lib/sandbox.js:1087:38)
    javascript.0
    2021-10-14 09:13:23.654 error at Object. (script.js.common.iRobot-Control:56:17)
    javascript.0
    2021-10-14 09:13:23.653 error at robot_auftrag (script.js.common.iRobot-Control:73:35)
    javascript.0
    2021-10-14 09:13:23.653 error Error in callback: TypeError: Cannot read property ‘split’ of null”

    und der Ordner “Bereiche” wird nicht angelegt.

      • Hallo Stephan, ja habe ich:
        // Instanzen der Geräte
        var datenpunkt_instanz = “roomba.”; // Abschließender Punkt | !!! BITTE NICHT ÄNDERN !!!
        var instanz_geraet = [0]; // Installierte Instanz | Bsp: 0 für Roomba, 1 für Braava
        var instanz_name = [“Roomba”]; // Keine Leerzeichen | Namen der Geräte ohne Leerzeichen

        Ich versiche mal Deine Änderungen

      • Nach Deinen Änderungen im Skript kommt zwar keine Fehlermeldung, es werden aber trotzdem nicht die Datenpunkte richtig angelegt. Der Ordner “Bereiche” fehlt weiterhin.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.