httpmod.template: bugs, Fragen, Anregungen

Begonnen von Beta-User, 21 Februar 2019, 12:04:17

Vorheriges Thema - Nächstes Thema

kjmEjfu

Das tasmota_updates liefert mittlerweile einen Fehler im Log:

2022.07.07 10:56:16.752 1: PERL WARNING: Use of uninitialized value $dev in concatenation (.) or string at (eval 1613921) line 21.
2022.07.07 10:56:16.752 1: PERL WARNING: Use of uninitialized value in sprintf at (eval 1613921) line 22.
2022.07.07 10:56:16.753 1: PERL WARNING: Use of uninitialized value $old in sprintf at (eval 1613921) line 26.
2022.07.07 10:56:16.753 1: PERL WARNING: Use of uninitialized value $new in concatenation (.) or string at (eval 1613921) line 28.
2022.07.07 10:56:16.753 1: PERL WARNING: Use of uninitialized value $new in sprintf at (eval 1613921) line 30.
2022.07.07 10:56:16.753 1: PERL WARNING: Use of uninitialized value $new in concatenation (.) or string at (eval 1613921) line 32.
2022.07.07 10:56:16.753 1: PERL WARNING: Use of uninitialized value $date in sprintf at (eval 1613921) line 34.


Jemand eine Idee woran das liegt?
Migriere derzeit zu Home Assistant

rudolfkoenig

Nach "attr global stacktrace 1" weiss man mehr.

kjmEjfu

Zitat von: rudolfkoenig am 07 Juli 2022, 11:06:37
Nach "attr global stacktrace 1" weiss man mehr.

2022.07.07 11:32:33.681 1: PERL WARNING: Use of uninitialized value $dev in concatenation (.) or string at (eval 1626052) line 21.
2022.07.07 11:32:33.682 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.682 1: stacktrace:
2022.07.07 11:32:33.682 1:     main::__ANON__                      called by (eval 1626052) (21)
2022.07.07 11:32:33.682 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.682 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.682 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.682 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.682 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.682 1: PERL WARNING: Use of uninitialized value $d in hash element at fhem.pl line 4736.
2022.07.07 11:32:33.682 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.682 1: stacktrace:
2022.07.07 11:32:33.682 1:     main::__ANON__                      called by fhem.pl (4736)
2022.07.07 11:32:33.682 1:     main::AttrVal                       called by (eval 1626052) (22)
2022.07.07 11:32:33.682 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.683 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.683 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.683 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.683 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.683 1: PERL WARNING: Use of uninitialized value in sprintf at (eval 1626052) line 22.
2022.07.07 11:32:33.683 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.683 1: stacktrace:
2022.07.07 11:32:33.683 1:     main::__ANON__                      called by (eval 1626052) (22)
2022.07.07 11:32:33.683 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.683 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.683 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.683 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.683 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.683 1: PERL WARNING: Use of uninitialized value $d in hash element at fhem.pl line 4661.
2022.07.07 11:32:33.683 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.683 1: stacktrace:
2022.07.07 11:32:33.684 1:     main::__ANON__                      called by fhem.pl (4661)
2022.07.07 11:32:33.684 1:     main::ReadingsVal                   called by (eval 1626052) (25)
2022.07.07 11:32:33.684 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.684 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.684 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.684 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.684 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.684 1: PERL WARNING: Use of uninitialized value $d in hash element at fhem.pl line 4661.
2022.07.07 11:32:33.684 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.684 1: stacktrace:
2022.07.07 11:32:33.684 1:     main::__ANON__                      called by fhem.pl (4661)
2022.07.07 11:32:33.684 1:     main::ReadingsVal                   called by (eval 1626052) (25)
2022.07.07 11:32:33.684 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.684 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.684 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.684 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.684 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.684 1: PERL WARNING: Use of uninitialized value $old in sprintf at (eval 1626052) line 26.
2022.07.07 11:32:33.685 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.685 1: stacktrace:
2022.07.07 11:32:33.685 1:     main::__ANON__                      called by (eval 1626052) (26)
2022.07.07 11:32:33.685 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.685 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.685 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.685 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.685 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.685 1: PERL WARNING: Use of uninitialized value $new in concatenation (.) or string at (eval 1626052) line 28.
2022.07.07 11:32:33.685 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.685 1: stacktrace:
2022.07.07 11:32:33.685 1:     main::__ANON__                      called by (eval 1626052) (28)
2022.07.07 11:32:33.685 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.685 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.685 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.685 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.685 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.685 1: PERL WARNING: Use of uninitialized value $new in sprintf at (eval 1626052) line 30.
2022.07.07 11:32:33.685 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.685 1: stacktrace:
2022.07.07 11:32:33.685 1:     main::__ANON__                      called by (eval 1626052) (30)
2022.07.07 11:32:33.685 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.685 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.685 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.685 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.685 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.686 1: PERL WARNING: Use of uninitialized value $new in concatenation (.) or string at (eval 1626052) line 32.
2022.07.07 11:32:33.686 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.686 1: stacktrace:
2022.07.07 11:32:33.686 1:     main::__ANON__                      called by (eval 1626052) (32)
2022.07.07 11:32:33.686 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.686 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.686 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.686 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.686 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.686 1: PERL WARNING: Use of uninitialized value $date in sprintf at (eval 1626052) line 34.
2022.07.07 11:32:33.686 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;

2022.07.07 11:32:33.686 1: stacktrace:
2022.07.07 11:32:33.686 1:     main::__ANON__                      called by (eval 1626052) (34)
2022.07.07 11:32:33.686 1:     (eval)                              called by fhem.pl (4852)
2022.07.07 11:32:33.686 1:     main::evalStateFormat               called by fhem.pl (4957)
2022.07.07 11:32:33.686 1:     main::readingsEndUpdate             called by ./FHEM/98_HTTPMOD.pm (2437)
2022.07.07 11:32:33.686 1:     HTTPMOD::ReadCallback               called by FHEM/HttpUtils.pm (720)
2022.07.07 11:32:33.686 1:     main::__ANON__                      called by fhem.pl (778)
2022.07.07 11:32:33.686 1: PERL WARNING: Use of uninitialized value $dev in concatenation (.) or string at (eval 1626052) line 21.
2022.07.07 11:32:33.686 1: eval:  my $ret ="";;
    my $lastCheck = ReadingsTimestamp($name,"MATCHED_READINGS","???");;
    $ret .= '<div style="text-align:left;;">';;
    $ret .= 'last <a title="versions" href="https://github.com/arendst/Tasmota/releases" target="_blank">tasmota</a>-check => '.$lastCheck;;
    $ret .= '<br><br><pre>';;
    $ret .= "| device                           | current |   new   |  released  |<br>";;
    $ret .= "---------------------------------------------------------------------<br>";;
    my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;
    if($check eq "no updates needed!") {
      $ret .= '| <b style="color:green;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } elsif($check eq "error => no or wrong data from server!") {
      $ret .= '| <b style="color:red;;">';;
      $ret .= sprintf("%-65s",$check);;
      $ret .= '</b> |';;
    } else {
      my @devices = split(',',$check);;
      foreach my $devStr (@devices) {
        my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;
        $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;
        $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;
        $ret .= '</b></a> | ';;
        $ret .= '<b style="color:lightgray;;">';;
        $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"INFO2_IPAddress","0.0.0.0")).'/up" target="_blank">';;
        $ret .= sprintf("%7s",$old);;
        $ret .= '</a></b> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:red;;">';;
        $ret .= sprintf("%7s",$new);;
        $ret .= '</b></a> | ';;
        $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;
        $ret .= '<b style="color:black;;">';;
        $ret .= sprintf("%-10s",$date);;
        $ret .= '</b></a>';;
        $ret .= " |<br>";;
      }
    }
    $ret .= '</pre></div>';;
  return $ret;;


Geht noch ewig lang so weiter.
Stacktrace überfordert mich regelmäßig.
Migriere derzeit zu Home Assistant

rudolfkoenig

Der Inhalt des updatableDevices Readings entspricht nicht den Erwartungen des Programmes im stateFormat-Attribut.

Btw. stateFormat ist eher fuer Auswertung (wie abspeichern im FileLogs, auswerten in Apps, etc) gedacht, und nicht fuer die Anzeige im Browser. Dafuer sollte man devStateIcon verwenden.

kjmEjfu

Zitat von: rudolfkoenig am 07 Juli 2022, 12:33:15
Der Inhalt des updatableDevices Readings entspricht nicht den Erwartungen des Programmes im stateFormat-Attribut.

Btw. stateFormat ist eher fuer Auswertung (wie abspeichern im FileLogs, auswerten in Apps, etc) gedacht, und nicht fuer die Anzeige im Browser. Dafuer sollte man devStateIcon verwenden.

Ok, danke für den Hinweis.
Meine Tasmota-Devices waren noch nicht mit den neuesten Templates aufgestattet, da hat sich wohl was geändert.

Wegen stateFormat musst du den Template-Erstellern ins Gewissen reden, ich nutze das nur ;-)
Migriere derzeit zu Home Assistant

kjmEjfu

Die reading01Regex von tasmota_updates müsste mal angepasst werden.

tag-title">[\w\W]*?<a href=".*">[\w\W]*?v(\d*.\d*.\d*)[\w\W]*?</a>

Die Versionsnummer 24 auf https://github.com/arendst/Tasmota/tags bringt die Regex aus dem Tritt und liefert ein "c" zurück statt einer "12.0.2".

Migriere derzeit zu Home Assistant

OdfFhem

@kjmEjfu

Version 24, die eigentlich keine Version ist, sorgt für Durcheinander.
Mit der nächsten, hoffentlich richtigen Versionsnummer sollte wieder alles passen.

reading01Regex - leicht angepasst - könnte so aussehen:

tag-title">[\s\W]*?<a href=".*">[\s\W]*?v(\d+.\d+.\d+)[\s\W]*?</a>


reading01 für latestVersion holt die erste, wirklich passende Version ... 12.0.2
reading02 holt das Datum für latestDate vom 24er-Eintrag ... 20.06.2022 ... ist aber (zum Glück) identisch
reading03 holt die URL für latestHref vom 24er-Eintrag ... ist sichtbar falsch; stört aber nicht, da dieses Reading momentan nicht wirklich benötigt wird.

yersinia

@OdfFhem: wäre es sinnvoller auf https://api.github.com/repos/arendst/Tasmota/releases/latest zu wechseln? Liefert zwar ein Json zurück aber auch hier kann der tag des aktuellen Release ausgelesen werden - ich nutze das für einen gleichen JsonMod tasmota fw check.
viele Grüße, yersinia
----
FHEM 6.3 (SVN) on RPi 4B with RasPi OS Bullseye (perl 5.32.1) | FTUI
nanoCUL->2x868(1x ser2net)@tsculfw, 1x433@Sduino | MQTT2 | Tasmota | ESPEasy
VCCU->14xSEC-SCo, 7xCC-RT-DN, 5xLC-Bl1PBU-FM, 3xTC-IT-WM-W-EU, 1xPB-2-WM55, 1xLC-Sw1PBU-FM, 1xES-PMSw1-Pl

OdfFhem

@yersinia ... vielen Dank für Deinen Hinweis

Habe gestern Abend angefangen, die beiden Templates für Tasmota und zigbee2mqtt anzupassen und zu testen. Dabei nutze ich genau den von Dir genannten Link, da man hier wenig "erraten" muss ...

OdfFhem

#219
Nach der gestrigen Analyse der GitHub-Probleme habe ich begonnen, die veralteten Templates für tasmota sowie zigbee2mqtt anzupassen.

tasmota

#Contributed by OdfFHEM, see https://forum.fhem.de/index.php/topic,97694.msg992348.html#msg992348
name:tasmota_firmware_updates
filter:TYPE=HTTPMOD
desc: Check Tasmota homepage for available new firmware files<br>Define a HTTPMOD device like <br>define tasmotaupdates HTTPMOD https://github.com/arendst/Tasmota/tags 86400<a href="https://forum.fhem.de/index.php/topic,97694.msg992308.html#msg992308">Source: Forum</a>.
order:TECHZ06
par:WHICHROOM;Actual room of the device, defaults to HTTPMOD; {AttrVal("DEVICE","room","HTTPMOD" )}
par:UPDATABLEMODE;Actual mode for updatableDevices, defaults to onlyUpdatable; {AttrVal("DEVICE","updatableDevicesMode","onlyUpdatable")}
par:INTERVAL;Actual interval for updating, defaults to one week; {InternalVal("DEVICE","Interval","604800")}
defmod DEVICE HTTPMOD https://api.github.com/repos/arendst/Tasmota/releases/latest INTERVAL
attr DEVICE userattr reading01JSON reading01Name reading01OExpr reading02JSON reading02Name reading02OExpr updatableDevicesMode:onlyUpdatable,all
attr DEVICE enableControlSet 1
attr DEVICE event-on-change-reading .*
attr DEVICE event-on-update-reading LAST_ERROR,MATCHED_READINGS
attr DEVICE handleRedirects 0
deleteattr DEVICE reading01Regex
attr DEVICE reading01JSON tag_name
attr DEVICE reading01Name latestVersion
attr DEVICE reading01OExpr $val =~ m/^v(\d+).(\d+).(\d+)$/ ;; "$1.$2.$3"
deleteattr DEVICE reading02Regex
attr DEVICE reading02JSON published_at
attr DEVICE reading02Name latestDate
attr DEVICE reading02OExpr $val =~ m/^(.{4})-(.{2})-(.{2})T..:..:..Z$/ ;; "$3.$2.$1"
attr DEVICE showError 1
attr DEVICE showMatched 1
attr DEVICE stateFormat { \
  my $ret ="";;\
  $ret .= '<div style="text-align:left;;">';;\
  my $lastCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(time_str2num(ReadingsTimestamp($name,"MATCHED_READINGS","1970-01-01 00:00:00"))));;\
  $ret .= '<div style="text-align:left;;">last <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">tasmota</a>-check => '.$lastCheck.' ...</div>';;\
  $ret .= '<br><pre>';;\
  $ret .= "| device                           | current |   new   |  released  |<br>";;\
  $ret .= "---------------------------------------------------------------------<br>";;\
  my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;\
  if($check eq "no updates needed!") {\
    $ret .= '| <b style="color:green;;">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } elsif($check eq "error => no or wrong data from server!") {\
    $ret .= '| <b style="color:red;;">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } else {\
    my @devices = split(',',$check);;\
    foreach my $devStr (@devices) {\
      my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;\
      $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;\
      $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;\
      $ret .= '</b></a> | ';;\
      $ret .= '<b style="color:lightgray;;">';;\
      $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"Info2_IPAddress","0.0.0.0")).'/up" target="_blank">';;\
      $ret .= sprintf("%7s",$old);;\
      $ret .= '</a></b> | ';;\
      $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;\
      $ret .= '<b style="color:red;;">';;\
      $ret .= sprintf("%7s",$new);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;\
      $ret .= '<b style="color:black;;">';;\
      $ret .= sprintf("%-10s",$date);;\
      $ret .= '</b></a>';;\
      $ret .= " |<br>";;\
    }\
  }\
  $ret .= '</pre><br>';;\
  my $nextCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(InternalVal($name,".TRIGGERTIME",0)));;\
  $ret .= '<div style="text-align:left;;">... next <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">tasmota</a>-check => '.$nextCheck.'</div>';;\
  $ret .= '</div>';;\
  return $ret;;\
}
attr DEVICE timestamp-on-change-reading .*
attr DEVICE updatableDevicesMode UPDATABLEMODE
attr DEVICE userReadings updatableDevices:MATCHED_READINGS.* {\
  my $ret = "";;\
  if (ReadingsVal($name,"MATCHED_READINGS","") eq "") {\
    $ret = "error => no or wrong data from server!";;\
  } else {\
    my $VERSION = ReadingsVal($name,"latestVersion","unknown");;\
    my $DATE = ReadingsVal($name,"latestDate","unknown");;\
    foreach my $dev (devspec2array("TYPE=MQTT[2]?_[D]EVICE:FILTER=Info1_Version!=")) {\
      my $version = ReadingsVal($dev,"Version",ReadingsVal($dev,"Info1_Version","0.0.0"));;\
      $version =~ m/([0-9.]*).*/;;\
      $version = $1;;\
      if ( AttrVal($name,"updatableDevicesMode","onlyUpdatable") eq "all" || $version ne $VERSION ) {\
        $ret .= "," if($ret ne "");;\
        $ret .= $dev." (".$version." | ".$VERSION." | ".$DATE.")";;\
      }\
    }\
  }\
  return ($ret eq "")?"no updates needed!":$ret;;\
}
attr DEVICE webCmd reread
attr DEVICE room WHICHROOM
attr DEVICE model tasmota_firmware_updates
setreading DEVICE attrTemplateVersion 20220807


zigbee2mqtt

#Contributed by OdfFHEM, see https://forum.fhem.de/index.php/topic,97694.msg998835.html#msg998835
name:zigbee2mqtt_daemon_updates
filter:TYPE=HTTPMOD
desc: Check zigbee2mqtt homepage for new versions of the deamon software.<br>Define a HTTPMOD device like <br>define zigbee2mqtt_updates HTTPMOD https://github.com/Koenkk/zigbee2mqtt/tags 604800<br><a href="https://forum.fhem.de/index.php/topic,97694.msg998835.html#msg998835">Source: Forum</a>.
order:TECHZ07
par:WHICHROOM;Actual room of the device, defaults to HTTPMOD; {AttrVal("DEVICE","room","HTTPMOD" )}
par:INTERVAL;Actual interval for updating, defaults to one day; {InternalVal("DEVICE","Interval",604800)}
par:UPDATABLEMODE;Actual mode for updatableDevices, defaults to onlyUpdatable; {AttrVal("DEVICE","updatableDevicesMode","onlyUpdatable")}
defmod DEVICE HTTPMOD https://api.github.com/repos/Koenkk/zigbee2mqtt/releases/latest INTERVAL
attr DEVICE userattr reading01JSON reading01Name reading01OExpr reading02JSON reading02Name reading02OExpr updatableDevicesMode:onlyUpdatable,all
attr DEVICE enableControlSet 1
attr DEVICE event-on-change-reading .*
attr DEVICE event-on-update-reading LAST_ERROR,MATCHED_READINGS
attr DEVICE handleRedirects 0
deleteattr DEVICE reading01Regex
attr DEVICE reading01JSON tag_name
attr DEVICE reading01Name latestVersion
attr DEVICE reading01OExpr $val =~ m/^(\d+).(\d+).(\d+)$/ ;; "$1.$2.$3"
deleteattr DEVICE reading02Regex
attr DEVICE reading02JSON published_at
attr DEVICE reading02Name latestDate
attr DEVICE reading02OExpr $val =~ m/^(.{4})-(.{2})-(.{2})T..:..:..Z$/ ;; "$3.$2.$1"
attr DEVICE showError 1
attr DEVICE showMatched 1
attr DEVICE stateFormat { \
  my $ret ="";;\
  $ret .= '<div style="text-align:left">';;\
  my $lastCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(time_str2num(ReadingsTimestamp($name,"MATCHED_READINGS","1970-01-01 00:00:00"))));;\
  $ret .= '<div style="text-align:left;;">last <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">zigbee2mqtt</a>-check => '.$lastCheck.' ...</div>';;\
  $ret .= '<br><pre>';;\
  $ret .= "| device                           | current |   new   |  released  |<br>";;\
  $ret .= "---------------------------------------------------------------------<br>";;\
  my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;\
  if($check eq "no updates needed!") {\
    $ret .= '| <b style="color:green">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } elsif($check eq "error => no or wrong data from server!") {\
    $ret .= '| <b style="color:red">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } else {\
    my @devices = split(',',$check);;\
    foreach my $devStr (@devices) {\
      my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;\
      $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;\
      $ret .= sprintf("%-32s",$dev);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<b style="color:lightgray">';;\
      $ret .= sprintf("%7s",$old);;\
      $ret .= '</b> | ';;\
      $ret .= '<a href="https://github.com/Koenkk/zigbee2mqtt/releases/tag/'.$new.'">';;\
      $ret .= '<b style="color:'.(($new eq $old)?'black':'red').'">';;\
      $ret .= sprintf("%7s",$new);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<a href="https://github.com/Koenkk/zigbee2mqtt/releases/tag/'.$new.'">';;\
      $ret .= '<b style="color:black">';;\
      $ret .= sprintf("%-10s",$date);;\
      $ret .= '</b></a>';;\
      $ret .= " |<br>";;\
    }\
  }\
  $ret .= '</pre><br>';;\
  my $nextCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(InternalVal($name,".TRIGGERTIME",0)));;\
  $ret .= '<div style="text-align:left;;">... next <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">zigbee2mqtt</a>-check => '.$nextCheck.'</div>';;\
  $ret .= '</div>';;\
  return $ret;;\
}
attr DEVICE updatableDevicesMode UPDATABLEMODE
attr DEVICE timestamp-on-change-reading .*
attr DEVICE userReadings updatableDevices:MATCHED_READINGS.* {\
  my $ret = "";;\
  if (ReadingsVal($name,"MATCHED_READINGS","") eq "") {\
    $ret = "error => no or wrong data from server!";;\
  } else {\
    my $VERSION = ReadingsVal($name,"latestVersion","unknown");;\
    my $DATE = ReadingsVal($name,"latestDate","unknown");;\
    foreach my $dev (devspec2array("TYPE=MQTT[2]?_[D]EVICE:FILTER=NAME=.*zigbee.*bridge.*")) {\
      my $version = ReadingsVal($dev,"version","0.0.0");;\
      $version =~ m/([0-9.]*).*/;;\
      $version = $1;;\
      if (AttrVal($name,"updatableDevicesMode","onlyUpdatable") eq "all" || $version ne $VERSION) {\
        $ret .= "," if($ret ne "");;\
        $ret .= $dev." (".$version." | ".$VERSION." | ".$DATE.")";;\
      }\
    }\
  }\
  return ($ret eq "")?"no updates needed!":$ret;;\
}
attr DEVICE webCmd reread
attr DEVICE room WHICHROOM
attr DEVICE model zigbee2mqtt_daemon_updates
setreading DEVICE attrTemplateVersion 20220807



Den Parameter UPDATABLEDEVICESMODE in UPDATABLEMODE umbenannt; ansonsten verhindert die DEVICE-Ersetzung einen sinnvolle Attribut-Vorbelegung.
Frage dazu - insbesondere an @Beta-User: Gibt es eine Möglichkeit DEVICE in einem solchen Fall zu neutralisieren ?

Bei der Testung vom angepassten zigbee2mqtt_daemon_updates wurde ständig ein harter Fehler "Unknown command <a" generiert. Zunächst dachte ich, dass es am Inhalt von stateFormat liegt, am Ende waren es aber dann folgende Zeilen:

desc: Check zigbee2mqtt homepage for new versions of the deamon software.<br>Define a HTTPMOD device like <br>define zigbee2mqtt_updates HTTPMOD https://github.com/Koenkk/zigbee2mqtt/tags 604800<br>
<a href="https://forum.fhem.de/index.php/topic,97694.msg998835.html#msg998835">Source: Forum</a>.

desc darf wohl nur aus einer Zeile bestehen - wie alle anderen Angaben auch.

Jeweils die <devspec> an die aktuell gebräuchlichen Verhältnisse angepasst.

deleteattr verwendet, um störende Altlasten loszuwerden.


Bei meinen Tests scheint alles zu funktionieren, aber wie immer: Machen Andere die gleiche Erfahrung oder gibt es Probleme ?
@yersinia ... Vielleicht hast Du ja Lust für einen praktischen Test ...


@Beta-User ... Sollte es keine Probleme geben, kannst Du die angepassten Versionen übernehmen ?


@rudolfkoenig ... Demnächst würde ich auch mal das devStateIcon-Attribut antesten ...

rudolfkoenig

Zitat@rudolfkoenig ... Demnächst würde ich auch mal das devStateIcon-Attribut antesten ...
Muss ich dafuer was tun, oder ist das als Drohung zu verstehen ? :)

yersinia

Zitat von: rudolfkoenig am 08 August 2022, 08:15:18
Muss ich dafuer was tun, oder ist das als Drohung zu verstehen ? :)
+1 für Drohung. ;D

Zitat von: OdfFhem am 07 August 2022, 22:59:30tasmota

#Contributed by OdfFHEM, see https://forum.fhem.de/index.php/topic,97694.msg992348.html#msg992348
name:tasmota_firmware_updates
filter:TYPE=HTTPMOD
desc: Check Tasmota homepage for available new firmware files<br>Define a HTTPMOD device like <br>define tasmotaupdates HTTPMOD https://github.com/arendst/Tasmota/tags 86400<a href="https://forum.fhem.de/index.php/topic,97694.msg992308.html#msg992308">Source: Forum</a>.
order:TECHZ06
par:WHICHROOM;Actual room of the device, defaults to HTTPMOD; {AttrVal("DEVICE","room","HTTPMOD" )}
par:UPDATABLEMODE;Actual mode for updatableDevices, defaults to onlyUpdatable; {AttrVal("DEVICE","updatableDevicesMode","onlyUpdatable")}
par:INTERVAL;Actual interval for updating, defaults to one week; {InternalVal("DEVICE","Interval","604800")}
defmod DEVICE HTTPMOD https://api.github.com/repos/arendst/Tasmota/releases/latest INTERVAL
attr DEVICE userattr reading01JSON reading01Name reading01OExpr reading02JSON reading02Name reading02OExpr updatableDevicesMode:onlyUpdatable,all
attr DEVICE enableControlSet 1
attr DEVICE event-on-change-reading .*
attr DEVICE event-on-update-reading LAST_ERROR,MATCHED_READINGS
attr DEVICE handleRedirects 0
deleteattr DEVICE reading01Regex
attr DEVICE reading01JSON tag_name
attr DEVICE reading01Name latestVersion
attr DEVICE reading01OExpr $val =~ m/^v(\d+).(\d+).(\d+)$/ ;; "$1.$2.$3"
deleteattr DEVICE reading02Regex
attr DEVICE reading02JSON published_at
attr DEVICE reading02Name latestDate
attr DEVICE reading02OExpr $val =~ m/^(.{4})-(.{2})-(.{2})T..:..:..Z$/ ;; "$3.$2.$1"
attr DEVICE showError 1
attr DEVICE showMatched 1
attr DEVICE stateFormat { \
  my $ret ="";;\
  $ret .= '<div style="text-align:left;;">';;\
  my $lastCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(time_str2num(ReadingsTimestamp($name,"MATCHED_READINGS","1970-01-01 00:00:00"))));;\
  $ret .= '<div style="text-align:left;;">last <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">tasmota</a>-check => '.$lastCheck.' ...</div>';;\
  $ret .= '<br><pre>';;\
  $ret .= "| device                           | current |   new   |  released  |<br>";;\
  $ret .= "---------------------------------------------------------------------<br>";;\
  my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;\
  if($check eq "no updates needed!") {\
    $ret .= '| <b style="color:green;;">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } elsif($check eq "error => no or wrong data from server!") {\
    $ret .= '| <b style="color:red;;">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } else {\
    my @devices = split(',',$check);;\
    foreach my $devStr (@devices) {\
      my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;\
      $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;\
      $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;\
      $ret .= '</b></a> | ';;\
      $ret .= '<b style="color:lightgray;;">';;\
      $ret .= '<a href="http://'.ReadingsVal($dev,"IPAddress",ReadingsVal($dev,"Info2_IPAddress","0.0.0.0")).'/up" target="_blank">';;\
      $ret .= sprintf("%7s",$old);;\
      $ret .= '</a></b> | ';;\
      $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;\
      $ret .= '<b style="color:red;;">';;\
      $ret .= sprintf("%7s",$new);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'">';;\
      $ret .= '<b style="color:black;;">';;\
      $ret .= sprintf("%-10s",$date);;\
      $ret .= '</b></a>';;\
      $ret .= " |<br>";;\
    }\
  }\
  $ret .= '</pre><br>';;\
  my $nextCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(InternalVal($name,".TRIGGERTIME",0)));;\
  $ret .= '<div style="text-align:left;;">... next <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">tasmota</a>-check => '.$nextCheck.'</div>';;\
  $ret .= '</div>';;\
  return $ret;;\
}
attr DEVICE timestamp-on-change-reading .*
attr DEVICE updatableDevicesMode UPDATABLEMODE
attr DEVICE userReadings updatableDevices:MATCHED_READINGS.* {\
  my $ret = "";;\
  if (ReadingsVal($name,"MATCHED_READINGS","") eq "") {\
    $ret = "error => no or wrong data from server!";;\
  } else {\
    my $VERSION = ReadingsVal($name,"latestVersion","unknown");;\
    my $DATE = ReadingsVal($name,"latestDate","unknown");;\
    foreach my $dev (devspec2array("TYPE=MQTT[2]?_[D]EVICE:FILTER=Info1_Version!=")) {\
      my $version = ReadingsVal($dev,"Version",ReadingsVal($dev,"Info1_Version","0.0.0"));;\
      $version =~ m/([0-9.]*).*/;;\
      $version = $1;;\
      if ( AttrVal($name,"updatableDevicesMode","onlyUpdatable") eq "all" || $version ne $VERSION ) {\
        $ret .= "," if($ret ne "");;\
        $ret .= $dev." (".$version." | ".$VERSION." | ".$DATE.")";;\
      }\
    }\
  }\
  return ($ret eq "")?"no updates needed!":$ret;;\
}
attr DEVICE webCmd reread
attr DEVICE room WHICHROOM
attr DEVICE model tasmota_firmware_updates
setreading DEVICE attrTemplateVersion 20220807

[...]
@yersinia ... Vielleicht hast Du ja Lust für einen praktischen Test ...
Ich nutze zwar mittlerweile nur noch JsonMod dafür, aber ich teste das hier gern. Und es läuft soweit ganz gut - mit kleineren Verbesserungsvorschlägen noch besser:
- kannst du den Hyperlinks hinter der neuen Version und dem Release-Datum ein target="_blank" verpassen, dadurch öffnet sich der link nicht in dem gleichen Tab/Fenster
- das release datum ist schlecht zu lesen wenn man -so wie ich- einen Dark-style nutzt, vlt lässt du das style="color:black;" hier weg
Danke für deine Mühe, sieht sonst wirklich gut aus.
viele Grüße, yersinia
----
FHEM 6.3 (SVN) on RPi 4B with RasPi OS Bullseye (perl 5.32.1) | FTUI
nanoCUL->2x868(1x ser2net)@tsculfw, 1x433@Sduino | MQTT2 | Tasmota | ESPEasy
VCCU->14xSEC-SCo, 7xCC-RT-DN, 5xLC-Bl1PBU-FM, 3xTC-IT-WM-W-EU, 1xPB-2-WM55, 1xLC-Sw1PBU-FM, 1xES-PMSw1-Pl

Beta-User

Zitat von: OdfFhem am 07 August 2022, 22:59:30
@Beta-User ... Sollte es keine Probleme geben, kannst Du die angepassten Versionen übernehmen ?
Moin, ich gehe mal davon aus, dass amenomade einfach grade länger im Urlaub ist und das dann irgendwann gerne machen wird:
Zitat von: amenomade am 08 September 2020, 01:13:30
Und da ich jetzt in Abstimmung mit Beta-User die Maintenance für httpmod.template übernommen habe, habe ich es gerade auch eingecheckt.

Zitat von: OdfFhem am 07 August 2022, 22:59:30
Den Parameter UPDATABLEDEVICESMODE in UPDATABLEMODE umbenannt; ansonsten verhindert die DEVICE-Ersetzung einen sinnvolle Attribut-Vorbelegung.
Frage dazu - insbesondere an @Beta-User: Gibt es eine Möglichkeit DEVICE in einem solchen Fall zu neutralisieren ?
DEVICE (genauer: alle par:-Parameter) kann/muss man "escapen". So sollte es funktionieren:
UPDATABLE\DEVICESMODE
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

OdfFhem

Zitat von: rudolfkoenig am 08 August 2022, 08:15:18
Muss ich dafuer was tun, oder ist das als Drohung zu verstehen ? :)

Nein, in keinster Weise eine Drohung ... sollte eigentlich eher eine Art Info sein, dass Deine Empfehlung ernst genommen wird.

Da ich das devStateIcon-Attribut schon an einigen Stellen nutze, denke ich momentan, dass Du vermutlich nichts erweitern musst. Aber ich kann mich natürlich auch irren ...

OdfFhem

@yersinia ... schon mal vielen Dank fürs Testen sowie die Verbesserungsvorschläge

Beide Templates noch ein wenig überarbeitet/getestet und Deine Vorschläge einfliessen lassen.

tasmota

#Contributed by OdfFHEM, see https://forum.fhem.de/index.php/topic,97694.msg992348.html#msg992348
name:tasmota_firmware_updates
filter:TYPE=HTTPMOD
desc: Check Tasmota homepage for available new firmware files<br>Define a HTTPMOD device like <br>define tasmotaupdates HTTPMOD https://github.com/arendst/Tasmota/tags 86400<a href="https://forum.fhem.de/index.php/topic,97694.msg992308.html#msg992308">Source: Forum</a>.
order:TECHZ06
par:WHICHROOM;Actual room of the device, defaults to HTTPMOD; {AttrVal("DEVICE","room","HTTPMOD" )}
par:UPDATABLEMODE;Actual mode for updatableDevices, defaults to onlyUpdatable; {AttrVal("DEVICE","updatableDevicesMode","onlyUpdatable")}
par:INTERVAL;Actual interval for updating, defaults to one week; {InternalVal("DEVICE","Interval","604800")}
defmod DEVICE HTTPMOD https://api.github.com/repos/arendst/Tasmota/releases/latest INTERVAL
attr DEVICE userattr reading01JSON reading01Name reading01OExpr reading02JSON reading02Name reading02OExpr updatableDevicesMode:onlyUpdatable,all
attr DEVICE enableControlSet 1
attr DEVICE event-on-change-reading .*
attr DEVICE event-on-update-reading LAST_ERROR,MATCHED_READINGS
attr DEVICE handleRedirects 0
deleteattr DEVICE reading01Regex
attr DEVICE reading01JSON tag_name
attr DEVICE reading01Name latestVersion
attr DEVICE reading01OExpr $val =~ m/^v(\d+).(\d+).(\d+)$/ ;; "$1.$2.$3"
deleteattr DEVICE reading02Regex
attr DEVICE reading02JSON published_at
attr DEVICE reading02Name latestDate
attr DEVICE reading02OExpr $val =~ m/^(.{4})-(.{2})-(.{2})T..:..:..Z$/ ;; "$3.$2.$1"
attr DEVICE showError 1
attr DEVICE showMatched 1
attr DEVICE stateFormat { \
  my $ret ="";;\
  $ret .= '<div style="text-align:left;;">';;\
  my $lastCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(time_str2num(ReadingsTimestamp($name,"MATCHED_READINGS","1970-01-01 00:00:00"))));;\
  $ret .= '<div style="text-align:left;;">last <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">tasmota</a>-check => '.$lastCheck.' ...</div>';;\
  $ret .= '<br><pre>';;\
  $ret .= "| device                           | current |   new   |  released  |<br>";;\
  $ret .= "---------------------------------------------------------------------<br>";;\
  my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;\
  if($check eq "no updates needed!") {\
    $ret .= '| <b style="color:green;;">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } elsif($check eq "error => no or wrong data from server!") {\
    $ret .= '| <b style="color:red;;">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } else {\
    my @devices = split(',',$check);;\
    foreach my $devStr (@devices) {\
      my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;\
      $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;\
      $ret .= sprintf("%-32s",AttrVal($dev,"alias",$dev));;\
      $ret .= '</b></a> | ';;\
      $ret .= '<b style="color:lightgray;;">';;\
      $ret .= '<a href="http://'.ReadingsVal($dev,"Info2_IPAddress",ReadingsVal($dev,"INFO2_IPAddress",ReadingsVal($dev,"IPAddress","0.0.0.0"))).'/up" target="_blank">';;\
      $ret .= sprintf("%7s",$old);;\
      $ret .= '</a></b> | ';;\
      $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'" target="_blank">';;\
      $ret .= '<b style="color:red;;">';;\
      $ret .= sprintf("%7s",$new);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<a href="https://github.com/arendst/Tasmota/releases/tag/v'.$new.'" target="_blank">';;\
      $ret .= '<b>';;\
      $ret .= sprintf("%-10s",$date);;\
      $ret .= '</b></a>';;\
      $ret .= " |<br>";;\
    }\
  }\
  $ret .= '</pre><br>';;\
  my $nextCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(InternalVal($name,".TRIGGERTIME",0)));;\
  $ret .= '<div style="text-align:left;;">... next <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">tasmota</a>-check => '.$nextCheck.'</div>';;\
  $ret .= '</div>';;\
  return $ret;;\
}
attr DEVICE timestamp-on-change-reading .*
attr DEVICE updatableDevicesMode UPDATABLEMODE
attr DEVICE userReadings updatableDevices:MATCHED_READINGS.* {\
  my $ret = "";;\
  if (ReadingsVal($name,"MATCHED_READINGS","") eq "") {\
    $ret = "error => no or wrong data from server!";;\
  } else {\
    my $VERSION = ReadingsVal($name,"latestVersion","unknown");;\
    my $DATE = ReadingsVal($name,"latestDate","unknown");;\
    foreach my $dev (devspec2array("TYPE=MQTT[2]?_[D]EVICE:FILTER=readingList~.*tele[/].*INFO.*")) {\
      my $version = ReadingsVal($dev,"Info1_Version",ReadingsVal($dev,"INFO1_Version",ReadingsVal($dev,"Version","0.0.0")));;\
      $version =~ m/([0-9.]*).*/;;\
      $version = $1;;\
      if ( AttrVal($name,"updatableDevicesMode","onlyUpdatable") eq "all" || $version ne $VERSION ) {\
        $ret .= "," if($ret ne "");;\
        $ret .= $dev." (".$version." | ".$VERSION." | ".$DATE.")";;\
      }\
    }\
  }\
  return ($ret eq "")?"no updates needed!":$ret;;\
}
attr DEVICE webCmd reread
attr DEVICE room WHICHROOM
attr DEVICE model tasmota_firmware_updates
setreading DEVICE attrTemplateVersion 20220808


zigbee2mqtt

#Contributed by OdfFHEM, see https://forum.fhem.de/index.php/topic,97694.msg998835.html#msg998835
name:zigbee2mqtt_daemon_updates
filter:TYPE=HTTPMOD
desc: Check zigbee2mqtt homepage for new versions of the deamon software.<br>Define a HTTPMOD device like <br>define zigbee2mqtt_updates HTTPMOD https://github.com/Koenkk/zigbee2mqtt/tags 604800<br><a href="https://forum.fhem.de/index.php/topic,97694.msg998835.html#msg998835">Source: Forum</a>.
order:TECHZ07
par:WHICHROOM;Actual room of the device, defaults to HTTPMOD; {AttrVal("DEVICE","room","HTTPMOD" )}
par:INTERVAL;Actual interval for updating, defaults to one day; {InternalVal("DEVICE","Interval",604800)}
par:UPDATABLEMODE;Actual mode for updatableDevices, defaults to onlyUpdatable; {AttrVal("DEVICE","updatableDevicesMode","onlyUpdatable")}
defmod DEVICE HTTPMOD https://api.github.com/repos/Koenkk/zigbee2mqtt/releases/latest INTERVAL
attr DEVICE userattr reading01JSON reading01Name reading01OExpr reading02JSON reading02Name reading02OExpr updatableDevicesMode:onlyUpdatable,all
attr DEVICE enableControlSet 1
attr DEVICE event-on-change-reading .*
attr DEVICE event-on-update-reading LAST_ERROR,MATCHED_READINGS
attr DEVICE handleRedirects 0
deleteattr DEVICE reading01Regex
attr DEVICE reading01JSON tag_name
attr DEVICE reading01Name latestVersion
attr DEVICE reading01OExpr $val =~ m/^(\d+).(\d+).(\d+)$/ ;; "$1.$2.$3"
deleteattr DEVICE reading02Regex
attr DEVICE reading02JSON published_at
attr DEVICE reading02Name latestDate
attr DEVICE reading02OExpr $val =~ m/^(.{4})-(.{2})-(.{2})T..:..:..Z$/ ;; "$3.$2.$1"
attr DEVICE showError 1
attr DEVICE showMatched 1
attr DEVICE stateFormat { \
  my $ret ="";;\
  $ret .= '<div style="text-align:left">';;\
  my $lastCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(time_str2num(ReadingsTimestamp($name,"MATCHED_READINGS","1970-01-01 00:00:00"))));;\
  $ret .= '<div style="text-align:left;;">last <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">zigbee2mqtt</a>-check => '.$lastCheck.' ...</div>';;\
  $ret .= '<br><pre>';;\
  $ret .= "| device                           | current |   new   |  released  |<br>";;\
  $ret .= "---------------------------------------------------------------------<br>";;\
  my $check = ReadingsVal($name,"updatableDevices","error => no or wrong data from server!");;\
  if($check eq "no updates needed!") {\
    $ret .= '| <b style="color:green">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } elsif($check eq "error => no or wrong data from server!") {\
    $ret .= '| <b style="color:red">';;\
    $ret .= sprintf("%-65s",$check);;\
    $ret .= '</b> |';;\
  } else {\
    my @devices = split(',',$check);;\
    foreach my $devStr (@devices) {\
      my ($dev,$old,$new,$date) = $devStr =~ m/^([^\s]+)\s\(([^\s]+)\s\|\s([^\s]+)\s\|\s([^\)]+)\)$/;;\
      $ret .= '| <a href="/fhem?detail='.$dev.'"><b>';;\
      $ret .= sprintf("%-32s",$dev);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<b style="color:lightgray">';;\
      $ret .= sprintf("%7s",$old);;\
      $ret .= '</b> | ';;\
      $ret .= '<a href="https://github.com/Koenkk/zigbee2mqtt/releases/tag/'.$new.'" target="_blank">';;\
      $ret .= '<b style="color:'.(($new eq $old)?'black':'red').'">';;\
      $ret .= sprintf("%7s",$new);;\
      $ret .= '</b></a> | ';;\
      $ret .= '<a href="https://github.com/Koenkk/zigbee2mqtt/releases/tag/'.$new.'" target="_blank">';;\
      $ret .= '<b>';;\
      $ret .= sprintf("%-10s",$date);;\
      $ret .= '</b></a>';;\
      $ret .= " |<br>";;\
    }\
  }\
  $ret .= '</pre><br>';;\
  my $nextCheck = POSIX::strftime("%d.%m.%Y, %H:%M",localtime(InternalVal($name,".TRIGGERTIME",0)));;\
  $ret .= '<div style="text-align:left;;">... next <a title="versions" href="'.InternalVal($name,"MainURL","unknown").'" target="_blank">zigbee2mqtt</a>-check => '.$nextCheck.'</div>';;\
  $ret .= '</div>';;\
  return $ret;;\
}
attr DEVICE updatableDevicesMode UPDATABLEMODE
attr DEVICE timestamp-on-change-reading .*
attr DEVICE userReadings updatableDevices:MATCHED_READINGS.* {\
  my $ret = "";;\
  if (ReadingsVal($name,"MATCHED_READINGS","") eq "") {\
    $ret = "error => no or wrong data from server!";;\
  } else {\
    my $VERSION = ReadingsVal($name,"latestVersion","unknown");;\
    my $DATE = ReadingsVal($name,"latestDate","unknown");;\
    foreach my $dev (devspec2array("TYPE=MQTT[2]?_[D]EVICE:FILTER=NAME=.*zigbee.*bridge.*")) {\
      my $version = ReadingsVal($dev,"version","0.0.0");;\
      $version =~ m/([0-9.]*).*/;;\
      $version = $1;;\
      if (AttrVal($name,"updatableDevicesMode","onlyUpdatable") eq "all" || $version ne $VERSION) {\
        $ret .= "," if($ret ne "");;\
        $ret .= $dev." (".$version." | ".$VERSION." | ".$DATE.")";;\
      }\
    }\
  }\
  return ($ret eq "")?"no updates needed!":$ret;;\
}
attr DEVICE webCmd reread
attr DEVICE room WHICHROOM
attr DEVICE model zigbee2mqtt_daemon_updates
setreading DEVICE attrTemplateVersion 20220808



@all
Da man insbesondere bei Tasmota drei Entwicklungsstände unterstützen will/sollte, bin ich beim devspec auch auf readingList ausgewichen.
Gäbe es eigentlich eine Möglichkeit, alle Geräte mittels list aufzuführen, die eins von drei möglichen Readings haben ?
(heisst übersetzt: ein qualifiziertes DEVICE hat entweder ein Reading namens Version oder INFO1_Version oder Info1_Version)