diff --git a/lib/Joba_Tsl2561/COPYING b/lib/Joba_Tsl2561-2.0.7/COPYING similarity index 100% rename from lib/Joba_Tsl2561/COPYING rename to lib/Joba_Tsl2561-2.0.7/COPYING diff --git a/lib/Joba_Tsl2561/COPYING.LESSER b/lib/Joba_Tsl2561-2.0.7/COPYING.LESSER similarity index 100% rename from lib/Joba_Tsl2561/COPYING.LESSER rename to lib/Joba_Tsl2561-2.0.7/COPYING.LESSER diff --git a/lib/Joba_Tsl2561/README b/lib/Joba_Tsl2561-2.0.7/README similarity index 100% rename from lib/Joba_Tsl2561/README rename to lib/Joba_Tsl2561-2.0.7/README diff --git a/lib/Joba_Tsl2561/examples/Autogain/Autogain.ino b/lib/Joba_Tsl2561-2.0.7/examples/Autogain/Autogain.ino similarity index 54% rename from lib/Joba_Tsl2561/examples/Autogain/Autogain.ino rename to lib/Joba_Tsl2561-2.0.7/examples/Autogain/Autogain.ino index 03da78d46..169d2b6e3 100644 --- a/lib/Joba_Tsl2561/examples/Autogain/Autogain.ino +++ b/lib/Joba_Tsl2561-2.0.7/examples/Autogain/Autogain.ino @@ -21,6 +21,17 @@ This file is part of the Joba_Tsl2561 Library. #include +// 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); } - diff --git a/lib/Joba_Tsl2561/examples/Simple/Simple.ino b/lib/Joba_Tsl2561-2.0.7/examples/Simple/Simple.ino similarity index 76% rename from lib/Joba_Tsl2561/examples/Simple/Simple.ino rename to lib/Joba_Tsl2561-2.0.7/examples/Simple/Simple.ino index f1c2d88d9..5bebb7e50 100644 --- a/lib/Joba_Tsl2561/examples/Simple/Simple.ino +++ b/lib/Joba_Tsl2561-2.0.7/examples/Simple/Simple.ino @@ -21,6 +21,17 @@ This file is part of the Joba_Tsl2561 Library. #include +// 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(); } diff --git a/lib/Joba_Tsl2561/examples/Testing/Testing.ino b/lib/Joba_Tsl2561-2.0.7/examples/Testing/Testing.ino similarity index 82% rename from lib/Joba_Tsl2561/examples/Testing/Testing.ino rename to lib/Joba_Tsl2561-2.0.7/examples/Testing/Testing.ino index 8fc6d121a..0dbeb09be 100644 --- a/lib/Joba_Tsl2561/examples/Testing/Testing.ino +++ b/lib/Joba_Tsl2561-2.0.7/examples/Testing/Testing.ino @@ -22,11 +22,22 @@ This file is part of the Joba_Tsl2561 Library. #include +// 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); } - diff --git a/lib/Joba_Tsl2561/examples/Utility/Utility.ino b/lib/Joba_Tsl2561-2.0.7/examples/Utility/Utility.ino similarity index 70% rename from lib/Joba_Tsl2561/examples/Utility/Utility.ino rename to lib/Joba_Tsl2561-2.0.7/examples/Utility/Utility.ino index 58e03ca14..d05549616 100644 --- a/lib/Joba_Tsl2561/examples/Utility/Utility.ino +++ b/lib/Joba_Tsl2561-2.0.7/examples/Utility/Utility.ino @@ -21,6 +21,17 @@ This file is part of the Joba_Tsl2561 Library. #include +// 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); } - diff --git a/lib/Joba_Tsl2561-2.0.7/examples/platformio.ini b/lib/Joba_Tsl2561-2.0.7/examples/platformio.ini new file mode 100644 index 000000000..ef71e03ae --- /dev/null +++ b/lib/Joba_Tsl2561-2.0.7/examples/platformio.ini @@ -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] diff --git a/lib/Joba_Tsl2561-2.0.7/examples/platformio.sh b/lib/Joba_Tsl2561-2.0.7/examples/platformio.sh new file mode 100644 index 000000000..e5f0d3f76 --- /dev/null +++ b/lib/Joba_Tsl2561-2.0.7/examples/platformio.sh @@ -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 + diff --git a/lib/Joba_Tsl2561-2.0.7/lib/readme.txt b/lib/Joba_Tsl2561-2.0.7/lib/readme.txt new file mode 100644 index 000000000..dbadc3d63 --- /dev/null +++ b/lib/Joba_Tsl2561-2.0.7/lib/readme.txt @@ -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 +#include + +// 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 diff --git a/lib/Joba_Tsl2561/library.json b/lib/Joba_Tsl2561-2.0.7/library.json similarity index 93% rename from lib/Joba_Tsl2561/library.json rename to lib/Joba_Tsl2561-2.0.7/library.json index cacc33d5a..94585c488 100644 --- a/lib/Joba_Tsl2561/library.json +++ b/lib/Joba_Tsl2561-2.0.7/library.json @@ -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": diff --git a/lib/Joba_Tsl2561/library.properties b/lib/Joba_Tsl2561-2.0.7/library.properties similarity index 95% rename from lib/Joba_Tsl2561/library.properties rename to lib/Joba_Tsl2561-2.0.7/library.properties index 148736de6..ba1840764 100644 --- a/lib/Joba_Tsl2561/library.properties +++ b/lib/Joba_Tsl2561-2.0.7/library.properties @@ -1,5 +1,5 @@ name=Joba Tsl2561 Library -version=2.0.1 +version=2.0.7 author=joba-1 maintainer=joba-1 sentence=IoT library for using the Tsl2561 luminosity sensor diff --git a/lib/Joba_Tsl2561-2.0.7/platformio.ini b/lib/Joba_Tsl2561-2.0.7/platformio.ini new file mode 100644 index 000000000..ea6847aaa --- /dev/null +++ b/lib/Joba_Tsl2561-2.0.7/platformio.ini @@ -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 diff --git a/lib/Joba_Tsl2561/src/Tsl2561.cpp b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561.cpp similarity index 85% rename from lib/Joba_Tsl2561/src/Tsl2561.cpp rename to lib/Joba_Tsl2561-2.0.7/src/Tsl2561.cpp index ad347f071..f0e324eb8 100644 --- a/lib/Joba_Tsl2561/src/Tsl2561.cpp +++ b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561.cpp @@ -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(_wire.endTransmission(false))) == ERR_OK ) { + if( _wire.requestFrom(_addr, 1) == 1 ) { val = static_cast(_wire.read()); } + else { + _status = ERR_RW; + } } - return (_status = static_cast(_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(_wire.endTransmission(false))) == ERR_OK ) { + if( _wire.requestFrom(_addr, 2) == 2 ) { + val = static_cast(_wire.read()) & 0xff; + val |= (static_cast(_wire.read()) & 0xff) << 8; + } + else { + _status = ERR_RW; } } - return (_status = static_cast(_wire.endTransmission())) == ERR_OK; + return _status == ERR_OK; } bool Tsl2561::writeByte( register_t reg, uint8_t val ) { diff --git a/lib/Joba_Tsl2561/src/Tsl2561.h b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561.h similarity index 100% rename from lib/Joba_Tsl2561/src/Tsl2561.h rename to lib/Joba_Tsl2561-2.0.7/src/Tsl2561.h diff --git a/lib/Joba_Tsl2561/src/Tsl2561Util.cpp b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.cpp similarity index 78% rename from lib/Joba_Tsl2561/src/Tsl2561Util.cpp rename to lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.cpp index 92997b60b..ae811f743 100644 --- a/lib/Joba_Tsl2561/src/Tsl2561Util.cpp +++ b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.cpp @@ -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; } diff --git a/lib/Joba_Tsl2561/src/Tsl2561Util.h b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.h similarity index 79% rename from lib/Joba_Tsl2561/src/Tsl2561Util.h rename to lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.h index 58c5d4bbf..5b831183d 100644 --- a/lib/Joba_Tsl2561/src/Tsl2561Util.h +++ b/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.h @@ -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 diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 4ce79838b..0635beae8 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -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 [(:,:)] (#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 [(:,:)] (#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 diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 08e909300..736e42904 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -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"; diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 1c1f24532..2cc9fa8e6 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -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 diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 98fb7b7a3..01051db1f 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -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 diff --git a/sonoff/support.ino b/sonoff/support.ino index 3e3ea7e74..f1d260bf2 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -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); +} + /*********************************************************************************************\ * \*********************************************************************************************/ diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index f2b972326..f29def2ce 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -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; } /*********************************************************************************************\ diff --git a/sonoff/xsns_05_ds18b20.ino b/sonoff/xsns_05_ds18b20.ino index dabaf25d4..fa0f4fee8 100644 --- a/sonoff/xsns_05_ds18b20.ino +++ b/sonoff/xsns_05_ds18b20.ino @@ -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); diff --git a/sonoff/xsns_05_ds18x20.ino b/sonoff/xsns_05_ds18x20.ino index 292191b18..869deac8e 100644 --- a/sonoff/xsns_05_ds18x20.ino +++ b/sonoff/xsns_05_ds18x20.ino @@ -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); diff --git a/sonoff/xsns_06_dht.ino b/sonoff/xsns_06_dht.ino index 91a154169..048337d25 100644 --- a/sonoff/xsns_06_dht.ino +++ b/sonoff/xsns_06_dht.ino @@ -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); diff --git a/sonoff/xsns_07_sht1x.ino b/sonoff/xsns_07_sht1x.ino index 98837471b..510ee7be3 100644 --- a/sonoff/xsns_07_sht1x.ino +++ b/sonoff/xsns_07_sht1x.ino @@ -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; diff --git a/sonoff/xsns_08_htu21.ino b/sonoff/xsns_08_htu21.ino index 3d9e21d3b..9534cbbce 100644 --- a/sonoff/xsns_08_htu21.ino +++ b/sonoff/xsns_08_htu21.ino @@ -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; diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino index a3769f8bc..2ffe02ebe 100644 --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -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); diff --git a/sonoff/xsns_10_bh1750.ino b/sonoff/xsns_10_bh1750.ino index 9c02f02e0..1dd18d90a 100644 --- a/sonoff/xsns_10_bh1750.ino +++ b/sonoff/xsns_10_bh1750.ino @@ -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} = , {m} = , {e} = + "%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = #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; diff --git a/sonoff/xsns_13_ina219.ino b/sonoff/xsns_13_ina219.ino index 50bcb1642..deb4d5f4f 100644 --- a/sonoff/xsns_13_ina219.ino +++ b/sonoff/xsns_13_ina219.ino @@ -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; diff --git a/sonoff/xsns_16_tsl2561.ino b/sonoff/xsns_16_tsl2561.ino index 63abbc4a1..ac0536c6a 100644 --- a/sonoff/xsns_16_tsl2561.ino +++ b/sonoff/xsns_16_tsl2561.ino @@ -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}"), diff --git a/sonoff/xsns_28_tm1638.ino b/sonoff/xsns_28_tm1638.ino index 6945261c8..01f2f21a5 100644 --- a/sonoff/xsns_28_tm1638.ino +++ b/sonoff/xsns_28_tm1638.ino @@ -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 diff --git a/sonoff/xsns_interface.ino b/sonoff/xsns_interface.ino index 19cd86bb3..7c18fa723 100644 --- a/sonoff/xsns_interface.ino +++ b/sonoff/xsns_interface.ino @@ -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; }