| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- ##############################################################################
- # $Id: 51_Netzer.pm 12059 2016-08-22 21:14:59Z klauswitt $
- # 51_Netzer.pm
- #
- ##############################################################################
- # Modul for Netzer access
- #
- #
- #
- ##############################################################################
- package main;
- use strict;
- use warnings;
- use POSIX;
- use Scalar::Util qw(looks_like_number);
- use IO::File;
- #vorhandene Ports
- my @ports = ( "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m" );
- sub Netzer_Initialize($) {
- my ($hash) = @_;
- $hash->{DefFn} = "Netzer_Define";
- $hash->{ReadFn} = "Netzer_Read";
- $hash->{GetFn} = "Netzer_Get";
- $hash->{SetFn} = "Netzer_Set";
- $hash->{AttrFn} = "Netzer_Attr";
- $hash->{UndefFn} = "Netzer_Undef";
- $hash->{ExceptFn} = "Netzer_Except";
- $hash->{AttrList} = "poll_interval" .
- " Port_a:in,out,cnt" . " Port_b:in,out,cnt" . " Port_c:in,out,cnt" .
- " Port_d:in,out,PWM" .
- " Port_e:in,out,ADC" . " Port_f:in,out,ADC" .
- " Port_g:in,out" . " Port_h:in,out" . " Port_i:in,out" .
- " Port_j:in,out,PWM" .
- " Port_k:in,out" . " Port_l:in,out" . " Port_m:in,out";
- }
- #############################################
- sub Netzer_Define($$) {
- my ($hash, $def) = @_;
- my @args = split("[ \t]+", $def);
- my $menge = int(@args);
- if (int(@args) < 2) {
- return "Define: to less arguments. Usage:\n" .
- "define <name> Netzer <Host>:<port>";
- }
- #Pruefen, ob GPIO bereits verwendet
- foreach my $dev (devspec2array("TYPE=$hash->{TYPE}")) {
- if ($args[2] eq InternalVal($dev,"DeviceName","")) {
- return "IP-Address $args[2] already used by $dev";
- }
- }
- my $name = $args[0];
- $hash->{DeviceName} = $args[2];
- Netzer_conn($hash);
- # create default attributes
- #my $msg = CommandAttr(undef, $name . ' direction input');
- #return $msg if ($msg);
- return undef;
- }
- #############################################
- sub Netzer_Get($;$) {
- my (@a) = @_;
- my $hash = $a[0];
- my $name = $hash->{NAME};
- my ($port,$cnt) = split("_", $a[2]) if ( defined($a[2]) );
- my $function = $attr{$name}{"Port_".$port} if defined($port) && defined($attr{$name}{"Port_".$port});
- my $buf = "";
- if ( !( defined($a[2]) ) ) {
- foreach (@ports) {
- if(defined($attr{$name}) && defined($attr{$name}{"Port_".$_})) {
- my $function = $attr{$name}{"Port_".$_};
- if ($function =~ m/^(PWM|ADC)$/i) {
- $buf = $_."=?\r\n";
- Netzer_send($hash, $buf);
- } elsif ($function =~ m/^(cnt)$/i) {
- $buf = "z".$_."=?\r\n";
- Netzer_send($hash, $buf);
- }
- }
- }
- $buf = "x=?\r\n";
- } elsif ( defined($port) && grep( /^$port$/, @ports ) && defined($cnt) && $cnt eq "counter" && defined($function) && $function eq "cnt" ) {
- $buf = "z" . $port ."=?\r\n";
- } elsif ( defined($port) && grep( /^$a[2]$/, @ports ) && $port ne "?" ) {
- $buf = $a[2]."=?\r\n";
- } else {
- my $list = "";
- foreach (@ports) {
- #next if (wenn port nicht genutzt werden soll);
- $list .= " " unless ($list eq "");
- $list .= $_ . ':noArg';
- $list .= " " . $_ . "_counter:noArg" if( defined($attr{$name}) && defined($attr{$name}{"Port_".$_}) && $attr{$name}{"Port_".$_} eq "cnt" );
- }
- return 'Unknown argument ' . $a[2] . ', choose one of ' . $list;
- }
- Netzer_send($hash, $buf);
- return;
- }
- #############################################
- sub Netzer_Set($@) {
- my ($hash, @a) = @_;
- my $name = $a[0];
- my $port = $a[1] if (defined ($a[1]));
- my $val = $a[2] if (defined ($a[2]));
- ($port, my $cnt) = split("_", $port) if defined($port) && $port =~ m/(_counter)$/;
- my $function = $attr{$name}{"Port_".$port} if defined($port) && defined($attr{$name}{"Port_".$port});
- if ( defined($function) && ( ( $function=~ m/^(PWM|out)$/i && !defined($cnt) ) || ( $function=~ m/^(cnt)$/i && defined($cnt) ) ) ) {
- my $msg = "$name: wrong value ". (defined($val)?"$val ":"") . "for Port_$a[1], valid values: 0-";
- my $buf = undef;
- if ( $function eq "cnt" && defined($cnt) ) {
- return $msg . "32767" if !defined($val) || $val > 32767 || $val < 0;
- $buf = "z" . $port;
- } else {
- return $msg . "1023" if ($function eq "PWM" && (!defined($val) || $val > 1023 || $val < 0));
- return $msg . "1" if ($function eq "out" && (!defined($val) || $val > 1 || $val < 0));
- $buf = $port;
- }
- $val = sprintf("%x",$val);
- $buf .= "=$val\r\n";
- Netzer_send($hash, $buf);
- } else {
- my $list = "";
- foreach (@ports) {
- if(defined($attr{$name}) && defined($attr{$name}{"Port_".$_})) {
- my $function = $attr{$name}{"Port_".$_};
- if ($function eq "out") {
- $list .= " " unless ($list eq "");
- $list .= $_ . ':0,1';
- } elsif ($function eq "PWM") {
- $list .= " " unless ($list eq "");
- $list .= $_ . ':slider,0,1,1023';
- } elsif ($function eq "cnt") {
- $list .= " " unless ($list eq "");
- $list .= $_ . "_counter" ;
- }
- }
- }
- return 'Unknown argument ' . (defined($port)?$port:"") . (defined($cnt)?"_$cnt":"") . ', choose one of ' . $list;
- }
- return;
- }
- #############################################
- sub Netzer_Attr(@) {
- my (undef, $name, $attr, $val) = @_;
- my $hash = $defs{$name};
- my $msg = '';
- #Log3 $name, 1, "Name: $name Attr: $attr Wert: $val";
-
- if ($attr eq 'poll_interval') {
- if ( defined($val) ) {
- if ( looks_like_number($val) && $val > 0) {
- RemoveInternalTimer($hash);
- InternalTimer(1, 'Netzer_Poll', $hash, 0);
- } else {
- $msg = "$hash->{NAME}: Wrong poll intervall defined. poll_interval must be a number > 0";
- }
- } else { #wird auch aufgerufen wenn $val leer ist, aber der attribut wert wird auf 1 gesetzt
- RemoveInternalTimer($hash);
- }
- }
-
- if (!$val) {
- delete ($hash->{READINGS}{$attr."_counter"}) if defined($hash->{READINGS}{$attr."_counter"});
- } elsif ($val =~ m/^(in|out)$/) {
- delete ($hash->{READINGS}{$attr."_counter"}) if defined($hash->{READINGS}{$attr."_counter"});
- } elsif ($attr =~ m/^(Port_[a-c])$/) {
- $msg = "$hash->{NAME}: $attr wrong function $val. Use in, out or cnt" if $val !~ m/^(cnt)$/;
- delete ($hash->{READINGS}{$attr."_counter"}) if defined($hash->{READINGS}{$attr."_counter"}) && $val !~ m/^(cnt)$/;
- } elsif ($attr =~ m/^(Port_[d|j])$/) {
- $msg = "$hash->{NAME}: $attr wrong function $val. Use in, out or PWM" if $val !~ m/^(PWM)$/;
- delete ($hash->{READINGS}{$attr."_counter"}) if defined($hash->{READINGS}{$attr."_counter"});
- } elsif ($attr =~ m/^(Port_[e|f])$/) {
- $msg = "$hash->{NAME}: $attr wrong function $val. Use in, out or ADC" if $val !~ m/^(ADC)$/;
- delete ($hash->{READINGS}{$attr."_counter"}) if defined($hash->{READINGS}{$attr."_counter"});
- }
- return ($msg) ? $msg : undef;
- }
- #############################################
- sub Netzer_Read($) {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- my $buf;
- my $ret = sysread($hash->{CD}, $buf, 1024*1024);
- if(!defined($ret) || $ret <= 0) {
- Netzer_conn($hash);
- return;
- } else {
- chomp ($buf);
- my @msg = split(" ", $buf);
- readingsBeginUpdate($hash);
- foreach (@msg) {
- #abfangen wenn mehrere botschafen
- my ($port, $val) = split("=", $_);
- $val =~ s/ //g;
- $val = hex($val);
- my $sval;
- #my ($bufc) = $_ =~ /(\d+)/;
- if ($port eq "x") {
- for (my $i = 0; $i <= 12; $i++) {
- next if defined($attr{$name}{"Port_".$ports[$i]}) && $attr{$name}{"Port_".$ports[$i]} =~ m/^(PWM|ADC)$/;
- $sval = hex($val) & (1 << $i);
- $sval = $sval == 0 ? "0" :"1";
- readingsBulkUpdate($hash, 'Port_'.$ports[$i] , $sval) if (ReadingsVal($name,'Port_'.$ports[$i],0) ne $sval);
- }
- } elsif ( grep( /^$port$/, @ports ) ) {
- readingsBulkUpdate($hash, 'Port_'.$port , $val);
- } elsif ( grep( ($port =~ s/z// ), @ports ) ) {
- readingsBulkUpdate($hash, 'Port_'.$port.'_counter' , ($val > 32767?"overflow":$val));
- }
- }
- readingsBulkUpdate($hash, 'received', $buf);
- #readingsBulkUpdate($hash, 'zeichenmenge', $ret);
- readingsEndUpdate($hash, 1);
- }
- }
- #############################################
- sub Netzer_Poll($) {#Update of all Readings
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Netzer_Get($hash);
- my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0);
- if ($pollInterval > 0) {
- InternalTimer(gettimeofday() + ($pollInterval * 60), 'Netzer_Poll', $hash, 0);
- }
- return;
- }
- #############################################
- sub Netzer_Undef($$) {
- my ($hash, $arg) = @_;
- if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) {
- RemoveInternalTimer($hash);
- }
- Netzer_disconn($hash,0);
- return undef;
- }
- #############################################
- sub Netzer_send($$) {
- my ($hash, $buf) = @_;
- my $cnt= length ($buf);
- if (not defined($hash->{CD})) {
- Log3 $hash, 1, "$hash->{NAME}: Verbindung unterbrochen, versuche Verbindungsaufbau";
- Netzer_conn($hash);
- }
- if ($hash->{CD}) {
- syswrite($hash->{CD}, $buf, $cnt) ;
- } else {
- Log3 $hash, 1, "$hash->{NAME}: Daten konnten nicht gesendet werden";
- }
- }
- #############################################
- sub Netzer_conn($) {
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- Netzer_disconn($hash,0);
- my $timeout = $hash->{TIMEOUT} ? $hash->{TIMEOUT} : 3;
- my $conn = IO::Socket::INET->new(PeerAddr=>"$hash->{DeviceName}", Timeout => $timeout);
- if($conn) {
- $hash->{STATE} = "Connected";
-
- $hash->{FD} = $conn->fileno();
- $hash->{CD} = $conn; # sysread / close won't work on fileno
- $hash->{CONNECTS}++;
- $selectlist{$name} = $hash;
- Log(GetLogLevel($name,3), "$name: connected to $hash->{DeviceName}");
- } else {
- Netzer_disconn($hash, 1);
- }
- }
- #############################################
- sub Netzer_disconn($$) {
- my ($hash, $connect) = @_;
- my $name = $hash->{NAME};
- return if( !$hash->{CD} );
- close($hash->{CD}) if($hash->{CD});
- delete($hash->{FD});
- delete($hash->{CD});
- delete($selectlist{$name});
- $hash->{STATE} = "Disconnected";
- if($connect) {
- Log3 $name, 4, "$name: Connect failed.";
- } else {
- Log3 $name, 4, "$name: Disconnected";
- }
- }
- 1;
- =pod
- =item device
- =item summary controls/reads GPIO pins on an Netzer
- =item summary_DE steuern/lesen der GPIO Pins eines Netzer
- =begin html
- <a name="Netzer"></a>
- <h3>Netzer</h3>
- <ul>
- The <a href="http://www.mobacon.de/wiki/doku.php/en/netzer/index">Netzer</a> realizes an Ethernet interface on a PIC-based platform. As a gateway module it enables communication between standard TCP/IP sockets and serial busses like I2C, SPI and UART.
- Also up to 13 GPIO pins can be accessed. This Modul provides access to these GPIO pins on a Netzer running IO_base in Version 1.5.
- There are two pins usable as ADC channel, two as PMW outputs, three as counter and three can generate an interrupt.
- The GPIO pins are configured a input per default. Before a port can be used as output it must be <a href="http://www.mobacon.de/wiki/doku.php/en/netzer/io">configured</a> via the embedded webpage.
- If one of the input ports is configured to send interrupt events on GPIO Server, on every event all port values will be updated.
- All ports can be read and controlled individually by the function readingsProxy.
- <br><br>
- <a name="NetzerDefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> Netzer <host:port></code>
- <br><br>
- </ul>
- <a name="NetzerSet"></a>
- <b>Set</b>
- <ul>
- <code>set <name> <port[_counter]> <value></code>
- <br>
- Where <value> is a character between <code>a</code> and <code>m</code> <br> according to the port. If Port attr is <code>cnt</code> an aditional value <port_counter> can be set.<br>
- Only ports with corresponding attr Port_[a-m] set to <code>PWM</code> or <code>out</code> can be used.<br>
- If Port attr is:<ul>
- <li>PWM <value> can be a number between 0 and 1023</li>
- <li>out <value> can be a number between 0 and 1</li>
- <li>cnt <port_counter> <value> can be a number between 0 and 32767</li>
- <br></ul>
- </ul>
- <b>Get</b>
- <ul>
- <code>get <name> [<port[_counter]>]</code>
- <br>
- If no <port> is set, all readings will be updated.<br>
- <port> is a character between <code>a</code> and <code>m</code><br> according to the port. If Port attr is <code>cnt</code> an aditional reading <port_counter> can be read.
- <br><br>
- </ul>
- <a name="NetzerAttr"></a>
- <b>Attributes</b>
- <ul>
- <a name="poll_interval"></a>
- <li>poll_interval<br>
- Set the polling interval in minutes to query the sensor for new measured values.
- Default: 5, valid values: decimal number</li><br>
- <a name="Port_<port>"></a>
- <li>Port_<port><br>
- <ul>
- Configuration for Netzer port.<br>
- <port> is a character between <code>a</code> and <code>m</code>.<br>
- <li><code>in</code>: Port is defined as input. Same behavior as no attribute. Set is not avaliable for this port.<br>
- Can be used for all ports</li>
- <li><code>out</code>: Port is defined as output. Set is avaliable for this port with <value> between 0 and 1.<br>
- Can be used for all ports</li>
- <li><code>cnt</code>: Port is defined as input. Set is not avaliable for this port.<br>
- An second reading: Port_<port>_counter is avaiable.
- It can be updated with <code>get</code> an changed with <code>set</code>.<br>
- Port_<port>_counter <value> = 0-32767 or overflow if outside this range.<br>
- Can be used for ports a,b,c</li>
- <li><code>ADC</code>: Port is defined as analog input. <code>Get</code> <value> is 0-1023 according the voltage on port. Set is not avaliable for this port.<br>
- Can be used for ports e,f</li>
- <li><code>PWM</code>: Port is defined as PWM output. <code>Set</code> and <code>get</code> <value> is 0-1023 according the duty cycle on the port.<br>
- Can be used for ports d,j</li>
- </ul>
- </li><br>
- </ul>
- <br>
- </ul>
- =end html
- =begin html_DE
- <a name="Netzer"></a>
- <h3>Netzer</h3>
- <ul>
- The <a href="http://www.mobacon.de/wiki/doku.php/de/netzer/index">Netzer</a> realisiert ein Ethernetinterface auf PIC-Basis. Es agiert als Gateway zwischen TCP/IP und verschiedenen seriellen Busses wie I2C, SPI oder UART. Es können bis zu 13 GPIO Pins angesprochen (gelesen oder geschrieben) werden.
- This Modul ermöglicht den Zugriff auf diese GPIO Pin's auf einem Netzer mit IO_base in Version 1.5.
- Es gibt zwei als ADC nutzbare Pin's channel, 2 als PMW Ausgänge, drei als Zähler sowie drei die einen Interrupt auslösen können.
- Die GPIO Pin's sind standardmäßig als Eingänge konfiguriert. Bevor ein Pin anderweitig genutzt werden kann, muss er über die eingebaute Website entsprechend <a href="http://www.mobacon.de/wiki/doku.php/de/netzer/io">eingestellt</a> werden.
- Ist einer der Eingänge als Inerrupteingang eingestellt, werden bei jedem Interrupereignis die Weter sämtlicher Ports aktualisiert.
- <br><br>
- <a name="NetzerDefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> Netzer <host:port></code>
- <br><br>
- </ul>
- <a name="NetzerSet"></a>
- <b>Set</b>
- <ul>
- <code>set <name> <port[_counter]> <value></code>
- <br>
- Dabei ist <value> ein dem Port entsprechender Buchstabe zwischen <code>a</code> und <code>m</code>. Besitzt der Port das Attribut <code>cnt</code> so kann ein weiterer Wert <port_counter> gesetzt werden.<br>
- Ausschließlich Port's die über Attribut Port_[a-m] auf <code>PWM</code> oder <code>out</code> gesetzt sind können benutzt werden.<br>
- Bei Port Attribut:<ul>
- <li>PWM <value> kann ein Wert zwischen 0 und 1023 sein</li>
- <li>out <value> kann ein Wert zwischen 0 und 1 sein</li>
- <li>cnt <port_counter> <value> kann ein Wert zwischen 0 und 32767 sein</li>
- <br></ul>
- </ul>
- <b>Get</b>
- <ul>
- <code>get <name> [<port[_counter]>]</code>
- <br>
- Ohne <port> werde alle Werte aktualisiert.<br>
- Wenn <port> ein Buchstabe zwischen <code>a</code> und <code>m</code><br> ist, wird der Portwert aktualisiert und bei Port Attribut <code>cnt</code> kann ein weiterer Zählerwert <port_counter> gelesen werden.<br>
- <br>
- </ul>
- <a name="NetzerAttr"></a>
- <b>Attributes</b>
- <ul>
- <a name="poll_interval"></a>
- <li>poll_interval<br>
- Aktualisierungsintervall aller Werte in Minuten.<br>
- Standard: 5, gültige Werte: Dezimalzahl
- </li><br>
- <a name="Port_<port>"></a>
- <li>Port_<port><br>
- <ul>
- Konfiguration des jeweiligen GPIO.<br>
- <port> ist ein Buchstabe zwischen <code>a</code> und <code>m</code>.<br>
- <li><code>in</code>: Port ist Eingang. Kann auch weggelassen werden, da Standard. Set ist für diesen Port nicht verfügbar.<br>
- Nutzbar für alle Port's</li>
- <li><code>out</code>: Port ist Ausgang. Set kann <value> zwischen 0 und 1 haben.<br>
- Nutzbar für alle Port's</li>
- <li><code>cnt</code>: Port ist Eingang. Set ist für diesen Port nicht verfügbar.<br>
- Ein weiteres Reading: Port_<port>_counter ist verfügbar.
- Dieses kann auch mit <code>get</code> gelesen und mit <code>set</code> verändert werden.<br>
- Port_<port>_counter <value> = 0-32767 oder overflow wenn es ausserhalb dieses Bereichs liegt.<br>
- Nutzbar für Port's a,b,c</li>
- <li><code>ADC</code>: Port ist Analogeingang. <code>get</code> <value> ist 0-1023 entsprechend der Spannung am Port. Set ist für diesen Port nicht verfügbar.<br>
- Nutzbar für Port's e,f</li>
- <li><code>PWM</code>: Port ist PWM-Ausgang. <code>set</code> und <code>get</code> <value> ist 0-1023 entsprechend des Dutycycle am Port.<br>
- Nutzbar für Port's d,j</li>
- </ul>
- </li><br>
- </ul>
- <br>
- </ul>
- =end html_DE
- =cut
|