Merge branch 'development' into development

This commit is contained in:
Theo Arends 2018-07-17 12:20:42 +02:00 committed by GitHub
commit 0288a2da15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 3276 additions and 2362 deletions

View File

@ -15,7 +15,7 @@ If you like **Sonoff-Tasmota**, give it a star, or fork it and contribute!
### Development
[![Build Status](https://img.shields.io/travis/arendst/Sonoff-Tasmota.svg)](https://travis-ci.org/arendst/Sonoff-Tasmota)
Current version is **6.0.0c** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
Current version is **6.1.1b** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for release information and [sonoff/_changelog.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_changelog.ino) for change information.
### Disclaimer
:warning: **DANGER OF ELECTROCUTION** :warning:
@ -39,7 +39,7 @@ If you want to compile Sonoff-Tasmota yourself keep in mind the following:
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.
- After reboot select config menu again or use commands ```GPIOs``` and ```GPIO``` to change GPIO with desired sensor.
### Migration Instructions
### Migration Information
See [wiki migration path](https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade#migration-path) for instructions how to migrate to a major version. Pay attention to the following version breaks due to dynamic settings updates:
1. Migrate to **Sonoff-Tasmota 3.9.x**
@ -134,34 +134,34 @@ Different firmware images are released based on Features and Sensors selection g
| USE_ADS1115 | - | - | - | - | x |
| USE_ADS1115_I2CDEV | - | - | - | - | - |
| USE_INA219 | - | - | - | - | x |
| USE_APDS9960 | - | - | - | - | - |
| USE_MGS | - | - | - | - | x |
| USE_SPI | - | - | - | - | - |
| USE_MHZ19 | x | x | - | x | x |
| USE_SENSEAIR | x | x | - | x | x |
| USE_PMS5003 | x | x | - | x | x |
| USE_SENSEAIR | x | - | - | x | x |
| USE_PMS5003 | x | - | - | x | x |
| USE_NOVA_SDS | x | - | - | x | x |
| USE_PZEM004T | x | x | - | x | x |
| USE_PZEM004T | x | - | - | x | x |
| USE_SERIAL_BRIDGE | x | - | - | x | x |
| USE_SDM120 | x | - | - | - | x |
| USE_SDM630 | x | - | - | - | x |
| USE_SDM120 | - | - | - | - | x |
| USE_SDM630 | - | - | - | - | x |
| USE_IR_REMOTE | x | x | - | x | x |
| USE_IR_HVAC | - | - | - | - | x |
| USE_IR_RECEIVE | x | - | - | x | x |
| USE_WS2812 | x | x | - | x | x |
| USE_WS2812_DMA | - | - | - | - | - |
| USE_ARILUX_RF | x | x | - | x | x |
| USE_ARILUX_RF | x | - | - | x | x |
| USE_SR04 | x | - | - | x | x |
| USE_TM1638 | - | - | - | - | - |
| USE_RF_FLASH | x | - | - | x | x |
#### Typical File Size
#### Typical file size
| ESP/Arduino library version | sonoff | classic | minimal | knx | allsensors |
|-----------------------------|--------|---------|---------|------|------------|
| ESP/Arduino lib v2.3.0 | 529k | 490k | 429k | 538k | 554k |
| ESP/Arduino lib v2.4.0 | 534k | 498k | 436k | 542k | 558k |
| ESP/Arduino lib v2.4.1 | 536k | 501k | 439k | 545k | 560k |
| ESP/Arduino lib v2.3.0 | 538k | 490k | 407k | 548k | 562k |
| ESP/Arduino lib v2.4.0 | 543k | 498k | 414k | 553k | 565k |
| ESP/Arduino lib v2.4.1 | 544k | 500k | 416k | 555k | 567k |
See [Tasmota ESP/Arduino library version related issues](https://github.com/arendst/Sonoff-Tasmota/wiki/Theo's-Tasmota-Tips#20180523---relation-tasmota-and-esp8266arduino-core-version) for more information.
### Contribute
You can contribute to Sonoff-Tasmota by
@ -176,13 +176,14 @@ You can contribute to Sonoff-Tasmota by
#### Libraries Used
Libraries used with Sonoff-Tasmota are:
- [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)
- [Adafruit BME680](https://github.com/adafruit/Adafruit_BME680)
- [Adafruit Sensor](https://github.com/adafruit/Adafruit_Sensor)
- [Adafruit SGP30](https://github.com/adafruit/Adafruit_SGP30)
- [ArduinoJson](https://arduinojson.org/)
- [Bosch BME680](https://github.com/BoschSensortec/BME680_driver)
- [C2 Programmer](http://app.cear.ufpb.br/~lucas.hartmann/tag/efm8bb1/)
- [Esp8266MqttClient](https://github.com/tuanpmt/ESP8266MQTTClient)
- [esp-knx-ip](https://github.com/envy/esp-knx-ip)
- [esp-mqtt-arduino](https://github.com/i-n-g-o/esp-mqtt-arduino)
- [ESPAsyncUDP](https://github.com/me-no-dev/ESPAsyncUDP)
- [I2Cdevlib](https://github.com/jrowberg/i2cdevlib)
- [IRremoteEsp8266](https://github.com/markszabo/IRremoteESP8266)
- [JobaTsl2561](https://github.com/joba-1/Joba_Tsl2561)

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

@ -39,7 +39,7 @@ platform = espressif8266@1.5.0
; *** Esp8266 core for Arduino version 2.4.0
;platform = espressif8266@1.6.0
; *** Esp8266 core for Arduino version 2.4.1
;platform = espressif8266@1.7.0
;platform = espressif8266@1.7.3
; *** Esp8266 core for Arduino version latest beta
;platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
; *** Esp8266 core for Arduino current version
@ -62,8 +62,7 @@ build_flags =
monitor_speed = 115200
; *** Upload Serial reset method for Wemos and NodeMCU
;upload_speed = 115200
upload_speed = 512000
upload_speed = 115200
upload_resetmethod = nodemcu
upload_port = COM5
; *** Fix Esp/Arduino core 2.4.x induced Tasmota unused floating point includes

1391
sonoff/_changelog.ino Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -215,6 +215,7 @@
#define D_WCFG_3_WPSCONFIG "WPSConfig"
#define D_WCFG_4_RETRY "Retry"
#define D_WCFG_5_WAIT "Wait"
#define D_WCFG_6_SERIAL "Serial"
#define D_CMND_FRIENDLYNAME "FriendlyName"
#define D_CMND_SWITCHMODE "SwitchMode"
#define D_CMND_TELEPERIOD "TelePeriod"
@ -471,6 +472,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";
@ -498,7 +500,8 @@ const char kWifiConfig[MAX_WIFI_OPTION][WCFG_MAX_STRING_LENGTH] PROGMEM = {
D_WCFG_2_WIFIMANAGER,
D_WCFG_3_WPSCONFIG,
D_WCFG_4_RETRY,
D_WCFG_5_WAIT };
D_WCFG_5_WAIT,
D_WCFG_6_SERIAL };
const char kPrefixes[3][PRFX_MAX_STRING_LENGTH] PROGMEM = {
D_CMND,
D_STAT,

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Подтвърдете рестартирането"
#define D_CONFIGURE_MODULE "Конфигурация на модула"
#define D_CONFIGURE_MCP230XX "Конфигурация на MCP230xx"
#define D_CONFIGURE_WIFI "Конфигурация на WiFi"
#define D_CONFIGURE_MQTT "Конфигурация на MQTT"
#define D_CONFIGURE_DOMOTICZ "Конфигурация на Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Potvrzení restartu"
#define D_CONFIGURE_MODULE "Nastavení modulu"
#define D_CONFIGURE_MCP230XX "Nastavení MCP230xx"
#define D_CONFIGURE_WIFI "Nastavení WiFi"
#define D_CONFIGURE_MQTT "Nastavení MQTT"
#define D_CONFIGURE_DOMOTICZ "Nastavení Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Wirklich neustarten?"
#define D_CONFIGURE_MODULE "Gerät konfigurieren"
#define D_CONFIGURE_MCP230XX "MCP230xx konfigurieren"
#define D_CONFIGURE_WIFI "WLAN konfigurieren"
#define D_CONFIGURE_MQTT "MQTT konfigurieren"
#define D_CONFIGURE_DOMOTICZ "Domoticz konfigurieren"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Επιβεβαίωση Επανεκκίνησης"
#define D_CONFIGURE_MODULE "Ρύθμιση Module"
#define D_CONFIGURE_MCP230XX "Ρύθμιση MCP230xx"
#define D_CONFIGURE_WIFI "Ρύθμιση WiFi"
#define D_CONFIGURE_MQTT "Ρύθμιση MQTT"
#define D_CONFIGURE_DOMOTICZ "Ρύθμιση Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Confirm Restart"
#define D_CONFIGURE_MODULE "Configure Module"
#define D_CONFIGURE_MCP230XX "Configure MCP230xx"
#define D_CONFIGURE_WIFI "Configure WiFi"
#define D_CONFIGURE_MQTT "Configure MQTT"
#define D_CONFIGURE_DOMOTICZ "Configure Domoticz"

View File

@ -131,7 +131,7 @@
#define D_PROGRAM_SIZE "Tamaño Programa"
#define D_PROJECT "Proyecto"
#define D_RECEIVED "Recibido"
#define D_RESTART "Reinicio"
#define D_RESTART "Reiniciar"
#define D_RESTARTING "Reiniciando"
#define D_RESTART_REASON "Causa Reinicio"
#define D_RESTORE "Restauración"
@ -168,7 +168,7 @@
#define D_WEB_SERVER "Servidor Web"
// sonoff.ino
#define D_WARNING_MINIMAL_VERSION "Precaución, esta versión no salva los cambios"
#define D_WARNING_MINIMAL_VERSION "Cuidado, esta versión no guarda los cambios"
#define D_LEVEL_10 "level 1-0"
#define D_LEVEL_01 "level 0-1"
#define D_SERIAL_LOGGING_DISABLED "Log serial deshabilitado"
@ -188,12 +188,12 @@
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
#define D_CONNECTING_TO_AP "Connectando a AP"
#define D_IN_MODE "en modo"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "Falló Conección, Dirección IP no recibida"
#define D_CONNECT_FAILED_AP_NOT_REACHED "Falló Conección, AP no pudo ser contactado"
#define D_CONNECT_FAILED_WRONG_PASSWORD "Falló Conección, clave de AP incorrecta"
#define D_CONNECT_FAILED_AP_TIMEOUT "Falló Conección, timeout de AP"
#define D_CONNECT_FAILED_NO_IP_ADDRESS "Falló Conexión, Dirección IP no recibida"
#define D_CONNECT_FAILED_AP_NOT_REACHED "Falló Conexión, AP no pudo ser contactado"
#define D_CONNECT_FAILED_WRONG_PASSWORD "Falló Conexión, clave de AP incorrecta"
#define D_CONNECT_FAILED_AP_TIMEOUT "Falló Conexión, timeout de AP"
#define D_ATTEMPTING_CONNECTION "Intentando conectar..."
#define D_CHECKING_CONNECTION "Probando conección..."
#define D_CHECKING_CONNECTION "Probando conexión..."
#define D_QUERY_DONE "Consulta lista. Servicio MQTT encontrado"
#define D_MQTT_SERVICE_FOUND "Servicio MQTT encontrado en"
#define D_FOUND_AT "encontrado en"
@ -211,22 +211,23 @@
#define D_WITH_IP_ADDRESS "con dirección IP"
#define D_WEBSERVER_STOPPED "Servidor web detenido"
#define D_FILE_NOT_FOUND "Archivo No Encontrado"
#define D_REDIRECTED "Redireccinado al portal captivo"
#define D_REDIRECTED "Redireccionado al portal captivo"
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager como AccessPoint y Estación"
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager como AccessPoint"
#define D_TRYING_TO_CONNECT "Intentado conectar dispositivo a la red"
#define D_RESTART_IN "Reinicio en"
#define D_SECONDS "segundos"
#define D_DEVICE_WILL_RESTART "El dispositivo se reiniciará en pocos segundos"
#define D_DEVICE_WILL_RESTART "El dispositivo se reiniciará en unos segundos"
#define D_BUTTON_TOGGLE "Alternar ON/OFF"
#define D_CONFIGURATION "Configuración"
#define D_INFORMATION "Información"
#define D_FIRMWARE_UPGRADE "Actualización Firmware"
#define D_FIRMWARE_UPGRADE "Actualizar Firmware"
#define D_CONSOLE "Consola"
#define D_CONFIRM_RESTART "Confirmar Reinicio"
#define D_CONFIGURE_MODULE "Configuración del Módulo"
#define D_CONFIGURE_MCP230XX "Configuración MCP230xx"
#define D_CONFIGURE_WIFI "Configuración WiFi"
#define D_CONFIGURE_MQTT "Configuración MQTT"
#define D_CONFIGURE_DOMOTICZ "Configuración Domoticz"
@ -239,7 +240,7 @@
#define D_MAIN_MENU "Menú Principal"
#define D_MODULE_PARAMETERS "Parámetros del módulo"
#define D_MODULE_TYPE "Tipo módulo"
#define D_MODULE_TYPE "Tipo de módulo"
#define D_GPIO "GPIO"
#define D_SERIAL_IN "Serial In"
#define D_SERIAL_OUT "Serial Out"
@ -250,7 +251,7 @@
#define D_NO_NETWORKS_FOUND "Ninguna red encontrada"
#define D_REFRESH_TO_SCAN_AGAIN "Recargar página para buscar nuevamente"
#define D_DUPLICATE_ACCESSPOINT "AccessPoint duplicado"
#define D_SKIPPING_LOW_QUALITY "Ignorado debido a baja calidad"
#define D_SKIPPING_LOW_QUALITY "Ignorado por baja calidad"
#define D_RSSI "RSSI"
#define D_WEP "WEP"
#define D_WPA_PSK "WPA PSK"
@ -268,7 +269,7 @@
#define D_SERIAL_LOG_LEVEL "Nivel de log Serial"
#define D_WEB_LOG_LEVEL "Nivel de log Web"
#define D_SYS_LOG_LEVEL "Nivel de Syslog"
#define D_MORE_DEBUG "Mas Debug"
#define D_MORE_DEBUG "Más Debug"
#define D_SYSLOG_HOST "Host del Syslog"
#define D_SYSLOG_PORT "Puerto del Syslog"
#define D_TELEMETRY_PERIOD "Período de Telemetría"
@ -287,7 +288,7 @@
#define D_CONFIGURATION_RESET "Configuración restablecida"
#define D_PROGRAM_VERSION "Versión del Programa"
#define D_BUILD_DATE_AND_TIME "Fecha y Hora de la Compilación"
#define D_BUILD_DATE_AND_TIME "Fecha y Hora de Compilación"
#define D_CORE_AND_SDK_VERSION "Versión Core/SDK"
#define D_FLASH_WRITE_COUNT "Contador de escritura en Flash"
#define D_MAC_ADDRESS "Dirección MAC"
@ -333,16 +334,16 @@
// xdrv_01_mqtt.ino
#define D_FINGERPRINT "Verificar TLS fingerprint..."
#define D_TLS_CONNECT_FAILED_TO "Falló Conección TLS a"
#define D_TLS_CONNECT_FAILED_TO "Falló Conexión TLS a"
#define D_RETRY_IN "Reintentando"
#define D_VERIFIED "Verificado Fingerprint"
#define D_INSECURE "Conección insegura por Fingerprint no válido"
#define D_CONNECT_FAILED_TO "Falló Conección a"
#define D_INSECURE "Conexión insegura por Fingerprint inválido"
#define D_CONNECT_FAILED_TO "Falló Conexión a"
// xplg_wemohue.ino
#define D_MULTICAST_DISABLED "Multicast deshabilitado"
#define D_MULTICAST_REJOINED "Multicast (re)conectado"
#define D_MULTICAST_JOIN_FAILED "Conección Multicast fallida"
#define D_MULTICAST_JOIN_FAILED "Conexión Multicast fallida"
#define D_FAILED_TO_SEND_RESPONSE "Falla al enviar respuesta"
#define D_WEMO "WeMo"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Confirmer redémarrage"
#define D_CONFIGURE_MODULE "Configuration du Module"
#define D_CONFIGURE_MCP230XX "Configuration MCP230xx"
#define D_CONFIGURE_WIFI "Configuration WiFi"
#define D_CONFIGURE_MQTT "Configuration MQTT"
#define D_CONFIGURE_DOMOTICZ "Configuration Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Újraindítás megerősítése"
#define D_CONFIGURE_MODULE "Eszköz konfiguráció"
#define D_CONFIGURE_MCP230XX "MCP230xx konfiguráció"
#define D_CONFIGURE_WIFI "WiFi konfiguráció"
#define D_CONFIGURE_MQTT "MQTT konfiguráció"
#define D_CONFIGURE_DOMOTICZ "Domoticz konfiguráció"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Conferma Riavvio"
#define D_CONFIGURE_MODULE "Configurazione Modulo"
#define D_CONFIGURE_MCP230XX "Configurazione MCP230xx"
#define D_CONFIGURE_WIFI "Configurazione WiFi"
#define D_CONFIGURE_MQTT "Configurazione MQTT"
#define D_CONFIGURE_DOMOTICZ "Configurazione Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Bevestig herstart"
#define D_CONFIGURE_MODULE "Configureer Module"
#define D_CONFIGURE_MCP230XX "Configureer MCP230xx"
#define D_CONFIGURE_WIFI "Configureer WiFi"
#define D_CONFIGURE_MQTT "Configureer MQTT"
#define D_CONFIGURE_DOMOTICZ "Configureer Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Potwierdź restart"
#define D_CONFIGURE_MODULE "Konfiguruj moduł"
#define D_CONFIGURE_MCP230XX "Konfiguruj MCP230xx"
#define D_CONFIGURE_WIFI "Konfiguruj WiFi"
#define D_CONFIGURE_MQTT "Konfiguruj MQTT"
#define D_CONFIGURE_DOMOTICZ "Konfiguruj Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Confirmar o reinicio"
#define D_CONFIGURE_MODULE "Configurar Módulo"
#define D_CONFIGURE_MCP230XX "Configurar MCP230xx"
#define D_CONFIGURE_WIFI "Configurar WiFi"
#define D_CONFIGURE_MQTT "Configurar MQTT"
#define D_CONFIGURE_DOMOTICZ "Configurar Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Confirmar o reinicio"
#define D_CONFIGURE_MODULE "Configurar Módulo"
#define D_CONFIGURE_MCP230XX "Configurar MCP230xx"
#define D_CONFIGURE_WIFI "Configurar WiFi"
#define D_CONFIGURE_MQTT "Configurar MQTT"
#define D_CONFIGURE_DOMOTICZ "Configurar Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Подтвердить перезагрузку"
#define D_CONFIGURE_MODULE "Конфигурация Модуля"
#define D_CONFIGURE_MCP230XX "Конфигурация MCP230xx"
#define D_CONFIGURE_WIFI "Конфигурация WiFi"
#define D_CONFIGURE_MQTT "Конфигурация MQTT"
#define D_CONFIGURE_DOMOTICZ "Конфигурация Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "Підтвердити перезавантаження"
#define D_CONFIGURE_MODULE "Конфігурація модуля"
#define D_CONFIGURE_MCP230XX "Конфігурація MCP230xx"
#define D_CONFIGURE_WIFI "Конфігурація WiFi"
#define D_CONFIGURE_MQTT "Конфігурація MQTT"
#define D_CONFIGURE_DOMOTICZ "Конфігурація Domoticz"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "确认重启"
#define D_CONFIGURE_MODULE "模块设置"
#define D_CONFIGURE_MCP230XX "MCP230xx设置"
#define D_CONFIGURE_WIFI "WiFi设置"
#define D_CONFIGURE_MQTT "MQTT设置"
#define D_CONFIGURE_DOMOTICZ "Domoticz设置"

View File

@ -227,6 +227,7 @@
#define D_CONFIRM_RESTART "確認重啟"
#define D_CONFIGURE_MODULE "模塊設置"
#define D_CONFIGURE_MCP230XX "MCP230xx設置"
#define D_CONFIGURE_WIFI "WiFi設置"
#define D_CONFIGURE_MQTT "MQTT設置"
#define D_CONFIGURE_DOMOTICZ "Domoticz設置"

View File

@ -56,7 +56,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t rf_receive_decimal : 1; // bit 28 (v6.0.0a)
uint32_t ir_receive_decimal : 1; // bit 29 (v6.0.0a)
uint32_t hass_light : 1; // bit 30 (v6.0.0b)
uint32_t spare31 : 1;
uint32_t global_state : 1; // bit 31 (v6.1.0)
};
} SysBitfield;
@ -394,6 +394,20 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
};
} RulesBitfield;
typedef union {
uint8_t data;
struct {
uint8_t wifi_down : 1;
uint8_t mqtt_down : 1;
uint8_t spare02 : 1;
uint8_t spare03 : 1;
uint8_t spare04 : 1;
uint8_t spare05 : 1;
uint8_t spare06 : 1;
uint8_t spare07 : 1;
};
} StateBitfield;
// See issue https://github.com/esp8266/Arduino/issues/2913
#ifdef USE_ADC_VCC
ADC_MODE(ADC_VCC); // Set ADC input for Power Supply Voltage usage

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
@ -109,11 +111,15 @@ typedef unsigned long power_t; // Power (Relay) type
#define SERIAL_POLLING 100 // Serial receive polling in ms
#define MAX_STATUS 11 // Max number of status lines
#define NO_EXTRA_4K_HEAP // Allocate 4k heap for WPS in ESP8166/Arduino core v2.4.2 (was always allocated in previous versions)
/*
// Removed from esp8266 core since 20171105
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
*/
#define tmin(a,b) ((a)<(b)?(a):(b))
#define tmax(a,b) ((a)>(b)?(a):(b))
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
@ -167,7 +173,7 @@ enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_RESTART, DT_UPTIME };
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL};
enum WifiConfigOptions {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, MAX_WIFI_OPTION};
enum WifiConfigOptions {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, MAX_WIFI_OPTION};
enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION};

View File

@ -25,7 +25,7 @@
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
====================================================*/
#define VERSION 0x06000003 // 6.0.0c
#define VERSION 0x06010102 // 6.1.1b
// Location specific includes
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
@ -161,6 +161,7 @@ uint8_t stop_flash_rotate = 0; // Allow flash configuration rotatio
int blinks = 201; // Number of LED blinks
uint8_t blinkstate = 0; // LED state
uint8_t blinkspeed = 1; // LED blink rate
uint8_t blockgpio0 = 4; // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit
uint8_t lastbutton[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; // Last button states
@ -169,7 +170,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
@ -184,6 +185,7 @@ uint8_t light_type = 0; // Light types
bool pwm_present = false; // Any PWM channel configured with SetOption15 0
boolean mdns_begun = false;
uint8_t ntp_force_sync = 0; // Force NTP sync
StateBitfield global_state;
RulesBitfield rules_flag;
char my_version[33]; // Composed version string
@ -540,6 +542,53 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
mqtt_data[0] = '\0';
MqttShowState();
}
else if (CMND_SLEEP == command_code) {
if ((payload >= 0) && (payload < 251)) {
if ((!Settings.sleep && payload) || (Settings.sleep && !payload)) restart_flag = 2;
Settings.sleep = payload;
sleep = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_UNIT_NVALUE_UNIT, command, sleep, (Settings.flag.value_units) ? " " D_UNIT_MILLISECOND : "", Settings.sleep, (Settings.flag.value_units) ? " " D_UNIT_MILLISECOND : "");
}
else if ((CMND_UPGRADE == command_code) || (CMND_UPLOAD == command_code)) {
// Check if the payload is numerically 1, and had no trailing chars.
// e.g. "1foo" or "1.2.3" could fool us.
// Check if the version we have been asked to upgrade to is higher than our current version.
// We also need at least 3 chars to make a valid version number string.
if (((1 == data_len) && (1 == payload)) || ((data_len >= 3) && NewerVersion(dataBuf))) {
ota_state_flag = 3;
// snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, Settings.ota_url);
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, GetOtaUrl(stemp1, sizeof(stemp1)));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_ONE_OR_GT "\"}", command, my_version);
}
}
else if (CMND_OTAURL == command_code) {
if ((data_len > 0) && (data_len < sizeof(Settings.ota_url)))
strlcpy(Settings.ota_url, (1 == payload) ? OTA_URL : dataBuf, sizeof(Settings.ota_url));
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.ota_url);
}
else if (CMND_SERIALLOG == command_code) {
if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
Settings.flag.mqtt_serial = 0;
SetSeriallog(payload);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.seriallog_level, seriallog_level);
}
else if (CMND_RESTART == command_code) {
switch (payload) {
case 1:
restart_flag = 2;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_RESTARTING);
break;
case 99:
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
EspRestart();
break;
default:
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESTART);
}
}
else if ((CMND_POWERONSTATE == command_code) && (Settings.module != MOTOR)) {
/* 0 = Keep relays off after power on
* 1 = Turn relays on after power on, if PulseTime set wait for PulseTime seconds, and turn relays off
@ -854,32 +903,6 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.pulse_counter_debounce);
}
else if (CMND_SLEEP == command_code) {
if ((payload >= 0) && (payload < 251)) {
if ((!Settings.sleep && payload) || (Settings.sleep && !payload)) restart_flag = 2;
Settings.sleep = payload;
sleep = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_UNIT_NVALUE_UNIT, command, sleep, (Settings.flag.value_units) ? " " D_UNIT_MILLISECOND : "", Settings.sleep, (Settings.flag.value_units) ? " " D_UNIT_MILLISECOND : "");
}
else if ((CMND_UPGRADE == command_code) || (CMND_UPLOAD == command_code)) {
// Check if the payload is numerically 1, and had no trailing chars.
// e.g. "1foo" or "1.2.3" could fool us.
// Check if the version we have been asked to upgrade to is higher than our current version.
// We also need at least 3 chars to make a valid version number string.
if (((1 == data_len) && (1 == payload)) || ((data_len >= 3) && NewerVersion(dataBuf))) {
ota_state_flag = 3;
// snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, Settings.ota_url);
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, GetOtaUrl(stemp1, sizeof(stemp1)));
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_ONE_OR_GT "\"}", command, my_version);
}
}
else if (CMND_OTAURL == command_code) {
if ((data_len > 0) && (data_len < sizeof(Settings.ota_url)))
strlcpy(Settings.ota_url, (1 == payload) ? OTA_URL : dataBuf, sizeof(Settings.ota_url));
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.ota_url);
}
else if (CMND_BAUDRATE == command_code) {
if (payload32 > 0) {
payload32 /= 1200; // Make it a valid baudrate
@ -917,13 +940,6 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.serial_delimiter);
}
else if (CMND_SERIALLOG == command_code) {
if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
Settings.flag.mqtt_serial = 0;
SetSeriallog(payload);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.seriallog_level, seriallog_level);
}
else if (CMND_SYSLOG == command_code) {
if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
Settings.syslog_level = payload;
@ -976,7 +992,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
else if ((CMND_SSID == command_code) && (index > 0) && (index <= 2)) {
if ((data_len > 0) && (data_len < sizeof(Settings.sta_ssid[0]))) {
strlcpy(Settings.sta_ssid[index -1], (1 == payload) ? (1 == index) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(Settings.sta_ssid[0]));
strlcpy(Settings.sta_ssid[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1 == index) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(Settings.sta_ssid[0]));
Settings.sta_active = index -1;
restart_flag = 2;
}
@ -984,7 +1000,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
else if ((CMND_PASSWORD == command_code) && (index > 0) && (index <= 2)) {
if ((data_len > 0) && (data_len < sizeof(Settings.sta_pwd[0]))) {
strlcpy(Settings.sta_pwd[index -1], (1 == payload) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0]));
strlcpy(Settings.sta_pwd[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0]));
Settings.sta_active = index -1;
restart_flag = 2;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_pwd[index -1]);
@ -1040,20 +1056,6 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_UNIT, command, Settings.tele_period, (Settings.flag.value_units) ? " " D_UNIT_SECOND : "");
}
else if (CMND_RESTART == command_code) {
switch (payload) {
case 1:
restart_flag = 2;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_RESTARTING);
break;
case 99:
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
EspRestart();
break;
default:
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESTART);
}
}
else if (CMND_RESET == command_code) {
switch (payload) {
case 1:
@ -1721,7 +1723,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]--;
@ -1802,6 +1804,7 @@ void SwitchHandler(byte mode)
void StateLoop()
{
power_t power_now;
uint8_t blinkinterval = 1;
state_loop_timer = millis() + (1000 / STATES);
state++;
@ -1879,27 +1882,38 @@ void StateLoop()
\*-------------------------------------------------------------------------------------------*/
if (!(state % ((STATES/10)*2))) {
if (!Settings.flag.global_state) { // Problem blinkyblinky enabled
if (global_state.data) { // Any problem
if (global_state.mqtt_down) { blinkinterval = 9; } // MQTT problem so blink every 2 seconds (slowest)
if (global_state.wifi_down) { blinkinterval = 4; } // Wifi problem so blink every second (slow)
blinks = 201; // Allow only a single blink in case the problem is solved
}
}
if (blinks || restart_flag || ota_state_flag) {
if (restart_flag || ota_state_flag) {
blinkstate = 1; // Stay lit
if (restart_flag || ota_state_flag) { // Overrule blinks and keep led lit
blinkstate = 1; // Stay lit
} else {
blinkstate ^= 1; // Blink
blinkspeed--;
if (!blinkspeed) {
blinkspeed = blinkinterval; // Set interval to 0.2 (default), 1 or 2 seconds
blinkstate ^= 1; // Blink
}
}
if ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) {
SetLedPower(blinkstate);
// if ( (!Settings.flag.global_state && global_state.data) || ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) ) {
SetLedPower(blinkstate); // Set led on or off
}
if (!blinkstate) {
blinks--;
if (200 == blinks) blinks = 0;
if (200 == blinks) blinks = 0; // Disable blink
}
} else {
if (Settings.ledstate &1) {
boolean tstate = power;
if ((SONOFF_TOUCH == Settings.module) || (SONOFF_T11 == Settings.module) || (SONOFF_T12 == Settings.module) || (SONOFF_T13 == Settings.module)) {
tstate = (!power) ? 1 : 0;
}
SetLedPower(tstate);
}
else if (Settings.ledstate &1) {
boolean tstate = power;
if ((SONOFF_TOUCH == Settings.module) || (SONOFF_T11 == Settings.module) || (SONOFF_T12 == Settings.module) || (SONOFF_T13 == Settings.module)) {
tstate = (!power) ? 1 : 0; // As requested invert signal for Touch devices to find them in the dark
}
SetLedPower(tstate);
}
}
@ -2142,6 +2156,7 @@ void SerialInput()
}
}
#ifdef USE_ENERGY_SENSOR
/*-------------------------------------------------------------------------------------------*\
* Sonoff S31 and Sonoff Pow R2 4800 baud serial interface
\*-------------------------------------------------------------------------------------------*/
@ -2152,7 +2167,7 @@ void SerialInput()
return;
}
}
#endif // USE_ENERGY_SENSOR
/*-------------------------------------------------------------------------------------------*/
if (serial_in_byte > 127) { // binary data...
@ -2364,10 +2379,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

@ -51,6 +51,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#endif
#define USE_DHT // Default DHT11 sensor needs no external library
#define USE_ENERGY_SENSOR // Use energy sensors
/*********************************************************************************************\
* [sonoff-allsensors.bin]
@ -58,6 +59,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
\*********************************************************************************************/
#ifdef USE_ALL_SENSORS
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
#define USE_DS18x20 // For more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
//#define USE_DS18x20_LEGACY // For more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code)
@ -65,16 +67,19 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#define USE_SHT // Add I2C emulating code for SHT1X sensor (+1k4 code)
#define USE_SHT3X // Add I2C code for SHT3x sensor (+0k6 code)
#define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor (+1k5 code)
#define USE_LM75AD // Add I2C code for LM75AD sensor (+0k5 code)
#define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code)
#define USE_BME680 // Add additional support for BME680 sensor using Adafruit Sensor and BME680 libraries (+6k code)
#define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code)
#define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code)
#define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code)
#define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code)
#define USE_TSL2561 // Add I2C code for TSL2561 sensor using library Adafruit TSL2561 Arduino (+1k2 code)
//#define USE_SI1145 // Add I2C code for SI1145/46/47 sensor (+1k code)
#define USE_ADS1115 // Add I2C code for ADS1115 16 bit A/D converter based on Adafruit ADS1x15 library (no library needed) (+0k7 code)
//#define USE_ADS1115_I2CDEV // Add I2C code for ADS1115 16 bit A/D converter using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code)
#define USE_INA219 // Add I2C code for INA219 Low voltage and current sensor (+1k code)
#define USE_MGS // Add I2C code for Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code)
//#define USE_APDS9960 // Add I2C code for APDS9960 Proximity Sensor. Disables SHT and VEML6070 (+4k7 code)
#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code)
#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)
#ifndef CO2_LOW
@ -87,6 +92,8 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code)
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code)
#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy meter (+1k7 code)
#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy meter (+2k code)
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram)
#define USE_IR_HVAC // Support for HVAC system using IR (+2k code)
#define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram)
@ -105,36 +112,28 @@ void KNX_CB_Action(message_t const &msg, void *arg);
\*********************************************************************************************/
#ifdef USE_CLASSIC
#ifdef USE_KNX
#undef USE_KNX
#endif
#ifdef USE_TIMERS
#undef USE_TIMERS
#endif
#ifdef USE_TIMERS_WEB
#undef USE_TIMERS_WEB
#endif
#ifdef USE_SUNRISE
#undef USE_SUNRISE
#endif
#ifdef USE_RULES
#undef USE_RULES
#endif
#ifdef USE_SGP30
#undef USE_SGP30
#endif
#ifdef USE_NOVA_SDS
#undef USE_NOVA_SDS
#endif
#ifdef USE_IR_RECEIVE
#undef USE_IR_RECEIVE
#endif
#ifdef USE_SERIAL_BRIDGE
#undef USE_SERIAL_BRIDGE
#endif
#ifdef USE_SR04
#undef USE_SR04
#endif
#undef USE_KNX // Disable KNX IP Protocol Support
#undef USE_TIMERS // Disable support for up to 16 timers
#undef USE_TIMERS_WEB // Disable support for timer webpage
#undef USE_SUNRISE // Disable support for Sunrise and sunset tools
#undef USE_RULES // Disable support for rules
#undef USE_LM75AD // Disable sensor
#undef USE_BME680 // Disable sensor
#undef USE_SGP30 // Disable sensor
#undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor
#undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor
#undef USE_PZEM004T // Disable PZEM004T energy sensor
#undef USE_IR_RECEIVE // Disable support for IR receiver
#undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge
#undef USE_SDM120 // Disable support for Eastron SDM120-Modbus energy meter
#undef USE_SDM630 // Disable support for Eastron SDM630-Modbus energy meter
#undef USE_ARILUX_RF // Disable support for Arilux RF remote controller
#undef USE_SR04 // Disable support for for HC-SR04 ultrasonic devices
#undef USE_TM1638 // Disable support for TM1638 switches copying Switch1 .. Switch8
#undef USE_RF_FLASH // Disable support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB
#undef DEBUG_THEO // Disable debug code
#undef USE_DEBUG_DRIVER // Disable debug code
#endif // USE_CLASSIC
/*********************************************************************************************\
@ -143,12 +142,11 @@ void KNX_CB_Action(message_t const &msg, void *arg);
\*********************************************************************************************/
#ifdef USE_KNX_NO_EMULATION
#ifndef USE_KNX
#define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem)
#endif
#ifdef USE_EMULATION
#undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem)
#endif
#endif // USE_KNX_NO_EMULATION
/*********************************************************************************************\
@ -166,96 +164,55 @@ void KNX_CB_Action(message_t const &msg, void *arg);
\*********************************************************************************************/
#ifdef BE_MINIMAL
#ifdef USE_MQTT_TLS
#undef USE_MQTT_TLS // Disable TLS support won't work as the MQTTHost is not set
#endif
#ifdef USE_DISCOVERY
#undef USE_DISCOVERY // Disable Discovery services for both MQTT and web server
#endif
#ifdef USE_DOMOTICZ
#undef USE_ENERGY_SENSOR // Disable energy sensors
#undef USE_ARDUINO_OTA // Disable support for Arduino OTA
#undef USE_WPS // Disable support for WPS as initial wifi configuration tool
#undef USE_SMARTCONFIG // Disable support for Wifi SmartConfig as initial wifi configuration tool
#undef USE_DOMOTICZ // Disable Domoticz
#endif
#ifdef USE_HOME_ASSISTANT
#undef USE_HOME_ASSISTANT // Disable Home Assistant
#endif
#ifdef USE_KNX
#undef USE_MQTT_TLS // Disable TLS support won't work as the MQTTHost is not set
#undef USE_KNX // Disable KNX IP Protocol Support
#endif
//#ifdef USE_WEBSERVER
//#undef USE_WEBSERVER // Disable Webserver
//#endif
#ifdef USE_EMULATION
#undef USE_DISCOVERY // Disable Discovery services for both MQTT and web server
#undef USE_EMULATION // Disable Wemo or Hue emulation
#endif
#ifdef USE_TIMERS
#undef USE_TIMERS // Disable support for up to 16 timers
#endif
#ifdef USE_SUNRISE
#undef USE_TIMERS_WEB // Disable support for timer webpage
#undef USE_SUNRISE // Disable support for Sunrise and sunset tools
#endif
#ifdef USE_RULES
#undef USE_RULES // Disable support for rules
#endif
#ifdef USE_DHT
#undef USE_DHT // Disable internal DHT sensor
#endif
#ifdef USE_DS18x20
#undef USE_DS18x20 // Disable DS18x20 sensor
#endif
#ifdef USE_DS18B20
#undef USE_DS18x20_LEGACY // Disable DS18x20 sensor
#undef USE_DS18B20 // Disable internal DS18B20 sensor
#endif
#ifdef USE_I2C
#undef USE_I2C // Disable all I2C sensors and devices
#endif
#ifdef USE_SPI
#undef USE_SPI // Disable all SPI devices
#endif
#ifdef USE_DISPLAY
#undef USE_DISPLAY // Disable Display support
#endif
#ifdef USE_MHZ19
#undef USE_MHZ19 // Disable support for MH-Z19 CO2 sensor
#endif
#ifdef USE_SENSEAIR
#undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor
#endif
#ifdef USE_PMS5003
#undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor
#endif
#ifdef USE_NOVA_SDS
#undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor
#endif
#ifdef USE_PZEM004T
#undef USE_PZEM004T // Disable PZEM004T energy sensor
#endif
#ifdef USE_SERIAL_BRIDGE
#undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge
#endif
#ifdef USE_IR_REMOTE
#undef USE_SDM120 // Disable support for Eastron SDM120-Modbus energy meter
#undef USE_SDM630 // Disable support for Eastron SDM630-Modbus energy meter
#undef USE_IR_REMOTE // Disable IR driver
#endif
#ifdef USE_WS2812
#undef USE_WS2812 // Disable WS2812 Led string
#endif
#ifdef USE_ARILUX_RF
#undef USE_ARILUX_RF // Disable support for Arilux RF remote controller
#endif
#ifdef USE_SR04
#undef USE_SR04 // Disable support for for HC-SR04 ultrasonic devices
#endif
#ifdef DEBUG_THEO
#undef USE_TM1638 // Disable support for TM1638 switches copying Switch1 .. Switch8
#undef USE_RF_FLASH // Disable support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB
#undef DEBUG_THEO // Disable debug code
#endif
#ifdef USE_DEBUG_DRIVER
#undef USE_DEBUG_DRIVER // Disable debug code
#endif
#endif // BE_MINIMAL
/*********************************************************************************************\
* Mandatory defines satisfying possible disabled defines
\*********************************************************************************************/
#ifndef USE_WPS // See https://github.com/esp8266/Arduino/pull/4889
#undef NO_EXTRA_4K_HEAP // Allocate 4k heap for WPS in ESP8166/Arduino core v2.4.2 (was always allocated in previous versions)
#endif
#ifndef SWITCH_MODE
#define SWITCH_MODE TOGGLE // TOGGLE, FOLLOW or FOLLOW_INV (the wall switch state)
#endif

View File

@ -735,6 +735,12 @@ void GetFeatures()
#ifdef USE_KNX
feature_drv1 |= 0x10000000; // xdrv_11_knx.ino
#endif
#ifdef USE_WPS
feature_drv1 |= 0x20000000; // support.ino
#endif
#ifdef USE_SMARTCONFIG
feature_drv1 |= 0x40000000; // support.ino
#endif
/*********************************************************************************************/
@ -954,42 +960,49 @@ boolean WifiWpsConfigDone(void)
boolean WifiWpsConfigBegin(void)
{
wps_result = 99;
if (!wifi_wps_disable()) {
return false;
}
if (!wifi_wps_enable(WPS_TYPE_PBC)) {
return false; // so far only WPS_TYPE_PBC is supported (SDK 2.0.0)
}
if (!wifi_set_wps_cb((wps_st_cb_t) &WifiWpsStatusCallback)) {
return false;
}
if (!wifi_wps_start()) {
return false;
}
if (!wifi_wps_disable()) { return false; }
if (!wifi_wps_enable(WPS_TYPE_PBC)) { return false; } // so far only WPS_TYPE_PBC is supported (SDK 2.0.0)
if (!wifi_set_wps_cb((wps_st_cb_t) &WifiWpsStatusCallback)) { return false; }
if (!wifi_wps_start()) { return false; }
return true;
}
void WifiConfig(uint8_t type)
{
if (!wifi_config_type) {
if (type >= WIFI_RETRY) { // WIFI_RETRY and WIFI_WAIT
return;
}
if ((WIFI_RETRY == type) || (WIFI_WAIT == type)) { return; }
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
UdpDisconnect();
#endif // USE_EMULATION
WiFi.disconnect(); // Solve possible Wifi hangs
WiFi.disconnect(); // Solve possible Wifi hangs
wifi_config_type = type;
#ifndef USE_WPS
if (WIFI_WPSCONFIG == wifi_config_type) { wifi_config_type = WIFI_MANAGER; }
#endif // USE_WPS
#ifndef USE_WEBSERVER
if (WIFI_MANAGER == wifi_config_type) { wifi_config_type = WIFI_SMARTCONFIG; }
#endif // USE_WEBSERVER
#ifndef USE_SMARTCONFIG
if (WIFI_SMARTCONFIG == wifi_config_type) { wifi_config_type = WIFI_SERIAL; }
#endif // USE_SMARTCONFIG
wifi_config_counter = WIFI_CONFIG_SEC; // Allow up to WIFI_CONFIG_SECS seconds for phone to provide ssid/pswd
wifi_counter = wifi_config_counter +5;
blinks = 1999;
if (WIFI_RESTART == wifi_config_type) {
restart_flag = 2;
}
else if (WIFI_SERIAL == wifi_config_type) {
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_6_SERIAL " " D_ACTIVE_FOR_3_MINUTES));
}
#ifdef USE_SMARTCONFIG
else if (WIFI_SMARTCONFIG == wifi_config_type) {
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_1_SMARTCONFIG " " D_ACTIVE_FOR_3_MINUTES));
WiFi.beginSmartConfig();
}
#endif // USE_SMARTCONFIG
#ifdef USE_WPS
else if (WIFI_WPSCONFIG == wifi_config_type) {
if (WifiWpsConfigBegin()) {
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_3_WPSCONFIG " " D_ACTIVE_FOR_3_MINUTES));
@ -998,6 +1011,7 @@ void WifiConfig(uint8_t type)
wifi_config_counter = 3;
}
}
#endif // USE_WPS
#ifdef USE_WEBSERVER
else if (WIFI_MANAGER == wifi_config_type) {
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES));
@ -1023,17 +1037,11 @@ void WifiBegin(uint8_t flag)
WiFi.disconnect(true); // Delete SDK wifi config
delay(200);
WiFi.mode(WIFI_STA); // Disable AP mode
if (Settings.sleep) {
#ifndef ARDUINO_ESP8266_RELEASE_2_4_1 // See https://github.com/arendst/Sonoff-Tasmota/issues/2559
WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
#ifndef ARDUINO_ESP8266_RELEASE_2_4_1 // See https://github.com/arendst/Sonoff-Tasmota/issues/2559 - Sleep bug
if (Settings.sleep) { WiFi.setSleepMode(WIFI_LIGHT_SLEEP); } // Allow light sleep during idle times
#endif
}
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) {
// WiFi.setPhyMode(WIFI_PHY_MODE_11N);
// }
if (!WiFi.getAutoConnect()) {
WiFi.setAutoConnect(true);
}
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); }
if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); }
// WiFi.setAutoReconnect(true);
switch (flag) {
case 0: // AP1
@ -1043,9 +1051,7 @@ void WifiBegin(uint8_t flag)
case 2: // Toggle
Settings.sta_active ^= 1;
} // 3: Current AP
if (0 == strlen(Settings.sta_ssid[1])) {
Settings.sta_active = 0;
}
if ('\0' == Settings.sta_ssid[Settings.sta_active][0]) { Settings.sta_active ^= 1; } // Skip empty SSID
if (Settings.ip_address[0]) {
WiFi.config(Settings.ip_address[0], Settings.ip_address[1], Settings.ip_address[2], Settings.ip_address[3]); // Set static IP
}
@ -1059,6 +1065,7 @@ void WifiBegin(uint8_t flag)
void WifiCheckIp()
{
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0)) {
global_state.wifi_down = 0;
wifi_counter = WIFI_CHECK_SEC;
wifi_retry = wifi_retry_init;
AddLog_P((wifi_status != WL_CONNECTED) ? LOG_LEVEL_INFO : LOG_LEVEL_DEBUG_MORE, S_LOG_WIFI, PSTR(D_CONNECTED));
@ -1070,6 +1077,8 @@ void WifiCheckIp()
}
wifi_status = WL_CONNECTED;
} else {
global_state.wifi_down = 1;
uint8_t wifi_config_tool = Settings.sta_config;
wifi_status = WiFi.status();
switch (wifi_status) {
case WL_CONNECTED:
@ -1103,7 +1112,12 @@ void WifiCheckIp()
if (!wifi_retry || ((wifi_retry_init / 2) == wifi_retry)) {
AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_TIMEOUT));
} else {
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_ATTEMPTING_CONNECTION));
if (('\0' == Settings.sta_ssid[0][0]) && ('\0' == Settings.sta_ssid[1][0])) {
wifi_config_tool = WIFI_CONFIG_NO_SSID; // Skip empty SSIDs and start Wifi config tool
wifi_retry = 0;
} else {
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_ATTEMPTING_CONNECTION));
}
}
}
if (wifi_retry) {
@ -1116,7 +1130,7 @@ void WifiCheckIp()
wifi_counter = 1;
wifi_retry--;
} else {
WifiConfig(Settings.sta_config);
WifiConfig(wifi_config_tool);
wifi_counter = 1;
wifi_retry = wifi_retry_init;
}
@ -1127,6 +1141,7 @@ void WifiCheck(uint8_t param)
{
wifi_counter--;
switch (param) {
case WIFI_SERIAL:
case WIFI_SMARTCONFIG:
case WIFI_MANAGER:
case WIFI_WPSCONFIG:
@ -1137,12 +1152,16 @@ void WifiCheck(uint8_t param)
wifi_config_counter--;
wifi_counter = wifi_config_counter +5;
if (wifi_config_counter) {
#ifdef USE_SMARTCONFIG
if ((WIFI_SMARTCONFIG == wifi_config_type) && WiFi.smartConfigDone()) {
wifi_config_counter = 0;
}
#endif // USE_SMARTCONFIG
#ifdef USE_WPS
if ((WIFI_WPSCONFIG == wifi_config_type) && WifiWpsConfigDone()) {
wifi_config_counter = 0;
}
#endif // USE_WPS
if (!wifi_config_counter) {
if (strlen(WiFi.SSID().c_str())) {
strlcpy(Settings.sta_ssid[0], WiFi.SSID().c_str(), sizeof(Settings.sta_ssid[0]));
@ -1156,10 +1175,10 @@ void WifiCheck(uint8_t param)
}
}
if (!wifi_config_counter) {
if (WIFI_SMARTCONFIG == wifi_config_type) {
WiFi.stopSmartConfig();
}
SettingsSdkErase();
#ifdef USE_SMARTCONFIG
if (WIFI_SMARTCONFIG == wifi_config_type) { WiFi.stopSmartConfig(); }
#endif // USE_SMARTCONFIG
// SettingsSdkErase(); // Disabled v6.1.0b due to possible bad wifi connects
restart_flag = 2;
}
} else {
@ -1169,6 +1188,7 @@ void WifiCheck(uint8_t param)
WifiCheckIp();
}
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0) && !wifi_config_type) {
global_state.wifi_down = 0;
#ifdef BE_MINIMAL
if (1 == RtcSettings.ota_loader) {
RtcSettings.ota_loader = 0;
@ -1194,9 +1214,7 @@ void WifiCheck(uint8_t param)
StopWebserver();
}
#ifdef USE_EMULATION
if (Settings.flag2.emulation) {
UdpConnect();
}
if (Settings.flag2.emulation) { UdpConnect(); }
#endif // USE_EMULATION
#endif // USE_WEBSERVER
#ifdef USE_KNX
@ -1206,6 +1224,7 @@ void WifiCheck(uint8_t param)
}
#endif // USE_KNX
} else {
global_state.wifi_down = 1;
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
UdpDisconnect();
#endif // USE_EMULATION
@ -1225,9 +1244,7 @@ int WifiState()
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0)) {
state = WIFI_RESTART;
}
if (wifi_config_type) {
state = wifi_config_type;
}
if (wifi_config_type) { state = wifi_config_type; }
return state;
}
@ -1240,6 +1257,8 @@ void WifiConnect()
wifi_counter = 1;
}
/*
// Enable from 6.0.0a until 6.1.0a - disabled due to possible cause of bad wifi connect on core 2.3.0
void WifiDisconnect()
{
// Courtesy of EspEasy
@ -1252,10 +1271,17 @@ void WifiDisconnect()
void EspRestart()
{
delay(100); // Allow time for message xfer
// This results in exception 3 on restarts
delay(100); // Allow time for message xfer - disabled v6.1.0b
WifiDisconnect();
ESP.restart();
}
*/
void EspRestart()
{
ESP.restart();
}
#ifdef USE_DISCOVERY
/*********************************************************************************************\
@ -2076,6 +2102,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

@ -44,7 +44,7 @@
\*********************************************************************************************/
// -- Master parameter control --------------------
#define CFG_HOLDER 4617 // [Reset 1] Change this value to load SECTION1 configuration parameters to flash
#define CFG_HOLDER 4617 // [Reset 1] Change this value (max 32000) to load SECTION1 configuration parameters to flash
// -- Project -------------------------------------
#define PROJECT "sonoff" // PROJECT is used as the default topic delimiter
@ -63,8 +63,13 @@
#define STA_PASS1 "" // [Password1] Wifi password
#define STA_SSID2 "" // [Ssid2] Optional alternate AP Wifi SSID
#define STA_PASS2 "" // [Password2] Optional alternate AP Wifi password
#define WIFI_CONFIG_TOOL WIFI_WPSCONFIG // [WifiConfig] Default tool if wifi fails to connect
// (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT)
#define WIFI_CONFIG_TOOL WIFI_WAIT // [WifiConfig] Default tool if wifi fails to connect
// (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL)
#define WIFI_CONFIG_NO_SSID WIFI_WPSCONFIG // Default tool if wifi fails to connect and no SSID is configured
// (WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_SERIAL)
// *** NOTE: When WPS is disabled by USE_WPS below, WIFI_WPSCONFIG will execute WIFI_MANAGER ***
// *** NOTE: When WIFI_MANAGER is disabled by USE_WEBSERVER below, WIFI_MANAGER will execute WIFI_SMARTCONFIG ***
// *** NOTE: When WIFI_SMARTCONFIG is disabled by USE_SMARTCONFIG below, WIFI_SMARTCONFIG will execute WIFI_SERIAL ***
// -- Syslog --------------------------------------
#define SYS_LOG_HOST "" // [LogHost] (Linux) syslog host
@ -178,8 +183,6 @@
* - Disable a feature by preceding it with //
\*********************************************************************************************/
//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code)
// -- Localization --------------------------------
// If non selected the default en-GB will be used
//#define MY_LANGUAGE bg-BG // Bulgarian in Bulgaria
@ -200,6 +203,13 @@
//#define MY_LANGUAGE zh-CN // Chinese (Simplified) in China
//#define MY_LANGUAGE zh-TW // Chinese (Traditional) in Taiwan
// -- Wifi Config tools ---------------------------
//#define USE_WPS // Add support for WPS as initial wifi configuration tool (+33k code, 1k mem (5k mem with core v2.4.2+))
//#define USE_SMARTCONFIG // Add support for Wifi SmartConfig as initial wifi configuration tool (+23k code, +0.6k mem)
// -- OTA -----------------------------------------
//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code)
/*-------------------------------------------------------------------------------------------*\
* Select ONE of possible three MQTT library types below
\*-------------------------------------------------------------------------------------------*/
@ -230,7 +240,7 @@
//#define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem)
// -- HTTP ----------------------------------------
#define USE_WEBSERVER // Enable web server and wifi manager (+66k code, +8k mem)
#define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem)
#define WEB_PORT 80 // Web server Port for User and Admin mode
#define WEB_USERNAME "admin" // Web server Admin mode user name
#define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+16k code, +2k mem)
@ -265,7 +275,7 @@
#define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor (+1k5 code)
#define USE_LM75AD // Add I2C code for LM75AD sensor (+0k5 code)
#define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code)
// #define USE_BME680 // Add additional support for BME680 sensor using Adafruit Sensor and BME680 libraries (+6k code)
// #define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code)
#define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code)
#define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code)
// #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code)
@ -277,8 +287,13 @@
// #define USE_MGS // Add I2C code for Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code)
#define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address
// #define USE_APDS9960 // Add I2C code for APDS9960 Proximity Sensor. Disables SHT and VEML6070 (+4k7 code)
// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons
// #define USE_MCP230xx // Add I2C code for MCP23008/MCP23017 for GP INPUT ONLY providing command Sensor29 for configuration (+2k2 code)
// #define USE_MCP230xx_displaymain // Display pin status on Tasmota main page (+0k2 code)
// #define USE_MCP230xx_webconfig // Enable web config button and form to Tasmota web interface (+2k1 code)
#endif // USE_I2C
// -- SPI sensors ---------------------------------
@ -314,9 +329,9 @@
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
//#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code)
#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code)
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code)
/*********************************************************************************************\
* Debug features are only supported in development branch

View File

@ -383,6 +383,7 @@ void MqttConnected()
}
mqtt_initial_connection_state = 0;
rules_flag.mqtt_connected = 1;
global_state.mqtt_down = 0;
}
#ifdef USE_MQTT_TLS
@ -443,6 +444,7 @@ void MqttReconnect()
mqtt_connected = false;
mqtt_retry_counter = Settings.mqtt_retry;
global_state.mqtt_down = 1;
#ifndef USE_MQTT_TLS
#ifdef USE_DISCOVERY
@ -512,13 +514,17 @@ void MqttCheck()
{
if (Settings.flag.mqtt_enabled) {
if (!MqttIsConnected()) {
global_state.mqtt_down = 1;
if (!mqtt_retry_counter) {
MqttReconnect();
} else {
mqtt_retry_counter--;
}
} else {
global_state.mqtt_down = 0;
}
} else {
global_state.mqtt_down = 0;
if (mqtt_initial_connection_state) MqttReconnect();
}
}

View File

@ -190,6 +190,10 @@ const char HTTP_BTN_RSTRT[] PROGMEM =
"<br/><form action='rb' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESTART "\");'><button class='button bred'>" D_RESTART "</button></form>";
const char HTTP_BTN_MENU_MODULE[] PROGMEM =
"<br/><form action='md' method='get'><button>" D_CONFIGURE_MODULE "</button></form>";
#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig)
const char HTTP_BTN_MCP230XX[] PROGMEM =
"<br/><form action='mc' method='get'><button>" D_CONFIGURE_MCP230XX "</button></form>";
#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
const char HTTP_BTN_MENU_TIMER[] PROGMEM =
"<br/><form action='tm' method='get'><button>" D_CONFIGURE_TIMER "</button></form>";
@ -367,8 +371,21 @@ void StartWebserver(int type, IPAddress ipweb)
if (!WebServer) {
WebServer = new ESP8266WebServer((HTTP_MANAGER==type) ? 80 : WEB_PORT);
WebServer->on("/", HandleRoot);
WebServer->on("/up", HandleUpgradeFirmware);
WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA
WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop);
WebServer->on("/cs", HandleConsole);
WebServer->on("/ax", HandleAjaxConsoleRefresh);
WebServer->on("/ay", HandleAjaxStatusRefresh);
WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest);
WebServer->on("/cm", HandleHttpCommand);
WebServer->on("/rb", HandleRestart);
#ifndef BE_MINIMAL
WebServer->on("/cn", HandleConfiguration);
WebServer->on("/md", HandleModuleConfiguration);
#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig)
WebServer->on("/mc", HandleMCP230xxConfiguration);
#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
WebServer->on("/tm", HandleTimerConfiguration);
#endif // USE_TIMERS and USE_TIMERS_WEB
@ -389,17 +406,7 @@ void StartWebserver(int type, IPAddress ipweb)
WebServer->on("/sv", HandleSaveSettings);
WebServer->on("/rs", HandleRestoreConfiguration);
WebServer->on("/rt", HandleResetConfiguration);
WebServer->on("/up", HandleUpgradeFirmware);
WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA
WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop);
WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest);
WebServer->on("/cm", HandleHttpCommand);
WebServer->on("/cs", HandleConsole);
WebServer->on("/ax", HandleAjaxConsoleRefresh);
WebServer->on("/ay", HandleAjaxStatusRefresh);
WebServer->on("/in", HandleInformation);
WebServer->on("/rb", HandleRestart);
WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
#ifdef USE_EMULATION
if (EMUL_WEMO == Settings.flag2.emulation) {
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
@ -411,6 +418,8 @@ void StartWebserver(int type, IPAddress ipweb)
WebServer->on("/description.xml", HandleUpnpSetupHue);
}
#endif // USE_EMULATION
#endif // Not BE_MINIMAL
WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
WebServer->onNotFound(HandleNotFound);
}
reset_web_log_flag = 0;
@ -520,6 +529,7 @@ void HandleRoot()
if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the page.
if (HTTP_MANAGER == webserver_state) {
#ifndef BE_MINIMAL
if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1"))) {
HandleWifiLogin();
} else {
@ -537,6 +547,7 @@ void HandleRoot()
HandleWifiLogin();
}
}
#endif // Not BE_MINIMAL
} else {
char stemp[10];
String page = FPSTR(HTTP_HEAD);
@ -672,6 +683,7 @@ boolean HttpUser()
return status;
}
#ifndef BE_MINIMAL
void HandleConfiguration()
{
if (HttpUser()) { return; }
@ -681,6 +693,11 @@ void HandleConfiguration()
page.replace(F("{v}"), FPSTR(S_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_BTN_MENU_MODULE);
#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig)
if (MCP230xx_Type()) { // Configuration button will only show if MCP23008/MCP23017 was detected on I2C
page += FPSTR(HTTP_BTN_MCP230XX);
}
#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
#ifdef USE_RULES
page += FPSTR(HTTP_BTN_MENU_TIMER);
@ -1119,6 +1136,11 @@ void HandleSaveSettings()
}
AddLog(LOG_LEVEL_INFO);
break;
#if defined(USE_I2C) && defined(USE_MCP230xx) && defined(USE_MCP230xx_webconfig)
case 8:
MCP230xx_SaveSettings();
break;
#endif // USE_I2C and USE_MCP230xx and USE_MCP230xx_webconfig
case 6:
WebGetArg("g99", tmp, sizeof(tmp));
byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp);
@ -1205,6 +1227,122 @@ void HandleRestoreConfiguration()
upload_file_type = UPL_SETTINGS;
}
void HandleInformation()
{
if (HttpUser()) { return; }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_INFORMATION);
char stopic[TOPSZ];
int freeMem = ESP.getFreeHeap();
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_INFORMATION));
page += FPSTR(HTTP_HEAD_STYLE);
// page += F("<fieldset><legend><b>&nbsp;Information&nbsp;</b></legend>");
page += F("<style>td{padding:0px 5px;}</style>");
page += F("<div id='i' name='i'></div>");
// Save 1k of code space replacing table html with javascript replace codes
// }1 = </td></tr><tr><th>
// }2 = </th><td>
String func = FPSTR(HTTP_SCRIPT_INFO_BEGIN);
func += F("<table style='width:100%'><tr><th>");
func += F(D_PROGRAM_VERSION "}2"); func += my_version;
func += F("}1" D_BUILD_DATE_AND_TIME "}2"); func += GetBuildDateAndTime();
func += F("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/"); func += String(ESP.getSdkVersion());
func += F("}1" D_UPTIME "}2"); func += GetDateAndTime(DT_UPTIME);
snprintf_P(stopic, sizeof(stopic), PSTR(" at %X"), GetSettingsAddress());
func += F("}1" D_FLASH_WRITE_COUNT "}2"); func += String(Settings.save_flag); func += stopic;
func += F("}1" D_BOOT_COUNT "}2"); func += String(Settings.bootcount);
func += F("}1" D_RESTART_REASON "}2"); func += GetResetReason();
uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; }
for (byte i = 0; i < maxfn; i++) {
func += F("}1" D_FRIENDLY_NAME " "); func += i +1; func += F("}2"); func += Settings.friendlyname[i];
}
func += F("}1}2&nbsp;"); // Empty line
func += F("}1" D_AP); func += String(Settings.sta_active +1);
func += F(" " D_SSID " (" D_RSSI ")}2"); func += Settings.sta_ssid[Settings.sta_active]; func += F(" ("); func += WifiGetRssiAsQuality(WiFi.RSSI()); func += F("%)");
func += F("}1" D_HOSTNAME "}2"); func += my_hostname;
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
func += F("}1" D_IP_ADDRESS "}2"); func += WiFi.localIP().toString();
func += F("}1" D_GATEWAY "}2"); func += IPAddress(Settings.ip_address[1]).toString();
func += F("}1" D_SUBNET_MASK "}2"); func += IPAddress(Settings.ip_address[2]).toString();
func += F("}1" D_DNS_SERVER "}2"); func += IPAddress(Settings.ip_address[3]).toString();
func += F("}1" D_MAC_ADDRESS "}2"); func += WiFi.macAddress();
}
if (static_cast<uint32_t>(WiFi.softAPIP()) != 0) {
func += F("}1" D_AP " " D_IP_ADDRESS "}2"); func += WiFi.softAPIP().toString();
func += F("}1" D_AP " " D_GATEWAY "}2"); func += WiFi.softAPIP().toString();
func += F("}1" D_AP " " D_MAC_ADDRESS "}2"); func += WiFi.softAPmacAddress();
}
func += F("}1}2&nbsp;"); // Empty line
if (Settings.flag.mqtt_enabled) {
func += F("}1" D_MQTT_HOST "}2"); func += Settings.mqtt_host;
func += F("}1" D_MQTT_PORT "}2"); func += String(Settings.mqtt_port);
func += F("}1" D_MQTT_CLIENT " &<br/>&nbsp;" D_FALLBACK_TOPIC "}2"); func += mqtt_client;
func += F("}1" D_MQTT_USER "}2"); func += Settings.mqtt_user;
func += F("}1" D_MQTT_TOPIC "}2"); func += Settings.mqtt_topic;
func += F("}1" D_MQTT_GROUP_TOPIC "}2"); func += Settings.mqtt_grptopic;
GetTopic_P(stopic, CMND, mqtt_topic, "");
func += F("}1" D_MQTT_FULL_TOPIC "}2"); func += stopic;
} else {
func += F("}1" D_MQTT "}2" D_DISABLED);
}
func += F("}1}2&nbsp;"); // Empty line
func += F("}1" D_EMULATION "}2");
#ifdef USE_EMULATION
if (EMUL_WEMO == Settings.flag2.emulation) {
func += F(D_BELKIN_WEMO);
}
else if (EMUL_HUE == Settings.flag2.emulation) {
func += F(D_HUE_BRIDGE);
}
else {
func += F(D_NONE);
}
#else
func += F(D_DISABLED);
#endif // USE_EMULATION
func += F("}1" D_MDNS_DISCOVERY "}2");
#ifdef USE_DISCOVERY
func += F(D_ENABLED);
func += F("}1" D_MDNS_ADVERTISE "}2");
#ifdef WEBSERVER_ADVERTISE
func += F(D_WEB_SERVER);
#else
func += F(D_DISABLED);
#endif // WEBSERVER_ADVERTISE
#else
func += F(D_DISABLED);
#endif // USE_DISCOVERY
func += F("}1}2&nbsp;"); // Empty line
func += F("}1" D_ESP_CHIP_ID "}2"); func += String(ESP.getChipId());
func += F("}1" D_FLASH_CHIP_ID "}2"); func += String(ESP.getFlashChipId());
func += F("}1" D_FLASH_CHIP_SIZE "}2"); func += String(ESP.getFlashChipRealSize() / 1024); func += F("kB");
func += F("}1" D_PROGRAM_FLASH_SIZE "}2"); func += String(ESP.getFlashChipSize() / 1024); func += F("kB");
func += F("}1" D_PROGRAM_SIZE "}2"); func += String(ESP.getSketchSize() / 1024); func += F("kB");
func += F("}1" D_FREE_PROGRAM_SPACE "}2"); func += String(ESP.getFreeSketchSpace() / 1024); func += F("kB");
func += F("}1" D_FREE_MEMORY "}2"); func += String(freeMem / 1024); func += F("kB");
func += F("</td></tr></table>");
func += FPSTR(HTTP_SCRIPT_INFO_END);
page.replace(F("</script>"), func);
page.replace(F("<body>"), F("<body onload='i()'>"));
// page += F("</fieldset>");
page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page);
}
#endif // Not BE_MINIMAL
void HandleUpgradeFirmware()
{
if (HttpUser()) { return; }
@ -1629,121 +1767,6 @@ void HandleAjaxConsoleRefresh()
WebServer->send(200, FPSTR(HDR_CTYPE_XML), message);
}
void HandleInformation()
{
if (HttpUser()) { return; }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_INFORMATION);
char stopic[TOPSZ];
int freeMem = ESP.getFreeHeap();
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_INFORMATION));
page += FPSTR(HTTP_HEAD_STYLE);
// page += F("<fieldset><legend><b>&nbsp;Information&nbsp;</b></legend>");
page += F("<style>td{padding:0px 5px;}</style>");
page += F("<div id='i' name='i'></div>");
// Save 1k of code space replacing table html with javascript replace codes
// }1 = </td></tr><tr><th>
// }2 = </th><td>
String func = FPSTR(HTTP_SCRIPT_INFO_BEGIN);
func += F("<table style='width:100%'><tr><th>");
func += F(D_PROGRAM_VERSION "}2"); func += my_version;
func += F("}1" D_BUILD_DATE_AND_TIME "}2"); func += GetBuildDateAndTime();
func += F("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/"); func += String(ESP.getSdkVersion());
func += F("}1" D_UPTIME "}2"); func += GetDateAndTime(DT_UPTIME);
snprintf_P(stopic, sizeof(stopic), PSTR(" at %X"), GetSettingsAddress());
func += F("}1" D_FLASH_WRITE_COUNT "}2"); func += String(Settings.save_flag); func += stopic;
func += F("}1" D_BOOT_COUNT "}2"); func += String(Settings.bootcount);
func += F("}1" D_RESTART_REASON "}2"); func += GetResetReason();
uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; }
for (byte i = 0; i < maxfn; i++) {
func += F("}1" D_FRIENDLY_NAME " "); func += i +1; func += F("}2"); func += Settings.friendlyname[i];
}
func += F("}1}2&nbsp;"); // Empty line
func += F("}1" D_AP); func += String(Settings.sta_active +1);
func += F(" " D_SSID " (" D_RSSI ")}2"); func += Settings.sta_ssid[Settings.sta_active]; func += F(" ("); func += WifiGetRssiAsQuality(WiFi.RSSI()); func += F("%)");
func += F("}1" D_HOSTNAME "}2"); func += my_hostname;
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
func += F("}1" D_IP_ADDRESS "}2"); func += WiFi.localIP().toString();
func += F("}1" D_GATEWAY "}2"); func += IPAddress(Settings.ip_address[1]).toString();
func += F("}1" D_SUBNET_MASK "}2"); func += IPAddress(Settings.ip_address[2]).toString();
func += F("}1" D_DNS_SERVER "}2"); func += IPAddress(Settings.ip_address[3]).toString();
func += F("}1" D_MAC_ADDRESS "}2"); func += WiFi.macAddress();
}
if (static_cast<uint32_t>(WiFi.softAPIP()) != 0) {
func += F("}1" D_AP " " D_IP_ADDRESS "}2"); func += WiFi.softAPIP().toString();
func += F("}1" D_AP " " D_GATEWAY "}2"); func += WiFi.softAPIP().toString();
func += F("}1" D_AP " " D_MAC_ADDRESS "}2"); func += WiFi.softAPmacAddress();
}
func += F("}1}2&nbsp;"); // Empty line
if (Settings.flag.mqtt_enabled) {
func += F("}1" D_MQTT_HOST "}2"); func += Settings.mqtt_host;
func += F("}1" D_MQTT_PORT "}2"); func += String(Settings.mqtt_port);
func += F("}1" D_MQTT_CLIENT " &<br/>&nbsp;" D_FALLBACK_TOPIC "}2"); func += mqtt_client;
func += F("}1" D_MQTT_USER "}2"); func += Settings.mqtt_user;
func += F("}1" D_MQTT_TOPIC "}2"); func += Settings.mqtt_topic;
func += F("}1" D_MQTT_GROUP_TOPIC "}2"); func += Settings.mqtt_grptopic;
GetTopic_P(stopic, CMND, mqtt_topic, "");
func += F("}1" D_MQTT_FULL_TOPIC "}2"); func += stopic;
} else {
func += F("}1" D_MQTT "}2" D_DISABLED);
}
func += F("}1}2&nbsp;"); // Empty line
func += F("}1" D_EMULATION "}2");
#ifdef USE_EMULATION
if (EMUL_WEMO == Settings.flag2.emulation) {
func += F(D_BELKIN_WEMO);
}
else if (EMUL_HUE == Settings.flag2.emulation) {
func += F(D_HUE_BRIDGE);
}
else {
func += F(D_NONE);
}
#else
func += F(D_DISABLED);
#endif // USE_EMULATION
func += F("}1" D_MDNS_DISCOVERY "}2");
#ifdef USE_DISCOVERY
func += F(D_ENABLED);
func += F("}1" D_MDNS_ADVERTISE "}2");
#ifdef WEBSERVER_ADVERTISE
func += F(D_WEB_SERVER);
#else
func += F(D_DISABLED);
#endif // WEBSERVER_ADVERTISE
#else
func += F(D_DISABLED);
#endif // USE_DISCOVERY
func += F("}1}2&nbsp;"); // Empty line
func += F("}1" D_ESP_CHIP_ID "}2"); func += String(ESP.getChipId());
func += F("}1" D_FLASH_CHIP_ID "}2"); func += String(ESP.getFlashChipId());
func += F("}1" D_FLASH_CHIP_SIZE "}2"); func += String(ESP.getFlashChipRealSize() / 1024); func += F("kB");
func += F("}1" D_PROGRAM_FLASH_SIZE "}2"); func += String(ESP.getFlashChipSize() / 1024); func += F("kB");
func += F("}1" D_PROGRAM_SIZE "}2"); func += String(ESP.getSketchSize() / 1024); func += F("kB");
func += F("}1" D_FREE_PROGRAM_SPACE "}2"); func += String(ESP.getFreeSketchSpace() / 1024); func += F("kB");
func += F("}1" D_FREE_MEMORY "}2"); func += String(freeMem / 1024); func += F("kB");
func += F("</td></tr></table>");
func += FPSTR(HTTP_SCRIPT_INFO_END);
page.replace(F("</script>"), func);
page.replace(F("<body>"), F("<body onload='i()'>"));
// page += F("</fieldset>");
page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page);
}
void HandleRestart()
{
if (HttpUser()) { return; }

View File

@ -17,8 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define USE_ENERGY_SENSOR
#ifdef USE_ENERGY_SENSOR
/*********************************************************************************************\
* HLW8012 and PZEM004T - Energy
@ -93,18 +91,18 @@ void EnergyUpdateToday()
}
/*********************************************************************************************\
* HLW8012, BL0937 or HJL-01 - Energy (Sonoff Pow)
* HLW8012, BL0937 or HJL-01 - Energy (Sonoff Pow, HuaFan, KMC70011, BlitzWolf)
*
* Based on Source: Shenzhen Heli Technology Co., Ltd
\*********************************************************************************************/
// HLW8012 based (Sonoff Pow, KMC70011)
// HLW8012 based (Sonoff Pow, KMC70011, HuaFan)
#define HLW_PREF 10000 // 1000.0W
#define HLW_UREF 2200 // 220.0V
#define HLW_IREF 4545 // 4.545A
#define HLW_SEL_VOLTAGE 1
// HJL-01 based (Homecube, BlitzWolf)
// HJL-01 based (BlitzWolf, Homecube, Gosund)
#define HJL_PREF 1362
#define HJL_UREF 822
#define HJL_IREF 3300

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

@ -253,7 +253,7 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule)
}
} else match = true;
if (Settings.flag.rules_once) {
if (bitRead(Settings.rule_once, rule_set)) {
if (match) { // Only allow match state changes
if (!bitRead(rules_triggers[rule_set], rules_trigger_count[rule_set])) {
bitSet(rules_triggers[rule_set], rules_trigger_count[rule_set]);
@ -557,44 +557,38 @@ boolean RulesCommand()
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]);
}
else if ((CMND_ADD == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( XdrvMailbox.data_len > 0 ) {
if (XdrvMailbox.data_len > 0) {
double tempvar = CharToDouble(vars[index -1]) + CharToDouble(XdrvMailbox.data);
dtostrfd(tempvar,2,vars[index -1]);
dtostrfd(tempvar, 2, vars[index -1]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_SUB == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( XdrvMailbox.data_len > 0 ){
if (XdrvMailbox.data_len > 0) {
double tempvar = CharToDouble(vars[index -1]) - CharToDouble(XdrvMailbox.data);
dtostrfd(tempvar,2,vars[index -1]);
dtostrfd(tempvar, 2, vars[index -1]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_MULT == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( XdrvMailbox.data_len > 0 ){
if (XdrvMailbox.data_len > 0) {
double tempvar = CharToDouble(vars[index -1]) * CharToDouble(XdrvMailbox.data);
dtostrfd(tempvar,2,vars[index -1]);
dtostrfd(tempvar, 2, vars[index -1]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
}
else if ((CMND_SCALE == command_code) && (index > 0) && (index <= RULES_MAX_VARS)) {
if ( XdrvMailbox.data_len > 0 ) {
if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, ",")) { // Process parameter entry
double value = 0;
double valueIN = 0;
double fromLow = 0;
double fromHigh = 0;
double toLow = 0;
double toHigh = 0;
char sub_string[XdrvMailbox.data_len +1];
valueIN = CharToDouble(subStr(XdrvMailbox.data, ",", 1));
fromLow = CharToDouble(subStr(XdrvMailbox.data, ",", 2));
fromHigh = CharToDouble(subStr(XdrvMailbox.data, ",", 3));
toLow = CharToDouble(subStr(XdrvMailbox.data, ",", 4));
toHigh = CharToDouble(subStr(XdrvMailbox.data, ",", 5));
value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh);
dtostrfd(value,2,vars[index -1]);
double valueIN = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 1));
double fromLow = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 2));
double fromHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 3));
double toLow = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 4));
double toHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 5));
double value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh);
dtostrfd(value, 2, vars[index -1]);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]);
@ -610,24 +604,23 @@ double map_double(double x, double in_min, double in_max, double out_min, double
}
// Function to return a substring defined by a delimiter at an index
char* subStr (char* str, const char *delim, int index) {
char *act, *sub, *ptr;
static char copy[10];
char* subStr(char* dest, char* str, const char *delim, int index)
{
char *act;
char *sub;
char *ptr;
int i;
// Since strtok consumes the first arg, make a copy
strcpy(copy, str);
for (i = 1, act = copy; i <= index; i++, act = NULL) {
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
strncpy(dest, str, strlen(str));
for (i = 1, act = dest; i <= index; i++, act = NULL) {
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
}
sub = LTrim(sub);
sub = RTrim(sub);
sub = Trim(sub);
return sub;
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/

View File

@ -126,7 +126,6 @@ int mod(int a, int b)
return ret;
}
#define cmin(a,b) ((a)<(b)?(a):(b))
void Ws2812UpdatePixelColor(int position, struct WsColor hand_color, float offset)
{
@ -140,9 +139,9 @@ void Ws2812UpdatePixelColor(int position, struct WsColor hand_color, float offse
color = strip->GetPixelColor(mod_position);
float dimmer = 100 / (float)Settings.light_dimmer;
color.R = cmin(color.R + ((hand_color.red / dimmer) * offset), 255);
color.G = cmin(color.G + ((hand_color.green / dimmer) * offset), 255);
color.B = cmin(color.B + ((hand_color.blue / dimmer) * offset), 255);
color.R = tmin(color.R + ((hand_color.red / dimmer) * offset), 255);
color.G = tmin(color.G + ((hand_color.green / dimmer) * offset), 255);
color.B = tmin(color.B + ((hand_color.blue / dimmer) * offset), 255);
strip->SetPixelColor(mod_position, color);
}

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

@ -25,8 +25,6 @@
* References:
* - https://www.dfrobot.com/wiki/index.php/Weather-proof_Ultrasonic_Sensor_SKU_:_SEN0207
\*********************************************************************************************/
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
uint8_t sr04_echo_pin = 0;
uint8_t sr04_trig_pin = 0;
@ -42,7 +40,7 @@ uint8_t sr04_trig_pin = 0;
#define PING_OVERHEAD 5
// Conversion from uS to distance (round result to nearest cm or inch).
#define EchoConvert(echoTime, conversionFactor) (max(((unsigned int)echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))
#define EchoConvert(echoTime, conversionFactor) (tmax(((unsigned int)echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))
/********************************************************************************************/
@ -74,7 +72,7 @@ uint16_t Sr04Ping(uint16_t max_cm_distance)
uint16_t duration = 0;
uint16_t maxEchoTime;
maxEchoTime = min(max_cm_distance + 1, (uint16_t) MAX_SENSOR_DISTANCE + 1) * US_ROUNDTRIP_CM;
maxEchoTime = tmin(max_cm_distance + 1, (uint16_t) MAX_SENSOR_DISTANCE + 1) * US_ROUNDTRIP_CM;
/* The following trigPin/echoPin cycle is used to determine the
distance of the nearest object by bouncing soundwaves off of it. */

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);
}
@ -155,7 +155,7 @@ void TmInit()
digitalWrite(tm1638_clock_pin, HIGH);
Tm16XXSendCommand(0x40);
Tm16XXSendCommand(0x80 | (tm1638_active_display ? 8 : 0) | min(7, tm1638_intensity));
Tm16XXSendCommand(0x80 | (tm1638_active_display ? 8 : 0) | tmin(7, tm1638_intensity));
digitalWrite(tm1638_strobe_pin, LOW);
Tm16XXSend(0xC0);
@ -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

467
sonoff/xsns_29_mcp230xx.ino Normal file
View File

@ -0,0 +1,467 @@
/*
xsns_29_mcp230xx.ino - Support for I2C MCP23008/MCP23017 GPIO Expander (INPUT ONLY!)
Copyright (C) 2018 Andre Thomas and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_I2C
#ifdef USE_MCP230xx
/*********************************************************************************************\
MCP23008/17 - I2C GPIO EXPANDER
Docs at https://www.microchip.com/wwwproducts/en/MCP23008
https://www.microchip.com/wwwproducts/en/MCP23017
I2C Address: 0x20 - 0x27
\*********************************************************************************************/
#define XSNS_29 29
#define MCP230xx_ADDRESS1 0x20
#define MCP230xx_ADDRESS2 0x21
#define MCP230xx_ADDRESS3 0x22
#define MCP230xx_ADDRESS4 0x23
#define MCP230xx_ADDRESS5 0x24
#define MCP230xx_ADDRESS6 0x25
#define MCP230xx_ADDRESS7 0x26
#define MCP230xx_ADDRESS8 0x27
/*
Default register locations for MCP23008 - They change for MCP23017 in default bank mode
*/
uint8_t MCP230xx_IODIR = 0x00;
uint8_t MCP230xx_GPINTEN = 0x02;
uint8_t MCP230xx_IOCON = 0x05;
uint8_t MCP230xx_GPPU = 0x06;
uint8_t MCP230xx_INTF = 0x07;
uint8_t MCP230xx_INTCAP = 0x08;
uint8_t MCP230xx_GPIO = 0x09;
uint8_t mcp230xx_type = 0;
uint8_t mcp230xx_address;
uint8_t mcp230xx_addresses[] = { MCP230xx_ADDRESS1, MCP230xx_ADDRESS2, MCP230xx_ADDRESS3, MCP230xx_ADDRESS4, MCP230xx_ADDRESS5, MCP230xx_ADDRESS6, MCP230xx_ADDRESS7, MCP230xx_ADDRESS8 };
uint8_t mcp280xx_pincount = 0;
const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29\":{\"D\":%i,\"MODE\":%i,\"PULL-UP\":%i}}";
#ifdef USE_WEBSERVER
#ifdef USE_MCP230xx_displaymain
const char HTTP_SNS_MCP230xx_GPIO[] PROGMEM = "%s{s}MCP230XX D%d{m}%d{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_MCP230xx_displaymain
#ifdef USE_MCP230xx_webconfig
const char MCP230XX_OPTION_SELECTED[] PROGMEM = " selected";
const char MCP230XX_OPTION_BLANK[] PROGMEM = "";
const char MCP230XX_OPTION_CHECKED[] PROGMEM = " checked";
const char HTTP_FORM_I2C_MCP230XX_T[] PROGMEM = "<table>";
const char HTTP_FORM_I2C_MCP230XX_TE[] PROGMEM = "</table>";
const char HTTP_FORM_MCP230XX[] PROGMEM =
"<fieldset><legend><b>&nbsp;MCP230xx settings &nbsp;</b></legend><form method='post' action='sv'><input id='w' name='w' value='8' hidden>";
const char HTTP_FORM_I2C_MCP230XX[] PROGMEM =
"<tr><td nowrap>{b0 </b> <br/></td><td nowrap><select id='{b1' name='{b1'>"
"<option value='0'{s0>Disabled</option>"
"<option value='1'{s1>Input</option>"
"<option value='2'{s2>Input (Int on Change)</option>"
"<option value='3'{s3>Input (Int when Low)</option>"
"<option value='4'{s4>Input (Int when High)</option>"
"</select></td>"
"<td nowrap>Enable Pullup</td>"
"<td nowrap><input type=checkbox name=epu{b1 value=1{b2></input></td>"
"</tr>";
void HandleMCP230xxConfiguration()
{
if (HttpUser()) {
return;
}
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_MCP230XX));
String page = FPSTR(HTTP_HEAD);
page.replace("{v}", FPSTR(D_CONFIGURE_MCP230XX));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_MCP230XX);
page += FPSTR(HTTP_FORM_I2C_MCP230XX_T);
for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) {
page += FPSTR(HTTP_FORM_I2C_MCP230XX);
page.replace("{b0", "MCP230XX D" + String(idx));
page.replace("{b1", "D" + String(idx));
// determine correct dropdown state
uint8_t bitsetting = 0; // Default to disabled
if (Settings.mcp230xx_config[idx].enable) {
bitsetting = 1; // Default to normal enable (floating without interrupt)
if (Settings.mcp230xx_config[idx].inten) { // Int choice
bitsetting = 2; // Default to INT on Change (LOW to HIGH, and HIGH to LOW)
if (Settings.mcp230xx_config[idx].intmode) { // On comparison
bitsetting = 3; // On comparison default to LOW
if (Settings.mcp230xx_config[idx].intcomp) {
bitsetting = 4; // On comparison default to HIGH
}
}
}
}
switch (bitsetting) {
case 0 : page.replace("{s0", FPSTR(MCP230XX_OPTION_SELECTED)); break;
case 1 : page.replace("{s1", FPSTR(MCP230XX_OPTION_SELECTED)); break;
case 2 : page.replace("{s2", FPSTR(MCP230XX_OPTION_SELECTED)); break;
case 3 : page.replace("{s3", FPSTR(MCP230XX_OPTION_SELECTED)); break;
case 4 : page.replace("{s4", FPSTR(MCP230XX_OPTION_SELECTED)); break;
}
// replace remaining unselected options - if one was replaced above it will be ignored
page.replace("{s0", FPSTR(MCP230XX_OPTION_BLANK));
page.replace("{s1", FPSTR(MCP230XX_OPTION_BLANK));
page.replace("{s2", FPSTR(MCP230XX_OPTION_BLANK));
page.replace("{s3", FPSTR(MCP230XX_OPTION_BLANK));
page.replace("{s4", FPSTR(MCP230XX_OPTION_BLANK));
if (Settings.mcp230xx_config[idx].pullup) {
page.replace("{b2", FPSTR(MCP230XX_OPTION_CHECKED));
} else {
page.replace("{b2", FPSTR(MCP230XX_OPTION_BLANK));
}
}
page += FPSTR(HTTP_FORM_I2C_MCP230XX_TE);
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_BTN_CONF);
ShowPage(page);
}
void MCP230xx_SaveSettings()
{
char stemp[8];
for (uint8_t idx = 0; idx < mcp280xx_pincount; idx++) {
snprintf_P(stemp, sizeof(stemp), PSTR("D%d"), idx);
uint8_t _pinvalue = (!strlen(WebServer->arg(stemp).c_str() )) ? 0 : atoi(WebServer->arg(stemp).c_str() );
if (_pinvalue) {
Settings.mcp230xx_config[idx].enable = 1;
if (_pinvalue >= 2) {
Settings.mcp230xx_config[idx].inten = 1;
if (_pinvalue >= 3) {
Settings.mcp230xx_config[idx].intmode = 1;
if (_pinvalue >= 4) {
Settings.mcp230xx_config[idx].intcomp = 1;
} else {
Settings.mcp230xx_config[idx].intcomp = 0;
}
} else {
Settings.mcp230xx_config[idx].intmode = 0;
Settings.mcp230xx_config[idx].intcomp = 0;
}
} else {
Settings.mcp230xx_config[idx].inten = 0;
Settings.mcp230xx_config[idx].intmode = 0;
Settings.mcp230xx_config[idx].intcomp = 0;
}
} else {
Settings.mcp230xx_config[idx].enable = 0;
Settings.mcp230xx_config[idx].inten = 0;
Settings.mcp230xx_config[idx].intmode = 0;
Settings.mcp230xx_config[idx].intcomp = 0;
}
Settings.mcp230xx_config[idx].b5 = 0;
Settings.mcp230xx_config[idx].b6 = 0;
Settings.mcp230xx_config[idx].b7 = 0;
if (Settings.mcp230xx_config[idx].enable) {
snprintf_P(stemp, sizeof(stemp), PSTR("epuD%d"), idx);
Settings.mcp230xx_config[idx].pullup = (!strlen(WebServer->arg(stemp).c_str() )) ? 0 : atoi(WebServer->arg(stemp).c_str() );
} else {
Settings.mcp230xx_config[idx].pullup = 0;
}
}
MCP230xx_ApplySettings();
}
#endif // USE_MCP230xx_webconfig
#endif // USE_WEBSERVER
uint8_t MCP230xx_Type(void) {
return mcp230xx_type;
}
uint8_t MCP230xx_readGPIO(uint8_t port) {
return I2cRead8(mcp230xx_address, MCP230xx_GPIO + port);
}
void MCP230xx_ApplySettings(void) {
uint8_t reg_gppu = 0;
uint8_t reg_gpinten = 0;
for (uint8_t idx = 0; idx < 8; idx++) {
if (Settings.mcp230xx_config[idx].enable) {
if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another
reg_gpinten |= (1 << idx);
}
if (Settings.mcp230xx_config[idx].pullup) {
reg_gppu |= (1 << idx);
}
}
}
I2cWrite8(mcp230xx_address, MCP230xx_GPPU, reg_gppu);
I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN, reg_gpinten);
if (mcp230xx_type == 2) { // We have a MCP23017
reg_gppu = 0;
reg_gpinten = 0;
for (uint8_t idx = 8; idx < 16; idx++) {
if (Settings.mcp230xx_config[idx].enable) {
if (Settings.mcp230xx_config[idx].inten) { // Int is enabled in some form or another
reg_gpinten |= (1 << idx - 8);
}
if (Settings.mcp230xx_config[idx].pullup) {
reg_gppu |= (1 << idx - 8);
}
}
}
I2cWrite8(mcp230xx_address, MCP230xx_GPPU + 1, reg_gppu);
I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN + 1, reg_gpinten);
}
}
void MCP230xx_Detect()
{
uint8_t buffer;
if (mcp230xx_type) {
return;
}
for (byte i = 0; i < sizeof(mcp230xx_addresses); i++) {
mcp230xx_address = mcp230xx_addresses[i];
I2cWrite8(mcp230xx_address, MCP230xx_IOCON, 0x80); // attempt to set bank mode - this will only work on MCP23017, so its the best way to detect the different chips 23008 vs 23017
if (I2cValidRead8(&buffer, mcp230xx_address, MCP230xx_IOCON)) {
if (buffer == 0x00) {
mcp230xx_type = 1; // We have a MCP23008
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23008", mcp230xx_address);
AddLog(LOG_LEVEL_DEBUG);
mcp280xx_pincount = 8;
MCP230xx_ApplySettings();
} else {
if (buffer == 0x80) {
mcp230xx_type = 2; // We have a MCP23017
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "MCP23017", mcp230xx_address);
AddLog(LOG_LEVEL_DEBUG);
mcp280xx_pincount = 16;
// Reset bank mode to 0
I2cWrite8(mcp230xx_address, MCP230xx_IOCON, 0x00);
// Update register locations for MCP23017
MCP230xx_GPINTEN = 0x04;
MCP230xx_GPPU = 0x0C;
MCP230xx_INTF = 0x0E;
MCP230xx_INTCAP = 0x10;
MCP230xx_GPIO = 0x12;
MCP230xx_ApplySettings();
}
}
break;
}
}
}
bool MCP230xx_CheckForInterrupt(void) {
uint8_t intf;
uint8_t mcp230xx_intcap = 0;
uint8_t report_int;
if (I2cValidRead8(&intf, mcp230xx_address, MCP230xx_INTF)) {
if (intf > 0) {
if (I2cValidRead8(&mcp230xx_intcap, mcp230xx_address, MCP230xx_INTCAP)) {
for (uint8_t intp = 0; intp < 8; intp++) {
if ((intf >> intp) & 0x01) { // we know which pin caused interrupt
report_int = 0;
if (Settings.mcp230xx_config[intp].intmode) { // change on INT
if (((mcp230xx_intcap >> intp) & 0x01) == Settings.mcp230xx_config[intp].intcomp) report_int = 1;
} else {
report_int = 1;
}
if (report_int) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"Pin\":\"D%i\", \"State\":%i}"), mqtt_data, intp, ((mcp230xx_intcap >> intp) & 0x01));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data);
}
}
}
}
}
}
if (mcp230xx_type == 2) { // We have a MCP23017 so we need to check the other 8 bits also
if (I2cValidRead8(&intf, mcp230xx_address, MCP230xx_INTF+1)) {
if (intf > 0) {
if (I2cValidRead8(&mcp230xx_intcap, mcp230xx_address, MCP230xx_INTCAP+1)) {
for (uint8_t intp = 0; intp < 8; intp++) {
if ((intf >> intp) & 0x01) { // we know which pin caused interrupt
report_int = 0;
if (Settings.mcp230xx_config[intp+8].intmode) { // change on INT
if (((mcp230xx_intcap >> intp) & 0x01) == Settings.mcp230xx_config[intp+8].intcomp) report_int = 1;
} else {
report_int = 1;
}
if (report_int) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"Pin\":\"D%i\", \"State\":%i}"), mqtt_data, intp+8, ((mcp230xx_intcap >> intp) & 0x01));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data);
}
}
}
}
}
}
}
}
void MCP230xx_Show(boolean json)
{
if (mcp230xx_type) {
if (json) {
if (mcp230xx_type == 1) {
uint8_t gpio = MCP230xx_readGPIO(0);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP23008\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i}"),
mqtt_data,(gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1);
}
if (mcp230xx_type == 2) {
uint8_t gpio1 = MCP230xx_readGPIO(0);
uint8_t gpio2 = MCP230xx_readGPIO(1);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP23017\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i,\"D8\":%i,\"D9\":%i,\"D10\":%i,\"D11\":%i,\"D12\":%i,\"D13\":%i,\"D14\":%i,\"D15\":%i}"),
mqtt_data, (gpio1>>0)&1,(gpio1>>1)&1,(gpio1>>2)&1,(gpio1>>3)&1,(gpio1>>4)&1,(gpio1>>5)&1,(gpio1>>6)&1,(gpio1>>7)&1,(gpio2>>0)&1,(gpio2>>1)&1,(gpio2>>2)&1,(gpio2>>3)&1,(gpio2>>4)&1,(gpio2>>5)&1,(gpio2>>6)&1,(gpio2>>7)&1);
}
#ifdef USE_WEBSERVER
#ifdef USE_MCP230xx_displaymain
} else {
uint8_t gpio1 = MCP230xx_readGPIO(0);
uint8_t gpio2 = 0;
if (mcp230xx_type == 2) {
gpio2=MCP230xx_readGPIO(1);
}
uint16_t gpio = (gpio2 << 8) + gpio1;
for (uint8_t pin = 0; pin < mcp280xx_pincount; pin++) {
if (Settings.mcp230xx_config[pin].enable) {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_MCP230xx_GPIO, mqtt_data, pin, (gpio>>pin)&1);
}
}
#endif // USE_MCP230xx_displaymain
#endif // USE_WEBSERVER
}
}
}
bool MCP230xx_Command(void) {
boolean serviced = true;
uint8_t _a, _b = 0;
uint8_t pin, pinmode, pullup = 0;
String data = XdrvMailbox.data;
_a = data.indexOf(",");
_b = data.indexOf(",", _a + 1);
if (_a < XdrvMailbox.data_len) {
if (_b < XdrvMailbox.data_len) {
pin = data.substring(0, _a).toInt();
pinmode = data.substring(_a+1, _b).toInt();
pullup = data.substring(_b+1, XdrvMailbox.data_len).toInt();
if (pinmode) {
Settings.mcp230xx_config[pin].enable = 1;
if (pinmode >= 2) {
Settings.mcp230xx_config[pin].inten = 1;
if (pinmode >= 3) {
Settings.mcp230xx_config[pin].intmode = 1;
if (pinmode >= 4) {
Settings.mcp230xx_config[pin].intcomp = 1;
} else {
Settings.mcp230xx_config[pin].intcomp = 0;
}
} else {
Settings.mcp230xx_config[pin].intmode = 0;
Settings.mcp230xx_config[pin].intcomp = 0;
}
} else {
Settings.mcp230xx_config[pin].inten = 0;
Settings.mcp230xx_config[pin].intmode = 0;
Settings.mcp230xx_config[pin].intcomp = 0;
}
} else {
Settings.mcp230xx_config[pin].enable = 0;
Settings.mcp230xx_config[pin].inten = 0;
Settings.mcp230xx_config[pin].intmode = 0;
Settings.mcp230xx_config[pin].intcomp = 0;
}
Settings.mcp230xx_config[pin].b5 = 0;
Settings.mcp230xx_config[pin].b6 = 0;
Settings.mcp230xx_config[pin].b7 = 0;
if (Settings.mcp230xx_config[pin].enable) {
Settings.mcp230xx_config[pin].pullup = pullup;
} else {
Settings.mcp230xx_config[pin].pullup = 0;
}
MCP230xx_ApplySettings();
snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_SENSOR_RESPONSE,pin,pinmode,pullup);
} else {
serviced = false;
}
} else {
serviced = false;
}
return serviced;
}
/*********************************************************************************************\
Interface
\*********************************************************************************************/
boolean Xsns29(byte function)
{
boolean result = false;
if (i2c_flg) {
switch (function) {
case FUNC_PREP_BEFORE_TELEPERIOD:
MCP230xx_Detect();
break;
case FUNC_EVERY_50_MSECOND:
MCP230xx_CheckForInterrupt();
break;
case FUNC_JSON_APPEND:
MCP230xx_Show(1);
break;
case FUNC_COMMAND:
if (XSNS_29 == XdrvMailbox.index) {
result = MCP230xx_Command();
}
break;
#ifdef USE_WEBSERVER
#ifdef USE_MCP230xx_displaymain
case FUNC_WEB_APPEND:
MCP230xx_Show(0);
break;
#endif // USE_MCP230xx_displaymain
#endif // USE_WEBSERVER
}
}
return result;
}
#endif // USE_MCP230xx
#endif // USE_I2C

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;
}

View File

@ -79,7 +79,8 @@ a_setoption = [
"KNX enhancement",
"RF receive decimal",
"IR receive decimal",
"Enforce HASS light group",""]
"Enforce HASS light group",
"Do not show Wifi and Mqtt state using Led"]
a_features = [[
"","","USE_I2C","USE_SPI",
@ -89,7 +90,7 @@ a_features = [[
"USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE",
"USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE",
"USE_TIMERS","USE_SUNRISE","USE_TIMERS_WEB","USE_RULES",
"USE_KNX","","",""
"USE_KNX","USE_WPS","USE_SMARTCONFIG",""
],[
"USE_CONFIG_OVERRIDE","BE_MINIMAL","USE_ALL_SENSORS","USE_CLASSIC",
"USE_KNX_NO_EMULATION","","","",