| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- ##############################################
- # $Id: 70_SCIVT.pm 3738 2013-08-18 14:13:59Z rudolfkoenig $
- package main;
- use strict;
- use warnings;
- use Device::SerialPort;
- my %sets = (
- "cmd" => "",
- "freq" => "",
- );
- #####################################
- sub
- SCIVT_Initialize($)
- {
- my ($hash) = @_;
- # Consumer
- $hash->{DefFn} = "SCIVT_Define";
- $hash->{GetFn} = "SCIVT_Get";
- $hash->{SetFn} = "SCIVT_Set";
- $hash->{AttrList}= "model:SCD10,SCD20,SCD30";
- }
- #####################################
- sub
- SCIVT_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- return "Define the serial device as a parameter, use none for a fake device"
- if(@a != 3);
- $hash->{STATE} = "Initialized";
- my $dev = $a[2];
- Log3 $hash, 1, "SCIVT device is none, commands will be echoed only"
- if($dev eq "none");
- if($dev ne "none") {
- Log3 $hash, 3, "SCIVT opening device $dev";
- my $po = new Device::SerialPort ($dev);
- return "SCIVT Can't open $dev: $!" if(!$po);
- Log3 $hash, 2, "SCIVT opened device $dev";
- $po->close();
- }
- $hash->{DeviceName} = $dev;
- $hash->{Timer} = 900; # call every 15 min
- $hash->{Cmd} = 'F'; # get all data, min/max unchanged
- my $tn = TimeNow();
- $hash->{READINGS}{"freq"}{TIME} = $tn;
- $hash->{READINGS}{"freq"}{VAL} = $hash->{Timer};
- $hash->{READINGS}{"cmd"}{TIME} = $tn;
- $hash->{READINGS}{"cmd"}{VAL} = $hash->{Cmd};
- $hash->{CHANGED}[0] = "freq: $hash->{Timer}";
- $hash->{CHANGED}[1] = "cmd: $hash->{Cmd}";
- # InternalTimer blocks if init_done is not true
- my $oid = $init_done;
- $init_done = 1;
- SCIVT_GetStatus($hash);
- $init_done = $oid;
- return undef;
- }
- #####################################
- sub
- SCIVT_Set($@)
- {
- my ($hash, @a) = @_;
- return "\"set SCIVT\" needs at least two parameter" if(@a < 3);
- my $name = $hash->{NAME};
- Log3 $name, 4, "SCIVT Set request $a[1] $a[2], old: Timer:$hash->{Timer} Cmd: $hash->{Cmd}";
- return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
- if(!defined($sets{$a[1]}));
- $name = shift @a;
- my $type = shift @a;
- my $arg = join("", @a);
- my $tn = TimeNow();
- if($type eq "freq")
- {
- if ($arg > 0)
- {
- $hash->{Timer} = $arg * 60;
- $hash->{READINGS}{$type}{TIME} = $tn;
- $hash->{READINGS}{$type}{VAL} = $hash->{Timer};
- $hash->{CHANGED}[0] = "$type: $hash->{Timer}";
- }
- }
- if($type eq "cmd")
- {
- if ($arg eq "F")
- {
- $hash->{Cmd} = 'F'; # F : get all data
- }
- if ($arg eq "L") # L : get all data and clear min-/max values
- {
- $hash->{Cmd} = 'L';
- }
- $hash->{READINGS}{$type}{TIME} = $tn;
- $hash->{READINGS}{$type}{VAL} = $hash->{Cmd};
- $hash->{CHANGED}[0] = "$type: $hash->{Cmd}";
- }
- DoTrigger($name, undef) if($init_done);
- Log3 $name, 3, "SCIVT Set result Timer:$hash->{Timer} sec Cmd:$hash->{Cmd}";
- return "SCIVT => Timer:$hash->{Timer} Cmd:$hash->{Cmd}";
- }
- #####################################
- sub
- SCIVT_Get($@)
- {
- my ($hash, @a) = @_;
- return "get for an SCIVT device needs exactly one parameter" if(@a != 2);
- my $name = $hash->{NAME};
- my $v;
- if($a[1] eq "data")
- {
- $v = SCIVT_GetLine($hash->{DeviceName}, $hash->{Cmd});
- if(!defined($v))
- {
- Log3 $name, 2, "SCIVT Get $a[1] error";
- return "$a[0] $a[1] => Error";
- }
- $v =~ s/[\r\n]//g; # Delete the NewLine
- $hash->{READINGS}{$a[1]}{VAL} = $v;
- $hash->{READINGS}{$a[1]}{TIME} = TimeNow();
- }
- else
- {
- if($a[1] eq "param")
- {
- $v = "$hash->{DeviceName} $hash->{Timer} $hash->{Cmd}";
- }
- else
- {
- return "Unknown argument $a[1], must be data or param";
- }
- }
- Log3 $name, 3, "SCIVT Get $a[1] $v";
- return "$a[0] $a[1] => $v";
- }
- #####################################
- sub
- SCIVT_GetStatus($)
- {
- my ($hash) = @_;
- my $dnr = $hash->{DEVNR};
- my $name = $hash->{NAME};
- # Call us in n minutes again.
- InternalTimer(gettimeofday()+ $hash->{Timer}, "SCIVT_GetStatus", $hash,1);
- my %vals;
- my $result = SCIVT_GetLine($hash->{DeviceName}, $hash->{Cmd});
- if(!defined($result))
- {
- Log3 $name, 4, "SCIVT read error, retry $hash->{DeviceName}, $hash->{Cmd}";
- $result = SCIVT_GetLine($hash->{DeviceName}, $hash->{Cmd});
- }
- if(!defined($result))
- {
- Log3 $name, 2, "SCIVT read error, abort $hash->{DeviceName}, $hash->{Cmd}";
- $hash->{STATE} = "timeout";
- return $hash->{STATE};
- }
- if (length($result) < 10)
- {
- Log3 $name, 2, "SCIVT incomplete line ($result)";
- $hash->{STATE} = "incomplete";
- }
- else
- {
- $result =~ s/^.*R://;
- $result =~ s/[\r\n ]//g;
- Log3 $name, 3, "SCIVT $result (raw)";
- $result=~ s/,/./g;
- my @data = split(";", $result);
- my @names = ("Vs", "Is", "Temp", "minV", "maxV", "minI", "maxI");
- my $tn = TimeNow();
- for(my $i = 0; $i < int(@names); $i++)
- {
- $hash->{CHANGED}[$i] = "$names[$i]: $data[$i]";
- $hash->{READINGS}{$names[$i]}{TIME} = $tn;
- $hash->{READINGS}{$names[$i]}{VAL} = $data[$i];
- }
- DoTrigger($name, undef) if($init_done);
- $result =~ s/;/ /g;
- $hash->{STATE} = "$result";
- }
- return $hash->{STATE};
- }
- #####################################
- sub
- SCIVT_GetLine($$)
- {
- my $retry = 0;
- my ($dev,$cmd) = @_;
- return "R:13,66; 0,0;30;13,62;15,09;- 0,2; 2,8;\n"
- if($dev eq "none"); # Fake-mode
- my $serport = new Device::SerialPort ($dev);
- if(!$serport) {
- Log3 undef, 1, "SCIVT: Can't open $dev: $!";
- return undef;
- }
- $serport->reset_error();
- $serport->baudrate(1200);
- $serport->databits(8);
- $serport->parity('none');
- $serport->stopbits(1);
- $serport->handshake('none');
- my $rm = "SCIVT timeout reading the answer";
- my $data="";
- $serport->write($cmd);
- sleep(1);
- for(;;)
- {
- my ($rout, $rin) = ('', '');
- vec($rin, $serport->FILENO, 1) = 1;
- my $nfound = select($rout=$rin, undef, undef, 3.0);
- if($nfound < 0) {
- $rm = "SCIVT Select error $nfound / $!";
- goto DONE;
- }
- last if($nfound == 0);
- my $buf = $serport->input();
- if(!defined($buf) || length($buf) == 0) {
- $rm = "SCIVT EOF on $dev";
- goto DONE;
- }
- $data .= $buf;
- if($data =~ m/[\r\n]/) { # Newline received
- $serport->close();
- return $data;
- }
- }
- DONE:
- $serport->close();
- Log3 undef, 3, "SCIVT $rm";
- return undef;
- }
- 1;
- =pod
- =begin html
- <a name="SCIVT"></a>
- <h3>SCIVT</h3>
- <ul>
- <br>
- <a name="SCIVTdefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> SCIVT <SCD-device></code>
- <br><br>
- Define a SCD series solar controler device. Details see <a
- href="http://english.ivt-hirschau.de/content.php?parent_id=CAT_64&doc_id=DOC_118">here</a>.
- You probably need a Serial to USB controller like the PL2303.
- <br>
- Defining an SCIVT device will schedule an internal task, which reads the
- status of the device every 5 minutes, and triggers notify/filelog commands.
- <br>Note: Currently this device does not support a "set" function, only
- a single get function which reads the device status immediately.
- <br><br>
- Example:
- <ul>
- <code>define scd SCIVT /dev/ttyUSB2</code><br>
- </ul>
- <br>
- </ul>
- <a name="SVICTset"></a>
- <b>Set</b> <ul>N/A</ul><br>
- <a name="SVICTget"></a>
- <b>Get</b>
- <ul>
- <code>get SCVIT data</code>
- <br>
- </ul>
- <br>
- <a name="SVICTattr"></a>
- <b>Attributes</b>
- <ul>
- <li><a href="#model">model</a> (SCD)</li>
- </ul>
- <br>
- </ul>
- =end html
- =cut
|