Hauptmenü

Neueste Beiträge

#1
Sonstige Systeme / Aw: FHEM-Integration von Tapo ...
Letzter Beitrag von Prof. Dr. Peter Henning - 20 März 2026, 17:29:01
So, ich habe das jetzt auf einem guten Stand. Mit einem FHEM Dummy
defmod TapoCam dummy
attr TapoCam readingList snapshot motor_action motor_result motor_presets error
attr TapoCam setList takePhoto:noArg privacy:on,off light:on,off light_intensity light_duration light_night:ir,white,auto led:on,off left right up down calibrate:noArg preset_goto:1,2,3,4,5,6,7,8 preset_save preset_delete presets_get detection_motion detection_person detection_pet detection_tamper detection_vehicle detection_linecrossing alarm:on,off alarm_light:on,off alarm_sound:on,off alarm_duration alarm_volume:low,medium,high
attr TapoCam webCmd takePhoto:left:right:up:down
und einem DOIF
defmod TapoCam.N DOIF ([TapoCam:state] ne "ready") \
({TapoCamHandler("$DEVICE","$EVENT")})\
(setreading TapoCam state ready)\
\
DOELSEIF\
([+00:05:00])\
({TapoCamHandler("TapoCam","status_update")})\
\

attr TapoCam.N do always
attr TapoCam.N group Control
attr TapoCam.N room Kontrollraum
attr TapoCam.N wait 0,3
sowie zwei verschiedenen Perl-Funktionen
sub TapoCamHandler($$){
  my ($name,$event) = @_;
 
  my $hash = $defs{$name};
  return if(!$hash);
  my $res;
  my $val;
  my $cmd;
 
  #--
  if( $event =~ /^takePhoto$/){
    $res = qx(/opt/fhem/tapo/tapo_snapshot.sh);
    chomp($res);
    fhem("setreading $name snapshot $res");
 
  #-- status update
  }elsif( $event eq "status_update" ){
    my $cmd = '/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_privacy.py; '
          . '/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_light.py status; '
          . '/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_alarm.py status; '
          . '/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_detection.py status; '
          . '/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_events.py events 300; ';
    system('/bin/sh', '-c', "($cmd) >/dev/null 2>&1 &");
  
  #-- privacy
  }elsif( $event =~ /^privacy\s+(on|off)$/){
    $event = $1;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_privacy.py $event >/dev/null 2>&1 &");
   
  #-- light
  }elsif($event =~ /^(led|light)\s+(on|off)$/){
    $event = $1;
    $val = $2;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_light.py $event $val >/dev/null 2>&1 &");
  }elsif($event =~ /^light_(intensity|duration)\s+(\d+)$/){
    $event = $1;
    $val = $2;
    $event =~ s/duration/time/;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_light.py $event $val >/dev/null 2>&1 &");
  }elsif($event =~ /^light_night\s+(ir|white|auto)$/){
    $event ="night";
    $val = $1;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_light.py $event $val >/dev/null 2>&1 &");
   
  #-- motor
  }elsif( $event =~ /^(left|right|up|down|calibrate|presets_get)$/){
    $event =~ s/_get//;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_motor.py $event >/dev/null 2>&1 &");
  }elsif( $event =~ /^(left|right|up|down|preset_goto|preset_delete)\s+(\d+)$/){
    $event = $1;
    $val = $2;
    $event =~ s/preset_//;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_motor.py $event $val >/dev/null 2>&1 &");
  }elsif( $event =~ /^preset_save\s+(\d+)\s+(.+)$/){
    $event = "save";
    $val = $1;
    $cmd = $2;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_motor.py $event $val $cmd >/dev/null 2>&1 &");
 
  #-- detection
  }elsif( $event =~ /^detection_(motion|person|pet|tamper|vehicle|linecrossing)\s+(\d+)$/){
    $event = $1;
    $val = $2;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_detection.py $event $val >/dev/null 2>&1 &");
 
  #-- alarm
   }elsif($event =~ /^alarm\s+(on|off)$/){
    $val = $1;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_alarm.py $val >/dev/null 2>&1 &");
  }elsif( $event =~ /^alarm_(light|sound)\s+(on|off)$/){
    $event = $1;
    $val = $2;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_alarm.py $event $val >/dev/null 2>&1 &");
  }elsif( $event =~ /^alarm_(volume|duration)\s+(.+)$/){
    $event = $1;
    $val = $2;
    system("/opt/fhem/tapo/.venv/bin/python3 /opt/fhem/tapo/tapo_control_alarm.py $event $val >/dev/null 2>&1 &");
  }
}
zum Setzen und
sub TapoReturnHandler($$$){
  my ($name,$group,$json) = @_;
 
  my $hash = $defs{$name};
  return if(!$hash);
 
  #Log 1,"obtained return to $name from Tapo group $group. json-result = $json";
 
  #-- JSON-String nach Perl-Hash wandeln
  if(!defined($json) || $json eq "") {
    readingsSingleUpdate($hash, "error", "empty json", 1) if $hash;
    return;
  }
  my $data;
  eval {
    $data = decode_json($json);
  };
  if($@ || ref($data) ne "HASH") {
    readingsSingleUpdate($hash, "error", "invalid json for group $group", 1);
    return;
  }
 
  #-- privacy
  if( $group eq "privacy" ){
    readingsBeginUpdate($hash);
    #-- Fehler-Rückgabe aus Python
    if(defined($data->{result})
      && $data->{result} eq "error"){
      my $msg = $data->{message} // "unknown error";
      readingsBulkUpdate($hash, "error", $msg);
      readingsBulkUpdate($hash, "state", "$group error: $msg");
    }else {
      my $state = $data->{privacy} // "";
      readingsBulkUpdate($hash,"privacy",$state);
      readingsBulkUpdate($hash, "error", "");
      readingsBulkUpdate($hash, "state", "privacy $state");
    }
    readingsEndUpdate($hash,1);
   
  #-- light
  }elsif($group eq "light") {
    readingsBeginUpdate($hash);
    #-- Fehler-Rückgabe aus Python
    if(defined($data->{result})
      && $data->{result} eq "error"){
      my $msg = $data->{message} // "unknown error";
      readingsBulkUpdate($hash, "error", $msg);
      readingsBulkUpdate($hash, "state", "$group error: $msg");
    }else {
      readingsBulkUpdate($hash, "light",           $data->{status})      if defined $data->{status};
      readingsBulkUpdate($hash, "light_intensity", $data->{intensity})   if defined $data->{intensity};
      readingsBulkUpdate($hash, "light_duration",  $data->{time})        if defined $data->{time};
      readingsBulkUpdate($hash, "light_remain",    $data->{time_remain}) if defined $data->{time_remain};
      readingsBulkUpdate($hash, "light_night",     $data->{night})       if defined $data->{night};
      readingsBulkUpdate($hash, "led",             $data->{led})         if defined $data->{led};
      readingsBulkUpdate($hash, "error", "");
      readingsBulkUpdate($hash, "state", "light ok");
    }
    readingsEndUpdate($hash, 1);
    
  #-- motor
  }elsif( $group eq "motor" ){
    readingsBeginUpdate($hash);
    #-- Fehler-Rückgabe aus Python
    if(defined($data->{result}) && $data->{result} eq "error") {
      my $msg = $data->{message} // "unknown error";
      readingsBulkUpdate($hash, "error", $msg);
      readingsBulkUpdate($hash, "state", "$group error: $msg");
    }else{
      my $action = $data->{action} // "";
      my $result = $data->{result} // "";
      my $motor_action = "";
      my $state = "";

      #-- motor_action zusammensetzen
      if($action =~ /^(left|right|up|down)$/) {
        my $value = $data->{value} // 0;
        $motor_action = "$action $value";
      }elsif($action =~ /^(goto|save|delete)$/) {
        my $preset = $data->{preset} // "";
        $motor_action = "$action $preset";
      }
      else {
        $motor_action = $action;
      }
      readingsBulkUpdate($hash, "motor_action", $motor_action);
      readingsBulkUpdate($hash, "motor_result", $result);
      $state = $motor_action || $result;

      #-- presets-Liste
      if($action eq "presets") {
        my $presets = $data->{presets};
        if(ref($presets) eq "HASH") {
          my @names = map { $presets->{$_} } sort { $a <=> $b } keys %{$presets};
          my $preset_list = join(",", @names);
          readingsBulkUpdate($hash, "motor_presets", $preset_list);
          $state = "presets: $preset_list";
        } else {
          readingsBulkUpdate($hash, "motor_presets", "");
          $state = "presets";
        }
      }
      readingsBulkUpdate($hash, "error", "");
      readingsBulkUpdate($hash, "state", $state);
    }
    readingsEndUpdate($hash, 1);
 
  #-- detection
  }elsif($group eq "detection") {
    readingsBeginUpdate($hash);
    #-- Fehler-Rückgabe aus Python
    if(defined($data->{result}) && $data->{result} eq "error") {
      my $msg = $data->{message} // "unknown error";
      readingsBulkUpdate($hash, "error", $msg);
      readingsBulkUpdate($hash, "state", "$group error: $msg");
    }else{
      #-- Fall 1: kompletter Status
      if(ref($data->{motion})       eq "HASH"
        || ref($data->{person})       eq "HASH"
        || ref($data->{vehicle})      eq "HASH"
        || ref($data->{pet})          eq "HASH"
        || ref($data->{tamper})       eq "HASH"
        || ref($data->{linecrossing}) eq "HASH") {
        foreach my $type (qw(motion person vehicle pet tamper linecrossing)) {
          next if ref($data->{$type}) ne "HASH";

          my $enabled = $data->{$type}{enabled};
          next if !defined $enabled;

          my $reading = "detection_$type";
          my $value;

          if($type eq "linecrossing") {
            $value = $enabled;
          } else {
            if($enabled eq "off") {
              $value = "off";
            } else {
              my $sens = $data->{$type}{sensitivity};
              $value = defined($sens) ? "on $sens" : "on";
            }
          }
          readingsBulkUpdate($hash, $reading, $value);
        }
        readingsBulkUpdate($hash, "error", "");
        readingsBulkUpdate($hash, "state", "detection status");

      #-- Fall 2: Rückgabe eines set-Befehls
      }elsif(defined $data->{action}) {
        my $action  = $data->{action} // "";
        my $enabled = $data->{enabled};
        my $value   = $data->{value};
        my $result  = $data->{result};
        my $reading = "detection_$action";
        my $onoff = defined($enabled) ? ($enabled ? "on" : "off") : "";

        if($action eq "linecrossing") {
          readingsBulkUpdate($hash, $reading, $onoff) if $onoff ne "";
        } else {
          my $reading_value;
          if($onoff eq "off") {
            $reading_value = "off";
          } else {
            $reading_value = "on";
            $reading_value .= " $value" if defined $value;
          }
          readingsBulkUpdate($hash, $reading, $reading_value) if $reading_value ne "";
        }
        my $state = $action;
        $state .= " $onoff" if $onoff ne "";
        $state .= " $value" if defined $value && $action ne "linecrossing" && $onoff eq "on";
        readingsBulkUpdate($hash, "error", "");
        readingsBulkUpdate($hash, "state", $state);
      }
    }
    readingsEndUpdate($hash, 1);
   
  #-- alarm
  }elsif($group eq "alarm") {
    readingsBeginUpdate($hash);
    #-- Fehler-Rückgabe aus Python
    if(defined($data->{result})
      && $data->{result} eq "error"){
      my $msg = $data->{message} // "unknown error";
      readingsBulkUpdate($hash, "error", $msg);
      readingsBulkUpdate($hash, "state", "alarm error: $msg");
    }else {
      readingsBulkUpdate($hash, "alarm",          $data->{status})   if defined $data->{status};
      readingsBulkUpdate($hash, "alarm_sound",    $data->{sound})    if defined $data->{sound};
      readingsBulkUpdate($hash, "alarm_light",    $data->{light})    if defined $data->{light};
      readingsBulkUpdate($hash, "alarm_duration", $data->{duration}) if defined $data->{duration};
      readingsBulkUpdate($hash, "alarm_volume",   $data->{volume})   if defined $data->{volume};
     readingsBulkUpdate($hash, "error", "");

      my $state = "";
      $state .= "alarm:$data->{status} " if defined $data->{status};
      $state .= "sound:$data->{sound} " if defined $data->{sound};
      $state .= "light:$data->{light} " if defined $data->{light};
      $state .= "vol:$data->{volume} " if defined $data->{volume};
      $state .= "dur:$data->{duration}" if defined $data->{duration};
      $state =~ s/\s+$//;
      readingsBulkUpdate($hash, "state", $state) if $state ne "";
    }
   readingsEndUpdate($hash, 1);

   #-- events
   }elsif( $group eq "events" ){
    readingsBeginUpdate($hash);
    #-- Fehler-Rückgabe aus Python
    if(defined($data->{result})
      && $data->{result} eq "error"){
      my $msg = $data->{message} // "unknown error";
      readingsBulkUpdate($hash, "error", $msg);
      readingsBulkUpdate($hash, "state", "$group error: $msg");
    }else {
      my $window = $data->{events_window} // "";
      my $start  = $data->{events_start}  // "";
      my $list   = $data->{events_list}   // "";

      readingsBulkUpdate($hash, "events_window", $window);
      readingsBulkUpdate($hash, "events_start",  $start);
      readingsBulkUpdate($hash, "events_list",   $list);
      readingsBulkUpdate($hash, "error", "");
      readingsBulkUpdate($hash, "state", "events updated");
    }
    readingsEndUpdate($hash,1);
  }
}
zum Auswerten der Returns kann ich die Kamera jetzt wunderbar steuern.
Die Python-Programme habe ich alle noch einmal grundlegend überarbeitet. Weil die relativ langsam laufen, erfolgt eine asychrone Rückmeldung an FHEM über einen REST-Call, FHEM wird also nicht blockiert. Alarm etc. lässt sich prima setzen, bei den Events muss man allerdings pollen - die werden über ONVIF nicht ausgegeben. Derzeit werden in FHEM jeweils die Events der letzten 5 Minuten angezeigt.

Jetzt könntet ihr mit dem Zeug erst einmal spielen. Die Doku im Wiki werde ich noch nachziehen, für heute habe ich allerdings genug  :P

LG

pah
#2
EnOcean / Aw: Schweigende FABH65S
Letzter Beitrag von hannsmattes - 20 März 2026, 17:01:51
Hei,

nach einem weiteren Tag in der Sonne und neuerlichem Anlernen verrichtet nun auch der zweite Sensor seinen Dienst. Warum das erst heute funktioniert, kann ich einstweilen nicht begründen - Hauptsache, er geht. Mal abwarten, ob der Standort (Nordseite unter einem ziemlich weit herausgezogenen Vordach) genug Licht für den Dauerbetrieb abwirft.

Beste Grüße

Hanns
#3
Verbrauchsmessung / Aw: HTTPMOD: Aktueller Strompr...
Letzter Beitrag von ch.eick - 20 März 2026, 16:49:37
Hallo rabehd,
in MySQL > V8 ist dieser Syntax bereits abgekündigt :-) , aber gut wenn es dann in MariaDB läuft.

Läuft der Rest mit dem "with" dann auch?
Welche MariaDb Version müsste dann verwendet werden?
#4
Verbrauchsmessung / Aw: HTTPMOD: Aktueller Strompr...
Letzter Beitrag von rabehd - 20 März 2026, 16:43:09
Zitat von: ch.eick am 20 März 2026, 10:02:50Es würde mich sehr freuen, wenn Du mir das dann getestet zusendest, dann würde ich im contrib zusätzlich das userReadings für MariaDB ablegen.

Ich habe alle Vorkommen ersetzt und keine Fehlermeldung mehr.

Aus:
AS new
WHERE TIMESTAMP >= CURDATE()
ON DUPLICATE KEY UPDATE
VALUE = new.VALUE;
wird:

WHERE TIMESTAMP >= CURDATE()
ON DUPLICATE KEY UPDATE
VALUE = VALUES(VALUE);
--AS new muss auch weg
#5
Sonstiges / Aw: Mein FHEM "hängt" sich bei...
Letzter Beitrag von hasselh - 20 März 2026, 16:13:57
OK, Ich hab's gefunden... mit Hilfe von:

perl -d:Trace fhem.pl fhem.cfg
tail -f /opt/fhem/log/fhem-YYYY-MM.log

Das Problem mit dem Einfrieren von FHEM liegt an einem sysread() Aufruf in der HttpUtils.pm, Zeile 601 (599 ist denke ich auch ein Kandidat). Hier der Trace:

>> FHEM/HttpUtils.pm:585:     if($@) {
>> FHEM/HttpUtils.pm:591:       $hash->{conn}->blocking(1);
>> /usr/lib/aarch64-linux-gnu/perl-base/IO/Socket.pm:174:     my $sock = shift;
>> /usr/lib/aarch64-linux-gnu/perl-base/IO/Socket.pm:176:     return $sock->SUPER::blocking(@_)
>> FHEM/HttpUtils.pm:592:       $usingSSL = 1;
>> FHEM/HttpUtils.pm:594:       if($hash->{hu_proxy}) {   # can block!
>> FHEM/HttpUtils.pm:595:         my $pw = AttrVal("global", "proxyAuth", "");
>> fhem.pl:4796:   my ($d,$n,$default) = @_;
>> fhem.pl:4797:   $n = resolveAttrRename($d, $n);
>> fhem.pl:4635:   my ($d,$n) = @_;
>> fhem.pl:4637:   return $n if(!$d || !$defs{$d});
>> fhem.pl:4638:   my $m = $modules{$defs{$d}{TYPE}};
>> fhem.pl:4639:   if($m->{AttrRenameMap} && defined($m->{AttrRenameMap}{$n})) {
>> fhem.pl:4644:   return $n;
>> fhem.pl:4798:   return $attr{$d}{$n} if(defined($attr{$d}) && defined($attr{$d}{$n}));
>> fhem.pl:4799:   return $default;
>> FHEM/HttpUtils.pm:596:         $pw = "Proxy-Authorization: Basic $pw\r\n" if($pw);
>> FHEM/HttpUtils.pm:597:         my $hdr = "CONNECT $hash->{host}:$hash->{hu_port} HTTP/1.0\r\n".
>> FHEM/HttpUtils.pm:599:         syswrite $hash->{conn}, $hdr;
>> FHEM/HttpUtils.pm:600:         my $buf;
>> FHEM/HttpUtils.pm:601:         my $len = sysread($hash->{conn},$buf,65536);

Danach bleibt der Log teilweise für 30-90 Sekunden stehen und FHEM ist in der Zeit auch nicht über telnet / WebBrowser erreichbar. Jetzt zu der Frage, wie man das Problem lösen/umgehen kann. Die Verwendung eines Proxys mit Whitelist, der bei mir auf der Firewall läuft, ist bei mir aus Sicherheitsgründen Pflicht...

Hallo @rudolfkoenig,

Lässt sich der Aufruf in der HttpUtils.pm evtl. in einen BlockingCall umwandeln ?
Könnte man alternativ dem sysread() einen timeout mitgeben ?
#6
FRITZ!Box / Aw: 72_FRITZBOX.pm wird zu 72_...
Letzter Beitrag von JoWiemann - 20 März 2026, 15:11:01
Hallo,

kann die angehängte Version bitte einmal jemand mit eine FritzBox mit Mobilempfang testen und mir bitte das Ergebnis von:get <DeviceName> tr064Command X_AVM-DE_WANMobileConnection:1 x_wanmobileconn GetInfoEx
zur Verfügung stellen.
Bitte vor dem Ausführen im Attribut setSubVerbose4 die Sub Fritz_SOAP_Request Auswählen. Nach dem Ausführen bitte einmal das Ergebnis und den Logauszug zur Verfügung stellen. Vielen Dank.

Grüße Jörg
#7
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von peterboeckmann - 20 März 2026, 14:27:59
Zitat von: DS_Starter am 20 März 2026, 14:19:41Hallo Peter,

checkin habe ich angefordert -> https://forum.fhem.de/index.php?msg=1359918

Die Icons gehören nach ../www/images/openautomation

Bzgl. Icon user_n_a schaue ich nochmal.
EDIT: Icon hier angehängt und checkin noch requested

Dankeschön!
Jetzt klappt alles.

Viele Grüße,
Peter
#8
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 20 März 2026, 14:19:41
Hallo Peter,

checkin habe ich angefordert -> https://forum.fhem.de/index.php?msg=1359918

Die Icons gehören nach ../www/images/openautomation

Bzgl. Icon user_n_a schaue ich nochmal.
EDIT: Icon hier angehängt und checkin noch requested
#9
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von peterboeckmann - 20 März 2026, 14:06:19
Hallo Heiko,

Zitat von: DS_Starter am 19 März 2026, 23:36:14Ach, da sind Icons nicht ausgeliefert. Ich werde morgen bitten einige neue Icons einzuchecken.
Hier angehängt das fehlende Teil.

ich und meine Ungeduld...
Wohin muss die Datei denn?
Und bei mir scheint auch noch die user_n_a zu fehlen, ggf. mehr, aber die sehe ich gerade auch nicht.

Ich habe die Datei unter Debian hier abgelegt: /opt/fhem/www/images/fhemSVG/weather
Dann als Owner den user fhem und die Gruppe dialout zugewiesen.
fhem neu gestartet hab ich auch.
Trotzdem wird es nicht angezeigt.

Viele Grüße,
Peter
#10
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 20 März 2026, 13:36:20
ZitatUnd für pvrl wird wohl nicht der Gesamtwert als Basis genommen, wie man im Reading Current_PV sieht (den hatte ich gestern als plausibel bei der Fehlersuche abgehakt), sondern die Summe aus pvrlXX (bei mir 01-03).
Ja, es ist die Summe aus pvrlXX. Es ist zu unterscheiden - pvrlXX = Ertrag in Wh vs. Current_PV = aktuelle Erzeugung in W. Das eine ist die Energie, das andere eine Leistung.
Die PV-Energie wird aus den Schlüsseln setupInverterDevXX->etotal abgeleitet und auf den in SF gültigen Stundentakt gerechnet. Die aktuelle PV Leistung aus setupInverterDevXX->pvOut gezogen/summiert.

ZitatNun die Frage, warum der Wert für den 3. Wechselrichter bei mir 0 ist, nicht wie bei 04 und 05 "-").
Es kommt darauf an, ob aus den in den setupInverterDevXX angebenen Device/Reading-Kombinationen Werte gelesen werden können. Wenn dies nicht klappt - oder nicht definiert ist - bleibt der Key undefiniert (-), was nicht zwangsläufig ein Fehler ist.

ZitatVor allem sehe ich auch in der Flussgrafik alle 3 Werte und die richtige Summe. Wird hier für die Anzeige in der Flussgrafik etwas anderes verwendet als für die Berechnung?
Grundsätzlich nicht. Nicht alle in der Flußgrafik verwendeten Werte sind auch als Reading verfügbar.

(Hat sich jetzt überschnitten)