diff --git a/fhem/FHEM/20_FRM_OUT.pm b/fhem/FHEM/20_FRM_OUT.pm index 424f7c12a..ac7c5aaa5 100755 --- a/fhem/FHEM/20_FRM_OUT.pm +++ b/fhem/FHEM/20_FRM_OUT.pm @@ -1,12 +1,43 @@ -############################################## +######################################################################################## +# # $Id$ -############################################## +# +# FHEM module for one Firmata digial output pin +# +######################################################################################## +# +# LICENSE AND COPYRIGHT +# +# Copyright (C) 2013 ntruchess +# Copyright (C) 2016 jensb +# +# All rights reserved +# +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The GNU General Public License can be found at +# http://www.gnu.org/copyleft/gpl.html. +# A copy is found in the textfile GPL.txt and important notices to the license +# from the author is found in LICENSE.txt distributed with these scripts. +# +# This script is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# This copyright notice MUST APPEAR in all copies of the script! +# +######################################################################################## + package main; use strict; use warnings; -#add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though... +#add FHEM/lib to @INC if it's not already included. Should rather be in fhem.pl than here though... BEGIN { if (!grep(/FHEM\/lib$/,@INC)) { foreach my $inc (grep(/FHEM$/,@INC)) { @@ -31,7 +62,7 @@ FRM_OUT_Initialize($) $hash->{AttrFn} = "FRM_OUT_Attr"; $hash->{StateFn} = "FRM_OUT_State"; - $hash->{AttrList} = "restoreOnReconnect:on,off restoreOnStartup:on,off activeLow:yes,no IODev $main::readingFnAttributes"; + $hash->{AttrList} = "restoreOnReconnect:on,off restoreOnStartup:on,off activeLow:yes,no IODev valueMode:send,receive,bidirectional $main::readingFnAttributes"; main::LoadModule("FRM"); } @@ -41,24 +72,48 @@ FRM_OUT_Init($$) my ($hash,$args) = @_; my $ret = FRM_Init_Pin_Client($hash,$args,PIN_OUTPUT); return $ret if (defined $ret); + eval { + my $firmata = FRM_Client_FirmataDevice($hash); + my $pin = $hash->{PIN}; + $firmata->observe_digital($pin,\&FRM_OUT_observer,$hash); + }; my $name = $hash->{NAME}; if (! (defined AttrVal($name,"stateFormat",undef))) { $main::attr{$name}{"stateFormat"} = "value"; } my $value = ReadingsVal($name,"value",undef); - if (defined $value and AttrVal($hash->{NAME},"restoreOnReconnect","on") eq "on") { + if (!defined($value)) { + readingsSingleUpdate($hash,"value","off",0); + } + if (AttrVal($hash->{NAME},"restoreOnReconnect", "on") eq "on") { FRM_OUT_Set($hash,$name,$value); } main::readingsSingleUpdate($hash,"state","Initialized",1); return undef; } +sub +FRM_OUT_observer($$$$) +{ + my ($pin,$old,$new,$hash) = @_; + my $name = $hash->{NAME}; + Log3 $name, 5, "onDigitalMessage for pin ".$pin.", old: ".(defined $old? $old : "--").", new: ".(defined $new? $new : "--"); + if (AttrVal($hash->{NAME}, "activeLow", "no") eq "yes") { + $old = $old == PIN_LOW ? PIN_HIGH : PIN_LOW if (defined $old); + $new = $new == PIN_LOW ? PIN_HIGH : PIN_LOW; + } + my $changed = !defined($old) || ($old != $new); + if ($changed && (AttrVal($hash->{NAME}, "valueMode", "send") ne "send")) { + main::readingsSingleUpdate($hash, "value", $new == PIN_HIGH? "on" : "off", 1); + } +} + sub FRM_OUT_Set($$$) { my ($hash, $name, $cmd, @a) = @_; my $value; - my $invert = AttrVal($hash->{NAME},"activeLow","no"); + my $invert = AttrVal($hash->{NAME},"activeLow", "no"); if ($cmd eq "on") { $value = $invert eq "yes" ? PIN_LOW : PIN_HIGH; } elsif ($cmd eq "off") { @@ -69,7 +124,9 @@ FRM_OUT_Set($$$) } eval { FRM_Client_FirmataDevice($hash)->digital_write($hash->{PIN},$value); - main::readingsSingleUpdate($hash,"value",$cmd, 1); + if (AttrVal($hash->{NAME}, "valueMode", "send") ne "receive") { + main::readingsSingleUpdate($hash,"value",$cmd, 1); + } }; return $@; } @@ -80,7 +137,7 @@ sub FRM_OUT_State($$$$) STATEHANDLER: { $sname eq "value" and do { - if (AttrVal($hash->{NAME},"restoreOnStartup","on") eq "on") { + if (AttrVal($hash->{NAME},"restoreOnStartup", "on") eq "on") { FRM_OUT_Set($hash,$hash->{NAME},$sval); } last; @@ -102,6 +159,18 @@ FRM_OUT_Attr($$$$) { } last; }; + $attribute eq "activeLow" and do { + my $oldval = AttrVal($hash->{NAME},"activeLow", "no"); + if ($oldval ne $value) { + # toggle output with attribute change + $main::attr{$hash->{NAME}}{activeLow} = $value; + if ($main::init_done) { + my $value = ReadingsVal($name,"value",undef); + FRM_OUT_Set($hash,$hash->{NAME},$value); + } + }; + last; + }; } } }; @@ -115,6 +184,24 @@ FRM_OUT_Attr($$$$) { 1; =pod + + CHANGES + + 2016 jensb + o new sub FRM_OUT_observer, modified sub FRM_OUT_Init + to receive output state from Firmata device + o support attribute "activeLow" + 01.01.2018 jensb + o create reading "value" in FRM_OUT_Init if missing + 02.01.2018 jensb + o new attribute "valueMode" to control how "value" reading is updated + +=cut + +=pod +=item device +=item summary Firmata: digital output +=item summary_DE Firmata: digitaler Ausang =begin html @@ -148,13 +235,31 @@ FRM_OUT_Attr($$$$) { Attributes
diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index c85fcfa50..daf9915c7 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -105,7 +105,7 @@ FHEM/20_FRM_ROTENC.pm ntruchsess Sonstige Systeme FHEM/20_FRM_I2C.pm ntruchsess Sonstige Systeme FHEM/20_FRM_IN.pm ntruchsess Sonstige Systeme FHEM/20_FRM_LCD.pm ntruchsess Sonstige Systeme (deprecated) -FHEM/20_FRM_OUT.pm ntruchsess Sonstige Systeme +FHEM/20_FRM_OUT.pm jensb Sonstige Systeme FHEM/20_FRM_PWM.pm ntruchsess Sonstige Systeme FHEM/20_FRM_RBG.pm ntruchsess Sonstige Systeme FHEM/20_FRM_SERVO.pm ntruchsess Sonstige Systeme