HTTPMOD/Device für Reolink Kameras

Begonnen von GunterB, 01 Juli 2021, 12:10:48

Vorheriges Thema - Nächstes Thema

Harox

Hallo Gunter,
erstmal vielen Dank für deine Vorarbeit mit der Reolink Kamera. Ich habe eine RLC-810A gerade zum testen. Hast du eigentlich eine Lösung gefunden, wenn die Kamera eine Personen, Auto- oder Tiererkennung hat, dass man diesen Alert auch als Push Meldung in die Fhem bekommt.
Du hast geschrieben, dass der Push nicht gut funktioniert. Wenn ich die Push Nachrichten aus der App ansehe, sehen die gar nicht so schlecht aus.
Ich verstehe nur nicht wie die Push Nachrichten in die Fhem kommen. Mit dem HTTPMOD kommst das Event aus der Fhem Richtung, das sollte ja bei Push anders herum sein.
Kannst du mir hierzu bitte ein Tipp geben, ich stehe an der Stelle auf dem Schlauch.

Danke dir.

Gruß Harald

ReneR1986

Hallo Harox,

ich habe meine Reolinks mit meiner Synology über Surveillance Station verbunden.
Dort kann man Auslöser/Aktionen definieren z.B. Erkennung von Fahrzeugen oder Personen. Als Aktion rufe ich dann einen Webhook (HTTP Request an FHEM) auf, der einen Dummy schaltet.
Das wird wiederum von einem DOIF abgefangen und es wird über Pushover eine Nachricht gesendet.
Eine Möglichkeit das über HTTPMOD zu machen sehe ich nicht, wie du ja schon beschrieben hast ist die Richtung hier eine andere.

Gruß
René

Harox

Hallo René,

danke dir für deinen Vorschlag. Allerdings ist mir das ein bisschen zu indirekt. Das ist eigentlich schade, die Kameras gefallen mir richtig gut. Nur der fehlende Alert ist für mich ein kritischer Punkt.

Gruß Harald

privat58

Hallo, ich habe mir zwei reolink e1 outdoor gekauft und komme mit der Einrichtung nicht klar.
Hat sich bei der Anmeldung wieder etwas geändert?
Danke für eine Hilfe
mvh

Maista

Zitat von: privat58 am 16 September 2023, 08:05:50Hallo, ich habe mir zwei reolink e1 outdoor gekauft und komme mit der Einrichtung nicht klar.
Hat sich bei der Anmeldung wieder etwas geändert?
Danke für eine Hilfe
mvh
Einrichtung bei FHEM oder wo?

privat58

Sorry, nicht eindeutig.
Ja es geht um die Einrichtung in fhem per HTTPMOD.
Es scheint sich bei der Anmeldung der Kameras geändert zu haben.
Bei mir kommt im log "Reolink1: Read callback: Error: start_SSL https://192.168.0.200:443 timed out"
mvh

ReneR1986

#36
Bei mir funktioniert es noch.
Allerdings habe ich auch kein https, sondern nur http.
Firmwareversion ist: v3.1.0.1318_22091311_v1.0.0.30

sparkiie

Zitat von: privat58 am 17 September 2023, 09:45:35Sorry, nicht eindeutig.
Ja es geht um die Einrichtung in fhem per HTTPMOD.
Es scheint sich bei der Anmeldung der Kameras geändert zu haben.
Bei mir kommt im log "Reolink1: Read callback: Error: start_SSL https://192.168.0.200:443 timed out"
mvh

Hast du hier eine Lösung gefunden?

Ich habe aktuell das selbe Problem mit einer RLC-810WA.

privat58

Ich habe es nicht weiter verfolgt, da ich in https://github.com/berfenger/cam2mqtt erst einmal eine Lösung gefunden habe und die Kamera als "Bewegungsmelder" missbrauche.

sparkiie

Ich habe die Kamera noch einmal zurückgesetzt und alles neu eingebunden, nun geht es auch bei mir.

Noch ein paar Frage an die Profis  :)

Ist es möglich die Bewegungsrekennung insgesamt zu deaktivieren, also die Kamera in Standby zu setzen?

Was genau passiert bei get Image? Bei mir passiert nämlich gar nichts, er speichert weder ein Bild auf der SD Karte noch auf dem FTP.

Ich leite die Videos vom FTP per inotifywait an Telegram weiter. Dort habe ich das Probleme das die Videos beim Abspielen nur 1 Sekunde lang zu sein scheinen. Tatsächlich läuft das Video aber weiter.
Wenn also ein Video 30 Sekunden lang ist, dann zeigt der Fortsschrittsbalken im Player auch nur 1 Sekunde an und ist direkt am Ende. Das Video läuft aber weiter, lässt sich dadurch aber nicht spulen z.B.. Liegt das am Codec oder könnte das auch an den Video Einstellungen liegen?

ReneR1986

Hier ist die API Dokumentation.
Da sollte auch stehen, was genau z.B. getImage macht.

https://drive.google.com/drive/folders/19vQBJia0wKvzwscA-EpTDSFV5OfNYUL6

VG

René

sparkiie

Zitat von: ReneR1986 am 22 Dezember 2023, 10:06:56Hier ist die API Dokumentation.
Da sollte auch stehen, was genau z.B. getImage macht.

https://drive.google.com/drive/folders/19vQBJia0wKvzwscA-EpTDSFV5OfNYUL6

VG

René
Vielen Dank.

Dann habe ich das falsch interpretiert. Ich dachte getImage bedeutet, dass die Kamera ein Foto aufnimmt - so wie im IPCAM Modul...

GunterB

#42
Hallo zusammen,

ich habe mich mittlerweile weiter um die Konfiguration der Kameras kümmern können.
Es besteht jetzt die Möglichkeit, Aufnahmezeiten und die Detection Area zu verändern.
Zudem kann die aktuelle Detection Area als PNG gespeichert und auch wieder rückgelesen werden (Funktionen in der 99_myUtils).

Du darfst diesen Dateianhang nicht ansehen.

attr K1_Konfig reading51JSON 01_value_MdAlarm_scope_cols
attr K1_Konfig reading51Name MdAlarm_scope_cols
attr K1_Konfig reading52JSON 01_value_MdAlarm_scope_rows
attr K1_Konfig reading52Name MdAlarm_scope_rows
attr K1_Konfig reading53JSON 01_value_MdAlarm_scope_table
attr K1_Konfig reading53Name MdAlarm_scope_table

attr K1_Konfig userReadings HddCapacity_2:HddCapacity.* {sprintf("%.0fGB%s", ReadingsVal($name,"HddCapacity",0)/1024.0, ReadingsVal($name,"HddCapacity",0) == 0 ? "🔴" : "")},\
newSens1:newSens-1[\s\S]* {my $v = ReadingsVal($name,"newSens-1","0");;;; fhem("deletereading $name newSens-1");;;; $v =~ s/\s//g;;;; $v},\
newSens2:newSens-2[\s\S]* {my $v = ReadingsVal($name,"newSens-2","0");;;; fhem("deletereading $name newSens-2");;;; $v =~ s/\s//g;;;; $v},\
newSens3:newSens-3[\s\S]* {my $v = ReadingsVal($name,"newSens-3","0");;;; fhem("deletereading $name newSens-3");;;; $v =~ s/\s//g;;;; $v},\
newSens4:newSens-4[\s\S]* {my $v = ReadingsVal($name,"newSens-4","0");;;; fhem("deletereading $name newSens-4");;;; $v =~ s/\s//g;;;; $v}

attr K1_Konfig get36Data [{"cmd":"GetMdAlarm","action":0,"param":{"channel":0}}]
attr K1_Konfig get36Name MdAlarm
attr K1_Konfig get36Poll 1

attr K1_Konfig set51Name api
attr K1_Konfig set51TextArg 1

Verwendung der Funktionen:
                my $wl_dev = "K${cam_num}_Konfig_Scope_${set}";
                if (IsDevice($wl_dev)) {
                    my $set_path = InternalVal($wl_dev, "LINK", "");
                    my ($cols, $rows, $binstring) = png_to_binstring("/opt/${set_path}");
                   
                    if (length($binstring)) {
                        my $MdAlarmJSON = "";
                        $MdAlarmJSON .= "[";
                        $MdAlarmJSON .= "{\"cmd\":\"SetMdAlarm\",\"action\":0,\"param\":{";
                        $MdAlarmJSON .= "\"MdAlarm\":{";
                        $MdAlarmJSON .= "\"channel\":0,";
                        ##--------------------------------------------
                        ## scope
                        $MdAlarmJSON .= "\"scope\":{\"cols\":${cols},\"rows\":${rows},\"table\":\"${binstring}\"}";
                        ##--------------------------------------------
                        $MdAlarmJSON .= "}}}]";
                        fhem("set $device api $MdAlarmJSON");
                    } else {
                        $message .= "no binstring\n";
                    }
                } else {
                    $message .= "no device ${wl_dev}\n";
                }

Code (99_myUtils.pm) Auswählen
...
#####################################################
#####################################################
## apt-get install libgd-perl
## binstring    String with Binary 0 1 characters
## name         Name of picture
## col          Columns / Spalten
## row          Row / Zeilen
sub binstring_to_png ($$$$) {
    use strict;
    use warnings;
    use GD;
    my ($p_binstring,$filename,$col,$row) = @_;
    my $SELF = "binstring_to_png";
    if (length($p_binstring) <= 0) { return "no binstring";}
    if ($col <= 0) { return "col";}
    if ($row <= 0) { return "row";}
    my $BitMap = GD::Image->new($col,$row);
   
    Log3($SELF, 4, "${SELF}: Filename: $filename");
    Log3($SELF, 4, "${SELF}: $col $row");

    my $white = $BitMap->colorAllocate(255,255,255);
    my $blue = $BitMap->colorAllocate(130,182,245);      ## ausgeblendet

    # Frame the BitMap
    ##$BitMap->rectangle(0,0,$col-1,$row-1,$blue);
    # Transparent image, white background color
    $BitMap->transparent($white);

    ### plot some, just to show it works #
    ##for my $x (0..100) {
    ##   for my $y (0 .. 100) {
    ##      $BitMap->setPixel(250+100*sin($x)-$y,150+125*cos($x)+$y,$blue);
    ##   }
    ##}
   
    for (my $i = 0; $i < length($p_binstring); $i++) {
        my $act_val = substr($p_binstring, $i, 1);
        if ($act_val eq "0") {
            my $x = $i % $col;
            my $y = POSIX::floor($i / $col);
            Log3($SELF, 4, "${SELF}: set x y: $x $y");
            $BitMap->setPixel($x,$y,$blue);
        }
    }

    # write png-format to file
    open my $fh,">","$filename" or die "$!";
    binmode $fh;
    print $fh $BitMap->png;
    close($fh);
    return 1;
}

#####################################################
#####################################################
## apt-get install libgd-perl
## Filename         Path/Name of picture
sub png_to_binstring ($) {
    use strict;
    use warnings;
    use GD;
    my ($filename) = @_;
    my $SELF = "png_to_binstring";
    my $p_binstring = "";
   
    ##Log3($SELF, 4, "${SELF}: Filename: $filename");

    my $img = GD::Image->new( $filename );
    my( $w, $h ) = $img->getBounds;
    ##print "$SELF: The image '$filename' is $w x $h pixels.\n";

    ##printf "The color of the pixel in the middle is: [0x%02x:0x%02x:0x%02x
    ##+].\n",
    ##$img->rgb( $img->getPixel( $w/2, $h/2 ) );
   
   
    for (my $y = 0; $y < $h; $y++) {
        for (my $x = 0; $x < $w; $x++) {
            my ($r,$g,$b) = $img->rgb( $img->getPixel( $x, $y ) );
            $p_binstring .= $r == 255 ? "1" : "0";
            ##if ($y == 0) {
            ##    printf "%s: x%d, y%d: [%d, %d,%d].\n", $SELF, $x, $y, $r, $g, $b;
            ##}
        }
    }
   
    return ($w, $h, $p_binstring);
}
...


Code (NTFY_Kx_Scope) Auswählen
define NTFY_Kx_Scope notify K[1-9]_Konfig.*:MdAlarm_scope_table.* {\
my $dev = $NAME;;\
\
my $binstring = ReadingsVal($dev,"MdAlarm_scope_table", "");;\
my $cols = ReadingsVal($dev,"MdAlarm_scope_cols", 0);;\
my $rows = ReadingsVal($dev,"MdAlarm_scope_rows", 0);;\
\
\
##Log3($SELF, 3, "${SELF}/${NAME}: $cols $rows");;\
\
binstring_to_png($binstring, "www/snapshots/${dev}.png", $cols, $rows);;\
my ($cols_back, $rows_back, $binstring_back) = png_to_binstring("www/snapshots/${dev}.png");;\
fhem("deletereading $dev MdAlarm_scope_.*");;\
\
if ($binstring ne $binstring_back) {\
    fhem("setreading $SELF ${NAME}_bin_error bin strings not equal");;\
}\
\
##fhem("setreading $SELF ${dev}_to $binstring");;\
##fhem("setreading $SELF ${dev}_from $binstring_back");;\
\
my $wl_dev = "${dev}_Scope";;\
my $ctrl_v = "0.03";;\
\
my ($a, $b, $c, $d, $e, $f) = (return_elements());;\
fhem("setreading $SELF a $a");;\
fhem("setreading $SELF b $b");;\
fhem("setreading $SELF e $e");;\
fhem("setreading $SELF f $f");;\
\
if (!IsDevice("$wl_dev")) {\
    ##fhem("define ${wl_dev} weblink htmlCode <img src=\"log/${dev}.png\" >");;\
    fhem("define ${wl_dev} weblink image /");;\
}\
\
if (IsDevice("$wl_dev")) {\
    my $dummy_v = AttrVal($wl_dev, "ctrl_v", "");;\
    if ($ctrl_v ne $dummy_v) {\
        fhem("defmod ${wl_dev} weblink image /fhem/www/snapshots/${dev}.png");;\
        fhem("attr ${wl_dev} room Kamera");;\
        fhem("attr ${wl_dev} userattr ctrl_by ctrl_v");;\
        fhem("attr ${wl_dev} ctrl_by $SELF");;\
        fhem("attr ${wl_dev} ctrl_v $ctrl_v");;\
    }\
}\
\
return 0;;\
}

Beispiel um für alle Kameras die Sonnenaufgangs und Sonnenuntergangszeiten als Zeitplan mit unterschiedlichen Empfindlichkeitsstufen zu hinterlegen.
Bei Bewölkung wird die Empfindlichkeit zusätzlich runter gesetzt, um gegenüber Hell/Dunkel- Wechseln unempfindlicher zu werden.
Code (dailyKamera_Configuration) Auswählen
define dailyKamera_Configuration at *23:50 {\
## dailyKamera_Configuration\
my $message = "#$SELF\n";;\
my $Twilight_Dev = "Sonnenstand";;\
my $PROPLANTA_Dev = "myProPlanta";;\
my $msgChatId = "#Telegram_Gruppe";;\
\
my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime(gettimeofday());;\
\
my $fc = "1";;\
if ($hour < 23) {$fc = "0";;}\
$message .= "Verwende Vorhersage: fc${fc}\n";;\
\
my $tw_sr_weather = ReadingsVal($Twilight_Dev, "sr_weather", "-1:-2");;\
my $tw_ss_weather = ReadingsVal($Twilight_Dev, "ss_weather", "-3:-4");;\
my $pp_fcX_cloud06 = ReadingsVal($PROPLANTA_Dev, "fc${fc}_cloud06", -1);;\
my $pp_fcX_cloud09 = ReadingsVal($PROPLANTA_Dev, "fc${fc}_cloud09", -1);;\
my $pp_fcX_cloud12 = ReadingsVal($PROPLANTA_Dev, "fc${fc}_cloud12", -1);;\
my $pp_fcX_cloud15 = ReadingsVal($PROPLANTA_Dev, "fc${fc}_cloud15", -1);;\
my $pp_fcX_cloud18 = ReadingsVal($PROPLANTA_Dev, "fc${fc}_cloud18", -1);;\
my $pp_fcX_solar_rad = ReadingsVal($PROPLANTA_Dev, "fc${fc}_solar_rad", -1);;\
\
my @Kameras = devspec2array("K[1-99]+.*_Konfig");;\
##my @Params;;\
\
    \
## Range 1=Low, 26= Medium, 50=High\
my $low_sens = 12;;      ## cloudy and sunny\
my $high_sens = 26;;     ##\
my $std_sens = 26;;      ## Medium (at night)\
my $cur_sens;;\
\
##if ( ($pp_fcX_cloud09 > 30 || $pp_fcX_cloud12 > 30 || $pp_fcX_cloud15 > 30) && $pp_fcX_solar_rad >= 1.4) {\
if ( ($pp_fcX_cloud09 > 30 || $pp_fcX_cloud12 > 30 || $pp_fcX_cloud15 > 30) ) {\
    $cur_sens = $low_sens;;\
} else {\
    $cur_sens = $high_sens;;        \
}\
   \
$message .= "Kameraempfindlichkeit auf ${cur_sens} gesetzt (1=Low,26=Med,50=High)\n";;\
\
my $daylight_sens = -$cur_sens+51;; \
$message .= "newSens wird auf ${daylight_sens} gesetzt\n";;\
\
my $json1;;\
foreach(@Kameras){\
    my $cam_dev = $_;;\
    ##my $kamera_model = ReadingsVal($_,"model",0);;\
    ##my $kamera_firmVer = ReadingsVal($_,"firmVer",0);;\
    ##my $kamera_model_rdsage = ReadingsAge($_,"model", -1);;\
    ##my $kamera_hardVer = ReadingsVal($_,"hardVer",0);;\
    ##push(@Params, [$_, $kamera_model, $kamera_firmVer, Format_Seconds_Age($kamera_model_rdsage), $kamera_hardVer])\
    \
    \
\
    ##.----------------------------------------------------------------.\
    ##|                             CONFIG                             |\
    ##.----------------------------------------------------------------.\
   \
    my $add_scope = 0;;\
    my $add_sens = 0;;\
    \
    \
    my $MdAlarmJSON = "";;\
    $MdAlarmJSON .= "[";;\
    $MdAlarmJSON .= "{\"cmd\":\"SetMdAlarm\",\"action\":0,\"param\":{";;\
    $MdAlarmJSON .= "\"MdAlarm\":{";;\
    $MdAlarmJSON .= "\"channel\":0,";;\
    ##--------------------------------------------\
    ## scope\
    if ($add_scope) {\
        $MdAlarmJSON .= "\"scope\":{\"cols\":80,\"rows\":60,\"table\":\"\"},";;\
    }\
    ##--------------------------------------------\
    \
    $MdAlarmJSON .= "\"useNewSens\":1,";;\
\
    ##--------------------------------------------\
    ## sens\
    if ($add_sens) {\
        $MdAlarmJSON .= "\"sens\":[";;\
        \
        $MdAlarmJSON .= "{\"beginHour\":0,\"beginMin\":0,\"endHour\":6,\"endMin\":0,\"id\":0,\"sensitivity\":15}";;\
        $MdAlarmJSON .= ",";;\
        $MdAlarmJSON .= "{\"beginHour\":6,\"beginMin\":0,\"endHour\":12,\"endMin\":0,\"id\":2,\"sensitivity\":15}";;\
        $MdAlarmJSON .= ",";;\
        $MdAlarmJSON .= "{\"beginHour\":12,\"beginMin\":0,\"endHour\":18,\"endMin\":0,\"id\":2,\"sensitivity\":15}";;\
        $MdAlarmJSON .= ",";;\
        $MdAlarmJSON .= "{\"beginHour\":18,\"beginMin\":0,\"endHour\":23,\"endMin\":59,\"id\":3,\"sensitivity\":15}";;\
        \
        ##for (my $id = 0;; $id <= 3;; $id++) {\
        ##    $MdAlarmJSON .= "{\"beginHour\":0,\"beginMin\":0,\"endHour\":6,\"endMin\":0,\"id\":0,\"sensitivity\":10}";;\
        ##    if ($id < 3) {\
        ##        $MdAlarmJSON .= ",";;\
        ##    }\
        ##}\
        $MdAlarmJSON .= "],";;\
    }\
    ##--------------------------------------------\
\
    ##--------------------------------------------\
    ## newSens\
    $MdAlarmJSON .= "\"newSens\":{\"sens\":[";;\
 \
    my $tw = "${tw_sr_weather} ${tw_ss_weather}";;\
    my ($sr_hh, $sr_mm, $ss_hh, $ss_mm) = $tw =~ /^0*([1-9][0-9]*|0):0*([1-9][0-9]*|0):\d{2} 0*([1-9][0-9]*|0):0*([1-9][0-9]*|0):\d{2}$/;;\
    my $hh1 = 0;;\
    my $mm1 = 0;;\
    my $hh2 = 0;;\
    my $mm2 = 0;;\
    my $newSensID0 = "{\"enable\":1,\"beginHour\":${sr_hh},\"beginMin\":${sr_mm},\"endHour\":${ss_hh},\"endMin\":${ss_mm},\"id\":0,\"priority\":2,\"sensitivity\":${daylight_sens}}";;\
    my $newSensID1 = "{\"enable\":0,\"beginHour\":${hh1},\"beginMin\":${mm1},\"endHour\":${hh2},\"endMin\":${mm2},\"id\":2,\"priority\":4,\"sensitivity\":${daylight_sens}}";;\
    my $newSensID2 = "{\"enable\":0,\"beginHour\":${hh1},\"beginMin\":${mm1},\"endHour\":${hh2},\"endMin\":${mm2},\"id\":2,\"priority\":4,\"sensitivity\":${daylight_sens}}";;\
    my $newSensID3 = "{\"enable\":0,\"beginHour\":${hh1},\"beginMin\":${mm1},\"endHour\":${hh2},\"endMin\":${mm2},\"id\":3,\"priority\":5,\"sensitivity\":${daylight_sens}}";;\
\
    $json1 = $newSensID0;;\
    \
    $MdAlarmJSON .= "${newSensID0}, ${newSensID1}, ${newSensID2}, ${newSensID3}";;\
    \
    ##for (my $id = 0;; $id <= 3;; $id++) {\
    ##    ##$enable\
    ##    ##$(hh1, mm1, hh2, mm2)\
    ##    ##$prio = $id + 2;;\
    ##    ##$sens\
    ##    $MdAlarmJSON .= "{\"enable\":${enable},\"beginHour\":${hh1},\"beginMin\":${mm1},\"endHour\":${hh2},\"endMin\":${mm2},\"id\":${id},\"priority\":${prio},\"sensitivity\":${sens}}";;\
    ##    if ($id % 3) then {\
    ##        $MdAlarmJSON .= ",";;\
    ##    }\
    ##}\
    $MdAlarmJSON .= "]";;\
    ##--------------------------------------------\
\
    $MdAlarmJSON .= ",\"sensDef\":${std_sens}}}}}";; ## sensitivity other period\
    \
    \
    #### Weitere Kommandos ....\
    #### [{"cmd":"GetAbility","action":0,"param":{"User":{"userName":"admin"}}},{"cmd":"GetDevInfo","action":0,"param":{}}]\
    ##$MdAlarmJSON .= "{\"cmd\":\"GetAbility\",\"action\":0,\"param\":{\"User\":{\"userName\":\"admin\"}}}";;\
    ##$MdAlarmJSON .= ",";;\
    ##\
    ##$MdAlarmJSON .= "{\"cmd\":\"GetDevInfo\",\"action\":0,\"param\":{}}";;\
    \
    ##--------------------------------------------\
    ## GetMdAlarm\
    $MdAlarmJSON .= ",{\"cmd\":\"GetMdAlarm\",\"action\":0,\"param\":{\"channel\":0}}";;\
    ##--------------------------------------------\
    \
\
    $MdAlarmJSON .= "]";;\
    \
    \
    fhem("set ${cam_dev} api $MdAlarmJSON");;\
    fhem("setreading ${cam_dev} api $MdAlarmJSON");;\
    \
}\
\
$message .= "JSON ID0: ${json1}\n";;\
fhem("set myTelegramBot _msg \@$msgChatId $message");;\
\
}




ReneR1986

Bei meiner Reolink kann man statt der Sirene auch eine kurze, individuelle Sprachaufnahme aufnehmen.
Das wird dann aber nur bei Bewegungserkennungen abgespielt.

Kann man die Sirene oder eben die Sprachaufnahme über die API auch "manuell" auslösen (ohne Bewegungserkennung)?


ReneR1986

OK, ich habe es hinbekommen...
Jetzt gibt die Kamera über den Lautsprecher meine Sprachaufnahme wieder  ;D

attr HofCam set38Data {"cmd":"AudioAlarmPlay","action":0,"param":{"alarm_mode":"times","manual_switch":0,"times":$val,"channel":0}}]
attr HofCam set38Name ManualAlarm
attr HofCam set38Hint 1,2,3