diff --git a/fhem/FHEM/98_ArduCounter.pm b/fhem/FHEM/98_ArduCounter.pm index e0ae8e4d4..81d31e7d1 100755 --- a/fhem/FHEM/98_ArduCounter.pm +++ b/fhem/FHEM/98_ArduCounter.pm @@ -41,8 +41,11 @@ # 2017-01-02 modification for sketch 1.7, monitor clock drift difference between ardino and Fhem # 2017-01-04 some more beatification in logging # 2017-01-06 avoid reopening when disable=0 is set during startup +# 2017-02-06 Doku korrigiert +# 2017-02-18 fixed a bug that caused a missing open when the device is defined while fhem is already initialized # ideas / todo: +# @@ -62,7 +65,7 @@ my %ArduCounter_gets = ( "info" => "" ); -my $ArduCounter_Version = '4.5 - 6.1.2017'; +my $ArduCounter_Version = '4.7 - 18.2.2017'; # # FHEM module intitialisation @@ -114,7 +117,12 @@ sub ArduCounter_Define($$) my $name = $a[0]; my $dev = $a[2]; - $dev .= '@38400' if ($dev !~ /.+@[0-9]+/); + if ($dev !~ /.+@([0-9]+)/) { + $dev .= '@38400'; + } else { + Log3 $name, 3, "$name: Warning: connection speed $1 is not the default for the ArduCounter firmware" + if ($1 != 38400); + } $hash->{buffer} = ""; $hash->{DeviceName} = $dev; $hash->{VersionModule} = $ArduCounter_Version; @@ -127,6 +135,10 @@ sub ArduCounter_Define($$) #$attr{$name}{'flashCommand'} = 'avrdude -p atmega328P -b 57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]'; $attr{$name}{'flashCommand'} = 'avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]'; } + + if ($init_done) { + ArduCounter_Open($hash); + } return; } @@ -161,7 +173,26 @@ sub ArduCounter_Undef($$) ######################################################## -# Notify for INITIALIZED +# Open Device +sub ArduCounter_Open($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + DevIo_OpenDev($hash, 0, 0); + if ($hash->{FD}) { + my $now = gettimeofday(); + my $hdl = AttrVal($name, "helloSendDelay", 3); + # send hello if device doesn't say "Started" withing $hdl seconds + RemoveInternalTimer ("sendHello:$name"); + InternalTimer($now+$hdl, "ArduCounter_SendHello", "sendHello:$name", 0); + } +} + + +######################################################## +# Notify for INITIALIZED or Modified +# -> Open connection to device sub ArduCounter_Notify($$) { my ($hash, $source) = @_; @@ -181,12 +212,7 @@ sub ArduCounter_Notify($$) } Log3 $name, 5, "$name: Notify called with events: @{$events}, open device and set timer to send hello to device"; - DevIo_OpenDev( $hash, 0, 0); - - my $now = gettimeofday(); - RemoveInternalTimer ("sendHello:$name"); - my $helloDelay = AttrVal($name, "helloSendDelay", 3); - InternalTimer($now+$helloDelay, "ArduCounter_SendHello", "sendHello:$name", 0); + ArduCounter_Open($hash); } @@ -211,20 +237,21 @@ sub ArduCounter_Write ($$) ####################################### # Aufruf aus InternalTimer +# send "h" to ask for "Hello" since device didn't say "Started" so fae - maybe it's still counting ... sub ArduCounter_SendHello($) { my $param = shift; my (undef,$name) = split(':',$param); my $hash = $defs{$name}; - my $now = gettimeofday(); Log3 $name, 3, "$name: sending h(ello) to device to ask for version"; return if (!ArduCounter_Write( $hash, "h")); - $hash->{WaitForHello} = 1; + my $now = gettimeofday(); + my $hwt = AttrVal($name, "helloWaitTime ", 3); RemoveInternalTimer ("hwait:$name"); - my $helloWait= AttrVal($name, "helloWaitTime ", 3); - InternalTimer($now+$helloWait, "ArduCounter_HelloTimeout", "hwait:$name", 0); + InternalTimer($now+$hwt, "ArduCounter_HelloTimeout", "hwait:$name", 0); + $hash->{WaitForHello} = 1; } @@ -235,7 +262,7 @@ sub ArduCounter_HelloTimeout($) my $param = shift; my (undef,$name) = split(':',$param); my $hash = $defs{$name}; - Log3 $name, 3, "$name: device didn't reply to h(ello). Is the right sketch flashed?"; + Log3 $name, 3, "$name: device didn't reply to h(ello). Is the right sketch flashed? Is speed set to 38400?"; delete $hash->{WaitForHello}; } @@ -313,11 +340,7 @@ sub ArduCounter_Attr(@) return; } else { Log3 $name, 3, "$name: disable attribute cleared"; - DevIo_OpenDev( $hash, 0, 0) if ($hash->{Initialized}); - my $now = gettimeofday(); - RemoveInternalTimer ("sendHello:$name"); - my $helloDelay = AttrVal($name, "helloSendDelay", 1); - InternalTimer($now+$helloDelay, "ArduCounter_SendHello", "sendHello:$name", 0); + ArduCounter_Open($hash) if ($init_done); # only if fhem is initialized } } @@ -363,16 +386,17 @@ sub ArduCounter_Attr(@) return "Invalid pin name $aName"; } my $pin = $1; - # this cannot come from fhem.cfg and waiting for initialized doesnt help so send it - ArduCounter_Write( $hash, "${pin}d"); + + if ($hash->{Initialized}) { # did device already report its version? + ArduCounter_Write( $hash, "${pin}d"); + } else { + Log3 $name, 5, "$name: pin config can not be deleted since device is not initialized yet"; + return "device is not initialized yet"; + } } elsif ($aName eq 'disable') { - Log3 $name, 3, "$name: disable attribute removed"; - DevIo_OpenDev( $hash, 0, 0) if ($hash->{Initialized}); - my $now = gettimeofday(); - RemoveInternalTimer ("sendHello:$name"); - my $helloDelay = AttrVal($name, "helloSendDelay", 1); - InternalTimer($now+$helloDelay, "ArduCounter_SendHello", "sendHello:$name", 0); + Log3 $name, 3, "$name: disable attribute removed"; + ArduCounter_Open($hash) if ($hash->{$init_done}); # if fhem is initialized } } return undef; @@ -471,6 +495,7 @@ sub ArduCounter_Set($@) } DevIo_OpenDev($hash, 0, 0); $log .= "$name opened\n"; + delete $hash->{Initialized}; } return $log; } @@ -525,6 +550,9 @@ sub ArduCounter_HandleVersion($$) if ($version < "1.7") { $version .= " - not compatible with this Module version - please flash new sketch"; Log3 $name, 3, "$name: device reported outdated Arducounter Firmware - please update!"; + delete $hash->{Initialized}; + } else { + $hash->{Initialized} = 1; # now device is initialized } $hash->{VersionFirmware} = $version; Log3 $name, 4, "$name: device reported firmware $version"; @@ -647,41 +675,40 @@ sub ArduCounter_Parse($) "s in " . sprintf("%.3f", $drTime) . "s" . ($drTime > 0 ? ", " . sprintf("%.2f", $hash->{'.Drift2'} / $drTime * 100) . "%" : ""); - if (!$hash->{Initialized}) { - Log3 $name, 3, "$name: device reported count"; - if (!$hash->{WaitForHello}) { + if (!$hash->{Initialized}) { # device has not sent Started / hello yet + Log3 $name, 3, "$name: device is still counting"; + if (!$hash->{WaitForHello}) { # if hello has not already been sent, send it now ArduCounter_SendHello("direct:$name"); } - $hash->{Initialized} = 1; - RemoveInternalTimer ("sendHello:$name"); + RemoveInternalTimer ("sendHello:$name"); # don't send hello again } - } elsif ($line =~ /ArduCounter V([\d\.]+).?Hello/) { # response to h(ello) + } elsif ($line =~ /ArduCounter V([\d\.]+).?Hello/) { # response to h(ello) Log3 $name, 3, "$name: device replied to hello, V$1"; ArduCounter_HandleVersion($hash, $line); - $hash->{Initialized} = 1; - ArduCounter_ConfigureDevice($hash) if ($hash->{WaitForHello}); - + if ($hash->{Initialized}) { + ArduCounter_ConfigureDevice($hash) # send pin configuration + } delete $hash->{WaitForHello}; RemoveInternalTimer ("hwait:$name"); RemoveInternalTimer ("sendHello:$name"); - } elsif ($line =~ /Status: ArduCounter V([\d\.]+)/) { # response to s(how) + } elsif ($line =~ /Status: ArduCounter V([\d\.]+)/) { # response to s(how) $retStr .= "\n" if ($retStr); $retStr .= $line; ArduCounter_HandleVersion($hash, $line); - #todo: remove here? delete $hash->{WaitForHello}; RemoveInternalTimer ("hwait:$name"); # dont wait for hello reply if already sent RemoveInternalTimer ("sendHello:$name"); # Hello not needed anymore if not sent yet - } elsif ($line =~ /ArduCounter V([\d\.]+).?Started/) { # setup message + } elsif ($line =~ /ArduCounter V([\d\.]+).?Started/) { # setup message Log3 $name, 3, "$name: device sent setup message, V$1"; ArduCounter_HandleVersion($hash, $line); - $hash->{Initialized} = 1; - ArduCounter_ConfigureDevice($hash); + if ($hash->{Initialized}) { + ArduCounter_ConfigureDevice($hash) # send pin configuration + } delete $hash->{WaitForHello}; RemoveInternalTimer ("hwait:$name"); # dont wait for hello reply if already sent @@ -821,13 +848,14 @@ sub ArduCounter_Ready($) # try to reopen if state is disconnected if ( $hash->{STATE} eq "disconnected" ) { #Log3 $name, 3, "$name: ReadyFN tries to open"; # debug + delete $hash->{Initialized}; DevIo_OpenDev( $hash, 1, undef ); - if ($hash->{FD} && !$hash->{Initialized}) { - Log3 $name, 3, "$name: device not initialized yet, set timer to send h(ello"; + if ($hash->{FD}) { + Log3 $name, 3, "$name: device maybe not initialized yet, set timer to send h(ello"; my $now = gettimeofday(); + my $hdl = AttrVal($name, "helloSendDelay", 3); RemoveInternalTimer ("sendHello:$name"); - my $helloDelay = AttrVal($name, "helloSendDelay", 3); - InternalTimer($now+$helloDelay, "ArduCounter_SendHello", "sendHello:$name", 0); + InternalTimer($now+$hdl, "ArduCounter_SendHello", "sendHello:$name", 0); } return; } @@ -862,7 +890,8 @@ sub ArduCounter_Ready($)