mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 16:56:54 +00:00
98_HourCounter : new module
git-svn-id: https://svn.fhem.de/fhem/trunk@6802 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
12d480e8e5
commit
900c655224
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- feature: new module 98_HourCounter added, 99_UtilsHourCounter.pm added to contrib (john)
|
||||||
- added: MYSENSORS: connect to serial or Ethernet MySensors Gateway
|
- added: MYSENSORS: connect to serial or Ethernet MySensors Gateway
|
||||||
- added: MYSENSORS_DEVICE: represent a MySensors sensor- or actor node
|
- added: MYSENSORS_DEVICE: represent a MySensors sensor- or actor node
|
||||||
- feature: global ATTR/DELETEATTR/MODIFIED events
|
- feature: global ATTR/DELETEATTR/MODIFIED events
|
||||||
|
930
fhem/FHEM/98_HourCounter.pm
Normal file
930
fhem/FHEM/98_HourCounter.pm
Normal file
@ -0,0 +1,930 @@
|
|||||||
|
# $Id: 98_HourCounter.pm 6802 2014-10-23 18:00:00Z john $
|
||||||
|
####################################################################################################
|
||||||
|
#
|
||||||
|
# 98_HourCounter.pm
|
||||||
|
# The HourCounter accumulates single events to a counter object.
|
||||||
|
# In the case of binary weighted events pulse- and pause-time are determined
|
||||||
|
#
|
||||||
|
# This module is written by john.
|
||||||
|
#
|
||||||
|
# This file is part of fhem.
|
||||||
|
#
|
||||||
|
# Fhem 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.
|
||||||
|
#
|
||||||
|
# Fhem 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.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# 16.11.13 - 0.99.b
|
||||||
|
# Loglevel adjusted
|
||||||
|
# 02.12.13 - 0.99.c
|
||||||
|
# $readingFnAttributes added
|
||||||
|
# 03.12.13 - 0.99.d
|
||||||
|
# missed attribute event-on-change-reading
|
||||||
|
# 02.02.14 - 1.00
|
||||||
|
# command queues
|
||||||
|
# 04.02.14 - 1.01
|
||||||
|
# queue removed
|
||||||
|
# 17.03.14 - 1.02
|
||||||
|
# adjusting log-levels, forceYearChange,HourCounter_RoundYear
|
||||||
|
# 07.06.14 - 1.03
|
||||||
|
# $ID changed
|
||||||
|
# setter for pulseTimeIncrement, pauseTimeIncrement
|
||||||
|
# 25.10.14 - 1.0.0.4
|
||||||
|
# official part of fhem
|
||||||
|
# adjusting log-output
|
||||||
|
# update documentation
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
package main;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use vars qw(%defs);
|
||||||
|
use vars qw($readingFnAttributes);
|
||||||
|
use vars qw(%attr);
|
||||||
|
use vars qw(%modules);
|
||||||
|
|
||||||
|
my $HourCounter_Version="1.0.0.4 - 23.10.2014";
|
||||||
|
|
||||||
|
my @HourCounter_cmdQeue =();
|
||||||
|
|
||||||
|
##########################
|
||||||
|
sub HourCounter_Log($$$)
|
||||||
|
{
|
||||||
|
my ( $hash, $loglevel, $text ) = @_;
|
||||||
|
my $xline = (caller(0))[2];
|
||||||
|
|
||||||
|
my $xsubroutine = (caller(1))[3];
|
||||||
|
my $sub = (split( ':', $xsubroutine ))[2];
|
||||||
|
$sub =~ s/HourCounter_//;
|
||||||
|
|
||||||
|
my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : "HourCounter";
|
||||||
|
Log3 $hash, $loglevel, "HourCounter $instName $sub.$xline " . $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
sub HourCounter_AddLog($$$)
|
||||||
|
{
|
||||||
|
my ($logdevice, $readingName,$value) = @_;
|
||||||
|
|
||||||
|
my $cmd='';
|
||||||
|
if ($readingName =~ m,state,i)
|
||||||
|
{
|
||||||
|
$cmd="trigger $logdevice $value << addLog";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cmd="trigger $logdevice $readingName: $value << addLog";
|
||||||
|
}
|
||||||
|
|
||||||
|
HourCounter_Log '',3,$cmd;
|
||||||
|
fhem ($cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# execute the content of the given parameter
|
||||||
|
sub HourCounter_Exec($)
|
||||||
|
{
|
||||||
|
my $doit = shift;
|
||||||
|
my $ret='';
|
||||||
|
eval $doit;
|
||||||
|
$ret = $@ if ($@);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
##########################
|
||||||
|
# add command to queue
|
||||||
|
sub HourCounter_cmdQueueAdd($$)
|
||||||
|
{
|
||||||
|
my ($hash,$cmd)= @_;
|
||||||
|
push(@{$hash->{helper}{cmdQueue}},$cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# execute command queue
|
||||||
|
sub HourCounter_ExecQueue($)
|
||||||
|
{
|
||||||
|
my ($hash)=@_;
|
||||||
|
my $result;
|
||||||
|
|
||||||
|
my $cnt=$#{$hash->{helper}{cmdQueue}};
|
||||||
|
my $loops =0;
|
||||||
|
my $cntAll=0;
|
||||||
|
|
||||||
|
HourCounter_Log $hash,4,"cnt: $cnt";
|
||||||
|
|
||||||
|
while ($cnt>=0)
|
||||||
|
{
|
||||||
|
for my $i (0 .. $cnt)
|
||||||
|
{
|
||||||
|
my $cmd = ${$hash->{helper}{cmdQueue}}[$i];
|
||||||
|
${$hash->{helper}{cmdQueue}}[$i]='';
|
||||||
|
$result=HourCounter_Exec($cmd);
|
||||||
|
if ($result)
|
||||||
|
{
|
||||||
|
HourCounter_Log $hash,2,"$result";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
HourCounter_Log $hash,4,"exec ok:$cmd";
|
||||||
|
}
|
||||||
|
$cntAll++;
|
||||||
|
}
|
||||||
|
|
||||||
|
# bearbeitete eintraege loeschen
|
||||||
|
for (my $i = $cnt; $i > -1; $i--)
|
||||||
|
{
|
||||||
|
splice (@{$hash->{helper}{cmdQueue}}, $i, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnt=$#HourCounter_cmdQeue;
|
||||||
|
$loops++;
|
||||||
|
if ($loops >= 5 || $cntAll>100)
|
||||||
|
{
|
||||||
|
HourCounter_Log $hash,2, "!!! too deep recursion";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# round off the date passed to the hour
|
||||||
|
sub HourCounter_RoundHour($)
|
||||||
|
{
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(shift);
|
||||||
|
return mktime(0, 0, $hour, $mday, $mon, $year);
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# round off the date passed to the day
|
||||||
|
sub HourCounter_RoundDay($)
|
||||||
|
{
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(shift);
|
||||||
|
return mktime(0, 0, 0, $mday, $mon, $year);
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# round off the date passed to the week
|
||||||
|
sub HourCounter_RoundWeek($)
|
||||||
|
{
|
||||||
|
my ($time) = @_;
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
|
||||||
|
# wday 0 Sonntag 1 Montag ...
|
||||||
|
$time-=$wday * 86400;
|
||||||
|
return HourCounter_RoundDay($time);
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# returns the seconds since the start of the day
|
||||||
|
sub HourCounter_SecondsOfDay()
|
||||||
|
{
|
||||||
|
my $timeToday = gettimeofday();
|
||||||
|
return int($timeToday - HourCounter_RoundDay($timeToday));
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# round off the date passed to the month
|
||||||
|
sub HourCounter_RoundMonth($)
|
||||||
|
{
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(shift);
|
||||||
|
return mktime(0, 0, 0, 1, $mon, $year);
|
||||||
|
}
|
||||||
|
##########################
|
||||||
|
# round off the date passed to the year
|
||||||
|
sub HourCounter_RoundYear($)
|
||||||
|
{
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(shift);
|
||||||
|
return mktime(0, 0, 0, 1, 1, $year);
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
sub HourCounter_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
$hash->{DefFn} = "HourCounter_Define";
|
||||||
|
$hash->{UndefFn} = "HourCounter_Undef";
|
||||||
|
|
||||||
|
$hash->{SetFn} = "HourCounter_Set";
|
||||||
|
$hash->{GetFn} = "HourCounter_Get";
|
||||||
|
$hash->{NotifyFn} = "HourCounter_Notify";
|
||||||
|
$hash->{AttrList} = "disable:0,1 ". $readingFnAttributes;
|
||||||
|
|
||||||
|
HourCounter_Log "", 3, "Init Done with Version $HourCounter_Version";
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
sub HourCounter_Define($$$)
|
||||||
|
{
|
||||||
|
my ( $hash, $def ) = @_;
|
||||||
|
my @a = split( "[ \t][ \t]*", $def );
|
||||||
|
my $name = $a[0];
|
||||||
|
HourCounter_Log $hash, 4, "parameters: @a";
|
||||||
|
if ( @a < 3 )
|
||||||
|
{
|
||||||
|
return "wrong syntax: define <name> HourCounter <regexp_for_ON> [<regexp_for_OFF>]";
|
||||||
|
}
|
||||||
|
my $onRegexp = $a[2];
|
||||||
|
|
||||||
|
my $offRegexp = (@a==4)?$a[3]:undef;
|
||||||
|
|
||||||
|
# Checking for misleading regexps
|
||||||
|
eval { "Hallo" =~ m/^$onRegexp/ };
|
||||||
|
return "Bad regexp_for_ON : $@" if ($@);
|
||||||
|
if ($offRegexp)
|
||||||
|
{
|
||||||
|
eval { "Hallo" =~ m/^$offRegexp/ };
|
||||||
|
return "Bad regexp_for_ON : $@" if ($@);
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{helper}{ON_Regexp} = $onRegexp;
|
||||||
|
$hash->{helper}{OFF_Regexp} = $offRegexp;
|
||||||
|
$hash->{helper}{isFirstRun} = 1;
|
||||||
|
$hash->{helper}{value} = -1;
|
||||||
|
$hash->{helper}{forceHourChange} = '';
|
||||||
|
$hash->{helper}{forceDayChange} = '';
|
||||||
|
$hash->{helper}{forceWeekChange} = '';
|
||||||
|
$hash->{helper}{forceMonthChange} = '';
|
||||||
|
$hash->{helper}{forceYearChange} = '';
|
||||||
|
|
||||||
|
$hash->{helper}{forceClear} = '';
|
||||||
|
$hash->{helper}{calledByEvent} = '';
|
||||||
|
$hash->{helper}{changedTimestamp} = '';
|
||||||
|
@{$hash->{helper}{cmdQueue}} = ();
|
||||||
|
|
||||||
|
$modules{HourCounter}{defptr}{$name}=$hash;
|
||||||
|
RemoveInternalTimer($name);
|
||||||
|
InternalTimer( int(gettimeofday() + 15), "HourCounter_Run", $name, 0 );
|
||||||
|
return undef;
|
||||||
|
|
||||||
|
}
|
||||||
|
##########################
|
||||||
|
sub HourCounter_Undef($$)
|
||||||
|
{
|
||||||
|
my ( $hash, $arg ) = @_;
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 3, "Done";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
###########################
|
||||||
|
sub HourCounter_Get($@)
|
||||||
|
{
|
||||||
|
my ( $hash, @a ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
my $ret = "Unknown argument $a[1], choose one of version:noArg";
|
||||||
|
my $cmd = lc( $a[1] );
|
||||||
|
|
||||||
|
if ($cmd eq 'version')
|
||||||
|
{
|
||||||
|
$ret = "Version : $HourCounter_Version\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
###########################
|
||||||
|
sub HourCounter_Set($@)
|
||||||
|
{
|
||||||
|
my ( $hash, @a ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $reINT = '^([\\+,\\-]?\\d+$)'; # int
|
||||||
|
|
||||||
|
# determine userReadings beginning with app
|
||||||
|
my @readingNames = keys (%{$hash->{READINGS}});
|
||||||
|
my @userReadings = ();
|
||||||
|
foreach (@readingNames)
|
||||||
|
{
|
||||||
|
if ($_ =~ m/app.*/)
|
||||||
|
{
|
||||||
|
push (@userReadings,$_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $strUserReadings = join(" ",@userReadings)." ";
|
||||||
|
|
||||||
|
# standard commands with parameter
|
||||||
|
my @cmdPara =(
|
||||||
|
"countsOverall","countsPerDay",
|
||||||
|
"pauseTimeIncrement","pauseTimePerDay","pauseTimeOverall",
|
||||||
|
"pulseTimeIncrement","pulseTimePerDay","pulseTimeOverall");
|
||||||
|
|
||||||
|
# standard commands with no parameter
|
||||||
|
my @cmdNoPara =("clear","forceHourChange","forceDayChange","forceWeekChange","forceMonthChange","forceYearChange");
|
||||||
|
|
||||||
|
my @allCommands = (@cmdPara,@cmdNoPara,@userReadings);
|
||||||
|
my $strAllCommands = join(" ",(@cmdPara,@userReadings))." ".join(":noArg ",@cmdNoPara).":noArg ";
|
||||||
|
#HourCounter_Log $hash, 2, "strAllCommands : $strAllCommands";
|
||||||
|
|
||||||
|
# stop:noArg
|
||||||
|
my $usage =
|
||||||
|
"Unknown argument $a[1], choose one of "
|
||||||
|
.$strAllCommands;
|
||||||
|
|
||||||
|
# we need at least 2 parameters
|
||||||
|
return "Need a parameter for set" if ( @a < 2 );
|
||||||
|
|
||||||
|
my $cmd = $a[1];
|
||||||
|
if ($cmd eq "?")
|
||||||
|
{
|
||||||
|
return $usage;
|
||||||
|
}
|
||||||
|
my $value = $a[2];
|
||||||
|
|
||||||
|
# is command defined ?
|
||||||
|
if ( (grep { /$cmd/ } @allCommands) <= 0)
|
||||||
|
{
|
||||||
|
HourCounter_Log $hash, 2, "cmd:$cmd no match for : @allCommands";
|
||||||
|
return return "unknown command : $cmd";
|
||||||
|
}
|
||||||
|
|
||||||
|
# need we a parameter ?
|
||||||
|
my $hits = scalar grep { /$cmd/ } @cmdNoPara;
|
||||||
|
my $needPara = ($hits > 0) ? '' : 1;
|
||||||
|
HourCounter_Log $hash, 4, "hits: $hits needPara:$needPara";
|
||||||
|
|
||||||
|
# if parameter needed, it must be an integer
|
||||||
|
return "Value must be an integer" if ($needPara && !($value =~ m/$reINT/));
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 4, "$cmd $value";
|
||||||
|
my $doRun='';
|
||||||
|
|
||||||
|
if($needPara)
|
||||||
|
{
|
||||||
|
readingsSingleUpdate( $hash, $cmd, $value, 1 );
|
||||||
|
}
|
||||||
|
elsif ($cmd eq "forceHourChange")
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceHourChange}=1;
|
||||||
|
$doRun=1;
|
||||||
|
}
|
||||||
|
elsif ($cmd eq "forceDayChange")
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceDayChange}=1;
|
||||||
|
$doRun=1;
|
||||||
|
}
|
||||||
|
elsif ($cmd eq "forceWeekChange")
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceWeekChange}=1;
|
||||||
|
$doRun=1;
|
||||||
|
}
|
||||||
|
elsif ($cmd eq "forceMonthChange")
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceMonthChange}=1;
|
||||||
|
$doRun=1;
|
||||||
|
}
|
||||||
|
elsif ($cmd eq "forceYearChange")
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceYearChange}=1;
|
||||||
|
$doRun=1;
|
||||||
|
}
|
||||||
|
elsif ($cmd eq "clear")
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceClear}=1;
|
||||||
|
$doRun=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "unknown command (2): $cmd";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($doRun)
|
||||||
|
{
|
||||||
|
$hash->{helper}{value}=-1;
|
||||||
|
$hash->{helper}{calledByEvent}=1;
|
||||||
|
HourCounter_Run($hash->{NAME});
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
##########################
|
||||||
|
sub HourCounter_Notify($$)
|
||||||
|
{
|
||||||
|
my ( $hash, $dev ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $devName = $dev->{NAME};
|
||||||
|
|
||||||
|
# return if disabled
|
||||||
|
if ( AttrVal( $name, 'disable', '0' ) eq '1' )
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
my $onRegexp = $hash->{helper}{ON_Regexp};
|
||||||
|
my $offRegexp = $hash->{helper}{OFF_Regexp};
|
||||||
|
|
||||||
|
#HourCounter_Log $hash,5,"Notify by DevName: ".$dev->{NAME};
|
||||||
|
my $max = int( @{ $dev->{CHANGED} } );
|
||||||
|
for ( my $i = 0 ; $i < $max ; $i++ )
|
||||||
|
{
|
||||||
|
my $s = $dev->{CHANGED}[$i]; # read changed reading
|
||||||
|
$s = "" if ( !defined($s) );
|
||||||
|
my $isOnReading = ( "$devName:$s" =~ m/^$onRegexp$/ );
|
||||||
|
my $isOffReading = ($offRegexp) ? ( "$devName:$s" =~ m/^$offRegexp$/ ):'';
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 5,
|
||||||
|
"devName:$devName; CHANGED:$s; isOnReading:$isOnReading; isOffReading:$isOffReading;";
|
||||||
|
next if ( !( $isOnReading || ($isOffReading && $offRegexp) ) );
|
||||||
|
|
||||||
|
$hash->{helper}{value} = 1 if ($isOnReading);
|
||||||
|
$hash->{helper}{value} = 0 if ($isOffReading);
|
||||||
|
$hash->{helper}{calledByEvent}=1;
|
||||||
|
HourCounter_Run($hash->{NAME});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# converts the seconds in the date format
|
||||||
|
sub HourCounter_Seconds2HMS($)
|
||||||
|
{
|
||||||
|
my ( $seconds) = @_;
|
||||||
|
my ($Sekunde, $Minute, $Stunde, $Monatstag, $Monat, $Jahr, $Wochentag, $Jahrestag, $Sommerzeit) = localtime($seconds);
|
||||||
|
my $days = int($seconds/86400);
|
||||||
|
return sprintf( "%d Tage %02d:%02d:%02d", $days,$Stunde - 1, $Minute, $Sekunde );
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# rounds the timestamp do the beginning of the week
|
||||||
|
sub HourCounter_weekBase($)
|
||||||
|
{
|
||||||
|
my ($time) = @_;
|
||||||
|
my $dayDiff = 60*60*24;
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
|
||||||
|
# wday 0 Sonntag 1 Montag ...
|
||||||
|
my $a=$time-$wday*$dayDiff;
|
||||||
|
my $b=int($a/$dayDiff); # auf tage gehen
|
||||||
|
my $c=$b*$dayDiff;
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################
|
||||||
|
sub HourCounter_Run($)
|
||||||
|
{
|
||||||
|
# print "xxx TAG A\n" ;
|
||||||
|
my ($name) = @_;
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
|
return if (!defined($hash->{TYPE}) || $hash->{TYPE} ne 'HourCounter');
|
||||||
|
|
||||||
|
delete($hash->{CHANGETIME}); # timestamps for event-log-file-entries older, than current time
|
||||||
|
|
||||||
|
my $calledByEvent = $hash->{helper}{calledByEvent};
|
||||||
|
$hash->{helper}{calledByEvent} = '';
|
||||||
|
|
||||||
|
# if call was made by timer force value to -1
|
||||||
|
my $valuePara = ($calledByEvent)? $hash->{helper}{value}:-1;
|
||||||
|
|
||||||
|
$hash->{helper}{changedTimestamp} = ReadingsTimestamp( $name, "value", TimeNow() )
|
||||||
|
if (!$hash->{helper}{changedTimestamp});
|
||||||
|
my $sdValue = time_str2num($hash->{helper}{changedTimestamp});
|
||||||
|
my $sdCurTime = gettimeofday();
|
||||||
|
|
||||||
|
my $isOffDefined = ($hash->{helper}{OFF_Regexp})? 1: '';
|
||||||
|
|
||||||
|
my $timeIncrement = int( $sdCurTime - $sdValue ); # time diff
|
||||||
|
$timeIncrement = 0 if ($timeIncrement<0); # wrong time offset in case of summer/winter time
|
||||||
|
|
||||||
|
my $valueOld = ReadingsVal( $name, 'value', 0 ); # get the old value
|
||||||
|
|
||||||
|
# variable for reading update
|
||||||
|
my $value = undef;
|
||||||
|
my $countsPerDay=undef;
|
||||||
|
my $countsOverall=undef;
|
||||||
|
|
||||||
|
my $pulseTimeIncrement=undef;
|
||||||
|
my $pulseTimePerDay=undef;
|
||||||
|
my $pulseTimeOverall=undef;
|
||||||
|
|
||||||
|
my $pauseTimePerDay=undef;
|
||||||
|
my $pauseTimeOverall=undef;
|
||||||
|
my $pauseTimeIncrement=undef;
|
||||||
|
|
||||||
|
my $state=undef;
|
||||||
|
my $clearDate = undef;
|
||||||
|
|
||||||
|
my $sdRoundHour = HourCounter_RoundHour($sdCurTime);
|
||||||
|
my $sdRoundHourLast = $hash->{helper}{sdRoundHourLast};
|
||||||
|
$sdRoundHourLast = $sdRoundHour if (!$sdRoundHourLast);
|
||||||
|
my $isHourChanged = ($sdRoundHour != $sdRoundHourLast) || $hash->{helper}{forceHourChange};
|
||||||
|
|
||||||
|
my $sdRoundDayCurTime = HourCounter_RoundDay($sdCurTime);
|
||||||
|
my $sdRoundDayValue = HourCounter_RoundDay($sdRoundHourLast);
|
||||||
|
my $isDayChanged = ($sdRoundDayCurTime != $sdRoundDayValue) || $hash->{helper}{forceDayChange};
|
||||||
|
|
||||||
|
my $sdRoundWeekCurTime = HourCounter_RoundWeek($sdCurTime);
|
||||||
|
my $sdRoundWeekValue = HourCounter_RoundWeek($sdRoundHourLast);
|
||||||
|
my $isWeekChanged = ($sdRoundWeekCurTime != $sdRoundWeekValue) || $hash->{helper}{forceWeekChange};
|
||||||
|
|
||||||
|
my $sdRoundMonthCurTime = HourCounter_RoundMonth($sdCurTime);
|
||||||
|
my $sdRoundMonthValue = HourCounter_RoundMonth($sdRoundHourLast);
|
||||||
|
my $isMonthChanged = ($sdRoundMonthCurTime != $sdRoundMonthValue) || $hash->{helper}{forceMonthChange};
|
||||||
|
|
||||||
|
my $sdRoundYearCurTime = HourCounter_RoundYear($sdCurTime);
|
||||||
|
my $sdRoundYearValue = HourCounter_RoundYear($sdRoundHourLast);
|
||||||
|
my $isYearChanged = ($sdRoundYearCurTime != $sdRoundYearValue) || $hash->{helper}{forceYearChange};
|
||||||
|
#HourCounter_Log $hash, 0,"sdRoundYearCurTime : $sdRoundYearCurTime";
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
# stop if disabled
|
||||||
|
last if ( AttrVal( $name, 'disable', '0' ) eq '1' );
|
||||||
|
|
||||||
|
# variables for controlling
|
||||||
|
my $resetDayCounter='';
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 5, "value:$valuePara changedTimestamp:".$hash->{helper}{changedTimestamp} ;
|
||||||
|
|
||||||
|
# --------------- basic init after startup of fhem or reload
|
||||||
|
if ( $hash->{helper}{isFirstRun} )
|
||||||
|
{
|
||||||
|
$hash->{helper}{isFirstRun}=undef;
|
||||||
|
$hash->{helper}{sdRoundHourLast} = $sdRoundHourLast;
|
||||||
|
HourCounter_Log $hash, 4, "first run done";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------ basic init, when first run after initial definition in fhem.cfg
|
||||||
|
if ( !defined(ReadingsVal( $name, 'value', undef)) || $hash->{helper}{forceClear} )
|
||||||
|
{
|
||||||
|
HourCounter_Log $hash, 4, "counters cleared "
|
||||||
|
."forceClear:$hash->{helper}{forceClear}"
|
||||||
|
." def(valueOld)".defined($valueOld);
|
||||||
|
|
||||||
|
if (!defined($valueOld))
|
||||||
|
{ # create readings without triggering
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
readingsBulkUpdate( $hash, 'tickHour', 0);
|
||||||
|
readingsBulkUpdate( $hash, 'tickDay', 0);
|
||||||
|
readingsBulkUpdate( $hash, 'tickWeek', 0);
|
||||||
|
readingsBulkUpdate( $hash, 'tickMonth',0);
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! ($hash->{helper}{forceClear})) # set value at basic init
|
||||||
|
{
|
||||||
|
$valueOld = 0;
|
||||||
|
$value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$timeIncrement = 0;
|
||||||
|
$hash->{helper}{forceClear} = '';
|
||||||
|
$countsPerDay = 0;
|
||||||
|
$countsOverall = 0;
|
||||||
|
|
||||||
|
$pulseTimeIncrement = 0;
|
||||||
|
$pulseTimePerDay = 0;
|
||||||
|
$pulseTimeOverall = 0;
|
||||||
|
|
||||||
|
$pauseTimeIncrement = 0;
|
||||||
|
$pauseTimePerDay = 0;
|
||||||
|
$pauseTimeOverall = 0;
|
||||||
|
|
||||||
|
$state = 0;
|
||||||
|
$clearDate = TimeNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------- handling of transitions
|
||||||
|
|
||||||
|
my $hasValueChanged = ( $isOffDefined && $valuePara == $valueOld ) ? '' :1;
|
||||||
|
|
||||||
|
# -------------- positive edge
|
||||||
|
if ( $hasValueChanged && $valuePara == 1 )
|
||||||
|
{
|
||||||
|
$hash->{helper}{changedTimestamp} = TimeNow();
|
||||||
|
|
||||||
|
$value = $valuePara;
|
||||||
|
$valueOld = $valuePara;
|
||||||
|
|
||||||
|
# handling of counters
|
||||||
|
$countsPerDay = ReadingsVal( $name, "countsPerDay", 0 ) + 1; # counter inkrementieren
|
||||||
|
$countsOverall = ReadingsVal( $name, "countsOverall", 0 ) + 1; # counter inkrementieren
|
||||||
|
|
||||||
|
if ($isOffDefined) # handling of pause
|
||||||
|
{
|
||||||
|
$pauseTimeIncrement = $timeIncrement;
|
||||||
|
|
||||||
|
$pauseTimePerDay = ReadingsVal( $name, "pauseTimePerDay", 0 ) + $pauseTimeIncrement;
|
||||||
|
$pauseTimeOverall = ReadingsVal( $name, "pauseTimeOverall", 0 )+ $pauseTimeIncrement;
|
||||||
|
my $pulsInc = ReadingsVal( $name, "pulseTimeIncrement", 0 );
|
||||||
|
}
|
||||||
|
HourCounter_Log $hash, 4, "rising edge; countPerDay:$countsPerDay";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------ negative edge
|
||||||
|
elsif ($isOffDefined && $hasValueChanged && $valuePara == 0 )
|
||||||
|
{
|
||||||
|
$hash->{helper}{changedTimestamp} = TimeNow();
|
||||||
|
$value = $valuePara;
|
||||||
|
$valueOld = $valuePara;
|
||||||
|
|
||||||
|
# handling of pulse time
|
||||||
|
$pulseTimeIncrement = $timeIncrement;
|
||||||
|
$pulseTimePerDay = ReadingsVal( $name, "pulseTimePerDay", 0 ) + $pulseTimeIncrement;
|
||||||
|
$pulseTimeOverall = ReadingsVal( $name, "pulseTimeOverall", 0 ) + $pulseTimeIncrement;
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 4, "falling edge pulseTimeIncrement:$pulseTimeIncrement";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# --------------- Day change, update pauseTime and pulseTime
|
||||||
|
if ($isDayChanged)
|
||||||
|
{
|
||||||
|
HourCounter_Log $hash, 4, "day change isDayChanged:$isDayChanged";
|
||||||
|
|
||||||
|
### accumulate incurred times until day change
|
||||||
|
if ($valueOld==0)
|
||||||
|
{
|
||||||
|
$pauseTimeIncrement = $timeIncrement;
|
||||||
|
$pauseTimePerDay = ReadingsVal( $name, "pauseTimePerDay", 0 ) + $timeIncrement;
|
||||||
|
$pauseTimeOverall = ReadingsVal( $name, "pauseTimeOverall", 0 ) + $timeIncrement;
|
||||||
|
}
|
||||||
|
elsif ($valueOld==1)
|
||||||
|
{
|
||||||
|
$pulseTimeIncrement = $timeIncrement;
|
||||||
|
$pulseTimePerDay = ReadingsVal( $name, "pulseTimePerDay", 0 ) + $timeIncrement;
|
||||||
|
$pulseTimeOverall = ReadingsVal( $name, "pulseTimeOverall", 0 ) + $timeIncrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
# update timestamp of reading value with current time
|
||||||
|
$hash->{helper}{changedTimestamp}=TimeNow();
|
||||||
|
|
||||||
|
# logabriss vermeiden
|
||||||
|
$pulseTimeIncrement = ReadingsVal( $name, "pulseTimeIncrement", 0 ) if (!defined($pulseTimeIncrement));
|
||||||
|
$pulseTimeOverall = ReadingsVal( $name, "pulseTimeOverall", 0 ) if (!defined($pulseTimeOverall));
|
||||||
|
|
||||||
|
$pauseTimeIncrement = ReadingsVal( $name, "pauseTimeIncrement", 0 ) if (!defined($pauseTimeIncrement));
|
||||||
|
$pauseTimeOverall = ReadingsVal( $name, "pauseTimeOverall", 0 ) if (!defined($pauseTimeOverall));
|
||||||
|
|
||||||
|
$countsOverall = ReadingsVal( $name, "countsOverall", 0 ) if (!defined($countsOverall));
|
||||||
|
|
||||||
|
$value = $valueOld;
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 4, "pulseTimeIncrement:$pulseTimeIncrement pauseTimeIncrement:$pauseTimeIncrement";
|
||||||
|
$resetDayCounter=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$state =$countsPerDay if (defined($countsPerDay) && ReadingsVal( $name, "state", 0 ) !=$countsPerDay);
|
||||||
|
|
||||||
|
|
||||||
|
### -------------- update readings
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
readingsBulkUpdate( $hash, "countsPerDay", $countsPerDay ) if defined($countsPerDay);
|
||||||
|
readingsBulkUpdate( $hash, "countsOverall", $countsOverall ) if defined($countsOverall);
|
||||||
|
|
||||||
|
readingsBulkUpdate( $hash, "pulseTimeIncrement",$pulseTimeIncrement ) if defined($pulseTimeIncrement);
|
||||||
|
readingsBulkUpdate( $hash, "pulseTimePerDay", $pulseTimePerDay ) if defined($pulseTimePerDay);
|
||||||
|
readingsBulkUpdate( $hash, "pulseTimeOverall", $pulseTimeOverall) if defined($pulseTimeOverall);
|
||||||
|
|
||||||
|
readingsBulkUpdate( $hash, "pauseTimeIncrement",$pauseTimeIncrement) if defined($pauseTimeIncrement);
|
||||||
|
readingsBulkUpdate( $hash, "pauseTimePerDay", $pauseTimePerDay) if defined($pauseTimePerDay);
|
||||||
|
readingsBulkUpdate( $hash, "pauseTimeOverall", $pauseTimeOverall) if defined($pauseTimeOverall);
|
||||||
|
|
||||||
|
readingsBulkUpdate( $hash, "value", $value) if defined($value);
|
||||||
|
readingsBulkUpdate( $hash, 'state', $state) if defined($state);
|
||||||
|
readingsBulkUpdate( $hash, 'clearDate', $clearDate) if defined($clearDate);
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
|
# --------------- fire time interval ticks for hour,day,month
|
||||||
|
if ($isHourChanged)
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceHourChange} = '';
|
||||||
|
$hash->{helper}{sdRoundHourLast} = $sdRoundHour;
|
||||||
|
readingsSingleUpdate( $hash, 'tickHour', 1,1);
|
||||||
|
HourCounter_Log $hash, 4, "tickHour fired";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isDayChanged)
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceDayChange}= '';
|
||||||
|
readingsSingleUpdate( $hash, 'tickDay', 1,1);
|
||||||
|
HourCounter_Log $hash, 4, "tickDay fired";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isWeekChanged)
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceWeekChange}= '';
|
||||||
|
readingsSingleUpdate( $hash, 'tickWeek', 1,1);
|
||||||
|
HourCounter_Log $hash, 4, "tickWeek fired";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isMonthChanged)
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceMonthChange}= '';
|
||||||
|
readingsSingleUpdate( $hash, 'tickMonth', 1,1);
|
||||||
|
HourCounter_Log $hash, 4, "tickMonth fired";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isYearChanged)
|
||||||
|
{
|
||||||
|
$hash->{helper}{forceYearChange}= '';
|
||||||
|
readingsSingleUpdate( $hash, 'tickYear', 1,1);
|
||||||
|
HourCounter_Log $hash, 4, "tickYear fired";
|
||||||
|
}
|
||||||
|
|
||||||
|
HourCounter_ExecQueue($hash); # execute command queue
|
||||||
|
|
||||||
|
# ----------- pending request for resetting all day counters
|
||||||
|
if ($resetDayCounter)
|
||||||
|
{
|
||||||
|
$resetDayCounter=undef;
|
||||||
|
|
||||||
|
### reset all day counters
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
readingsBulkUpdate( $hash, "countsPerDay", 0 );
|
||||||
|
readingsBulkUpdate( $hash, "pulseTimePerDay", 0 );
|
||||||
|
readingsBulkUpdate( $hash, "pauseTimePerDay", 0 );
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------ calculate seconds until next hour starts
|
||||||
|
my $actTime = int(gettimeofday());
|
||||||
|
my ($sec,$min,$hour) = localtime($actTime);
|
||||||
|
my $nextHourTime = int(($actTime + 3600)/3600)*3600; # round to next hour start
|
||||||
|
my $nextCall = $nextHourTime - $actTime;
|
||||||
|
|
||||||
|
HourCounter_Log $hash, 5, "nextCall:$nextCall changedTimestamp:"
|
||||||
|
.$hash->{helper}{changedTimestamp};
|
||||||
|
|
||||||
|
RemoveInternalTimer($name);
|
||||||
|
InternalTimer( gettimeofday() + $nextCall, "HourCounter_Run", $hash->{NAME}, 0 );
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<a name="HourCounter"></a>
|
||||||
|
<h3>HourCounter</h3>
|
||||||
|
<ul>
|
||||||
|
<a name="HourCounterdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<br/>
|
||||||
|
<code>define <name> HourCounter <pattern_for_ON> [<pattern_for_OFF>] </code>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
Hourcounter can detect both the activiy-time and the inactivity-time of a property.<br/>
|
||||||
|
The "pattern_for_ON" identifies the events, that signal the activity of the desired property.<br/>
|
||||||
|
The "pattern_for_OFF" identifies the events, that signal the inactivity of the desired property.<br/>
|
||||||
|
<br/>
|
||||||
|
If "pattern_for_OFF" is not defined, any matching event of "patter_for_ON" will be counted.<br/>
|
||||||
|
Otherwise only the rising edges of "pattern_for_ON" will be counted.<br/>
|
||||||
|
This means a "pattern_for_OFF"-event must be detected before a "pattern_for_ON"-event is accepted. <br/>
|
||||||
|
<br/>
|
||||||
|
"pattern_for_ON" and "pattern_for_OFF" must be formed using the following structure:<br/>
|
||||||
|
<br/>
|
||||||
|
<code>device:[regexp]</code>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
The forming-rules are the same as for the notify-command.<br/>
|
||||||
|
<br/>
|
||||||
|
<b>Example:</b><br/>
|
||||||
|
<br/>
|
||||||
|
<ul>
|
||||||
|
<code>define BurnerCounter HourCounter SHUTTER_TEST:on SHUTTER_TEST:off</code>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="HourCounterset"></a>
|
||||||
|
<b>Set-Commands</b>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> clear</code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>
|
||||||
|
clears the readings countsPerDay, countsOverall,pauseTimeIncrement, pauseTimePerDay, pauseTimeOverall,
|
||||||
|
pulseTimeIncrement, pulseTimePerDay, pulseTimeOverall by setting to 0.<br/>
|
||||||
|
The reading clearDate is set to the current Date/Time.
|
||||||
|
</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> countsOverall <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading countsOverall to the given value.This is the total-counter.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> countsPerDay <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading countsPerDay to the given value. This reading will automatically be set to 0, after change of day.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> pauseTimeIncrement <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading pauseTimeIncrement to the given value.<br/>
|
||||||
|
This reading in seconds is automatically set after a rising edge of the property.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> pauseTimeOverall <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading pauseTimeOverall to the given value.<br/>
|
||||||
|
This reading in seconds is automatically adjusted after a change of pauseTimeIncrement.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> pauseTimePerDay <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading pauseTimePerDay to the given value.<br/>
|
||||||
|
This reading in seconds is automatically adjusted after a change of pauseTimeIncrement and set to 0 after change of day.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> pulseTimeIncrement <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading pulseTimeIncrement to the given value.<br/>
|
||||||
|
This reading in seconds is automatically set after a falling edge of the property.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> pulseTimeOverall <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading pulseTimeOverall to the given value.<br/>
|
||||||
|
This reading in seconds is automatically adjusted after a change of pulseTimeIncrement.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> pulseTimePerDay <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Sets the reading pulseTimePerDay to the given value.<br/>
|
||||||
|
This reading in seconds is automatically adjusted after a change of pulseTimeIncrement and set to 0 after change of day.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> forceHourChange </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>This modifies the reading tickHour, which is automatically modified after change of hour.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> forceDayChange </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>This modifies the reading tickDay, which is automatically modified after change of day.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> forceWeekChange </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>This modifies the reading tickWeek, which is automatically modified after change of week.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> forceMonthChange </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>This modifies the reading tickMonth, which is automatically modified after change of month.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> forceYearChange </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>This modifies the reading tickYear, which is automatically modified after change of year.</ul><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<code>set <name> app.* <value> </code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Any reading with the leading term "app", can be modified.<br/
|
||||||
|
This can be useful for user-readings.
|
||||||
|
</ul><br/>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="HourCounterget"></a>
|
||||||
|
<b>Get-Commands</b><br/>
|
||||||
|
<ul>
|
||||||
|
<br/>
|
||||||
|
<code>get <name> version</code>
|
||||||
|
<br/><br/>
|
||||||
|
<ul>Get the current version of the module.</ul>
|
||||||
|
<br/>
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<a name="HourCounterattr"></a>
|
||||||
|
<b>Attributes</b><br/><br/>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<b>Additional information</b><br/><br/>
|
||||||
|
<ul>
|
||||||
|
<li><a href="http://forum.fhem.de/index.php/topic,12216.0.html">Discussion in FHEM forum</a></li><br/>
|
||||||
|
<li><a href="http://www.fhemwiki.de/wiki/HourCounter">WIKI information in FHEM Wiki</a></li><br/>
|
||||||
|
<li>
|
||||||
|
The file 99_UtilsHourCounter.pm is a reference implementation for user defined extensions.<br/>
|
||||||
|
It shows how to create sum values for hours,days, weeks, months and years.<br/>
|
||||||
|
This file is located in the sub-folder contrib. For further information take a look to FHEM Wiki.<br/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
=end html
|
||||||
|
=cut
|
||||||
|
|
@ -250,6 +250,7 @@ FHEM/98_CustomReadings.pm HCS http://forum.fhem.de Unterstue
|
|||||||
FHEM/98_dewpoint.pm Joachim http://forum.fhem.de Automatisierung
|
FHEM/98_dewpoint.pm Joachim http://forum.fhem.de Automatisierung
|
||||||
FHEM/98_dummy.pm rudolfkoenig http://forum.fhem.de Automatisierung
|
FHEM/98_dummy.pm rudolfkoenig http://forum.fhem.de Automatisierung
|
||||||
FHEM/98_fheminfo.pm mfr69bs http://forum.fhem.de Sonstiges
|
FHEM/98_fheminfo.pm mfr69bs http://forum.fhem.de Sonstiges
|
||||||
|
FHEM/98_HourCounter.pm john http://forum.fhem.de MAX
|
||||||
FHEM/98_notice.pm mfr69bs http://forum.fhem.de Sonstiges
|
FHEM/98_notice.pm mfr69bs http://forum.fhem.de Sonstiges
|
||||||
FHEM/98_pilight.pm andreas-fey http://forum.fhem.de Unterstuetzende Dienste
|
FHEM/98_pilight.pm andreas-fey http://forum.fhem.de Unterstuetzende Dienste
|
||||||
FHEM/98_rain.pm baumrasen http://forum.fhem.de Sonstiges
|
FHEM/98_rain.pm baumrasen http://forum.fhem.de Sonstiges
|
||||||
|
283
fhem/contrib/99_UtilsHourCounter.pm
Normal file
283
fhem/contrib/99_UtilsHourCounter.pm
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
##############################################
|
||||||
|
# $Id: 99_UtilsHourCounter.pm 6802 2014-10-25 18:00:00Z john $
|
||||||
|
#
|
||||||
|
# This ist a reference implementation for enhanced features for modul hourCounter
|
||||||
|
#
|
||||||
|
# This module is written by john.
|
||||||
|
#
|
||||||
|
# This file is part of fhem.
|
||||||
|
#
|
||||||
|
# Fhem 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.
|
||||||
|
#
|
||||||
|
# Fhem 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.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Changelog
|
||||||
|
#
|
||||||
|
# 04.02.14 - 1.00 modul created
|
||||||
|
# 06.02.14 - 1.01 fixed: wrong timing in assignment appUtilization
|
||||||
|
# 17.03.14 - 1.01 added: appHC_OnYear
|
||||||
|
|
||||||
|
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use POSIX;
|
||||||
|
use vars qw(%defs);
|
||||||
|
use vars qw(%modules);
|
||||||
|
|
||||||
|
#require "98_HourCounter.pm";
|
||||||
|
|
||||||
|
my $UtilsHourCounter_Version="1.02 - 17.03.2014 (john)";
|
||||||
|
sub Log3($$$);
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
sub UtilsHourCounter_Initialize($$)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
Log3 '', 3, "[UtilsHourCounter] Init Done with Version $UtilsHourCounter_Version";
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# yearly tasks
|
||||||
|
#
|
||||||
|
sub appHC_OnYear($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # name objects, name des parameters, wert des parameters
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
my $appCountsPerYear = ReadingsVal ($name, 'appCountsPerYearTemp' ,0);
|
||||||
|
my $appOpHoursPerYear = ReadingsVal ($name, 'appOpHoursPerYearTemp' ,0);
|
||||||
|
|
||||||
|
#---------------
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerYearTemp' , 0 );
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerYear' , $appCountsPerYear );
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerYearTemp' , 0 );
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerYear' , $appOpHoursPerYear );
|
||||||
|
|
||||||
|
readingsEndUpdate($hash, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# monthly tasks
|
||||||
|
#
|
||||||
|
sub appHC_OnMonth($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # name objects, name des parameters, wert des parameters
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
my $appCountsPerMonth = ReadingsVal ($name, 'appCountsPerMonthTemp' ,0);
|
||||||
|
my $appOpHoursPerMonth = ReadingsVal ($name, 'appOpHoursPerMonthTemp' ,0);
|
||||||
|
|
||||||
|
#---------------
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerMonthTemp' , 0 );
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerMonth' , $appCountsPerMonth );
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerMonthTemp' , 0 );
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerMonth' , $appOpHoursPerMonth );
|
||||||
|
|
||||||
|
readingsEndUpdate($hash, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# weekly tasks
|
||||||
|
sub appHC_OnWeek($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # name objects, name des parameters, wert des parameters
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
my $appCountsPerWeek = ReadingsVal ($name, 'appCountsPerWeekTemp' ,0);
|
||||||
|
my $appOpHoursPerWeek = ReadingsVal ($name, 'appOpHoursPerWeekTemp' ,0);
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerWeekTemp' , 0);
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerWeek' , $appCountsPerWeek);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerWeekTemp' , 0);
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerWeek' , $appOpHoursPerWeek);
|
||||||
|
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# dayly tasks
|
||||||
|
sub appHC_OnDay($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # name objects, name des parameters, wert des parameters
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
my $appCountsPerDay = ReadingsVal($name, 'countsPerDay',0);
|
||||||
|
my $pulseTimePerDay = ReadingsVal($name, 'pulseTimePerDay',0);
|
||||||
|
|
||||||
|
#HourCounter_Log $hash, 2, "pulseTimePerDay:$pulseTimePerDay";
|
||||||
|
|
||||||
|
my $appOpHoursPerDay = $pulseTimePerDay/3600;
|
||||||
|
my $appOpHoursPerWeekTemp = ReadingsVal ($name,'appOpHoursPerWeekTemp',0 )+$appOpHoursPerDay;
|
||||||
|
my $appOpHoursPerMonthTemp =ReadingsVal ($name,'appOpHoursPerMonthTemp',0 )+$appOpHoursPerDay;
|
||||||
|
my $appOpHoursPerYearTemp =ReadingsVal ($name,'appOpHoursPerYearTemp',0 )+$appOpHoursPerDay;
|
||||||
|
|
||||||
|
my $appUtilizationTempOld = ReadingsVal ($name,'appUtilizationTempOld',0 );
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerDay' , $appCountsPerDay);
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerDay' , $appOpHoursPerDay);
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerDayTemp' , 0);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerWeekTemp' , $appOpHoursPerWeekTemp);
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerMonthTemp', $appOpHoursPerMonthTemp);
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerYearTemp' , $appOpHoursPerYearTemp);
|
||||||
|
|
||||||
|
readingsBulkUpdate ($hash, 'appUtilization', $appUtilizationTempOld);
|
||||||
|
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# hourly tasks
|
||||||
|
sub appHC_OnHour($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # name objects, name des parameters, wert des parameters
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
my $appCountsPerHourTemp = ReadingsVal($name, 'appCountsPerHourTemp',0);
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerHourTemp', 0 );
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerHour', $appCountsPerHourTemp);
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
# --------------------------------------------------
|
||||||
|
# task on count change
|
||||||
|
sub appHC_OnCount($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # name objects, name des parameters, wert des parameters
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
|
||||||
|
my $appCountsPerHourTemp = ReadingsVal($name,'appCountsPerHourTemp',0) + 1;
|
||||||
|
my $appCountsPerWeekTemp = ReadingsVal($name,'appCountsPerWeekTemp',0) + 1;
|
||||||
|
my $appCountsPerMonthTemp = ReadingsVal($name,'appCountsPerMonthTemp',0)+ 1;
|
||||||
|
my $appCountsPerYearTemp = ReadingsVal($name,'appCountsPerYearTemp',0) + 1;
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerHourTemp', $appCountsPerHourTemp );
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerWeekTemp', $appCountsPerWeekTemp );
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerMonthTemp',$appCountsPerMonthTemp );
|
||||||
|
readingsBulkUpdate ($hash, 'appCountsPerYearTemp',$appCountsPerYearTemp );
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# task on value change
|
||||||
|
sub appHC_OnValueChanged($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # object name, parameter name, parameter value
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
# acquire needed values
|
||||||
|
my $secs= HourCounter_SecondsOfDay();
|
||||||
|
my $pulseTimePerDay = ReadingsVal($name,'pulseTimePerDay',0);
|
||||||
|
|
||||||
|
# calc utilization
|
||||||
|
$secs= 1 if ($secs==0); # no zero division
|
||||||
|
my $appUtilizationTempOld = ReadingsVal($name,'appUtilizationTemp',0);
|
||||||
|
my $appUtilizationTemp = $pulseTimePerDay/$secs*100;
|
||||||
|
|
||||||
|
# calc operating hours
|
||||||
|
my $appOpHoursPerDayTemp =$pulseTimePerDay/3600; # operating time per Day temporary
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
readingsBulkUpdate ($hash, 'appOpHoursPerDayTemp' , $appOpHoursPerDayTemp);
|
||||||
|
readingsBulkUpdate ($hash, 'appUtilizationTemp' , $appUtilizationTemp );
|
||||||
|
readingsBulkUpdate ($hash, 'appUtilizationTempOld' , $appUtilizationTempOld );
|
||||||
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# central event dispatcher
|
||||||
|
sub appHCNotify($$$)
|
||||||
|
{
|
||||||
|
my ($name,$part0,$part1) = @_; # object name, parameter name, parameter value
|
||||||
|
$name = "?" if (!defined($name));
|
||||||
|
$part0='' if (!defined($part0));
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
|
return undef if (!defined ($hash));
|
||||||
|
|
||||||
|
# HourCounter_Log $hash, 2, "Name:$name part0:$part0 part1:$part1";
|
||||||
|
|
||||||
|
# event dispatcher for delayed execution
|
||||||
|
if ($part0 eq "value:") # trigger CN.Test value: 1
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnValueChanged q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
elsif ($part0 eq "countsOverall:")
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnCount q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
elsif ($part0 eq "tickHour:") # trigger CN.Test tickHour: 1
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnHour q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
elsif ($part0 eq "tickDay:") # trigger CN.Test tickDay: 1
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnDay q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
elsif ($part0 eq "tickWeek:")
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnWeek q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
elsif ($part0 eq "tickMonth:")
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnMonth q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
elsif ($part0 eq "tickYear:")
|
||||||
|
{
|
||||||
|
HourCounter_cmdQueueAdd($hash,"appHC_OnYear q($name),q($part0),q($part1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
@ -110,10 +110,10 @@
|
|||||||
<a href="#HTTPSRV">HTTPSRV</a>
|
<a href="#HTTPSRV">HTTPSRV</a>
|
||||||
<a href="#Heating_Control">Heating_Control</a>
|
<a href="#Heating_Control">Heating_Control</a>
|
||||||
<a href="#holiday">holiday</a>
|
<a href="#holiday">holiday</a>
|
||||||
|
<a href="#HourCounter">HourCounter</a>
|
||||||
<a href="#LightScene">LightScene</a>
|
<a href="#LightScene">LightScene</a>
|
||||||
<a href="#mailcheck">mailcheck</a>
|
<a href="#mailcheck">mailcheck</a>
|
||||||
<a href="#notify">notify</a>
|
<a href="#notify">notify</a>
|
||||||
<a href="#PID">PID</a>
|
|
||||||
<a href="#PRESENCE">PRESENCE</a>
|
<a href="#PRESENCE">PRESENCE</a>
|
||||||
<a href="#PachLog">PachLog</a>
|
<a href="#PachLog">PachLog</a>
|
||||||
<a href="#RSS">RSS</a>
|
<a href="#RSS">RSS</a>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user