From fbc242b555ab1574ffdb57b67d448ebad58087ca Mon Sep 17 00:00:00 2001 From: charlie71 <> Date: Sun, 27 Aug 2017 05:25:39 +0000 Subject: [PATCH] 44_S7: DWRITE supports trigger_length < 1s git-svn-id: https://svn.fhem.de/fhem/trunk@14965 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/44_S7_ARead.pm | 1 + fhem/FHEM/44_S7_AWrite.pm | 2 +- fhem/FHEM/44_S7_DRead.pm | 5 +- fhem/FHEM/44_S7_DWrite.pm | 123 ++++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 43 deletions(-) diff --git a/fhem/FHEM/44_S7_ARead.pm b/fhem/FHEM/44_S7_ARead.pm index a429fabca..11d34a1ba 100644 --- a/fhem/FHEM/44_S7_ARead.pm +++ b/fhem/FHEM/44_S7_ARead.pm @@ -4,6 +4,7 @@ package main; use strict; use warnings; +use Time::HiRes qw(gettimeofday); #use Switch; require "44_S7_Client.pm"; diff --git a/fhem/FHEM/44_S7_AWrite.pm b/fhem/FHEM/44_S7_AWrite.pm index 9963ab650..ff61cd6dd 100644 --- a/fhem/FHEM/44_S7_AWrite.pm +++ b/fhem/FHEM/44_S7_AWrite.pm @@ -4,8 +4,8 @@ package main; use strict; use warnings; +use Time::HiRes qw(gettimeofday); -#use Switch; require "44_S7_Client.pm"; my %gets = ( diff --git a/fhem/FHEM/44_S7_DRead.pm b/fhem/FHEM/44_S7_DRead.pm index 2f6440642..35beeabe1 100644 --- a/fhem/FHEM/44_S7_DRead.pm +++ b/fhem/FHEM/44_S7_DRead.pm @@ -4,9 +4,8 @@ package main; use strict; use warnings; +use Time::HiRes qw(gettimeofday); -#use Switch; -#use 44_S7_Client; my %gets = ( @@ -608,4 +607,4 @@ Note: the required memory area need to be with in the configured PLC reading of =end html_DE -=cut \ No newline at end of file +=cut diff --git a/fhem/FHEM/44_S7_DWrite.pm b/fhem/FHEM/44_S7_DWrite.pm index c7383e479..1918aa2d0 100644 --- a/fhem/FHEM/44_S7_DWrite.pm +++ b/fhem/FHEM/44_S7_DWrite.pm @@ -4,8 +4,7 @@ package main; use strict; use warnings; - -#use Switch; +use Time::HiRes qw(gettimeofday usleep); my %sets = ( "on" => "", @@ -18,6 +17,15 @@ my %gets = ( "STATE" => "" ); + +sub __isfloat { + my $val = shift; + + # return $val =~ m/^\d+.\d+$/; + return $val =~ m/^[-+]?\d*\.?\d*$/; + + #[-+]?[0-9]*\.?[0-9]* +} ##################################### sub S7_DWrite_Initialize($) { my $hash = shift @_; @@ -249,24 +257,30 @@ sub S7_DWrite_setABit($$) { if ( $newValue eq "on" || $newValue eq "trigger" ) { $b = 1; } + + my $byte; + my $bit; + my $readbuffer; + my @cbuffer; + my $tbuffer; + if ( $shash->{S7TYPE} eq "S5" ) { #S5 #lesen wir das aktuelle byte - my $byte = int( $position / 8 ); - my $bit = int( $position % 8 ); - my $readbuffer; + $byte = int( $position / 8 ); + $bit = int( $position % 8 ); ( $res, $readbuffer ) = S7_ReadBlockFromPLC( $shash, $writeAreaIndex, $dbNR, $byte, 1 ); if ( $res == 0 && length($readbuffer) == 1 ) { #reading was OK #setzen/löschen wir das gewünsche bit - my $tbuffer = join( ", ", unpack( "H2 " x length($readbuffer), $readbuffer ) ); + $tbuffer = join( ", ", unpack( "H2 " x length($readbuffer), $readbuffer ) ); Log3( undef, 5, "S5 Read old Value <-- " . $tbuffer ." now changing bitNr: ".$bit ); - my @cbuffer = unpack( "C" x length($readbuffer), $readbuffer); + @cbuffer = unpack( "C" x length($readbuffer), $readbuffer); if ($b == 1) { $cbuffer[0] |= (1 << $bit); } else { @@ -292,7 +306,7 @@ sub S7_DWrite_setABit($$) { } - } else { + } else { my $error = $shash->{S7PLCClient}->getErrorStr($res); my $msg = @@ -301,38 +315,68 @@ sub S7_DWrite_setABit($$) { S7_reconnect($shash); #lets try a reconnect return ( -2, $msg ); - } - } - else { + + } else { #S7 - $res = - S7_WriteBitToPLC( $shash, $writeAreaIndex, $dbNR, $position, $b ); - } - - if ( $res == 0 ) { - main::readingsSingleUpdate( $hash, "state", $newValue, 1 ); - } - else { - main::readingsSingleUpdate( $hash, "state", "", 1 ); - } - - if ( $newValue eq "trigger" ) { - - my $triggerLength = 1; - if ( defined( $main::attr{$name}{trigger_length} ) ) { - $triggerLength = $main::attr{$name}{trigger_length}; - } - - InternalTimer( gettimeofday() + $triggerLength, - "S7_DWrite_SwitchOff", $hash, 1 ); - } - - return undef; - + $res = S7_WriteBitToPLC( $shash, $writeAreaIndex, $dbNR, $position, $b ); } + if ( $newValue eq "trigger" ) { + + my $triggerLength = 1;#1 second + if ( defined( $main::attr{$name}{trigger_length} ) ) { + $triggerLength = $main::attr{$name}{trigger_length}; + } + + if ($triggerLength >=1 ) { + InternalTimer( gettimeofday() + $triggerLength, "S7_DWrite_SwitchOff", $hash, 1 ); + } else { + #we use usleep + $triggerLength = $triggerLength*1000*1000; + $triggerLength = int($triggerLength); + + usleep ($triggerLength); + + if ( $shash->{S7TYPE} eq "S5" ) { + $cbuffer[0] &= (~(1 << $bit)) & 0xFF; + + + $readbuffer = pack( "C" x 1, @cbuffer); + + #schreiben wir das byte + $tbuffer = join( ", ", unpack( "H2 " x length($readbuffer), $readbuffer ) ); + Log3( undef, 5, "S5 Write new Value 2 <-- " . $tbuffer ); + $res = S7_WriteToPLC( $shash, $writeAreaIndex, $dbNR, $byte, &S7Client::S7WLByte , $readbuffer ); + + if ( $res != 0 ) { + my $error = $shash->{S7PLCClient}->getErrorStr($res); + my $msg = + "$name S7_DWrite_setABit -S5- S7_WriteToPLC2 error: $res=$error"; + Log3( $name, 3, $msg ); + } + + } else { + #S7 + $res = + S7_WriteBitToPLC( $shash, $writeAreaIndex, $dbNR, $position, 0 ); + + } + $newValue = "off"; + } + } + + if ( $res == 0 ) { + main::readingsSingleUpdate( $hash, "state", $newValue, 1 ); + } else { + main::readingsSingleUpdate( $hash, "state", "", 1 ); + } + + return undef; + +} + ##################################### sub S7_DWrite_Set(@) { @@ -394,7 +438,7 @@ sub S7_DWrite_setABit($$) { my $now = gettimeofday(); foreach my $clientName (@clientList) { - + my $h = $defs{$clientName}; if ( $h->{TYPE} eq "S7_DWrite" @@ -494,6 +538,7 @@ sub S7_DWrite_setABit($$) { if ($changed == 1) { main::readingsSingleUpdate( $h, $reading, $valueText, 1 ); } + } } @@ -571,7 +616,7 @@ sub S7_DWrite_setABit($$) { my $hash = $defs{$name}; if ( $cmd eq "set" ) { if ( $aName eq "trigger_length" ) { - if ( $aVal ne int($aVal) ) { + if ( !__isfloat ($aVal) ) { Log3 $name, 3, "S7_DWrite: Invalid $aName in attr $name $aName ($aVal is not a number): $@"; return "Invalid $aName : $aVal is not a number"; @@ -623,7 +668,7 @@ Note: the required memory area need to be with in the configured PLC reading of
Attr
The following parameters are used to scale every reading
Attr
The following parameters are used to scale every reading