Merge branch 'development' of https://github.com/arendst/Sonoff-Tasmota into tuya-wifi-state

This commit is contained in:
Joel Stein 2018-10-29 23:35:13 +01:00
commit d8914906a8
30 changed files with 373 additions and 275 deletions

View File

@ -1,11 +1,17 @@
/* 6.2.1.19 20181023
/* 6.2.1.20 20181028
* Add command SetOption35 0..255 (seconds) to delay mDNS initialization to control possible Wifi connect problems
* Add command SetOption53 0/1 to toggle gui display of Hostname and IP address (#1006, #2091)
* Add token %hostname% to command FullTopic (#3018)
* Add support for two BMP/BME sensors (#4195)
*
* 6.2.1.19 20181023
* Fix header file execution order by renaming user_config.h to my_user_config.h
* Fix invalid JSON floating point result from nan (Not a Number) and inf (Infinity) into null (#4147)
* Fix rule mqtt#connected trigger when mqtt is disabled (#4149)
* Initial release of RF transceiving using library RcSwitch (#2702)
* Change default OTA Url to http://thehackbox.org/tasmota/release/sonoff.bin (#4170)
* Add Tuya Software Serial to support additional Tuya configurations (#4178)
* Add sonoff-basic.bin without most sensors
* Add define USE_BASIC for selecting image sonoff-basic without most sensors
*
* 6.2.1.18 20181019
* Add more API callbacks and document API.md

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "h"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kΩ"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -1,3 +1,4 @@
/*
el-GR.h - localization for Greek - Greece for Sonoff-Tasmota
@ -537,7 +538,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kΩ"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "ó"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Godz"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "H"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Ч"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "кОм"
#define D_UNIT_KILOWATTHOUR "кВт"
#define D_UNIT_LUX "лк"

View File

@ -536,7 +536,7 @@
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "Г"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "кОм"
#define D_UNIT_KILOWATTHOUR "кВт"
#define D_UNIT_LUX "лк"

View File

@ -536,7 +536,7 @@
#define D_UNIT_HOUR "时"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "千欧"
#define D_UNIT_KILOWATTHOUR "千瓦时"
#define D_UNIT_LUX "勒克斯"

View File

@ -537,7 +537,7 @@
#define D_UNIT_HOUR "時"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOMETER_PER_HOUR "kmph" // or "km/h"
#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h"
#define D_UNIT_KILOOHM "千歐"
#define D_UNIT_KILOWATTHOUR "千瓦時"
#define D_UNIT_LUX "勒克斯"

View File

@ -281,7 +281,7 @@
#ifdef USE_I2C
#define USE_SHT // Enable SHT1X sensor (+1k4 code)
#define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code)
#define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address 0x76 or 0x77) (+4k code)
#define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensors (I2C addresses 0x76 and 0x77) (+4k4 code)
// #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code)
#define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code)
// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+1k5 code)

View File

@ -66,7 +66,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t timers_enable : 1; // bit 0 (v6.1.1b)
uint32_t user_esp8285_enable : 1; // bit 1 (v6.1.1.14)
uint32_t time_append_timezone : 1; // bit 2 (v6.2.1.2)
uint32_t spare03 : 1;
uint32_t gui_hostname_ip : 1; // bit 3 (v6.2.1.20)
uint32_t spare04 : 1;
uint32_t spare05 : 1;
uint32_t spare06 : 1;

View File

@ -60,6 +60,7 @@ typedef unsigned long power_t; // Power (Relay) type
#define MQTT_TOKEN_PREFIX "%prefix%" // To be substituted by mqtt_prefix[x]
#define MQTT_TOKEN_TOPIC "%topic%" // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
#define MQTT_TOKEN_HOSTNAME "%hostname%" // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
#define MQTT_TOKEN_ID "%id%" // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic
#define WIFI_HOSTNAME "%s-%04d" // Expands to <MQTT_TOPIC>-<last 4 decimal chars of MAC address>
@ -202,7 +203,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED };
enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER };
enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MAX_PARAM8};
enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_MAX_PARAM8}; // Max is PARAM8_SIZE (18)
enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_MAX_SENSORS};

View File

@ -186,6 +186,7 @@ byte reset_web_log_flag = 0; // Reset web console log
byte devices_present = 0; // Max number of devices supported
byte seriallog_level; // Current copy of Settings.seriallog_level
byte syslog_level; // Current copy of Settings.syslog_level
byte mdns_delayed_start = 0; // mDNS delayed start
boolean latest_uptime_flag = true; // Signal latest uptime
boolean pwm_present = false; // Any PWM channel configured with SetOption15 0
boolean mdns_begun = false; // mDNS active
@ -278,6 +279,7 @@ void GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic)
}
fulltopic.replace(F(MQTT_TOKEN_PREFIX), Settings.mqtt_prefix[prefix]);
fulltopic.replace(F(MQTT_TOKEN_TOPIC), topic);
fulltopic.replace(F(MQTT_TOKEN_HOSTNAME), my_hostname);
String token_id = WiFi.macAddress();
token_id.replace(":", "");
fulltopic.replace(F(MQTT_TOKEN_ID), token_id);
@ -2580,6 +2582,7 @@ void setup()
}
baudrate = Settings.baudrate * 1200;
mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
seriallog_level = Settings.seriallog_level;
seriallog_timer = SERIALLOG_TIMER;
#ifndef USE_EMULATION

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
#define VERSION 0x06020112
#define VERSION 0x06020114
#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"

View File

@ -715,7 +715,6 @@ boolean GetUsedInModule(byte val, uint8_t *arr)
if (GPIO_RFRECV == val) { return true; }
#endif
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
offset = (GPIO_REL1_INV - GPIO_REL1);
}
@ -1558,19 +1557,29 @@ void WifiCheck(uint8_t param)
ota_state_flag = 3;
}
#endif // BE_MINIMAL
#ifdef USE_DISCOVERY
if (!mdns_begun) {
mdns_begun = MDNS.begin(my_hostname);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS "%s"), (mdns_begun) ? D_INITIALIZED : D_FAILED);
AddLog(LOG_LEVEL_INFO);
if (mdns_delayed_start) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
mdns_delayed_start--;
} else {
mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
mdns_begun = MDNS.begin(my_hostname);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS "%s"), (mdns_begun) ? D_INITIALIZED : D_FAILED);
AddLog(LOG_LEVEL_INFO);
}
}
#endif // USE_DISCOVERY
#ifdef USE_WEBSERVER
if (Settings.webserver) {
StartWebserver(Settings.webserver, WiFi.localIP());
#ifdef USE_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
MDNS.addService("http", "tcp", WEB_PORT);
if (mdns_begun) {
MDNS.addService("http", "tcp", WEB_PORT);
}
#endif // WEBSERVER_ADVERTISE
#endif // USE_DISCOVERY
} else {
@ -1580,12 +1589,14 @@ void WifiCheck(uint8_t param)
if (Settings.flag2.emulation) { UdpConnect(); }
#endif // USE_EMULATION
#endif // USE_WEBSERVER
#ifdef USE_KNX
if (!knx_started && Settings.flag.knx_enabled) {
KNXStart();
knx_started = true;
}
#endif // USE_KNX
} else {
WifiState(0);
#if defined(USE_WEBSERVER) && defined(USE_EMULATION)
@ -1646,38 +1657,6 @@ void EspRestart()
ESP.restart();
}
#ifdef USE_DISCOVERY
/*********************************************************************************************\
* mDNS
\*********************************************************************************************/
#ifdef MQTT_HOST_DISCOVERY
boolean MdnsDiscoverMqttServer()
{
if (!mdns_begun) {
return false;
}
int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
AddLog(LOG_LEVEL_INFO);
if (n > 0) {
// Note: current strategy is to get the first MQTT service (even when many are found)
snprintf_P(Settings.mqtt_host, sizeof(Settings.mqtt_host), MDNS.IP(0).toString().c_str());
Settings.mqtt_port = MDNS.port(0);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"),
MDNS.hostname(0).c_str(), Settings.mqtt_host, Settings.mqtt_port);
AddLog(LOG_LEVEL_INFO);
}
return n > 0;
}
#endif // MQTT_HOST_DISCOVERY
#endif // USE_DISCOVERY
/*********************************************************************************************\
* Basic I2C routines
\*********************************************************************************************/

View File

@ -119,7 +119,7 @@ const char HTTP_HEAD_STYLE[] PROGMEM =
#else
"<h3>{ha " D_MODULE "</h3>"
#endif
"<h2>{h}</h2></div>";
"<h2>{h}</h2>{j}</div>";
const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"var sn=0;" // Scroll position
"var id=0;" // Get most of weblog initially
@ -453,6 +453,25 @@ void ShowPage(String &page, bool auth)
page.replace(F("{a}"), String(Settings.web_refresh));
page.replace(F("{ha"), my_module.name);
page.replace(F("{h}"), Settings.friendlyname[0]);
String info = "";
if (Settings.flag3.gui_hostname_ip) {
uint8_t more_ips = 0;
info += F("<h3>"); info += my_hostname;
if (mdns_begun) { info += F(".local"); }
info += F(" (");
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
info += WiFi.localIP().toString();
more_ips++;
}
if (static_cast<uint32_t>(WiFi.softAPIP()) != 0) {
if (more_ips) { info += F(", "); }
info += WiFi.softAPIP().toString();
}
info += F(")</h3>");
}
page.replace(F("{j}"), info);
if (HTTP_MANAGER == webserver_state) {
if (WifiConfigCounter()) {
page.replace(F("<body>"), F("<body onload='u()'>"));
@ -1241,6 +1260,7 @@ void HandleInformation()
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 (mdns_begun) { func += F(".local"); }
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();

View File

@ -197,6 +197,32 @@ void MqttLoop()
/*********************************************************************************************/
#ifdef USE_DISCOVERY
#ifdef MQTT_HOST_DISCOVERY
boolean MqttDiscoverServer()
{
if (!mdns_begun) { return false; }
int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
AddLog(LOG_LEVEL_INFO);
if (n > 0) {
// Note: current strategy is to get the first MQTT service (even when many are found)
snprintf_P(Settings.mqtt_host, sizeof(Settings.mqtt_host), MDNS.IP(0).toString().c_str());
Settings.mqtt_port = MDNS.port(0);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"),
MDNS.hostname(0).c_str(), Settings.mqtt_host, Settings.mqtt_port);
AddLog(LOG_LEVEL_INFO);
}
return n > 0;
}
#endif // MQTT_HOST_DISCOVERY
#endif // USE_DISCOVERY
int MqttLibraryType()
{
return (int)MQTT_LIBRARY_TYPE;
@ -468,9 +494,7 @@ void MqttReconnect()
#ifndef USE_MQTT_TLS
#ifdef USE_DISCOVERY
#ifdef MQTT_HOST_DISCOVERY
if (!strlen(Settings.mqtt_host)) {
MdnsDiscoverMqttServer();
}
if (!strlen(Settings.mqtt_host) && !MqttDiscoverServer()) { return; }
#endif // MQTT_HOST_DISCOVERY
#endif // USE_DISCOVERY
#endif // USE_MQTT_TLS
@ -539,6 +563,13 @@ void MqttCheck()
if (!MqttIsConnected()) {
global_state.mqtt_down = 1;
if (!mqtt_retry_counter) {
#ifndef USE_MQTT_TLS
#ifdef USE_DISCOVERY
#ifdef MQTT_HOST_DISCOVERY
if (!strlen(Settings.mqtt_host) && !mdns_begun) { return; }
#endif // MQTT_HOST_DISCOVERY
#endif // USE_DISCOVERY
#endif // USE_MQTT_TLS
MqttReconnect();
} else {
mqtt_retry_counter--;

View File

@ -809,6 +809,11 @@ void HandleHueApi(String *path)
* user part and allow every caller as with Web or WeMo.
*
* (c) Heiko Krupp, 2017
*
* Hue URL
* http://sonoff/api/username/lights/1/state with post data {"on":true,"hue":56100,"sat":254,"bri":254,"alert":"none","transitiontime":40}
* is converted by webserver to
* http://sonoff/api/username/lights/1/state with arg plain={"on":true,"hue":56100,"sat":254,"bri":254,"alert":"none","transitiontime":40}
*/
uint8_t args = 0;

View File

@ -27,8 +27,8 @@
* I2C Address: 0x76 or 0x77
\*********************************************************************************************/
#define BMP_ADDR1 0x77
#define BMP_ADDR2 0x76
#define BMP_ADDR1 0x76
#define BMP_ADDR2 0x77
#define BMP180_CHIPID 0x55
#define BMP280_CHIPID 0x58
@ -37,18 +37,27 @@
#define BMP_REGISTER_CHIPID 0xD0
#define BMP_MAX_SENSORS 2
const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280|BME680";
uint8_t bmp_address;
uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 };
uint8_t bmp_type = 0;
uint8_t bmp_model = 0;
char bmp_name[7];
uint8_t bmp_count = 0;
uint8_t bmp_valid = 0;
float bmp_temperature = 0.0;
float bmp_pressure = 0.0;
float bmp_humidity = 0.0;
struct BMPSTRUCT {
uint8_t bmp_address; // I2C bus address
char bmp_name[7]; // Sensor name - "BMPXXX"
uint8_t bmp_type = 0;
uint8_t bmp_model = 0;
uint8_t bmp_valid = 0;
#ifdef USE_BME680
uint8_t bme680_state = 0;
float bmp_gas_resistance = 0.0;
#endif // USE_BME680
float bmp_temperature = 0.0;
float bmp_pressure = 0.0;
float bmp_humidity = 0.0;
} bmp_sensors[BMP_MAX_SENSORS];
/*********************************************************************************************\
* BMP085 and BME180
@ -84,18 +93,18 @@ uint16_t cal_ac4;
uint16_t cal_ac5;
uint16_t cal_ac6;
boolean Bmp180Calibration()
boolean Bmp1802xCalibration(uint8_t bmp_idx)
{
cal_ac1 = I2cRead16(bmp_address, BMP180_AC1);
cal_ac2 = I2cRead16(bmp_address, BMP180_AC2);
cal_ac3 = I2cRead16(bmp_address, BMP180_AC3);
cal_ac4 = I2cRead16(bmp_address, BMP180_AC4);
cal_ac5 = I2cRead16(bmp_address, BMP180_AC5);
cal_ac6 = I2cRead16(bmp_address, BMP180_AC6);
cal_b1 = I2cRead16(bmp_address, BMP180_VB1);
cal_b2 = I2cRead16(bmp_address, BMP180_VB2);
cal_mc = I2cRead16(bmp_address, BMP180_MC);
cal_md = I2cRead16(bmp_address, BMP180_MD);
cal_ac1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC1);
cal_ac2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC2);
cal_ac3 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC3);
cal_ac4 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC4);
cal_ac5 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC5);
cal_ac6 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC6);
cal_b1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB1);
cal_b2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB2);
cal_mc = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MC);
cal_md = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MD);
// Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF
if (!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 | !cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md) {
@ -117,19 +126,20 @@ boolean Bmp180Calibration()
return true;
}
void Bmp180Read()
void Bmp1802xRead(uint8_t bmp_idx)
{
I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE);
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE);
delay(5); // 5ms conversion time
int ut = I2cRead16(bmp_address, BMP180_REG_RESULT);
int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT);
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;
bmp_sensors[bmp_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0;
I2cWrite8(bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
uint32_t up = I2cRead24(bmp_address, BMP180_REG_RESULT);
uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT);
up >>= (8 - BMP180_OSS);
int32_t b6 = bmp180_b5 - 4000;
@ -155,7 +165,7 @@ void Bmp180Read()
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
p += ((x1 + x2 + (int32_t)3791) >> 4);
bmp_pressure = (float)p / 100.0; // convert to mbar
bmp_sensors[bmp_idx].bmp_pressure = (float)p / 100.0; // convert to mbar
}
/*********************************************************************************************\
@ -212,45 +222,45 @@ struct BME280CALIBDATA
int8_t dig_H6;
} Bme280CalibrationData;
boolean Bmx280Calibrate()
boolean Bmx2802xCalibrate(uint8_t bmp_idx)
{
// if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false;
Bme280CalibrationData.dig_T1 = I2cRead16LE(bmp_address, BME280_REGISTER_DIG_T1);
Bme280CalibrationData.dig_T2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_T2);
Bme280CalibrationData.dig_T3 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_T3);
Bme280CalibrationData.dig_P1 = I2cRead16LE(bmp_address, BME280_REGISTER_DIG_P1);
Bme280CalibrationData.dig_P2 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P2);
Bme280CalibrationData.dig_P3 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P3);
Bme280CalibrationData.dig_P4 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P4);
Bme280CalibrationData.dig_P5 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P5);
Bme280CalibrationData.dig_P6 = I2cReadS16_LE(bmp_address, BME280_REGISTER_DIG_P6);
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) { // #1051
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);
Bme280CalibrationData.dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1);
Bme280CalibrationData.dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2);
Bme280CalibrationData.dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3);
Bme280CalibrationData.dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1);
Bme280CalibrationData.dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2);
Bme280CalibrationData.dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3);
Bme280CalibrationData.dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4);
Bme280CalibrationData.dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5);
Bme280CalibrationData.dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6);
Bme280CalibrationData.dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7);
Bme280CalibrationData.dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8);
Bme280CalibrationData.dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9);
if (BME280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { // #1051
Bme280CalibrationData.dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1);
Bme280CalibrationData.dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2);
Bme280CalibrationData.dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3);
Bme280CalibrationData.dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF);
Bme280CalibrationData.dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5) >> 4);
Bme280CalibrationData.dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6);
I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0x00); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27)
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27)
// Set before CONTROL_meas (DS 5.4.3)
I2cWrite8(bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); // 1x oversampling
I2cWrite8(bmp_address, BME280_REGISTER_CONFIG, 0xA0); // 1sec standby between measurements (to limit self heating), IIR filter off
I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0x27); // 1x oversampling, normal mode
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); // 1x oversampling
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0); // 1sec standby between measurements (to limit self heating), IIR filter off
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27); // 1x oversampling, normal mode
} else {
I2cWrite8(bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
}
return true;
}
void Bme280Read(void)
void Bme2802xRead(uint8_t bmp_idx)
{
int32_t adc_T = I2cRead24(bmp_address, BME280_REGISTER_TEMPDATA);
int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA);
adc_T >>= 4;
int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData.dig_T1 << 1))) * ((int32_t)Bme280CalibrationData.dig_T2)) >> 11;
@ -258,9 +268,9 @@ void Bme280Read(void)
((int32_t)Bme280CalibrationData.dig_T3)) >> 14;
int32_t t_fine = vart1 + vart2;
float T = (t_fine * 5 + 128) >> 8;
bmp_temperature = T / 100.0;
bmp_sensors[bmp_idx].bmp_temperature = T / 100.0;
int32_t adc_P = I2cRead24(bmp_address, BME280_REGISTER_PRESSUREDATA);
int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA);
adc_P >>= 4;
int64_t var1 = ((int64_t)t_fine) - 128000;
@ -277,11 +287,11 @@ void Bme280Read(void)
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);
bmp_pressure = (float)p / 25600.0;
bmp_sensors[bmp_idx].bmp_pressure = (float)p / 25600.0;
if (BMP280_CHIPID == bmp_type) { return; }
if (BMP280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { return; }
int32_t adc_H = I2cRead16(bmp_address, BME280_REGISTER_HUMIDDATA);
int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA);
int32_t v_x1_u32r = (t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData.dig_H4) << 20) -
@ -294,7 +304,7 @@ void Bme280Read(void)
v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
float h = (v_x1_u32r >> 12);
bmp_humidity = h / 1024.0;
bmp_sensors[bmp_idx].bmp_humidity = h / 1024.0;
}
#ifdef USE_BME680
@ -306,17 +316,14 @@ void Bme280Read(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);
}
boolean Bme680Init()
boolean Bme6802xInit(uint8_t bmp_idx)
{
gas_sensor.dev_id = bmp_address;
gas_sensor.dev_id = bmp_sensors[bmp_idx].bmp_address;
gas_sensor.intf = BME680_I2C_INTF;
gas_sensor.read = &I2cReadBuffer;
gas_sensor.write = &I2cWriteBuffer;
@ -353,17 +360,17 @@ boolean Bme680Init()
rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor);
if (rslt != BME680_OK) { return false; }
bme680_state = 0;
bmp_sensors[bmp_idx].bme680_state = 0;
return true;
}
void Bme680Read()
void Bme6802xRead(uint8_t bmp_idx)
{
int8_t rslt = BME680_OK;
if (BME680_CHIPID == bmp_type) {
if (0 == bme680_state) {
if (BME680_CHIPID == bmp_sensors[bmp_idx].bmp_type) {
if (0 == bmp_sensors[bmp_idx].bme680_state) {
/* Trigger the next measurement if you would like to read data out continuously */
rslt = bme680_set_sensor_mode(&gas_sensor);
if (rslt != BME680_OK) { return; }
@ -374,22 +381,22 @@ void Bme680Read()
// bme680_get_profile_dur(&meas_period, &gas_sensor);
// delay(meas_period); /* Delay till the measurement is ready */ // 183 mSec - we'll wait a second
bme680_state = 1;
bmp_sensors[bmp_idx].bme680_state = 1;
} else {
bme680_state = 0;
bmp_sensors[bmp_idx].bme680_state = 0;
struct bme680_field_data data;
rslt = bme680_get_sensor_data(&data, &gas_sensor);
if (rslt != BME680_OK) { return; }
bmp_temperature = data.temperature / 100.0;
bmp_humidity = data.humidity / 1000.0;
bmp_pressure = data.pressure / 100.0;
bmp_sensors[bmp_idx].bmp_temperature = data.temperature / 100.0;
bmp_sensors[bmp_idx].bmp_humidity = data.humidity / 1000.0;
bmp_sensors[bmp_idx].bmp_pressure = data.pressure / 100.0;
/* Avoid using measurements from an unstable heating setup */
if (data.status & BME680_GASM_VALID_MSK) {
bmp_gas_resistance = data.gas_resistance / 1000.0;
bmp_sensors[bmp_idx].bmp_gas_resistance = data.gas_resistance / 1000.0;
} else {
bmp_gas_resistance = 0;
bmp_sensors[bmp_idx].bmp_gas_resistance = 0;
}
}
}
@ -402,65 +409,66 @@ void Bme680Read()
void BmpDetect()
{
if (bmp_type) { return; }
if (bmp_count) return;
for (byte i = 0; i < sizeof(bmp_addresses); i++) {
bmp_address = bmp_addresses[i];
bmp_type = I2cRead8(bmp_address, BMP_REGISTER_CHIPID);
for (byte i = 0; i < BMP_MAX_SENSORS; i++) {
uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID);
if (bmp_type) {
break;
}
}
if (bmp_type) {
bmp_model = 0;
boolean success = false;
switch (bmp_type) {
case BMP180_CHIPID:
success = Bmp180Calibration();
break;
case BME280_CHIPID:
bmp_model++; // 2
case BMP280_CHIPID:
bmp_model++; // 1
success = Bmx280Calibrate();
break;
#ifdef USE_BME680
case BME680_CHIPID:
bmp_model = 3; // 3
success = Bme680Init();
break;
#endif // USE_BME680
}
if (success) {
GetTextIndexed(bmp_name, sizeof(bmp_name), bmp_model, kBmpTypes);
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_name, bmp_address);
AddLog(LOG_LEVEL_DEBUG);
}
else {
bmp_type = 0;
bmp_sensors[bmp_count].bmp_address = bmp_addresses[i];
bmp_sensors[bmp_count].bmp_type = bmp_type;
bmp_sensors[bmp_count].bmp_model = 0;
boolean success = false;
switch (bmp_type) {
case BMP180_CHIPID:
success = Bmp1802xCalibration(bmp_count);
break;
case BME280_CHIPID:
bmp_sensors[bmp_count].bmp_model++; // 2
case BMP280_CHIPID:
bmp_sensors[bmp_count].bmp_model++; // 1
success = Bmx2802xCalibrate(bmp_count);
break;
#ifdef USE_BME680
case BME680_CHIPID:
bmp_sensors[bmp_count].bmp_model = 3; // 3
success = Bme6802xInit(bmp_count);
break;
#endif // USE_BME680
}
if (success) {
GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes);
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_sensors[bmp_count].bmp_name, bmp_sensors[bmp_count].bmp_address);
AddLog(LOG_LEVEL_DEBUG);
bmp_count++;
}
}
}
}
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
for (byte bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) {
switch (bmp_sensors[bmp_idx].bmp_type) {
case BMP180_CHIPID:
Bmp1802xRead(bmp_idx);
break;
case BMP280_CHIPID:
case BME280_CHIPID:
Bme2802xRead(bmp_idx);
break;
#ifdef USE_BME680
case BME680_CHIPID:
Bme6802xRead(bmp_idx);
break;
#endif // USE_BME680
}
if (bmp_sensors[bmp_idx].bmp_temperature != 0.0) {
bmp_sensors[bmp_idx].bmp_temperature = ConvertTemp(bmp_sensors[bmp_idx].bmp_temperature);
}
}
if (bmp_temperature != 0.0) { bmp_temperature = ConvertTemp(bmp_temperature); }
SetGlobalValues(bmp_temperature, bmp_humidity);
SetGlobalValues(bmp_sensors[0].bmp_temperature, bmp_sensors[0].bmp_humidity);
}
void BmpEverySecond()
@ -477,72 +485,91 @@ void BmpEverySecond()
void BmpShow(boolean json)
{
if (bmp_type) {
float bmp_sealevel = 0.0;
char temperature[10];
char pressure[10];
char sea_pressure[10];
char humidity[10];
for (byte bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) {
if (bmp_sensors[bmp_idx].bmp_type) {
float bmp_sealevel = 0.0;
char temperature[10];
char pressure[10];
char sea_pressure[10];
char humidity[10];
char name[10];
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(bmp_gas_resistance, 2, gas_resistance);
#endif // USE_BME680
if (json) {
char json_humidity[40];
snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity);
char json_sealevel[40];
snprintf_P(json_sealevel, sizeof(json_sealevel), PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure);
#ifdef USE_BME680
char json_gas[40];
snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"),
mqtt_data, bmp_name, temperature, (bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "", (bmp_model >= 3) ? json_gas : "");
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"),
mqtt_data, bmp_name, temperature, (bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "");
#endif // USE_BME680
#ifdef USE_DOMOTICZ
if (0 == tele_period) {
DomoticzTempHumPressureSensor(temperature, humidity, pressure);
#ifdef USE_BME680
if (bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp_gas_resistance); }
#endif // USE_BME680
if (bmp_sensors[bmp_idx].bmp_pressure != 0.0) {
bmp_sealevel = (bmp_sensors[bmp_idx].bmp_pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6;
}
snprintf(name, sizeof(name), bmp_sensors[bmp_idx].bmp_name);
if (bmp_count > 1) {
snprintf_P(name, sizeof(name), PSTR("%s-%02X"), name, bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX
}
dtostrfd(bmp_sensors[bmp_idx].bmp_temperature, Settings.flag2.temperature_resolution, temperature);
dtostrfd(bmp_sensors[bmp_idx].bmp_pressure, Settings.flag2.pressure_resolution, pressure);
dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure);
dtostrfd(bmp_sensors[bmp_idx].bmp_humidity, Settings.flag2.humidity_resolution, humidity);
#ifdef USE_BME680
char gas_resistance[10];
dtostrfd(bmp_sensors[bmp_idx].bmp_gas_resistance, 2, gas_resistance);
#endif // USE_BME680
if (json) {
char json_humidity[40];
snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity);
char json_sealevel[40];
snprintf_P(json_sealevel, sizeof(json_sealevel), PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure);
#ifdef USE_BME680
char json_gas[40];
snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance);
snprintf_P(mqtt_data,
sizeof(mqtt_data),
PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"),
mqtt_data,
name,
temperature,
(bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "",
pressure,
(Settings.altitude != 0) ? json_sealevel : "",
(bmp_sensors[bmp_idx].bmp_model >= 3) ? json_gas : ""
);
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"),
mqtt_data, name, temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : "");
#endif // USE_BME680
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && (0 == bmp_idx)) { // We want the same first sensor to report to Domoticz in case a read is missed
DomoticzTempHumPressureSensor(temperature, humidity, pressure);
#ifdef USE_BME680
if (bmp_sensors[bmp_idx].bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp_sensors[bmp_idx].bmp_gas_resistance); }
#endif // USE_BME680
}
#endif // USE_DOMOTICZ
#ifdef USE_KNX
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, bmp_temperature);
KnxSensor(KNX_HUMIDITY, bmp_humidity);
}
if (0 == tele_period) {
KnxSensor(KNX_TEMPERATURE, bmp_sensors[bmp_idx].bmp_temperature);
KnxSensor(KNX_HUMIDITY, bmp_sensors[bmp_idx].bmp_humidity);
}
#endif // USE_KNX
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, bmp_name, temperature, TempUnit());
if (bmp_model >= 2) {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, bmp_name, humidity);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_PRESSURE, mqtt_data, bmp_name, pressure);
if (Settings.altitude != 0) {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SEAPRESSURE, mqtt_data, bmp_name, sea_pressure);
}
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, name, temperature, TempUnit());
if (bmp_sensors[bmp_idx].bmp_model >= 2) {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, name, humidity);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_PRESSURE, mqtt_data, name, pressure);
if (Settings.altitude != 0) {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SEAPRESSURE, mqtt_data, name, sea_pressure);
}
#ifdef USE_BME680
if (bmp_model >= 3) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{s}%s " D_GAS "{m}%s " D_UNIT_KILOOHM "{e}"), mqtt_data, bmp_name, gas_resistance);
}
if (bmp_sensors[bmp_idx].bmp_model >= 3) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{s}%s " D_GAS "{m}%s " D_UNIT_KILOOHM "{e}"), mqtt_data, name, gas_resistance);
}
#endif // USE_BME680
#endif // USE_WEBSERVER
}
}
}
}

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
VER = '2.0.0000'
VER = '2.0.0001'
"""
decode-config.py - Backup/Restore Sonoff-Tasmota configuration data
@ -201,7 +201,7 @@ DEFAULTS = {
'jsonsort': True,
'jsonrawvalues':False,
'jsonrawkeys': False,
'jsonhidepw': True,
'jsonhidepw': False,
},
}
args = {}
@ -250,21 +250,27 @@ Settings dictionary describes the config file fields definition:
negative <s> shift the result <s> left bits
datadef
Define the field interpretation different from simple
standard types (like char, byte, int) e. g. lists or bit fields
Can be None, a single integer, a list or a dictionary
None:
None must be given if the field contains a simple value
desrcibed by the <format> prefix
n:
Same as [n] below
[n]:
Defines a one-dimensional array of size <n>
[n, n <,n...>]
Defines a multi-dimensional array
Data definition, is either a array definition or a
tuple containing an array definition and min/max values
Format: arraydef|(arraydef, min, max)
arraydef:
None:
None must be given if the field contains a
simple value desrcibed by the <format> prefix
n:
[n]:
Defines a one-dimensional array of size <n>
[n, m <,o...>]
Defines a multi-dimensional array
min:
defines a minimum valid value or None if all values
for this format is allowed.
max:
defines a maximum valid value or None if all values
for this format is allowed.
converter (optional)
Conversion methode(s): ()|'xxx'|func
Conversion methode(s): 'xxx'|func or ('xxx'|func, 'xxx'|func)
Read conversion is used if args.jsonrawvalues is False
Write conversion is used if jsonrawvalues from restore json
file is False or args.jsonrawvalues is False.
@ -845,7 +851,19 @@ Setting_6_2_1_19.update({
'weight_max': ('<L', 0x7B8, None, ('float($) / 10', 'int($ * 10)')),
})
Setting_6_2_1_20 = Setting_6_2_1_19
Setting_6_2_1_20.update({
'flag3': ({
'raw': ('<L', 0x3A0, None, ('"0x{:08x}".format($)', None)),
'timers_enable': ('<L', (0x3A0, 1, 0), None),
'user_esp8285_enable': ('<L', (0x3A0, 1, 1), None),
'time_append_timezone':('<L', (0x3A0, 1, 2), None),
'gui_hostname_ip': ('<L', (0x3A0, 1, 3), None),
}, 0x3A0, None),
})
Settings = [
(0x6020114, 0xe00, Setting_6_2_1_20),
(0x6020113, 0xe00, Setting_6_2_1_19),
(0x602010E, 0xe00, Setting_6_2_1_14),
(0x602010A, 0xe00, Setting_6_2_1_10),
@ -892,21 +910,22 @@ def GetTemplateSetting(decode_cfg):
@return:
version, template, size, settings to use; None if version is invalid
"""
version = 0x0
template = size = setting = None
try:
version = GetField(decode_cfg, 'version', Setting_6_2_1['version'], raw=True)
# search setting definition
template = None
setting = None
size = None
for cfg in Settings:
if version >= cfg[0]:
template = cfg
size = template[1]
setting = template[2]
break
except:
return None,None,None,None
# search setting definition
template = None
setting = None
size = None
for cfg in Settings:
if version >= cfg[0]:
template = cfg
size = template[1]
setting = template[2]
break
pass
return version, template, size, setting
@ -1652,6 +1671,9 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
result = None
if fieldname == 'raw' and not args.jsonrawkeys:
return result
# get field definition
_format, baseaddr, bits, bitshift, datadef, convert = GetFieldDef(fielddef)
@ -1662,7 +1684,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
for i in range(0, datadef[0]):
subfielddef = GetSubfieldDef(fielddef)
length = GetFieldLength(subfielddef)
if length != 0 and (fieldname != 'raw' or args.jsonrawkeys):
if length != 0:
result.append(GetField(dobj, fieldname, subfielddef, raw=raw, addroffset=addroffset+offset))
offset += length
@ -1722,6 +1744,9 @@ def SetField(dobj, fieldname, fielddef, restore, raw=False, addroffset=0, filena
_format, baseaddr, bits, bitshift, datadef, convert = GetFieldDef(fielddef)
fieldname = str(fieldname)
if fieldname == 'raw' and not args.jsonrawkeys:
return dobj
# do not write readonly values
if isinstance(convert, (list,tuple)) and len(convert)>1 and convert[1]==None:
if args.debug: