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:downund einem DOIFdefmod 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,3sowie zwei verschiedenen Perl-Funktionensub 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.
, aber gut wenn es dann in MariaDB läuft.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.
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 wegperl -d:Trace fhem.pl fhem.cfg
tail -f /opt/fhem/log/fhem-YYYY-MM.log
>> 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);
get <DeviceName> tr064Command X_AVM-DE_WANMobileConnection:1 x_wanmobileconn GetInfoEx
zur Verfügung stellen.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
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.
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.
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.