I2C_TSL2561 [devicename] address';
+ } elsif ((@a == 3)) {
+ $address = lc($a[2]);
+ } else {
+ $address = lc($a[3]);
+ if ($libcheck_hasHiPi) {
+ $hash->{HiPi_used} = 1;
+ } else {
+ $msg = '$name error: HiPi library not installed';
+ }
}
-
- # create default attributes
- $msg = CommandAttr(undef, $name . ' poll_interval 5');
- #$msg = CommandAttr(undef, $name . ' gain 1');
- #$msg = CommandAttr(undef, $name . ' integrationTime 13');
-
if ($msg) {
- Log (1, $msg);
+ Log3 ($hash, 1, $msg);
+ return $msg;
+ }
+
+ $address = $validAdresses{$address};
+ if (defined($address)) {
+ $hash->{I2C_Address} = hex($address);
+ } else {
+ $msg = "Wrong address $address, must be one of 0x29, 0x39, 0x49";
+ Log3 ($hash, 1, $msg);
return $msg;
}
- # check for existing i2c device
- my $i2cModulesLoaded = 0;
- $i2cModulesLoaded = 1 if -e $dev;
-
- if ($i2cModulesLoaded) {
- if (-r $dev && -w $dev) {
- $hash->{devTSL2561} = HiPi::Device::I2C->new(
- devicename => $dev,
- address => hex($address),
- busmode => 'i2c',
- );
- Log3 $name, 3, "I2C_TSL2561_Define device created";
-
- # Make sure we're actually connected
-
- my $sensorId = I2C_TSL2561_ReadByte($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID);
- if ( !($sensorId & 0b00010000) ) {
- return $name . ': Error! I2C failure: Please check your i2c bus ' . $dev . ' and the connected device address: ' . $address;
- }
- my $package = '';
- $hash->{tsl2561Package} = $sensorId >> 4;
- if ($hash->{tsl2561Package} == TSL2561_PACKAGE_CS) {
- $package = 'CS';
- } else {
- $package = 'T/FN/CL';
- }
- $hash->{sensorType} = 'TSL2561 Package' . $package . ' Rev. ' . ( $sensorId & 0x0f );
-
- Log3 $name, 5, 'sensorId ' . $hash->{sensorType};
-
- $hash->{tsl2561IntegrationTime} = TSL2561_INTEGRATIONTIME_13MS;
- $hash->{tsl2561Gain} = TSL2561_GAIN_1X;
-
- I2C_TSL2561_SetIntegrationTime($hash,TSL2561_INTEGRATIONTIME_13MS);
- I2C_TSL2561_SetGain($hash, TSL2561_GAIN_1X);
- readingsSingleUpdate($hash, 'state', 'Initialized',1);
- } else {
- my @groups = split '\s', $(;
- return "$name :Error! $dev isn't readable/writable by user " . getpwuid( $< ) . " or group(s) " .
- getgrgid($_) . " " foreach(@groups);
+ # create default attributes
+ if (AttrVal($name, 'poll_interval', '?') eq '?') {
+ $msg = CommandAttr(undef, $name . ' poll_interval 5');
+ if ($msg) {
+ Log (1, $msg);
+ return $msg;
+ }
+ }
+ if (AttrVal($name, 'floatArithmetics', '?') eq '?') {
+ $msg = CommandAttr(undef, $name . ' floatArithmetics 1');
+ if ($msg) {
+ Log (1, $msg);
+ return $msg;
}
-
- } else {
- return $name . ': Error! I2C device not found: ' . $dev . '. Please check that these kernelmodules are loaded: i2c_bcm2708, i2c_dev';
}
- Log3 $name, 5, "I2C_TSL2561_Define end";
+ # preset internal readings
+ if (!defined($hash->{tsl2561IntegrationTime})) {
+ my $attrVal = AttrVal($name, 'integrationTime', 13);
+ $hash->{tsl2561IntegrationTime} = $attrVal == 402? TSL2561_INTEGRATIONTIME_402MS : $attrVal == 101? TSL2561_INTEGRATIONTIME_101MS : TSL2561_INTEGRATIONTIME_13MS;
+ }
+ if (!defined($hash->{tsl2561Gain})) {
+ my $attrVal = AttrVal($name, 'gain', 1);
+ $hash->{tsl2561Gain} = $attrVal == 16? TSL2561_GAIN_16X : TSL2561_GAIN_1X;
+ }
+ if (!defined($hash->{tsl2561AutoGain})) {
+ $hash->{tsl2561AutoGain} = AttrVal($name, 'autoGain', 1);
+ }
+
+ readingsSingleUpdate($hash, 'state', 'Defined', 1);
+
+ eval {
+ I2C_TSL2561_Init($hash, [ @a[ 2 .. scalar(@a) - 1 ] ] );
+ };
+ Log3 ($hash, 1, $hash->{NAME} . ': ' . I2C_TSL2561_Catch($@)) if $@;;
+
+ Log3 $name, 5, "I2C_TSL2561_Define end";
+ return undef;
+}
+
+sub I2C_TSL2561_Init($$) {
+ my ($hash, $args) = @_;
+ my $name = $hash->{NAME};
+
+ if ($hash->{HiPi_used}) {
+ # check for existing i2c device
+ my $i2cModulesLoaded = 0;
+ my $dev = shift @$args;
+ $i2cModulesLoaded = 1 if -e $dev;
+ if ($i2cModulesLoaded) {
+ if (-r $dev && -w $dev) {
+ $hash->{devTSL2561} = HiPi::Device::I2C->new(
+ devicename => $dev,
+ address => $hash->{I2C_Address},
+ busmode => 'i2c',
+ );
+ Log3 $name, 3, "I2C_TSL2561_Define device created";
+ } else {
+ my @groups = split '\s', $(;
+ return "$name :Error! $dev isn't readable/writable by user " . getpwuid( $< ) . " or group(s) " .
+ getgrgid($_) . " " foreach(@groups);
+ }
+ } else {
+ return $name . ': Error! I2C device not found: ' . $dev . '. Please check that these kernelmodules are loaded: i2c_bcm2708, i2c_dev';
+ }
+ } else {
+ AssignIoPort($hash);
+ }
+
+ readingsSingleUpdate($hash, 'state', 'Initialized', 1);
+
+ return undef;
+}
+
+sub I2C_TSL2561_Catch($) {
+ my $exception = shift;
+ if ($exception) {
+ $exception =~ /^(.*)( at.*FHEM.*)$/;
+ return $1;
+ }
return undef;
}
@@ -367,17 +435,17 @@ sub I2C_TSL2561_Attr (@) {
my $hash = $defs{$name};
my $msg = '';
- Log3 $name, 5, "I2C_TSL2561_Attr: attr " . $attr . " val " . $val;
+ Log3 $name, 5, "I2C_TSL2561_Attr: attr " . $attr . " val " . defined($val)? $val : "undef";
if ($attr eq 'poll_interval') {
my $pollInterval = (defined($val) && looks_like_number($val) && $val > 0) ? $val : 0;
if ($val > 0) {
RemoveInternalTimer($hash);
InternalTimer(1, 'I2C_TSL2561_Poll', $hash, 0);
- } else {
+ } elsif (defined($val)) {
$msg = 'Wrong poll intervall defined. poll_interval must be a number > 0';
}
- } elsif ($attr eq 'gain') {
+ } elsif ($attr eq 'gain') {
my $gain = (defined($val) && looks_like_number($val) && $val > 0) ? $val : 0;
Log3 $name, 5, "attr gain is" . $gain;
@@ -385,7 +453,7 @@ sub I2C_TSL2561_Attr (@) {
I2C_TSL2561_SetGain($hash, TSL2561_GAIN_1X);
} elsif ($gain == 16) {
I2C_TSL2561_SetGain($hash, TSL2561_GAIN_16X);
- } else {
+ } elsif (defined($val)) {
$msg = 'Wrong gain defined. must be 1 or 16';
}
} elsif ($attr eq 'integrationTime') {
@@ -397,13 +465,18 @@ sub I2C_TSL2561_Attr (@) {
I2C_TSL2561_SetIntegrationTime($hash, TSL2561_INTEGRATIONTIME_101MS);
} elsif ($time == 402) {
I2C_TSL2561_SetIntegrationTime($hash, TSL2561_INTEGRATIONTIME_402MS);
- } else {
+ } elsif (defined($val)) {
$msg = 'Wrong integrationTime defined. must be 13 or 101 or 402';
}
} elsif ($attr eq 'autoGain') {
my $autoGain = (defined($val) && looks_like_number($val) && $val > 0) ? $val : 0;
$hash->{tsl2561AutoGain} = $autoGain;
+ if (!$autoGain) {
+ I2C_TSL2561_Attr($hash, $name, 'gain', AttrVal($name, 'gain', 1));
+ }
+ } elsif ($attr eq 'floatArithmetics') {
+ my $floatArithmetics = (defined($val) && looks_like_number($val) && $val > 0) ? $val : 0;
}
return ($msg) ? $msg : undef;
@@ -422,10 +495,12 @@ sub I2C_TSL2561_Poll($) {
my ($hash) = @_;
my $name = $hash->{NAME};
- # Read values
+ # Read new values
I2C_TSL2561_Get($hash);
+ # Schedule next polling
my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0);
+ Log3 $name, 5, "I2C_TSL2561_Poll: $pollInterval min";
if ($pollInterval > 0) {
InternalTimer(gettimeofday() + ($pollInterval * 60), 'I2C_TSL2561_Poll', $hash, 0);
}
@@ -444,16 +519,32 @@ sub I2C_TSL2561_Poll($) {
sub I2C_TSL2561_Get($) {
my ( $hash ) = @_;
my $name = $hash->{NAME};
-
- my $lux = I2C_TSL2561_CalculateLux($hash);
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash,"luminosity",$lux);
- readingsBulkUpdate($hash,"broadband",$hash->{broadband});
- readingsBulkUpdate($hash,"ir",$hash->{ir});
- readingsEndUpdate($hash,1);
+
+ Log3 $name, 5, "I2C_TSL2561_Get start";
+
+ my $state = ReadingsVal($name, 'state', '');
+ if ($state eq 'Error') {
+ # try to turn off the device to check I2C communication (hotplug and error recovery)
+ if (I2C_TSL2561_Disable($hash)) {
+ $state = 'Initialized';
+ readingsSingleUpdate($hash, 'state', $state, 1);
+ }
+ }
+ if ($state ne 'Error') {
+ # read from TSL2561 and calculate luminosity
+ my $lux = I2C_TSL2561_CalculateLux($hash);
+ $state = ReadingsVal($name, 'state', '');
+ if ($state eq 'Initialized') {
+ my $chScale = I2C_TSL2561_GetChannelScale($hash);
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash, "broadband", ceil($chScale*$hash->{broadband}));
+ readingsBulkUpdate($hash, "ir", ceil($chScale*$hash->{ir}));
+ readingsBulkUpdate($hash, "luminosity", $lux);
+ readingsEndUpdate($hash, 1);
+ }
+ }
#readingsSingleUpdate($hash,"failures",ReadingsVal($hash->{NAME},"failures",0)+1,1);
-
}
=head2 I2C_TSL2561_Set
@@ -496,72 +587,125 @@ sub I2C_TSL2561_Undef($$) {
my ($hash, $arg) = @_;
RemoveInternalTimer($hash);
- $hash->{devTSL2561}->close( ).
+ if ($hash->{HiPi_used}) {
+ $hash->{devTSL2561}->close()
+ }
+
return undef;
}
-=head2 I2C_TSL2561_ReadWord
- Title: I2C_TSL2561_ReadWord
- Function: Read 2 bytes from i2c device from given register.
- Returns: number
- Args: named arguments:
- -argument1 => hash: $hash hash of device
- -argument2 => number: $register
-
-=cut
-
-sub I2C_TSL2561_ReadWord($$) {
- my ($hash, $register) = @_;
+sub I2C_TSL2561_I2CRcvControl($$) {
+ my ($hash, $control) = @_;
my $name = $hash->{NAME};
- my $retVal = undef;
-
- try {
- my @values = $hash->{devTSL2561}->bus_read($register, 2);
-
- $retVal = $values[0] | $values[1] << 8;
-
- } catch Error with {
- Log3 $name, 1, 'ERROR: I2C_TSL2561_ReadWord: i2c-bus_read failure';
- };
+ my $enabled = $control & 0x3;
+ if ($enabled == TSL2561_CONTROL_POWERON) {
+ Log3 $name, 5, "I2C_TSL2561_Enable: is enabled";
+ $hash->{sensorEnabled} = 1;
+ } else {
+ Log3 $name, 5, "I2C_TSL2561_Enable: is not enabled";
+ readingsSingleUpdate($hash, 'state', 'Error', 1);
+ $hash->{sensorEnabled} = 0;
+ }
- return $retVal;
}
-=head2 I2C_TSL2561_ReadByte
- Title: I2C_TSL2561_ReadByte
- Function: Read 1 byte from i2c device from given register.
- Returns: number
- Args: named arguments:
- -argument1 => hash: $hash hash of device
- -argument2 => number: $register
-
-=cut
-
-sub I2C_TSL2561_ReadByte($$) {
- my ($hash, $register) = @_;
+sub I2C_TSL2561_I2CRcvID($$) {
+ my ($hash, $sensorId) = @_;
my $name = $hash->{NAME};
- my $retVal = undef;
-
- try {
- Log3 $name, 5,'I2C_TSL2561_ReadByte: start ';
- my @bytes = $hash->{devTSL2561}->bus_read($register, 1);
- $retVal = $bytes[0];
-
- Log3 $name, 5, 'I2C_TSL2561_ReadByte: ' . $retVal;
- } catch Error with {
- Log3 $name, 1, 'ERROR: I2C_TSL2561_ReadByte: i2c-bus_read failure';
- };
+ if ( !($sensorId & 0b00010000) ) {
+ return $name . ': Error! I2C failure: Please check your i2c bus and the connected device address: ' . $hash->{I2C_Address};
+ }
- return $retVal;
+ my $package = '';
+ $hash->{tsl2561Package} = $sensorId >> 4;
+ if ($hash->{tsl2561Package} == TSL2561_PACKAGE_CS) {
+ $package = 'CS';
+ } else {
+ $package = 'T/FN/CL';
+ }
+ $hash->{sensorType} = 'TSL2561 Package ' . $package . ' Rev. ' . ( $sensorId & 0x0f );
+
+ Log3 $name, 5, 'sensorId ' . $hash->{sensorType};
}
+sub I2C_TSL2561_I2CRcvTiming ($$) {
+ my ($hash, $timing) = @_;
+
+ $hash->{tsl2561IntegrationTime} = $timing & 0x03;
+ $hash->{tsl2561Gain} = $timing & 0x10;
+
+ my $name = $hash->{NAME};
+ Log3 $name, 5, "I2C_TSL2561_I2CRcvTiming: $timing, $hash->{tsl2561IntegrationTime}, $hash->{tsl2561Gain}";
+}
+
+sub I2C_TSL2561_I2CRcvChan0 ($$) {
+ my ($hash, $broadband) = @_;
+
+ my $name = $hash->{NAME};
+ Log3 $name, 5, 'I2C_TSL2561_I2CRcvChan0 ' . $broadband;
+
+ $hash->{broadband} = $broadband;
+}
+
+sub I2C_TSL2561_I2CRcvChan1 ($$) {
+ my ($hash, $ir) = @_;
+
+ my $name = $hash->{NAME};
+ Log3 $name, 5, 'I2C_TSL2561_I2CRcvChan1 ' . $ir;
+
+ $hash->{ir} = $ir;
+}
+
+sub I2C_TSL2561_I2CRec ($$) {
+ my ($hash, $clientmsg) = @_;
+ my $name = $hash->{NAME};
+
+ my $pname = undef;
+ unless ($hash->{HiPi_used}) { #nicht nutzen wenn HiPi Bibliothek in Benutzung
+ my $phash = $hash->{IODev};
+ $pname = $phash->{NAME};
+ while (my ( $k, $v ) = each %$clientmsg) { #erzeugen von Internals für alle Keys in $clientmsg die mit dem physical Namen beginnen
+ $hash->{$k} = $v if $k =~ /^$pname/;
+ }
+ }
+
+ if ($clientmsg->{direction} && $clientmsg->{reg} &&
+ (($pname && $clientmsg->{$pname . "_SENDSTAT"} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok")
+ || $hash->{HiPi_used})) {
+ if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received})) {
+ my $register = $clientmsg->{reg} & 0xF;
+ Log3 $hash, 5, "$name RX register $register, $clientmsg->{nbyte} byte: $clientmsg->{received}";
+ my $byte = undef;
+ my $word = undef;
+ my @raw = split(" ", $clientmsg->{received});
+ if ($clientmsg->{nbyte} == 1) {
+ $byte = $raw[0];
+ } elsif ($clientmsg->{nbyte} == 2) {
+ $word = $raw[1] << 8 | $raw[0];
+ }
+ if ($register == TSL2561_REGISTER_CONTROL) {
+ I2C_TSL2561_I2CRcvControl($hash, $byte);
+ } elsif ($register == TSL2561_REGISTER_ID) {
+ I2C_TSL2561_I2CRcvID($hash, $byte);
+ } elsif ($register == TSL2561_REGISTER_TIMING) {
+ I2C_TSL2561_I2CRcvTiming($hash, $byte);
+ } elsif ($register == TSL2561_REGISTER_CHAN0_LOW) {
+ I2C_TSL2561_I2CRcvChan0($hash, $word);
+ } elsif ($register == TSL2561_REGISTER_CHAN1_LOW) {
+ I2C_TSL2561_I2CRcvChan1($hash, $word);
+ } else {
+ Log3 $name, 3, "I2C_TSL2561_I2CRec unsupported register $register";
+ }
+ }
+ }
+}
=head2 I2C_TSL2561_Enable
Title: I2C_TSL2561_Enable
Function: Enables the device
- Returns: -
+ Returns: 1 if sensor was enabled, 0 if enabling sensor failed
Args: named arguments:
-argument1 => hash: $hash hash of device
@@ -570,29 +714,33 @@ sub I2C_TSL2561_ReadByte($$) {
sub I2C_TSL2561_Enable($) {
my ($hash) = @_;
my $name = $hash->{NAME};
- my $enabled = 0;
Log3 $name, 5, 'I2C_TSL2561_Enable: start ';
- try {
- $hash->{devTSL2561}->bus_write( TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON );
- $enabled = I2C_TSL2561_ReadByte( $hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL);
- if ($enabled == TSL2561_CONTROL_POWERON) {
- Log3 $name, 5, "I2C_TSL2561_Enable: is enabled";
- } else {
- Log3 $name, 5, "I2C_TSL2561_Enable: is not enabled";
- readingsSingleUpdate($hash, 'state', 'Error',1);
+
+ # Detect TLS2561 package type and init integration time and gain
+ if (!defined($hash->{tsl2561Package})) {
+ # Get TLS2561 package type
+ if (I2C_TSL2561_i2cread($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID, 1)) {
+ # Preset integration time and gain
+ I2C_TSL2561_SetGain($hash, $hash->{tsl2561Gain});
}
- } catch Error with {
- Log3 $name, 1, 'ERROR: I2C_TSL2561_Enable: i2c-bus_write failure';
- };
+ }
+
+ # Enable TLS2561
+ $hash->{sensorEnabled} = 0;
+ if (I2C_TSL2561_i2cwrite($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON)) {
+ I2C_TSL2561_i2cread($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, 1);
+ }
+
Log3 $name, 5, 'I2C_TSL2561_Enable: end ';
- return $enabled;
+
+ return $hash->{sensorEnabled};
}
=head2 I2C_TSL2561_Disable
Title: I2C_TSL2561_Disable
Function: Enables the device
- Returns: -
+ Returns: 1 if write was successful, 0 if write failed
Args: named arguments:
-argument1 => hash: $hash hash of device
@@ -601,15 +749,13 @@ sub I2C_TSL2561_Enable($) {
sub I2C_TSL2561_Disable($) {
my ($hash) = @_;
my $name = $hash->{NAME};
-
Log3 $name, 5, 'I2C_TSL2561_Disable: start ';
- try {
- $hash->{devTSL2561}->bus_write( (TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF) );
- } catch Error with {
- Log (1, $name . ': ERROR: I2C_TSL2561_Disable: i2c-bus_write failure');
- }
+ my $success = I2C_TSL2561_i2cwrite($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF);
+ $hash->{sensorEnabled} = 0;
Log3 $name, 5, 'I2C_TSL2561_Disable: end ';
+
+ return $success;
}
=head2 I2C_TSL2561_GetData
@@ -626,25 +772,27 @@ sub I2C_TSL2561_GetData($) {
my $name = $hash->{NAME};
# Enable the device by setting the control bit to 0x03
- I2C_TSL2561_Enable( $hash );
+ if (I2C_TSL2561_Enable($hash)) {
- # Wait x ms for ADC to complete
- if ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
- usleep(14000); # 14ms
- } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
- usleep(102000); # 102ms
- } else {
- usleep(403000); # 403ms
+ # Wait x ms for ADC to complete
+ if ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
+ usleep(14000); # 14ms
+ } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
+ usleep(102000); # 102ms
+ } else {
+ usleep(403000); # 403ms
+ }
+
+ # Reads a two byte value from channel 0 (visible + infrared)
+ if (I2C_TSL2561_i2cread($hash, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW, 2)) {
+
+ # Reads a two byte value from channel 1 (infrared)
+ I2C_TSL2561_i2cread($hash, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW, 2);
+ }
}
- # Reads a two byte value from channel 0 (visible + infrared)
- $hash->{broadband} = I2C_TSL2561_ReadWord($hash, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW);
-
- # Reads a two byte value from channel 1 (infrared)
- $hash->{ir} = I2C_TSL2561_ReadWord($hash, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW);
-
- # Turn the device off to save power
- I2C_TSL2561_Disable( $hash );
+ # Turn the device off to save power
+ I2C_TSL2561_Disable($hash);
}
=head2 I2C_TSL2561_SetIntegrationTime
@@ -662,21 +810,18 @@ sub I2C_TSL2561_SetIntegrationTime($$) {
my $name = $hash->{NAME};
# Enable the device by setting the control bit to 0x03
- I2C_TSL2561_Enable( $hash );
+ if (I2C_TSL2561_Enable($hash)) {
- #try {
- # Update the timing register
- Log3 $name, 5, "I2C_TSL2561_SetIntegrationTime: time is " . $time ;
- Log3 $name, 5, "I2C_TSL2561_SetIntegrationTime: gain is " . $hash->{tsl2561Gain};
- $hash->{devTSL2561}->bus_write( (TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, $time | $hash->{tsl2561Gain}) );
- #} catch Error with {
- # Log3 $name, 1, 'ERROR: I2C_TSL2561_SetIntegrationTime: i2c-bus_write failure';
- #}
- # Update value placeholders
- $hash->{tsl2561IntegrationTime} = $time;
-
- # Turn the device off to save power
- I2C_TSL2561_Disable( $hash );
+ # Update the timing register
+ Log3 $name, 5, "I2C_TSL2561_SetIntegrationTime: time " . $time ;
+ Log3 $name, 5, "I2C_TSL2561_SetIntegrationTime: gain " . $hash->{tsl2561Gain};
+ if (I2C_TSL2561_i2cwrite($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, $time | $hash->{tsl2561Gain})) {
+ I2C_TSL2561_i2cread($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, 1);
+ }
+ }
+
+ # Turn the device off to save power
+ I2C_TSL2561_Disable($hash);
}
=head2 I2C_TSL2561_SetGain
@@ -692,29 +837,19 @@ sub I2C_TSL2561_SetIntegrationTime($$) {
sub I2C_TSL2561_SetGain($$) {
my ($hash, $gain) = @_;
my $name = $hash->{NAME};
- my $timing = 0;
-
- # Enable the device by setting the control bit to 0x03
- I2C_TSL2561_Enable( $hash );
- #try {
- Log3 $name, 5, 'I2C_TSL2561_SetGain: gain is ' . $gain;
- Log3 $name, 5, 'I2C_TSL2561_SetGain: time is ' . $hash->{tsl2561IntegrationTime};
- $timing = $gain | $hash->{tsl2561IntegrationTime};
- Log3 $name, 5, ' I2C_TSL2561_SetGain: timing is ' . sprintf("%x", $timing);
- # Update the timing register
- my $ret = $hash->{devTSL2561}->bus_write( (TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, $timing) );
- Log3 $name, 5, "I2C_TSL2561_SetGain: return from write is " . sprintf("%x", $ret);
- $ret = I2C_TSL2561_ReadByte($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING );
- Log3 $name, 5, "I2C_TSL2561_SetGain: register read is " . sprintf("%x", $ret);
- #} catch Error with {
- # Log3 $name, 1,'ERROR: I2C_TSL2561_SetGain: i2c-bus_write failure';
- #}
- # Update value placeholders
- $hash->{tsl2561Gain} = $gain;
-
- # Turn the device off to save power
- I2C_TSL2561_Disable( $hash );
+ # Enable the device by setting the control bit to 0x03
+ if (I2C_TSL2561_Enable($hash)) {
+ # Update the timing register
+ Log3 $name, 5, "I2C_TSL2561_SetGain: gain " . $gain ;
+ Log3 $name, 5, "I2C_TSL2561_SetGain: time " . $hash->{tsl2561IntegrationTime};
+ if (I2C_TSL2561_i2cwrite($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, $gain | $hash->{tsl2561IntegrationTime})) {
+ I2C_TSL2561_i2cread($hash, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, 1);
+ }
+ }
+
+ # Turn the device off to save power
+ I2C_TSL2561_Disable($hash);
}
=head2 I2C_TSL2561_GetLuminosity
@@ -730,65 +865,106 @@ sub I2C_TSL2561_GetLuminosity($) {
my ($hash) = @_;
my $name = $hash->{NAME};
- my $valid = 0;
-
- # If Auto gain disabled get a single reading and continue
- if ($hash->{tsl2561AutoGain}) {
+ # If Auto gain disabled get a single reading and continue
+ if (!$hash->{tsl2561AutoGain}) {
I2C_TSL2561_GetData($hash);
return;
}
+
+ # Read data until we find a valid range
+ my $agcCheck = 0;
+ my $hi = 0;
+ my $lo = 0;
+ my $it = 0;
+ my $lux = 0;
+ my $valid = 0;
+ while (!$valid) {
+ $it = $hash->{tsl2561IntegrationTime};
- # Read data until we find a valid range
- my $agcCheck = 0;
- my $hi = 0;
- my $lo = 0;
- my $it = 0;
- my $lux = 0;
- while (!$valid) {
- $it = $hash->{tsl2561IntegrationTime};
+ # Get the hi/low threshold for the current integration time
+ if ($it==TSL2561_INTEGRATIONTIME_13MS) {
+ $hi = TSL2561_AGC_THI_13MS;
+ $lo = TSL2561_AGC_TLO_13MS;
+ } elsif ( $it==TSL2561_INTEGRATIONTIME_101MS) {
+ $hi = TSL2561_AGC_THI_101MS;
+ $lo = TSL2561_AGC_TLO_101MS;
+ } else {
+ $hi = TSL2561_AGC_THI_402MS;
+ $lo = TSL2561_AGC_TLO_402MS;
+ }
- # Get the hi/low threshold for the current integration time
- if ($it==TSL2561_INTEGRATIONTIME_13MS) {
- $hi = TSL2561_AGC_THI_13MS;
- $lo = TSL2561_AGC_TLO_13MS;
- } elsif ( $it==TSL2561_INTEGRATIONTIME_101MS) {
- $hi = TSL2561_AGC_THI_101MS;
- $lo = TSL2561_AGC_TLO_101MS;
- } else {
- $hi = TSL2561_AGC_THI_402MS;
- $lo = TSL2561_AGC_TLO_402MS;
- }
+ I2C_TSL2561_GetData($hash);
- I2C_TSL2561_GetData($hash);
+ # Run an auto-gain check if we haven't already done so ...
+ if (!$agcCheck) {
+ if (($hash->{broadband} < $lo) && ($hash->{tsl2561Gain} == TSL2561_GAIN_1X)) {
+ # Increase the gain and try again
+ I2C_TSL2561_SetGain($hash, TSL2561_GAIN_16X);
+ # Drop the previous conversion results
+ I2C_TSL2561_GetData($hash);
+ # Set a flag to indicate we've adjusted the gain
+ $agcCheck = 1;
+ } elsif (($hash->{broadband} > $hi) && ($hash->{tsl2561Gain} == TSL2561_GAIN_16X)) {
+ # Drop gain to 1x and try again
+ I2C_TSL2561_SetGain($hash, TSL2561_GAIN_1X);
+ # Drop the previous conversion results
+ I2C_TSL2561_GetData($hash);
+ # Set a flag to indicate we've adjusted the gain
+ $agcCheck = 1;
+ } else {
+ # Nothing to look at here, keep moving ....
+ # Reading is either valid, or we're already at the chips limits
+ $valid = 1;
+ }
+ } else {
+ # If we've already adjusted the gain once, just return the new results.
+ # This avoids endless loops where a value is at one extreme pre-gain,
+ # and the the other extreme post-gain
+ $valid = 1;
+ }
+ }
+}
- # Run an auto-gain check if we haven't already done so ...
- if ($agcCheck) {
- if (($hash->{broadband} < $lo) && ($hash->{tsl2561Gain} == TSL2561_GAIN_1X)) {
- # Increase the gain and try again
- I2C_TSL2561_SetGain($hash, TSL2561_GAIN_16X);
- # Drop the previous conversion results
- I2C_TSL2561_GetData($hash);
- # Set a flag to indicate we've adjusted the gain
- $agcCheck = 1;
- } elsif (($hash->{broadband} > $hi) && ($hash->{tsl2561Gain} == TSL2561_GAIN_16X)) {
- # Drop gain to 1x and try again
- I2C_TSL2561_SetGain($hash, TSL2561_GAIN_1X);
- # Drop the previous conversion results
- I2C_TSL2561_GetData($hash);
- # Set a flag to indicate we've adjusted the gain
- $agcCheck = 1;
- } else {
- # Nothing to look at here, keep moving ....
- # Reading is either valid, or we're already at the chips limits
- $valid = 1;
- }
- } else {
- # If we've already adjusted the gain once, just return the new results.
- # This avoids endless loops where a value is at one extreme pre-gain,
- # and the the other extreme post-gain
- $valid = 1;
- }
- }
+# get channel scale
+sub I2C_TSL2561_GetChannelScale($) {
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ my $chScale = 0;
+
+ if (AttrVal($name, 'floatArithmetics', 0)) {
+ # Get the correct scale depending on the integration time
+ if (!defined($hash->{tsl2561IntegrationTime})) {
+ $chScale = 1.0;
+ } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
+ $chScale = 322.0/11;
+ } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
+ $chScale = 322.0/81;
+ } else {
+ $chScale = 1.0;
+ }
+
+ # Scale for gain (1x or 16x)
+ if (!defined($hash->{tsl2561Gain}) || !$hash->{tsl2561Gain}) {
+ $chScale = $chScale*16;
+ }
+ } else {
+ # Get the correct scale depending on the integration time
+ if ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
+ $chScale = TSL2561_LUX_CHSCALE_TINT0;
+ } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
+ $chScale = TSL2561_LUX_CHSCALE_TINT1;
+ } else {
+ $chScale = (1 << TSL2561_LUX_CHSCALE);
+ }
+
+ # Scale for gain (1x or 16x)
+ if (!$hash->{tsl2561Gain}) {
+ $chScale = $chScale << 4;
+ }
+ }
+
+ return $chScale;
}
=head2 I2C_TSL2561_CalculateLux
@@ -802,126 +978,242 @@ sub I2C_TSL2561_GetLuminosity($) {
sub I2C_TSL2561_CalculateLux($) {
my ($hash) = @_;
- my $clipThreshold = 0;
- my $chScale = 0;
-
- I2C_TSL2561_GetLuminosity($hash);
- # Make sure the sensor isn't saturated!
- if ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
- $clipThreshold = TSL2561_CLIPPING_13MS;
- } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
- $clipThreshold = TSL2561_CLIPPING_101MS;
- } else {
- $clipThreshold = TSL2561_CLIPPING_402MS;
- }
+ my $name = $hash->{NAME};
- # Return 0 lux if the sensor is saturated
- if (($hash->{broadband} > $clipThreshold) || ($hash->{ir} > $clipThreshold)) {
- readingsSingleUpdate($hash, 'state', 'Saturated',1);
- return 0;
- }
+ I2C_TSL2561_GetLuminosity($hash);
- # Get the correct scale depending on the integration time
- if ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
- $chScale = TSL2561_LUX_CHSCALE_TINT0;
- } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
- $chScale = TSL2561_LUX_CHSCALE_TINT1;
- } else {
- $chScale = (1 << TSL2561_LUX_CHSCALE);
- }
+ # Make sure the sensor isn't saturated!
+ my $clipThreshold = 0;
+ if ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_13MS) {
+ $clipThreshold = TSL2561_CLIPPING_13MS;
+ } elsif ($hash->{tsl2561IntegrationTime} == TSL2561_INTEGRATIONTIME_101MS) {
+ $clipThreshold = TSL2561_CLIPPING_101MS;
+ } else {
+ $clipThreshold = TSL2561_CLIPPING_402MS;
+ }
- # Scale for gain (1x or 16x)
- if (!$hash->{tsl2561Gain}) {
- $chScale = $chScale << 4;
- }
+ # Return 0 lux if the sensor is saturated
+ if (($hash->{broadband} > $clipThreshold) || ($hash->{ir} > $clipThreshold)) {
+ readingsSingleUpdate($hash, 'state', 'Saturated', 1);
+ return 0;
+ } else {
+ readingsSingleUpdate($hash, 'state', 'Initialized', 1);
+ }
- # Scale the channel values
- my $channel0 = ($hash->{broadband} * $chScale) >> TSL2561_LUX_CHSCALE;
- my $channel1 = ($hash->{ir} * $chScale) >> TSL2561_LUX_CHSCALE;
+ # Get the correct scale depending on gain and integration time
+ my $chScale = I2C_TSL2561_GetChannelScale($hash);
+ if (AttrVal($name, 'floatArithmetics', 0)) {
+ # Scale the channel values
+ my $channel0 = $chScale*$hash->{broadband};
+ my $channel1 = $chScale*$hash->{ir};
- # Find the ratio of the channel values (Channel1/Channel0)
- my $ratio1 = 0;
- if ($channel0 != 0) {
- $ratio1 = ($channel1 << (TSL2561_LUX_RATIOSCALE+1)) / $channel0;
- }
+ # Find the ratio of the channel values (Channel1/Channel0)
+ my $ratio = 0.0;
+ if ($channel0 != 0) {
+ $ratio = $channel1/$channel0;
+ }
+
+ # Calculate luminosity (see TSL2561 data sheet)
+ my $lux = undef;
+ if ($hash->{tsl2561Package} == TSL2561_PACKAGE_CS) {
+ # CS package
+ if ($ratio <= 0.52) {
+ $lux = 0.0315*$channel0 - 0.0593*$channel1*pow($ratio, 1.4);
+ } elsif ($ratio <= 0.65) {
+ $lux = 0.0229*$channel0 - 0.0291*$channel1;
+ } elsif ($ratio <= 0.80) {
+ $lux = 0.0157*$channel0 - 0.0180*$channel1;
+ } elsif ($ratio <= 1.30) {
+ $lux = 0.00338*$channel0 - 0.00260*$channel1;
+ } else {
+ $lux = 0.0;
+ }
+ } else {
+ # T, FN and CL package
+ if ($ratio <= 0.50) {
+ $lux = 0.0304*$channel0 - 0.062*$channel1*pow($ratio, 1.4);
+ } elsif ($ratio <= 0.61) {
+ $lux = 0.0224*$channel0 - 0.031*$channel1;
+ } elsif ($ratio <= 0.80) {
+ $lux = 0.0128*$channel0 - 0.0153*$channel1;
+ } elsif ($ratio <= 1.30) {
+ $lux = 0.00146*$channel0 - 0.00112*$channel1;
+ } else {
+ $lux = 0.0;
+ }
+ }
+
+ if ($lux >= 100) {
+ # Round to 3 significant digits if at least 100
+ my $roundFactor = 10**(floor(log($lux)/log(10)) - 2);
+ $lux = $roundFactor*floor($lux/$roundFactor + 0.5);
+ } else {
+ # Round to 1 fractional digit if less than 100
+ $lux = floor(10*$lux + 0.5)/10;
+ }
+
+ return $lux;
+ } else {
+ # Scale the channel values
+ my $channel0 = ($hash->{broadband} * $chScale) >> TSL2561_LUX_CHSCALE;
+ my $channel1 = ($hash->{ir} * $chScale) >> TSL2561_LUX_CHSCALE;
- # round the ratio value
- my $ratio = ($ratio1 + 1) >> 1;
-
- my $b=0;
- my $m=0;
+ # Find the ratio of the channel values (Channel1/Channel0)
+ my $ratio1 = 0;
+ if ($channel0 != 0) {
+ $ratio1 = ($channel1 << (TSL2561_LUX_RATIOSCALE+1)) / $channel0;
+ }
- if ($hash->{tsl2561Package} == TSL2561_PACKAGE_CS) {
- # CS package
- if (($ratio >= 0) && ($ratio <= TSL2561_LUX_K1C)) {
- $b=TSL2561_LUX_B1C;
- $m=TSL2561_LUX_M1C;
- } elsif ($ratio <= TSL2561_LUX_K2C) {
- $b=TSL2561_LUX_B2C;
- $m=TSL2561_LUX_M2C;
- } elsif ($ratio <= TSL2561_LUX_K3C) {
- $b=TSL2561_LUX_B3C;
- $m=TSL2561_LUX_M3C;
- } elsif ($ratio <= TSL2561_LUX_K4C) {
- $b=TSL2561_LUX_B4C;
- $m=TSL2561_LUX_M4C;
- } elsif ($ratio <= TSL2561_LUX_K5C) {
- $b=TSL2561_LUX_B5C;
- $m=TSL2561_LUX_M5C;
- } elsif ($ratio <= TSL2561_LUX_K6C) {
- $b=TSL2561_LUX_B6C;
- $m=TSL2561_LUX_M6C;
- } elsif ($ratio <= TSL2561_LUX_K7C) {
- $b=TSL2561_LUX_B7C;
- $m=TSL2561_LUX_M7C;
- } elsif ($ratio > TSL2561_LUX_K8C) {
- $b=TSL2561_LUX_B8C;
- $m=TSL2561_LUX_M8C;
- }
- } elsif ($hash->{tsl2561Package} == TSL2561_PACKAGE_T_FN_CL) {
- # T, FN and CL package
- if (($ratio >= 0) && ($ratio <= TSL2561_LUX_K1T)) {
- $b=TSL2561_LUX_B1T;
- $m=TSL2561_LUX_M1T;
- } elsif ($ratio <= TSL2561_LUX_K2T) {
- $b=TSL2561_LUX_B2T;
- $m=TSL2561_LUX_M2T;
- } elsif ($ratio <= TSL2561_LUX_K3T) {
- $b=TSL2561_LUX_B3T;
- $m=TSL2561_LUX_M3T;
- } elsif ($ratio <= TSL2561_LUX_K4T) {
- $b=TSL2561_LUX_B4T;
- $m=TSL2561_LUX_M4T;
- } elsif ($ratio <= TSL2561_LUX_K5T) {
- $b=TSL2561_LUX_B5T;
- $m=TSL2561_LUX_M5T;
- } elsif ($ratio <= TSL2561_LUX_K6T) {
- $b=TSL2561_LUX_B6T;
- $m=TSL2561_LUX_M6T;
- } elsif ($ratio <= TSL2561_LUX_K7T) {
- $b=TSL2561_LUX_B7T;
- $m=TSL2561_LUX_M7T;
- } elsif ($ratio > TSL2561_LUX_K8T) {
- $b=TSL2561_LUX_B8T;
- $m=TSL2561_LUX_M8T;
- }
- }
+ # round the ratio value
+ my $ratio = ($ratio1 + 1) >> 1;
+
+ my $b=0;
+ my $m=0;
- my $temp = (($channel0 * $b) - ($channel1 * $m));
+ if ($hash->{tsl2561Package} == TSL2561_PACKAGE_CS) {
+ # CS package
+ if (($ratio >= 0) && ($ratio <= TSL2561_LUX_K1C)) {
+ $b=TSL2561_LUX_B1C;
+ $m=TSL2561_LUX_M1C;
+ } elsif ($ratio <= TSL2561_LUX_K2C) {
+ $b=TSL2561_LUX_B2C;
+ $m=TSL2561_LUX_M2C;
+ } elsif ($ratio <= TSL2561_LUX_K3C) {
+ $b=TSL2561_LUX_B3C;
+ $m=TSL2561_LUX_M3C;
+ } elsif ($ratio <= TSL2561_LUX_K4C) {
+ $b=TSL2561_LUX_B4C;
+ $m=TSL2561_LUX_M4C;
+ } elsif ($ratio <= TSL2561_LUX_K5C) {
+ $b=TSL2561_LUX_B5C;
+ $m=TSL2561_LUX_M5C;
+ } elsif ($ratio <= TSL2561_LUX_K6C) {
+ $b=TSL2561_LUX_B6C;
+ $m=TSL2561_LUX_M6C;
+ } elsif ($ratio <= TSL2561_LUX_K7C) {
+ $b=TSL2561_LUX_B7C;
+ $m=TSL2561_LUX_M7C;
+ } elsif ($ratio > TSL2561_LUX_K8C) {
+ $b=TSL2561_LUX_B8C;
+ $m=TSL2561_LUX_M8C;
+ }
+ } elsif ($hash->{tsl2561Package} == TSL2561_PACKAGE_T_FN_CL) {
+ # T, FN and CL package
+ if (($ratio >= 0) && ($ratio <= TSL2561_LUX_K1T)) {
+ $b=TSL2561_LUX_B1T;
+ $m=TSL2561_LUX_M1T;
+ } elsif ($ratio <= TSL2561_LUX_K2T) {
+ $b=TSL2561_LUX_B2T;
+ $m=TSL2561_LUX_M2T;
+ } elsif ($ratio <= TSL2561_LUX_K3T) {
+ $b=TSL2561_LUX_B3T;
+ $m=TSL2561_LUX_M3T;
+ } elsif ($ratio <= TSL2561_LUX_K4T) {
+ $b=TSL2561_LUX_B4T;
+ $m=TSL2561_LUX_M4T;
+ } elsif ($ratio <= TSL2561_LUX_K5T) {
+ $b=TSL2561_LUX_B5T;
+ $m=TSL2561_LUX_M5T;
+ } elsif ($ratio <= TSL2561_LUX_K6T) {
+ $b=TSL2561_LUX_B6T;
+ $m=TSL2561_LUX_M6T;
+ } elsif ($ratio <= TSL2561_LUX_K7T) {
+ $b=TSL2561_LUX_B7T;
+ $m=TSL2561_LUX_M7T;
+ } elsif ($ratio > TSL2561_LUX_K8T) {
+ $b=TSL2561_LUX_B8T;
+ $m=TSL2561_LUX_M8T;
+ }
+ }
- # Do not allow negative lux value
- if ($temp < 0) {
- $temp = 0;
- }
+ my $temp = (($channel0 * $b) - ($channel1 * $m));
- # Round lsb (2^(LUX_SCALE-1))
- $temp += (1 << (TSL2561_LUX_LUXSCALE-1));
+ # Do not allow negative lux value
+ if ($temp < 0) {
+ $temp = 0;
+ }
- # Strip off fractional portion
- my $lux = $temp >> TSL2561_LUX_LUXSCALE;
+ # Round lsb (2^(LUX_SCALE-1))
+ $temp += (1 << (TSL2561_LUX_LUXSCALE-1));
- # Signal I2C had no errors
- return $lux;
+ # Strip off fractional portion
+ my $lux = $temp >> TSL2561_LUX_LUXSCALE;
+
+ # Signal I2C had no errors
+ return $lux;
+ }
+
+}
+
+sub I2C_TSL2561_i2cread($$$) {
+ my ($hash, $reg, $nbyte) = @_;
+ my $success = 1;
+
+ if ($hash->{HiPi_used}) {
+ eval {
+ my @values = $hash->{devTSL2561}->bus_read($reg, $nbyte);
+ I2C_TSL2561_I2CRec($hash, {
+ direction => "i2cread",
+ i2caddress => $hash->{I2C_Address},
+ reg => $reg,
+ nbyte => $nbyte,
+ received => join (' ',@values),
+ });
+ };
+ Log3 ($hash, 1, $hash->{NAME} . ': ' . I2C_TSL2561_Catch($@)) if $@;
+ } elsif (defined (my $iodev = $hash->{IODev})) {
+ CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
+ direction => "i2cread",
+ i2caddress => $hash->{I2C_Address},
+ reg => $reg,
+ nbyte => $nbyte
+ });
+ if ($hash->{$iodev->{NAME}.'_SENDSTAT'} eq 'error') {
+ $hash->{tsl2561Package} = undef;
+ readingsSingleUpdate($hash, 'state', 'I2C Error', 1);
+ $success = 0;
+ }
+ } else {
+ Log3 ($hash, 1, $hash->{NAME} . ': ' . "no IODev assigned to '$hash->{NAME}'");
+ $success = 0;
+ }
+
+ return $success;
+}
+
+sub I2C_TSL2561_i2cwrite($$$) {
+ my ($hash, $reg, @data) = @_;
+ my $success = 1;
+
+ if ($hash->{HiPi_used}) {
+ eval {
+ $hash->{devTSL2561}->bus_write($reg, join (' ',@data));
+ I2C_TSL2561_I2CRec($hash, {
+ direction => "i2cwrite",
+ i2caddress => $hash->{I2C_Address},
+ reg => $reg,
+ data => join (' ',@data),
+ });
+ };
+ Log3 ($hash, 1, $hash->{NAME} . ': ' . I2C_TSL2561_Catch($@)) if $@;
+ } elsif (defined (my $iodev = $hash->{IODev})) {
+ CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, {
+ direction => "i2cwrite",
+ i2caddress => $hash->{I2C_Address},
+ reg => $reg,
+ data => join (' ',@data),
+ });
+ if ($hash->{$iodev->{NAME}.'_SENDSTAT'} eq 'error') {
+ $hash->{tsl2561Package} = undef;
+ readingsSingleUpdate($hash, 'state', 'I2C Error', 1);
+ $success = 0;
+ }
+ } else {
+ Log3 ($hash, 1, $hash->{NAME} . ': ' . "no IODev assigned to '$hash->{NAME}'");
+ $success = 0;
+ }
+
+ return $success;
}
1;
@@ -932,67 +1224,104 @@ sub I2C_TSL2561_CalculateLux($) {
I2C_TSL2561
-
-
- With this module you can read values from the digital luminosity sensor TSL2561
- via the i2c bus on Raspberry Pi.
+
+
+ With this module you can read values from the ambient light sensor TSL2561
+ via the i2c bus on Raspberry Pi.
+ The luminosity value returned is a good human eye reponse approximation of an
+ illumination measurement in the range of 0.1 to 40000+ lux (but not a replacement for a
+ precision measurement, relation between measured value and true value may vary by 40%).
+
- Before you can use the module on the Raspberry Pi you must load the I2C kernel
- modules.
- Add these two lines to your /etc/modules file to load the kernel modules
- automatically when booting your Raspberry Pi.
-
- i2c-bcm2708
- i2c-dev
-
-
- Please note:
- For the i2c communication, the perl modules HiPi::Device::I2C
- are required.
- For a simple automated installation:
- wget http://raspberry.znix.com/hipifiles/hipi-install
- perl hipi-install
-
-
-
- Define
-
- define TSL2561 I2C_TSL2561 <I2C device> <I2C address>
+ There are two possibilities connecting to I2C bus:
+
+ - via IODev module
+ 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
+
+
+ - via HiPi library
+ Add these two lines to your /etc/modules file to load the I2C relevant kernel modules
+ automaticly during booting your Raspberry Pi.
+
+ i2c-bcm2708
+ i2c-dev
+
+ Install HiPi perl modules:
+ wget http://raspberry.znix.com/hipifiles/hipi-install perl hipi-install
+ To change the permissions of the I2C device create file:
+ /etc/udev/rules.d/98_i2c.rules
+ with this content:
+ SUBSYSTEM=="i2c-dev", MODE="0666"
+ Reboot
+
+ To use the sensor on the second I2C bus at P5 connector
+ (only for version 2 of Raspberry Pi) you must add the bold
+ line of following code to your FHEM start script:
+
+ case "$1" in
+ 'start')
+ sudo hipi-i2c e 0 1
+ ...
+
+
+
+
+
+ Define
+
+ define TSL2561 I2C_TSL2561 [<I2C device>] <I2C address>
+ <I2C device> must not be used if you connect via IODev. For HiPi it's mandatory.
+
+ Examples:
+
+ define TSL2561 I2C_TSL2561 /dev/i2c-0 0x39
+ attr TSL2561 poll_interval 5
+
+
+ define TSL2561 I2C_TSL2561 0x39
+ attr TSL2561 IODev I2CModule
+ attr TSL2561 poll_interval 5
+
+
+
+
+ Attributes
+
+ - IODev
+ Set the name of a IODev module.
+ Default: undefined
+ if undefined the perl modules HiPi::Device::I2C are required
+
+ - poll_interval
+ Set the polling interval in minutes to query the sensor for new measured values.
+ Default: 5, valid values: 1, 2, 5, 10, 20, 30
+
+ - integrationTime
+ Set time in ms the sensor takes to measure the light.
+ Default: 13, valid values: 13, 101, 402
+ see this tutorial
+ for more details
+
+ - gain
+ Set gain factor.
+ Default: 1, valid values: 1, 16
+
+ - autoGain
+ Enable auto gain.
+ Default: 1, valid values: 0, 1
+ if set to 1, the gain parameter is adjusted automatically depending on light conditions
+
+ - floatArithmetics
+ Enable float arithmetics.
+ Default: 1, valid values: 0, 1
+ if set to 0, the luminosity is calculated using int arithmetics (for very low powered platforms)
+ if set to 1, the luminosity is calculated using float arithmetics, yielding some additional precision
+
+
- Examples:
-
- define TSL2561 I2C_TSL2561 /dev/i2c-0 0x39
- attr TSL2561 poll_interval 5
-
-
-
-
- Attributes
-
- - poll_interval
- Set the polling interval in minutes to query the sensor for new measured
- values.
- Default: 5, valid values: 1, 2, 5, 10, 20, 30
-
- - integrationTime
- time in ms the sensor takes to measure the light.
- Default: 13, valid values: 13, 101, 402
- see this tutorial
- for more details
-
- - gain
- gain factor
- Default: 1, valid values: 1, 16
-
- - autoGain
- enable auto gain
- Default: 1, valid values: 0, 1
- if set to 1,the gain parameter is set automatically depending on light conditions
-
-
-
-
=end html