Hauptmenü

Perl Modulhilfe erbeten

Begonnen von bgewehr, 19 Januar 2016, 21:05:37

Vorheriges Thema - Nächstes Thema

bgewehr

Hallo!

Mein Volkszaehler Modul ist eigentlich so ganz OK, läuft nun schon lange stabil.

Wenn aber die Antwort der Web-Abfrage in der Variable $state oder $last 0 ist, dann wird kein Wert in das Reading state geschrieben. Wie kann ich den Code so ändern, dass auch null als Wert angesehen und ins Reading übernommen wird?

Dass der null Wert korrekt vom Volkszaehler geliefert wird, habe ich per Browserabfrage geprüft:

{"version":"0.3","data":{"tuples":[[1453234373956,0,2]],"uuid":"8102dbc0-6fcd-11e2-a8b7-a1307aa80770","from":1453234253938,"to":1453234373956,"min":[1453234373956,0],"max":[1453234373956,0],"average":0,"consumption":0,"rows":1}}


Es handelt sich um die null hinter tuples.

Dank Euch!

Gruß Bernd


################################################################
#
#  Copyright notice
#
#  (c) 2013 Bernd Gewehr
#
#  This script is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  The GNU General Public License can be found at
#  http://www.gnu.org/copyleft/gpl.html.
#  A copy is found in the textfile GPL.txt and important notices to the license
#  from the author is found in LICENSE.txt distributed with these scripts.
#
#  This script is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  This copyright notice MUST APPEAR in all copies of the script!
#
################################################################
# $Id:$
################################################################
package main;

use strict;
use warnings;
use JSON;
use Time::Piece;
use Data::Dumper;
use LWP::UserAgent;
use HTTP::Request;

sub
VOLKSZAEHLER_Initialize($)
{
  my ($hash) = @_;

  $hash->{DefFn}     = "VOLKSZAEHLER_Define";
  $hash->{AttrList}  = "delay loglevel:0,1,2,3,4,5,6 ".
    "stateS ".
    $readingFnAttributes;
}

sub
VOLKSZAEHLER_Define($$)
{
  my ($hash, $def) = @_;
  my $name=$hash->{NAME}||"";
  my @a = split("[ \t][ \t]*", $def);

  my $host = $a[2]||"";
  my $host_port = $a[3]||"";
  my $channel = $a[4]||"";
  my $reading = $a[5]||"";
  my $delay = $a[6]||"";
 
  $attr{$name}{delay}=$delay if $delay;

  return "Wrong syntax: use define <name> VOLKSZAEHLER <ip-address> <port-nr> <channel> <Wert:last/min/max/average/consumption> <poll-delay>" if(int(@a) != 7);

  $hash->{Host} = $host;
  $hash->{Host_Port} = $host_port;
  $hash->{Channel} = $channel;
  $hash->{Reading} = $reading;

  InternalTimer(gettimeofday(), "VOLKSZAEHLER_GetStatus", $hash, 0);

  return undef;
}

######################################

sub
VOLKSZAEHLER_GetStatus($)
{
  my ($hash) = @_;
  my $err_log='';

  my $name = $hash->{NAME}||"";
  my $host = $hash->{Host}||"";
  my $channel = $hash->{Channel}||"";
  my $reading = $hash->{Reading}||"";
 
  my $delay=$attr{$name}{delay}||300;
 
  InternalTimer(gettimeofday()+$delay, "VOLKSZAEHLER_GetStatus", $hash, 0);

  if(!defined($hash->{Host_Port})) { return(""); }
 
  my $host_port = $hash->{Host_Port}||"";
  my $URL="http://".$host.":".$host_port."/middleware.php/data/".$channel.".json?from=".$delay."%20seconds%20ago&tuples=1";
  my $agent = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1, timeout => 25)||"";
  my $header = HTTP::Request->new(GET => $URL)||"";
  my $request = HTTP::Request->new('GET', $URL, $header)||"";
  my $response = $agent->request($request)||"";

  $err_log.= "Can't get $URL -- ".$response->status_line
                unless $response->is_success;

  if($err_log ne "")
  {
        Log GetLogLevel($name,2), "VOLKSZAEHLER ".$err_log;
        return("");
  }

  my $decoded = decode_json( $response->content );
 
  #used for debugging
  #print $response->content."\n";
  #print Dumper($decoded);
 
  my $min = $decoded->{data}->{min}[1]||0; 
  my $min_at = $decoded->{data}->{min}[0]||0;
  $min_at = localtime($min_at/1000);
  my $max = $decoded->{data}->{max}[1]||0; 
  my $max_at = $decoded->{data}->{max}[0]||0; 
  $max_at = localtime($max_at/1000);
  my $average = $decoded->{data}->{average}||0;
  my $consumption = $decoded->{data}->{consumption}||0;
  my $from = $decoded->{data}->{from}||0;
  $from = localtime($from/1000);
  my $to = $decoded->{data}->{to}||0;
  $to = localtime($to/1000);
  my $last = $decoded->{data}->{tuples}[0][1]||0;
  my $last_at = $decoded->{data}->{tuples}[0][0]||0;
  $last_at = localtime($last_at/1000);
  my $state=$last||0;
 
  SELECT:{
  if ($reading eq "average"){$state = $average; last SELECT; }
  if ($reading eq "min"){$state = $min; last SELECT; }
  if ($reading eq "max"){$state = $max; last SELECT; }
  if ($reading eq "consumption"){$state = $consumption; last SELECT; }
  }
 
 
  Log 4, "VOLKSZAEHLER_GetStatus: $name $host_port ".$hash->{STATE}." -> ".$state;

  #my $text=$reading.": ".$state||"";
  my $text=$state||"";
 
  $hash->{STATE} = $state;
  $hash->{CHANGED}[0] = $text;
 
  my $sensor0="CONSUMPTION";
  $hash->{READINGS}{$sensor0}{TIME} = $to->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor0}{VAL} = $consumption;
   
  my $sensor1="MIN";
  $hash->{READINGS}{$sensor1}{TIME} = $min_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor1}{VAL} = $min;
 
  my $sensor2="MAX";
  $hash->{READINGS}{$sensor2}{TIME} = $max_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor2}{VAL} = $max;
 
  my $sensor3="AVERAGE";
  $hash->{READINGS}{$sensor3}{TIME} = $to->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor3}{VAL} = $average;
 
  my $sensor4="LAST";
  $hash->{READINGS}{$sensor4}{TIME} = $last_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor4}{VAL} = $last;
   
  my $sensor5="FROM";
  $hash->{READINGS}{$sensor5}{TIME} = $from->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor5}{VAL} = "";
 
  my $sensor6="TO";
  $hash->{READINGS}{$sensor6}{TIME} = $to->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{READINGS}{$sensor6}{VAL} = "";
     
  DoTrigger($name, undef) if($init_done);
}

1;



Gesendet von meinem iPad mit Tapatalk
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868

betateilchen

Abgesehen davon, dass man so, wie Du das machst, schon seit Jahren keine readings mehr setzen sollte, könntest Du einfach die 0 als "0" zuweisen.

Zum Anlegen von readings gibt es komplette Funktionen in der fhem.pl, die man auch benutzen sollte.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

bgewehr

Ich hab was probiert - wie es scheint mit Erfolg.

Die Zeile

my $text=$state||"";


habe ich geändert in


my $text=$state||0;


Das scheint zu funktionieren.


Gesendet von meinem iPad mit Tapatalk
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868

bgewehr

Meinst Du Readingsbulkupdate? Ich kann ja mal umbauen...


Gesendet von meinem iPad mit Tapatalk
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868

bgewehr

#4
Habe jetzt mal umgebaut. Was ein Nachteil der "neuen" Methode ist: ich kann nicht mehr die Timestamps der Readings manuell setzten, oder? Früher war der Timestamp von MAX der Moment, an dem der Maxwert eingetreten ist. Nun brauch ich weitere Readings für max_at usw.


################################################################
#
#  Copyright notice
#
#  (c) 2013 Bernd Gewehr
#
#  This script is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  The GNU General Public License can be found at
#  http://www.gnu.org/copyleft/gpl.html.
#  A copy is found in the textfile GPL.txt and important notices to the license
#  from the author is found in LICENSE.txt distributed with these scripts.
#
#  This script is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  This copyright notice MUST APPEAR in all copies of the script!
#
################################################################
# $Id:$
################################################################
package main;

use strict;
use warnings;
use JSON;
use Time::Piece;
use Data::Dumper;
use LWP::UserAgent;
use HTTP::Request;

sub
VOLKSZAEHLER_Initialize($)
{
  my ($hash) = @_;

  $hash->{DefFn}     = "VOLKSZAEHLER_Define";
  $hash->{AttrList}  = "delay period loglevel:0,1,2,3,4,5,6 ".
    "stateS ".
    $readingFnAttributes;
}

sub
VOLKSZAEHLER_Define($$)
{
  my ($hash, $def) = @_;
  my $name=$hash->{NAME}||"";
  my @a = split("[ \t][ \t]*", $def);

  my $host = $a[2]||"";
  my $host_port = $a[3]||"";
  my $channel = $a[4]||"";
  my $reading = uc($a[5])||"";
  my $delay = $a[6]||"";
  my $period = $a[7]||$delay;
 
  $attr{$name}{delay}=$delay if $delay;
  $attr{$name}{period}=$period if $period;
  $attr{$name}{'event-on-change-reading'} = uc($reading);
  $attr{$name}{stateFormat} = uc($reading);

  return "Wrong syntax: use define <name> VOLKSZAEHLER <ip-address> <port-nr> <channel> <Wert:last/min/max/average/consumption> <poll-delay> optional: <period>" if(int(@a) < 7);

  $hash->{Host} = $host;
  $hash->{Host_Port} = $host_port;
  $hash->{Channel} = $channel;
  $hash->{Reading} = $reading;

  InternalTimer(gettimeofday(), "VOLKSZAEHLER_GetStatus", $hash, 0);

  return undef;
}

######################################

sub
VOLKSZAEHLER_GetStatus($)
{
  my ($hash) = @_;
  my $err_log='';

  my $name = $hash->{NAME}||"";
  my $host = $hash->{Host}||"";
  my $channel = $hash->{Channel}||"";
  my $reading = $hash->{Reading}||"";
 
  my $delay=$attr{$name}{delay}||300;
  my $period=$attr{$name}{period}||$delay;
 
  #Log 0, $name.' Delay: '.$delay.' Period: '.$period;
  InternalTimer(gettimeofday()+$delay, "VOLKSZAEHLER_GetStatus", $hash, 0);

  if(!defined($hash->{Host_Port})) { return(""); }
 
  my $host_port = $hash->{Host_Port}||"";
  my $URL="http://".$host.":".$host_port."/middleware.php/data/".$channel.".json?from=".$period."%20seconds%20ago&tuples=1";
  my $agent = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1, timeout => 25)||"";
  my $header = HTTP::Request->new(GET => $URL)||"";
  my $request = HTTP::Request->new('GET', $URL, $header)||"";
  my $response = $agent->request($request)||"";

  $err_log.= "Can't get $URL -- ".$response->status_line
                unless $response->is_success;

  if($err_log ne "")
  {
        Log GetLogLevel($name,2), "VOLKSZAEHLER ".$err_log;
        return("");
  }

  my $decoded = decode_json( $response->content );
 
  #used for debugging
  #print $response->content."\n";
  #print Dumper($decoded);
 
  my $min = $decoded->{data}->{min}[1]||0; 
  my $min_at = $decoded->{data}->{min}[0]||0;
  $min_at = localtime($min_at/1000);
  my $max = $decoded->{data}->{max}[1]||0; 
  my $max_at = $decoded->{data}->{max}[0]||0; 
  $max_at = localtime($max_at/1000);
  my $average = $decoded->{data}->{average}||0;
  my $consumption = $decoded->{data}->{consumption}||0;
  my $from = $decoded->{data}->{from}||0;
  $from = localtime($from/1000);
  my $to = $decoded->{data}->{to}||0;
  $to = localtime($to/1000);
  my $last = $decoded->{data}->{tuples}[0][1]||0;
  my $last_at = $decoded->{data}->{tuples}[0][0]||0;
  $last_at = localtime($last_at/1000);
  my $i;
  my $ts;
 
  Log 4, "VOLKSZAEHLER_GetStatus: $name $host_port ".$hash->{STATE};

  readingsBeginUpdate($hash);
  $ts = localtime()->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
 
  readingsBulkUpdate($hash, "CONSUMPTION", $consumption );
 
  $i = $#{ $hash->{CHANGED} };
  $ts = $min_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "MIN", $min );
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
 
  readingsBulkUpdate($hash, "MIN_AT", $min_at->strftime('%Y-%m-%d %H:%M:%S'));
   
  $i = $#{ $hash->{CHANGED} };
  $ts = $max_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "MAX", $max );
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  readingsBulkUpdate($hash, "MAX_AT", $max_at->strftime('%Y-%m-%d %H:%M:%S'));

  readingsBulkUpdate($hash, "AVERAGE", $average );

  $i = $#{ $hash->{CHANGED} };
  $ts = $last_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "LAST", $last );
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  readingsBulkUpdate($hash, "LAST_AT", $last_at->strftime('%Y-%m-%d %H:%M:%S'));

  $i = $#{ $hash->{CHANGED} };
  $ts = $from->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "FROM", $from->strftime('%Y-%m-%d %H:%M:%S'));
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  $i = $#{ $hash->{CHANGED} };
  $ts = $to->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "TO", $to->strftime('%Y-%m-%d %H:%M:%S'));
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  readingsEndUpdate($hash, 1);
}

1;


Bin ich jetzt "up to date"?
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868

justme1968

doch. das geht in dem du das $hash->{CHANGETIME}[] array passend zu den readingsBulkUpdate füllst. es gibt auch gerade einen thread dazu.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

bgewehr

Habe den Thread gefunden (http://forum.fhem.de/index.php/topic,47437.0/all.html). Scheint aber gar nicht so einfach zu sein, besoders wenn man Perl 5.20 verwendet...

Mein Code hier jedenfalls macht nix sinnvolles:

  readingsBeginUpdate($hash);
  my $changeindex = 0;
  readingsBulkUpdate($hash, "CONSUMPTION", $consumption );
  $changeindex++;
  readingsBulkUpdate($hash, "MIN", $min );
  $hash->{CHANGETIME}[$changeindex++] = $min_at->strftime('%Y-%m-%d %H:%M:%S');
  readingsBulkUpdate($hash, "MIN_AT", $min_at->strftime('%Y-%m-%d %H:%M:%S'));
  $changeindex++;
  readingsBulkUpdate($hash, "MAX", $max );
  $hash->{CHANGETIME}[$changeindex++] = $max_at->strftime('%Y-%m-%d %H:%M:%S');
  readingsBulkUpdate($hash, "MAX_AT", $max_at->strftime('%Y-%m-%d %H:%M:%S'));
  $changeindex++;
  readingsBulkUpdate($hash, "AVERAGE", $average );
  $changeindex++;
  readingsBulkUpdate($hash, "LAST", $last );
  $hash->{CHANGETIME}[$changeindex++] = $last_at->strftime('%Y-%m-%d %H:%M:%S');
  readingsBulkUpdate($hash, "LAST_AT", $last_at->strftime('%Y-%m-%d %H:%M:%S'));
  readingsBulkUpdate($hash, "FROM", $from->strftime('%Y-%m-%d %H:%M:%S'));
  readingsBulkUpdate($hash, "TO",   $to->strftime('%Y-%m-%d %H:%M:%S'));
  readingsEndUpdate($hash, 1);



Readings

AVERAGE 0 2016-01-30 15:30:03
CONSUMPTION 0 2016-01-30 15:30:03
FROM   2016-01-28 12:31:59 2016-01-30 15:30:03
LAST 0 2016-01-30 15:30:03
LAST_AT 2016-01-28 12:32:00 2016-01-30 15:30:03
MAX 0 2016-01-30 15:30:03
MAX_AT 2016-01-28 12:32:00 2016-01-30 15:30:03
MIN 0 2016-01-30 15:30:03
MIN_AT 2016-01-28 12:32:00 2016-01-30 15:30:03
STATE 0 2016-01-25 11:52:42
TO 2016-01-28 12:32:00 2016-01-30 15:30:03


Da sind die Timestamps der Änderungen trotzdem alle auf jetzt().

Noch ein Tipp?
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868

justme1968

wenn du den index einfach von hand hoch zählst gibt es das problem mit der perl version aus dem anderen thread nicht.

so mache ich es im withings und netatmo modul. und es funktioniert problemlos.

wo ist denn das listig her? das CHANGETIME wirkt such auch den intern gespeicherten timestamp aus und auf das was im file oder db log landet. nicht beim per longpoll aktualisieren timestamp. wenn du die browser seite neu lädst solltest du die richtigen timetamps sehen.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

herrmannj

#8
oh. Kann ich auflösen. hat nix mit der verwendeten Perl Version zu tun sondern lag an den event-on attributen.

So gehts richtig

    $i = $#{ $hash->{CHANGED} };
    readingsBulkUpdate($hash, "meter", $msg->{meter});
    $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to


Jeweils vor und nach jedem BulkUpdate einmal den Index nehmen und nur wenn er sich erhöht CHANGETIME setzen.

@andre
Von Hand hoch zählen "knallt" wenn der user ein event-on setzt und das greift.

vg
joerg

Edith: das setzt die Einträge für das log. Die Einträge für das webif müssen getrennt gesetzt werden. Einmalig nach beginUpdate:

    readingsBeginUpdate($hash);
    $hash->{".updateTimestamp"} = $ts;

bgewehr

#9
Also, ich habe es dann jetzt so gemacht:


################################################################
#
#  Copyright notice
#
#  (c) 2013 Bernd Gewehr
#
#  This script is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  The GNU General Public License can be found at
#  http://www.gnu.org/copyleft/gpl.html.
#  A copy is found in the textfile GPL.txt and important notices to the license
#  from the author is found in LICENSE.txt distributed with these scripts.
#
#  This script is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  This copyright notice MUST APPEAR in all copies of the script!
#
################################################################
# $Id:$
################################################################
package main;

use strict;
use warnings;
use JSON;
use Time::Piece;
use Data::Dumper;
use LWP::UserAgent;
use HTTP::Request;

sub
VOLKSZAEHLER_Initialize($)
{
  my ($hash) = @_;

  $hash->{DefFn}     = "VOLKSZAEHLER_Define";
  $hash->{AttrList}  = "delay period loglevel:0,1,2,3,4,5,6 ".
    "stateS ".
    $readingFnAttributes;
}

sub
VOLKSZAEHLER_Define($$)
{
  my ($hash, $def) = @_;
  my $name=$hash->{NAME}||"";
  my @a = split("[ \t][ \t]*", $def);

  my $host = $a[2]||"";
  my $host_port = $a[3]||"";
  my $channel = $a[4]||"";
  my $reading = uc($a[5])||"";
  my $delay = $a[6]||"";
  my $period = $a[7]||$delay;
 
  $attr{$name}{delay}=$delay if $delay;
  $attr{$name}{period}=$period if $period;
  $attr{$name}{'event-on-change-reading'} = uc($reading);
  $attr{$name}{stateFormat} = uc($reading);

  return "Wrong syntax: use define <name> VOLKSZAEHLER <ip-address> <port-nr> <channel> <Wert:last/min/max/average/consumption> <poll-delay> optional: <period>" if(int(@a) < 7);

  $hash->{Host} = $host;
  $hash->{Host_Port} = $host_port;
  $hash->{Channel} = $channel;
  $hash->{Reading} = $reading;

  InternalTimer(gettimeofday(), "VOLKSZAEHLER_GetStatus", $hash, 0);

  return undef;
}

######################################

sub
VOLKSZAEHLER_GetStatus($)
{
  my ($hash) = @_;
  my $err_log='';

  my $name = $hash->{NAME}||"";
  my $host = $hash->{Host}||"";
  my $channel = $hash->{Channel}||"";
  my $reading = $hash->{Reading}||"";
 
  my $delay=$attr{$name}{delay}||300;
  my $period=$attr{$name}{period}||$delay;
 
  #Log 0, $name.' Delay: '.$delay.' Period: '.$period;
  InternalTimer(gettimeofday()+$delay, "VOLKSZAEHLER_GetStatus", $hash, 0);

  if(!defined($hash->{Host_Port})) { return(""); }
 
  my $host_port = $hash->{Host_Port}||"";
  my $URL="http://".$host.":".$host_port."/middleware.php/data/".$channel.".json?from=".$period."%20seconds%20ago&tuples=1";
  my $agent = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1, timeout => 25)||"";
  my $header = HTTP::Request->new(GET => $URL)||"";
  my $request = HTTP::Request->new('GET', $URL, $header)||"";
  my $response = $agent->request($request)||"";

  $err_log.= "Can't get $URL -- ".$response->status_line
                unless $response->is_success;

  if($err_log ne "")
  {
        Log GetLogLevel($name,2), "VOLKSZAEHLER ".$err_log;
        return("");
  }

  my $decoded = decode_json( $response->content );
 
  #used for debugging
  #print $response->content."\n";
  #print Dumper($decoded);
 
  my $min = $decoded->{data}->{min}[1]||0; 
  my $min_at = $decoded->{data}->{min}[0]||0;
  $min_at = localtime($min_at/1000);
  my $max = $decoded->{data}->{max}[1]||0; 
  my $max_at = $decoded->{data}->{max}[0]||0; 
  $max_at = localtime($max_at/1000);
  my $average = $decoded->{data}->{average}||0;
  my $consumption = $decoded->{data}->{consumption}||0;
  my $from = $decoded->{data}->{from}||0;
  $from = localtime($from/1000);
  my $to = $decoded->{data}->{to}||0;
  $to = localtime($to/1000);
  my $last = $decoded->{data}->{tuples}[0][1]||0;
  my $last_at = $decoded->{data}->{tuples}[0][0]||0;
  $last_at = localtime($last_at/1000);
  my $i;
  my $ts;
 
  Log 4, "VOLKSZAEHLER_GetStatus: $name $host_port ".$hash->{STATE};

  readingsBeginUpdate($hash);
  $ts = localtime()->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
 
  readingsBulkUpdate($hash, "CONSUMPTION", $consumption );
 
  $i = $#{ $hash->{CHANGED} };
  $ts = $min_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "MIN", $min );
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
 
  readingsBulkUpdate($hash, "MIN_AT", $min_at->strftime('%Y-%m-%d %H:%M:%S'));
   
  $i = $#{ $hash->{CHANGED} };
  $ts = $max_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "MAX", $max );
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  readingsBulkUpdate($hash, "MAX_AT", $max_at->strftime('%Y-%m-%d %H:%M:%S'));

  readingsBulkUpdate($hash, "AVERAGE", $average );

  $i = $#{ $hash->{CHANGED} };
  $ts = $last_at->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "LAST", $last );
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  readingsBulkUpdate($hash, "LAST_AT", $last_at->strftime('%Y-%m-%d %H:%M:%S'));

  $i = $#{ $hash->{CHANGED} };
  $ts = $from->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "FROM", $from->strftime('%Y-%m-%d %H:%M:%S'));
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  $i = $#{ $hash->{CHANGED} };
  $ts = $to->strftime('%Y-%m-%d %H:%M:%S');
  $hash->{".updateTimestamp"} = $ts;
  readingsBulkUpdate($hash, "TO", $to->strftime('%Y-%m-%d %H:%M:%S'));
  $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to

  readingsEndUpdate($hash, 1);
}

1;


Im Webif sehe ich aber immer noch nicht die richtigen Readingstimestamps, wie Ihr ja auch schon geschrieben habt. Das hätte ich aber nun gern. Was ist also zu tun?

(Ich gehe bald zu meiner alten Methode zurück, das war ja viel einfacher...)
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868

bgewehr

#10
Hatte ich schon erwähnt, dass ich im Code ein attr $device event-on-change-reading $reading ausführe?

Scheint ja hierfür relevant zu sein, oder?

Jedenfalls wird im webif nur das reading in der Zeit und im Wert aktualisiert, für das ich das event generiere.

Gefällt mir eigentlich nicht, hat aber meine fhem Gesamtgeschwindigkeit wieder deutlich erhöht. Alle events prasseln zu lassen, hat das webif ziemlich zäh gemacht.
FritzBox 7590, Synology DS216+II mit Docker
Docker: FHEM mit hmlan, Homebridge, node-red, mosquitto, ems-collector für Buderus EMS mit AVR Net-IO
Gartenwasser über MQTT auf R/Pi A+
Volkszaehler.org auf R/Pi 2B mit Pi_Erweiterung
Raspberrymatic auf R/Pi 4B mit RPI-RF-MOD u. CUL868