Skip to content
  • 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
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere)

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.1k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    1.8k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    15
    1
    2.1k

[Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere)

Geplant Angeheftet Gesperrt Verschoben JavaScript
javascript
50 Beiträge 19 Kommentatoren 12.5k Aufrufe 40 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.
  • crunchipC Abwesend
    crunchipC Abwesend
    crunchip
    Forum Testing Most Active
    schrieb am zuletzt editiert von
    #28

    funktioniert prima, 👏 da kommen bestimmt ein paar neue Ideen auf😊
    Test mit 2 BWM steht allerdings noch aus

    umgestiegen von Proxmox auf Unraid

    1 Antwort Letzte Antwort
    1
    • T Offline
      T Offline
      Tirador
      schrieb am zuletzt editiert von Tirador
      #29

      Hallo Mic,

      ein tolles Skript von Dir! 🙂

      Ich nutze deconz. Dort ist es so, dass es mehrere Datenpunkte gibt für einen Bewegungsmelder (Hue Philipps).

      Das führt dazu, dass die Eigenschaft Bewegung "presence" und "lux" in verschiedenen Ordnern liegen:

      2020-03-24 20_21_08-objects - ioBroker.png

      So wie ich das Skript nun interpretiere werden aktuell alle Eigenschaften unter einem Ordner erwartet oder habe ich dies falsch interpretiert?

      Was mir auch aufgefallen ist: Erwägst du es noch auch die Helligkeit der zu steuernden Lampen mit vorgeben zu können.
      Bei mir ist es so, dass ich Nachts im Flur eher gedimmtes Licht möchte 😉

      mein Vorschlag für die Implementierung im Skript wäre es die Bewegungsmelder einzeln mit Datenpunkten für presence und lux als Array vorgeben zu können.

      Beispiel:

      const BWM = {
              flur: {sensorState: 'deconz.0.Sensors.36.presence', stateLux: 'deconz.0.Sensors.40.lux' },
             bad: {sensorState: 'deconz.0.Sensors.45.presence', stateLux: 'deconz.0.Sensors.47.lux' },
      };
      
      1 Antwort Letzte Antwort
      0
      • tugsiT Offline
        tugsiT Offline
        tugsi
        schrieb am zuletzt editiert von
        #30

        N´Abend,
        erstmal Danke für das Script.
        Nur irgendwie will das bei mir nicht so richtig klappen.

        Habe mein Aqara BWM eingebunden und der soll mir ein Datenpunkt setzen, dies passiert auch, aber wenn ich unter Objekte schaue, wird der Datenpunkt hinten mit einem roten "true" gesetzt, nicht mit einem grünen.

        Das ist mein Datenpunkt:

        {
          "common": {
            "type": "boolean",
            "read": true,
            "write": true,
            "name": "Flurbeleuchtung",
            "role": "switch",
            "unit": "",
            "smartName": {
              "de": "Flurbeleuchtung",
              "smartType": "SWITCH"
            }
          },
          "native": {
            "name": "Flurbeleuchtung",
            "role": "switch",
            "type": "boolean",
            "unit": "",
            "read": true,
            "write": true,
            "smartName": {
              "de": "Flurbeleuchtung",
              "smartType": "SWITCH"
            }
          },
          "type": "state",
          "from": "system.adapter.javascript.0",
          "user": "system.user.admin",
          "ts": 1579636502610,
          "_id": "javascript.0.S7.s7-0.Flurbeleuchtung",
          "acl": {
            "object": 1636,
            "state": 1636,
            "owner": "system.user.admin",
            "ownerGroup": "system.group.administrator"
          }
        }
        

        Klicke ich unter Objekte den manuell an auf true, funzt alles wie gehabt.
        Der Datenpunkt wird auch von meiner Alexa angesteuert, auf Zuruf, da klappt es auch.

        Jemand eine Erklärung?
        Gruß Thomas

        Master ioBroker in Proxmox als LXC auf 1. Tiny-Lenovo, Proxmox-VM als Slave auf 2. Tinyi-Lenovo mit Zigbee und Monitor zur Visualisierung, Hauptautomatisierung über S7 auf Beckhoff CX, dazu noch Shelly, Homematic...

        1 Antwort Letzte Antwort
        0
        • Michael SauerM Offline
          Michael SauerM Offline
          Michael Sauer
          schrieb am zuletzt editiert von
          #31

          Hallo Mic,

          tolles Script. Praktisch wäre auch mehrere Targets gleichzeitig zu schalten.

          Mfg

          1 Antwort Letzte Antwort
          0
          • MicM Offline
            MicM Offline
            Mic
            Developer
            schrieb am zuletzt editiert von
            #32

            Hi zusammen,
            danke für eure Rückmeldungen. Ich entwickle gerade 2 neue ioBroker-Adapter, daher komme ich momentan nicht dazu, das Script zu erweitern.
            Aber ich plane einen Adapter hierfür, also für die Steuerung von Bereichen (z.B. Flur, Wohnzimmer, xyz, im Verbund mit Bewegungsmeldern und Schalter/Lichter). Aber erst mal muss ich die beiden jetzt zu entwickelnden Adapter fertigstellen 😉

            1 Antwort Letzte Antwort
            2
            • W Offline
              W Offline
              wannabe
              schrieb am zuletzt editiert von wannabe
              #33

              Sehr schönes, praktisches Projekt. Das Reinarbeiten in die Config hat ein bisschen gedauert, aber wenns dann einmal läuft ...
              Will ich nicht mehr missen, schön zentral alles zusammen, nicht x verschiedene Skripte.
              Ein Backup davon kommt auf jeden Fall in meinen Ordner für schlechte Zeiten.
              Danke fürs veröffentlichen.

              1 Antwort Letzte Antwort
              0
              • ? Offline
                ? Offline
                Ein ehemaliger Benutzer
                schrieb am zuletzt editiert von
                #34

                Einen Dank an den Entwickler des Scripts. Funktioniert soweit sehr gut und hat bei mir eine Menge anderer Blocklys abgelöst 🙂
                Ein kleines Problem habe ich dann doch noch gefunden. Mein Hausflur hat zwei BW plus einen Türkontakt der die Beleuchtung einschaltet wenn man ins Haus kommt. Aber erst wenn es Dunkel ist bzw die entsprechenden LUX unterschritten sind. Und genau das bekomme ich mit deinem Script nicht umgesetzt. Ich habe bei mir den deconz Adapter im Einsatz. Als Sensoren habe ich zum größten Teil Xiaomi Geräte.

                const ADAPTER_STATES = {
                mihome: {stateMotion: 'state', stateLux: 'lux'},
                zigbee: {stateMotion: 'occupancy', stateLux: 'illuminance'},
                deconz: {stateMotion: 'presence', stateMotion: 'open'},
                sonoff: {stateLux: 'BH1750_Illuminance'},
                };

                Das war mein Versuch den Türkontakt mit einzubinden. Der schaltet zwar das Licht ein wenn ich die Tür öffne aber auch wenn es taghell ist. Die eingetragenen LUX Werte werden ignoriert. Die zwei BM hingegen funktionieren wie gewünscht.

                1 Antwort Letzte Antwort
                0
                • MicM Mic

                  (Update: 15.03.2020)

                  Hi,

                  Auszug aus den Features:

                  1. Beliebig viele Bewegungsmelder einbinden. Pro Bewegungsmelder/Bereich können Geräte/Lichter bei Bewegung eingeschaltet und wieder ausgeschaltet werden, sobald x Sekunden keine Bewegung mehr.
                  2. Mehrere Bewegungsmelder pro Raum/Bereich (z.B. Flur) möglich.
                  3. Beliebig viele Zeiträume zum Schalten einstellbar (z.B. nur bestimmte Wochentage, Uhrzeiten, Astro, etc.).
                  4. Helligkeit (Lux) als Trigger - es wird optional nur eingeschaltet, wenn Helligkeit unter einem vorgegeben Wert ist, damit z.B. bei genügend Helligkeit nicht eingeschaltet wird.
                  5. Optionale Verzögerung zum wieder einschalten: In manchen Fällen will man ggf. mit dem Bewegungsmelder nur einmalig einschalten. Da kann man für bestimmte Bewegungsmelder einstellen, dass x Sekunden (z.B. 10 Minuten = 600s) nicht mehr neu ausgelöst wird.
                  6. Prüfung auf Anwesenheit (oder andere Datenpunkte): Wenn im Script konfigurierte Datenpunkte mit einem bestimmten Wert übereinstimmen, wird nicht geschaltet. Hilfreich, um z.B. nicht zu schalten, wenn keiner anwesend ist, oder etwa ein Fenster offen ist, etc.

                  Installation und Einrichtung:

                  Link: Github: Bewegungsmelder-Script (für Xiaomi und andere)

                  Ich freue mich über Euer Feedback.

                  F Offline
                  F Offline
                  FabianHM
                  schrieb am zuletzt editiert von
                  #35

                  Hallo @Mic
                  neben Deinen anderen tollen Scripten (Logparser) bin ich gerade bei meinem aktuellen use case zum Thema Bewegungsmelder auf dieses Script gestoßen.
                  Bevor ich mich tiefer einarbeite kurz die Frage, ob folgender use case bereits out of the box enthalten ist, bzw nutzbar ist:

                  Ich habe mehrere Bewegungsmelder im Einsatz und möchte den identifizieren, wo zuletzt Bewegung und zu welchem Zeitpunkt erkannt wurde?
                  Ist das bereits on Board?
                  Danke und Grüße
                  Fabian

                  MicM 1 Antwort Letzte Antwort
                  0
                  • F FabianHM

                    Hallo @Mic
                    neben Deinen anderen tollen Scripten (Logparser) bin ich gerade bei meinem aktuellen use case zum Thema Bewegungsmelder auf dieses Script gestoßen.
                    Bevor ich mich tiefer einarbeite kurz die Frage, ob folgender use case bereits out of the box enthalten ist, bzw nutzbar ist:

                    Ich habe mehrere Bewegungsmelder im Einsatz und möchte den identifizieren, wo zuletzt Bewegung und zu welchem Zeitpunkt erkannt wurde?
                    Ist das bereits on Board?
                    Danke und Grüße
                    Fabian

                    MicM Offline
                    MicM Offline
                    Mic
                    Developer
                    schrieb am zuletzt editiert von Mic
                    #36

                    Hi,

                    @FabianHM sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                    Bevor ich mich tiefer einarbeite kurz die Frage, ob folgender use case bereits out of the box enthalten ist, bzw nutzbar ist:
                    Ich habe mehrere Bewegungsmelder im Einsatz und möchte den identifizieren, wo zuletzt Bewegung und zu welchem Zeitpunkt erkannt wurde?
                    Ist das bereits on Board?

                    Nein, das bietet dieses Bewegungsmelder-Script nicht bzw. nicht für diesen Einsatzzweck.

                    @FabianHM sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                    neben Deinen anderen tollen Scripten (Logparser)

                    Das Logparser-Script wurde mittlerweile durch einen Adapter ersetzt, ich empfehle, dass du daher den Adapter einsetzt: https://forum.iobroker.net/topic/31969/test-adapter-log-parser-v0-x-x-github

                    Falls deine Bewegungsmelder Logs ausgeben bei Bewegung, kannst du das natürlich dann auch über den Logparser-Adapter parsen/filtern und zur Anzeige bringen. Geht auch über Blockly/JavaScript.

                    F 1 Antwort Letzte Antwort
                    0
                    • MicM Mic

                      Hi,

                      @FabianHM sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                      Bevor ich mich tiefer einarbeite kurz die Frage, ob folgender use case bereits out of the box enthalten ist, bzw nutzbar ist:
                      Ich habe mehrere Bewegungsmelder im Einsatz und möchte den identifizieren, wo zuletzt Bewegung und zu welchem Zeitpunkt erkannt wurde?
                      Ist das bereits on Board?

                      Nein, das bietet dieses Bewegungsmelder-Script nicht bzw. nicht für diesen Einsatzzweck.

                      @FabianHM sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                      neben Deinen anderen tollen Scripten (Logparser)

                      Das Logparser-Script wurde mittlerweile durch einen Adapter ersetzt, ich empfehle, dass du daher den Adapter einsetzt: https://forum.iobroker.net/topic/31969/test-adapter-log-parser-v0-x-x-github

                      Falls deine Bewegungsmelder Logs ausgeben bei Bewegung, kannst du das natürlich dann auch über den Logparser-Adapter parsen/filtern und zur Anzeige bringen. Geht auch über Blockly/JavaScript.

                      F Offline
                      F Offline
                      FabianHM
                      schrieb am zuletzt editiert von
                      #37

                      @Mic said in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                      Hi,

                      @FabianHM sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                      Bevor ich mich tiefer einarbeite kurz die Frage, ob folgender use case bereits out of the box enthalten ist, bzw nutzbar ist:
                      Ich habe mehrere Bewegungsmelder im Einsatz und möchte den identifizieren, wo zuletzt Bewegung und zu welchem Zeitpunkt erkannt wurde?
                      Ist das bereits on Board?

                      Nein, das bietet dieses Bewegungsmelder-Script nicht bzw. nicht für diesen Einsatzzweck.

                      @FabianHM sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                      neben Deinen anderen tollen Scripten (Logparser)

                      Das Script wurde mittlerweile durch einen Adapter ersetzt, ich empfehle, dass du daher den Adapter einsetzt: https://forum.iobroker.net/topic/31969/test-adapter-log-parser-v0-x-x-github

                      Falls deine Bewegungsmelder Logs ausgeben bei Bewegung, kannst du das natürlich dann auch über den Logparser-Adapter parsen/filtern und zur Anzeige bringen. Geht auch über Blockly/JavaScript.

                      Das ist eine gute Idee! Schaue es mir mal an, denn über das Log bzw den Filter den Bewegungsmelder zu identifizieren sollte einfach realisierbar sein.
                      Dankeschön!

                      1 Antwort Letzte Antwort
                      0
                      • H Offline
                        H Offline
                        heinzie
                        schrieb am zuletzt editiert von heinzie
                        #38

                        Hallo,

                        versuche mich gerade auch an dem Script, aber irgendwie läuft es nicht.
                        Verwende den zigbee Adapter und habe dort eine Xiaomi Bewegungsmelder und ien OSRAM Steckdose dran.
                        Das hat bisher mit mit einem Blocky soweit funktioniert. Da ich aber mehrere habe wollte ich gerne auf das Script umstellen.

                        Für den Test habe ich nur dieses eingebunden:

                        /////////////////////
                        // Hier die einzelnen Bewegungssensoren anlegen und einstellen.
                        // Im ersten Beispiel ist alles im Detail beschrieben.
                        /////////////////////
                        const MOTION_SENSORS = [
                            
                           {
                            name:                   'Bad',
                            sensorState:            'zigbee.0.00158d00023d8e9a.occupancy',
                            period_1:               {start:'6:00', end:'23:00',    sec:240 },
                            //period_2:               {start:'9:00', end:'23:00',    sec:120 },
                            //neverPeriod_1:          {start:'12:00', end:{astro:'goldenHour', offset: -30} },
                            //neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                            target:                 'zigbee.0.7cb03eaa00a3ca47.state',
                          },
                        ];
                        

                        müsste doch eigentlich passen (von der Syntax) , oder?

                        Im Log steht nur folgendes

                        javascript.0	2020-05-16 18:50:33.548	info	(522) script.js.common.Bewegungsmelder: registered 1 subscription and 0 schedules
                        javascript.0	2020-05-16 18:50:33.547	info	(522) script.js.common.Bewegungsmelder: *** Bewegungsmelder-Script gestartet *** Folgende Bewegungsmelder werden überwacht: Bad
                        javascript.0	2020-05-16 18:50:33.547	info	(522) script.js.common.Bewegungsmelder: [DEBUG] VALIDIERUNG *** ENDE: Prüfung der Script-Konfiguration, Ergebnis: keine Fehler ***
                        javascript.0	2020-05-16 18:50:33.546	info	(522) script.js.common.Bewegungsmelder: [DEBUG] VALIDIERUNG Bad: Adapter/Datenpunkt [zigbee] ist korrekt konfiguriert.
                        javascript.0	2020-05-16 18:50:33.546	info	(522) script.js.common.Bewegungsmelder: [DEBUG] VALIDIERUNG *** START: Prüfung der Script-Konfiguration ***
                        javascript.0	2020-05-16 18:50:33.532	info	(522) Start javascript script.js.common.Bewegungsmelder
                        

                        hängt es ggf. mit "and 0 schedules" zusammen?

                        1 Antwort Letzte Antwort
                        0
                        • H Offline
                          H Offline
                          heinzie
                          schrieb am zuletzt editiert von
                          #39

                          @heinzie sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                          sensorState: 'zigbee.0.00158d00023d8e9a.occupancy',

                          Habe das Problem gefunden, die Angabe bei sensorState war falsch:

                          falsch -> sensorState: 'zigbee.0.00158d00023d8e9a.occupancy'
                          richtig -> sensorState: 'zigbee.0.00158d00023d8e9a'

                          1 Antwort Letzte Antwort
                          0
                          • M Offline
                            M Offline
                            MartyBr
                            schrieb am zuletzt editiert von
                            #40

                            @Mic
                            Hallo, ich habe dein Script installiert und zum testen zwei Bewegungsmelder im Wohnzimmer verbunden. Sie schalten zum Test eine Tischleuchte.
                            Bis dahin alles gut. Ich habe nur das Problem, dass das Script nun auch die Lampe ausschaltet, die ich vorher eingeschaltet habe. Das Script merkt also nicht das die Lampe schon eingeschaltet war.

                            Wie kann ich das verhalten verhindern?

                            P.S.
                            Ich setze vorrangig HM Komponenten ein, das funktioniert auch alles.

                            Hier das Script:

                            /*******************************************************************************
                             * Bewegungsmelder-Script: Schaltung Lichter/Geräte mittels Bewegungsmelder.
                             * ----------------------------------------------------
                             * In das Script lassen sich beliebig viele Xiaomi Aqara Bewegungsmelder einbinden. Getestet mit Adapter mihome und zigbee.
                             * Sicherlich lassen sich auch Bewegungsmelder anderer Hersteller einbinden, siehe hierzu ADAPTER_STATES unten.
                             * Hiweis: Es werden keinerlei Datenpunkte angelegt, da wir diese nicht benötigen.
                             * ----------------------------------------------------
                             * Autor: ioBroker-Forum-Name: Mic / Github-Name: Mic-M
                             * Source:  https://github.com/Mic-M/iobroker.xiaomi-aquara-motion-control
                             * Support: https://forum.iobroker.net/topic/22034/
                             * ----------------------------------------------------
                             * Change Log:
                             *  2.0 Mic - Complete recoding. Also, addition of several options, etc.
                             *  0.4 Mic - Allow using Zigbee adapter and others as well.
                             *  0.3 Mic - few code improvements
                             *  0.2 Mic - Fix: Compare Time
                             *  0.1 Mic - Initial Release
                             ******************************************************************************/
                            
                            
                            
                            /*******************************************************************************
                             * Konfiguration
                             ******************************************************************************/
                            
                            /////////////////////
                            // Hier die einzelnen Bewegungssensoren anlegen und einstellen.
                            // Im ersten Beispiel ist alles im Detail beschrieben.
                            /////////////////////
                            const MOTION_SENSORS = [
                            /*
                            {
                                // Beliebiger Name (für Log-Ausgabe). Bitte individuell vergeben.
                            name:                   'Gästezimmer',
                            
                                // Haupt-Datenpunkt des Bewegungsmelders, z.B. "mihome.0.devices.sensor_motion_aq2_1234567abcde" oder "zigbee.0.00123456789415"
                                // Es werden auch mehrere Sensoren unterstützt, d.h. etwa 3 Bewegungsmelder im Flur.
                            sensorState:            'mihome.0.devices.sensor_motion_aq2_11111111111111',
                            //    sensorState:            ['mihome.0.devices.sensor_motion_aq2_XXXXXXXXXXX', 'zigbee.0.XXXXXXXXXXXXX', 'zigbee.0.YYYYYYYYYYYYYYYYYYYYY'],
                            
                                // Hier beliebig viele Schaltzeitpunkte hinzufügen (period_1, period_2, period_3, usw.)
                                //  - "start" und "end": Erforderlich. Es wird geprüft, ob start/end innerhalb aktueller Uhrzeit ist, wenn Bewegungsmelder auslöst.
                                //                       Astro-Zeitangaben sind erlaubt, also etwa 'sunrise' oder mit einem Offset wie {astro: 'sunrise', offset: -30}
                                //                       Details zu start/end und Astro-Zeitangaben: https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#comparetime
                                // - "days":             OPTIONAL: Wenn weggelassen, wird jeden Tag geschaltet (Montag-Sonntag). 
                                //                       Montag = 1, Dienstag = 2, ... Sonntag = 7. 
                                //                       Mehrere Tage mit Komma trennen, z.B. '1, 3, 5' für Montag/Mittwoch/Freitag.
                                //                       Periodische Angaben wie '2-4' für Dienstag/Mittwoch/Donnerstag sind auch möglich.
                                //                       Ebenso Kombination einzelner Tage und Periode möglich, z.B. '2-4, 7' für Dienstag/Mittwoch/Donnerstag und Sonntag.
                                // - "sec":              OPTIONAL: Nach wie vielen Sekunden soll wieder ausgeschalten werden? Falls weggelassen oder 0, dann wird nicht ausgeschaltet.
                                // - "lux"               OPTIONAL: Ab wieviel Lux soll NICHT eingeschaltet werden? Falls weggelassen oder größer 9999, dann wird unababhängig von den gemessenen Lux immer eingeschaltet.
                                // - "luxAlways"         OPTIONAL: Wir gehen davon aus, dass Lampen geschaltet werden. Ist eine Lampe an, wird ein größerer Lux-Wert vom Sensor gemessen, daher macht die Prüfung auf Lux bei  
                                //                                 bereits eingeschalteter Lampe auf erneute Bewegung und Lux-Abfrage keinen Sinn mehr. Daher wird durch dieses Script bei Bewegung
                                //                                 -- während das Gerät (die Lampe) an ist -- die Lux-Erkennung hier deaktiviert. Zum dauerhaften aktivieren auf "true" setzen, damit wird immer auf Lux geprüft, 
                                //                                 auch wenn das Gerät an ist.
                            period_1:               {start:'sunsetStart', end:'21:30', days:'2-4, 7',   sec:120,     lux:90,    luxAlways:false},
                            
                                // Hier den Datenpunkt des Gerätes angeben, das geschaltet werden soll bei Bewegung an und wieder aus.
                                // Falls als String gesetzt, z.B. 'javascript.0.Licht.Schlafzimmer.Switch', muss Datenpunkt muss von Typ "Boolean" (true/false) sein.
                                //
                                // Es sind noch deutlich mehr Optionen möglich, hierzu muss als Objekt gesetzt werden: {on:{state:'fullybrowser.0.X_X_X_X.Commands.screenOn', cmd:true}, off:{state:'fullybrowser.X_X_X_X.Commands.screenOff', cmd: true}, checkOnOffStatusState:'fullybrowser.X_X_X_X.Info.isScreenOn'}
                                // Dadurch ist folgendes möglich:
                                // 1. Individuellen State für An/Aus setzen, Beispiel: {on:{state:'javascript.0.Wohnzimmer.Licht.Szene', cmd:'Entspannen'}, off:{state:'shelly.0.XXXXXXXXXX.Relay0.Switch', cmd: false}, checkOnOffStatusState:'shelly.0.XXXXXXXXXX.Relay0.Switch'}
                                // 2. Ausschalten deaktivieren (es wird also nur eingeschaltet): Einfach den Teil "off:{state:'fullybrowser.X_X_X_X.Commands.screenOff', cmd: true}," rauslöschen.
                                // 3. Individuellen State zur Erkennung, ob Gerät an oder aus ist setzen: checkOnOffStatusState:'fullybrowser.X_X_X_X.Info.isScreenOn'. Dies ist notwenig, wenn "on:{state" nicht Boolean (true/false) ist.
                                //target:                 {on:{state:'hue.0.R_Schlafzimmer.on', cmd:true}, off:{state:'hue.0.R_Schlafzimmer.on', cmd: false}, checkOnOffStatusState:'hue.0.R_Schlafzimmer.on'},
                            target:                 'hue.0.R_Gästezimmer.on',
                            
                                // Optional: In manchen Fällen will man ggf. mit dem Bewegungsmelder nur einmalig einschalten. Dann soll der Bewegungsmelder x Sekunden (z.B. 10 Minuten = 600s) nicht mehr neu auslösen.
                                //           Dazu hier den Wert in Sekunden entsprechend setzen. Durch weglassen oder wait:0 wird das ignoriert. 
                            wait:                0,
                            
                                // Optional: Nicht schalten: Wenn einer der folgenden Datenpunkte mit dem Wert übereinstimmt, wird nicht geschaltet.
                                //           Hilfreich, um z.B. nicht zu schalten, wenn keiner anwesend ist, oder etwa ein Fenster offen ist, etc.
                                //           Es können beliebig viele States hinzugefügt werden (neverState_1, neverState_2, neverState_3 usw.)
                            neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                            }, 
                            */  
                               
                               //
                               // Hier nun weitere Beispiele, ohne weiterer Erläuterung (da oben bereits beschrieben).
                              
                              {
                                name:                   'Wohnzimmer',
                                sensorState:            ['hm-rpc.2.000918A9xxxx.1', 'hm-rpc.2.000918A98yyyy.1'], // wir überwachen hier 2 Bewegungsmelder gleichzeitig
                                period_1:               {start:'00:00', end:'07:00',    sec:240},
                                period_2:               {start:'22:00', end:'23:59',    sec:240},
                                neverState_1:           {state:'hm-rega.0.950', val:false}, // Anwesenheit CCU
                                target:                'hm-rpc.1.OEQ0zzzz3.1.STATE',
                              }, 
                            /*  
                              {
                                name:                   'Küche',
                                sensorState:            'mihome.0.devices.sensor_motion_aq2_xxxxxxxxxxxx',
                                period_1:               {start:'7:00', end:'23:00',    sec:120, lux:10 },
                                neverPeriod_1:          {start:'goldenHourEnd', end:'goldenHour', days:'1-7'},
                                neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                                target:                 'shelly.0.SHSW-1#XXXXX#1.Relay0.Switch',
                                wait:                   300,
                              }, 
                              {
                                name:                   'Bad',
                                sensorState:            'zigbee.0.xxxxxxxxxxxx',
                                period_1:               {start:'6:00', end:'09:00',    sec:240, lux:150 },
                                period_2:               {start:'9:00', end:'23:00',    sec:120, lux:150 },
                                neverPeriod_1:          {start:'12:00', end:{astro:'goldenHour', offset: -30} },
                                neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                                target:                 'shelly.0.SHSW-1#XXXXX#1.Relay0.Switch',
                              }, 
                            
                              {
                                name:                   'Tablet',
                                sensorState:            'zigbee.0.xxxxxxxxxxxxxx',
                                period_1:               {start:'7:00', end:'23:00',  days:'1-4',  sec:600 },
                                period_2:               {start:'7:00', end:'24:00',  days:'5',  sec:600 },
                                period_3:               {start:'0:00', end:'02:00',  days:'6',  sec:600 },
                                period_4:               {start:'7:00', end:'24:00',  days:'6',  sec:600 },
                                period_5:               {start:'0:00', end:'02:00',  days:'7',  sec:600 },
                                period_6:               {start:'7:00', end:'23:00',  days:'7',  sec:600 },
                                neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                                target:                 {on:{state:'fullybrowser.0.10_10_0_129.Commands.screenOn', cmd:true}, off:{state:'fullybrowser.0.10_10_0_129.Commands.screenOff', cmd: true}, checkOnOffStatusState:'fullybrowser.0.10_10_0_129.Info.isScreenOn'},
                              }, 
                            */
                            ];
                            
                            
                            /*******************************************************************************
                             * Optionale weitere Einstellungen
                             ******************************************************************************/
                            
                            // Die Datenpunkte der einzelnen Adapter (mihome, zigbee, etc.) unterscheiden sich, daher definieren wir diese hier.
                            // Es können weitere Adapter hinzugefügt werden.
                            // - Erster Teil (z.B. "mihome"): Hauptdatenpunkt ohne Instanz. Also bei mihome.0 ist das einfach nur "mihome".
                            // - stateMotion: Der Datenpunkt, der eine neue Bewegung erfasst und dann auf true setzt. z.B. [mihome.0.devices.sensor_motion_aq2_123456789abc.state]
                            //                Hier dann nur den Teil nach dem letzten Punkt nehmen, also hier "state"
                            // - stateLux:    Der Datenpunkt, der die Lux (Helligkeit) anzeigt. Kann man weglassen, dann wird Lux nicht berücksichtigt.
                            //                Z.B. [mihome.0.devices.sensor_motion_aq2_123456789abc.lux]. -> Nur den Teil nach dem letzten Punkt nehmen, also hier "lux"
                            const ADAPTER_STATES = {
                                    //mihome: {stateMotion: 'state',     stateLux: 'lux'},
                                    'hm-rpc': {stateMotion: 'MOTION', stateLux: 'ILLUMINATION'},     
                                    //zigbee: {stateMotion: 'occupancy', stateLux: 'illuminance'},
                            };
                            
                            
                            // Logeinträge: Infos zeigen (wenn eingeschaltet oder ausgeschaltet wurde)
                            const INFO = true;
                            
                            // Logeinträge: Zusätzliche Einträge anzeigen zur Fehlerbehebung. Auf "false" setzen, wenn alles funktioniert.
                            const DEBUG = false;
                            
                            
                            /*************************************************************************************************************************
                             * Ab hier nichts mehr ändern / Stop editing here!
                             *************************************************************************************************************************/
                            
                            
                            /****************************************************************************
                             * Global variables and constants
                             ****************************************************************************/
                            let G_Timers = []; // Timer for each motion sensor (sensors as configured above). Key is 'name' of config.
                            let G_WaitTimers = []; // Wait Timers
                            let G_Sensornames = []; // All names of the sensors in this array. For logging...
                            
                            
                            /****************************************************************************
                             * First, we are validating the configuration
                             ****************************************************************************/
                            validate();
                            function validate() {
                            
                                let errorCount = 0;
                            
                                if (DEBUG) log('[DEBUG] ' + 'VALIDIERUNG *** START: Prüfung der Script-Konfiguration ***');
                                for (const LPCONF of MOTION_SENSORS) {
                            
                                    if (isLikeEmpty(LPCONF.name)) {
                                        log('"name" wurde nicht gesetzt in Script-Konfiguration.', 'warn');
                                        errorCount++;
                                    } else {
                                        G_Sensornames.push(LPCONF.name); // For logging
                                    }
                            
                                    /////////////////////////////////////////////////////
                                    // 1. Check if adapters in MOTION_SENSORS are matching with ADAPTER_STATES
                                    // We use sensorState() function to check
                                    /////////////////////////////////////////////////////
                                    let sensorStateArray = [];         // We are allowing multiple sensors for one area.
                                    if (typeof LPCONF.sensorState == 'string') {
                                        sensorStateArray.push(LPCONF.sensorState); // If we just have one sensor as string
                                    }
                                    for (const lpSensorStatePath of sensorStateArray) {
                                        if(sensorState(LPCONF.sensorState, 'stateMotion') == 'ERROR') {
                                            log('Konfiguration von Bewegungsmelder ' + LPCONF.name + ': Adapter/Datenpunkt [' + lpSensorStatePath.split('.')[0] + '] ist NICHT korrekt definiert.', 'warn');
                                            errorCount++;
                                        } else {
                                            if (DEBUG) log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Adapter/Datenpunkt [' + lpSensorStatePath.split('.')[0] + '] ist korrekt konfiguriert.');
                                        }
                                    }
                            
                                    /////////////////////////////////////////////////////
                                    // 2. Prüfung und Umwandlung LPCONF.target
                                    /////////////////////////////////////////////////////
                                    if (typeof LPCONF.target == 'string') {
                                        if( getObject(LPCONF.target).common['type'] != 'boolean') {
                                            log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Einstellung für "target" ist fehlerhaft: Datenpunkt ist nicht vom Typ Boolean (true/false).', 'warn');
                                            errorCount++;
                                        } else {
                                            LPCONF.target = {on:{state:LPCONF.target, cmd:true}, off:{state:LPCONF.target, cmd: false}, checkOnOffStatusState:LPCONF.target};
                                        }
                                    } else {
                                        // We expect an object with at least on.state and on.cmd available
                                        if( isLikeEmpty(LPCONF.target.on.state) || isLikeEmpty(LPCONF.target.on.cmd) ) {
                                            log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Einstellung für "target" ist fehlerhaft - target.on.state und/oder target.on.cmd nicht definiert!', 'warn');
                                            errorCount++;
                                        } else {
                                            // If checkOnOffStatusState is not defined, we ensure that on.state is boolean, so that we can use this state instead.
                                            if( isLikeEmpty(LPCONF.target.checkOnOffStatusState)) {
                                                if ( ! (LPCONF.target.on.cmd == true || LPCONF.target.on.cmd == false) ) {
                                                    log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Einstellung für "target" ist fehlerhaft: target.checkOnOffStatusState ist nicht gesetzt, und target.on.cmd ist nicht Boolean (true/false), daher kann nicht geprüft werden ob Gerät an/aus!', 'warn');
                                                    errorCount++;
                                                } else {
                                                    // checkOnOffStatusState is not defined, but on.state is boolean, so we use this instead.
                                                    LPCONF.target.checkOnOffStatusState = LPCONF.target.on.state;
                                                }
                                            }
                                        }
                                    }
                            
                            
                            
                            
                                    /////////////////////////////////////////////////////
                                    // 3. Some more validation
                                    /////////////////////////////////////////////////////
                                    const LP_PERIOD_KEYS = (Object.keys(LPCONF).filter(str => str.includes('period_'))); // gibt alle Keys mit 'period_' als Array zurück, also z.B. ['period_1','period_2']
                                    if (isLikeEmpty(LP_PERIOD_KEYS)) {
                                        log('Konfiguration von Bewegungsmelder ' + LPCONF.name + 'Es wurden keine Zeiten definiert (period_1, etc.). Bitte Script-Konfiguration überprüfen.', 'warn');
                                        errorCount++;
                                    } else {
                                        for (const LP_PERIOD_KEY of LP_PERIOD_KEYS) {
                                            let lpSecs = LPCONF[LP_PERIOD_KEY].sec;                    
                                            if( (isLikeEmpty(lpSecs) || (lpSecs <= 0)) ) {
                                                if (DEBUG) log('[DEBUG] VALIDIERUNG ' + LPCONF.name + ': In [' + LP_PERIOD_KEY + '] wurden keine Sekunden zum Ausschalten definiert oder auf 0 gesetzt, daher wird nicht automatisch abgeschaltet.');
                                            } 
                                        }
                                    }
                            
                                } //for
                            
                                if (errorCount == 0) {
                                    if (DEBUG) log('[DEBUG] ' + 'VALIDIERUNG *** ENDE: Prüfung der Script-Konfiguration, Ergebnis: keine Fehler ***');
                                    main();
                                } else {
                                    log('Insgesamt ' + errorCount + ' Fehler in der Script-Konfiguration gefunden. Daher wird abgebrochen und das Script nicht weiter ausgeführt.', 'error');
                                }
                            
                            };
                            
                            
                            
                            /****************************************************************************
                             * Main function
                             ****************************************************************************/
                            function main() {
                            
                                if(INFO) log('*** Bewegungsmelder-Script gestartet *** Folgende Bewegungsmelder werden überwacht: ' + G_Sensornames.join(', '));
                            
                                for (const LPCONF of MOTION_SENSORS) {
                            
                                    // Initialize Timers
                                    G_Timers[LPCONF.name] = new myTimer();
                                    G_WaitTimers[LPCONF.name] = new myTimer();
                            
                                    // We are allowing multiple sensors for one area.
                                    let sensorStateArray = [];
                                    if (typeof LPCONF.sensorState == 'string') {
                                        // If we just have one sensor as string
                                        sensorStateArray.push(LPCONF.sensorState);
                                    } else {
                                        sensorStateArray = LPCONF.sensorState;
                                    }
                            
                                    for (const lpSensorState of sensorStateArray) {
                            
                                        on({id: sensorState(lpSensorState, 'stateMotion'), val:true}, function(obj) {
                            
                                            // Need to have statePath within on() function;
                                            let lpSensorStatePath = obj.id.substring(0, obj.id.length - (obj.id.match(/([^.]*$)/)[0].length + 1)); // removes the last part like ".motion"
                            
                            
                                            /////////////////////////////////////////////////////////////////////
                                            ///////////// Wir haben eine Bewegung //////////////////////////
                                            /////////////////////////////////////////////////////////////////////
                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Bewegungsmelder wurde ausgelöst.');
                                            let whyNotOnLog = ''; // for final info log
                                            let doIt = true;  // tells us we we REALLY want to turn device on
                                            let periodHit = ''; // Which period? Need this several times
                                            G_Timers[LPCONF.name].stop(); // just in case: stop timer.
                                            
                            
                                            // Einschalten Prüfung 1: Wait aktiv?
                                            if (doIt) {
                                                if (G_WaitTimers[LPCONF.name].isRunning()) {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #1: Wait-Timer ist noch aktiv für ' + Math.round(G_WaitTimers[LPCONF.name].getTimeLeft()/1000) + ' Sekunden, also schalten wir nicht und brechen hier ab.');
                                                    whyNotOnLog = 'Wait ist noch aktiv für ' + Math.round(G_WaitTimers[LPCONF.name].getTimeLeft()/1000) + ' Sekunden';
                                                    doIt = false;
                                                } else {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #1: Wait-Timer ist nicht aktiv.');
                                                };
                                            };
                            
                                            // Einschalten Prüfung 2: Soll lt. definierten Datenpunkt in MOTION_SENSORS, neverState_XXX nicht geschaltet werden.
                                            if (doIt) {
                                                const lpNeverStateKeys = (Object.keys(LPCONF).filter(str => str.includes('neverState_'))); // gibt alle Keys mit 'neverState_' als Array zurück, also z.B. ['neverState_1','neverState_2']. Oder leeres Array [] falls nichts vorhanden
                                                if(isLikeEmpty(lpNeverStateKeys)) {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Keine Datenpunkte definiert, die geprüft werden, ob NICHT geschaltet werden soll.');
                                                } else {
                                                    for (const lpNeverStateKey of lpNeverStateKeys) {
                                                        let lpStateId = LPCONF[lpNeverStateKey].state;
                                                        let lpStateVal = LPCONF[lpNeverStateKey].val;
                                                        let validationPassed = false;
                            
                                                        // 1. Validierung
                                                        if( isLikeEmpty(lpStateId) || lpStateVal == undefined ) { // check lpStateVal for undefined only, since it could have like an empty string.
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Keine korrekte Konfiguration in ' + lpNeverStateKey);
                                                        } else if( ($(lpStateId).length < 1) || (!existsState(lpStateId)) ) { // Workaround due to https://github.com/ioBroker/ioBroker.javascript/issues/478
                                                            log('Bewegungsmelder ' + LPCONF.name + ': In ' + lpNeverStateKey + ' angegebener Datenpunkt "' + lpStateId + '" wurde nicht gefunden.', 'warn');
                                                            // Wir machen aber trotzdem weiter, also lassen doIt auf true.
                                                        } else {
                                                            validationPassed = true;
                                                        }
                            
                                                        // 2. Prüfung Datenpunkt
                                                        if (validationPassed) {
                                                            let stateValToCheck = getState(lpStateId).val;
                                                            if (stateValToCheck == lpStateVal) {
                                                                // Treffer -- wir schalten NICHT
                                                                if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Datenpunkt-Inhalt zum nicht schalten (' + lpStateId + ') stimmt mit Script-Einstellung überein, Inhalt: [' + lpStateVal + ']. Also NICHT schalten.');
                                                                whyNotOnLog = 'Datenpunkt  (' + lpStateId + ') stimmt mit Script-Einstellung überein, Inhalt: [' + lpStateVal + '].';
                                                                doIt = false;
                                                                break; // Exit loop since we have a hit                                
                                                            } else {
                                                                if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Datenpunkt-Inhalt zum nicht schalten (' + lpStateId + ') stimmt NICHT mit Script-Einstellung überein; Script-Vorgabe: [' + lpStateVal + '], Datenpunkt-Inhalt: [' + stateValToCheck + ']. Also machen wir weiter.');
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                            
                                            // Einschalten Prüfung 3: Ist aktuelle Zeit im Zeitraum "Nie schalten". Wird nur angewendet, falls neverPeriod_xxx vorhanden.
                                            if (doIt) {
                                                const lpNeverKeys = (Object.keys(LPCONF).filter(str => str.includes('neverPeriod_'))); // gibt alle Keys mit 'neverPeriod_' als Array zurück, also z.B. ['neverPeriod_1','neverPeriod_2']. Oder leeres Array [] falls nichts vorhanden
                                                if(isLikeEmpty(lpNeverKeys)) {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #3: Keine Zeiträume für "Nie schalten" definiert.');
                                                } else {
                                                    for (const lpNeverKey of lpNeverKeys) {
                                                        // Die Funktion prüft alles für uns.
                                                        let match = currentTimeMatchesPeriod(LPCONF[lpNeverKey], LPCONF.name + ': Check #3 (' + lpNeverKey + ')');
                                                        if (match) {
                                                            // Treffer, also nicht schalten.
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #3: Zeitraum (' + lpNeverKey + ') ist in Bereich "Nie schalten", also schalten wir nicht.');
                                                            whyNotOnLog = 'Zeitraum  (' + lpNeverKey + ') ist in Bereich "Nie schalten"';
                                                            doIt = false;
                                                            break; // Exit loop since we have a hit
                                                        }
                                                    }
                                                }
                                            }
                            
                                            // Einschalten Prüfung 4: Nur zu definierten Zeiten. 
                                            if (doIt) {
                                                const lpPeriodKeys = (Object.keys(LPCONF).filter(str => str.includes('period_'))); // gibt alle Keys mit 'period_' als Array zurück, also z.B. ['period_1','period_2']
                                                if (isLikeEmpty(lpPeriodKeys)) {
                                                    log('Im Script wurden keine Zeiten definiert (period_1, etc.). Bitte Script-Konfiguration überprüfen.', 'error');
                                                    whyNotOnLog = 'Keine Zeiten im Script (period_xxx) definiert';
                                                    doIt = false;
                                                } else {
                                                    let isInRange = false;
                                                    for (const lpPeriodKey of lpPeriodKeys) {
                                                        // Die Funktion prüft alles für uns.
                                                        let match = currentTimeMatchesPeriod(LPCONF[lpPeriodKey], LPCONF.name + ': Check #4 (' + lpPeriodKey + ')');
                                                        if (match) {
                                                            // Treffer, also schalten.
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #4: Treffer - aktuelle Uhrzeit ist innerhalb Zeitraum (' + lpPeriodKey + ').' );
                                                            isInRange = true;
                                                            periodHit = lpPeriodKey; // Gefundene Zeitperiode ('period_') in globale Variable. Brauchen wir für Prüfung Lichtstärke, und auch beim Ausschalten (um die jew. gesetzten Lux zu bekommen)
                                                            break; // Exit loop since we have a hit                            
                                                        }
                                                    }
                                                    if (!isInRange) {
                                                        if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #4: Aktuelle Uhrzeit fällt in keine der definierten Zeitperioden.' );
                                                        whyNotOnLog = 'Aktuelle Uhrzeit fällt in keine der definierten Zeitperioden.';
                                                        doIt = false;
                                                    }
                                                }
                                            }
                            
                                            // Einschalten Prüfung 5: Lichtstärke
                                            if (doIt) {
                                                if (! isLikeEmpty(LPCONF[periodHit].lux )) {
                                                    if( (LPCONF[periodHit].lux < 10000) && (LPCONF[periodHit].lux > -1))  {
                                                        if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Prüfung auf Lux ist aktiviert.')
                                                        // Prüfung: luxAlways
                                                        let luxAlways = false;
                                                        if( !isLikeEmpty(LPCONF[periodHit].luxAlways) && LPCONF[periodHit].luxAlways == true ) {
                                                            luxAlways = true;
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "luxAlways" ist aktiviert, daher schalten wir immer auch auf Basis der Lux des Bewegungsmelders, auch wenn das Gerät (z.B. Licht) bereits an ist."')
                                                        }
                                                        if (getState(LPCONF.target.checkOnOffStatusState).val == true && luxAlways == false) {
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Gerät ist aber bereits an, also wird Prüfung auf Lux jetzt deaktiviert (da durch das Licht die Lux-Prüfung verfälscht wird).')
                                                        } else {
                                                            // Prüfung: gemessene Lux kleiner Schwellwert, bis zu dem geschalten werden soll?
                                                            let luxSensorState = getState(sensorState(lpSensorStatePath, 'stateLux')).val;
                                                            if (luxSensorState >= LPCONF[periodHit].lux) {
                                                                if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Gemessene Lux = ' + luxSensorState + ', >= Schwelle von ' + LPCONF[periodHit].lux + ', daher wird nicht geschaltet.');
                                                                whyNotOnLog = 'Gemessene Lux = ' + luxSensorState + ', >= Schwelle von ' + LPCONF[periodHit].lux;
                                                                doIt = false;
                                                            } else {
                                                                if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Gemessene Lux = ' + luxSensorState + ', < Schwelle von ' + LPCONF[periodHit].lux + ', daher eingeschaltet.')
                                                            }
                                                        }
                                                    } else {
                                                        if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Prüfung auf Lux ist deaktiviert.')
                                                    }
                                                } else {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Prüfung auf Lux ist deaktiviert.')
                                                }
                                            }
                            
                                            // Einschalten: All checks processed.
                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Alle Einschalt-Prüfungen durchgeführt, Ergebnis: ' + ((doIt) ? 'JA - einschalten' : 'NEIN - nicht einschalten'));
                                            if (doIt) {
                            
                                                ////////////////////////////////
                                                // Jetzt einschalten
                                                ////////////////////////////////
                            
                                                // Prüfung ob bereits eingeschaltet.
                                                let isOnAlready = false;
                                                if (!isLikeEmpty(LPCONF.target.checkOnOffStatusState)) {
                                                    if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Datenpunkt für Prüfung, ob Gerät bereits angeschaltet ist, ist vorhanden: ' + LPCONF.target.checkOnOffStatusState)
                                                    if ( getState(LPCONF.target.checkOnOffStatusState).val ) {
                                                        // Device is already turned on
                                                        if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Gerät ist bereits angeschaltet, also schalten wir nicht noch mal.');
                                                        isOnAlready = true;
                                                    } else {
                                                        if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Gerät ist nicht eingeschaltet, also schalten wir es ein.')
                                                    }
                                                } else {
                                                    if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Kein Datenpunkt für Prüfung, ob Gerät bereits angeschaltet ist, definiert. Also wird auf jeden Fall geschaltet.')
                                                }
                                                // JETZT SCHALTEN.
                                                if(DEBUG && G_WaitTimers[LPCONF.name].isRunning()) log('[DEBUG] ' + LPCONF.name + ': "wait" ist aktiv, läuft noch ' + Math.round(G_WaitTimers[LPCONF.name].getTimeLeft()/1000) + ' Sekunden.');
                                                // nur falls: 1.) Nicht bereits an und 2.) Kein wait aktiv                    
                                                if(doIt && !isOnAlready && !G_WaitTimers[LPCONF.name].isRunning()) {
                                                    setState(LPCONF.target.on.state, LPCONF.target.on.cmd);
                                                    if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Ausgelöst und alle Kriterien erfüllt, daher wird eingeschaltet.');
                                                }
                            
                                                //////////////////////////
                                                // Falls "wait" aktiviert: Timer prüfen / setzen für nächste Bewegungen
                                                //////////////////////////
                                                if( (isLikeEmpty(LPCONF[periodHit].sec) || (LPCONF[periodHit].sec == 0)) ) {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Wait-Timer wird nicht gesetzt, da keine Ausschaltsekunden definiert.');
                                                } else {
                                                    if ( isLikeEmpty(LPCONF.wait) || LPCONF.wait < LPCONF[periodHit].sec ) {
                                                        if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "wait" ist nicht gesetzt oder kleiner als definierte Ausschaltsekunden von ' + LPCONF[periodHit].sec + 's, daher wird "wait" nicht weiter betrachtet.')
                                                    } else {
                                                        if ( !G_WaitTimers[LPCONF.name].isRunning() ) {
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "Wait"-Timer läuft nicht. Also starten wir den Timer: ' + LPCONF.wait + ' Sekunden. Damit wird erst wieder nach dieser Zeit erneut eingeschaltet.');
                                                                // Timer-Start
                                                                G_WaitTimers[LPCONF.name].start(function() {
                                                                    G_WaitTimers[LPCONF.name].stop(); // just in case
                                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "wait" von ' + LPCONF.wait + ' Sekunden seit letzter Einschaltung ist abgelaufen, daher wird "wait" wieder deaktiviert.');
                                                                }, LPCONF.wait * 1000);
                                                        } else {
                                                            if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "Wait"-Timer ist noch aktiv und läuft noch ' + G_WaitTimers[LPCONF.name].getTimeLeft() + ' Sekunden. ');
                                                        }
                                                    }
                                                }
                            
                                                ////////////////////////////////
                                                // Nun der Timer zum Ausschalten
                                                ////////////////////////////////
                                                // Timer-Prüfung: Falls sec=0 oder sec nicht definiert, dann soll nicht per diesem Script ausgeschaltet werden.
                                                if( (isLikeEmpty(LPCONF[periodHit].sec) || (LPCONF[periodHit].sec <= 0)) ) {
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Keine Sekunden zum Ausschalten definiert oder Ausschalten deaktiviert (lt. [' + periodHit + '] in Konfiguration). Daher setzen wir keinen Timer zum ausschalten.')
                                                } else {
                                                    // Jetzt wird der Timer gesetzt.
                                                    if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Wir setzen einen Timer von ' + LPCONF[periodHit].sec + ' Sekunden zum Ausschalten (lt. [' + periodHit + '] in Konfiguration).')
                                                    
                                                    G_Timers[LPCONF.name].start(function() {
                                                        /////////////////////////////////////////
                                                        // Timer ist abgelaufen (wir sind im Callback von setTimeout())
                                                        /////////////////////////////////////////
                                                        G_Timers[LPCONF.name].stop();
                                                        if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Timer (' + LPCONF[periodHit].sec + ' Sekunden) ist abgelaufen (lt. [' + periodHit + '] in Konfiguration).');
                            
                            
                                                        // Jetzt ausschalten
                                                        let whyNotOffLog = ''; // for final info log
                                                        let turnOff = true;
                                                        if (!isLikeEmpty(LPCONF.target.checkOnOffStatusState)) {
                                                            if (DEBUG) log('[DEBUG] TurnOff Check 1: ' + LPCONF.name + ': Datenpunkt für Prüfung, ob Gerät bereits ausgeschaltet ist, ist vorhanden: ' + LPCONF.target.checkOnOffStatusState)
                                                            if (! getState(LPCONF.target.checkOnOffStatusState).val ) {
                                                                if (DEBUG) log('[DEBUG] TurnOff Check 2: ' + LPCONF.name + ': Gerät ist bereits ausgeschaltet, also machen wir nichts weiter.')
                                                                whyNotOffLog = 'Gerät ist bereits ausgeschaltet';
                                                                turnOff = false;
                                                            } else {
                                                                if (DEBUG) log('[DEBUG] TurnOff Check 2: ' + LPCONF.name + ': Gerät ist eingeschaltet, also schalten wir aus.')
                                                            }
                                                        } else {
                                                            if (DEBUG) log('[DEBUG] TurnOff Check #2 - ' + LPCONF.name + ': Kein Datenpunkt für Prüfung, ob Gerät bereits ausgeschaltet ist, definiert. Also wird auf jeden Fall ausgeschaltet.')
                                                        }
                                                        // Ausschalten: All checks processed.
                                                        if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Alle Ausschalt-Prüfungen durchgeführt. Ergebnis (ob ausgeschaltet werden soll): ' + turnOff);
                                                        if (turnOff) {
                                                            //////////// FINALLY, WE TURN DEVICE OFF //////////////////
                                                            if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Timer (' + LPCONF[periodHit].sec + 's) abgelaufen und alle Kriterien erfüllt, daher wird ausgeschaltet.');
                                                            setState(LPCONF.target.off.state, LPCONF.target.off.cmd);               
                                                        } else {
                                                            if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Timer (' + LPCONF[periodHit].sec + 's) abgelaufen, aber es wird nicht geschaltet, Grund: ' + whyNotOffLog);
                                                        }
                                                    }, (LPCONF[periodHit].sec) * 1000);
                                                }
                                            
                                            } else {
                                                if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Ausgelöst, aber es wird nicht geschaltet, Grund: ' + whyNotOnLog);
                                            }
                            
                                        }); // on() auf stateMotion - true
                                    } // for loop: sensorStatesArray
                                } // for (const LPCONF of MOTION_SENSORS)
                            }
                            
                            
                            /**
                             * Returns the full state for a given motion sensor state
                             * @param {string} sensorState     sensor state, like "mihome.0.devices.sensor_motion_aq2_1234567abcde"
                             * @param {string} stateNameToAdd  state name you want to add per ADAPTER_STATES, like "stateLux"
                             * @return {string}    The according state name of the adapter, like: mihome.0.devices.sensor_motion_aq2_1234567abcde.lux
                             */
                            function sensorState(sensorState, stateNameToAdd) {
                                if (!sensorState.endsWith('.')) sensorState = sensorState + '.'; // add "." at the end, if it is not there
                                const adapterName = sensorState.split('.')[0]; // like: mihome, zigbee, etc.
                                let result = '';
                                let isError = true;
                                if (! isLikeEmpty(adapterName) && (ADAPTER_STATES[adapterName] != undefined)) {
                                    if (stateNameToAdd in ADAPTER_STATES[adapterName]) {
                                        result = ADAPTER_STATES[adapterName][stateNameToAdd];
                                        if(! isLikeEmpty(result)) {
                                            isError = false;
                                        }
                                    }
                                }
                                if(isError) {
                                    log('Catched Script Error in function sensorState(): Could not get adapter state name "' + stateNameToAdd + '" for [' + sensorState + '].', 'error');
                                    return 'ERROR';
                                } else {
                                    return sensorState + result;
                                }
                            }
                            
                            /**
                             * Better timer function
                             * Features: Find out time remaining, stop timer easily, check status (running yes/no).
                             * Autor:               Mic (ioBroker) | Mic-M (github)
                             * Version:             0.1 (14 March 2020)
                             * Source:              https://stackoverflow.com/questions/3144711/
                             * -----------------------------------------------
                             * Make a timer:
                                  let a = new myTimer();
                                  a.start(function() {
                                   // Do what ever
                                  }, 5000);
                             * Time remaining:      a.getTimeLeft()
                             * Stop (clear) timer:  a.stop()
                             * Is timer running:    a.isRunning()
                             * -----------------------------------------------
                             */
                            function myTimer() {
                                let fcallback;
                                let id;
                                let started;
                                let remaining = 0;
                                let running = false;
                            
                                this.start = function(callback, delay) {
                                    fcallback = callback;
                                    remaining = delay;
                                    clearTimeout(id);
                                    id = null;
                                    running = true;
                                    started = Date.now();
                                    id = setTimeout(fcallback, remaining);
                                }
                            
                                this.pause = function() {
                                    running = false;
                                    clearTimeout(id);
                                    remaining -= Date.now() - started;
                                }
                            
                                this.stop = function() {
                                    running = false;
                                    clearTimeout(id); id = null;
                                    remaining = 0;
                                }
                            
                                this.getTimeLeft = function() {
                                    if (running) {
                                        this.pause();
                                        this.start(fcallback, remaining);
                                        return remaining;
                                    } else {
                                        return 0;
                                    }
                                }
                            
                                this.isRunning = function() {
                                    return running;
                                }
                            
                            }
                            
                            
                            /***************************************************************
                             * Checks if provided period as object, like {start:'7:00', end:'23:00', days:'2-4, 6'} is matching with current date/time.
                             * start and end: See https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#comparetime
                             *                Astro is allowed as well, so like start:'sunsetStart' or with an offset like end:{astro: 'sunrise', offset: -30}
                             * days:          Monday = 1, Tuesday = 2, ... Sunday = 7. You can separate days with comma, so like '1, 3, 5' for Mon/Wed/Fri,
                             *                and you can use period like '2-4' for Tue/Wed/Thu, and you can combine both, so like '2-4, 7' for Tue/Wed/Thu/Sun.
                             * @param  {string} info   Any info (like device name), just for the logging.
                             * @return {boolean}   true, if current date/time within period, false if not.
                             ***************************************************************/
                            function currentTimeMatchesPeriod(objectPeriod, info) {
                            
                                let fStart = objectPeriod.start;
                                let fEnd = objectPeriod.end;
                                let fDays = objectPeriod.days;
                            
                                // Part 1: Check week days
                                if (fDays == undefined) {
                                    if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Keine Wochentage definiert, also gilt jeder Tag.');
                                    // We continue: If no days defined in object, we consider this as no day limit and allow every day
                                } else {
                                    if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Zu schaltende Wochentage definiert: ' + fDays);
                                    if (isCurrentDayInRange(fDays)) {
                                        if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Aktueller Wochentag ist innerhalb definierter Tage.');
                                        // We continue
                                    } else {
                                        if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Aktueller Wochentag ist NICHT innerhalb definierter Tage.');
                                        // We leave function with false
                                        return false;
                                    }
                                }
                            
                                // Part 2: Check time
                                let logPeriod = ((typeof fStart == 'string') ? fStart : JSON.stringify(fStart)) + ' - ' + ((typeof fEnd == 'string') ? fEnd : JSON.stringify(fEnd));
                                if (withinRange(fStart, fEnd)) {
                                    if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Treffer: aktuelle Uhrzeit ist innerhalb Zeitraum (' + logPeriod + ').' );
                                    return true;
                                } else {
                                    if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Aktuelle Uhrzeit ist NICHT innerhalb Zeitraum (' + logPeriod + ').' );
                                    return false;
                                }
                            
                            
                                /*************************************************************************
                                 * Helper functions following below
                                 *************************************************************************/
                            
                                /**
                                 * Checks if given string of ranges is matching with current day
                                 * Numbers 1-7 allowed (stand for weekdays).
                                 * @param {string} inputRanges   String, like: '5,6', '1-3, 6, 7', '3'
                                 * @return {boolean} true if matches, false if not
                                 */
                                function isCurrentDayInRange(inputRanges) {
                                
                                    // Get current weekday. Monday = 1, Tuesday = 2, ... Sunday = 7.
                                    let dateNow = new Date();
                                    let currWeekday = (dateNow.getDay());
                                    if (currWeekday == 0) currWeekday = 7; // Sunday should be 7, not 0.
                            
                                    let resArray = getSingleDaysFromRanges(inputRanges);
                            
                                    if (resArray.indexOf(currWeekday) != -1) {
                                        return true;
                                    } else {
                                        return false;
                                    }
                                }
                            
                                /**
                                 * Convert given string of ranges to array.
                                 * Numbers 1-7 allowed (stand for weekdays).
                                 * @param {string} inputRanges   String, like: '5,6', '1-3, 6, 7', '3'
                                 * @return {array} Array with each individual number, so '2-4, 7' will return [2,3,4,7]. Returns empty array [] if no matches
                                 */
                                function getSingleDaysFromRanges(inputRanges) {
                                    let resultArray = [];
                                    if(!isLikeEmpty(inputRanges)) {
                                        inputRanges = inputRanges.replace(/[^1-7.,-]+/g,'') // just keep numbers 1-7, ",", ".", "-"
                                        let inputArray = inputRanges.split(',');
                                        for (const lpVal of inputArray) {
                                            let matchResultPeriod = lpVal.match(/(\d)(-)(\d)/); // matches like 2-4
                                            let matchResultSingle = lpVal.match(/^\d$/g); // matches single number like 2
                                            if (matchResultPeriod != null) {
                                                // Wir haben eine Angabe wie 2-4 - match gibt zurück: ['2-4','2','-','4']
                                                for (let i = parseInt(matchResultPeriod[1]); i <= parseInt(matchResultPeriod[3]); i++) {
                                                    resultArray.push(i);
                                                }        
                                            } else if (matchResultSingle != null) {
                                                resultArray.push(parseInt(matchResultSingle[0]));
                                            }
                                        }
                                    }    
                                    return resultArray;
                                }
                            
                            
                                /**
                                 * Checks if time is within range using compareTime()
                                 */
                                function withinRange(startTime, endTime) {
                                    let result = false;
                                    if (! isLikeEmpty(startTime) && ! isLikeEmpty(startTime)) {
                                        if (compareTime(startTime, endTime, 'between')) {
                                            result = true;
                                        }
                                    }
                                    return result;
                                }
                            
                            }
                            
                            /**
                             * Clear timeouts once script is stopped.
                             */
                            onStop(function (callback) {
                                let counter = 0;
                                for (const LPCONF of MOTION_SENSORS) {
                                    if (G_Timers[LPCONF.name].isRunning()) {
                                        G_Timers[LPCONF.name].stop();
                                        if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] ' + LPCONF.name + ': Ausschalt-Timer deaktiviert.');
                                        counter++;
                                    }
                                    if (G_WaitTimers[LPCONF.name].isRunning()) {
                                        G_WaitTimers[LPCONF.name].stop();
                                        if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] ' + LPCONF.name + ': Wait-Timer deaktiviert.');            
                                        counter++;
                                    }
                                }
                                if (counter > 0) {
                                    if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] Script sauber gestoppt, es wurden ' + counter + ' Timer deaktiviert.');
                                } else {
                                    if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] Script sauber gestoppt, es gab keine aktivierten Timer.');
                                }
                            
                                callback();
                            }, 500);
                            
                            
                            
                            /**
                             * Checks if Array or String is not undefined, null or empty.
                             * 08-Sep-2019: added check for [ and ] to also catch arrays with empty strings.
                             * @param inputVar - Input Array or String, Number, etc.
                             * @return true if it is undefined/null/empty, false if it contains value(s)
                             * Array or String containing just whitespaces or >'< or >"< or >[< or >]< is considered empty
                             */
                            function isLikeEmpty(inputVar) {
                                if (typeof inputVar !== 'undefined' && inputVar !== null) {
                                    let strTemp = JSON.stringify(inputVar);
                                    strTemp = strTemp.replace(/\s+/g, ''); // remove all whitespaces
                                    strTemp = strTemp.replace(/\"+/g, "");  // remove all >"<
                                    strTemp = strTemp.replace(/\'+/g, "");  // remove all >'<
                                    strTemp = strTemp.replace(/\[+/g, "");  // remove all >[<
                                    strTemp = strTemp.replace(/\]+/g, "");  // remove all >]<
                                    if (strTemp !== '') {
                                        return false;
                                    } else {
                                        return true;
                                    }
                                } else {
                                    return true;
                                }
                            }
                            
                            

                            Gruß
                            Martin


                            Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                            Raspeberry mit USB Leseköpfen für Smartmeter
                            Homematic und Homematic IP

                            MicM 1 Antwort Letzte Antwort
                            0
                            • M MartyBr

                              @Mic
                              Hallo, ich habe dein Script installiert und zum testen zwei Bewegungsmelder im Wohnzimmer verbunden. Sie schalten zum Test eine Tischleuchte.
                              Bis dahin alles gut. Ich habe nur das Problem, dass das Script nun auch die Lampe ausschaltet, die ich vorher eingeschaltet habe. Das Script merkt also nicht das die Lampe schon eingeschaltet war.

                              Wie kann ich das verhalten verhindern?

                              P.S.
                              Ich setze vorrangig HM Komponenten ein, das funktioniert auch alles.

                              Hier das Script:

                              /*******************************************************************************
                               * Bewegungsmelder-Script: Schaltung Lichter/Geräte mittels Bewegungsmelder.
                               * ----------------------------------------------------
                               * In das Script lassen sich beliebig viele Xiaomi Aqara Bewegungsmelder einbinden. Getestet mit Adapter mihome und zigbee.
                               * Sicherlich lassen sich auch Bewegungsmelder anderer Hersteller einbinden, siehe hierzu ADAPTER_STATES unten.
                               * Hiweis: Es werden keinerlei Datenpunkte angelegt, da wir diese nicht benötigen.
                               * ----------------------------------------------------
                               * Autor: ioBroker-Forum-Name: Mic / Github-Name: Mic-M
                               * Source:  https://github.com/Mic-M/iobroker.xiaomi-aquara-motion-control
                               * Support: https://forum.iobroker.net/topic/22034/
                               * ----------------------------------------------------
                               * Change Log:
                               *  2.0 Mic - Complete recoding. Also, addition of several options, etc.
                               *  0.4 Mic - Allow using Zigbee adapter and others as well.
                               *  0.3 Mic - few code improvements
                               *  0.2 Mic - Fix: Compare Time
                               *  0.1 Mic - Initial Release
                               ******************************************************************************/
                              
                              
                              
                              /*******************************************************************************
                               * Konfiguration
                               ******************************************************************************/
                              
                              /////////////////////
                              // Hier die einzelnen Bewegungssensoren anlegen und einstellen.
                              // Im ersten Beispiel ist alles im Detail beschrieben.
                              /////////////////////
                              const MOTION_SENSORS = [
                              /*
                              {
                                  // Beliebiger Name (für Log-Ausgabe). Bitte individuell vergeben.
                              name:                   'Gästezimmer',
                              
                                  // Haupt-Datenpunkt des Bewegungsmelders, z.B. "mihome.0.devices.sensor_motion_aq2_1234567abcde" oder "zigbee.0.00123456789415"
                                  // Es werden auch mehrere Sensoren unterstützt, d.h. etwa 3 Bewegungsmelder im Flur.
                              sensorState:            'mihome.0.devices.sensor_motion_aq2_11111111111111',
                              //    sensorState:            ['mihome.0.devices.sensor_motion_aq2_XXXXXXXXXXX', 'zigbee.0.XXXXXXXXXXXXX', 'zigbee.0.YYYYYYYYYYYYYYYYYYYYY'],
                              
                                  // Hier beliebig viele Schaltzeitpunkte hinzufügen (period_1, period_2, period_3, usw.)
                                  //  - "start" und "end": Erforderlich. Es wird geprüft, ob start/end innerhalb aktueller Uhrzeit ist, wenn Bewegungsmelder auslöst.
                                  //                       Astro-Zeitangaben sind erlaubt, also etwa 'sunrise' oder mit einem Offset wie {astro: 'sunrise', offset: -30}
                                  //                       Details zu start/end und Astro-Zeitangaben: https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#comparetime
                                  // - "days":             OPTIONAL: Wenn weggelassen, wird jeden Tag geschaltet (Montag-Sonntag). 
                                  //                       Montag = 1, Dienstag = 2, ... Sonntag = 7. 
                                  //                       Mehrere Tage mit Komma trennen, z.B. '1, 3, 5' für Montag/Mittwoch/Freitag.
                                  //                       Periodische Angaben wie '2-4' für Dienstag/Mittwoch/Donnerstag sind auch möglich.
                                  //                       Ebenso Kombination einzelner Tage und Periode möglich, z.B. '2-4, 7' für Dienstag/Mittwoch/Donnerstag und Sonntag.
                                  // - "sec":              OPTIONAL: Nach wie vielen Sekunden soll wieder ausgeschalten werden? Falls weggelassen oder 0, dann wird nicht ausgeschaltet.
                                  // - "lux"               OPTIONAL: Ab wieviel Lux soll NICHT eingeschaltet werden? Falls weggelassen oder größer 9999, dann wird unababhängig von den gemessenen Lux immer eingeschaltet.
                                  // - "luxAlways"         OPTIONAL: Wir gehen davon aus, dass Lampen geschaltet werden. Ist eine Lampe an, wird ein größerer Lux-Wert vom Sensor gemessen, daher macht die Prüfung auf Lux bei  
                                  //                                 bereits eingeschalteter Lampe auf erneute Bewegung und Lux-Abfrage keinen Sinn mehr. Daher wird durch dieses Script bei Bewegung
                                  //                                 -- während das Gerät (die Lampe) an ist -- die Lux-Erkennung hier deaktiviert. Zum dauerhaften aktivieren auf "true" setzen, damit wird immer auf Lux geprüft, 
                                  //                                 auch wenn das Gerät an ist.
                              period_1:               {start:'sunsetStart', end:'21:30', days:'2-4, 7',   sec:120,     lux:90,    luxAlways:false},
                              
                                  // Hier den Datenpunkt des Gerätes angeben, das geschaltet werden soll bei Bewegung an und wieder aus.
                                  // Falls als String gesetzt, z.B. 'javascript.0.Licht.Schlafzimmer.Switch', muss Datenpunkt muss von Typ "Boolean" (true/false) sein.
                                  //
                                  // Es sind noch deutlich mehr Optionen möglich, hierzu muss als Objekt gesetzt werden: {on:{state:'fullybrowser.0.X_X_X_X.Commands.screenOn', cmd:true}, off:{state:'fullybrowser.X_X_X_X.Commands.screenOff', cmd: true}, checkOnOffStatusState:'fullybrowser.X_X_X_X.Info.isScreenOn'}
                                  // Dadurch ist folgendes möglich:
                                  // 1. Individuellen State für An/Aus setzen, Beispiel: {on:{state:'javascript.0.Wohnzimmer.Licht.Szene', cmd:'Entspannen'}, off:{state:'shelly.0.XXXXXXXXXX.Relay0.Switch', cmd: false}, checkOnOffStatusState:'shelly.0.XXXXXXXXXX.Relay0.Switch'}
                                  // 2. Ausschalten deaktivieren (es wird also nur eingeschaltet): Einfach den Teil "off:{state:'fullybrowser.X_X_X_X.Commands.screenOff', cmd: true}," rauslöschen.
                                  // 3. Individuellen State zur Erkennung, ob Gerät an oder aus ist setzen: checkOnOffStatusState:'fullybrowser.X_X_X_X.Info.isScreenOn'. Dies ist notwenig, wenn "on:{state" nicht Boolean (true/false) ist.
                                  //target:                 {on:{state:'hue.0.R_Schlafzimmer.on', cmd:true}, off:{state:'hue.0.R_Schlafzimmer.on', cmd: false}, checkOnOffStatusState:'hue.0.R_Schlafzimmer.on'},
                              target:                 'hue.0.R_Gästezimmer.on',
                              
                                  // Optional: In manchen Fällen will man ggf. mit dem Bewegungsmelder nur einmalig einschalten. Dann soll der Bewegungsmelder x Sekunden (z.B. 10 Minuten = 600s) nicht mehr neu auslösen.
                                  //           Dazu hier den Wert in Sekunden entsprechend setzen. Durch weglassen oder wait:0 wird das ignoriert. 
                              wait:                0,
                              
                                  // Optional: Nicht schalten: Wenn einer der folgenden Datenpunkte mit dem Wert übereinstimmt, wird nicht geschaltet.
                                  //           Hilfreich, um z.B. nicht zu schalten, wenn keiner anwesend ist, oder etwa ein Fenster offen ist, etc.
                                  //           Es können beliebig viele States hinzugefügt werden (neverState_1, neverState_2, neverState_3 usw.)
                              neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                              }, 
                              */  
                                 
                                 //
                                 // Hier nun weitere Beispiele, ohne weiterer Erläuterung (da oben bereits beschrieben).
                                
                                {
                                  name:                   'Wohnzimmer',
                                  sensorState:            ['hm-rpc.2.000918A9xxxx.1', 'hm-rpc.2.000918A98yyyy.1'], // wir überwachen hier 2 Bewegungsmelder gleichzeitig
                                  period_1:               {start:'00:00', end:'07:00',    sec:240},
                                  period_2:               {start:'22:00', end:'23:59',    sec:240},
                                  neverState_1:           {state:'hm-rega.0.950', val:false}, // Anwesenheit CCU
                                  target:                'hm-rpc.1.OEQ0zzzz3.1.STATE',
                                }, 
                              /*  
                                {
                                  name:                   'Küche',
                                  sensorState:            'mihome.0.devices.sensor_motion_aq2_xxxxxxxxxxxx',
                                  period_1:               {start:'7:00', end:'23:00',    sec:120, lux:10 },
                                  neverPeriod_1:          {start:'goldenHourEnd', end:'goldenHour', days:'1-7'},
                                  neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                                  target:                 'shelly.0.SHSW-1#XXXXX#1.Relay0.Switch',
                                  wait:                   300,
                                }, 
                                {
                                  name:                   'Bad',
                                  sensorState:            'zigbee.0.xxxxxxxxxxxx',
                                  period_1:               {start:'6:00', end:'09:00',    sec:240, lux:150 },
                                  period_2:               {start:'9:00', end:'23:00',    sec:120, lux:150 },
                                  neverPeriod_1:          {start:'12:00', end:{astro:'goldenHour', offset: -30} },
                                  neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                                  target:                 'shelly.0.SHSW-1#XXXXX#1.Relay0.Switch',
                                }, 
                              
                                {
                                  name:                   'Tablet',
                                  sensorState:            'zigbee.0.xxxxxxxxxxxxxx',
                                  period_1:               {start:'7:00', end:'23:00',  days:'1-4',  sec:600 },
                                  period_2:               {start:'7:00', end:'24:00',  days:'5',  sec:600 },
                                  period_3:               {start:'0:00', end:'02:00',  days:'6',  sec:600 },
                                  period_4:               {start:'7:00', end:'24:00',  days:'6',  sec:600 },
                                  period_5:               {start:'0:00', end:'02:00',  days:'7',  sec:600 },
                                  period_6:               {start:'7:00', end:'23:00',  days:'7',  sec:600 },
                                  neverState_1:           {state:'0_userdata.0.Anwesenheit.Status.anyonePresent', val:false},
                                  target:                 {on:{state:'fullybrowser.0.10_10_0_129.Commands.screenOn', cmd:true}, off:{state:'fullybrowser.0.10_10_0_129.Commands.screenOff', cmd: true}, checkOnOffStatusState:'fullybrowser.0.10_10_0_129.Info.isScreenOn'},
                                }, 
                              */
                              ];
                              
                              
                              /*******************************************************************************
                               * Optionale weitere Einstellungen
                               ******************************************************************************/
                              
                              // Die Datenpunkte der einzelnen Adapter (mihome, zigbee, etc.) unterscheiden sich, daher definieren wir diese hier.
                              // Es können weitere Adapter hinzugefügt werden.
                              // - Erster Teil (z.B. "mihome"): Hauptdatenpunkt ohne Instanz. Also bei mihome.0 ist das einfach nur "mihome".
                              // - stateMotion: Der Datenpunkt, der eine neue Bewegung erfasst und dann auf true setzt. z.B. [mihome.0.devices.sensor_motion_aq2_123456789abc.state]
                              //                Hier dann nur den Teil nach dem letzten Punkt nehmen, also hier "state"
                              // - stateLux:    Der Datenpunkt, der die Lux (Helligkeit) anzeigt. Kann man weglassen, dann wird Lux nicht berücksichtigt.
                              //                Z.B. [mihome.0.devices.sensor_motion_aq2_123456789abc.lux]. -> Nur den Teil nach dem letzten Punkt nehmen, also hier "lux"
                              const ADAPTER_STATES = {
                                      //mihome: {stateMotion: 'state',     stateLux: 'lux'},
                                      'hm-rpc': {stateMotion: 'MOTION', stateLux: 'ILLUMINATION'},     
                                      //zigbee: {stateMotion: 'occupancy', stateLux: 'illuminance'},
                              };
                              
                              
                              // Logeinträge: Infos zeigen (wenn eingeschaltet oder ausgeschaltet wurde)
                              const INFO = true;
                              
                              // Logeinträge: Zusätzliche Einträge anzeigen zur Fehlerbehebung. Auf "false" setzen, wenn alles funktioniert.
                              const DEBUG = false;
                              
                              
                              /*************************************************************************************************************************
                               * Ab hier nichts mehr ändern / Stop editing here!
                               *************************************************************************************************************************/
                              
                              
                              /****************************************************************************
                               * Global variables and constants
                               ****************************************************************************/
                              let G_Timers = []; // Timer for each motion sensor (sensors as configured above). Key is 'name' of config.
                              let G_WaitTimers = []; // Wait Timers
                              let G_Sensornames = []; // All names of the sensors in this array. For logging...
                              
                              
                              /****************************************************************************
                               * First, we are validating the configuration
                               ****************************************************************************/
                              validate();
                              function validate() {
                              
                                  let errorCount = 0;
                              
                                  if (DEBUG) log('[DEBUG] ' + 'VALIDIERUNG *** START: Prüfung der Script-Konfiguration ***');
                                  for (const LPCONF of MOTION_SENSORS) {
                              
                                      if (isLikeEmpty(LPCONF.name)) {
                                          log('"name" wurde nicht gesetzt in Script-Konfiguration.', 'warn');
                                          errorCount++;
                                      } else {
                                          G_Sensornames.push(LPCONF.name); // For logging
                                      }
                              
                                      /////////////////////////////////////////////////////
                                      // 1. Check if adapters in MOTION_SENSORS are matching with ADAPTER_STATES
                                      // We use sensorState() function to check
                                      /////////////////////////////////////////////////////
                                      let sensorStateArray = [];         // We are allowing multiple sensors for one area.
                                      if (typeof LPCONF.sensorState == 'string') {
                                          sensorStateArray.push(LPCONF.sensorState); // If we just have one sensor as string
                                      }
                                      for (const lpSensorStatePath of sensorStateArray) {
                                          if(sensorState(LPCONF.sensorState, 'stateMotion') == 'ERROR') {
                                              log('Konfiguration von Bewegungsmelder ' + LPCONF.name + ': Adapter/Datenpunkt [' + lpSensorStatePath.split('.')[0] + '] ist NICHT korrekt definiert.', 'warn');
                                              errorCount++;
                                          } else {
                                              if (DEBUG) log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Adapter/Datenpunkt [' + lpSensorStatePath.split('.')[0] + '] ist korrekt konfiguriert.');
                                          }
                                      }
                              
                                      /////////////////////////////////////////////////////
                                      // 2. Prüfung und Umwandlung LPCONF.target
                                      /////////////////////////////////////////////////////
                                      if (typeof LPCONF.target == 'string') {
                                          if( getObject(LPCONF.target).common['type'] != 'boolean') {
                                              log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Einstellung für "target" ist fehlerhaft: Datenpunkt ist nicht vom Typ Boolean (true/false).', 'warn');
                                              errorCount++;
                                          } else {
                                              LPCONF.target = {on:{state:LPCONF.target, cmd:true}, off:{state:LPCONF.target, cmd: false}, checkOnOffStatusState:LPCONF.target};
                                          }
                                      } else {
                                          // We expect an object with at least on.state and on.cmd available
                                          if( isLikeEmpty(LPCONF.target.on.state) || isLikeEmpty(LPCONF.target.on.cmd) ) {
                                              log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Einstellung für "target" ist fehlerhaft - target.on.state und/oder target.on.cmd nicht definiert!', 'warn');
                                              errorCount++;
                                          } else {
                                              // If checkOnOffStatusState is not defined, we ensure that on.state is boolean, so that we can use this state instead.
                                              if( isLikeEmpty(LPCONF.target.checkOnOffStatusState)) {
                                                  if ( ! (LPCONF.target.on.cmd == true || LPCONF.target.on.cmd == false) ) {
                                                      log('[DEBUG] ' + 'VALIDIERUNG ' + LPCONF.name + ': Einstellung für "target" ist fehlerhaft: target.checkOnOffStatusState ist nicht gesetzt, und target.on.cmd ist nicht Boolean (true/false), daher kann nicht geprüft werden ob Gerät an/aus!', 'warn');
                                                      errorCount++;
                                                  } else {
                                                      // checkOnOffStatusState is not defined, but on.state is boolean, so we use this instead.
                                                      LPCONF.target.checkOnOffStatusState = LPCONF.target.on.state;
                                                  }
                                              }
                                          }
                                      }
                              
                              
                              
                              
                                      /////////////////////////////////////////////////////
                                      // 3. Some more validation
                                      /////////////////////////////////////////////////////
                                      const LP_PERIOD_KEYS = (Object.keys(LPCONF).filter(str => str.includes('period_'))); // gibt alle Keys mit 'period_' als Array zurück, also z.B. ['period_1','period_2']
                                      if (isLikeEmpty(LP_PERIOD_KEYS)) {
                                          log('Konfiguration von Bewegungsmelder ' + LPCONF.name + 'Es wurden keine Zeiten definiert (period_1, etc.). Bitte Script-Konfiguration überprüfen.', 'warn');
                                          errorCount++;
                                      } else {
                                          for (const LP_PERIOD_KEY of LP_PERIOD_KEYS) {
                                              let lpSecs = LPCONF[LP_PERIOD_KEY].sec;                    
                                              if( (isLikeEmpty(lpSecs) || (lpSecs <= 0)) ) {
                                                  if (DEBUG) log('[DEBUG] VALIDIERUNG ' + LPCONF.name + ': In [' + LP_PERIOD_KEY + '] wurden keine Sekunden zum Ausschalten definiert oder auf 0 gesetzt, daher wird nicht automatisch abgeschaltet.');
                                              } 
                                          }
                                      }
                              
                                  } //for
                              
                                  if (errorCount == 0) {
                                      if (DEBUG) log('[DEBUG] ' + 'VALIDIERUNG *** ENDE: Prüfung der Script-Konfiguration, Ergebnis: keine Fehler ***');
                                      main();
                                  } else {
                                      log('Insgesamt ' + errorCount + ' Fehler in der Script-Konfiguration gefunden. Daher wird abgebrochen und das Script nicht weiter ausgeführt.', 'error');
                                  }
                              
                              };
                              
                              
                              
                              /****************************************************************************
                               * Main function
                               ****************************************************************************/
                              function main() {
                              
                                  if(INFO) log('*** Bewegungsmelder-Script gestartet *** Folgende Bewegungsmelder werden überwacht: ' + G_Sensornames.join(', '));
                              
                                  for (const LPCONF of MOTION_SENSORS) {
                              
                                      // Initialize Timers
                                      G_Timers[LPCONF.name] = new myTimer();
                                      G_WaitTimers[LPCONF.name] = new myTimer();
                              
                                      // We are allowing multiple sensors for one area.
                                      let sensorStateArray = [];
                                      if (typeof LPCONF.sensorState == 'string') {
                                          // If we just have one sensor as string
                                          sensorStateArray.push(LPCONF.sensorState);
                                      } else {
                                          sensorStateArray = LPCONF.sensorState;
                                      }
                              
                                      for (const lpSensorState of sensorStateArray) {
                              
                                          on({id: sensorState(lpSensorState, 'stateMotion'), val:true}, function(obj) {
                              
                                              // Need to have statePath within on() function;
                                              let lpSensorStatePath = obj.id.substring(0, obj.id.length - (obj.id.match(/([^.]*$)/)[0].length + 1)); // removes the last part like ".motion"
                              
                              
                                              /////////////////////////////////////////////////////////////////////
                                              ///////////// Wir haben eine Bewegung //////////////////////////
                                              /////////////////////////////////////////////////////////////////////
                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Bewegungsmelder wurde ausgelöst.');
                                              let whyNotOnLog = ''; // for final info log
                                              let doIt = true;  // tells us we we REALLY want to turn device on
                                              let periodHit = ''; // Which period? Need this several times
                                              G_Timers[LPCONF.name].stop(); // just in case: stop timer.
                                              
                              
                                              // Einschalten Prüfung 1: Wait aktiv?
                                              if (doIt) {
                                                  if (G_WaitTimers[LPCONF.name].isRunning()) {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #1: Wait-Timer ist noch aktiv für ' + Math.round(G_WaitTimers[LPCONF.name].getTimeLeft()/1000) + ' Sekunden, also schalten wir nicht und brechen hier ab.');
                                                      whyNotOnLog = 'Wait ist noch aktiv für ' + Math.round(G_WaitTimers[LPCONF.name].getTimeLeft()/1000) + ' Sekunden';
                                                      doIt = false;
                                                  } else {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #1: Wait-Timer ist nicht aktiv.');
                                                  };
                                              };
                              
                                              // Einschalten Prüfung 2: Soll lt. definierten Datenpunkt in MOTION_SENSORS, neverState_XXX nicht geschaltet werden.
                                              if (doIt) {
                                                  const lpNeverStateKeys = (Object.keys(LPCONF).filter(str => str.includes('neverState_'))); // gibt alle Keys mit 'neverState_' als Array zurück, also z.B. ['neverState_1','neverState_2']. Oder leeres Array [] falls nichts vorhanden
                                                  if(isLikeEmpty(lpNeverStateKeys)) {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Keine Datenpunkte definiert, die geprüft werden, ob NICHT geschaltet werden soll.');
                                                  } else {
                                                      for (const lpNeverStateKey of lpNeverStateKeys) {
                                                          let lpStateId = LPCONF[lpNeverStateKey].state;
                                                          let lpStateVal = LPCONF[lpNeverStateKey].val;
                                                          let validationPassed = false;
                              
                                                          // 1. Validierung
                                                          if( isLikeEmpty(lpStateId) || lpStateVal == undefined ) { // check lpStateVal for undefined only, since it could have like an empty string.
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Keine korrekte Konfiguration in ' + lpNeverStateKey);
                                                          } else if( ($(lpStateId).length < 1) || (!existsState(lpStateId)) ) { // Workaround due to https://github.com/ioBroker/ioBroker.javascript/issues/478
                                                              log('Bewegungsmelder ' + LPCONF.name + ': In ' + lpNeverStateKey + ' angegebener Datenpunkt "' + lpStateId + '" wurde nicht gefunden.', 'warn');
                                                              // Wir machen aber trotzdem weiter, also lassen doIt auf true.
                                                          } else {
                                                              validationPassed = true;
                                                          }
                              
                                                          // 2. Prüfung Datenpunkt
                                                          if (validationPassed) {
                                                              let stateValToCheck = getState(lpStateId).val;
                                                              if (stateValToCheck == lpStateVal) {
                                                                  // Treffer -- wir schalten NICHT
                                                                  if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Datenpunkt-Inhalt zum nicht schalten (' + lpStateId + ') stimmt mit Script-Einstellung überein, Inhalt: [' + lpStateVal + ']. Also NICHT schalten.');
                                                                  whyNotOnLog = 'Datenpunkt  (' + lpStateId + ') stimmt mit Script-Einstellung überein, Inhalt: [' + lpStateVal + '].';
                                                                  doIt = false;
                                                                  break; // Exit loop since we have a hit                                
                                                              } else {
                                                                  if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #2: Datenpunkt-Inhalt zum nicht schalten (' + lpStateId + ') stimmt NICHT mit Script-Einstellung überein; Script-Vorgabe: [' + lpStateVal + '], Datenpunkt-Inhalt: [' + stateValToCheck + ']. Also machen wir weiter.');
                                                              }
                                                          }
                                                      }
                                                  }
                                              }
                              
                                              // Einschalten Prüfung 3: Ist aktuelle Zeit im Zeitraum "Nie schalten". Wird nur angewendet, falls neverPeriod_xxx vorhanden.
                                              if (doIt) {
                                                  const lpNeverKeys = (Object.keys(LPCONF).filter(str => str.includes('neverPeriod_'))); // gibt alle Keys mit 'neverPeriod_' als Array zurück, also z.B. ['neverPeriod_1','neverPeriod_2']. Oder leeres Array [] falls nichts vorhanden
                                                  if(isLikeEmpty(lpNeverKeys)) {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #3: Keine Zeiträume für "Nie schalten" definiert.');
                                                  } else {
                                                      for (const lpNeverKey of lpNeverKeys) {
                                                          // Die Funktion prüft alles für uns.
                                                          let match = currentTimeMatchesPeriod(LPCONF[lpNeverKey], LPCONF.name + ': Check #3 (' + lpNeverKey + ')');
                                                          if (match) {
                                                              // Treffer, also nicht schalten.
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #3: Zeitraum (' + lpNeverKey + ') ist in Bereich "Nie schalten", also schalten wir nicht.');
                                                              whyNotOnLog = 'Zeitraum  (' + lpNeverKey + ') ist in Bereich "Nie schalten"';
                                                              doIt = false;
                                                              break; // Exit loop since we have a hit
                                                          }
                                                      }
                                                  }
                                              }
                              
                                              // Einschalten Prüfung 4: Nur zu definierten Zeiten. 
                                              if (doIt) {
                                                  const lpPeriodKeys = (Object.keys(LPCONF).filter(str => str.includes('period_'))); // gibt alle Keys mit 'period_' als Array zurück, also z.B. ['period_1','period_2']
                                                  if (isLikeEmpty(lpPeriodKeys)) {
                                                      log('Im Script wurden keine Zeiten definiert (period_1, etc.). Bitte Script-Konfiguration überprüfen.', 'error');
                                                      whyNotOnLog = 'Keine Zeiten im Script (period_xxx) definiert';
                                                      doIt = false;
                                                  } else {
                                                      let isInRange = false;
                                                      for (const lpPeriodKey of lpPeriodKeys) {
                                                          // Die Funktion prüft alles für uns.
                                                          let match = currentTimeMatchesPeriod(LPCONF[lpPeriodKey], LPCONF.name + ': Check #4 (' + lpPeriodKey + ')');
                                                          if (match) {
                                                              // Treffer, also schalten.
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #4: Treffer - aktuelle Uhrzeit ist innerhalb Zeitraum (' + lpPeriodKey + ').' );
                                                              isInRange = true;
                                                              periodHit = lpPeriodKey; // Gefundene Zeitperiode ('period_') in globale Variable. Brauchen wir für Prüfung Lichtstärke, und auch beim Ausschalten (um die jew. gesetzten Lux zu bekommen)
                                                              break; // Exit loop since we have a hit                            
                                                          }
                                                      }
                                                      if (!isInRange) {
                                                          if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #4: Aktuelle Uhrzeit fällt in keine der definierten Zeitperioden.' );
                                                          whyNotOnLog = 'Aktuelle Uhrzeit fällt in keine der definierten Zeitperioden.';
                                                          doIt = false;
                                                      }
                                                  }
                                              }
                              
                                              // Einschalten Prüfung 5: Lichtstärke
                                              if (doIt) {
                                                  if (! isLikeEmpty(LPCONF[periodHit].lux )) {
                                                      if( (LPCONF[periodHit].lux < 10000) && (LPCONF[periodHit].lux > -1))  {
                                                          if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Prüfung auf Lux ist aktiviert.')
                                                          // Prüfung: luxAlways
                                                          let luxAlways = false;
                                                          if( !isLikeEmpty(LPCONF[periodHit].luxAlways) && LPCONF[periodHit].luxAlways == true ) {
                                                              luxAlways = true;
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "luxAlways" ist aktiviert, daher schalten wir immer auch auf Basis der Lux des Bewegungsmelders, auch wenn das Gerät (z.B. Licht) bereits an ist."')
                                                          }
                                                          if (getState(LPCONF.target.checkOnOffStatusState).val == true && luxAlways == false) {
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Gerät ist aber bereits an, also wird Prüfung auf Lux jetzt deaktiviert (da durch das Licht die Lux-Prüfung verfälscht wird).')
                                                          } else {
                                                              // Prüfung: gemessene Lux kleiner Schwellwert, bis zu dem geschalten werden soll?
                                                              let luxSensorState = getState(sensorState(lpSensorStatePath, 'stateLux')).val;
                                                              if (luxSensorState >= LPCONF[periodHit].lux) {
                                                                  if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Gemessene Lux = ' + luxSensorState + ', >= Schwelle von ' + LPCONF[periodHit].lux + ', daher wird nicht geschaltet.');
                                                                  whyNotOnLog = 'Gemessene Lux = ' + luxSensorState + ', >= Schwelle von ' + LPCONF[periodHit].lux;
                                                                  doIt = false;
                                                              } else {
                                                                  if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Gemessene Lux = ' + luxSensorState + ', < Schwelle von ' + LPCONF[periodHit].lux + ', daher eingeschaltet.')
                                                              }
                                                          }
                                                      } else {
                                                          if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Prüfung auf Lux ist deaktiviert.')
                                                      }
                                                  } else {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Check #5: Prüfung auf Lux ist deaktiviert.')
                                                  }
                                              }
                              
                                              // Einschalten: All checks processed.
                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Alle Einschalt-Prüfungen durchgeführt, Ergebnis: ' + ((doIt) ? 'JA - einschalten' : 'NEIN - nicht einschalten'));
                                              if (doIt) {
                              
                                                  ////////////////////////////////
                                                  // Jetzt einschalten
                                                  ////////////////////////////////
                              
                                                  // Prüfung ob bereits eingeschaltet.
                                                  let isOnAlready = false;
                                                  if (!isLikeEmpty(LPCONF.target.checkOnOffStatusState)) {
                                                      if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Datenpunkt für Prüfung, ob Gerät bereits angeschaltet ist, ist vorhanden: ' + LPCONF.target.checkOnOffStatusState)
                                                      if ( getState(LPCONF.target.checkOnOffStatusState).val ) {
                                                          // Device is already turned on
                                                          if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Gerät ist bereits angeschaltet, also schalten wir nicht noch mal.');
                                                          isOnAlready = true;
                                                      } else {
                                                          if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Gerät ist nicht eingeschaltet, also schalten wir es ein.')
                                                      }
                                                  } else {
                                                      if (DEBUG) log('[DEBUG] Check #5 - ' + LPCONF.name + ': Kein Datenpunkt für Prüfung, ob Gerät bereits angeschaltet ist, definiert. Also wird auf jeden Fall geschaltet.')
                                                  }
                                                  // JETZT SCHALTEN.
                                                  if(DEBUG && G_WaitTimers[LPCONF.name].isRunning()) log('[DEBUG] ' + LPCONF.name + ': "wait" ist aktiv, läuft noch ' + Math.round(G_WaitTimers[LPCONF.name].getTimeLeft()/1000) + ' Sekunden.');
                                                  // nur falls: 1.) Nicht bereits an und 2.) Kein wait aktiv                    
                                                  if(doIt && !isOnAlready && !G_WaitTimers[LPCONF.name].isRunning()) {
                                                      setState(LPCONF.target.on.state, LPCONF.target.on.cmd);
                                                      if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Ausgelöst und alle Kriterien erfüllt, daher wird eingeschaltet.');
                                                  }
                              
                                                  //////////////////////////
                                                  // Falls "wait" aktiviert: Timer prüfen / setzen für nächste Bewegungen
                                                  //////////////////////////
                                                  if( (isLikeEmpty(LPCONF[periodHit].sec) || (LPCONF[periodHit].sec == 0)) ) {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Wait-Timer wird nicht gesetzt, da keine Ausschaltsekunden definiert.');
                                                  } else {
                                                      if ( isLikeEmpty(LPCONF.wait) || LPCONF.wait < LPCONF[periodHit].sec ) {
                                                          if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "wait" ist nicht gesetzt oder kleiner als definierte Ausschaltsekunden von ' + LPCONF[periodHit].sec + 's, daher wird "wait" nicht weiter betrachtet.')
                                                      } else {
                                                          if ( !G_WaitTimers[LPCONF.name].isRunning() ) {
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "Wait"-Timer läuft nicht. Also starten wir den Timer: ' + LPCONF.wait + ' Sekunden. Damit wird erst wieder nach dieser Zeit erneut eingeschaltet.');
                                                                  // Timer-Start
                                                                  G_WaitTimers[LPCONF.name].start(function() {
                                                                      G_WaitTimers[LPCONF.name].stop(); // just in case
                                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "wait" von ' + LPCONF.wait + ' Sekunden seit letzter Einschaltung ist abgelaufen, daher wird "wait" wieder deaktiviert.');
                                                                  }, LPCONF.wait * 1000);
                                                          } else {
                                                              if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': "Wait"-Timer ist noch aktiv und läuft noch ' + G_WaitTimers[LPCONF.name].getTimeLeft() + ' Sekunden. ');
                                                          }
                                                      }
                                                  }
                              
                                                  ////////////////////////////////
                                                  // Nun der Timer zum Ausschalten
                                                  ////////////////////////////////
                                                  // Timer-Prüfung: Falls sec=0 oder sec nicht definiert, dann soll nicht per diesem Script ausgeschaltet werden.
                                                  if( (isLikeEmpty(LPCONF[periodHit].sec) || (LPCONF[periodHit].sec <= 0)) ) {
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Keine Sekunden zum Ausschalten definiert oder Ausschalten deaktiviert (lt. [' + periodHit + '] in Konfiguration). Daher setzen wir keinen Timer zum ausschalten.')
                                                  } else {
                                                      // Jetzt wird der Timer gesetzt.
                                                      if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Wir setzen einen Timer von ' + LPCONF[periodHit].sec + ' Sekunden zum Ausschalten (lt. [' + periodHit + '] in Konfiguration).')
                                                      
                                                      G_Timers[LPCONF.name].start(function() {
                                                          /////////////////////////////////////////
                                                          // Timer ist abgelaufen (wir sind im Callback von setTimeout())
                                                          /////////////////////////////////////////
                                                          G_Timers[LPCONF.name].stop();
                                                          if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Timer (' + LPCONF[periodHit].sec + ' Sekunden) ist abgelaufen (lt. [' + periodHit + '] in Konfiguration).');
                              
                              
                                                          // Jetzt ausschalten
                                                          let whyNotOffLog = ''; // for final info log
                                                          let turnOff = true;
                                                          if (!isLikeEmpty(LPCONF.target.checkOnOffStatusState)) {
                                                              if (DEBUG) log('[DEBUG] TurnOff Check 1: ' + LPCONF.name + ': Datenpunkt für Prüfung, ob Gerät bereits ausgeschaltet ist, ist vorhanden: ' + LPCONF.target.checkOnOffStatusState)
                                                              if (! getState(LPCONF.target.checkOnOffStatusState).val ) {
                                                                  if (DEBUG) log('[DEBUG] TurnOff Check 2: ' + LPCONF.name + ': Gerät ist bereits ausgeschaltet, also machen wir nichts weiter.')
                                                                  whyNotOffLog = 'Gerät ist bereits ausgeschaltet';
                                                                  turnOff = false;
                                                              } else {
                                                                  if (DEBUG) log('[DEBUG] TurnOff Check 2: ' + LPCONF.name + ': Gerät ist eingeschaltet, also schalten wir aus.')
                                                              }
                                                          } else {
                                                              if (DEBUG) log('[DEBUG] TurnOff Check #2 - ' + LPCONF.name + ': Kein Datenpunkt für Prüfung, ob Gerät bereits ausgeschaltet ist, definiert. Also wird auf jeden Fall ausgeschaltet.')
                                                          }
                                                          // Ausschalten: All checks processed.
                                                          if (DEBUG) log('[DEBUG] ' + LPCONF.name + ': Alle Ausschalt-Prüfungen durchgeführt. Ergebnis (ob ausgeschaltet werden soll): ' + turnOff);
                                                          if (turnOff) {
                                                              //////////// FINALLY, WE TURN DEVICE OFF //////////////////
                                                              if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Timer (' + LPCONF[periodHit].sec + 's) abgelaufen und alle Kriterien erfüllt, daher wird ausgeschaltet.');
                                                              setState(LPCONF.target.off.state, LPCONF.target.off.cmd);               
                                                          } else {
                                                              if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Timer (' + LPCONF[periodHit].sec + 's) abgelaufen, aber es wird nicht geschaltet, Grund: ' + whyNotOffLog);
                                                          }
                                                      }, (LPCONF[periodHit].sec) * 1000);
                                                  }
                                              
                                              } else {
                                                  if (INFO) log('Bewegungsmelder ' + LPCONF.name + ': Ausgelöst, aber es wird nicht geschaltet, Grund: ' + whyNotOnLog);
                                              }
                              
                                          }); // on() auf stateMotion - true
                                      } // for loop: sensorStatesArray
                                  } // for (const LPCONF of MOTION_SENSORS)
                              }
                              
                              
                              /**
                               * Returns the full state for a given motion sensor state
                               * @param {string} sensorState     sensor state, like "mihome.0.devices.sensor_motion_aq2_1234567abcde"
                               * @param {string} stateNameToAdd  state name you want to add per ADAPTER_STATES, like "stateLux"
                               * @return {string}    The according state name of the adapter, like: mihome.0.devices.sensor_motion_aq2_1234567abcde.lux
                               */
                              function sensorState(sensorState, stateNameToAdd) {
                                  if (!sensorState.endsWith('.')) sensorState = sensorState + '.'; // add "." at the end, if it is not there
                                  const adapterName = sensorState.split('.')[0]; // like: mihome, zigbee, etc.
                                  let result = '';
                                  let isError = true;
                                  if (! isLikeEmpty(adapterName) && (ADAPTER_STATES[adapterName] != undefined)) {
                                      if (stateNameToAdd in ADAPTER_STATES[adapterName]) {
                                          result = ADAPTER_STATES[adapterName][stateNameToAdd];
                                          if(! isLikeEmpty(result)) {
                                              isError = false;
                                          }
                                      }
                                  }
                                  if(isError) {
                                      log('Catched Script Error in function sensorState(): Could not get adapter state name "' + stateNameToAdd + '" for [' + sensorState + '].', 'error');
                                      return 'ERROR';
                                  } else {
                                      return sensorState + result;
                                  }
                              }
                              
                              /**
                               * Better timer function
                               * Features: Find out time remaining, stop timer easily, check status (running yes/no).
                               * Autor:               Mic (ioBroker) | Mic-M (github)
                               * Version:             0.1 (14 March 2020)
                               * Source:              https://stackoverflow.com/questions/3144711/
                               * -----------------------------------------------
                               * Make a timer:
                                    let a = new myTimer();
                                    a.start(function() {
                                     // Do what ever
                                    }, 5000);
                               * Time remaining:      a.getTimeLeft()
                               * Stop (clear) timer:  a.stop()
                               * Is timer running:    a.isRunning()
                               * -----------------------------------------------
                               */
                              function myTimer() {
                                  let fcallback;
                                  let id;
                                  let started;
                                  let remaining = 0;
                                  let running = false;
                              
                                  this.start = function(callback, delay) {
                                      fcallback = callback;
                                      remaining = delay;
                                      clearTimeout(id);
                                      id = null;
                                      running = true;
                                      started = Date.now();
                                      id = setTimeout(fcallback, remaining);
                                  }
                              
                                  this.pause = function() {
                                      running = false;
                                      clearTimeout(id);
                                      remaining -= Date.now() - started;
                                  }
                              
                                  this.stop = function() {
                                      running = false;
                                      clearTimeout(id); id = null;
                                      remaining = 0;
                                  }
                              
                                  this.getTimeLeft = function() {
                                      if (running) {
                                          this.pause();
                                          this.start(fcallback, remaining);
                                          return remaining;
                                      } else {
                                          return 0;
                                      }
                                  }
                              
                                  this.isRunning = function() {
                                      return running;
                                  }
                              
                              }
                              
                              
                              /***************************************************************
                               * Checks if provided period as object, like {start:'7:00', end:'23:00', days:'2-4, 6'} is matching with current date/time.
                               * start and end: See https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#comparetime
                               *                Astro is allowed as well, so like start:'sunsetStart' or with an offset like end:{astro: 'sunrise', offset: -30}
                               * days:          Monday = 1, Tuesday = 2, ... Sunday = 7. You can separate days with comma, so like '1, 3, 5' for Mon/Wed/Fri,
                               *                and you can use period like '2-4' for Tue/Wed/Thu, and you can combine both, so like '2-4, 7' for Tue/Wed/Thu/Sun.
                               * @param  {string} info   Any info (like device name), just for the logging.
                               * @return {boolean}   true, if current date/time within period, false if not.
                               ***************************************************************/
                              function currentTimeMatchesPeriod(objectPeriod, info) {
                              
                                  let fStart = objectPeriod.start;
                                  let fEnd = objectPeriod.end;
                                  let fDays = objectPeriod.days;
                              
                                  // Part 1: Check week days
                                  if (fDays == undefined) {
                                      if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Keine Wochentage definiert, also gilt jeder Tag.');
                                      // We continue: If no days defined in object, we consider this as no day limit and allow every day
                                  } else {
                                      if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Zu schaltende Wochentage definiert: ' + fDays);
                                      if (isCurrentDayInRange(fDays)) {
                                          if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Aktueller Wochentag ist innerhalb definierter Tage.');
                                          // We continue
                                      } else {
                                          if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Aktueller Wochentag ist NICHT innerhalb definierter Tage.');
                                          // We leave function with false
                                          return false;
                                      }
                                  }
                              
                                  // Part 2: Check time
                                  let logPeriod = ((typeof fStart == 'string') ? fStart : JSON.stringify(fStart)) + ' - ' + ((typeof fEnd == 'string') ? fEnd : JSON.stringify(fEnd));
                                  if (withinRange(fStart, fEnd)) {
                                      if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Treffer: aktuelle Uhrzeit ist innerhalb Zeitraum (' + logPeriod + ').' );
                                      return true;
                                  } else {
                                      if (DEBUG) log('[DEBUG] ' + info + ' - Time Period Check - Aktuelle Uhrzeit ist NICHT innerhalb Zeitraum (' + logPeriod + ').' );
                                      return false;
                                  }
                              
                              
                                  /*************************************************************************
                                   * Helper functions following below
                                   *************************************************************************/
                              
                                  /**
                                   * Checks if given string of ranges is matching with current day
                                   * Numbers 1-7 allowed (stand for weekdays).
                                   * @param {string} inputRanges   String, like: '5,6', '1-3, 6, 7', '3'
                                   * @return {boolean} true if matches, false if not
                                   */
                                  function isCurrentDayInRange(inputRanges) {
                                  
                                      // Get current weekday. Monday = 1, Tuesday = 2, ... Sunday = 7.
                                      let dateNow = new Date();
                                      let currWeekday = (dateNow.getDay());
                                      if (currWeekday == 0) currWeekday = 7; // Sunday should be 7, not 0.
                              
                                      let resArray = getSingleDaysFromRanges(inputRanges);
                              
                                      if (resArray.indexOf(currWeekday) != -1) {
                                          return true;
                                      } else {
                                          return false;
                                      }
                                  }
                              
                                  /**
                                   * Convert given string of ranges to array.
                                   * Numbers 1-7 allowed (stand for weekdays).
                                   * @param {string} inputRanges   String, like: '5,6', '1-3, 6, 7', '3'
                                   * @return {array} Array with each individual number, so '2-4, 7' will return [2,3,4,7]. Returns empty array [] if no matches
                                   */
                                  function getSingleDaysFromRanges(inputRanges) {
                                      let resultArray = [];
                                      if(!isLikeEmpty(inputRanges)) {
                                          inputRanges = inputRanges.replace(/[^1-7.,-]+/g,'') // just keep numbers 1-7, ",", ".", "-"
                                          let inputArray = inputRanges.split(',');
                                          for (const lpVal of inputArray) {
                                              let matchResultPeriod = lpVal.match(/(\d)(-)(\d)/); // matches like 2-4
                                              let matchResultSingle = lpVal.match(/^\d$/g); // matches single number like 2
                                              if (matchResultPeriod != null) {
                                                  // Wir haben eine Angabe wie 2-4 - match gibt zurück: ['2-4','2','-','4']
                                                  for (let i = parseInt(matchResultPeriod[1]); i <= parseInt(matchResultPeriod[3]); i++) {
                                                      resultArray.push(i);
                                                  }        
                                              } else if (matchResultSingle != null) {
                                                  resultArray.push(parseInt(matchResultSingle[0]));
                                              }
                                          }
                                      }    
                                      return resultArray;
                                  }
                              
                              
                                  /**
                                   * Checks if time is within range using compareTime()
                                   */
                                  function withinRange(startTime, endTime) {
                                      let result = false;
                                      if (! isLikeEmpty(startTime) && ! isLikeEmpty(startTime)) {
                                          if (compareTime(startTime, endTime, 'between')) {
                                              result = true;
                                          }
                                      }
                                      return result;
                                  }
                              
                              }
                              
                              /**
                               * Clear timeouts once script is stopped.
                               */
                              onStop(function (callback) {
                                  let counter = 0;
                                  for (const LPCONF of MOTION_SENSORS) {
                                      if (G_Timers[LPCONF.name].isRunning()) {
                                          G_Timers[LPCONF.name].stop();
                                          if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] ' + LPCONF.name + ': Ausschalt-Timer deaktiviert.');
                                          counter++;
                                      }
                                      if (G_WaitTimers[LPCONF.name].isRunning()) {
                                          G_WaitTimers[LPCONF.name].stop();
                                          if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] ' + LPCONF.name + ': Wait-Timer deaktiviert.');            
                                          counter++;
                                      }
                                  }
                                  if (counter > 0) {
                                      if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] Script sauber gestoppt, es wurden ' + counter + ' Timer deaktiviert.');
                                  } else {
                                      if (DEBUG) log('[DEBUG] [SCRIPT STOPPED] Script sauber gestoppt, es gab keine aktivierten Timer.');
                                  }
                              
                                  callback();
                              }, 500);
                              
                              
                              
                              /**
                               * Checks if Array or String is not undefined, null or empty.
                               * 08-Sep-2019: added check for [ and ] to also catch arrays with empty strings.
                               * @param inputVar - Input Array or String, Number, etc.
                               * @return true if it is undefined/null/empty, false if it contains value(s)
                               * Array or String containing just whitespaces or >'< or >"< or >[< or >]< is considered empty
                               */
                              function isLikeEmpty(inputVar) {
                                  if (typeof inputVar !== 'undefined' && inputVar !== null) {
                                      let strTemp = JSON.stringify(inputVar);
                                      strTemp = strTemp.replace(/\s+/g, ''); // remove all whitespaces
                                      strTemp = strTemp.replace(/\"+/g, "");  // remove all >"<
                                      strTemp = strTemp.replace(/\'+/g, "");  // remove all >'<
                                      strTemp = strTemp.replace(/\[+/g, "");  // remove all >[<
                                      strTemp = strTemp.replace(/\]+/g, "");  // remove all >]<
                                      if (strTemp !== '') {
                                          return false;
                                      } else {
                                          return true;
                                      }
                                  } else {
                                      return true;
                                  }
                              }
                              
                              
                              MicM Offline
                              MicM Offline
                              Mic
                              Developer
                              schrieb am zuletzt editiert von
                              #41

                              @MartyBr
                              Hört sich nach einem Feature Request an (ich bau grad nen Adapter um dieses Script abzulösen, aber so nebenbei wie ich dazu komme, dauert also noch 😉 )

                              Was ist dein Use Case, etwa so?
                              Falls keine Bewegung mehr, soll nur ausgeschaltet werden, falls nicht vor erkannter Bewegung "manuell" das Licht eingeschaltet wurde?

                              M crunchipC 2 Antworten Letzte Antwort
                              1
                              • MicM Mic

                                @MartyBr
                                Hört sich nach einem Feature Request an (ich bau grad nen Adapter um dieses Script abzulösen, aber so nebenbei wie ich dazu komme, dauert also noch 😉 )

                                Was ist dein Use Case, etwa so?
                                Falls keine Bewegung mehr, soll nur ausgeschaltet werden, falls nicht vor erkannter Bewegung "manuell" das Licht eingeschaltet wurde?

                                M Offline
                                M Offline
                                MartyBr
                                schrieb am zuletzt editiert von
                                #42

                                @Mic
                                Keine Eile, ich habe noch die Programmierung in der Homematic laufen. Ich migriere gerade alle Scripte in Richtung ioBroker.

                                Der Used case:
                                Die Bewegungsmelder stehen im Wohnzimmer. Bei Dunkelheit geht die Rollos runter und kleine Präsenzlichter gehen an. Das nutzen wir gerne, wenn wir Fernsehen oder uns unterhalten.
                                Wenn wir ins Schlafzimmer gehen, dann schalten wir die Lichter aus.
                                Nun kann es mal passieren, dass Gäste Nachts ins Wohnzimmer gehen. In diesem Fall schalten die Lichter bei Bewegung ein und nach 5 Minuten wieder aus. Das sind die gleichen Lampen, die Abends auch in Benutzung sind.
                                In der Homematic prüfe ich den state. Ist er "True" passiert nichts (die Lampe wird auch nicht ausgeschaltet), ist er "false" dann schaltet der Bewegungsmelder Licht an.

                                Mit deinem Script passiert folgendes: Ist die Startzeit erreicht, dann wird nach weiteren 5 Minuten die Lampe abgeschaltet. Das kann schon dumm sein, wenn ich gerade ein Buch lese.

                                Auf den Adapter bin ich gespannt 😎

                                Ich habe vin dir einige Scripte laufen, herzlichen Dank für deine Arbeit und das Teilen 👍

                                Gruß
                                Martin


                                Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                                Raspeberry mit USB Leseköpfen für Smartmeter
                                Homematic und Homematic IP

                                1 Antwort Letzte Antwort
                                0
                                • MicM Mic

                                  @MartyBr
                                  Hört sich nach einem Feature Request an (ich bau grad nen Adapter um dieses Script abzulösen, aber so nebenbei wie ich dazu komme, dauert also noch 😉 )

                                  Was ist dein Use Case, etwa so?
                                  Falls keine Bewegung mehr, soll nur ausgeschaltet werden, falls nicht vor erkannter Bewegung "manuell" das Licht eingeschaltet wurde?

                                  crunchipC Abwesend
                                  crunchipC Abwesend
                                  crunchip
                                  Forum Testing Most Active
                                  schrieb am zuletzt editiert von
                                  #43

                                  @Mic sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                                  Was ist dein Use Case

                                  ja, das wäre noch klasse, das erkennen, ob Licht "manuell" eingeschaltet wurde
                                  gibt auch hierzu ein Script, siehe

                                  umgestiegen von Proxmox auf Unraid

                                  1 Antwort Letzte Antwort
                                  0
                                  • MicM Offline
                                    MicM Offline
                                    Mic
                                    Developer
                                    schrieb am zuletzt editiert von
                                    #44

                                    @MartyBr
                                    @crunchip

                                    Danke euch beiden, baue ich in den Adapter ein. Hab es mir in die Adapter-Konfig des Roh-Entwurfs reingeschrieben, so geht es nicht unter 😁
                                    71556f07-6e58-471c-9975-5b208e13121c-image.png

                                    M 2 Antworten Letzte Antwort
                                    2
                                    • MicM Mic

                                      @MartyBr
                                      @crunchip

                                      Danke euch beiden, baue ich in den Adapter ein. Hab es mir in die Adapter-Konfig des Roh-Entwurfs reingeschrieben, so geht es nicht unter 😁
                                      71556f07-6e58-471c-9975-5b208e13121c-image.png

                                      M Offline
                                      M Offline
                                      MartyBr
                                      schrieb am zuletzt editiert von
                                      #45

                                      @Mic
                                      Danke dir. Auich für die prompte Reaktion 👍

                                      Gruß
                                      Martin


                                      Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                                      Raspeberry mit USB Leseköpfen für Smartmeter
                                      Homematic und Homematic IP

                                      1 Antwort Letzte Antwort
                                      0
                                      • MicM Mic

                                        @MartyBr
                                        @crunchip

                                        Danke euch beiden, baue ich in den Adapter ein. Hab es mir in die Adapter-Konfig des Roh-Entwurfs reingeschrieben, so geht es nicht unter 😁
                                        71556f07-6e58-471c-9975-5b208e13121c-image.png

                                        M Offline
                                        M Offline
                                        MartyBr
                                        schrieb am zuletzt editiert von MartyBr
                                        #46

                                        @Mic
                                        Hast du schon eine Version zum Testen auf GitHub?

                                        Gruß
                                        Martin


                                        Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                                        Raspeberry mit USB Leseköpfen für Smartmeter
                                        Homematic und Homematic IP

                                        MicM 1 Antwort Letzte Antwort
                                        0
                                        • M MartyBr

                                          @Mic
                                          Hast du schon eine Version zum Testen auf GitHub?

                                          MicM Offline
                                          MicM Offline
                                          Mic
                                          Developer
                                          schrieb am zuletzt editiert von
                                          #47

                                          @MartyBr sagte in [Vorlage] Bewegungsmelder-Script (Xiaomi Aqara und andere):

                                          @Mic
                                          Hast du schon eine Version zum Testen auf GitHub?

                                          Hier geht es weiter 🙂

                                          Planung neuer Adapter: Licht-/Raumsteuerung und mehr

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


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          370

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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