From 8bc3889a4ac99e8f9b45472210c5728cff45a8b2 Mon Sep 17 00:00:00 2001 From: ntruchsess <> Date: Fri, 21 Mar 2014 12:54:48 +0000 Subject: [PATCH] FRM: refactor I2C to support new hardware-independent interface, refactor and rename FRM_LCD to I2C_LCD git-svn-id: https://svn.fhem.de/fhem/trunk@5273 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/10_FRM.pm | 81 +++++- fhem/FHEM/20_FRM_LCD.pm | 353 ++----------------------- fhem/FHEM/52_I2C_LCD.pm | 408 +++++++++++++++++++++++++++++ fhem/FHEM/lib/LiquidCrystal_I2C.pm | 4 +- 4 files changed, 508 insertions(+), 338 deletions(-) create mode 100644 fhem/FHEM/52_I2C_LCD.pm diff --git a/fhem/FHEM/10_FRM.pm b/fhem/FHEM/10_FRM.pm index 74cc3f5f8..4d0099fe8 100755 --- a/fhem/FHEM/10_FRM.pm +++ b/fhem/FHEM/10_FRM.pm @@ -31,6 +31,24 @@ my %gets = ( "version" => "" ); +my @clients = qw( + FRM_IN + FRM_OUT + FRM_AD + FRM_PWM + FRM_I2C + FRM_SERVO + FRM_RGB + FRM_ROTENC + FRM_STEPPER + OWX + I2C_LCD + I2C_PC.* + I2C_MCP23017 + I2C_BMP180 + FRM_LCD +); + ##################################### sub FRM_Initialize($) { my $hash = shift @_; @@ -38,10 +56,12 @@ sub FRM_Initialize($) { require "$main::attr{global}{modpath}/FHEM/DevIo.pm"; # Provider - $hash->{Clients} = ":FRM_IN:FRM_OUT:FRM_AD:FRM_PWM:FRM_I2C:FRM_SERVO:OWX:FRM_LCD:FRM_RGB:FRM_ROTENC:FRM_STEPPER:"; + $hash->{Clients} = join (':',@clients); $hash->{ReadyFn} = "FRM_Ready"; $hash->{ReadFn} = "FRM_Read"; + $hash->{I2CWrtFn} = "FRM_I2C_Write"; + # Consumer $hash->{DefFn} = "FRM_Define"; $hash->{UndefFn} = "FRM_Undef"; @@ -605,6 +625,54 @@ sub data_read { package main; +# im master muss eine I2CWrtFn definiert werden, diese wird vom client mit +# CallFn(, "I2CWrtFn", , \%sendpackage); +# aufgerufen. +# Der Master muss mit AssignIoPort() dem Client zugeordnet werden; +# %sendpackage muss folgende keys enthalten: +# +# i2caddress => +# direction => +# data => +# +# der Master fügt zu %sendpackage noch folgende keys hinzu: +# +# received (durch leerzeichen getrennte 1byte hexwerte) +# mastername_* (alle mit mastername_ beginnenden keys können als internal im client angelegt weden) +# unter anderem: mastername_SENDSTAT (enthält "Ok" wenn Übertragung erfolgreich) +# +# danach ruft er über: +# CallFn(, "I2CRecFn", , $sendpackage); +# die I2CRecFn im client auf. Dort werden die Daten verarbeitet und +# im Master wird der Hash sendpackage gelöscht. +# +# $package->{i2caddress}; # single byte value +# $package->{direction}; # i2cread|i2cwrite +# $package->{data}; # space separated list of values +# $package->{reg}; # register +# $package->{nbyte}; # number of bytes to read +# +# $firmata->i2c_read($address,$register,$bytestoread); +# $firmata->i2c_write($address,@data); + +sub FRM_I2C_Write +{ + my ($hash,$package) = @_; + + if (defined (my $firmata = $hash->{FirmataDevice})) { + COMMANDHANDLER: { + $package->{direction} eq "i2cwrite" and do { + $firmata->i2c_write($package->{i2caddress},split(" ",$package->{data})); + last; + }; + $package->{direction} eq "i2cread" and do { + $firmata->i2c_read($package->{i2caddress},$package->{reg},$package->{nbyte}); + last; + }; + } + } +} + sub FRM_i2c_observer { @@ -616,7 +684,16 @@ FRM_i2c_observer sub FRM_i2c_update_device { my ($hash,$data) = @_; - if (defined $hash->{"i2c-address"} && $hash->{"i2c-address"}==$data->{address}) { + + if (defined $hash->{I2C_Address} and $hash->{I2C_Address} eq $data->{address}) { + CallFn($hash->{NAME}, "I2CRecFn", $hash, { + i2caddress => $data->{address}, + direction => "i2cread", + reg => $data->{register}, + nbyte => scalar(@{$data->{data}}), + data => join (' ',@{$data->{data}}) + }); + } elsif (defined $hash->{"i2c-address"} && $hash->{"i2c-address"}==$data->{address}) { my $replydata = $data->{data}; my @values = split(" ",ReadingsVal($hash->{NAME},"values","")); splice(@values,$data->{register},@$replydata, @$replydata); diff --git a/fhem/FHEM/20_FRM_LCD.pm b/fhem/FHEM/20_FRM_LCD.pm index 563b137de..2303e3b3c 100755 --- a/fhem/FHEM/20_FRM_LCD.pm +++ b/fhem/FHEM/20_FRM_LCD.pm @@ -4,292 +4,33 @@ 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... -BEGIN { - if (!grep(/FHEM\/lib$/,@INC)) { - foreach my $inc (grep(/FHEM$/,@INC)) { - push @INC,$inc."/lib"; - }; - }; -}; - -use Device::Firmata::Constants qw/ :all /; - -##################################### - -my %sets = ( - "text" => "", - "home" => "noArg", - "clear" => "noArg", - "display" => "on,off", - "cursor" => "", - "scroll" => "left,right", - "backlight" => "on,off", - "reset" => "noArg", - "writeXY" => "" - ); - -my %gets = ( -); - sub FRM_LCD_Initialize($) { my ($hash) = @_; + main::LoadModule("I2C_LCD"); + I2C_LCD_Initialize($hash); + $hash->{DefFn} = "FRM_LCD_Define"; + $hash->{InitFn} = "FRM_LCD_Init"; +}; - $hash->{DefFn} = "FRM_Client_Define"; - $hash->{InitFn} = "FRM_LCD_Init"; - $hash->{SetFn} = "FRM_LCD_Set"; - $hash->{AttrFn} = "FRM_LCD_Attr"; - $hash->{StateFn} = "FRM_LCD_State"; - - $hash->{AttrList} = "restoreOnReconnect:on,off restoreOnStartup:on,off IODev model" - ." backLight:on,off blink:on,off autoClear:on,off autoBreak:on,off $main::readingFnAttributes"; - # autoScroll:on,off direction:leftToRight,rightToLeft do not work reliably - main::LoadModule("FRM"); +sub +FRM_LCD_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + shift @a; + return I2C_LCD_Define($hash,join(' ',@a)); } sub FRM_LCD_Init($) { - my ($hash,$args) = @_; - my $u = "wrong syntax: define FRM_LCD [
]"; - - return $u if(int(@$args) < 3); - - $hash->{type} = shift @$args; - $hash->{sizex} = shift @$args; - $hash->{sizey} = shift @$args; - $hash->{address} = shift @$args if (@$args); - - my $name = $hash->{NAME}; - if (($hash->{type} eq "i2c") and defined $hash->{address}) { - eval { - FRM_Client_AssignIOPort($hash); - my $firmata = FRM_Client_FirmataDevice($hash); - require LiquidCrystal_I2C; - my $lcd = LiquidCrystal_I2C->new($hash->{address},$hash->{sizex},$hash->{sizey}); - $lcd->attach($firmata); - $lcd->init(); - $hash->{lcd} = $lcd; - FRM_LCD_Apply_Attribute($name,"backLight"); -# FRM_LCD_Apply_Attribute($name,"autoscroll"); -# FRM_LCD_Apply_Attribute($name,"direction"); - FRM_LCD_Apply_Attribute($name,"blink"); - }; - return FRM_Catch($@) if $@; - } - if (! (defined AttrVal($name,"stateFormat",undef))) { - $main::attr{$name}{"stateFormat"} = "text"; - } - if (AttrVal($hash->{NAME},"restoreOnReconnect","on") eq "on") { - foreach my $reading (("display","scroll","backlight","text","writeXY")) { - if (defined (my $value = ReadingsVal($name,$reading,undef))) { - FRM_LCD_Set($hash,$name,$reading,split " ", $value); - } - } - } - return undef; -} - -sub -FRM_LCD_Attr($$$$) { - my ($command,$name,$attribute,$value) = @_; - my $hash = $main::defs{$name}; - eval { - if ($command eq "set") { - ARGUMENT_HANDLER: { - $attribute eq "IODev" and do { - if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $value)) { - FRM_Client_AssignIOPort($hash,$value); - FRM_Init_Client($hash) if (defined ($hash->{IODev})); - } - last; - }; - $main::attr{$name}{$attribute}=$value; - FRM_LCD_Apply_Attribute($name,$attribute); - } - } - }; - my $ret = FRM_Catch($@) if $@; - if ($ret) { - $hash->{STATE} = "error setting $attribute to $value: ".$ret; - return "cannot $command attribute $attribute to $value for $name: ".$ret; - } -} - -sub FRM_LCD_Apply_Attribute { - my ($name,$attribute) = @_; - my $lcd = $main::defs{$name}{lcd}; - if ($main::init_done and defined $lcd) { - ATTRIBUTE_HANDLER: { - $attribute eq "backLight" and do { - if (AttrVal($name,"backLight","on") eq "on") { - $lcd->backlight(); - } else { - $lcd->noBacklight(); - } - last; - }; - $attribute eq "autoScroll" and do { - if (AttrVal($name,"autoScroll","on") eq "on") { - $lcd->autoscroll(); - } else { - $lcd->noAutoscroll(); - } - last; - }; - $attribute eq "direction" and do { - if (AttrVal($name,"direction","leftToRight") eq "leftToRight") { - $lcd->leftToRight(); - } else { - $lcd->rightToLeft(); - } - last; - }; - $attribute eq "blink" and do { - if (AttrVal($name,"blink","off") eq "on") { - $lcd->blink(); - } else { - $lcd->noBlink(); - } - last; - }; - } - } -} - -sub FRM_LCD_Set(@) { - my ($hash, @a) = @_; - return "Need at least one parameters" if(@a < 2); - my $command = $a[1]; - my $value = $a[2]; - if(!defined($sets{$command})) { - my @commands = (); - foreach my $key (sort keys %sets) { - push @commands, $sets{$key} ? $key.":".join(",",$sets{$key}) : $key; - } - return "Unknown argument $a[1], choose one of " . join(" ", @commands); - } - my $lcd = $hash->{lcd}; - return unless defined $lcd; - eval { - COMMAND_HANDLER: { - $command eq "text" and do { - shift @a; - shift @a; - $value = join(" ", @a); - if (AttrVal($hash->{NAME},"autoClear","on") eq "on") { - $lcd->clear(); - } - if (AttrVal($hash->{NAME},"autoBreak","on") eq "on") { - my $sizex = $hash->{sizex}; - my $sizey = $hash->{sizey}; - my $start = 0; - my $len = length $value; - for (my $line = 0;$line<$sizey;$line++) { - $lcd->setCursor(0,$line); - if ($start<$len) { - $lcd->print(substr $value, $start, $sizex); - } else { - last; - } - $start+=$sizex; - } - } else { - $lcd->print($value); - } - main::readingsSingleUpdate($hash,"text",$value,1); - last; - }; - $command eq "home" and do { - $lcd->home(); - last; - }; - $command eq "reset" and do { - $lcd->init(); -# $hash->{lcd} = $lcd; - last; - }; - $command eq "clear" and do { - $lcd->clear(); - main::readingsSingleUpdate($hash,"text","",1); - last; - }; - $command eq "display" and do { - if ($value ne "off") { - $lcd->display(); - } else { - $lcd->noDisplay(); - } - main::readingsSingleUpdate($hash,"display",$value,1); - last; - }; - $command eq "cursor" and do { - my ($x,$y) = split ",",$value; - $lcd->setCursor($x,$y); - last; - }; - $command eq "scroll" and do { - if ($value eq "left") { - $lcd->scrollDisplayLeft(); - } else { - $lcd->scrollDisplayRight(); - } - main::readingsSingleUpdate($hash,"scroll",$value,1); - last; - }; - $command eq "backlight" and do { - if ($value eq "on") { - $lcd->backlight(); - } else { - $lcd->noBacklight(); - } - main::readingsSingleUpdate($hash,"backlight",$value,1); - last; - }; - $command eq "writeXY" and do { - my ($x,$y,$l,$al) = split(",",$value); - $lcd->setCursor($x,$y); - shift @a; shift @a; shift @a; - my $t = join(" ", @a); - my %umlaute = ("ä" => "ae", "Ä" => "Ae", "ü" => "ue", "Ü" => "Ue", "ö" => "oe", "Ö" => "Oe", "ß" => "ss" ," - " => " " ,"©"=>"@"); - my $umlautkeys = join ("|", keys(%umlaute)); - $t =~ s/($umlautkeys)/$umlaute{$1}/g; - my $sl = length $t; - if ($sl > $l) { - $t = substr($t,0,$l); - } - if ($sl < $l) { - my $dif = ""; - for (my $i=$sl; $i<$l; $i++) { - $dif .= " "; - } - $t = ($al eq "l") ? $t.$dif : $dif.$t; - } - $lcd->print($t); - main::readingsSingleUpdate($hash,"writeXY",$value." ".$t,1); - readingsSingleUpdate($hash,"state",$t,1); - last; #"X=$x|Y=$y|L=$l|Text=$t"; - }; - } - }; - return FRM_Catch($@) if $@; - return undef; -} - -sub FRM_LCD_State($$$$) -{ - my ($hash, $tim, $sname, $sval) = @_; - -STATEHANDLER: { - $sname eq "text" and do { - if (AttrVal($hash->{NAME},"restoreOnStartup","on") eq "on") { - FRM_LCD_Set($hash,$hash->{NAME},$sname,$sval); - } - last; - } - } + my ($hash,$args) = @_; + my $u = "wrong syntax: define FRM_LCD i2c [
]"; + return $u if(int(@$args) < 3); + shift @$args; + return I2C_LCD_Init($hash,$args); } 1; @@ -300,63 +41,7 @@ STATEHANDLER: {

FRM_LCD

    - drives LiquidCrystal Displays (LCD) that are connected to Firmata (via I2C). - Supported are Displays that use a PCF8574T as I2C Bridge (as found on eBay when searching for - 'LCD' and 'I2C'). Tested is the 1602 type (16 characters, 2 Lines), the 2004 type (and other cheap chinise-made - I2C-LCDs for Arduino) ship with the same library, so they should work as well. - See http://arduino.cc/en/Tutorial/LiquidCrystal for details about - how to hook up the LCD to the arduino. - - Requires a defined FRM-device to work.
    - this FRM-device has to be configures for i2c by setting attr 'i2c-config' on the FRM-device
    - - - Define -
      - define <name> FRM_LCD i2c <size-x> <size-y> <i2c-address>
      - Specifies the FRM_LCD device.
      -
    • size-x is the number of characters per line
    • -
    • size-y is the numbers of rows.
    • -
    • i2c-address is the (device-specific) address of the ic on the i2c-bus
    • -
    - -
    - - Set
    -
      -
    • set <name> text <text to be displayed>
    • -
    • set <name> home
    • -
    • set <name> clear
    • -
    • set <name> display on|off
    • -
    • set <name> cursor <...>
    • -
    • set <name> scroll left|right
    • -
    • set <name> backlight on|off
    • -
    • set <name> reset
    • -
    • set <name> writeXY x-pos,y-pos,len[,l] <text to be displayed>
    • -
    - - - Get
    -
      - N/A
      -

    - - Attributes
    -
      -
    • backLight <on|off>
    • -
    • autoClear <on|off>
    • -
    • autoBreak <on|off>
    • -
    • restoreOnStartup <on|off>
    • -
    • restoreOnReconnect <on|off>
    • -
    • IODev
      - Specify which FRM to use. (Optional, only required if there is more - than one FRM-device defined.) -
    • -
    • eventMap
    • -
    • readingFnAttributes
    • -
    -
-
- + deprecated, use I2C_LCD + =end html =cut diff --git a/fhem/FHEM/52_I2C_LCD.pm b/fhem/FHEM/52_I2C_LCD.pm new file mode 100644 index 000000000..2d8776b8a --- /dev/null +++ b/fhem/FHEM/52_I2C_LCD.pm @@ -0,0 +1,408 @@ +############################################# +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... +BEGIN { + if (!grep(/FHEM\/lib$/,@INC)) { + foreach my $inc (grep(/FHEM$/,@INC)) { + push @INC,$inc."/lib"; + }; + }; +}; + +##################################### + +my %sets = ( + "text" => "", + "home" => "noArg", + "clear" => "noArg", + "display" => "on,off", + "cursor" => "", + "scroll" => "left,right", + "backlight" => "on,off", + "reset" => "noArg", + "writeXY" => "" + ); + +my %gets = ( +); + +sub +I2C_LCD_Initialize($) +{ + my ($hash) = @_; + + $hash->{DefFn} = "I2C_LCD_Define"; + $hash->{InitFn} = "I2C_LCD_Init"; + $hash->{SetFn} = "I2C_LCD_Set"; + $hash->{AttrFn} = "I2C_LCD_Attr"; + $hash->{StateFn} = "I2C_LCD_State"; + + $hash->{AttrList} = "restoreOnReconnect:on,off restoreOnStartup:on,off IODev model" + ." backLight:on,off blink:on,off autoClear:on,off autoBreak:on,off $main::readingFnAttributes"; + # autoScroll:on,off direction:leftToRight,rightToLeft do not work reliably +} + +sub +I2C_LCD_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + $hash->{STATE}="defined"; + + if ($main::init_done) { + eval { + I2C_LCD_Init($hash,[@a[2..scalar(@a)-1]]); + }; + return I2C_LCD_Catch($@) if $@; + } + return undef; +} + +sub +I2C_LCD_Init($$) +{ + my ($hash,$args) = @_; + my $u = "wrong syntax: define I2C_LCD [
]"; + + return $u if(int(@$args) < 2); + + $hash->{sizex} = shift @$args; + $hash->{sizey} = shift @$args; + $hash->{address} = shift @$args if (@$args); + + my $name = $hash->{NAME}; + if (defined $hash->{address}) { + eval { + main::AssignIoPort($hash,AttrVal($hash->{NAME},"IODev",undef)); + require LiquidCrystal_I2C; + my $lcd = LiquidCrystal_I2C->new($hash->{address},$hash->{sizex},$hash->{sizey}); + $lcd->attach(I2C_LCD_IO->new($hash)); + $lcd->init(); + $hash->{lcd} = $lcd; + I2C_LCD_Apply_Attribute($name,"backLight"); +# I2C_LCD_Apply_Attribute($name,"autoscroll"); +# I2C_LCD_Apply_Attribute($name,"direction"); + I2C_LCD_Apply_Attribute($name,"blink"); + }; + return I2C_LCD_Catch($@) if $@; + } + if (! (defined AttrVal($name,"stateFormat",undef))) { + $main::attr{$name}{"stateFormat"} = "text"; + } + if (AttrVal($hash->{NAME},"restoreOnReconnect","on") eq "on") { + foreach my $reading (("display","scroll","backlight","text","writeXY")) { + if (defined (my $value = ReadingsVal($name,$reading,undef))) { + I2C_LCD_Set($hash,$name,$reading,split " ", $value); + } + } + } + return undef; +} + +sub +I2C_LCD_Attr($$$$) { + my ($command,$name,$attribute,$value) = @_; + my $hash = $main::defs{$name}; + eval { + if ($command eq "set") { + ARGUMENT_HANDLER: { + $attribute eq "IODev" and do { + if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $value)) { + main::AssignIoPort($hash,$value); + my @def = split (' ',$hash->{DEF}); + I2C_LCD_Init($hash,\@def) if (defined ($hash->{IODev})); + } + last; + }; + $main::attr{$name}{$attribute}=$value; + I2C_LCD_Apply_Attribute($name,$attribute); + } + } + }; + return $@ if $@; + my $ret = I2C_LCD_Catch($@) if $@; + if ($ret) { + $hash->{STATE} = "error setting $attribute to $value: ".$ret; + return "cannot $command attribute $attribute to $value for $name: ".$ret; + } +} + +sub I2C_LCD_Apply_Attribute { + my ($name,$attribute) = @_; + my $lcd = $main::defs{$name}{lcd}; + if ($main::init_done and defined $lcd) { + ATTRIBUTE_HANDLER: { + $attribute eq "backLight" and do { + if (AttrVal($name,"backLight","on") eq "on") { + $lcd->backlight(); + } else { + $lcd->noBacklight(); + } + last; + }; + $attribute eq "autoScroll" and do { + if (AttrVal($name,"autoScroll","on") eq "on") { + $lcd->autoscroll(); + } else { + $lcd->noAutoscroll(); + } + last; + }; + $attribute eq "direction" and do { + if (AttrVal($name,"direction","leftToRight") eq "leftToRight") { + $lcd->leftToRight(); + } else { + $lcd->rightToLeft(); + } + last; + }; + $attribute eq "blink" and do { + if (AttrVal($name,"blink","off") eq "on") { + $lcd->blink(); + } else { + $lcd->noBlink(); + } + last; + }; + } + } +} + +sub I2C_LCD_Set(@) { + my ($hash, @a) = @_; + return "Need at least one parameters" if(@a < 2); + my $command = $a[1]; + my $value = $a[2]; + if(!defined($sets{$command})) { + my @commands = (); + foreach my $key (sort keys %sets) { + push @commands, $sets{$key} ? $key.":".join(",",$sets{$key}) : $key; + } + return "Unknown argument $a[1], choose one of " . join(" ", @commands); + } + my $lcd = $hash->{lcd}; + return unless defined $lcd; + eval { + COMMAND_HANDLER: { + $command eq "text" and do { + shift @a; + shift @a; + $value = join(" ", @a); + if (AttrVal($hash->{NAME},"autoClear","on") eq "on") { + $lcd->clear(); + } + if (AttrVal($hash->{NAME},"autoBreak","on") eq "on") { + my $sizex = $hash->{sizex}; + my $sizey = $hash->{sizey}; + my $start = 0; + my $len = length $value; + for (my $line = 0;$line<$sizey;$line++) { + $lcd->setCursor(0,$line); + if ($start<$len) { + $lcd->print(substr $value, $start, $sizex); + } else { + last; + } + $start+=$sizex; + } + } else { + $lcd->print($value); + } + main::readingsSingleUpdate($hash,"text",$value,1); + last; + }; + $command eq "home" and do { + $lcd->home(); + last; + }; + $command eq "reset" and do { + $lcd->init(); +# $hash->{lcd} = $lcd; + last; + }; + $command eq "clear" and do { + $lcd->clear(); + main::readingsSingleUpdate($hash,"text","",1); + last; + }; + $command eq "display" and do { + if ($value ne "off") { + $lcd->display(); + } else { + $lcd->noDisplay(); + } + main::readingsSingleUpdate($hash,"display",$value,1); + last; + }; + $command eq "cursor" and do { + my ($x,$y) = split ",",$value; + $lcd->setCursor($x,$y); + last; + }; + $command eq "scroll" and do { + if ($value eq "left") { + $lcd->scrollDisplayLeft(); + } else { + $lcd->scrollDisplayRight(); + } + main::readingsSingleUpdate($hash,"scroll",$value,1); + last; + }; + $command eq "backlight" and do { + if ($value eq "on") { + $lcd->backlight(); + } else { + $lcd->noBacklight(); + } + main::readingsSingleUpdate($hash,"backlight",$value,1); + last; + }; + $command eq "writeXY" and do { + my ($x,$y,$l,$al) = split(",",$value); + $lcd->setCursor($x,$y); + shift @a; shift @a; shift @a; + my $t = join(" ", @a); + my %umlaute = ("ä" => "ae", "Ä" => "Ae", "ü" => "ue", "Ü" => "Ue", "ö" => "oe", "Ö" => "Oe", "ß" => "ss" ," - " => " " ,"©"=>"@"); + my $umlautkeys = join ("|", keys(%umlaute)); + $t =~ s/($umlautkeys)/$umlaute{$1}/g; + my $sl = length $t; + if ($sl > $l) { + $t = substr($t,0,$l); + } + if ($sl < $l) { + my $dif = ""; + for (my $i=$sl; $i<$l; $i++) { + $dif .= " "; + } + $t = ($al eq "l") ? $t.$dif : $dif.$t; + } + $lcd->print($t); + main::readingsSingleUpdate($hash,"writeXY",$value." ".$t,1); + readingsSingleUpdate($hash,"state",$t,1); + last; #"X=$x|Y=$y|L=$l|Text=$t"; + }; + } + }; + return I2C_LCD_Catch($@) if $@; + return undef; +} + +sub I2C_LCD_Catch($) { + my $exception = shift; + if ($exception) { + $exception =~ /^(.*)( at.*FHEM.*)$/; + return $1; + } + return undef; +} + +sub I2C_LCD_State($$$$) +{ + my ($hash, $tim, $sname, $sval) = @_; + +STATEHANDLER: { + $sname eq "text" and do { + if (AttrVal($hash->{NAME},"restoreOnStartup","on") eq "on") { + I2C_LCD_Set($hash,$hash->{NAME},$sname,$sval); + } + last; + } + } +} + +package I2C_LCD_IO; + +sub new { + my ($class,$hash) = @_; + return bless { + hash => $hash, + }, $class; +} + +sub i2c_write { + my ( $self, $address, @data ) = @_; + my $hash = $self->{hash}; + if (defined (my $iodev = $hash->{IODev})) { + main::CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, { + i2caddress => $address, + direction => "i2cwrite", + data => join (' ',@data) + }); + } else { + die "no IODev assigned to '$hash->{NAME}'"; + } +} + +1; + +=pod +=begin html + + +

I2C_LCD

+
    + drives LiquidCrystal Displays (LCD) that are connected to Firmata (via I2C). + Supported are Displays that use a PCF8574T as I2C Bridge (as found on eBay when searching for + 'LCD' and 'I2C'). Tested is the 1602 type (16 characters, 2 Lines), the 2004 type (and other cheap chinise-made + I2C-LCDs for Arduino) ship with the same library, so they should work as well. + See http://arduino.cc/en/Tutorial/LiquidCrystal for details about + how to hook up the LCD to the arduino. + + Requires a defined I2C-device to work.
    + this I2C-device has to be configures for i2c by setting attr 'i2c-config' on the I2C-device
    + + + Define +
      + define <name> I2C_LCD <size-x> <size-y> <i2c-address>
      + Specifies the I2C_LCD device.
      +
    • size-x is the number of characters per line
    • +
    • size-y is the numbers of rows.
    • +
    • i2c-address is the (device-specific) address of the ic on the i2c-bus
    • +
    + +
    + + Set
    +
      +
    • set <name> text <text to be displayed>
    • +
    • set <name> home
    • +
    • set <name> clear
    • +
    • set <name> display on|off
    • +
    • set <name> cursor <...>
    • +
    • set <name> scroll left|right
    • +
    • set <name> backlight on|off
    • +
    • set <name> reset
    • +
    • set <name> writeXY x-pos,y-pos,len[,l] <text to be displayed>
    • +
    + + + Get
    +
      + N/A
      +

    + + Attributes
    +
      +
    • backLight <on|off>
    • +
    • autoClear <on|off>
    • +
    • autoBreak <on|off>
    • +
    • restoreOnStartup <on|off>
    • +
    • restoreOnReconnect <on|off>
    • +
    • IODev
      + Specify which I2C to use. (Optional, only required if there is more + than one I2C-device defined.) +
    • +
    • eventMap
    • +
    • readingFnAttributes
    • +
    +
+
+ +=end html +=cut diff --git a/fhem/FHEM/lib/LiquidCrystal_I2C.pm b/fhem/FHEM/lib/LiquidCrystal_I2C.pm index 5f22f7849..11941b9db 100644 --- a/fhem/FHEM/lib/LiquidCrystal_I2C.pm +++ b/fhem/FHEM/lib/LiquidCrystal_I2C.pm @@ -107,7 +107,7 @@ sub init($) { sub attach($$) { my ($self,$dev) = @_; - $self->{FirmataDevice} = $dev; + $self->{I2CDevice} = $dev; } sub init_priv($) { @@ -360,7 +360,7 @@ sub write4bits($$) { sub expanderWrite($$) { my ( $self, $data ) = @_; - $self->{FirmataDevice}->i2c_write($self->{Addr},($data) | $self->{backlightval}); + $self->{I2CDevice}->i2c_write($self->{Addr},($data) | $self->{backlightval}); } sub pulseEnable($$) {