Merge branch 'arendst/development' into development

This commit is contained in:
reloxx13 2018-07-12 18:58:34 +02:00
commit 431c9bb469
34 changed files with 951 additions and 606 deletions

View File

@ -21,6 +21,17 @@ This file is part of the Joba_Tsl2561 Library.
#include <Tsl2561Util.h>
// to mimic Serial.printf() of esp8266 core for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
va_start(arg, fmt);
vsnprintf(buf, sizeof(buf), fmt, arg);
buf[sizeof(buf)-1] = '\0';
va_end(arg);
return buf;
}
Tsl2561 Tsl(Wire);
uint8_t id;
@ -35,31 +46,30 @@ void setup() {
}
void loop() {
uint16_t scaledFull = ~0, scaledIr = ~0;
uint32_t full = ~0, ir = ~0, milliLux = ~0;
uint16_t scaledFull = 0xffff, scaledIr = 0xffff;
uint32_t full = 0xffffffff, ir = 0xffffffff, milliLux = 0xffffffff;
bool gain = false;
Tsl2561::exposure_t exposure = Tsl2561::EXP_OFF;
if( Tsl2561Util::autoGain(Tsl, gain, exposure, scaledFull, scaledIr) ) {
if( Tsl2561Util::normalizedLuminosity(gain, exposure, full = scaledFull, ir = scaledIr) ) {
if( Tsl2561Util::milliLux(full, ir, milliLux, Tsl2561::packageCS(id)) ) {
Serial.printf("Tsl2561 addr: 0x%02x, id: 0x%02x, sfull: %5u, sir: %5u, full: %5u, ir: %5u, gain: %d, exp: %d, lux: %5u.%03u\n",
Tsl.address(), id, scaledFull, scaledIr, full, ir, gain, exposure, milliLux/1000, milliLux%1000);
if( Tsl2561Util::milliLux(full, ir, milliLux, Tsl2561::packageCS(id), 5) ) {
Serial.print(format("Tsl2561 addr: 0x%02x, id: 0x%02x, sfull: %5u, sir: %5u, full: %7lu, ir: %7lu, gain: %d, exp: %d, lux: %5lu.%03lu\n",
Tsl.address(), id, scaledFull, scaledIr, (unsigned long)full, (unsigned long)ir, gain, exposure, (unsigned long)milliLux/1000, (unsigned long)milliLux%1000));
}
else {
Serial.printf("Tsl2561Util::milliLux(full=%u, ir=%u) error\n", full, ir);
Serial.print(format("Tsl2561Util::milliLux(full=%lu, ir=%lu) error\n", (unsigned long)full, (unsigned long)ir));
}
}
else {
Serial.printf("Tsl2561Util::normalizedLuminosity(gain=%u, exposure=%u, sfull=%u, sir=%u, full=%u, ir=%u) error\n",
gain, exposure, scaledFull, scaledIr, full, ir);
Serial.print(format("Tsl2561Util::normalizedLuminosity(gain=%u, exposure=%u, sfull=%u, sir=%u, full=%lu, ir=%lu) error\n",
gain, exposure, scaledFull, scaledIr, (unsigned long)full, (unsigned long)ir));
}
}
else {
Serial.printf("Tsl2561Util::autoGain(gain=%u, exposure=%u, sfull=%u, sir=%u) error\n",
gain, exposure, scaledFull, scaledIr);
Serial.print(format("Tsl2561Util::autoGain(gain=%u, exposure=%u, sfull=%u, sir=%u) error\n",
gain, exposure, scaledFull, scaledIr));
}
delay(1000);
}

View File

@ -21,6 +21,17 @@ This file is part of the Joba_Tsl2561 Library.
#include <Tsl2561.h>
// to mimic Serial.printf() of esp8266 core for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
va_start(arg, fmt);
vsnprintf(buf, sizeof(buf), fmt, arg);
buf[sizeof(buf)-1] = '\0';
va_end(arg);
return buf;
}
Tsl2561 Tsl(Wire);
void setup() {
@ -44,7 +55,7 @@ void loop() {
Tsl.fullLuminosity(full);
Tsl.irLuminosity(ir);
Serial.printf("Tsl2561 at 0x%02x(id=0x%02x) luminosity is %5u (full) and %5u (ir)\n", Tsl.address(), id, full, ir);
Serial.print(format("Tsl2561 at 0x%02x(id=0x%02x) luminosity is %5u (full) and %5u (ir)\n", Tsl.address(), id, full, ir));
Tsl.off();
}

View File

@ -22,11 +22,22 @@ This file is part of the Joba_Tsl2561 Library.
#include <Tsl2561.h>
// to mimic Serial.printf() of esp8266 core for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
va_start(arg, fmt);
vsnprintf(buf, sizeof(buf), fmt, arg);
buf[sizeof(buf)-1] = '\0';
va_end(arg);
return buf;
}
Tsl2561 Tsl(Wire);
void showError( Tsl2561 &tsl ) {
Tsl2561::status_t status = tsl.status();
Serial.printf("Error was %u: ", status);
Serial.print(format("Error was %u: ", status));
switch( status ) {
case Tsl2561::ERR_OK: Serial.println("None"); break;
case Tsl2561::ERR_RW: Serial.println("Read/Write"); break;
@ -40,7 +51,7 @@ void showError( Tsl2561 &tsl ) {
void testSensitivity( Tsl2561 &tsl, bool newGain, Tsl2561::exposure_t newExp ) {
if( tsl.on() ) {
uint32_t start = millis();
Serial.printf("Chip powered on at %u\n", start);
Serial.print(format("Chip powered on at %lu\n", (unsigned long)start));
bool chipGain;
Tsl2561::exposure_t chipExp;
@ -58,7 +69,7 @@ void testSensitivity( Tsl2561 &tsl, bool newGain, Tsl2561::exposure_t newExp ) {
bool check = true;
if( change ) {
if( tsl.setSensitivity(newGain, newExp) ) {
Serial.printf("New gain = %d, exposure = 0x%02x\n", newGain, newExp);
Serial.print(format("New gain = %d, exposure = 0x%02x\n", newGain, newExp));
}
else {
check = false;
@ -69,6 +80,7 @@ void testSensitivity( Tsl2561 &tsl, bool newGain, Tsl2561::exposure_t newExp ) {
if( check ) {
uint16_t ir, full = 0;
while( !full && millis() - start < 1000 ) {
if( !tsl.fullLuminosity(full) ) {
Serial.print("Check full luminosity failed. ");
@ -89,7 +101,7 @@ void testSensitivity( Tsl2561 &tsl, bool newGain, Tsl2561::exposure_t newExp ) {
Serial.println("No luminosity reading after 1s. Too dark?");
}
else {
Serial.printf("Got luminosity after %d ms. Full spectrum is %d and IR only is %d\n", millis() - start, full, ir);
Serial.print(format("Got luminosity after %lu ms. Full spectrum is %u and IR only is %u\n", (unsigned long)millis() - start, full, ir));
}
}
@ -107,7 +119,7 @@ void testSensitivity( Tsl2561 &tsl, bool newGain, Tsl2561::exposure_t newExp ) {
bool testPackage( Tsl2561 &tsl ) {
uint8_t id;
if( tsl.id(id) ) {
Serial.printf("Chip has type %02x and revision %x\n", Tsl2561::type(id), Tsl2561::revision(id) );
Serial.print(format("Chip has type %02x and revision %x\n", Tsl2561::type(id), Tsl2561::revision(id)));
if( Tsl2561::packageT_FN_CL(id) ) {
Serial.println("Chip is a T, FN or CL type package");
}
@ -128,7 +140,7 @@ bool testPackage( Tsl2561 &tsl ) {
void test( Tsl2561 &tsl ) {
bool ok = tsl.available();
Serial.printf("\nTesting Tsl2561 at address %02x: %sfound\n", tsl.address(), ok ? "" : "NOT ");
Serial.print(format("\nTesting Tsl2561 at address %02x: %sfound\n", tsl.address(), ok ? "" : "NOT "));
if( ok ) {
if( testPackage(tsl) ) {
testSensitivity(tsl, Tsl2561::GAIN_OFF, Tsl2561::EXP_402);
@ -160,4 +172,3 @@ void loop() {
Serial.println("\nNext test in 5s\n");
delay(5000);
}

View File

@ -21,6 +21,17 @@ This file is part of the Joba_Tsl2561 Library.
#include <Tsl2561Util.h>
// to mimic Serial.printf() of esp8266 core for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
va_start(arg, fmt);
vsnprintf(buf, sizeof(buf), fmt, arg);
buf[sizeof(buf)-1] = '\0';
va_end(arg);
return buf;
}
Tsl2561::address_t addr[] = { Tsl2561::ADDR_GND, Tsl2561::ADDR_FLOAT, Tsl2561::ADDR_VDD };
Tsl2561 Tsl(Wire);
@ -58,18 +69,19 @@ void loop() {
Tsl.fullLuminosity(scaledFull);
Tsl.irLuminosity(scaledIr);
Serial.printf("Tsl2561 addr: 0x%02x, id: 0x%02x, sfull: %5u, sir: %5u, gain: %d, exp: %d", addr[i], id, scaledFull, scaledIr, gain, exposure);
Serial.print(format("Tsl2561 addr: 0x%02x, id: 0x%02x, sfull: %5u, sir: %5u, gain: %d, exp: %d",
addr[i], id, scaledFull, scaledIr, gain, exposure));
if( Tsl2561Util::normalizedLuminosity(gain, exposure, full = scaledFull, ir = scaledIr) ) {
if( Tsl2561Util::milliLux(full, ir, milliLux, Tsl2561::packageCS(id)) ) {
Serial.printf(", full: %5u, ir: %5u, lux: %5u.%03u\n", full, ir, milliLux/1000, milliLux%1000);
Serial.print(format(", full: %5lu, ir: %5lu, lux: %5lu.%03lu\n", (unsigned long)full, (unsigned long)ir, (unsigned long)milliLux/1000, (unsigned long)milliLux%1000));
}
else {
Serial.printf(", full: %5u, ir: %5u: Tsl2561Util::milliLux() error\n", full, ir);
Serial.print(format(", full: %5lu, ir: %5lu: Tsl2561Util::milliLux() error\n", (unsigned long)full, (unsigned long)ir));
}
}
else {
Serial.printf(", full: %5u, ir: %5u: Tsl2561Util::normalizedLuminosity() error\n", full, ir);
Serial.print(format(", full: %5lu, ir: %5lu: Tsl2561Util::normalizedLuminosity() error\n", (unsigned long)full, (unsigned long)ir));
}
Tsl.off();
@ -84,4 +96,3 @@ void loop() {
delay(5000);
}

View File

@ -0,0 +1,61 @@
; PlatformIO Project Configuration File
;
; Example config for flashing nodemcuv2 boards via linux serial port
;
; Adapt (e.g. platform, board, port) to your environment as needed.
; Then call platformio.sh to copy the file to all examples.
; Now cd to the example directory (e.g. Autogain/) and do "pio run"
; to build it or directly upload with "pio run --target upload".
; Watch the serial output of your sketch with "pio device monitor".
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[platformio]
src_dir = .
lib_dir = ../..
; uncomment one, if you want to build only one
; env_default = nodemcuv2
; env_default = nano328
[env:nodemcuv2]
; TSL <-> ESP8266
; ------------
; GND <-> GND
; VCC <-> 3V
; SCL <-> D1
; SDA <-> D2
platform = espressif8266
board = nodemcuv2
framework = arduino
build_flags = -Wall
monitor_speed = 115200
upload_speed = 230400
upload_resetmethod = nodemcu
;usually upload port is autodetected
;upload_port = /dev/ttyUSB[1-9]
[env:nano328]
; TSL <-> NANO
; ------------
; GND <-> GND
; VCC <-> 3V3
; SCL <-> A5
; SDA <-> A4
platform = atmelavr
board = nanoatmega328
framework = arduino
build_flags = -Wall
monitor_speed = 115200
;upload_port = /dev/ttyUSB[1-9]

View File

@ -0,0 +1,12 @@
#!/bin/bash
#
# Create platformio.ini templates for all examples, if missing.
# Start this script from within the examples directory.
for d in *; do
if [ -d "$d" -a -f "$d/$d.ino" -a ! -e "$d/platformio.ini" ]
then
cp -av platformio.ini "$d/"
fi
done

View File

@ -0,0 +1,36 @@
This directory is intended for the project specific (private) libraries.
PlatformIO will compile them to static libraries and link to executable file.
The source code of each library should be placed in separate directory, like
"lib/private_lib/[here are source files]".
For example, see how can be organized `Foo` and `Bar` libraries:
|--lib
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |- readme.txt --> THIS FILE
|- platformio.ini
|--src
|- main.c
Then in `src/main.c` you should use:
#include <Foo.h>
#include <Bar.h>
// rest H/C/CPP code
PlatformIO will find your libraries automatically, configure preprocessor's
include paths and build them.
More information about PlatformIO Library Dependency Finder
- http://docs.platformio.org/page/librarymanager/ldf.html

View File

@ -1,6 +1,6 @@
{
"name": "Joba_Tsl2561",
"version": "2.0.1",
"version": "2.0.7",
"keywords": "twowire, i2c, bus, sensor, luminosity, illuminance, lux",
"description": "Arduino Library for ams (taos) luminance chip Tsl2561 with autogain",
"repository":

View File

@ -1,5 +1,5 @@
name=Joba Tsl2561 Library
version=2.0.1
version=2.0.7
author=joba-1
maintainer=joba-1 <joban123.psn@gmail.com>
sentence=IoT library for using the Tsl2561 luminosity sensor

View File

@ -0,0 +1,58 @@
; PlatformIO Project Configuration File
;
; Example config for flashing nodemcuv2 boards via linux serial port
;
; Adapt (e.g. platform, board, port) to your environment as needed.
; Then call platformio.sh to copy the file to all examples.
; Now cd to the example directory (e.g. Autogain/) and do "pio run"
; to build it or directly upload with "pio run --target upload".
; Watch the serial output of your sketch with "pio device monitor".
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[platformio]
; uncomment one, if you want to build only one
; env_default = nodemcuv2
; env_default = nano328
[env:nodemcuv2]
; TSL <-> ESP8266
; ------------
; GND <-> GND
; VCC <-> 3V
; SCL <-> D1
; SDA <-> D2
platform = espressif8266
board = nodemcuv2
framework = arduino
build_flags = -Wall
monitor_speed = 115200
upload_speed = 230400
upload_resetmethod = nodemcu
;usually upload port is autodetected
;upload_port = /dev/ttyUSB[1-9]
[env:nano328]
; TSL <-> NANO
; ------------
; GND <-> GND
; VCC <-> 3V3
; SCL <-> A5
; SDA <-> A4
platform = atmelavr
board = nanoatmega328
framework = arduino
build_flags = -Wall
monitor_speed = 115200

View File

@ -29,7 +29,7 @@ bool Tsl2561::available() {
bool Tsl2561::begin( address_t addr ) {
_addr = addr;
return available();
return available();
}
bool Tsl2561::begin() {
@ -48,24 +48,30 @@ bool Tsl2561::begin() {
bool Tsl2561::readByte( register_t reg, uint8_t &val ) {
_wire.beginTransmission(_addr);
_wire.write(reg | CONTROL_CMD);
if( _wire.endTransmission(false) == ERR_OK ) {
if( _wire.requestFrom(_addr, 1) ) {
if( (_status = static_cast<status_t>(_wire.endTransmission(false))) == ERR_OK ) {
if( _wire.requestFrom(_addr, 1) == 1 ) {
val = static_cast<uint8_t>(_wire.read());
}
else {
_status = ERR_RW;
}
}
return (_status = static_cast<status_t>(_wire.endTransmission())) == ERR_OK;
return _status == ERR_OK;
}
bool Tsl2561::readWord( register_t reg, uint16_t &val ) {
_wire.beginTransmission(_addr);
_wire.write(reg | CONTROL_CMD);
if( _wire.endTransmission(false) == ERR_OK ) {
if( _wire.requestFrom(_addr, 2) ) {
val = (uint16_t)_wire.read() & 0xff;
val |= ((uint16_t)_wire.read() & 0xff) << 8;
if( (_status = static_cast<status_t>(_wire.endTransmission(false))) == ERR_OK ) {
if( _wire.requestFrom(_addr, 2) == 2 ) {
val = static_cast<uint16_t>(_wire.read()) & 0xff;
val |= (static_cast<uint16_t>(_wire.read()) & 0xff) << 8;
}
else {
_status = ERR_RW;
}
}
return (_status = static_cast<status_t>(_wire.endTransmission())) == ERR_OK;
return _status == ERR_OK;
}
bool Tsl2561::writeByte( register_t reg, uint8_t val ) {

View File

@ -39,22 +39,22 @@ bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &fu
switch( exposure ) {
case Tsl2561::EXP_14:
full = (scaledFull >= 5047/4*3) ? ~0 : ((full + 5) * 322) / 11;
ir = (scaledIr >= 5047/4*3) ? ~0 : ((ir + 5) * 322) / 11;
full = (scaledFull >= 5047/4*3) ? 0xffffffff : ((full + 5) * 322) / 11;
ir = (scaledIr >= 5047/4*3) ? 0xffffffff : ((ir + 5) * 322) / 11;
break;
case Tsl2561::EXP_101:
full = (scaledFull >= 37177/4*3) ? ~0 : ((full + 40) * 322) / 81;
ir = (scaledIr >= 37177/4*3) ? ~0 : ((ir + 40) * 322) / 81;
full = (scaledFull >= 37177/4*3) ? 0xffffffff : ((full + 40) * 322) / 81;
ir = (scaledIr >= 37177/4*3) ? 0xffffffff : ((ir + 40) * 322) / 81;
break;
case Tsl2561::EXP_402:
if( scaledFull >= 65535/4*3 ) full = ~0;
if( scaledIr >= 65535/4*3 ) ir = ~0;
if( scaledFull >= 65535/4*3 ) full = 0xffffffff;
if( scaledIr >= 65535/4*3 ) ir = 0xffffffff;
break;
default:
return false;
}
return full != ~0U && ir != ~0U;
return full != 0xffffffff && ir != 0xffffffff;
}
return false;
@ -72,9 +72,9 @@ uint16_t getLimit( Tsl2561::exposure_t exposure ) {
// Wait for one measurement interval plus some empirically tested extra millis
void waitNext( Tsl2561::exposure_t exposure ) {
switch( exposure ) {
case Tsl2561::EXP_14: delay(16); break;
case Tsl2561::EXP_101: delay(103); break;
default: delay(408); break;
case Tsl2561::EXP_14: delay(Tsl2561Util::DELAY_EXP_14); break;
case Tsl2561::EXP_101: delay(Tsl2561Util::DELAY_EXP_101); break;
default: delay(Tsl2561Util::DELAY_EXP_402); break;
}
}
@ -95,7 +95,7 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
// get current sensitivity
if( !tsl.getSensitivity(gain, exposure) ) {
return false;
return false; // I2C error
}
// find index of current sensitivity
@ -111,11 +111,13 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
}
// in a loop wait for next sample, get values and adjust sensitivity if needed
uint8_t retryOnSaturated = 10;
while( true ) {
waitNext(exposure);
if( !tsl.fullLuminosity(full) || !tsl.irLuminosity(ir) ) {
return false;
return false; // I2C error
}
uint16_t limit = getLimit(exposure);
@ -126,13 +128,15 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
if( (full < 1000 && ++curr < sizeof(sensitivity)/sizeof(sensitivity[0]))
|| (full > limit && curr-- > 0) ) {
if( !tsl.setSensitivity(sensitivity[curr].gain, sensitivity[curr].exposure) ) {
return false;
return false; // I2C error
}
gain = sensitivity[curr].gain;
exposure = sensitivity[curr].exposure;
}
else {
return true; // saturated, but best we can do
if( ++curr > 0 && retryOnSaturated-- == 0 ) {
return true; // saturated, but best we can do
}
}
}
}
@ -141,16 +145,32 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
bool compensateTemperature( int16_t centiCelsius, uint32_t &full, uint32_t &ir ) {
// assume linear gradient 0% at 25°C to +20% at 70°C
if( centiCelsius >= -3000 && centiCelsius <= 7000 ) {
full -= (full * (centiCelsius - 2500) * 20) / (100 * (7000 - 2500));
ir -= (ir * (centiCelsius - 2500) * 20) / (100 * (7000 - 2500));
full -= (full * (centiCelsius - 2500)) / (5 * (7000 - 2500));
ir -= (ir * (centiCelsius - 2500)) / (5 * (7000 - 2500));
return true;
}
return false;
}
// Round num after valid digits
uint32_t significance( uint32_t num, uint8_t digits ) {
uint8_t len = 1;
uint32_t n = num;
while( n /= 10 ) {
len++;
}
uint32_t e10 = 1;
while( len-- > digits ) {
e10 *= 10;
}
return ((num + e10 / 2) / e10) * e10;
}
// Calculate lux from raw luminosity values
bool milliLux( uint32_t full, uint32_t ir, uint32_t &mLux, bool csType ) {
bool milliLux( uint32_t full, uint32_t ir, uint32_t &mLux, bool csType, uint8_t digits ) {
if( !full ) {
mLux = 0;
return true;
@ -187,6 +207,8 @@ bool milliLux( uint32_t full, uint32_t ir, uint32_t &mLux, bool csType ) {
mLux /= 400 * 16 / 193; // 33 = counts/lux (cpl)
}
mLux = significance(mLux, digits); // only the first 4 digits seem to make sense.
return true;
}

View File

@ -24,6 +24,14 @@ This file is part of the Joba_Tsl2561 Library.
namespace Tsl2561Util {
// Some chips may need higher values.
// Tweak here if autogain does not return valid results.
typedef enum {
DELAY_EXP_14 = 20, // Max. delay in ms after
DELAY_EXP_101 = 110, // starting a measurement until
DELAY_EXP_402 = 430 // the first values arrive.
} delay_t;
// delay until next sample is available
void waitNext( Tsl2561::exposure_t exposure );
@ -40,9 +48,11 @@ namespace Tsl2561Util {
// adjust luminosity according to sensor temperature (max +/-20% from 25°C)
bool compensateTemperature( int16_t centiCelsius, uint32_t &full, uint32_t &ir );
// calculate lux from normalized (and optionally temperature adjusted) luminosity
bool milliLux( uint32_t full, uint32_t ir, uint32_t &milliLux, bool csType = false );
// helper function to round after significant digits (~4 digits for Tsl2561)
uint32_t significance( uint32_t value, uint8_t digits );
// calculate lux from normalized (and optionally temperature adjusted) luminosity
bool milliLux( uint32_t full, uint32_t ir, uint32_t &milliLux, bool csType = false, uint8_t digits = 4 );
};
#endif

View File

@ -1,4 +1,15 @@
/* 6.1.0a
* Add TM1638 switch support (#2226)
* Fix invalid response using more than 4 switches and domoticz
* Update sensor drivers to provide instant results
* Add read sensor retry to DS18B20, DS18x20, DHT, SHT1X and HTU21
* Change SHT1x driver to provide better instant results
* Fix DHT driver mixing values for different sensors (#1797)
* Change DHT driver to provide better instant results and add decimals to DHT11 (#3164)
* Change DS18x20 driver to provide better instant results (#3169)
* Change DS18B20 driver to provide better instant results
* Remove TSL2561 debug message and update library (#2415)
* Change SHT1x sensor initialization from pre-teleperiod to once during restart to fix I2C interference
* Add wifi and mqtt status led blinkyblinky to be disabled by SetOption31 1. Does not work when LedPower is On (deliberate) (#871, #2230, #3114, #3155)
* Add experimental (untested) TM1638 switch support (#2226)
* Add support for APDS9960 proximity sensor (#3051)
@ -15,16 +26,42 @@
* Fix KNX bug when doing reply of sensors values
* Fix rules induced LWT message
* Fix possible wifi connection problem (#1366)
* Fix some Pow R2 and S31 checksum errors (#1907)
* Fix display selection of un-available GPIO options in Module Configuration webpage (#2718)
* Fix timer re-trigger within one minute after restart (#2744)
* Fix IRSend not accepting data value of 0 by David Conran (#2751)
* Fix vars on rules by Adrian Scillato (#2769)
* Fix bug in KNX menu by Adrian Scillato (#2770)
* Fix anomalies in rules (#2778)
* Fix HUE bridge V1 software version by Heiko Krupp (#2788)
* Fix Hardware Watchdog restart when using event command (#2853)
* Add Ukrainian language file
* Add KNX support for DS18S20 Temperature sensor
* Add CRC to Settings making future upgrades more fail-safe
* Add feature information to Status 4
* Add tools folder with python script decode-status.py for decoding some status fields like SetOption and Features
* Add Slots on the KNX Web Menu to select Group Addess to receive data to trigger rules
* Add two rule sets of 511 characters using commands rule1, rule2 and rule3
* Add Console Commands to send KNX Commands and KNX Values
* Add Slots on the KNX Web Menu to select Group Addess to send data from console commands
* Add Events to trigger rules when a command or read requests is received from KNX
* Add command SetOption30 to enforce Hass discovery as light group (#1784)
* Add support for BlitzWolf BW-SHP2 (and Homecube, Gosund SP1) Energy Monitoring Smart Socket (#2223)
* Add time in minutes to rule Time#Initialized, Time#set and Time#Minute (#2669)
* Add Eastron SDM630 energy meter by Gennaro Tortone (#2735)
* Add KNX communication enhancement by Adrian Scillato (#2742)
* Add KNX energy data by Adrian Scillato (#2750)
* Add rule support for IrReceive and RfReceive (#2758)
* Add python script fw-server.py in tools folder to create a simple OTA server by Gennaro Tortone (#2759)
* Add rule variables %time% for minutes since midnight, %uptime%, %sunrise% and %sunset% giving time in minutes (#2669)
* Add rules %mem1% to %mem5% variable names storing data in flash (#2780)
* Add rules test on %varx% or %memx% (#2780)
* Add optional token %id% substituting the unique MAC address to fulltopic by Michael Graf (#2794)
* Add support for Sonoff S26 Smart Socket (#2808)
* Add command WebSend [<host>(:<port>,<user>:<password>)] <command> (#2821)
* Add increment and decrement value to command Counter (#2838)
* Add support for Sonoff iFan02 as module 44 introducing command FanSpeed 0..3 (#2839)
* Add source information to command execution to be shown with logging option 3 (#2843)
* Add support for uploading Sonoff Bridge firmware found in tools/fw_efm8bb1 folder build by Portisch using Web Gui File Upload (#2886)
* Add command RfRaw to control Portisch firmware features
* Add support for I2C temperature sensor LM75AD (#2909)
@ -35,52 +72,6 @@
* Add decimal values support for commands ADD, SUB, MULT and SCALE (#3083, #3089)
* Add support for bitflags SetOption50 .. SetOption81 (#3118)
*
* 5.14.0b
* Add Console Commands to send KNX Commands
usage: KnxTx_Cmnd[slot] command
where [slot] is any of the 5 slots on the KNX Menu and command is 0 or 1
example: KnxTx_Cmnd1 0
* Add Console Commands to send KNX Values
usage: KnxTx_Val[slot] value
where [slot] is any of the 5 slots on the KNX Menu and value is a number
example: KnxTx_Val1 35
* Add Slots on the KNX Web Menu to select Group Addess to send data from console commands
* Add Events to trigger rules when a command is received from KNX
usage on rules as: event#KnxRx_Cmnd[slot]
where [slot] is any of the 5 slots on the KNX Menu
example: rule on event#KnxRx_Cmnd1 do VAR1 %value% endon
(where %value% can be 0 or 1)
* Add Events to trigger rules when received read requests from KNX
usage on rules as: event#KnxRx_Req[slot]
where [slot] is any of the 5 slots on the KNX Menu
example: rule on event#KnxRx_Req1 do KnxTx_Val1 35 endon
* Add Slots on the KNX Web Menu to select Group Addess to receive data to trigger rules
* Add two rule sets of 511 characters using commands rule1, rule2 and rule3
* Add Ukranian language file
* Add rule support for IrReceive and RfReceive (#2758)
* Add command WebSend [<host>(:<port>,<user>:<password>)] <command> (#2821)
* Add source information to command execution to be shown with logging option 3 (#2843)
* Fix some Pow R2 and S31 checksum errors (#1907)
* Fix Hardware Watchdog restart when using event command (#2853)
*
* 5.14.0a
* Add feature information to Status 4
* Add tools folder with python script decode-status.py for decoding some status fields like SetOption and Features
* Add Eastron SDM630 energy meter by Gennaro Tortone (#2735)
* Add KNX communication enhancement by Adrian Scillato (#2742)
* Add KNX energy data by Adrian Scillato (#2750)
* Add python script fw-server.py in tools folder to create a simple OTA server by Gennaro Tortone (#2759)
* Add rules %mem1% to %mem5% variable names storing data in flash (#2780)
* Add rules test on %varx% or %memx% (#2780)
* Add optional token %id% substituting the unique MAC address to fulltopic by Michael Graf (#2794)
* Fix display selection of un-available GPIO options in Module Configuration webpage (#2718)
* Fix timer re-trigger within one minute after restart (#2744)
* Fix IRSend not accepting data value of 0 by David Conran (#2751)
* Fix vars on rules by Adrian Scillato (#2769)
* Fix bug in KNX menu by Adrian Scillato (#2770)
* Fix anomalies in rules (#2778)
* Fix HUE bridge V1 software version by Heiko Krupp (#2788)
*
* 5.14.0 20180515
* Update language files
* Update TasmotaSerial to 2.0.0 allowing Hardware Serial Fallback when correct connections are configured

View File

@ -471,6 +471,7 @@ const char S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s%d\":\"%d
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";
const char JSON_SNS_TEMP[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
const char JSON_SNS_TEMPHUM[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}";
const char S_LOG_I2C_FOUND_AT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x";

View File

@ -95,6 +95,8 @@ typedef unsigned long power_t; // Power (Relay) type
#define LOGSZ 512 // Max number of characters in log
#define MIN_MESSZ 893 // Min number of characters in MQTT message
#define SENSOR_MAX_MISS 5 // Max number of missed sensor reads before deciding it's offline
#ifdef USE_MQTT_TLS
#define WEB_LOG_SIZE 2000 // Max number of characters in weblog
#else

View File

@ -177,7 +177,7 @@ uint8_t multiwindow[MAX_KEYS] = { 0 }; // Max time between button presses t
uint8_t multipress[MAX_KEYS] = { 0 }; // Number of button presses within multiwindow
uint8_t lastwallswitch[MAX_SWITCHES]; // Last wall switch states
uint8_t holdwallswitch[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold
uint8_t virtualswitch[MAX_SWITCHES] = { 0 }; // Virtual switch states
uint8_t virtualswitch[MAX_SWITCHES]; // Virtual switch states
mytmplt my_module; // Active copy of Module name and GPIOs
uint8_t pin[GPIO_MAX]; // Possible pin configurations
@ -1734,7 +1734,7 @@ void SwitchHandler(byte mode)
uint8_t switchflag;
for (byte i = 0; i < MAX_SWITCHES; i++) {
if (pin[GPIO_SWT1 +i] < 99) {
if ((pin[GPIO_SWT1 +i] < 99) || (mode)) {
if (holdwallswitch[i]) {
holdwallswitch[i]--;
@ -2390,10 +2390,13 @@ void GpioInit()
}
}
for (byte i = 0; i < MAX_SWITCHES; i++) {
lastwallswitch[i] = 1; // Init global to virtual switch state;
if (pin[GPIO_SWT1 +i] < 99) {
pinMode(pin[GPIO_SWT1 +i], (16 == pin[GPIO_SWT1 +i]) ? INPUT_PULLDOWN_16 :INPUT_PULLUP);
lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // set global now so doesn't change the saved power state on first switch check
lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // Set global now so doesn't change the saved power state on first switch check
}
virtualswitch[i] = lastwallswitch[i];
}
#ifdef USE_WS2812

View File

@ -2080,6 +2080,12 @@ void AddLogSerial(byte loglevel)
AddLogSerial(loglevel, (uint8_t*)serial_in_buffer, serial_in_byte_counter);
}
void AddLogMissed(char *sensor, uint8_t misses)
{
snprintf_P(log_data, sizeof(log_data), PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses);
AddLog(LOG_LEVEL_DEBUG);
}
/*********************************************************************************************\
*
\*********************************************************************************************/

View File

@ -271,14 +271,17 @@ boolean DomoticzCommand()
boolean DomoticzSendKey(byte key, byte device, byte state, byte svalflg)
{
if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
(key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off");
MqttPublish(domoticz_in_topic);
return 1;
} else {
return 0;
boolean result = 0;
if (device <= MAX_DOMOTICZ_IDX) {
if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
(key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off");
MqttPublish(domoticz_in_topic);
result = 1;
}
}
return result;
}
/*********************************************************************************************\

View File

@ -26,9 +26,10 @@
#define W1_CONVERT_TEMP 0x44
#define W1_READ_SCRATCHPAD 0xBE
float ds18b20_last_temperature = 0;
uint16_t ds18b20_last_result = 0;
float ds18b20_temperature = 0;
uint8_t ds18b20_valid = 0;
uint8_t ds18x20_pin = 0;
char ds18b20_types[] = "DS18B20";
/*********************************************************************************************\
* Embedded stripped and tuned OneWire library
@ -126,12 +127,7 @@ boolean OneWireCrc8(uint8_t *addr)
/********************************************************************************************/
void Ds18x20Init()
{
ds18x20_pin = pin[GPIO_DSB];
}
void Ds18x20Convert()
void Ds18b20Convert()
{
OneWireReset();
OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus
@ -139,25 +135,16 @@ void Ds18x20Convert()
// delay(750); // 750ms should be enough for 12bit conv
}
boolean Ds18b20Read(float &t)
boolean Ds18b20Read()
{
uint8_t data[9];
int8_t sign = 1;
if (!ds18b20_last_temperature) {
t = NAN;
} else {
ds18b20_last_result++;
if (ds18b20_last_result > 4) { // Reset after 4 misses
ds18b20_last_temperature = NAN;
}
t = ds18b20_last_temperature;
}
if (ds18b20_valid) { ds18b20_valid--; }
/*
if (!OneWireReadBit()) { //check measurement end
if (!OneWireReadBit()) { // Check end of measurement
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_BUSY));
return !isnan(t);
return;
}
*/
for (uint8_t retry = 0; retry < 3; retry++) {
@ -173,44 +160,55 @@ boolean Ds18b20Read(float &t)
temp12 = (~temp12) +1;
sign = -1;
}
t = ConvertTemp(sign * temp12 * 0.0625);
ds18b20_last_result = 0;
}
if (!isnan(t)) {
ds18b20_last_temperature = t;
ds18b20_temperature = ConvertTemp(sign * temp12 * 0.0625);
ds18b20_valid = SENSOR_MAX_MISS;
return true;
}
}
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR));
return !isnan(t);
return false;
}
/********************************************************************************************/
void Ds18b20EverySecond()
{
ds18x20_pin = pin[GPIO_DSB];
if (uptime &1) {
// 2mS
Ds18b20Convert(); // Start conversion, takes up to one second
} else {
// 12mS
if (!Ds18b20Read()) { // Read temperature
AddLogMissed(ds18b20_types, ds18b20_valid);
}
}
}
void Ds18b20Show(boolean json)
{
float t;
if (Ds18b20Read(t)) { // Check if read failed
if (ds18b20_valid) { // Check for valid temperature
char temperature[10];
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(ds18b20_temperature, Settings.flag2.temperature_resolution, temperature);
if(json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18B20\":{\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, temperature);
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMP, mqtt_data, ds18b20_types, temperature);
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzSensor(DZ_TEMP, temperature);
if (0 == tele_period) {
DomoticzSensor(DZ_TEMP, temperature);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, t);
KnxSensor(KNX_TEMPERATURE, ds18b20_temperature);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, "DS18B20", temperature, TempUnit());
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, ds18b20_types, temperature, TempUnit());
#endif // USE_WEBSERVER
}
}
Ds18x20Convert(); // Start conversion, takes up to one second
}
/*********************************************************************************************\
@ -225,11 +223,8 @@ boolean Xsns05(byte function)
if (pin[GPIO_DSB] < 99) {
switch (function) {
case FUNC_INIT:
Ds18x20Init();
break;
case FUNC_PREP_BEFORE_TELEPERIOD:
Ds18x20Convert(); // Start conversion, takes up to one second
case FUNC_EVERY_SECOND:
Ds18b20EverySecond();
break;
case FUNC_JSON_APPEND:
Ds18b20Show(1);

View File

@ -21,6 +21,7 @@
/*********************************************************************************************\
* DS18B20 - Temperature - Multiple sensors
\*********************************************************************************************/
//#define USE_DS18x20_RECONFIGURE // When sensor is lost keep retrying or re-configure
#define DS18S20_CHIPID 0x10 // +/-0.5C 9-bit
#define DS1822_CHIPID 0x22 // +/-2C 12-bit
@ -38,11 +39,16 @@
const char kDs18x20Types[] PROGMEM = "DS18x20|DS18S20|DS1822|DS18B20|MAX31850";
uint8_t ds18x20_chipids[] = { 0, DS18S20_CHIPID, DS1822_CHIPID, DS18B20_CHIPID, MAX31850_CHIPID };
uint8_t ds18x20_address[DS18X20_MAX_SENSORS][8];
uint8_t ds18x20_index[DS18X20_MAX_SENSORS] = { 0 };
struct DS18X20STRUCT {
uint8_t address[8];
uint8_t index;
uint8_t valid;
float temperature;
} ds18x20_sensor[DS18X20_MAX_SENSORS];
uint8_t ds18x20_sensors = 0;
uint8_t ds18x20_pin = 0;
char ds18x20_types[9];
char ds18x20_types[12];
/*********************************************************************************************\
* Embedded tuned OneWire library
@ -246,28 +252,29 @@ void Ds18x20Init()
uint64_t ids[DS18X20_MAX_SENSORS];
ds18x20_pin = pin[GPIO_DSB];
OneWireResetSearch();
for (ds18x20_sensors = 0; ds18x20_sensors < DS18X20_MAX_SENSORS; ds18x20_sensors) {
if (!OneWireSearch(ds18x20_address[ds18x20_sensors])) {
if (!OneWireSearch(ds18x20_sensor[ds18x20_sensors].address)) {
break;
}
if (OneWireCrc8(ds18x20_address[ds18x20_sensors]) &&
((ds18x20_address[ds18x20_sensors][0] == DS18S20_CHIPID) ||
(ds18x20_address[ds18x20_sensors][0] == DS1822_CHIPID) ||
(ds18x20_address[ds18x20_sensors][0] == DS18B20_CHIPID) ||
(ds18x20_address[ds18x20_sensors][0] == MAX31850_CHIPID))) {
ds18x20_index[ds18x20_sensors] = ds18x20_sensors;
ids[ds18x20_sensors] = ds18x20_address[ds18x20_sensors][0]; // Chip id
if (OneWireCrc8(ds18x20_sensor[ds18x20_sensors].address) &&
((ds18x20_sensor[ds18x20_sensors].address[0] == DS18S20_CHIPID) ||
(ds18x20_sensor[ds18x20_sensors].address[0] == DS1822_CHIPID) ||
(ds18x20_sensor[ds18x20_sensors].address[0] == DS18B20_CHIPID) ||
(ds18x20_sensor[ds18x20_sensors].address[0] == MAX31850_CHIPID))) {
ds18x20_sensor[ds18x20_sensors].index = ds18x20_sensors;
ids[ds18x20_sensors] = ds18x20_sensor[ds18x20_sensors].address[0]; // Chip id
for (uint8_t j = 6; j > 0; j--) {
ids[ds18x20_sensors] = ids[ds18x20_sensors] << 8 | ds18x20_address[ds18x20_sensors][j];
ids[ds18x20_sensors] = ids[ds18x20_sensors] << 8 | ds18x20_sensor[ds18x20_sensors].address[j];
}
ds18x20_sensors++;
}
}
for (uint8_t i = 0; i < ds18x20_sensors; i++) {
for (uint8_t j = i + 1; j < ds18x20_sensors; j++) {
if (ids[ds18x20_index[i]] > ids[ds18x20_index[j]]) { // Sort ascending
std::swap(ds18x20_index[i], ds18x20_index[j]);
if (ids[ds18x20_sensor[i].index] > ids[ds18x20_sensor[j].index]) { // Sort ascending
std::swap(ds18x20_sensor[i].index, ds18x20_sensor[j].index);
}
}
}
@ -283,7 +290,7 @@ void Ds18x20Convert()
// delay(750); // 750ms should be enough for 12bit conv
}
boolean Ds18x20Read(uint8_t sensor, float &t)
bool Ds18x20Read(uint8_t sensor)
{
uint8_t data[9];
int8_t sign = 1;
@ -291,17 +298,17 @@ boolean Ds18x20Read(uint8_t sensor, float &t)
int16_t temp14 = 0;
float temp9 = 0.0;
t = NAN;
uint8_t index = ds18x20_sensor[sensor].index;
if (ds18x20_sensor[index].valid) { ds18x20_sensor[index].valid--; }
for (uint8_t retry = 0; retry < 3; retry++) {
OneWireReset();
OneWireSelect(ds18x20_address[ds18x20_index[sensor]]);
OneWireSelect(ds18x20_sensor[index].address);
OneWireWrite(W1_READ_SCRATCHPAD);
for (uint8_t i = 0; i < 9; i++) {
data[i] = OneWireRead();
}
if (OneWireCrc8(data)) {
switch(ds18x20_address[ds18x20_index[sensor]][0]) {
switch(ds18x20_sensor[index].address[0]) {
case DS18S20_CHIPID:
if (data[1] > 0x80) {
data[0] = (~data[0]) +1;
@ -312,19 +319,20 @@ boolean Ds18x20Read(uint8_t sensor, float &t)
} else {
temp9 = (data[0] >> 1) * sign;
}
t = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0));
break;
ds18x20_sensor[index].temperature = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0));
ds18x20_sensor[index].valid = SENSOR_MAX_MISS;
return true;
case DS1822_CHIPID:
case DS18B20_CHIPID:
if (data[4] != 0x7F) {
data[4] = 0x7F; // Set resolution to 12-bit
OneWireReset();
OneWireSelect(ds18x20_address[ds18x20_index[sensor]]);
OneWireSelect(ds18x20_sensor[index].address);
OneWireWrite(W1_WRITE_SCRATCHPAD);
OneWireWrite(data[2]); // Th Register
OneWireWrite(data[3]); // Tl Register
OneWireWrite(data[4]); // Configuration Register
OneWireSelect(ds18x20_address[ds18x20_index[sensor]]);
OneWireSelect(ds18x20_sensor[index].address);
OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM
}
temp12 = (data[1] << 8) + data[0];
@ -332,72 +340,99 @@ boolean Ds18x20Read(uint8_t sensor, float &t)
temp12 = (~temp12) +1;
sign = -1;
}
t = ConvertTemp(sign * temp12 * 0.0625); // Divide by 16
break;
ds18x20_sensor[index].temperature = ConvertTemp(sign * temp12 * 0.0625); // Divide by 16
ds18x20_sensor[index].valid = SENSOR_MAX_MISS;
return true;
case MAX31850_CHIPID:
temp14 = (data[1] << 8) + (data[0] & 0xFC);
t = ConvertTemp(temp14 * 0.0625); // Divide by 16
break;
ds18x20_sensor[index].temperature = ConvertTemp(temp14 * 0.0625); // Divide by 16
ds18x20_sensor[index].valid = SENSOR_MAX_MISS;
return true;
}
}
if (!isnan(t)) {
return true;
}
}
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR));
return false;
}
void Ds18x20Name(uint8_t sensor)
{
uint8_t index = sizeof(ds18x20_chipids);
while (index) {
if (ds18x20_sensor[ds18x20_sensor[sensor].index].address[0] == ds18x20_chipids[index]) {
break;
}
index--;
}
GetTextIndexed(ds18x20_types, sizeof(ds18x20_types), index, kDs18x20Types);
if (ds18x20_sensors > 1) {
snprintf_P(ds18x20_types, sizeof(ds18x20_types), PSTR("%s-%d"), ds18x20_types, sensor +1);
}
}
/********************************************************************************************/
void Ds18x20EverySecond()
{
if (uptime &1) {
// 2mS
Ds18x20Convert(); // Start conversion, takes up to one second
} else {
for (uint8_t i = 0; i < ds18x20_sensors; i++) {
// 12mS per device
if (!Ds18x20Read(i)) { // Read temperature
Ds18x20Name(i);
AddLogMissed(ds18x20_types, ds18x20_sensor[ds18x20_sensor[i].index].valid);
#ifdef USE_DS18x20_RECONFIGURE
if (!ds18x20_sensor[ds18x20_sensor[i].index].valid) {
memset(&ds18x20_sensor, 0, sizeof(ds18x20_sensor));
Ds18x20Init(); // Re-configure
}
#endif // USE_DS18x20_RECONFIGURE
}
}
}
}
void Ds18x20Show(boolean json)
{
char temperature[10];
char stemp[12];
float t;
bool domoticz_flag = true;
for (uint8_t i = 0; i < ds18x20_sensors; i++) {
if (Ds18x20Read(i, t)) { // Check if read failed
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
uint8_t index = ds18x20_sensor[i].index;
uint8_t index = sizeof(ds18x20_chipids);
while (index) {
if (ds18x20_address[ds18x20_index[i]][0] == ds18x20_chipids[index]) {
break;
}
index--;
}
GetTextIndexed(ds18x20_types, sizeof(ds18x20_types), index, kDs18x20Types);
if (ds18x20_sensor[index].valid) { // Check for valid temperature
dtostrfd(ds18x20_sensor[index].temperature, Settings.flag2.temperature_resolution, temperature);
Ds18x20Name(i);
snprintf_P(stemp, sizeof(stemp), PSTR("%s-%d"), ds18x20_types, i +1);
if (json) {
if (1 == ds18x20_sensors) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, ds18x20_types, temperature);
} else {
char address[17];
for (byte j = 0; j < 6; j++) {
sprintf(address+2*j, "%02X", ds18x20_address[ds18x20_index[i]][6-j]); // Skip sensor type and crc
sprintf(address+2*j, "%02X", ds18x20_sensor[index].address[6-j]); // Skip sensor type and crc
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, stemp, address, temperature);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), mqtt_data, ds18x20_types, address, temperature);
}
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && domoticz_flag) {
if ((0 == tele_period) && (0 == i)) {
DomoticzSensor(DZ_TEMP, temperature);
domoticz_flag = false;
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if ((0 == tele_period) && (0 == i)) {
KnxSensor(KNX_TEMPERATURE, t);
KnxSensor(KNX_TEMPERATURE, ds18x20_sensor[index].temperature);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, (1 == ds18x20_sensors) ? ds18x20_types : stemp, temperature, TempUnit());
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, ds18x20_types, temperature, TempUnit());
#endif // USE_WEBSERVER
}
}
}
Ds18x20Convert(); // Start conversion, takes up to one second
}
/*********************************************************************************************\
@ -415,8 +450,8 @@ boolean Xsns05(byte function)
case FUNC_INIT:
Ds18x20Init();
break;
case FUNC_PREP_BEFORE_TELEPERIOD:
Ds18x20Convert(); // Start conversion, takes up to one second
case FUNC_EVERY_SECOND:
Ds18x20EverySecond();
break;
case FUNC_JSON_APPEND:
Ds18x20Show(1);

View File

@ -28,7 +28,6 @@
#define DHT_MAX_SENSORS 3
#define DHT_MAX_RETRY 8
#define MIN_INTERVAL 2000
uint32_t dht_max_cycles;
uint8_t dht_data[5];
@ -63,15 +62,10 @@ int32_t DhtExpectPulse(byte sensor, bool level)
return count;
}
void DhtRead(byte sensor)
boolean DhtRead(byte sensor)
{
int32_t cycles[80];
uint32_t currenttime = millis();
if ((currenttime - Dht[sensor].lastreadtime) < MIN_INTERVAL) {
return;
}
Dht[sensor].lastreadtime = currenttime;
uint8_t error = 0;
dht_data[0] = dht_data[1] = dht_data[2] = dht_data[3] = dht_data[4] = 0;
@ -99,27 +93,27 @@ void DhtRead(byte sensor)
delayMicroseconds(10);
if (-1 == DhtExpectPulse(sensor, LOW)) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_LOW " " D_PULSE));
Dht[sensor].lastresult++;
return;
error = 1;
}
if (-1 == DhtExpectPulse(sensor, HIGH)) {
else if (-1 == DhtExpectPulse(sensor, HIGH)) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_HIGH " " D_PULSE));
Dht[sensor].lastresult++;
return;
error = 1;
}
for (int i = 0; i < 80; i += 2) {
cycles[i] = DhtExpectPulse(sensor, LOW);
cycles[i+1] = DhtExpectPulse(sensor, HIGH);
else {
for (int i = 0; i < 80; i += 2) {
cycles[i] = DhtExpectPulse(sensor, LOW);
cycles[i+1] = DhtExpectPulse(sensor, HIGH);
}
}
interrupts();
if (error) { return false; }
for (int i = 0; i < 40; ++i) {
int32_t lowCycles = cycles[2*i];
int32_t highCycles = cycles[2*i+1];
if ((-1 == lowCycles) || (-1 == highCycles)) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_PULSE));
Dht[sensor].lastresult++;
return;
return false;
}
dht_data[i/8] <<= 1;
if (highCycles > lowCycles) {
@ -127,57 +121,43 @@ void DhtRead(byte sensor)
}
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DHT D_RECEIVED " %02X, %02X, %02X, %02X, %02X =? %02X"),
dht_data[0], dht_data[1], dht_data[2], dht_data[3], dht_data[4], (dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) & 0xFF);
AddLog(LOG_LEVEL_DEBUG);
if (dht_data[4] == ((dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) & 0xFF)) {
Dht[sensor].lastresult = 0;
} else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_CHECKSUM_FAILURE));
Dht[sensor].lastresult++;
uint8_t checksum = (dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) & 0xFF;
if (dht_data[4] != checksum) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DHT D_CHECKSUM_FAILURE " %02X, %02X, %02X, %02X, %02X =? %02X"),
dht_data[0], dht_data[1], dht_data[2], dht_data[3], dht_data[4], checksum);
AddLog(LOG_LEVEL_DEBUG);
return false;
}
return true;
}
boolean DhtReadTempHum(byte sensor, float &t, float &h)
void DhtReadTempHum(byte sensor)
{
if (NAN == Dht[sensor].h) {
t = NAN;
h = NAN;
} else {
if (Dht[sensor].lastresult > DHT_MAX_RETRY) { // Reset after 8 misses
Dht[sensor].t = NAN;
Dht[sensor].h = NAN;
}
t = Dht[sensor].t;
h = Dht[sensor].h;
if ((NAN == Dht[sensor].h) || (Dht[sensor].lastresult > DHT_MAX_RETRY)) { // Reset after 8 misses
Dht[sensor].t = NAN;
Dht[sensor].h = NAN;
}
DhtRead(sensor);
if (!Dht[sensor].lastresult) {
if (DhtRead(sensor)) {
switch (Dht[sensor].type) {
case GPIO_DHT11:
h = dht_data[0];
t = dht_data[2];
Dht[sensor].h = dht_data[0];
Dht[sensor].t = dht_data[2] + ((float)dht_data[3] * 0.1f); // Issue #3164
break;
case GPIO_DHT22:
case GPIO_SI7021:
h = ((dht_data[0] << 8) | dht_data[1]) * 0.1;
t = (((dht_data[2] & 0x7F) << 8 ) | dht_data[3]) * 0.1;
Dht[sensor].h = ((dht_data[0] << 8) | dht_data[1]) * 0.1;
Dht[sensor].t = (((dht_data[2] & 0x7F) << 8 ) | dht_data[3]) * 0.1;
if (dht_data[2] & 0x80) {
t *= -1;
Dht[sensor].t *= -1;
}
break;
}
t = ConvertTemp(t);
if (!isnan(t)) {
Dht[sensor].t = t;
}
if (!isnan(h)) {
Dht[sensor].h = h;
}
Dht[sensor].t = ConvertTemp(Dht[sensor].t);
Dht[sensor].lastresult = 0;
} else {
Dht[sensor].lastresult++;
}
return (!isnan(t) && !isnan(h));
}
boolean DhtSetup(byte pin, byte type)
@ -210,41 +190,46 @@ void DhtInit()
}
}
void DhtEverySecond()
{
if (uptime &1) {
// <1mS
DhtReadPrep();
} else {
for (byte i = 0; i < dht_sensors; i++) {
// DHT11 and AM2301 25mS per sensor, SI7021 5mS per sensor
DhtReadTempHum(i);
}
}
}
void DhtShow(boolean json)
{
char temperature[10];
char humidity[10];
byte dsxflg = 0;
for (byte i = 0; i < dht_sensors; i++) {
float t = NAN;
float h = NAN;
if (DhtReadTempHum(i, t, h)) { // Read temperature
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
dtostrfd(Dht[i].t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(Dht[i].h, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, Dht[i].stype, temperature, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, Dht[i].stype, temperature, humidity);
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && !dsxflg) {
DomoticzTempHumSensor(temperature, humidity);
dsxflg++;
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, t);
KnxSensor(KNX_HUMIDITY, h);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, Dht[i].stype, temperature, TempUnit());
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, Dht[i].stype, humidity);
#endif // USE_WEBSERVER
if ((0 == tele_period) && (0 == i)) {
DomoticzTempHumSensor(temperature, humidity);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if ((0 == tele_period) && (0 == i)) {
KnxSensor(KNX_TEMPERATURE, Dht[i].t);
KnxSensor(KNX_HUMIDITY, Dht[i].h);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, Dht[i].stype, temperature, TempUnit());
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, Dht[i].stype, humidity);
#endif // USE_WEBSERVER
}
}
}
@ -264,8 +249,8 @@ boolean Xsns06(byte function)
case FUNC_INIT:
DhtInit();
break;
case FUNC_PREP_BEFORE_TELEPERIOD:
DhtReadPrep();
case FUNC_EVERY_SECOND:
DhtEverySecond();
break;
case FUNC_JSON_APPEND:
DhtShow(1);

View File

@ -37,6 +37,10 @@ enum {
uint8_t sht_sda_pin;
uint8_t sht_scl_pin;
uint8_t sht_type = 0;
char sht_types[] = "SHT1X";
uint8_t sht_valid = 0;
float sht_temperature = 0;
float sht_humidity = 0;
boolean ShtReset()
{
@ -119,46 +123,32 @@ int ShtReadData()
return val;
}
boolean ShtReadTempHum(float &t, float &h)
boolean ShtRead()
{
float tempRaw;
float humRaw;
float rhLinear;
if (sht_valid) { sht_valid--; }
if (!ShtReset()) { return false; }
if (!ShtSendCommand(SHT1X_CMD_MEASURE_TEMP)) { return false; }
if (!ShtAwaitResult()) { return false; }
float tempRaw = ShtReadData();
if (!ShtSendCommand(SHT1X_CMD_MEASURE_RH)) { return false; }
if (!ShtAwaitResult()) { return false; }
float humRaw = ShtReadData();
t = NAN;
h = NAN;
if (!ShtReset()) {
return false;
}
if (!ShtSendCommand(SHT1X_CMD_MEASURE_TEMP)) {
return false;
}
if (!ShtAwaitResult()) {
return false;
}
tempRaw = ShtReadData();
// Temperature conversion coefficients from SHT1X datasheet for version 4
const float d1 = -39.7; // 3.5V
const float d2 = 0.01; // 14-bit
t = d1 + (tempRaw * d2);
if (!ShtSendCommand(SHT1X_CMD_MEASURE_RH)) {
return false;
}
if (!ShtAwaitResult()) {
return false;
}
humRaw = ShtReadData();
// Temperature conversion coefficients from SHT1X datasheet for version 4
sht_temperature = d1 + (tempRaw * d2);
const float c1 = -2.0468;
const float c2 = 0.0367;
const float c3 = -1.5955E-6;
const float t1 = 0.01;
const float t2 = 0.00008;
rhLinear = c1 + c2 * humRaw + c3 * humRaw * humRaw;
h = (t - 25) * (t1 + t2 * humRaw) + rhLinear;
t = ConvertTemp(t);
return (!isnan(t) && !isnan(h));
float rhLinear = c1 + c2 * humRaw + c3 * humRaw * humRaw;
sht_humidity = (sht_temperature - 25) * (t1 + t2 * humRaw) + rhLinear;
sht_temperature = ConvertTemp(sht_temperature);
sht_valid = SENSOR_MAX_MISS;
return true;
}
/********************************************************************************************/
@ -169,12 +159,9 @@ void ShtDetect()
return;
}
float t;
float h;
sht_sda_pin = pin[GPIO_I2C_SDA];
sht_scl_pin = pin[GPIO_I2C_SCL];
if (ShtReadTempHum(t, h)) {
if (ShtRead()) {
sht_type = 1;
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_SHT1X_FOUND));
} else {
@ -183,38 +170,44 @@ void ShtDetect()
}
}
void ShtEverySecond()
{
if (sht_type && !(uptime %4)) { // Update every 4 seconds
// 344mS
if (!ShtRead()) {
AddLogMissed(sht_types, sht_valid);
// if (!sht_valid) { sht_type = 0; }
}
}
}
void ShtShow(boolean json)
{
if (sht_type) {
float t;
float h;
if (sht_valid) {
char temperature[10];
char humidity[10];
if (ShtReadTempHum(t, h)) {
char temperature[10];
char humidity[10];
dtostrfd(sht_temperature, Settings.flag2.temperature_resolution, temperature);
dtostrfd(sht_humidity, Settings.flag2.humidity_resolution, humidity);
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, "SHT1X", temperature, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, sht_types, temperature, humidity);
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzTempHumSensor(temperature, humidity);
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, t);
KnxSensor(KNX_HUMIDITY, h);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, "SHT1X", temperature, TempUnit());
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, "SHT1X", humidity);
#endif // USE_WEBSERVER
if (0 == tele_period) {
DomoticzTempHumSensor(temperature, humidity);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, sht_temperature);
KnxSensor(KNX_HUMIDITY, sht_humidity);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, sht_types, temperature, TempUnit());
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, sht_types, humidity);
#endif // USE_WEBSERVER
}
}
}
@ -231,9 +224,13 @@ boolean Xsns07(byte function)
if (i2c_flg) {
switch (function) {
case FUNC_PREP_BEFORE_TELEPERIOD:
// case FUNC_PREP_BEFORE_TELEPERIOD: // As this is not a real I2C device it may interfere with other sensors
case FUNC_INIT: // Move detection to restart only removing interference
ShtDetect();
break;
case FUNC_EVERY_SECOND:
ShtEverySecond();
break;
case FUNC_JSON_APPEND:
ShtShow(1);
break;

View File

@ -58,8 +58,11 @@ const char kHtuTypes[] PROGMEM = "HTU21|SI7013|SI7020|SI7021|T/RH?";
uint8_t htu_address;
uint8_t htu_type = 0;
uint8_t delay_temp;
uint8_t delay_humidity = 50;
uint8_t htu_delay_temp;
uint8_t htu_delay_humidity = 50;
uint8_t htu_valid = 0;
float htu_temperature = 0;
float htu_humidity = 0;
char htu_types[7];
uint8_t HtuCheckCrc8(uint16_t data)
@ -135,87 +138,62 @@ void HtuInit()
HtuSetResolution(HTU21_RES_RH12_T14);
}
float HtuReadHumidity(void)
boolean HtuRead()
{
uint8_t checksum = 0;
uint16_t sensorval = 0;
float humidity = 0.0;
Wire.beginTransmission(HTU21_ADDR);
Wire.write(HTU21_READHUM);
if (Wire.endTransmission() != 0) {
return 0.0; // In case of error
}
delay(delay_humidity); // Sensor time at max resolution
Wire.requestFrom(HTU21_ADDR, 3);
if (3 <= Wire.available()) {
sensorval = Wire.read() << 8; // MSB
sensorval |= Wire.read(); // LSB
checksum = Wire.read();
}
if (HtuCheckCrc8(sensorval) != checksum) {
return 0.0; // Checksum mismatch
}
sensorval ^= 0x02; // clear status bits
humidity = 0.001907 * (float)sensorval - 6;
if (humidity > 100) {
return 100.0;
}
if (humidity < 0) {
return 0.01;
}
return humidity;
}
float HtuReadTemperature()
{
uint8_t checksum=0;
uint16_t sensorval=0;
float t;
if (htu_valid) { htu_valid--; }
Wire.beginTransmission(HTU21_ADDR);
Wire.write(HTU21_READTEMP);
if (Wire.endTransmission() != 0) {
return 0.0; // In case of error
}
delay(delay_temp); // Sensor time at max resolution
if (Wire.endTransmission() != 0) { return false; } // In case of error
delay(htu_delay_temp); // Sensor time at max resolution
Wire.requestFrom(HTU21_ADDR, 3);
if (3 == Wire.available()) {
sensorval = Wire.read() << 8; // MSB
sensorval |= Wire.read(); // LSB
sensorval = Wire.read() << 8; // MSB
sensorval |= Wire.read(); // LSB
checksum = Wire.read();
}
if (HtuCheckCrc8(sensorval) != checksum) {
return 0.0; // Checksum mismatch
if (HtuCheckCrc8(sensorval) != checksum) { return false; } // Checksum mismatch
htu_temperature = ConvertTemp(0.002681 * (float)sensorval - 46.85);
Wire.beginTransmission(HTU21_ADDR);
Wire.write(HTU21_READHUM);
if (Wire.endTransmission() != 0) { return false; } // In case of error
delay(htu_delay_humidity); // Sensor time at max resolution
Wire.requestFrom(HTU21_ADDR, 3);
if (3 <= Wire.available()) {
sensorval = Wire.read() << 8; // MSB
sensorval |= Wire.read(); // LSB
checksum = Wire.read();
}
if (HtuCheckCrc8(sensorval) != checksum) { return false; } // Checksum mismatch
sensorval ^= 0x02; // clear status bits
htu_humidity = 0.001907 * (float)sensorval - 6;
if (htu_humidity > 100) { htu_humidity = 100.0; }
if (htu_humidity < 0) { htu_humidity = 0.01; }
if ((0.00 == htu_humidity) && (0.00 == htu_temperature)) {
htu_humidity = 0.0;
}
if ((htu_temperature > 0.00) && (htu_temperature < 80.00)) {
htu_humidity = (-0.15) * (25 - htu_temperature) + htu_humidity;
}
t = ConvertTemp(0.002681 * (float)sensorval - 46.85);
return t;
}
float HtuCompensatedHumidity(float humidity, float temperature)
{
if(humidity == 0.00 && temperature == 0.00) {
return 0.0;
}
if(temperature > 0.00 && temperature < 80.00) {
return (-0.15)*(25-temperature)+humidity;
}
return humidity;
htu_valid = SENSOR_MAX_MISS;
return true;
}
/********************************************************************************************/
void HtuDetect()
{
if (htu_type) {
return;
}
if (htu_type) { return; }
htu_address = HTU21_ADDR;
htu_type = HtuReadDeviceId();
@ -224,8 +202,8 @@ void HtuDetect()
HtuInit();
switch (htu_type) {
case HTU21_CHIPID:
delay_temp = 50;
delay_humidity = 16;
htu_delay_temp = 50;
htu_delay_humidity = 16;
break;
case SI7021_CHIPID:
index++; // 3
@ -233,13 +211,13 @@ void HtuDetect()
index++; // 2
case SI7013_CHIPID:
index++; // 1
delay_temp = 12;
delay_humidity = 23;
htu_delay_temp = 12;
htu_delay_humidity = 23;
break;
default:
index = 4;
delay_temp = 50;
delay_humidity = 23;
htu_delay_temp = 50;
htu_delay_humidity = 23;
}
GetTextIndexed(htu_types, sizeof(htu_types), index, kHtuTypes);
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, htu_types, htu_address);
@ -247,31 +225,45 @@ void HtuDetect()
}
}
void HtuEverySecond()
{
if (92 == (uptime %100)) {
// 1mS
HtuDetect();
}
else if (uptime &1) {
// HTU21: 68mS, SI70xx: 37mS
if (htu_type) {
if (!HtuRead()) {
AddLogMissed(htu_types, htu_valid);
// if (!htu_valid) { htu_type = 0; }
}
}
}
}
void HtuShow(boolean json)
{
if (htu_type) {
if (htu_valid) {
char temperature[10];
char humidity[10];
float t = HtuReadTemperature();
float h = HtuReadHumidity();
h = HtuCompensatedHumidity(h, t);
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
dtostrfd(htu_temperature, Settings.flag2.temperature_resolution, temperature);
dtostrfd(htu_humidity, Settings.flag2.humidity_resolution, humidity);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, htu_types, temperature, humidity);
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzTempHumSensor(temperature, humidity);
if (0 == tele_period) {
DomoticzTempHumSensor(temperature, humidity);
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, t);
KnxSensor(KNX_HUMIDITY, h);
KnxSensor(KNX_TEMPERATURE, htu_temperature);
KnxSensor(KNX_HUMIDITY, htu_humidity);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, htu_types, temperature, TempUnit());
@ -293,9 +285,12 @@ boolean Xsns08(byte function)
if (i2c_flg) {
switch (function) {
case FUNC_PREP_BEFORE_TELEPERIOD:
case FUNC_INIT:
HtuDetect();
break;
case FUNC_EVERY_SECOND:
HtuEverySecond();
break;
case FUNC_JSON_APPEND:
HtuShow(1);
break;

View File

@ -45,6 +45,11 @@ uint8_t bmp_type = 0;
uint8_t bmp_model = 0;
char bmp_name[7];
uint8_t bmp_valid = 0;
float bmp_temperature = 0.0;
float bmp_pressure = 0.0;
float bmp_humidity = 0.0;
/*********************************************************************************************\
* BMP085 and BME180
\*********************************************************************************************/
@ -78,7 +83,6 @@ int16_t cal_md;
uint16_t cal_ac4;
uint16_t cal_ac5;
uint16_t cal_ac6;
int32_t bmp180_b5 = 0;
boolean Bmp180Calibration()
{
@ -113,21 +117,15 @@ boolean Bmp180Calibration()
return true;
}
double Bmp180ReadTemperature()
void Bmp180Read()
{
I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE);
delay(5); // 5ms conversion time
int ut = I2cRead16(bmp_address, BMP180_REG_RESULT);
int32_t x1 = (ut - (int32_t)cal_ac6) * ((int32_t)cal_ac5) >> 15;
int32_t x2 = ((int32_t)cal_mc << 11) / (x1 + (int32_t)cal_md);
bmp180_b5 = x1 + x2;
return ((bmp180_b5 + 8) >> 4) / 10.0;
}
double Bmp180ReadPressure()
{
int32_t p;
int32_t xt1 = (ut - (int32_t)cal_ac6) * ((int32_t)cal_ac5) >> 15;
int32_t xt2 = ((int32_t)cal_mc << 11) / (xt1 + (int32_t)cal_md);
int32_t bmp180_b5 = xt1 + xt2;
bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0;
I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
@ -146,19 +144,18 @@ double Bmp180ReadPressure()
uint32_t b4 = ((uint32_t)cal_ac4 * (uint32_t)(x3 + 32768)) >> 15;
uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)(50000UL >> BMP180_OSS);
int32_t p;
if (b7 < 0x80000000) {
p = (b7 * 2) / b4;
}
else {
p = (b7 / b4) * 2;
}
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
p += ((x1 + x2 + (int32_t)3791) >> 4);
return p / 100.0; // convert to mbar
bmp_pressure = (float)p / 100.0; // convert to mbar
}
/*********************************************************************************************\
@ -215,8 +212,6 @@ struct BME280CALIBDATA
int8_t dig_H6;
} Bme280CalibrationData;
int32_t t_fine;
boolean Bmx280Calibrate()
{
// if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false;
@ -233,20 +228,6 @@ boolean Bmx280Calibrate()
Bme280CalibrationData.dig_P7 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P7);
Bme280CalibrationData.dig_P8 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P8);
Bme280CalibrationData.dig_P9 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P9);
/*
if (BME280_CHIPID == bmp_type) {
Bme280CalibrationData.dig_H1 = I2cRead8(bmp_address, BME280_REGISTER_DIG_H1);
Bme280CalibrationData.dig_H2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_H2);
Bme280CalibrationData.dig_H3 = I2cRead8(bmp_address, BME280_REGISTER_DIG_H3);
Bme280CalibrationData.dig_H4 = (I2cRead8(bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF);
Bme280CalibrationData.dig_H5 = (I2cRead8(bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp_address, BME280_REGISTER_DIG_H5) >> 4);
Bme280CalibrationData.dig_H6 = (int8_t)I2cRead8(bmp_address, BME280_REGISTER_DIG_H6);
// Set before CONTROL_meas (DS 5.4.3)
I2cWrite8(bmp_address, BME280_REGISTER_CONTROLHUMID, 0x05); // 16x oversampling (Adafruit)
}
I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
*/
if (BME280_CHIPID == bmp_type) { // #1051
Bme280CalibrationData.dig_H1 = I2cRead8(bmp_address, BME280_REGISTER_DIG_H1);
Bme280CalibrationData.dig_H2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_H2);
@ -267,62 +248,42 @@ boolean Bmx280Calibrate()
return true;
}
double Bme280ReadTemperature(void)
void Bme280Read(void)
{
int32_t var1;
int32_t var2;
int32_t adc_T = I2cRead24(bmp_address, BME280_REGISTER_TEMPDATA);
adc_T >>= 4;
var1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData.dig_T1 << 1))) * ((int32_t)Bme280CalibrationData.dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((int32_t)Bme280CalibrationData.dig_T1)) * ((adc_T >> 4) - ((int32_t)Bme280CalibrationData.dig_T1))) >> 12) *
int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData.dig_T1 << 1))) * ((int32_t)Bme280CalibrationData.dig_T2)) >> 11;
int32_t vart2 = (((((adc_T >> 4) - ((int32_t)Bme280CalibrationData.dig_T1)) * ((adc_T >> 4) - ((int32_t)Bme280CalibrationData.dig_T1))) >> 12) *
((int32_t)Bme280CalibrationData.dig_T3)) >> 14;
t_fine = var1 + var2;
double T = (t_fine * 5 + 128) >> 8;
return T / 100.0;
}
double Bme280ReadPressure(void)
{
int64_t var1;
int64_t var2;
int64_t p;
// Must be done first to get the t_fine variable set up
// Bme280ReadTemperature();
int32_t t_fine = vart1 + vart2;
float T = (t_fine * 5 + 128) >> 8;
bmp_temperature = T / 100.0;
int32_t adc_P = I2cRead24(bmp_address, BME280_REGISTER_PRESSUREDATA);
adc_P >>= 4;
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)Bme280CalibrationData.dig_P6;
int64_t var1 = ((int64_t)t_fine) - 128000;
int64_t var2 = var1 * var1 * (int64_t)Bme280CalibrationData.dig_P6;
var2 = var2 + ((var1 * (int64_t)Bme280CalibrationData.dig_P5) << 17);
var2 = var2 + (((int64_t)Bme280CalibrationData.dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)Bme280CalibrationData.dig_P3) >> 8) + ((var1 * (int64_t)Bme280CalibrationData.dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)Bme280CalibrationData.dig_P1) >> 33;
if (0 == var1) {
return 0; // avoid exception caused by division by zero
return; // avoid exception caused by division by zero
}
p = 1048576 - adc_P;
int64_t p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)Bme280CalibrationData.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)Bme280CalibrationData.dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)Bme280CalibrationData.dig_P7) << 4);
return (double)p / 25600.0;
}
bmp_pressure = (float)p / 25600.0;
double Bme280ReadHumidity(void)
{
int32_t v_x1_u32r;
// Must be done first to get the t_fine variable set up
// Bme280ReadTemperature();
if (BMP280_CHIPID == bmp_type) { return; }
int32_t adc_H = I2cRead16(bmp_address, BME280_REGISTER_HUMIDDATA);
v_x1_u32r = (t_fine - ((int32_t)76800));
int32_t v_x1_u32r = (t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData.dig_H4) << 20) -
(((int32_t)Bme280CalibrationData.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
(((((((v_x1_u32r * ((int32_t)Bme280CalibrationData.dig_H6)) >> 10) *
@ -332,8 +293,8 @@ double Bme280ReadHumidity(void)
((int32_t)Bme280CalibrationData.dig_H1)) >> 4));
v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
double h = (v_x1_u32r >> 12);
return h / 1024.0;
float h = (v_x1_u32r >> 12);
bmp_humidity = h / 1024.0;
}
#ifdef USE_BME680
@ -345,17 +306,14 @@ double Bme280ReadHumidity(void)
struct bme680_dev gas_sensor;
float bmp_gas_resistance = 0.0;
uint8_t bme680_state = 0;
static void BmeDelayMs(uint32_t ms)
{
delay(ms);
}
uint8_t bme680_state = 0;
float bme680_temperature;
float bme680_pressure;
float bme680_humidity;
float bme680_gas_resistance;
boolean Bme680Init()
{
gas_sensor.dev_id = bmp_address;
@ -400,7 +358,7 @@ boolean Bme680Init()
return true;
}
void Bme680PerformReading()
void Bme680Read()
{
int8_t rslt = BME680_OK;
@ -424,14 +382,14 @@ void Bme680PerformReading()
rslt = bme680_get_sensor_data(&data, &gas_sensor);
if (rslt != BME680_OK) { return; }
bme680_temperature = data.temperature / 100.0;
bme680_humidity = data.humidity / 1000.0;
bme680_pressure = data.pressure;
bmp_temperature = data.temperature / 100.0;
bmp_humidity = data.humidity / 1000.0;
bmp_pressure = data.pressure / 100.0;
/* Avoid using measurements from an unstable heating setup */
if (data.status & BME680_GASM_VALID_MSK) {
bme680_gas_resistance = data.gas_resistance;
bmp_gas_resistance = data.gas_resistance / 1000.0;
} else {
bme680_gas_resistance = 0;
bmp_gas_resistance = 0;
}
}
}
@ -444,9 +402,7 @@ void Bme680PerformReading()
void BmpDetect()
{
if (bmp_type) {
return;
}
if (bmp_type) { return; }
for (byte i = 0; i < sizeof(bmp_addresses); i++) {
bmp_address = bmp_addresses[i];
@ -456,22 +412,21 @@ void BmpDetect()
}
}
if (bmp_type) {
bmp_model = 0;
boolean success = false;
switch (bmp_type) {
case BMP180_CHIPID:
success = Bmp180Calibration();
break;
case BMP280_CHIPID:
bmp_model = 1; // 1
success = Bmx280Calibrate();
break;
case BME280_CHIPID:
bmp_model = 2; // 2
bmp_model++; // 2
case BMP280_CHIPID:
bmp_model++; // 1
success = Bmx280Calibrate();
break;
#ifdef USE_BME680
case BME680_CHIPID:
bmp_model = 3; // 2
bmp_model = 3; // 3
success = Bme680Init();
break;
#endif // USE_BME680
@ -487,54 +442,57 @@ void BmpDetect()
}
}
void BmpRead()
{
switch (bmp_type) {
case BMP180_CHIPID:
Bmp180Read();
break;
case BMP280_CHIPID:
case BME280_CHIPID:
Bme280Read();
break;
#ifdef USE_BME680
case BME680_CHIPID:
Bme680Read();
break;
#endif // USE_BME680
}
if (bmp_temperature != 0.0) { bmp_temperature = ConvertTemp(bmp_temperature); }
}
void BmpEverySecond()
{
if (91 == (uptime %100)) {
// 1mS
BmpDetect();
}
else {
// 2mS
BmpRead();
}
}
void BmpShow(boolean json)
{
if (bmp_type) {
float t = 0.0;
float p = 0.0;
float h = 0.0;
float g = 0.0;
float bmp_sealevel = 0.0;
switch (bmp_type) {
case BMP180_CHIPID:
t = Bmp180ReadTemperature();
p = Bmp180ReadPressure();
break;
case BME280_CHIPID:
h = Bme280ReadHumidity();
case BMP280_CHIPID:
t = Bme280ReadTemperature();
p = Bme280ReadPressure();
break;
#ifdef USE_BME680
case BME680_CHIPID:
t = bme680_temperature;
p = bme680_pressure / 100.0;
h = bme680_humidity;
g = bme680_gas_resistance / 1000.0;
break;
#endif // USE_BME680
}
if (t != 0.0) {
t = ConvertTemp(t);
}
if (p != 0.0) {
// bmp_sealevel = p / pow(1.0 - ((float)Settings.altitude / 44330.0), 5.255); // pow adds 8k to the code
bmp_sealevel = (p / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6;
}
char temperature[10];
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
char pressure[10];
dtostrfd(p, Settings.flag2.pressure_resolution, pressure);
char sea_pressure[10];
dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure);
char humidity[10];
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
if (bmp_pressure != 0.0) {
bmp_sealevel = (bmp_pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6;
}
dtostrfd(bmp_temperature, Settings.flag2.temperature_resolution, temperature);
dtostrfd(bmp_pressure, Settings.flag2.pressure_resolution, pressure);
dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure);
dtostrfd(bmp_humidity, Settings.flag2.humidity_resolution, humidity);
#ifdef USE_BME680
char gas_resistance[10];
dtostrfd(g, 2, gas_resistance);
dtostrfd(bmp_gas_resistance, 2, gas_resistance);
#endif // USE_BME680
if (json) {
@ -555,15 +513,15 @@ void BmpShow(boolean json)
if (0 == tele_period) {
DomoticzTempHumPressureSensor(temperature, humidity, pressure);
#ifdef USE_BME680
if (bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)g); }
if (bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp_gas_resistance); }
#endif // USE_BME680
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, t);
KnxSensor(KNX_HUMIDITY, h);
KnxSensor(KNX_TEMPERATURE, bmp_temperature);
KnxSensor(KNX_HUMIDITY, bmp_humidity);
}
#endif // USE_KNX
@ -599,13 +557,11 @@ boolean Xsns09(byte function)
if (i2c_flg) {
switch (function) {
case FUNC_INIT:
BmpDetect();
break;
case FUNC_EVERY_SECOND:
if (tele_period == Settings.tele_period -2) { // Allow 2 seconds to prepare BME680 readings
BmpDetect();
}
#ifdef USE_BME680
Bme680PerformReading();
#endif // USE_BME680
BmpEverySecond();
break;
case FUNC_JSON_APPEND:
BmpShow(1);

View File

@ -33,14 +33,20 @@
uint8_t bh1750_address;
uint8_t bh1750_addresses[] = { BH1750_ADDR1, BH1750_ADDR2 };
uint8_t bh1750_type = 0;
uint8_t bh1750_valid = 0;
uint16_t bh1750_illuminance = 0;
char bh1750_types[] = "BH1750";
uint16_t Bh1750ReadLux()
bool Bh1750Read()
{
Wire.requestFrom(bh1750_address, (uint8_t)2);
if (bh1750_valid) { bh1750_valid--; }
if (2 != Wire.requestFrom(bh1750_address, (uint8_t)2)) { return false; }
byte msb = Wire.read();
byte lsb = Wire.read();
uint16_t value = ((msb << 8) | lsb) / 1.2;
return value;
bh1750_illuminance = ((msb << 8) | lsb) / 1.2;
bh1750_valid = SENSOR_MAX_MISS;
return true;
}
/********************************************************************************************/
@ -57,31 +63,48 @@ void Bh1750Detect()
Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE);
if (!Wire.endTransmission()) {
bh1750_type = 1;
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "BH1750", bh1750_address);
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bh1750_types, bh1750_address);
AddLog(LOG_LEVEL_DEBUG);
break;
}
}
}
void Bh1750EverySecond()
{
if (90 == (uptime %100)) {
// 1mS
Bh1750Detect();
}
else {
// 1mS
if (bh1750_type) {
if (!Bh1750Read()) {
AddLogMissed(bh1750_types, bh1750_valid);
// if (!bh1750_valid) { bh1750_type = 0; }
}
}
}
}
#ifdef USE_WEBSERVER
const char HTTP_SNS_ILLUMINANCE[] PROGMEM =
"%s{s}BH1750 " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
"%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
void Bh1750Show(boolean json)
{
if (bh1750_type) {
uint16_t illuminance = Bh1750ReadLux();
if (bh1750_valid) {
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"BH1750\":{\"" D_JSON_ILLUMINANCE "\":%d}"), mqtt_data, illuminance);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}"), mqtt_data, bh1750_types, bh1750_illuminance);
#ifdef USE_DOMOTICZ
if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, illuminance);
if (0 == tele_period) {
DomoticzSensor(DZ_ILLUMINANCE, bh1750_illuminance);
}
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE, mqtt_data, illuminance);
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE, mqtt_data, bh1750_types, bh1750_illuminance);
#endif // USE_WEBSERVER
}
}
@ -99,9 +122,12 @@ boolean Xsns10(byte function)
if (i2c_flg) {
switch (function) {
case FUNC_PREP_BEFORE_TELEPERIOD:
case FUNC_INIT:
Bh1750Detect();
break;
case FUNC_EVERY_SECOND:
Bh1750EverySecond();
break;
case FUNC_JSON_APPEND:
Bh1750Show(1);
break;

View File

@ -93,6 +93,11 @@ uint32_t ina219_cal_value = 0;
// The following multiplier is used to convert raw current values to mA, taking into account the current config settings
uint32_t ina219_current_divider_ma = 0;
uint8_t ina219_valid = 0;
float ina219_voltage = 0;
float ina219_current = 0;
char ina219_types[] = "INA219";
bool Ina219SetCalibration(uint8_t mode)
{
uint16_t config = 0;
@ -155,8 +160,20 @@ float Ina219GetCurrent_mA()
return value;
}
bool Ina219Read()
{
ina219_voltage = Ina219GetBusVoltage_V() + (Ina219GetShuntVoltage_mV() / 1000);
ina219_current = Ina219GetCurrent_mA() / 1000;
ina219_valid = SENSOR_MAX_MISS;
return true;
}
/*********************************************************************************************\
* Command Sensor13
*
* 0 - Max 32V 2A range
* 1 - Max 32V 1A range
* 2 - Max 16V 0.4A range
\*********************************************************************************************/
bool Ina219CommandSensor()
@ -176,21 +193,36 @@ bool Ina219CommandSensor()
void Ina219Detect()
{
if (ina219_type) {
return;
}
if (ina219_type) { return; }
for (byte i = 0; i < sizeof(ina219_addresses); i++) {
ina219_address = ina219_addresses[i];
if (Ina219SetCalibration(Settings.ina219_mode)) {
ina219_type = 1;
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "INA219", ina219_address);
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, ina219_types, ina219_address);
AddLog(LOG_LEVEL_DEBUG);
break;
}
}
}
void Ina219EverySecond()
{
if (87 == (uptime %100)) {
// 2mS
Ina219Detect();
}
else {
// 3mS
if (ina219_type) {
if (!Ina219Read()) {
AddLogMissed(ina219_types, ina219_valid);
// if (!ina219_valid) { ina219_type = 0; }
}
}
}
}
#ifdef USE_WEBSERVER
const char HTTP_SNS_INA219_DATA[] PROGMEM = "%s"
"{s}INA219 " D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"
@ -200,21 +232,19 @@ const char HTTP_SNS_INA219_DATA[] PROGMEM = "%s"
void Ina219Show(boolean json)
{
if (ina219_type) {
if (ina219_valid) {
char voltage[10];
char current[10];
char power[10];
float fvoltage = Ina219GetBusVoltage_V() + (Ina219GetShuntVoltage_mV() / 1000);
float fcurrent = Ina219GetCurrent_mA() / 1000;
float fpower = fvoltage * fcurrent;
dtostrfd(fvoltage, Settings.flag2.voltage_resolution, voltage);
float fpower = ina219_voltage * ina219_current;
dtostrfd(ina219_voltage, Settings.flag2.voltage_resolution, voltage);
dtostrfd(fpower, Settings.flag2.wattage_resolution, power);
dtostrfd(fcurrent, Settings.flag2.current_resolution, current);
dtostrfd(ina219_current, Settings.flag2.current_resolution, current);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"INA219\":{\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"),
mqtt_data, voltage, current, power);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"),
mqtt_data, ina219_types, voltage, current, power);
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzSensor(DZ_VOLTAGE, voltage);
@ -244,9 +274,12 @@ boolean Xsns13(byte function)
result = Ina219CommandSensor();
}
break;
case FUNC_PREP_BEFORE_TELEPERIOD:
case FUNC_INIT:
Ina219Detect();
break;
case FUNC_EVERY_SECOND:
Ina219EverySecond();
break;
case FUNC_JSON_APPEND:
Ina219Show(1);
break;

View File

@ -63,9 +63,9 @@ void Tsl2561Show(boolean json)
&& Tsl2561Util::normalizedLuminosity(gain, exposure, full = scaledFull, ir = scaledIr)
&& Tsl2561Util::milliLux(full, ir, milliLux, Tsl2561::packageCS(id))) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_ILLUMINANCE " g:%d, e:%d, f:%u, i:%u -> %u.%03u " D_UNIT_LUX),
gain, exposure, full, ir, milliLux/1000, milliLux%1000);
AddLog(LOG_LEVEL_DEBUG);
// snprintf_P(log_data, sizeof(log_data), PSTR(D_ILLUMINANCE " g:%d, e:%d, f:%u, i:%u -> %u.%03u " D_UNIT_LUX),
// gain, exposure, full, ir, milliLux/1000, milliLux%1000);
// AddLog(LOG_LEVEL_DEBUG);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%u.%03u}"),

View File

@ -35,19 +35,20 @@ uint8_t tm1638_clock_pin = 0;
uint8_t tm1638_data_pin = 0;
uint8_t tm1638_strobe_pin = 0;
uint8_t tm1638_displays = 8;
uint8_t tm1638_active_display = 0;
uint8_t tm1638_active_display = 1;
uint8_t tm1638_intensity = 0;
uint8_t tm1638_state = 0;
/*********************************************************************************************\
* Pieces from library https://github.com/rjbatista/tm1638-library
* and from library https://github.com/MartyMacGyver/TM1638-demos-and-examples
\*********************************************************************************************/
void Tm16XXSend(byte data)
{
for (int i = 0; i < 8; i++) {
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(tm1638_data_pin, !!(data & (1 << i)));
digitalWrite(tm1638_clock_pin, LOW);
digitalWrite(tm1638_data_pin, data & 1 ? HIGH : LOW);
data >>= 1;
delayMicroseconds(TM1638_CLOCK_DELAY);
digitalWrite(tm1638_clock_pin, HIGH);
}
@ -77,11 +78,10 @@ byte Tm16XXReceive()
pinMode(tm1638_data_pin, INPUT);
digitalWrite(tm1638_data_pin, HIGH);
for (int i = 0; i < 8; i++) {
temp >>= 1;
for (uint8_t i = 0; i < 8; ++i) {
digitalWrite(tm1638_clock_pin, LOW);
delayMicroseconds(TM1638_CLOCK_DELAY);
if (digitalRead(tm1638_data_pin)) { temp |= 0x80; }
temp |= digitalRead(tm1638_data_pin) << i;
digitalWrite(tm1638_clock_pin, HIGH);
}
@ -165,25 +165,32 @@ void TmInit()
digitalWrite(tm1638_strobe_pin, HIGH);
tm1638_type = 1;
tm1638_state = 1;
}
}
void TmLoop()
{
byte buttons = Tm1638GetButtons();
for (byte i = 0; i < MAX_SWITCHES; i++) {
virtualswitch[i] = buttons &1;
byte color = (virtualswitch[i]) ? TM1638_COLOR_RED : TM1638_COLOR_NONE;
Tm1638SetLED(color, i);
buttons >>= 1;
if (tm1638_state) {
byte buttons = Tm1638GetButtons();
for (byte i = 0; i < MAX_SWITCHES; i++) {
virtualswitch[i] = (buttons &1) ^1;
byte color = (virtualswitch[i]) ? TM1638_COLOR_NONE : TM1638_COLOR_RED;
Tm1638SetLED(color, i);
buttons >>= 1;
}
SwitchHandler(1);
}
SwitchHandler(1);
}
/*
void TmShow(boolean json)
{
if (tm1638_type) {
}
}
*/
/*********************************************************************************************\
* Interface

View File

@ -146,6 +146,38 @@ boolean (* const xsns_func_ptr[])(byte) PROGMEM = { // Sensor Function Pointers
&Xsns32,
#endif
#ifdef XSNS_33
&Xsns33,
#endif
#ifdef XSNS_34
&Xsns34,
#endif
#ifdef XSNS_35
&Xsns35,
#endif
#ifdef XSNS_36
&Xsns36,
#endif
#ifdef XSNS_37
&Xsns37,
#endif
#ifdef XSNS_38
&Xsns38,
#endif
#ifdef XSNS_39
&Xsns39,
#endif
#ifdef XSNS_40
&Xsns40,
#endif
// Optional user defined sensors in range 91 - 99
#ifdef XSNS_91
@ -217,10 +249,40 @@ boolean XsnsCall(byte Function)
{
boolean result = false;
#ifdef PROFILE_XSNS_EVERY_SECOND
uint32_t profile_start_millis = millis();
#endif // PROFILE_XSNS_EVERY_SECOND
for (byte x = 0; x < xsns_present; x++) {
#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND
uint32_t profile_start_millis = millis();
#endif // PROFILE_XSNS_SENSOR_EVERY_SECOND
result = xsns_func_ptr[x](Function);
#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND
uint32_t profile_millis = millis() - profile_start_millis;
if (profile_millis) {
if (FUNC_EVERY_SECOND == Function) {
snprintf_P(log_data, sizeof(log_data), PSTR("PRF: At %08u XsnsCall %d to Sensor %d took %u mS"), uptime, Function, x, profile_millis);
AddLog(LOG_LEVEL_DEBUG);
}
}
#endif // PROFILE_XSNS_SENSOR_EVERY_SECOND
if (result) break;
}
#ifdef PROFILE_XSNS_EVERY_SECOND
uint32_t profile_millis = millis() - profile_start_millis;
if (profile_millis) {
if (FUNC_EVERY_SECOND == Function) {
snprintf_P(log_data, sizeof(log_data), PSTR("PRF: At %08u XsnsCall %d took %u mS"), uptime, Function, profile_millis);
AddLog(LOG_LEVEL_DEBUG);
}
}
#endif // PROFILE_XSNS_EVERY_SECOND
return result;
}