| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- #
- #
- # 81_M232Counter.pm
- # written by Dr. Boris Neubert 2007-11-26
- # e-mail: omega at online dot de
- #
- ##############################################
- # $Id: 81_M232Counter.pm 16375 2018-03-10 15:40:02Z neubert $
- package main;
- use strict;
- use warnings;
- use Time::HiRes qw(gettimeofday);
- sub M232Counter_Get($@);
- sub M232Counter_Set($@);
- sub M232Counter_SetBasis($@);
- sub M232Counter_Define($$);
- sub M232Counter_GetStatus($);
- ###################################
- sub
- M232Counter_Initialize($)
- {
- my ($hash) = @_;
- $hash->{GetFn} = "M232Counter_Get";
- $hash->{SetFn} = "M232Counter_Set";
- $hash->{DefFn} = "M232Counter_Define";
- $hash->{AttrList} = "dummy:1,0 model:M232Counter";
- }
- ###################################
- sub
- M232Counter_GetStatus($)
- {
- my ($hash) = @_;
- if(!$hash->{LOCAL}) {
- InternalTimer(gettimeofday()+$hash->{INTERVAL}, "M232Counter_GetStatus", $hash, 1);
- }
- my $name = $hash->{NAME};
- my $r= $hash->{READINGS};
- my $d = IOWrite($hash, "z");
- if(!defined($d)) {
- my $msg = "M232Counter $name tick count read error";
- Log3 $name, 2, $msg;
- return $msg;
- }
- # time
- my $tn = TimeNow();
- #tsecs
- my $tsecs= time(); # number of non-leap seconds since January 1, 1970, UTC
- # previous tsecs
- my $tsecs_prev;
- if(defined($r->{tsecs})) {
- $tsecs_prev= $r->{tsecs}{VAL};
- } else{
- $tsecs_prev= $tsecs; # 1970-01-01
- }
- # basis
- my $basis;
- if(defined($r->{basis})) {
- $basis= $r->{basis}{VAL};
- } else {
- $basis= 0;
- }
- my $basis_prev= $basis;
- # previous count (this variable is currently unused)
- my $count_prev;
- if(defined($r->{count})) {
- $count_prev= $r->{count}{VAL};
- } else {
- $count_prev= 0;
- }
- # current count
- my $count= hex $d;
- # If the counter reaches 65536, the counter does not wrap around but
- # stops at 0. We therefore purposefully reset the counter to 0 before
- # it reaches its final tick count.
- if($count > 64000) {
- $basis+= $count;
- $count= 0;
- $r->{basis}{VAL} = $basis;
- $r->{basis}{TIME}= $tn;
- my $ret = IOWrite($hash, "Z1");
- if(!defined($ret)) {
- my $msg = "M232Counter $name reset error";
- Log3 $name, 2, $msg;
- return $msg;
- }
- }
- # previous value
- my $value_prev;
- if(defined($r->{value})) {
- $value_prev= $r->{value}{VAL};
- } else {
- $value_prev= 0;
- }
- # current value
- my $value= ($basis+$count) * $hash->{FACTOR};
- # round to 3 digits
- $value= int($value*1000.0+0.5)/1000.0;
- # set new values
- $r->{count}{TIME} = $tn;
- $r->{count}{VAL} = $count;
- $r->{value}{TIME} = $tn;
- $r->{value}{VAL} = $value;
- $r->{tsecs}{TIME} = $tn;
- $r->{tsecs}{VAL} = $tsecs;
- $hash->{CHANGED}[0]= "count: $count";
- $hash->{CHANGED}[1]= "value: $value";
- # delta
- my $tsecs_delta= $tsecs-$tsecs_prev;
- my $count_delta= ($count+$basis)-($count_prev+$basis_prev);
- if($tsecs_delta>0) {
- my $delta= ($count_delta/$tsecs_delta)*$hash->{DELTAFACTOR};
- # round to 3 digits
- $delta= int($delta*1000.0+0.5)/1000.0;
- $r->{delta}{TIME} = $tn;
- $r->{delta}{VAL} = $delta;
- $hash->{CHANGED}[2]= "delta: $delta";
- }
- if(!$hash->{LOCAL}) {
- DoTrigger($name, undef) if($init_done);
- }
- $hash->{STATE} = $value;
- Log3 $name, 4, "M232Counter $name: $value $hash->{UNIT}";
- return $hash->{STATE};
- }
- ###################################
- sub
- M232Counter_Get($@)
- {
- my ($hash, @a) = @_;
- return "argument is missing" if(int(@a) != 2);
- my $msg;
- if($a[1] ne "status") {
- return "unknown get value, valid is status";
- }
- $hash->{LOCAL} = 1;
- my $v = M232Counter_GetStatus($hash);
- delete $hash->{LOCAL};
- return "$a[0] $a[1] => $v";
- }
- #############################
- sub
- M232Counter_Calibrate($@)
- {
- my ($hash, $value) = @_;
- my $rm= undef;
- my $name = $hash->{NAME};
- # adjust basis
- my $tn = TimeNow();
- $hash->{READINGS}{basis}{VAL}= $value / $hash->{FACTOR};
- $hash->{READINGS}{basis}{TIME}= $tn;
- $hash->{READINGS}{count}{VAL}= 0;
- $hash->{READINGS}{count}{TIME}= $tn;
- # recalculate value
- $hash->{READINGS}{value}{VAL} = $value;
- $hash->{READINGS}{value}{TIME} = $tn;
- # reset counter
- my $ret = IOWrite($hash, "Z1");
- if(!defined($ret)) {
- my $rm = "M232Counter $name read error";
- Log3 $name, 2, $rm;
- }
- return $rm;
- }
- #############################
- sub
- M232Counter_Set($@)
- {
- my ($hash, @a) = @_;
- my $u = "Usage: set <name> value <value>\n" .
- "set <name> interval <seconds>\n" ;
- return $u if(int(@a) != 3);
- my $reading= $a[1];
- if($a[1] eq "value") {
- my $value= $a[2];
- my $rm= M232Counter_Calibrate($hash, $value);
- } elsif($a[1] eq "interval") {
- my $interval= $a[2];
- $hash->{INTERVAL}= $interval;
- } else {
- return $u;
- }
- return undef;
- }
- #############################
- sub
- M232Counter_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- return "syntax: define <name> M232Counter [unit] [factor] [deltaunit] [deltafactor]"
- if(int(@a) < 2 && int(@a) > 6);
- my $unit= ((int(@a) > 2) ? $a[2] : "ticks");
- my $factor= ((int(@a) > 3) ? $a[3] : 1.0);
- my $deltaunit= ((int(@a) > 4) ? $a[4] : "ticks per second");
- my $deltafactor= ((int(@a) > 5) ? $a[5] : 1.0);
- $hash->{UNIT}= $unit;
- $hash->{FACTOR}= $factor;
- $hash->{DELTAUNIT}= $deltaunit;
- $hash->{DELTAFACTOR}= $deltafactor;
- $hash->{INTERVAL}= 60; # poll every minute per default
- AssignIoPort($hash);
- if(!$hash->{LOCAL}) {
- InternalTimer(gettimeofday()+60, "M232Counter_GetStatus", $hash, 0);
- }
- return undef;
- }
- 1;
- =pod
- =item summary digital input of a ELV M232 module
- =item summary_DE digitaler Eingang eines ELV-M232-Moduls
- =begin html
- <a name="M232Counter"></a>
- <h3>M232Counter</h3>
- <ul>
- <a name="M232Counterdefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> M232Counter [unit [factor [deltaunit [deltafactor]]]]</code>
- <br><br>
- Define at most one M232Counter for a M232 device. Defining a M232Counter
- will schedule an internal task, which periodically reads the status of the
- counter, and triggers notify/filelog commands. <code>unit</code> is the unit
- name, <code>factor</code> is used to calculate the reading of the counter
- from the number of ticks. <code>deltaunit</code> is the unit name of the counter
- differential per second, <code>deltafactor</code> is used to calculate the
- counter differential per second from the number of ticks per second.<br><br>
- Default values:
- <ul>
- <li>unit: ticks</li>
- <li>factor: 1.0</li>
- <li>deltaunit: ticks per second</li>
- <li>deltafactor: 1.0</li>
- </ul>
- <br>Note: the parameters in square brackets are optional. If you wish to
- specify an optional parameter, all preceding parameters must be specified
- as well.
- <br><br>Examples:
- <ul>
- <code>define counter M232Counter turns</code><br>
- <code>define counter M232Counter kWh 0.0008 kW 2.88</code>
- (one tick equals 1/1250th kWh)<br>
- </ul>
- <br>
- Do not forget to start the counter (with <code>set .. start</code> for
- M232) or to start the counter and set the reading to a specified value
- (with <code>set ... value</code> for M232Counter).<br><br>
- To avoid issues with the tick count reaching the end point, the device's
- internal counter is automatically reset to 0 when the tick count is 64,000
- or above and the reading <i>basis</i> is adjusted accordingly.
- <br><br>
- </ul>
- <a name="M232Counterset"></a>
- <b>Set </b>
- <ul>
- <code>set <name> value <value></code>
- <br><br>
- Sets the reading of the counter to the given value. The counter is reset
- and started and the offset is adjusted to value/unit.
- <br><br>
- <code>set <name> interval <interval></code>
- <br><br>
- Sets the status polling interval in seconds to the given value. The default
- is 60 seconds.
- <br><br>
- </ul>
- <a name="M232Counterget"></a>
- <b>Get</b>
- <ul>
- <code>get <name> status</code>
- <br><br>
- Gets the reading of the counter multiplied by the factor from the
- <code>define</code> statement. Wraparounds of the counter are accounted for
- by an offset (see reading <code>basis</code> in the output of the
- <code>list</code> statement for the device).
- <br><br>
- </ul>
- <a name="M232Counterattr"></a>
- <b>Attributes</b>
- <ul>
- <li><a href="#attrdummy">dummy</a></li><br>
- <li><a href="#model">model</a> (M232Counter)</li>
- </ul>
- <br>
- </ul>
- =end html
- =cut
|