diff --git a/fhem/CHANGED b/fhem/CHANGED
index 81b1e2999..aed3d01fe 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - feature: new module 52_I2C_BME280.pm added (klausw)
+ - bugfix: 52_I2C_PCA9685: bugfix for interaction with FRM
- change: 49_SSCAM: changed DEF in order to remove credentials from string,
added "set credentials" command to save username/password,
added Attribute "session" to make login-session selectable,
diff --git a/fhem/FHEM/00_NetzerI2C.pm b/fhem/FHEM/00_NetzerI2C.pm
index 1e4f37701..a024f6a33 100644
--- a/fhem/FHEM/00_NetzerI2C.pm
+++ b/fhem/FHEM/00_NetzerI2C.pm
@@ -23,7 +23,8 @@ my @clients = qw(
I2C_LCD
I2C_DS1307
I2C_PC.*
-I2C_MCP23.*
+I2C_MCP.*
+I2C_BME280
I2C_BMP180
I2C_SHT21
I2C_TSL2561
diff --git a/fhem/FHEM/00_RPII2C.pm b/fhem/FHEM/00_RPII2C.pm
index 6cdfc5bed..2d64c674f 100644
--- a/fhem/FHEM/00_RPII2C.pm
+++ b/fhem/FHEM/00_RPII2C.pm
@@ -14,6 +14,7 @@ I2C_LCD
I2C_DS1307
I2C_PC.*
I2C_MCP.*
+I2C_BME280
I2C_BMP180
I2C_SHT21
I2C_TSL2561
diff --git a/fhem/FHEM/10_FRM.pm b/fhem/FHEM/10_FRM.pm
index 52b912189..d024a6536 100755
--- a/fhem/FHEM/10_FRM.pm
+++ b/fhem/FHEM/10_FRM.pm
@@ -51,6 +51,7 @@ my @clients = qw(
I2C_PC.*
I2C_MCP23.*
I2C_SHT21
+ I2C_BME280
I2C_BMP180
I2C_TSL2561
FRM_LCD
diff --git a/fhem/FHEM/51_RPI_GPIO.pm b/fhem/FHEM/51_RPI_GPIO.pm
index 3c7083029..0f05f7926 100644
--- a/fhem/FHEM/51_RPI_GPIO.pm
+++ b/fhem/FHEM/51_RPI_GPIO.pm
@@ -684,56 +684,8 @@ sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling
Define
define RPI_GPIO <GPIO number>
- all usable GPIO number
are in the following tables
+ all usable GPIO number
can be found here
-
-
- PCB Revision 1 P1 pin header
-
- Function | Pin | | Pin | Function |
- 3,3V | 1 | | 2 | 5V |
- GPIO 0 (SDA0) | 3 | | 4 | |
- GPIO 1 (SCL0) | 5 | | 6 | GND |
- GPIO 4 (GPCLK0) | 7 | | 8 | GPIO 14 (TxD) |
- | 9 | | 10 | GPIO 15 (RxD) |
- GPIO 17 | 11 | | 12 | GPIO 18 (PCM_CLK) |
- GPIO 21 | 13 | | 14 | |
- GPIO 22 | 15 | | 16 | GPIO 23 |
- | 17 | | 18 | GPIO 24 |
- GPIO 10 (MOSI) | 19 | | 20 | |
- GPIO 9 (MISO) | 21 | | 22 | GPIO 25 |
- GPIO 11 (SCLK) | 23 | | 24 | GPIO 8 (CE0) |
- | 25 | | 26 | GPIO 7 (CE1) |
- |
-
- PCB Revision 2 P1 pin header
-
- Function | Pin | | Pin | Function |
- 3,3V | 1 | | 2 | 5V |
- GPIO 2 (SDA1) | 3 | | 4 | |
- GPIO 3 (SCL1) | 5 | | 6 | GND |
- GPIO 4 (GPCLK0) | 7 | | 8 | GPIO 14 (TxD) |
- | 9 | | 10 | GPIO 15 (RxD) |
- GPIO 17 | 11 | | 12 | GPIO 18 (PCM_CLK) |
- GPIO 27 | 13 | | 14 | |
- GPIO 22 | 15 | | 16 | GPIO 23 |
- | 17 | | 18 | GPIO 24 |
- GPIO 10 (MOSI) | 19 | | 20 | |
- GPIO 9 (MISO) | 21 | | 22 | GPIO 25 |
- GPIO 11 (SCLK) | 23 | | 24 | GPIO 8 (CE0) |
- | 25 | | 26 | GPIO 7 (CE1) |
- |
-
- PCB Revision 2 P5 pin header
-
- Function | Pin | | Pin | Function |
- 5V | 1 | | 2 | 3,3V |
- GPIO 28 (SDA0) | 3 | | 4 | GPIO 29 (SCL0) |
- GPIO 30 | 5 | | 6 | GPOI 31 |
- GND | 7 | | 8 | GND |
- |
-
-
Examples:
define Pin12 RPI_GPIO 18
@@ -877,56 +829,8 @@ sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling
Define
define <name> RPI_GPIO <GPIO number>
- Alle verfügbaren GPIO number
sind in den folgenden Tabellen zu finden
-
-
-
- PCB Revision 1 P1 pin header
-
- Function | Pin | | Pin | Function |
- 3,3V | 1 | | 2 | 5V |
- GPIO 0 (SDA0) | 3 | | 4 | |
- GPIO 1 (SCL0) | 5 | | 6 | GND |
- GPIO 4 (GPCLK0) | 7 | | 8 | GPIO 14 (TxD) |
- | 9 | | 10 | GPIO 15 (RxD) |
- GPIO 17 | 11 | | 12 | GPIO 18 (PCM_CLK) |
- GPIO 21 | 13 | | 14 | |
- GPIO 22 | 15 | | 16 | GPIO 23 |
- | 17 | | 18 | GPIO 24 |
- GPIO 10 (MOSI) | 19 | | 20 | |
- GPIO 9 (MISO) | 21 | | 22 | GPIO 25 |
- GPIO 11 (SCLK) | 23 | | 24 | GPIO 8 (CE0) |
- | 25 | | 26 | GPIO 7 (CE1) |
- |
-
- PCB Revision 2 P1 pin header
-
- Function | Pin | | Pin | Function |
- 3,3V | 1 | | 2 | 5V |
- GPIO 2 (SDA1) | 3 | | 4 | |
- GPIO 3 (SCL1) | 5 | | 6 | GND |
- GPIO 4 (GPCLK0) | 7 | | 8 | GPIO 14 (TxD) |
- | 9 | | 10 | GPIO 15 (RxD) |
- GPIO 17 | 11 | | 12 | GPIO 18 (PCM_CLK) |
- GPIO 27 | 13 | | 14 | |
- GPIO 22 | 15 | | 16 | GPIO 23 |
- | 17 | | 18 | GPIO 24 |
- GPIO 10 (MOSI) | 19 | | 20 | |
- GPIO 9 (MISO) | 21 | | 22 | GPIO 25 |
- GPIO 11 (SCLK) | 23 | | 24 | GPIO 8 (CE0) |
- | 25 | | 26 | GPIO 7 (CE1) |
- |
-
- PCB Revision 2 P5 pin header
-
- Function | Pin | | Pin | Function |
- 5V | 1 | | 2 | 3,3V |
- GPIO 28 (SDA0) | 3 | | 4 | GPIO 29 (SCL0) |
- GPIO 30 | 5 | | 6 | GPOI 31 |
- GND | 7 | | 8 | GND |
- |
-
-
+ Alle verfügbaren GPIO number
sind z.B. hier zu finden
+
Beispiele:
define Pin12 RPI_GPIO 18
diff --git a/fhem/FHEM/52_I2C_BME280.pm b/fhem/FHEM/52_I2C_BME280.pm
new file mode 100644
index 000000000..429513aba
--- /dev/null
+++ b/fhem/FHEM/52_I2C_BME280.pm
@@ -0,0 +1,629 @@
+# $Id$
+=head1
+ 52_I2C_BME280.pm
+
+=head1 SYNOPSIS
+ Modul for FHEM for reading a BME280 digital pressure/humidity sensor via I2C
+=cut
+
+package main;
+
+use strict;
+use warnings;
+
+use constant {
+ BME280_I2C_ADDRESS => 0x76,
+};
+
+##################################################
+# Forward declarations
+#
+sub I2C_BME280_I2CRec ($$);
+sub I2C_BME280_GetReadings ($$);
+sub I2C_BME280_GetTemp ($@);
+sub I2C_BME280_GetPress ($@);
+sub I2C_BME280_GetHum ($@);
+sub I2C_BME280_calcTrueTemperature($$);
+sub I2C_BME280_calcTrueHumidity($$);
+sub I2C_BME280_calcTruePressure($$);
+
+my %sets = (
+ 'readValues' => 1,
+);
+
+sub I2C_BME280_Initialize($) {
+ my ($hash) = @_;
+
+ $hash->{DefFn} = 'I2C_BME280_Define';
+ $hash->{InitFn} = 'I2C_BME280_Init';
+ $hash->{AttrFn} = 'I2C_BME280_Attr';
+ $hash->{SetFn} = 'I2C_BME280_Set';
+ #$hash->{GetFn} = 'I2C_BME280_Get';
+ $hash->{UndefFn} = 'I2C_BME280_Undef';
+ $hash->{I2CRecFn} = 'I2C_BME280_I2CRec';
+ $hash->{AttrList} = 'IODev do_not_notify:0,1 showtime:0,1 poll_interval:1,2,5,10,20,30 ' .
+ 'oversampling_t:0,1,2,3,4,5 oversampling_p:0,1,2,3,4,5 oversampling_h:0,1,2,3,4,5 ' .
+ 'roundPressureDecimal:0,1,2 roundTemperatureDecimal:0,1,2 roundHumidityDecimal:0,1,2 ' .
+ $readingFnAttributes;
+ $hash->{DbLog_splitFn} = "I2C_BME280_DbLog_splitFn";
+}
+
+sub I2C_BME280_Define($$) {
+ my ($hash, $def) = @_;
+ my @a = split('[ \t][ \t]*', $def);
+ $hash->{STATE} = 'defined';
+
+ my $name = $a[0];
+
+ my $msg = '';
+ if((@a < 2)) {
+ $msg = 'wrong syntax: define I2C_BME280 [I2C-Address]';
+ }
+ if ($msg) {
+ Log3 ($hash, 1, $msg);
+ return $msg;
+ }
+ if ($main::init_done) {
+ eval { I2C_BME280_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); };
+ return I2C_BME280_Catch($@) if $@;
+ }
+}
+
+sub I2C_BME280_Init($$) { # wird bei FHEM start Define oder wieder
+ my ( $hash, $args ) = @_;
+ my $name = $hash->{NAME};
+
+ if (defined (my $address = shift @$args)) {
+ $hash->{I2C_Address} = $address =~ /^0x.*$/ ? oct($address) : $address;
+ return "$name: I2C Address not valid" unless ($hash->{I2C_Address} < 128 && $hash->{I2C_Address} > 3);
+ } else {
+ $hash->{I2C_Address} = BME280_I2C_ADDRESS;
+ }
+ my $msg = '';
+ # create default attributes
+ #if (AttrVal($name, 'poll_interval', '?') eq '?') {
+ # $msg = CommandAttr(undef, $name . ' poll_interval 5');
+ # if ($msg) {
+ # Log3 ($hash, 1, $msg);
+ # return $msg;
+ # }
+ #}
+ eval {
+ AssignIoPort($hash, AttrVal($hash->{NAME},"IODev",undef));
+ I2C_BME280_i2cread($hash, 0xD0, 1); #get Id
+ $hash->{STATE} = 'getCalData';
+ I2C_BME280_i2cread($hash, 0x88, 26);
+ I2C_BME280_i2cread($hash, 0xE1, 8);
+ };
+ return I2C_BME280_Catch($@) if $@;
+}
+
+sub I2C_BME280_Catch($) { # Fehlermeldungen formattieren
+ my $exception = shift;
+ if ($exception) {
+ $exception =~ /^(.*)( at.*FHEM.*)$/;
+ return $1;
+ }
+ return undef;
+}
+
+sub I2C_BME280_Attr (@) { # Wird beim Attribut anlegen/aendern aufgerufen
+ my ($command, $name, $attr, $val) = @_;
+ my $hash = $defs{$name};
+ my $msg = '';
+
+ if (defined $command && $command eq "set" && $attr eq "IODev") {
+ eval {
+ if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $val)) {
+ main::AssignIoPort($hash,$val);
+ my @def = split (' ',$hash->{DEF});
+ I2C_LCD_Init($hash,\@def) if (defined ($hash->{IODev}));
+ }
+ };
+ $msg = I2C_BME280_Catch($@) if $@;
+ } elsif ($attr eq 'poll_interval') {
+ if (defined($val)) {
+ if ($val =~ m/^(0*[1-9][0-9]*)$/) {
+ RemoveInternalTimer($hash);
+ I2C_BME280_Poll($hash) if ($main::init_done);
+ #InternalTimer(gettimeofday() + 5, 'I2C_BME280_Poll', $hash, 0) if ($main::init_done);
+ } else {
+ $msg = 'Wrong poll intervall defined. poll_interval must be a number > 0';
+ }
+ } else {
+ RemoveInternalTimer($hash);
+ }
+ } elsif ($attr =~ m/^oversampling_.$/ && defined($val)) {
+ $msg = 'Wrong value: $val for $attr defined. value must be a one of 0,1,2,3,4,5' unless ($val =~ m/^(0*[0-5])$/);
+ } elsif ($attr =~ m/^round(Pressure|Temperature|Humidity)Decimal$/ && defined($val)) {
+ $msg = 'Wrong value: $val for $attr defined. value must be a one of 0,1,2' unless ($val =~ m/^(0*[0-2])$/);
+ }
+ return ($msg) ? $msg : undef;
+}
+
+sub I2C_BME280_Poll($) { # Messwerte regelmaessig anfordern
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ I2C_BME280_Set($hash, ($name, 'readValues')); # Read values
+ my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0);
+ if ($pollInterval > 0) {
+ InternalTimer(gettimeofday() + ($pollInterval * 60), 'I2C_BME280_Poll', $hash, 0);
+ }
+}
+
+sub I2C_BME280_Set($@) { # Messwerte manuell anfordern
+ my ($hash, @a) = @_;
+
+ my $name = $a[0];
+ my $cmd = $a[1];
+
+ if(!defined($sets{$cmd})) {
+ return 'Unknown argument ' . $cmd . ', choose one of ' . join(' ', keys %sets) . ":noArg"
+ }
+
+ if ($cmd eq 'readValues') {
+ if (defined($hash->{calibrationData}{dig_H6})) { # query sensor
+ I2C_BME280_i2cwrite($hash, 0xF2, AttrVal($name, 'oversampling_h', 1) & 7);
+ my $data = ( AttrVal($name, 'oversampling_t', 1) & 7 ) << 5 | ( AttrVal($name, 'oversampling_p', 1) & 7 ) << 2 | 1; #Register 0xF4 “ctrl_meas” zusammenbasteln
+ I2C_BME280_i2cwrite($hash, 0xF4, $data);
+ RemoveInternalTimer($hash);
+ InternalTimer(gettimeofday() + 1, 'I2C_BME280_UpdateReadings', $hash, 0); #nach 1s Werte auslesen
+ } else { #..but get calibration variables first
+ Log3 $hash, 5, "$name: in set but no calibrationData, requesting again";
+ I2C_BME280_i2cread($hash, 0x88, 26);
+ I2C_BME280_i2cread($hash, 0xE1, 16);
+ }
+ }
+ return undef
+}
+
+
+sub I2C_BME280_Get($@) { # Messwerte manuell anfordern
+ my ($hash, @a) = @_;
+ my $name = $a[0];
+ my $cmd = $a[1];
+
+ if (defined($cmd) && $cmd eq 'readValues') {
+ if (defined($hash->{calibrationData}{dig_H6})) { # query sensor
+ I2C_BME280_i2cwrite($hash, 0xF2, AttrVal($name, 'oversampling_h', 1) & 7);
+ my $data = ( AttrVal($name, 'oversampling_t', 1) & 7 ) << 5 | ( AttrVal($name, 'oversampling_p', 1) & 7 ) << 2 | 1; #Register 0xF4 “ctrl_meas” zusammenbasteln
+ I2C_BME280_i2cwrite($hash, 0xF4, $data);
+ RemoveInternalTimer($hash);
+ InternalTimer(gettimeofday() + 1, 'I2C_BME280_UpdateReadings', $hash, 0); #nach 1s Werte auslesen
+ } else { #..but get calibration variables first
+ Log3 $hash, 5, "$name: in set but no calibrationData, requesting again";
+ I2C_BME280_i2cread($hash, 0x88, 26);
+ I2C_BME280_i2cread($hash, 0xE1, 16);
+ }
+ } else {
+ return 'Unknown argument ' . $cmd . ', choose one of readValues:noArg';
+ }
+ return undef
+}
+
+
+sub I2C_BME280_UpdateReadings($) { # Messwerte auslesen
+ my ($hash) = @_;
+ I2C_BME280_i2cread($hash, 0xF7, 8); # alle Werte auslesen
+ my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0); #poll_interval Timer wiederherstellen
+ InternalTimer(gettimeofday() + ($pollInterval * 60), 'I2C_BME280_Poll', $hash, 0) if ($pollInterval > 0);
+}
+
+sub I2C_BME280_Undef($$) { # Device loeschen
+ my ($hash, $arg) = @_;
+ RemoveInternalTimer($hash);
+ return undef;
+}
+
+sub I2C_BME280_I2CRec ($$) { # wird vom IODev aus aufgerufen wenn I2C Daten vorliegen
+ my ($hash, $clientmsg) = @_;
+ my $name = $hash->{NAME};
+ my $pname = undef;
+ my $phash = $hash->{IODev};
+ $pname = $phash->{NAME};
+ while ( my ( $k, $v ) = each %$clientmsg ) { #erzeugen von Internals fuer alle Keys in $clientmsg die mit dem physical Namen beginnen
+ $hash->{$k} = $v if $k =~ /^$pname/ ;
+ }
+
+ if ( $clientmsg->{direction} && $clientmsg->{reg} && $clientmsg->{$pname . "_SENDSTAT"} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok" ) {
+ if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
+ Log3 $hash, 5, "$name Rx, Reg: $clientmsg->{reg}, Data: $clientmsg->{received}";
+ I2C_BME280_GetCal1 ($hash, $clientmsg->{received}) if $clientmsg->{reg} == 0x88 && $clientmsg->{nbyte} == 26;
+ I2C_BME280_GetCal2 ($hash, $clientmsg->{received}) if $clientmsg->{reg} == 0xE1 && $clientmsg->{nbyte} == 8;
+ I2C_BME280_GetId ($hash, $clientmsg->{received}) if $clientmsg->{reg} == 0xD0;
+ I2C_BME280_GetReadings ($hash, $clientmsg->{received}) if $clientmsg->{reg} == 0xF7 && $clientmsg->{nbyte} == 8;
+ }
+ }
+
+ return undef
+}
+
+sub I2C_BME280_GetId ($$) { # empfangenes Id Byte auswerten
+ my ($hash, $rawdata) = @_;
+ if ($rawdata == hex("60")) {
+ $hash->{DeviceType} = "BME280";
+ } elsif ($rawdata == hex("58")) {
+ $hash->{DeviceType} = "BMP280";
+ } if ($rawdata == hex("56") || $rawdata == hex("57")) {
+ $hash->{DeviceType} = "BMP280s";
+ }
+}
+
+sub I2C_BME280_GetCal1 ($$) { # empfangene Cal Daten in Internals Speichern
+ my ($hash, $rawdata) = @_;
+ my @raw = split(" ",$rawdata);
+ my $n = 0;
+ $hash->{calibrationData}{dig_T1} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++], 0); # unsigned
+ $hash->{calibrationData}{dig_T2} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_T3} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P1} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++], 0); # unsigned
+ $hash->{calibrationData}{dig_P2} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P3} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P4} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P5} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P6} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P7} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P8} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_P9} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $n++;
+ $hash->{calibrationData}{dig_H1} = $raw[$n++]; # unsigned
+ $hash->{STATE} = 'First calibration block received';
+ return
+}
+
+sub I2C_BME280_GetCal2 ($$) { # empfangene Cal Daten in Internals Speichern Teil 2
+ my ($hash, $rawdata) = @_;
+ my @raw = split(" ",$rawdata);
+ my $n = 0;
+ $hash->{calibrationData}{dig_H2} = I2C_BME280_GetCalVar($raw[$n++], $raw[$n++]);
+ $hash->{calibrationData}{dig_H3} = $raw[$n++]; # unsigned
+ $hash->{calibrationData}{dig_H4} = ($raw[$n++] << 4) | $raw[$n] & 0xF; # signed word, kann aber nur positiv sein, da nur 12 bit
+ $hash->{calibrationData}{dig_H5} = (($raw[$n++] >> 4) & 0x0F) | ($raw[$n++] << 4); # signed word, kann aber nur positiv sein, da nur 12 bit
+ $hash->{calibrationData}{dig_H6} = I2C_BME280_GetCalVar($raw[$n++], undef); # signed 8bit #geht das? oder muss I2C_BME280_GetCalVar ($;$$) angepasst werden
+ $hash->{STATE} = 'Initialized';
+ I2C_BME280_Poll($hash) if defined(AttrVal($hash->{NAME}, 'poll_interval', undef)); # wenn poll_interval definiert -> timer starten
+ return
+}
+
+sub I2C_BME280_GetCalVar ($$;$) { # Variablen aus Bytes zusammenbauen (signed und unsigned)
+ my ($lsb, $msb, $returnSigned) = @_;
+
+ $returnSigned = (!defined($returnSigned) || $returnSigned == 1) ? 1 : 0;
+ my $retVal = undef;
+ if (defined $msb) { # 16 bit Variable
+ $retVal = $msb << 8 | $lsb;
+ # check if we need return signed or unsigned int
+ if ($returnSigned == 1) {
+ $retVal = $retVal >> 15 ? $retVal - 2**16 : $retVal;
+ }
+ } else { # 8 bit Variable
+ $retVal = $lsb >> 7 ? $lsb - 2 ** 8 : $lsb;
+ }
+ return $retVal;
+}
+
+sub I2C_BME280_GetReadings ($$) { # Empfangene Messwerte verarbeiten
+ my ($hash, $rawdata) = @_;
+ my @raw = split(" ",$rawdata);
+ my @pres = splice(@raw,0,3);
+ my @temp = splice(@raw,0,3);
+ I2C_BME280_GetTemp ($hash, @temp );
+ I2C_BME280_GetPress ($hash, @pres);
+ I2C_BME280_GetHum ($hash, @raw );
+
+ my $tem = ReadingsVal($hash->{NAME},"temperature", undef);
+ my $hum = ReadingsVal($hash->{NAME},"humidity", undef);
+ my $prs = ReadingsVal($hash->{NAME},"pressure", undef);
+ readingsSingleUpdate(
+ $hash,
+ 'state',
+ ((defined $tem ? "T: $tem " : "") . (defined $hum ? "H: $hum " : "") . (defined $prs ? ("P: $prs P-NN: " . ReadingsVal($hash->{NAME},"pressure-nn", 0)) : "")),
+ 1
+ );
+}
+
+sub I2C_BME280_GetTemp ($@) { # Temperatur Messwerte verarbeiten
+ my ($hash, @raw) = @_;
+ if ( $raw[0] == 0x80 && $raw[1] == 0 && $raw[2] == 0 ) { # 0x80000 (MSB = 0x80) wird ausgegeben, wenn Temperaturmessung deaktiviert (oversampling_t = 0)
+ Log3 $hash, 4, "temperature reading deleted due to oversampling_t = 0";
+ delete ($hash->{READINGS}{temperature});
+ } else {
+ my $ut = $raw[0] << 12 | $raw[1] << 4 | $raw[2] >> 4 ;
+ my $temperature = sprintf(
+ '%.' . AttrVal($hash->{NAME}, 'roundTemperatureDecimal', 1) . 'f',
+ I2C_BME280_calcTrueTemperature($hash, $ut)
+ );
+ readingsSingleUpdate($hash, 'temperature', $temperature, 1);
+ }
+}
+
+sub I2C_BME280_GetPress ($@) { # Luftdruck Messwerte verarbeiten
+ my ($hash, @raw) = @_;
+ if ( $raw[0] == 0x80 && $raw[1] == 0 && $raw[2] == 0 ) { # 0x80000 (MSB = 0x80) wird ausgegeben, wenn Luftdruckmessung deaktiviert (oversampling_p = 0)
+ Log3 $hash, 4, "pressure readings seleted due to oversampling_p = 0";
+ delete ($hash->{READINGS}{'pressure'});
+ delete ($hash->{READINGS}{'pressure-nn'});
+ } else {
+ my $up = $raw[0] << 12 | $raw[1] << 4 | $raw[2] >> 4 ;
+ my $pressure = sprintf(
+ '%.' . AttrVal($hash->{NAME}, 'roundPressureDecimal', 1) . 'f',
+ I2C_BME280_calcTruePressure($hash, $up) / 100
+ );
+ my $altitude = AttrVal('global', 'altitude', 0);
+ # simple barometric height formula
+ my $pressureNN = sprintf(
+ '%.' . AttrVal($hash->{NAME}, 'roundPressureDecimal', 1) . 'f',
+ $pressure + ($altitude / 8.5)
+ );
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash, 'pressure', $pressure);
+ readingsBulkUpdate($hash, 'pressure-nn', $pressureNN);
+ readingsEndUpdate($hash, 1);
+ }
+}
+
+sub I2C_BME280_GetHum ($@) { # Luftfeuchte Messwerte verarbeiten
+ my ($hash, @raw) = @_;
+ if ( $raw[0] == 0x80 && $raw[1] == 0 ) { # 0x8000 (MSB = 0x80) wird ausgegeben, wenn Feuchtemessung deaktiviert (oversampling_h = 0)
+ Log3 $hash, 4, "humidity readings seleted due to oversampling_h = 0";
+ delete ($hash->{READINGS}{humidity})
+ } else {
+ my $uh = $raw[0] << 8 | $raw[1];
+ my $humidity = sprintf(
+ '%.' . AttrVal($hash->{NAME}, 'roundHumidityDecimal', 1) . 'f',
+ I2C_BME280_calcTrueHumidity($hash, $uh)
+ );
+ readingsSingleUpdate($hash, 'humidity', $humidity, 1);
+ }
+}
+
+sub I2C_BME280_i2cread($$$) { # Lesebefehl an Hardware absetzen (antwort kommt in I2C_*****_I2CRec an)
+ my ($hash, $reg, $nbyte) = @_;
+ if (defined (my $iodev = $hash->{IODev})) {
+ Log3 $hash, 5, "$hash->{NAME}: $hash->{I2C_Address} read $nbyte Byte from Register $reg";
+ CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
+ direction => "i2cread",
+ i2caddress => $hash->{I2C_Address},
+ reg => $reg,
+ nbyte => $nbyte
+ });
+ } else {
+ return "no IODev assigned to '$hash->{NAME}'";
+ }
+}
+
+sub I2C_BME280_i2cwrite($$$) { # Schreibbefehl an Hardware absetzen
+ my ($hash, $reg, @data) = @_;
+ if (defined (my $iodev = $hash->{IODev})) {
+ Log3 $hash, 5, "$hash->{NAME}: $hash->{I2C_Address} write " . join (' ',@data) . " to Register $reg";
+ CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
+ direction => "i2cwrite",
+ i2caddress => $hash->{I2C_Address},
+ reg => $reg,
+ data => join (' ',@data),
+ });
+ } else {
+ return "no IODev assigned to '$hash->{NAME}'";
+ }
+}
+
+sub I2C_BME280_calcTrueTemperature($$) { # Temperatur aus Rohwerten berechnen
+ my ($hash, $ut) = @_;
+ my $dig_T1 = $hash->{calibrationData}{dig_T1};
+ my $dig_T2 = $hash->{calibrationData}{dig_T2};
+ my $dig_T3 = $hash->{calibrationData}{dig_T3};
+
+ my $h1 = ( $ut / 16384.0 - $dig_T1 / 1024.0 ) * $dig_T2;
+ my $h2 = ( ( $ut / 131072.0 - $dig_T1 / 8192.0 ) * ( $ut / 131072.0 - $dig_T1 / 8192.0 ) ) * $dig_T3;
+ $hash->{calibrationData}{t_fine} = $h1 + $h2;
+ my $ct = $hash->{calibrationData}{t_fine} / 5120.0;
+
+ return $ct;
+}
+
+sub I2C_BME280_calcTruePressure($$) { # Luftdruck aus Rohwerten berechnen
+ my ($hash, $up) = @_;
+
+ my $t_fine = $hash->{calibrationData}{t_fine};
+ my $dig_P1 = $hash->{calibrationData}{dig_P1};
+ my $dig_P2 = $hash->{calibrationData}{dig_P2};
+ my $dig_P3 = $hash->{calibrationData}{dig_P3};
+ my $dig_P4 = $hash->{calibrationData}{dig_P4};
+ my $dig_P5 = $hash->{calibrationData}{dig_P5};
+ my $dig_P6 = $hash->{calibrationData}{dig_P6};
+ my $dig_P7 = $hash->{calibrationData}{dig_P7};
+ my $dig_P8 = $hash->{calibrationData}{dig_P8};
+ my $dig_P9 = $hash->{calibrationData}{dig_P9};
+
+ my $h1 = ($t_fine / 2) - 64000.0;
+ my $h2 = $h1 * $h1 * $dig_P6 / 32768;
+ $h2 = $h2 + $h1 * $dig_P5 * 2;
+ $h2 = $h2 / 4 + $dig_P4 * 65536;
+ #$h1 = $dig_P3 * $h1 * $h1 / 524288 + $dig_P2 * $h1 / 524288;
+ $h1 = ((($dig_P3 * ((($h1/4.0) * ($h1/4.0)) / 8192)) / 8) + (($dig_P2 * $h1) / 2.0)) / 262144;
+ #$h1 = ( 1 + $h1 / 32768) * $dig_P1;
+ $h1 = ((32768 + $h1) * $dig_P1) / 32768;
+ return 0 if ($h1 == 0);
+ my $p = ((1048576 - $up) - ($h2 / 4096)) * 3125;
+ if ($p < 0x80000000) {
+ $p = ($p * 2) / $h1;
+ } else {
+ $p = ($p / $h1) * 2 ;
+ }
+ #$p = ( $p - $h2 / 4096 ) * 6250 / $h1;
+ $h1 = ($dig_P9 * ((($p/8.0) * ($p/8.0)) / 8192.0)) / 4096;
+ $h2 = (($p/4.0) * $dig_P8) / 8192.0;
+ $p = $p + (($h1 + $h2 + $dig_P7) / 16);
+ return $p;
+}
+
+sub I2C_BME280_calcTrueHumidity($$) { # Luftfeuchte aus Rohwerten berechnen
+ my ($hash, $uh) = @_;
+
+ my $t_fine = $hash->{calibrationData}{t_fine};
+ my $dig_H1 = $hash->{calibrationData}{dig_H1};
+ my $dig_H2 = $hash->{calibrationData}{dig_H2};
+ my $dig_H3 = $hash->{calibrationData}{dig_H3};
+ my $dig_H4 = $hash->{calibrationData}{dig_H4};
+ my $dig_H5 = $hash->{calibrationData}{dig_H5};
+ my $dig_H6 = $hash->{calibrationData}{dig_H6};
+
+ my $t1 = $t_fine - 76800;
+ $t1 = ( $uh - ( $dig_H4 * 64 + $dig_H5 / 16384 * $t1 ) ) * ( $dig_H2 / 65536 * ( 1 + $dig_H6 / 67108864 * $t1 * ( 1 + $dig_H3 / 67108864 * $t1 ) ) );
+ $t1 = $t1 * ( 1 - $dig_H1 * $t1 / 524288);
+ if ($t1 > 100) {
+ $t1 = 100;
+ } elsif ($t1 < 0) {
+ $t1 = 0;
+ }
+ return $t1;
+}
+
+sub I2C_BME280_DbLog_splitFn($) { # Einheiten
+ my ($event) = @_;
+ Log3 undef, 5, "in DbLog_splitFn empfangen: $event";
+ my ($reading, $value, $unit) = "";
+
+ my @parts = split(/ /,$event);
+ $reading = shift @parts;
+ $reading =~ tr/://d;
+ $value = $parts[0];
+ $unit = "\xB0C" if(lc($reading) =~ m/temp/);
+ $unit = "hPa" if(lc($reading) =~ m/pres/);
+ $unit = "%" if(lc($reading) =~ m/humi/);
+ return ($reading, $value, $unit);
+}
+
+1;
+
+=pod
+=begin html
+
+
+I2C_BME280
+(en | de)
+
+
+ Provides an interface to the digital pressure/humidity sensor BME280
+ The I2C messages are send through an I2C interface module like RPII2C, FRM
+ or NetzerI2C so this device must be defined first.
+ attribute IODev must be set
+ Define
+
+ define BME280 I2C_BME280 [<I2C Address>]
+ without defined <I2C Address>
0x76 will be used as address
+
+ Examples:
+
+ define BME280 I2C_BME280 0x77
+ attr BME280 poll_interval 5
+
+
+
+
+ Set
+
+ set BME280 <readValues>
+
+ Reads current temperature, humidity and pressure values from the sensor.
+ Normaly this execute automaticly at each poll intervall. You can execute
+ this manually if you want query the current values.
+
+
+
+
+ Attributes
+
+ - oversampling_t,oversampling_h,oversampling_p
+ Controls the oversampling settings of the temperature,humidity or pressure measurement in the sensor.
+ Default: 1, valid values: 0, 1, 2, 3, 4, 5
+ 0 switches the respective measurement off
+ 1 to 5 complies to oversampling value 2^value/2
+
+ - poll_interval
+ Set the polling interval in minutes to query the sensor for new measured
+ values.
+ Default: 5, valid values: any whole number
+
+ - roundTemperatureDecimal,roundHumidityDecimal,roundPressureDecimal
+ Round temperature, humidity or pressure values to given decimal places.
+ Default: 1, valid values: 0, 1, 2
+
+ - altitude
+ if set, this altitude is used for calculating the pressure related to sea level (nautic null) NN
+ Note: this is a global attributes, e.g
+ attr global altitude 220
+
+ - IODev
+ - do_not_notify
+ - showtime
+
+
+
+=end html
+
+=begin html_DE
+
+
+I2C_BME280
+(en | de)
+
+
+ Ermöglicht die Verwendung eines digitalen (Luft)druck/feuchtesensors BME280 über den I2C Bus des Raspberry Pi.
+ I2C-Botschaften werden über ein I2C Interface Modul wie beispielsweise das RPII2C, FRM
+ oder NetzerI2C gesendet. Daher muss dieses vorher definiert werden.
+ Das Attribut IODev muss definiert sein.
+
+ Define
+
+ define BME280 <BME280_name> [<I2C Addresse>]
+ Fehlt <I2C Address>
wird 0x76 verwendet
+
+ Beispiel:
+
+ define BME280 I2C_BME280 0x77
+ attr BME280 poll_interval 5
+
+
+
+
+ Set
+
+ set BME280 readValues
+
+ set <name> readValues
+ Aktuelle Temperatur, Feuchte und Luftdruck Werte vom Sensor lesen.
+
+
+
+ Attribute
+
+ - oversampling_t,oversampling_h,oversampling_p
+ Steuert das jeweils das Oversampling der Temperatur-, Feuchte-, oder Druckmessung im Sensor.
+ Standard: 1, gültige Werte: 0, 1, 2, 3, 4, 5
+ 0 deaktiviert die jeweilige Messung
+ 1 to 5 entspricht einem Oversampling von 2^zahl/2
+
+ - poll_interval
+ Definiert das Poll Intervall in Minuten für das Auslesen einer neuen Messung.
+ Default: 5, gültige Werte: 1, 2, 5, 10, 20, 30
+
+ - roundTemperatureDecimal, roundHumidityDecimal, roundPressureDecimal
+ Rundet jeweils den Temperatur-, Feuchte-, oder Druckwert mit den angegebenen Nachkommastellen.
+ Standard: 1, gültige Werte: 0, 1, 2
+
+ - altitude
+ Wenn dieser Wert definiert ist, wird diese Angabe zusä für die Berechnung des
+ Luftdrucks bezogen auf Meereshöhe (Normalnull) NN herangezogen.
+ Bemerkung: Dies ist ein globales Attribut.
+ attr global altitude 220
+
+ - IODev
+ - do_not_notify
+ - showtime
+
+
+
+=end html_DE
+=cut
\ No newline at end of file
diff --git a/fhem/FHEM/52_I2C_EEPROM.pm b/fhem/FHEM/52_I2C_EEPROM.pm
index 3023ae08d..4355e99af 100644
--- a/fhem/FHEM/52_I2C_EEPROM.pm
+++ b/fhem/FHEM/52_I2C_EEPROM.pm
@@ -1,5 +1,5 @@
##############################################################################
-# $Id: 52_I2C_EEPROM.pm 7007 2014-11-17 18:03:42Z klauswitt $
+# $Id$
##############################################################################
# Modul for I2C EEPROM
#
diff --git a/fhem/FHEM/52_I2C_MCP23008.pm b/fhem/FHEM/52_I2C_MCP23008.pm
index d3bce8eca..08dde2e43 100644
--- a/fhem/FHEM/52_I2C_MCP23008.pm
+++ b/fhem/FHEM/52_I2C_MCP23008.pm
@@ -1,5 +1,5 @@
##############################################################################
-# $Id: 52_I2C_MCP23008.pm 6209 2014-07-06 21:38:39Z klauswitt $
+# $Id$
##############################################################################
# Modul for I2C GPIO Extender MCP23008
#
diff --git a/fhem/FHEM/52_I2C_MCP342x.pm b/fhem/FHEM/52_I2C_MCP342x.pm
index fc7f86683..097876b27 100644
--- a/fhem/FHEM/52_I2C_MCP342x.pm
+++ b/fhem/FHEM/52_I2C_MCP342x.pm
@@ -1,5 +1,5 @@
##############################################
-# $Id: 52_MCP342x.pm 5865 2014-05-14 23:00:12Z klauswitt $
+# $Id$
package main;
diff --git a/fhem/FHEM/52_I2C_PCA9685.pm b/fhem/FHEM/52_I2C_PCA9685.pm
index 0f02ada2e..f17122bb4 100644
--- a/fhem/FHEM/52_I2C_PCA9685.pm
+++ b/fhem/FHEM/52_I2C_PCA9685.pm
@@ -25,7 +25,6 @@ use strict;
use warnings;
use SetExtensions;
#use POSIX;
-use Scalar::Util qw(looks_like_number);
my $setdim = ":slider,0,1,4095 ";
@@ -34,23 +33,32 @@ my %setsP = (
'on' => 1,
);
+my %confregs = (
+0 => 'modereg1',
+1 => 'modereg2',
+2 => 'SUBADR1',
+3 => 'SUBADR2',
+4 => 'SUBADR3',
+5 => 'ALLCALLADR',
+);
+
my %defaultreg = (
'modereg1' => 32, #32-> Bit 5 -> Autoincrement
'modereg2' => 0,
-'sub1' => 113,
-'sub2' => 114,
-'sub3' => 116,
-'allc' => 112,
-'presc' => 30,
+'SUBADR1' => 113,
+'SUBADR2' => 114,
+'SUBADR3' => 116,
+'ALLCALLADR' => 112,
+'PRESCALE' => 30,
);
my %mr1 = (
'EXTCLK' => 64,
'SLEEP' => 16,
-'SUB1' => 8,
-'SUB2' => 4,
-'SUB3' => 2,
-'ALLCALL' => 1,
+'SUBADR1' => 8,
+'SUBADR2' => 4,
+'SUBADR3' => 2,
+'ALLCALLADR' => 1,
);
my %mr2 = (
@@ -69,22 +77,14 @@ sub I2C_PCA9685_Initialize($) { #
$hash->{AttrFn} = "I2C_PCA9685_Attr";
$hash->{StateFn} = "I2C_PCA9685_State";
$hash->{SetFn} = "I2C_PCA9685_Set";
- $hash->{GetFn} = "I2C_PCA9685_Get";
+ #$hash->{GetFn} = "I2C_PCA9685_Get";
$hash->{I2CRecFn} = "I2C_PCA9685_I2CRec";
$hash->{AttrList} = "IODev do_not_notify:1,0 ignore:1,0 showtime:1,0 ".
"prescale:slider,0,1,255 OnStartup ".
- "subadr1 subadr2 subadr3 allcalladr ".
- "modreg1:multiple-strict,EXTCLK,SUB1,SUB2,SUB3,ALLCALL ".
- "modreg2:multiple-strict,INVRT,OCH,OUTDRV,OUTNE0,OUTNE1 ".
- "$readingFnAttributes dummy:0,1";
-}
-#############################################################################
-sub I2C_PCA9685_SetState($$$$) { #-------wozu?
- my ($hash, $tim, $vt, $val) = @_;
-
- $val = $1 if($val =~ m/^(.*) \d+$/);
- #return "Undefined value $val" if(!defined($it_c2b{$val}));
- return undef;
+ "SUBADR1 SUBADR2 SUBADR3 ALLCALLADR ".
+ "modereg1:multiple-strict,EXTCLK,SUBADR1,SUBADR2,SUBADR3,ALLCALLADR ".
+ "modereg2:multiple-strict,INVRT,OCH,OUTDRV,OUTNE0,OUTNE1 ".
+ "$readingFnAttributes dummy:0,1 extClock";
}
#############################################################################
sub I2C_PCA9685_Define($$) {
@@ -98,45 +98,74 @@ sub I2C_PCA9685_Define($$) {
return undef;
}
#############################################################################
-sub I2C_PCA9685_Init($$) { #
+sub I2C_PCA9685_Init($$) { # wird ausgefuehrt bei Initialisierung und Connect/Reconnect des DEVio
my ( $hash, $args ) = @_;
#my @a = split("[ \t]+", $args);
my $name = $hash->{NAME};
- if (defined $args && int(@$args) != 1) {
+ if (defined $args && int(@$args) < 1) {
return "Define: Wrong syntax. Usage:\n" .
"define I2C_PCA9685 ";
}
- #return "$name I2C Address not valid" unless ($a[0] =~ /^(0x|)([0-7]|)[0-9A-F]$/xi);
- my $msg = undef;
if (defined (my $address = shift @$args)) {
- $hash->{I2C_Address} = $address =~ /^0.*$/ ? oct($address) : $address;
+ $hash->{I2C_Address} = $address =~ /^0x.*$/ ? oct($address) : $address;
+ return "$name: I2C Address not valid" unless ($hash->{I2C_Address} < 128 && $hash->{I2C_Address} > 3);
} else {
- return "$name I2C Address not valid";
+ return "$name: no I2C Address defined" unless defined($hash->{I2C_Address});
}
- AssignIoPort($hash);
- #Mode register wiederherstellen
- I2C_PCA9685_i2cread($hash, 1, 1); # Modreg2 schonmal lesen
- I2C_PCA9685_i2cread($hash, 254, 1); # Frequenz fuer Internal
- select(undef, undef, undef, 0.1);
- I2C_PCA9685_Attr(undef, $name, "modreg1", AttrVal($name, "modreg1", ""));
- I2C_PCA9685_Attr(undef, $name, "modreg2", AttrVal($name, "modreg2", "OUTDRV"));
- #alternative I2C Adressen wiederherstellen
- I2C_PCA9685_i2cwrite($hash,AttrVal($name, $defaultreg{'sub1'}, "subadr1") << 1, 2) if defined AttrVal($name, "subadr1", undef);
- I2C_PCA9685_i2cwrite($hash,AttrVal($name, $defaultreg{'sub2'}, "subadr2") << 1, 3) if defined AttrVal($name, "subadr2", undef);
- I2C_PCA9685_i2cwrite($hash,AttrVal($name, $defaultreg{'sub3'}, "subadr3") << 1, 4) if defined AttrVal($name, "subadr3", undef);
- I2C_PCA9685_i2cwrite($hash,AttrVal($name, $defaultreg{'allc'}, "allcalladr") << 1, 5) if defined AttrVal($name, "allcalladr", undef);
- #PWM Frequenz wiederherstellen
- I2C_PCA9685_Attr(undef, $name, "prescale", AttrVal($name, "prescale", $defaultreg{'presc'})) if defined AttrVal($name, "prescale", undef);
- #Portzustände wiederherstellen
- foreach (0..15) {
- my $port = "Port".sprintf ('%02d', $_);
- I2C_PCA9685_Set($hash, $name, $port, ReadingsVal($name,$port ,0) );
+ if (defined (my $maxbuff = shift @$args)) {
+ return "$name: I2C buffer size must be a number" if $maxbuff =~ m/^d+$/;
+ $hash->{I2C_Buff} = $maxbuff;
}
- $hash->{STATE} = 'Initialized';
- return;
+ my $msg = '';
+ eval {
+ Log3 $hash, 4, "$hash->{NAME}: Init1 Konfigurationsregister auslesen";
+ AssignIoPort($hash);
+ #Config Register lesen (einzeln, da Blockweises lesen noch aktiviert werden muss)
+ I2C_PCA9685_i2cread($hash, 0, 1); # Modereg1
+ I2C_PCA9685_i2cread($hash, 1, 1); # Modereg2
+ I2C_PCA9685_i2cread($hash, 2, 1); # Subadr1
+ I2C_PCA9685_i2cread($hash, 3, 1); # Subadr2
+ I2C_PCA9685_i2cread($hash, 4, 1); # Subadr3
+ I2C_PCA9685_i2cread($hash, 5, 1); # Allcalladr
+ I2C_PCA9685_i2cread($hash, 254, 1); # Frequenz fuer Internal
+ $hash->{STATE} = 'Initializing';
+ InternalTimer(gettimeofday() + 10, 'I2C_PCA9685_InitError', $hash, 0); # nach 10s Initialisierungsfehler ablegen
+ };
+ return I2C_BME280_Catch($@) if $@;
}
#############################################################################
-sub I2C_PCA9685_Catch($) { #
+sub I2C_PCA9685_Init2($) { # wird audgefuehrt wenn Frequenzregisterinhalt empfangen wird und entsprechendes Internal noch leer ist
+ my ( $hash ) = @_;
+ my $name = $hash->{NAME};
+ eval {
+ Log3 $hash, 4, "$hash->{NAME}: Init2 Konfigurationsregister beschreiben";
+ RemoveInternalTimer($hash); # Timer fuer Initialisierungsfehler stoppen
+ # Mode register wiederherstellen
+ I2C_PCA9685_Attr(undef, $name, "modereg1", AttrVal($name, "modereg1", undef));
+ I2C_PCA9685_Attr(undef, $name, "modereg2", AttrVal($name, "modereg2", undef));
+ # alternative I2C Adressen wiederherstellen
+ I2C_PCA9685_Attr(undef, $name, "SUBADR1", AttrVal($name, "SUBADR1", undef));
+ I2C_PCA9685_Attr(undef, $name, "SUBADR2", AttrVal($name, "SUBADR2", undef));
+ I2C_PCA9685_Attr(undef, $name, "SUBADR3", AttrVal($name, "SUBADR3", undef));
+ I2C_PCA9685_Attr(undef, $name, "ALLCALLADR", AttrVal($name, "ALLCALLADR", undef));
+ # PWM Frequenz wiederherstellen
+ I2C_PCA9685_Attr(undef, $name, "prescale", AttrVal($name, "prescale", undef));
+ #Portzustände wiederherstellen
+ foreach (0..15) {
+ my $port = "Port".sprintf ('%02d', $_);
+ I2C_PCA9685_Set($hash, $name, $port, ReadingsVal($name,$port ,0) );
+ }
+ $hash->{STATE} = 'Initialized';
+ };
+ return I2C_BME280_Catch($@) if $@;
+}
+#############################################################################
+sub I2C_PCA9685_InitError($) { # wird audgefuehrt wenn 10s nach Init immer noch keine Registerwerte empfangen wurden
+ my ( $hash ) = @_;
+ $hash->{STATE} = 'Error during Initialisation';
+}
+#############################################################################
+sub I2C_PCA9685_Catch($) { # Fehlermeldung von eval formattieren
my $exception = shift;
if ($exception) {
$exception =~ /^(.*)( at.*FHEM.*)$/;
@@ -147,7 +176,7 @@ sub I2C_PCA9685_Catch($) { #
#############################################################################
sub I2C_PCA9685_State($$$$) { # reload readings at FHEM start
my ($hash, $tim, $sname, $sval) = @_;
- Log3 $hash, 4, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim";
+ Log3 $hash, 5, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim";
if ($sname =~ m/^Port(((0|)[0-9])|(1[0-5]))$/i) {
substr($sname,0,4,"");
$sname = sprintf('%d', $sname);
@@ -156,7 +185,7 @@ sub I2C_PCA9685_State($$$$) { # reload readings at FHEM start
Log3 $hash, 5, "$hash->{NAME}: Port" . sprintf('%02d', $sname) . " soll auf $onstart{$sname} gesetzt werden";
readingsSingleUpdate($hash,"Port". sprintf('%02d', $sname), $onstart{$sname}, 1);
} else {
- Log3 $hash, 5, "$hash->{NAME}: Port" . sprintf('%02d', $sname) . " soll auf Altzustand: $sval gesetzt werden";
+ Log3 $hash, 4, "$hash->{NAME}: Port" . sprintf('%02d', $sname) . " soll auf Altzustand: $sval gesetzt werden";
$hash->{READINGS}{'Port'. sprintf('%02d', $sname)}{VAL} = $sval;
$hash->{READINGS}{'Port'. sprintf('%02d', $sname)}{TIME} = $tim;
}
@@ -164,12 +193,15 @@ sub I2C_PCA9685_State($$$$) { # reload readings at FHEM start
return undef;
}
#############################################################################
-sub I2C_PCA9685_Undefine($$) { #
+sub I2C_PCA9685_Undefine($$) { # wird beim loeschen des Device ausgefuehrt
my ($hash, $arg) = @_;
+ my ($msg, $data, $reg) = I2C_PCA9685_CalcRegs($hash, 61, 'off', undef); # Registerinhalte berechnen alle Ports aus
+ $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data) unless($msg); # Rausschicken
+ RemoveInternalTimer($hash);
return undef
}
#############################################################################
-sub I2C_PCA9685_Attr(@) { #
+sub I2C_PCA9685_Attr(@) { # wird beim setzen eines Attributes ausgefuehrt
my ($command, $name, $attr, $val) = @_;
my $hash = $defs{$name};
my $msg = '';
@@ -180,69 +212,80 @@ sub I2C_PCA9685_Attr(@) { #
I2C_PCA9685_Init($hash,\@def) if (defined ($hash->{IODev}));
}
} elsif ($attr && $attr =~ m/^prescale$/i) { # Frequenz
- return undef unless ($main::init_done);
- $val = 30 unless (defined($val)); #beim loeschen wieder auf Standard setzen
+ $val = $defaultreg{'PRESCALE'} unless (defined($val)); #beim loeschen wieder auf Standard setzen
return "wrong value: $val for \"set $name $attr\" use 0-255"
- unless(looks_like_number($val) && $val >= 0 && $val < 256);
- my $modereg1 = defined $hash->{confregs}{0} ? $hash->{confregs}{0} : $defaultreg{'modreg1'};
- my $modereg1mod = ( $modereg1 & 0x7F ) | $mr1{ "SLEEP" };
- $msg = I2C_PCA9685_i2cwrite($hash, 0, $modereg1mod); #sleep Mode aktivieren
- $msg = I2C_PCA9685_i2cwrite($hash, 254 ,$val); #Frequenz aktualisieren
- $msg = I2C_PCA9685_i2cwrite($hash, 0 ,$modereg1); #sleep Mode wieder aus
- foreach (0..15) { #Portzustände wiederherstellen
- my $port = "Port".sprintf ('%02d', $_);
- I2C_PCA9685_Set($hash, $name, $port, ReadingsVal($name,$port ,0) );
+ unless($val =~ m/^(\d+)$/ && $val >= 0 && $val < 256);
+ Log3 $hash, 5, $hash->{NAME} . ": $attr alter Wert: ".$hash->{confregs}{PRESCALE}." neuer Wert: ".$val;
+ if ($main::init_done && $val != $hash->{confregs}{PRESCALE}) {
+ my $modereg1 = defined $hash->{confregs}{$confregs{0}} ? $hash->{confregs}{$confregs{0}} : $defaultreg{'modereg1'};
+ my $modereg1mod = ( $modereg1 & 0x7F ) | $mr1{ "SLEEP" };
+ $msg = I2C_PCA9685_i2cwrite($hash, 0, $modereg1mod); #sleep Mode aktivieren
+ $msg = I2C_PCA9685_i2cwrite($hash, 254 ,$val); #Frequenz aktualisieren
+ $msg = I2C_PCA9685_i2cwrite($hash, 0 ,$modereg1); #sleep Mode wieder aus
+ foreach (0..15) { #Portzustände wiederherstellen
+ my $port = "Port".sprintf ('%02d', $_);
+ I2C_PCA9685_Set($hash, $name, $port, ReadingsVal($name,$port ,0) );
+ }
}
- } elsif ($attr && $attr =~ m/^(subadr[1-3])|allcalladr$/i) { # weitere I2C Adressen
- return undef unless ($main::init_done);
- substr($attr,0,6,"");
+ } elsif ($attr && $attr =~ m/^(SUBADR[1-3])|ALLCALLADR$/i) { # weitere I2C Adressen
+ $val = $defaultreg{$attr} unless defined($val);
+ substr($attr,0,6,"");
my $regaddr = ($attr =~ m/^l/i) ? 5 : $attr + 1;
- my $subadr = $val =~ /^0.*$/ ? oct($val) : $val;
- return "I2C Address not valid" if $subadr > 127;
- $msg = I2C_PCA9685_i2cwrite($hash, $regaddr ,$subadr << 1);
- } elsif ($attr && $attr =~ m/^modreg1$/i) { # Mode register 1
- return undef unless ($main::init_done);
+ my $SUBADR = $val =~ /^0x.*$/ ? oct($val) : $val;
+ return "I2C Address not valid" if $SUBADR > 127;
+ Log3 $hash, 5, $hash->{NAME} . ": $confregs{$regaddr} alter Wert: ".$hash->{confregs}{$confregs{$regaddr}}." neuer Wert: ".($SUBADR << 1);
+ $msg = I2C_PCA9685_i2cwrite($hash, $regaddr ,$SUBADR << 1) if $main::init_done && ($SUBADR << 1) != $hash->{confregs}{$confregs{$regaddr}};
+ } elsif ($attr && $attr =~ m/^modereg1$/i) { # Mode register 1
my @inp = split(/,/, $val) if defined($val);
my $data = 32; # Auto increment soll immer gesetzt sein
foreach (@inp) {
return "wrong value: $_ for \"attr $name $attr\" use comma separated list of " . join(',', (sort { $mr1{ $a } <=> $mr1{ $b } } keys %setsP) )
unless(exists($mr1{$_}));
$data |= $mr1{$_};
- if ($_ eq "EXTCLK") { #wenn externer Oszillator genutzt werden soll, zuerst den sleep mode aktivieren (wenn er gelöscht wird dann noch reset machen)
- my $modereg1 = defined $hash->{confregs}{0} ? $hash->{confregs}{0} : $defaultreg{'modreg1'};
+ if ($main::init_done && $_ eq "EXTCLK" && ($hash->{confregs}{$confregs{0}} & $mr1{"EXTCLK"}) == 0) { #wenn externer Oszillator genutzt werden soll, zuerst den sleep mode aktivieren
+ my $modereg1 = defined $hash->{confregs}{$confregs{0}} ? $hash->{confregs}{$confregs{0}} : $defaultreg{'modereg1'};
my $modereg1mod = ( $modereg1 & 0x7F ) | $mr1{ "SLEEP" };
Log3 $hash, 5, "$hash->{NAME}: sleep Mode aktivieren (Vorbereitung fuer EXTCLK)";
$msg = I2C_PCA9685_i2cwrite($hash, 0 ,$modereg1mod); #sleep Mode aktivieren
- $data += $mr1{"SLEEP"};
+# $data += $mr1{"SLEEP"}; #???????? muss hier nicht deaktiviert werden?????
}
}
- if ( defined $hash->{confregs}{0} && ($hash->{confregs}{0} & $mr1{"EXTCLK"}) == $mr1{"EXTCLK"} && ($data & $mr1{"EXTCLK"}) == 0 ) { #reset wenn EXTCLK abgeschaltet wird
+ if ($main::init_done && defined $hash->{confregs}{$confregs{0}} && ($hash->{confregs}{$confregs{0}} & $mr1{"EXTCLK"}) == $mr1{"EXTCLK"} && ($data & $mr1{"EXTCLK"}) == 0 ) { #reset wenn EXTCLK abgeschaltet wird
$msg = I2C_PCA9685_i2cwrite($hash, 0 , $data | 0x80);
}
- $msg = I2C_PCA9685_i2cwrite($hash, 0 , $data);
- } elsif ($attr && $attr =~ m/^modreg2$/i) { #Mode register 2
- return undef unless ($main::init_done);
+ Log3 $hash, 5, $hash->{NAME} . ": $attr alter Wert: ".$hash->{confregs}{$confregs{0}}." neuer Wert: ".$data;
+ if ( $main::init_done && $data != $hash->{confregs}{$confregs{0}} ) {
+ I2C_PCA9685_UpdReadings($hash, 0, $data); #schonmal in den Internals ablegen lassen (damit wärend Initialisierung mit korrekten daten gearbeitet wird... bei Frequenz z.B.)
+ $msg = I2C_PCA9685_i2cwrite($hash, 0 , $data);
+ }
+ } elsif ($attr && $attr =~ m/^modereg2$/i) { #Mode register 2
my @inp = split(/,/, $val) if defined($val);
- my $data = 0; # Auto increment soll immer gesetzt sein
+ my $data = 0;
foreach (@inp) {
return "wrong value: $_ for \"attr $name $attr\" use comma separated list of " . join(',', (sort { $mr2{ $a } <=> $mr2{ $b } } keys %setsP) )
unless(exists($mr2{$_}));
$data += $mr2{$_};
}
- $msg = I2C_PCA9685_i2cwrite($hash, 1, $data) if ($hash->{confregs}{1} != $data);
+ Log3 $hash, 5, $hash->{NAME} . ": $attr alter Wert: ".(defined($hash->{confregs}{$confregs{1}})?$hash->{confregs}{$confregs{1}}:"")." neuer Wert: ".$data;
+ $msg = I2C_PCA9685_i2cwrite($hash, 1, $data) if $main::init_done && $data != $hash->{confregs}{$confregs{1}};
} elsif ($attr && $attr eq "OnStartup") {
- if (defined $val) {
- foreach (split (/,/,$val)) {
- my @pair = split (/=/,$_);
- $msg = "wrong value: $_ for \"attr $hash->{NAME} $attr\" use comma separated =on|off|0..4095|last where = 0 - 15 "
- unless ( scalar(@pair) == 2 &&
- (($pair[0] =~ m/(^[0-9]|1[0-5])$/i &&
- ( $pair[1] eq "last" || exists($setsP{$pair[1]}) ||
- ( $pair[1] =~ m/^\d+$/ && $pair[1] < 4095 ) ) ) )
- );
+ if (defined $val) {
+ foreach (split (/,/,$val)) {
+ my @pair = split (/=/,$_);
+ $msg = "wrong value: $_ for \"attr $hash->{NAME} $attr\" use comma separated =on|off|0..4095|last where = 0 - 15 "
+ unless ( scalar(@pair) == 2 &&
+ (($pair[0] =~ m/(^[0-9]|1[0-5])$/i &&
+ ( $pair[1] eq "last" || exists($setsP{$pair[1]}) ||
+ ( $pair[1] =~ m/^\d+$/ && $pair[1] < 4095 ) ) ) )
+ );
+ }
}
+ } elsif ($attr && $attr eq "extClock") {
+ $val = defined($val) ? $val : 25;
+ return "wrong value: $val for \"set $name $attr\" use point number"
+ unless($val =~ m/^[1-9][0-9]*\.?[0-9]*$/);
+ I2C_PCA9685_i2cread($hash, 254, 1); # Frequenz fuer Internal neu auslesen und berechnen
}
- }
return ($msg) ? $msg : undef;
}
#############################################################################
@@ -253,38 +296,78 @@ sub I2C_PCA9685_Set($@) { #
my $dimcount = AttrVal($name, "dimcount", "4095");
my $msg;
my $str = join(' ',@rest);
- if ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))/i) { # (mehrere) Ports ( regex unfertig)
- #Log3 undef, 1, "$name: empfangen: $str";
- if (index($str, ',') == -1) { # Nur ein Port
- my ($port, $dim, $delay) = split(' ', $str);
- #Log3 undef, 1, "$name: ein Wert: $port, $dim, $delay";
- $msg = I2C_PCA9685_SetPort($hash, $port, $dim, $delay);
- } elsif ($str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))(( ){0,3},( ){0,3}(P(ort|)((0|)[0-9]|1[0-5])){1,})( ){1,3}\d*(( ){1,3}\d*)?( ){0,3}$/i ) { # Format P[ort]x,P[ort]y[,P..] Dimwert[ Delay]
- my @einzel = split(',', $str);
- my (undef, $dim, $delay) = split(' ', $einzel[$#einzel]);
- foreach (reverse @einzel) {
- my ($port) = split(' ', $_);
- #Log3 undef, 1, "$name: mehrere Ports gleich: $port, $dim" . (defined $delay ? ", $delay" : "" );
- $msg = I2C_PCA9685_SetPort($hash, $port, $dim, $delay);
- last if defined($msg);
- }
-
- } elsif ($str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( ){1,3}\d*(( ){1,3}\d*)?(( ){0,3},( ){0,3}(P(ort|)((0|)[0-9]|1[0-5]))( ){1,3}\d*(( ){1,3}\d*)?){1,}( ){0,3}$/i ) { # Mehrere Ports auf versch. Werte setzen
- my @einzel = split(',', $str);
- foreach (@einzel) {
- my ($port, $dim, $delay) = split(' ', $_);
- #Log3 undef, 1, "$name: mehrere Ports: $port, $dim" . (defined $delay ? ", $delay" : "" );
- $msg = I2C_PCA9685_SetPort($hash, $port, $dim, $delay);
- last if defined($msg);
- }
-
+ #Log3 undef, 5, "$name: empfangen: $str";
+ if ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))/i && index($str, ',') == -1) { # Nur ein Port
+ my ($port, $dim, $delay) = split(' ', $str);
+ $port =~ tr/(P|p)(ort|)//d;
+ #Log3 undef, 5, "$name: ein Port: $port, $dim, $delay";
+ ($msg, my $data, my $reg) = I2C_PCA9685_CalcRegs($hash, $port, $dim, $delay); # Registerinhalte berechnen
+ $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data) unless($msg); # Rausschicken
+ # } elsif ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( *, *(P(ort|)((0|)[0-9]|1[0-5]))){1,} +\d+( +\d*)?/i ) { # Format P[ort]x,P[ort]y[,P..] Dimwert[ Delay]
+ } elsif ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( *, *(P(ort|)((0|)[0-9]|1[0-5]))){1,}/i ) { # Format P[ort]x,P[ort]y[,P..] Dimwert[ Delay]
+ Log3 undef, 5, "mehrere ports und ein wert";
+ $str =~ tr/(P|p)(ort|)//d;
+ my @einzel = split(',', $str);
+ my @port;
+ my (undef, $dim, $delay) = split(' ', $einzel[$#einzel]);
+ for my $i (0..$#einzel){
+ ($port[$i]) = split(' ', $einzel[$i]);
}
- } elsif ($str =~ m/(a(ll|) \d{1,4}( \d{1,4})?)( ){0,3}$/i) { # Alle Ports gleichzeitig
+ my ($data, $reg) = undef;
+ my $j = 1;
+ for my $i (0..$#einzel){
+ ($msg, my $tdata, my $treg) = I2C_PCA9685_CalcRegs($hash, $port[$i], $dim, ( defined($delay) ? $delay : undef ) ); # Registerinhalte berechnen
+ return $msg if defined($msg);
+ Log3 $hash, 5, "$name: Port: $port[$i], Reg: $treg, Inhalt: $tdata, Rohwerte: $einzel[$i], Dimwert: $dim, Delay: ". ( defined($delay) ? ( $delay = "" ? "leer" : $delay ) : "leer" );
+ if ( defined($data) && defined($reg) ) { # bereits Werte für Ports vorhanden
+ $j += 1;
+ $data .= " " . $tdata;
+ } else {
+ $data = $tdata;
+ $reg = $treg;
+ }
+ unless ( $j < (int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4)) && $i < $#einzel && ($port[$i] + 1) == $port[$i+1]){ #wenn der naechste Port nicht der direkt Nachfolgende ist oder mehr als 8 Ports (32Bytes)
+ $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data); # Rausschicken
+ ($data, $reg) = undef;
+ $j = 1;
+ }
+ }
+ } elsif ($str && $str =~ m/^(P(ort|)((0|)[0-9]|1[0-5]))( ){1,3}\d*(( ){1,3}\d*)?(( ){0,3},( ){0,3}(P(ort|)((0|)[0-9]|1[0-5]))( ){1,3}\d*(( ){1,3}\d*)?){1,}( ){0,3}$/i ) { # Mehrere Ports auf versch. Werte setzen
+ Log3 undef, 5, "mehrere ports und unterschiedliche Werte";
+ $str =~ tr/(P|p)(ort|)//d;
+ my @einzel = split(',', $str);
+ my (@port, @dim, @delay);
+ #@einzel = sort { $a <=> $b } @einzel;
+ for my $i (0..$#einzel){
+ ($port[$i], $dim[$i], $delay[$i]) = split(' ', $einzel[$i]);
+ }
+ my ($data, $reg) = undef;
+ my $j = 1;
+ for my $i (0..$#einzel){
+ ($msg, my $tdata, my $treg) = I2C_PCA9685_CalcRegs($hash, $port[$i], $dim[$i], ( defined($delay[$i]) ? $delay[$i] : undef ) ); # Registerinhalte berechnen
+ return $msg if defined($msg);
+ Log3 $hash, 5, "$name: Port: $port[$i], Reg: $treg, Inhalt: $tdata, Rohwerte: $einzel[$i], Dimwert: $dim[$i], Delay: ". ( defined($delay[$i]) ? ( $delay[$i] =~ m/ */ ? "leer" : $delay[$i] ) : "leer" );
+ if ( defined($data) && defined($reg) ) { # bereits Werte für Ports vorhanden
+ $j += 1;
+ $data .= " " . $tdata;
+ } else {
+ $data = $tdata;
+ $reg = $treg;
+ }
+ unless ( $j < int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4) && $i < $#einzel && ($port[$i] + 1) == $port[$i+1]){ #wenn der naechste Port nicht der direkt Nachfolgende ist oder mehr als 8 Ports (32Bytes)
+ $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data); # Rausschicken
+ ($data, $reg) = undef;
+ $j = 1;
+
+ }
+ }
+ } elsif ($str =~ m/(a(ll|)( ){0,3}((\d{1,4})|on|off)(( ){0,3}\d{1,4})?)( ){0,3}$/i) { # Alle Ports gleichzeitig
my ($port, $dim, $delay) = split(' ', $str);
$port = 61; # Portnummer auf 61 für All setzen (All Startreg ist 250)
- #Log3 undef, 1, "$name: alle Ports: $port, $dim" . (defined $delay ? ", $delay" : "" );
- $msg = I2C_PCA9685_SetPort($hash, $port, $dim, $delay);
- } else {
+ Log3 undef, 5, "$name: alle Ports: $port, $dim" . (defined $delay ? ", $delay" : "" );
+ my ($msg, $data, $reg) = I2C_PCA9685_CalcRegs($hash, $port, $dim, $delay); # Registerinhalte berechnen
+ $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data) unless($msg); # Rausschicken
+ } else {
my $list = undef;
foreach (0..15) {
$list .= "Port" . sprintf ('%02d', $_) . ":slider,0,$dimstep,$dimcount ";
@@ -292,97 +375,68 @@ sub I2C_PCA9685_Set($@) { #
$list .= "all:slider,0,$dimstep,$dimcount";
$msg = "Unknown argument $str, choose one of " . $list;
}
-
- return (defined($msg) ? $msg."--" : undef);
-
-}
- #my $string = 'AA55FF0102040810204080';
- #my @hex = ($string =~ /(..)/g);
- #my @dec = map { hex($_) } @hex;
- #my @bytes = map { pack('C', $_) } @dec;
- #or
- #my @bytes = map { pack('C', hex($_)) } ($string =~ /(..)/g);
- #or
- #my $bytes = pack "H*", $hex;
- #----------------------
- #$int = 2001;
- #$bint = pack("N", $int);
- #@octets = unpack("C4", $bint);
- #sprintf "%02X " x 4 . "\n", @octets;
- # prints: 00 00 07 D1
-#############################################################################
-sub I2C_PCA9685_SetPort($$$$) { #
- my ($hash, $port, $dim, $delay) = @_;
- my $name = $hash->{NAME};
- my $dimcount = AttrVal($name, "dimcount", "4095");
- $port =~ tr/P(ort|)//d; #Nummer aus Port extrahieren
- return "wrong dimvalue: $dim for \"set $name $port\" use one of: " .
- join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) .
- " 0..$dimcount"
- unless(exists($setsP{$dim}) || ($dim >= 0 && $dim <= $dimcount));
-
- return "wrong delayvalue: $delay for \"set $name $port $dim\" use one of: " .
- join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) .
- " 0..$dimcount"
- unless( not defined($delay) && ( exists($setsP{$delay}) || ($delay >= 0 && $delay <= $dimcount) ));
-
- my ($data, $reg) = I2C_PCA9685_CalcRegs($hash, $port, $dim, $delay); # Registerinhalte berechnen
- my $msg = I2C_PCA9685_i2cwrite($hash,$reg, $data); # Rausschicken
- return defined $msg ? $msg : undef
+ return (defined($msg) ? $msg : undef);
}
#############################################################################
sub I2C_PCA9685_CalcRegs($$$$) { # Registerinhalte berechnen
- my ($hash, $port, $val, $del) = @_;
+ my ($hash, $port, $dim, $del) = @_;
+ my $name = $hash->{NAME};
+ #$port =~ tr/P(ort|)//d; #Nummer aus Port extrahieren
my $dimcount = AttrVal($hash->{NAME}, "dimcount", "4095");
my $data;
- if ($val eq "on") {
+ my $msg = undef;
+ if (defined($dim) && $dim eq "on") {
$data = "0 16 0 0";
- } elsif ($val eq "off") {
+ } elsif (defined($dim) && $dim eq "off") {
$data = "0 0 0 16";
- } else {
+ } elsif (defined($dim) && $dim =~ m/^\d+$/ && $dim >= 0 && $dim <= $dimcount) {
my $delaytime = 0;
if ($dimcount < 4095) { #DimmWert anpassen bei anderem Faktor
- $val = int($val * 4095 / $dimcount);
+ $dim = int($dim * 4095 / $dimcount);
}
if (defined $del) { #Delaytime angegeben?
- return "wrong delay value: $del for \"set $hash->{NAME} Port$port $val $del\" use value between 0 and $dimcount"
- unless ($del >= 0 && $del <= $dimcount);
+ $msg = "wrong delay value: \"$del\" for \"$name Port$port $dim\" use value between 0 and $dimcount"
+ unless ($del =~ m/^\d+$/ && $del >= 0 && $del <= $dimcount);
if ($dimcount < 4095) { #DelayWert anpassen bei anderem Faktor
$del = int($del * 4095 / $dimcount);
}
$delaytime = $del
} else { #...wenn nicht aus Reading holen (für all kommt immer 0 raus)
- $delaytime = ReadingsVal($hash->{NAME},'Port_d'.sprintf ('%02d', $port),"0");
+ $delaytime = ReadingsVal($name,'Port_d'.sprintf ('%02d', $port),"0");
}
- my $LEDx_OFF = $delaytime + $val - (( $val + $delaytime < 4096 ) ? 0 : 4096);
- if ($LEDx_OFF == $delaytime) { #beide Register dürfen nicht gleichen Inhalt haben, das entpricht "aus"
- $data = "0 0 0 16";
- } else {
- my @LEDx = unpack("C*", pack("S", $delaytime));
- push @LEDx, unpack("C*", pack("S", $LEDx_OFF)); #Array $LEDx[0] = LEDx_ON_L, $LEDx[1] = LEDx_ON_H, $LEDx[2] = LEDx_OFF_L, $LEDx[3] = LEDx_OFF_H
- $data = sprintf "%01d " x 4, @LEDx;
+ unless($msg) { # nur berechnen wenn es keine Fehlermeldung gibt
+ my $LEDx_OFF = $delaytime + $dim - (( $dim + $delaytime < 4096 ) ? 0 : 4096);
+ if ($LEDx_OFF == $delaytime) { #beide Register dürfen nicht gleichen Inhalt haben, das entpricht "aus"
+ $data = "0 0 0 16";
+ } else {
+ my @LEDx = unpack("C*", pack("S", $delaytime));
+ push @LEDx, unpack("C*", pack("S", $LEDx_OFF)); #Array $LEDx[0] = LEDx_ON_L, $LEDx[1] = LEDx_ON_H, $LEDx[2] = LEDx_OFF_L, $LEDx[3] = LEDx_OFF_H
+ # $data = sprintf "%01d " x 4, @LEDx;
+ $data = sprintf "%01d %01d %01d %01d", @LEDx;
}
+ }
+ } else {
+ $msg = "wrong dimvalue: \"".(defined($dim)?$dim:"...")."\" for \"$name Port$port\" use one of: " .
+ join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " 0..$dimcount";
}
- my $reg = 6 + 4 * $port; # Nummer des entspechenden LEDx_ON_L Registers (LED0_ON_L = 0x06) jede LED hat 4 Register
- return $data, $reg;
+ my $reg = 6 + 4 * $port if defined $port; # Nummer des entspechenden LEDx_ON_L Registers (LED0_ON_L = 0x06) jede LED hat 4 Register
+ return $msg, $data, $reg;
}
#############################################################################
sub I2C_PCA9685_Get($@) { # Portwerte bei laden der Datailseite aktualisieren
my ($hash, @a) = @_;
+ unless ($hash->{IODev}->{TYPE} eq 'RPII2C') { #fuer FRM, etc. Register zurücklesen (bei RPII2C kommt bei erfolgreicher Uebertragung die Botschaft zurueck)
+ my $reg = int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4) * 4; # Anzahl moegliche 4er Registergruppen pro Lesevorgang
+ my $n = int(64 / $reg); # Anzahl Lesevorgänge (abgerundet)
+ foreach (0 .. ($n-1)) {
+ I2C_PCA9685_i2cread($hash, 6 + $_ * $reg, $reg);
+ }
+ I2C_PCA9685_i2cread($hash, 6 + $n * $reg, $reg - ($reg * ($n+1) - 64)) if (($n+1) * $reg) > 64;
-
- I2C_PCA9685_i2cread($hash, 0x6, 64);
+ } else {
+ I2C_PCA9685_i2cread($hash, 0x6, 64);
+ }
return;
-
- #my $name =$a[0];
- #my %sendpackage = ( i2caddress => $hash->{I2C_Address}, direction => "i2cread" );
- #$sendpackage{reg} = 0x6; #startadresse zum lesen
- #$sendpackage{nbyte} = 64;
- #return "$name: no IO device defined" unless ($hash->{IODev});
- #my $phash = $hash->{IODev};
- #my $pname = $phash->{NAME};
- #CallFn($pname, "I2CWrtFn", $phash, \%sendpackage);
-
}
#############################################################################
sub I2C_PCA9685_i2cread($$$) { # Lesebefehl an Hardware absetzen (antwort kommt in I2C_*****_I2CRec an)
@@ -404,21 +458,36 @@ sub I2C_PCA9685_i2cread($$$) { # Lesebefehl an Hardware absetzen (ant
}
#############################################################################
sub I2C_PCA9685_i2cwrite($$$) { # Schreibbefehl an Hardware absetzen
- my ($hash, $reg, @data) = @_;
+ my ($hash, $reg, $data) = @_;
if (defined (my $iodev = $hash->{IODev})) {
- Log3 $hash, 5, "$hash->{NAME}: $hash->{I2C_Address} write " . join (' ',@data) . " to Register $reg";
+ Log3 $hash, 5, "$hash->{NAME}: $hash->{I2C_Address} write " . $data . " to Register $reg";
CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
direction => "i2cwrite",
i2caddress => $hash->{I2C_Address},
reg => $reg,
- data => join (' ',@data),
+ data => $data,
});
+ unless ($hash->{IODev}->{TYPE} eq 'RPII2C') { #fuer FRM, etc. Register zurücklesen (bei RPII2C kommt bei erfolgreicher Uebertragung die Botschaft zurueck)
+ my $nbyte = () = $data =~ / /gi;
+ unless ($reg == 250) {
+ I2C_PCA9685_i2cread($hash, $reg, $nbyte + 1);
+ } else {
+ #I2C_PCA9685_UpdReadings($hash, $reg, $data);
+ my $reg = int( (defined($hash->{I2C_Buff})?$hash->{I2C_Buff}:30) / 4) * 4; # Anzahl moegliche 4er Registergruppen pro Lesevorgang
+ my $n = int(64 / $reg); # Anzahl Lesevorgänge (abgerundet)
+ foreach (0 .. ($n-1)) {
+ I2C_PCA9685_i2cread($hash, 6 + $_ * $reg, $reg);
+ }
+ I2C_PCA9685_i2cread($hash, 6 + $n * $reg, $reg - ($reg * ($n+1) - 64)) if (($n+1) * $reg) > 64;
+ }
+ }
} else {
if (AttrVal($hash->{NAME}, "dummy", 0) == 1) {
- I2C_PCA9685_UpdReadings($hash, $reg, @data); # Zeile zum testen (Werte werden direkt zu I2CRec umgeleitet)
+ I2C_PCA9685_UpdReadings($hash, $reg, $data); # Zeile zum testen (Werte werden direkt zu I2CRec umgeleitet)
} else {
return "no IODev assigned to '$hash->{NAME}'";
- } }
+ }
+ }
}
#############################################################################
sub I2C_PCA9685_I2CRec($@) { # vom IODev aufgerufen
@@ -433,7 +502,7 @@ sub I2C_PCA9685_I2CRec($@) { # vom IODev aufgerufen
if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
I2C_PCA9685_UpdReadings($hash, $clientmsg->{reg} , $clientmsg->{received});
readingsSingleUpdate($hash,"state", "Ok", 1);
- } elsif ( $clientmsg->{direction} eq "i2cwrite" && defined($clientmsg->{data}) ) { #readings aktualisieren wenn uebertragung ok
+ } elsif ( $clientmsg->{direction} eq "i2cwrite" && defined($clientmsg->{data}) ) { #readings aktualisieren wenn uebertragung ok (bei FRM kommt nix zurueck)
I2C_PCA9685_UpdReadings($hash, $clientmsg->{reg} , $clientmsg->{data});
readingsSingleUpdate($hash,"state", "Ok", 1);
@@ -480,7 +549,7 @@ sub I2C_PCA9685_CalcVal($@) { # Readings aus Registerwerten berechnen
sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Readings/Internals schreiben
my ($hash, $reg, $inh) = @_;
my $name = $hash->{NAME};
- #Log3 $hash, 1, "$name UpdReadings Start Register: " .sprintf("0x%.2X", $reg).", Inhalt: $inh";
+ Log3 $hash, 5, "$name Received from Register $reg: $inh"; #sprintf("0x%.2X", $reg)
my @reginh = split(" ", $inh);
my $dimstep = AttrVal($name, "dimstep", "1");
my $dimcount = AttrVal($name, "dimcount", "4095");
@@ -498,31 +567,27 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
($dimval, $delay) = I2C_PCA9685_CalcVal($dimcount, @reginh);
readingsBulkUpdate($hash, 'Port'.$port , $dimval) if (ReadingsVal($name, 'Port'.$port, "failure") ne $dimval); #nur wenn Wert geaendert
readingsBulkUpdate($hash, 'Port_d'.$port , $delay) if (defined $delay && ReadingsVal($name, 'Port_d'.$port, "failure") ne $delay); #nur wenn Wert geaendert
- Log3 $hash, 5, "$name: lese einen Port - Reg: $reg ; Inh: @reginh";
+ Log3 $hash, 5, "$name: lese einen Port - Reg: $reg, Inh: @reginh";
- } elsif ( $reg < 70 && $reg > 5 && @reginh > 4 ) { #Wenn alle Ports abgefragt werden
+ } elsif ( $reg < 70 && $reg > 5 && @reginh > 4 ) { #Wenn mehrere Ports abgefragt werden
for (my $i = 0; $i < @reginh; $i++) {
- next unless ( ($reg + $i - 2) / 4 =~ m/^\d+$/ );
+ next unless ( ($reg + $i - 2) / 4 =~ m/^\d+$/ && defined($reginh[$i + 3]) );
my @regpart = ( $reginh[$i], $reginh[$i + 1], $reginh[$i + 2], $reginh[$i + 3] );
my $port = sprintf ('%02d', ($reg + $i - 6) / 4);
($dimval, $delay) = I2C_PCA9685_CalcVal($dimcount, @regpart);
readingsBulkUpdate($hash, 'Port'.$port , $dimval) if (ReadingsVal($name, 'Port'.$port, "failure") ne $dimval); #nur wenn Wert geaendert
readingsBulkUpdate($hash, 'Port_d'.$port , $delay) if (defined $delay && ReadingsVal($name, 'Port_d'.$port, "failure") ne $delay); #nur wenn Wert geaendert
- Log3 $hash, 5, "$name: lese mehrere Ports - Reg: $reg ; i: $i; Inh: @regpart";
+ Log3 $hash, 5, "$name: lese mehrere Ports - Reg: $reg, i: $i; Inh: @regpart";
$i += 3;
}
} elsif ($reg == 254) { #wenn Frequenz Register
my $clock = AttrVal($name, "extClock", 25);
+ my $init = 1 unless defined($hash->{Frequency});
+ $hash->{confregs}{PRESCALE} = $inh;
$hash->{Frequency} = sprintf( "%.1f", $clock * 1000000 / (4096 * ($inh + 1)) ) . " Hz";
+ I2C_PCA9685_Init2($hash) if defined($init);
} elsif ( $reg >= 0 && $reg < 6 ) { #Konfigurations Register
- $hash->{confregs}{$reg} = $inh;
- #folgendes evtl noch weg
- #$hash->{CONF} = (defined $hash->{confregs}{0} ? sprintf('0x%.2X ', $hash->{confregs}{0}) : "0x__ ") .
- # (defined $hash->{confregs}{1} ? sprintf('0x%.2X ', $hash->{confregs}{1}) : "0x__ ") .
- # (defined $hash->{confregs}{2} ? sprintf('0x%.2X ', $hash->{confregs}{2}) : "0x__ ") .
- # (defined $hash->{confregs}{3} ? sprintf('0x%.2X ', $hash->{confregs}{3}) : "0x__ ") .
- # (defined $hash->{confregs}{4} ? sprintf('0x%.2X ', $hash->{confregs}{4}) : "0x__ ") .
- # (defined $hash->{confregs}{5} ? sprintf('0x%.2X ', $hash->{confregs}{5}) : "0x__ ");
+ $hash->{confregs}{$confregs{$reg}} = $inh;
}
readingsEndUpdate($hash, 1);
return;
@@ -546,16 +611,19 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Define
- define <name> I2C_PCA9685 <I2C Address>
+ define <name> I2C_PCA9685 <I2C Address> [<I2C Buffer Size>]
where <I2C Address>
can be written as decimal value or 0xnn
+ <I2C Buffer Size>
sets the maximum size of the I2C-Packet.
+ Without this option the packet size is 30 Bytes (32 incl. Address and Register number).
+ For RPII2C this option has no influence, cause it can deal with arbitrary packet sizes.
Set
- set <name> <port> <value> [<delay>]
+ set <name> <port> <dimvalue> [<delay>]
- where
<port>
is one of Port0 to Port15
- and <value>
one of
+ and <dimvalue>
one of
off
@@ -563,10 +631,13 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
0..4095
- <delay>
defines the switch on time inside the PWM counting loop. It does not have an influence to the duty cycle. Default value is 0 and, possible values are 0..4095
+ <delay>
defines the switch on time inside the PWM counting loop. It does not have an influence to the duty cycle.
+ Default value is 0 and, possible values are 0..4095
-
- It is also possible to change more than one port at the same time with comma separated values.
+ It is also possible to change more than one port at the same time. Just separate them by comma.
+ If only the last of the comma separated ports has dimvalue (and delay), all ports will set to the same values.
+ Sequently ports will set at once (useful for multi color LED's).
Also P instead of Port is Possible.
@@ -574,7 +645,7 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Examples:
set mod1 Port04 543
- set mod1 Port14 434 765
+ set mod1 Port4 434 765
set mod1 Port1, Port14 434 765
set mod1 Port1 on, P14 434 765
@@ -592,10 +663,10 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Attributes
- - subadr1,subadr2,subadr3,allcalladr
+ - SUBADR1,SUBADR2,SUBADR3,ALLCALLADR
Alternative slave addresses, if you want to control more than one PCA9685 with one define
- Respective flag in modreg1 must be set as well
- Default: subadr1=113,subadr2=114,subadr3=116,allcalladr=112, valid values: valid I2C Address
+ Respective flag in modereg1 must be set as well
+ Default: SUBADR1=113,SUBADR2=114,SUBADR3=116,ALLCALLADR=112, valid values: valid I2C Address
- OnStartup
Comma separated list of output ports/PWM registers and their desired state after start
@@ -603,30 +674,33 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Default: -, valid values: <port>=on|off|0..4095|last where <port> = 0 - 15
- prescale
- Sets PWM Frequency. The Formula is: Fx = 25MHz/(4096 * (prescale + 1)) The corresponding frequency value is shown under internals (valid for the internal 25MHz clock).
- Default: 30 (200Hz), valid values: 0-255
+ Sets PWM Frequency. The Formula is: Fx = 25MHz/(4096 * (prescale + 1)).
+ The corresponding frequency value is shown under internals.
+ If provided, attribute extClock will be used for frequency calculation. Otherwise 25MHz
+ Default: 30 (200Hz for 25MHz clock), valid values: 0-255
- - modreg1
+ - modereg1
Comma separated list of:
- EXTCLK
- If set the an external connected clock will be used instead of the internal 25MHz oscillator
+ If set the an external connected clock will be used instead of the internal 25MHz oscillator.
+ Use the attribute extClock to provide the external oscillater value.
- - SUB1
- If set the PCA9685 responds to I2C-bus subaddress 1.
+ - SUBADR1
+ If set the PCA9685 responds to I2C-bus SUBADR 1.
- - SUB2
- If set the PCA9685 responds to I2C-bus subaddress 2.
+ - SUBADR2
+ If set the PCA9685 responds to I2C-bus SUBADR 2.
- - SUB3
- If set the PCA9685 responds to I2C-bus subaddress 3.
+ - SUBADR3
+ If set the PCA9685 responds to I2C-bus SUBADR 3.
- - ALLCALL
- If set the PCA9685 responds to I2C-bus allcall address.
+ - ALLCALLADR
+ If set the PCA9685 responds to I2C-bus ALLCALLADR address.
- - modreg2
+ - modereg2
Comma separated list of:
- INVRT
@@ -678,16 +752,18 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Define
- define <name> I2C_PCA9685 <I2C Address>
+ define <name> I2C_PCA9685 <I2C Address> [<I2C Buffer Size>]
Der Wert <I2C Address>
ist ein zweistelliger Hex-Wert im Format 0xnn oder eine Dezimalzahl
+ <I2C Buffer Size>
gibt die maximale Anzahl von Datenbytes pro I2C Datenpaket an. Nicht angegeben, wird der Wert 30 verwendet
+ ( entspricht 32 Bytes incl. Adresse und Registernummer). RPII2C kann mit beliebig großen Paketlängen umgehen, daher ist diese Option dort inaktiv.
Set
- set <name> <port> <value> [<delay>]
+ set <name> <port> <dimvalue> [<delay>]
- Als
<port>
kann Port00 bis Port15 verwendet werden
- <value>
kann folgende Werte annehmen:
+ <dimvalue>
kann folgende Werte annehmen:
off
@@ -695,11 +771,15 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
0..4095
- <delay>
gibt den Wert innerhalb der Zählschleife an, an dem der Ausgang eingeschaltet wird. Damit lassen sich die 16 Ausgänge zu unterschiedlichen Zeiten einschalten um Stromspitzen zu minimieren.
+ <delay>
gibt den Wert innerhalb der Zählschleife an, an dem der Ausgang eingeschaltet wird.
+ Damit lassen sich die 16 Ausgänge zu unterschiedlichen Zeiten einschalten um Stromspitzen zu minimieren.
Dieser Wert hat keinerlei Einfluss auf die Pulsbreite. Stardartwert ist 0, mögliche Werte sind 0..4095
-
- Um mehrer Ports mit einem Befehl zu ändern können mehrere Befehle per Komma getrennt eingegeben werden.
+ Um mehrer Ports mit einem Befehl zu ändern können mehrere Befehle per Komma getrennt eingegeben werden.
+ Dabei kann jeder Port auf einen separaten, oder alle Ports auf den selben Wert gesettz werden.
+ Fär letzteres darf nur der letzte Befehl dimvalue (und delay) enthalten.
+ Aufeinanerfolgene Ports werden mit einem Befehl geschrieben. So können beispielsweise multicolor LED's ohne flackern geschaltet werden.
Anstelle von Port kann auch einfach ein P verwendet werden.
@@ -707,8 +787,8 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Examples:
set mod1 Port04 543
- set mod1 Port14 434 765
- set mod1 Port1, Port14 434 765
+ set mod1 Port4 434 765
+ set mod1 Port1, Port2, Port14 434 765
set mod1 Port1 on, P14 434 765
@@ -725,49 +805,52 @@ sub I2C_PCA9685_UpdReadings($$$) { # vom IODev gesendete Werte in Read
Attribute
- - subadr1,subadr2,subadr3,allcalladr
- Alternative slave Adressen, if you want to control more than one PCA9685 with one define
- Zusätzlich zu diesen Registern müssen die Passenden Bits in modreg1 gesetzt werden.
- Standard: subadr1=113,subadr2=114,subadr3=116,allcalladr=112, gültige Werte: I2C Adresse
+ - SUBADR1,SUBADR2,SUBADR3,ALLCALLADR
+ Alternative slave Adressen, zum kontrollieren mehrerer PCA9685 mit einem define
+ Zusätzlich zu diesen Registern müssen die Passenden Bits in modereg1 gesetzt werden.
+ Standard: SUBADR1=113,SUBADR2=114,SUBADR3=116,ALLCALLADR=112, gültige Werte: I2C Adresse
- OnStartup
- Comma separated list of output ports/PWM registers and their desired state after start
- Without this atribut all output ports will set to last state
+ Kommagetrennte Liste der Ports mit den gewünschten Startwerten.
+ Nicht gelistete Ports werden auf en letzte state wiederhergestellt.
Standard: last, gültige Werte: <port>=on|off|0..4095|last wobei <port> = 0 - 15
- prescale
- Sets PWM Frequency. The Formula is: Fx = 25MHz/(4096 * (prescale + 1)) The corresponding frequency value is shown under internals (valid for the internal 25MHz clock).
- Standard: 30 (200Hz), gültige Werte: 0-255
+ PWM Frequenz setzen. Formel: Fx = 25MHz/(4096 * (prescale + 1)).
+ Die eingestellte Frequenz wird in den Internals angezeigt.
+ Wenn das Attribut extclock angegeben ist, wird dieses zur Frequenzberechnung verwendet. Andernfalls 25MHz.
+ Standard: 30 (200Hz für 25MHz clock), gültige Werte: 0-255
- - modreg1
+ - modereg1
Durch Komma getrennte Liste von:
- EXTCLK
Anstelle des internen 25MHz Oszillators wird ein extern Angeschlossener verwendet.
+ Die Frequenz des externen Oszillators kann über das Attribut extclock angegeben werden.
- - SUB1
+ - SUBADR1
Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Subadresse 1.
- - SUB2
+ - SUBADR2
Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Subadresse 2.
- - SUB3
+ - SUBADR3
Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Subadresse 3.
- - ALLCALL
- Wenn gesetzt, antwortet der PCA9685 auf I2C-bus Allcall Adresse.
+ - ALLCALLADR
+ Wenn gesetzt, antwortet der PCA9685 auf I2C-bus ALLCALLADR Adresse.
- - modreg2
+ - modereg2
Durch Komma getrennte Liste von:
- INVRT
Wenn gesetzt, werden die Ausgänge invertiert.
- OCH
- If set the outputs changes on ACK (after every byte sent).
- Otherwise the output changes on STOP command (bus write action finished)
+ Wenn gesetzt, werden die Ports nach jedem ACK gesetzt (also nach jedem gesendeten Byte).
+ Andernfalls werden sie nach einem STOP Kommando gesetzt (Bus Schreibaktion fertig, also nach einem Datenpaket)
- OUTDRV
Wenn gesetzt, werden die Ausgänge als totem pole konfiguriert.
diff --git a/fhem/FHEM/52_I2C_SHT21.pm b/fhem/FHEM/52_I2C_SHT21.pm
index 99813fe34..2b2ca590c 100644
--- a/fhem/FHEM/52_I2C_SHT21.pm
+++ b/fhem/FHEM/52_I2C_SHT21.pm
@@ -109,16 +109,19 @@ sub I2C_SHT21_Attr (@) {# hier noch Werteueberpruefung einfuegen
my $hash = $defs{$name};
my $msg = '';
if ($command && $command eq "set" && $attr && $attr eq "IODev") {
- if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $val)) {
- main::AssignIoPort($hash,$val);
- my @def = split (' ',$hash->{DEF});
- I2C_SHT21_Init($hash,\@def) if (defined ($hash->{IODev}));
- }
+ eval {
+ if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $val)) {
+ main::AssignIoPort($hash,$val);
+ my @def = split (' ',$hash->{DEF});
+ I2C_SHT21_Init($hash,\@def) if (defined ($hash->{IODev}));
+ }
+ };
+ return I2C_SHT21_Catch($@) if $@;
}
if ($attr eq 'poll_interval') {
if ($val > 0) {
RemoveInternalTimer($hash);
- InternalTimer(1, 'I2C_SHT21_Poll', $hash, 0);
+ InternalTimer(gettimeofday() + 5, 'I2C_SHT21_Poll', $hash, 0);
} else {
$msg = 'Wrong poll intervall defined. poll_interval must be a number > 0';
}
diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt
index 6a43c9755..bad5c9edb 100644
--- a/fhem/MAINTAINER.txt
+++ b/fhem/MAINTAINER.txt
@@ -185,6 +185,7 @@ FHEM/51_RPI_GPIO.pm klausw http://forum.fhem.de Einplatin
FHEM/52_I2C_DS1307 ntruchsess http://forum.fhem.de Sonstige Systeme
FHEM/52_I2C_EEPROM.pm klausw http://forum.fhem.de Sonstige Systeme
FHEM/52_I2C_LCD ntruchsess http://forum.fhem.de Sonstige Systeme
+FHEM/52_I2C_BME280 klausw http://forum.fhem.de Sonstige Systeme
FHEM/52_I2C_MCP23008 klausw http://forum.fhem.de Sonstige Systeme
FHEM/52_I2C_MCP23017 klausw http://forum.fhem.de Sonstige Systeme
FHEM/52_I2C_MCP342x klausw http://forum.fhem.de Sonstige Systeme