Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. [Script] Kamera Alarm ohne Synology oder motion nutzen.

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

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

    • ioBroker goes Matter ... Matter Adapter in Stable

    [Script] Kamera Alarm ohne Synology oder motion nutzen.

    This topic has been deleted. Only users with topic management privileges can see it.
    • jmeister79
      jmeister79 last edited by jmeister79

      Hi,
      ich wollte auch mal was beisteuern hier anstatt immer nur zu fragen
      vielleicht hat ja jemand von Euch Interesse/Verwendung an und für meiner Lösung oder lässt sich inspirieren

      Und zwar wollte ich meine Reolink Kamera zur Bewegungserkennung und Kontrolle auf dem ioBroker für den Raspberry Pi benutzen ohne externe Lösungen wie Synology Surveillance Station oder motion zu verwenden.
      Auch wollte ich die Aufnahmen AUSSERHALB der Kamera speichern, damit ein Bösswicht sie nicht einfach klaut.

      1. Vorraussetzungen
      • Die Kamera muss Zugang zum Netzwerk haben
      • Die Kamera braucht eine eigene Bewegungserkennung
      • Die Kamera sendet die Bilder per FTP
      • FTP Server im Netz. (Ich habe aus meinem pi gleich einen Server gemacht dann hab ich alles an Bord(proFTP), alternativ den FTP via fStab auf dem System Mounten, natürlich kann man sich auch woanders einloggen aber dann braucht ihr andere Befehle fürs Dateisystem. Wichtig ist allerdings, dass ioBroker Lese und Schreibzugriff auf die Ordner hat.
      1. Prinzip
      • Kamera Erkennt Bewegung und erzeugt ein MP4 Film sowie ein jpg Bild
      • Kamera schickt das auf einen FTP Server
      • ioBroker überwacht das Verzeichnis mit Chokidar und erkennt neue Dateien.
      • Tagesverzeichnis wird dann durchgezählt und sollten es mehr Dateien geworden sein gibt es einen Alarm in der vis und das aktuellste Bild per Telegram.
      • letztes jpg wird ausgelesen und in den VIS Ordner gespeichert, damit es angezeigt wird.
      • Ein Sweeper Script löscht alte Verzeichnisse nach Datum

      Dazu brauche ich ein Script.

      [update] Script zum löschen stark optimiert, so dass jetzt nach dateiinfo gelöscht wird und nicht mehr nach namen, somit kompatibel mit allen kameras

      var fs = require('fs');             //Dateisystemoperationen
      const path = require('path')        //Pfadobjekte
      var chokidar = require('chokidar');     //Watcher für Dateisystemveränderungen
      
      //DPs erzeugen
      createState("javascript.0.Alerts.latestSnapshot", "leer", {type: 'string',name: 'latesSnapshot'});
      createState("javascript.0.Alerts.CameraFilesCount_Last", "leer", {type: 'number',name: 'Anzahl Alarme'});
      createState("javascript.0.Alerts.CamMotionDetected", "leer", {type: 'boolean',name: 'Bewegung Kamera'});
      createState("javascript.0.Parameter.enableTelegramCamAlert", "false", {type: 'boolean',name: 'Alarm Bewegung'});
      createState("javascript.0.Parameter.CamStorageDuration", 10, {type: 'number',name: 'Speicherdauer Kameradaten'});
      createState("javascript.0.Helper.CamDeleteOldFiles", false, {type: 'boolean',name: 'Alte Kameradaten löschen'});
      
      
      //String aus Datum berechnen um in die verzeichnisse zu kommen
      function stringofdate(date){
          var d = date.getDate();
          var m = date.getMonth() + 1;
          var y = date.getFullYear();
          var datestring = y + '/' + (m <= 9 ? '0' + m : m) + '/' + (d <= 9 ? '0' + d : d);
          return datestring;
      }
      
      // Verzeichnisstruktur ist zb
      // /watchpath/Kameraname/YYYY/MM/dd/blbala.jpg
      
      var watchpath = '/home/reolink/Kameras';   //Kameraordner darf nicht = home Ordner sein
      var dirlist = fs.readdirSync(watchpath);   //Liste der Kameras holen
      
      
      var watcher = chokidar.watch(watchpath+'/**/*.jpg', {ignored: /^\./, persistent: true,awaitWriteFinish: true, ignoreInitial:true});
      //Was passiert wenn er was findet
      watcher.on('add', function(pathfound) {
          var dirlist = fs.readdirSync(watchpath);   //Liste der Kameras updaten   
          setState("javascript.0.Alerts.CamMotionDetected", true);
          //log("Neue Datei erkannt")    
          for (let i of dirlist) { 
              //DPs updaten
              createState("javascript.0.Alerts.latestSnapshot"+i, "leer", {type: 'string',name: 'latestnapshot'});
              createState("javascript.0.Alerts.CamMotionDetected"+i, "leer", {type: 'boolean',name: 'Bewegung Kamera'});
              var re = new RegExp(i, 'g');        
              // allgmeines Alarmbit setzen und neuen Zählerstand in DP speichern
              setState("javascript.0.Alerts.CamMotionDetected", true);
              if (pathfound.match(re)){  //wenn es sich um dieses element handelt
                  //log('javascript.0.Alerts.latestSnapshot'+i+' = '+pathfound);
                  setState("javascript.0.Alerts.latestSnapshot"+i, pathfound); //den gefunden Pfad in einen Datenpunkt fürs VIS kopieren
                  setState("javascript.0.Alerts.CamMotionDetected"+i, true);  //individuelles alarmbit setzen
                  var logtext = 'Bewegung Kamera '+i+' erkannt';
                  setState("javascript.0.Logbuch.array_LogMsg", ['move',logtext]);
                  //wenn gewollt per telegram verschicken
                  if(getState("javascript.0.Parameter.enableTelegramCamAlert").val===true){  
                      sendTo("telegram.0",  {
                          text: fs.readFileSync(pathfound),
                          type: 'photo',
                          caption: logtext
                      }); 
                  }  
                  try { 
                      //fünf sekunden warten,damit die datei Zeit hat fertig gespeichert zu werden    
                      //log('Schreibe '+pathfound +' auf /vis.0/latest_'+i+'.jpg');  ACHTUNG! dateien ohne Leerzeichen verwenden
                      setTimeout(function(){},5000);exec( 'iobroker file write '+pathfound+' /vis.0/latest_'+i+'.jpg');  
                  }catch(err) {
                      console.error("Cam Monitor: Fehler beim Kopieren der Kameradaten "+i);
                  }   
              }
          }
      })
      
      //Wichtig beim Beenden des Skriptes den watcher killen, sonst läuft der ewig weiter und es entstehen mit jedem neustart des skripts neue Instanzen
      onStop(() => {
          watcher.close()
              .then(log('Watcher gestoppt', 'info'))
      })
      
      
      //Bewegung erkennen und wert zurücksetzen
      on({id: 'javascript.0.Alerts.CamMotionDetected', val: true}, async function (obj) {
          setTimeout(function () {
              setState("javascript.0.Alerts.CamMotionDetected", false);
          for (let i of dirlist) { 
              setState("javascript.0.Alerts.CamMotionDetected"+i, false);  //individuelles alarmbit setzen
          }
          }, 60000);
      });
      
      //Deklaration der Löschfunktion alter Daten
      function ThroughDirectory(Directory,deletedate) {
          var files;
          fs.readdirSync(Directory).forEach(File => {
              const Absolute = path.join(Directory, File);
              //Fallunterscheidung Verzeichnis oder Datei
              if (fs.statSync(Absolute).isDirectory()){      
                  ThroughDirectory(Absolute, deletedate);  //recursiver Aufruf der Funktion, da es ein Verzeichnis ist   
                  //checken ob das verzeichnis nun evtl leer ist
                  if(fs.readdirSync(Absolute).length === 0){//Leeres Verzeichnis gefunden
                      log("Leeres Verzeichnis "+Absolute+" wird gelöscht");  
                      setState("javascript.0.Logbuch.array_LogMsg", ['info', 'Verz. '+Absolute+' wird gelöscht']);
                      fs.rmdirSync(Absolute);
                  }
                  return
              }else{
                  const info = fs.statSync(Absolute);  //Dateiinfo holen
                  files = files + "/n"+info.birthtime        
                  if(info.birthtime < deletedate){    // ist die datei älter als der Parameter?
                      fs.unlink(Absolute, (err => {
                      if (err) console.log(err);
                      }));
                  }
              }
          })
      }
      
      on({id: 'javascript.0.Parameter.CamStorageDuration', change: "ne"}, async function (obj) {
              setState("javascript.0.Helper.CamDeleteOldFiles", true);  
          //javascript.0.Helper.CamDeleteOldFiles
      });
      
      //Löschen der alten Daten
      schedule("0 0 * * *", function () {//everyday at 00:00
              setState("javascript.0.Helper.CamDeleteOldFiles", true);  
      });
      on({id: 'javascript.0.Helper.CamDeleteOldFiles', val: true}, async function (obj) {
              setState("javascript.0.Helper.CamDeleteOldFiles", false);  
      //schedule("* * * * *", function () {//everyday at 00:00
          var storageduration = getState("javascript.0.Parameter.CamStorageDuration").val;    
          //Datum holen
          var deletedate = new Date()
          deletedate.setDate(deletedate.getDate() - storageduration);//altes datum erzeugen
          log("Deleting older than "+deletedate)
          //setState("javascript.0.Logbuch.array_LogMsg", ['info', 'Deleting older than '+deletedate]);
          ThroughDirectory(watchpath,deletedate); 
          
      
      });
      

      Ich habe so gut es geht versucht zu kommentieren wo nötig.
      Bin für Verbesserungen offen.

      Known Bugs / ToDo:

      • Filme per Telegram?
      • Code ist z.Zt. gewachsen und ist jetzt auf einem für mich funktionierenden Stand.

      LG
      Nils

      jmeister79 1 Reply Last reply Reply Quote 1
      • jmeister79
        jmeister79 @jmeister79 last edited by jmeister79

        [update] neues script im ersten post

        jmeister79 1 Reply Last reply Reply Quote 0
        • jmeister79
          jmeister79 @jmeister79 last edited by

          @jmeister79 ursprungspost angepasst und script stark optimiert

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

          Support us

          ioBroker
          Community Adapters
          Donate

          426
          Online

          31.8k
          Users

          79.9k
          Topics

          1.3m
          Posts

          1
          3
          345
          Loading More Posts
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes
          Reply
          • Reply as topic
          Log in to reply
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
          The ioBroker Community 2014-2023
          logo