/* * @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.1 * Erstell-Datum: 13. 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) { 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) { var tmp_id = obj.id.split("."); if (obj.state.val != "" || obj.state.val != null) { 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] }); } } abonniere_datenpunkte(); } 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();