diff --git a/README.md b/README.md
index e2075c92e..77ed35fc1 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
## Sonoff-Tasmota
Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE.
-Current version is **5.8.0h** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
+Current version is **5.8.0i** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
### ATTENTION All versions
diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino
index 5936bf5ae..e7c357674 100644
--- a/sonoff/_releasenotes.ino
+++ b/sonoff/_releasenotes.ino
@@ -1,6 +1,13 @@
-/* 5.8.0h
+/* 5.8.0i
+ * Add Domoticz counter sensor to IrReceive representing Received IR Protocol and Data
+ * Fix Southern Hemisphere TIME_STD/TIME_DST (#968)
+ * Add Sea level pressure calculation (#974)
+ * Fix virtual relay status message used with Color/Dimmer control (#989)
+ * Fix command IRSend and IRHvac case sensitive parameter regression introduced with version 5.8.0 (#993)
+ *
+ * 5.8.0h
* Rename command IRRemote to IRSend (#956)
- * Add optional IR Receiver support (#956)
+ * Add IR Receiver support. Disable in user_config.h (#956)
* Change default PWM assignment for Witty Cloud to support optional Color/Dimmer control (#976)
* GPIO12 (Green) from GPIO_PWM4 to GPIO_PWM2
* GPIO13 (Blue) from GPIO_PWM5 to GPIO_PWM3
diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h
index ea6796ec0..90cbddb3c 100644
--- a/sonoff/language/en-GB.h
+++ b/sonoff/language/en-GB.h
@@ -134,6 +134,7 @@
#define D_POWERFACTOR "Factor"
#define D_POWERUSAGE "Power"
#define D_PRESSURE "Pressure"
+#define D_PRESSUREATSEALEVEL "SeaPressure"
#define D_PROGRAM_FLASH_SIZE "Program Flash Size"
#define D_PROGRAMFLASHSIZE "ProgramFlashSize"
#define D_PROGRAM_SIZE "Program Size"
@@ -617,6 +618,7 @@
#define D_RESET_AND_RESTARTING "Reset and Restarting"
#define D_ONE_TO_RESET "1 to reset"
#define D_CMND_TIMEZONE "Timezone"
+#define D_CMND_ALTITUDE "Altitude"
#define D_CMND_LEDPOWER "LedPower"
#define D_CMND_LEDSTATE "LedState"
#define D_CMND_CFGDUMP "CfgDump"
diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h
index 5f4aa6db2..8dc1e979a 100644
--- a/sonoff/language/nl-NL.h
+++ b/sonoff/language/nl-NL.h
@@ -134,6 +134,7 @@
#define D_POWERFACTOR "Factor"
#define D_POWERUSAGE "Vermogen"
#define D_PRESSURE "Luchtdruk"
+#define D_PRESSUREATSEALEVEL "ZeeLuchtdruk"
#define D_PROGRAM_FLASH_SIZE "Programma Flash Grootte"
#define D_PROGRAMFLASHSIZE "ProgrammaFlashGrootte"
#define D_PROGRAM_SIZE "Programma Grootte"
@@ -617,6 +618,7 @@
#define D_RESET_AND_RESTARTING "Reset en herstarten"
#define D_ONE_TO_RESET "1 voor reset"
#define D_CMND_TIMEZONE "Timezone"
+#define D_CMND_ALTITUDE "Altitude"
#define D_CMND_LEDPOWER "LedPower"
#define D_CMND_LEDSTATE "LedState"
#define D_CMND_CFGDUMP "CfgDump"
diff --git a/sonoff/settings.h b/sonoff/settings.h
index e50c0acd8..90f2ddce4 100644
--- a/sonoff/settings.h
+++ b/sonoff/settings.h
@@ -89,8 +89,9 @@ struct SYSCFG {
char ex_state_text[3][11]; // was state_text until 5.1.6, was ex_mqtt_subtopic[33] until 4.1.1
byte ex_mqtt_button_retain; // Not used since 5.0.2
byte ex_mqtt_power_retain; // Not used since 5.0.2
- byte ex_value_units; // Not used since 5.0.2
- byte ex_button_restrict; // Not used since 5.0.2
+ //byte ex_value_units; // Not used since 5.0.2
+ //byte ex_button_restrict; // Not used since 5.0.2
+ int16_t altitude; // Add since 5.8.0i
uint16_t tele_period;
uint8_t power;
diff --git a/sonoff/settings.ino b/sonoff/settings.ino
index c3479336b..775c5c695 100644
--- a/sonoff/settings.ino
+++ b/sonoff/settings.ino
@@ -639,9 +639,6 @@ void CFG_Delta()
if (sysCfg.version < 0x03091500) {
for (byte i = 0; i < 4; i++) sysCfg.switchmode[i] = SWITCH_MODE;
}
- if (sysCfg.version < 0x04000200) {
- sysCfg.ex_button_restrict = 0;
- }
if (sysCfg.version < 0x04000400) {
CFG_DefaultSet_4_0_4();
}
@@ -663,8 +660,8 @@ void CFG_Delta()
if (sysCfg.version < 0x05000105) {
sysCfg.flag = { 0 };
sysCfg.flag.savestate = SAVE_STATE;
- sysCfg.flag.button_restrict = sysCfg.ex_button_restrict;
- sysCfg.flag.value_units = sysCfg.ex_value_units;
+ sysCfg.flag.button_restrict = 0;
+ sysCfg.flag.value_units = 0;
sysCfg.flag.mqtt_enabled = sysCfg.ex_mqtt_enabled;
// sysCfg.flag.mqtt_response = 0;
sysCfg.flag.mqtt_power_retain = sysCfg.ex_mqtt_power_retain;
diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino
index cf31167f0..241c2d79f 100644
--- a/sonoff/sonoff.ino
+++ b/sonoff/sonoff.ino
@@ -25,11 +25,12 @@
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
====================================================*/
-#define VERSION 0x05080008 // 5.8.0h
+#define VERSION 0x05080009 // 5.8.0i
enum week_t {Last, First, Second, Third, Fourth};
enum dow_t {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
enum month_t {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
+enum hemis_t {North, South};
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; // SerialLog, Syslog, Weblog
enum wifi_t {WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, MAX_WIFI_OPTION}; // WifiConfig
enum swtch_t {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, MAX_SWITCH_OPTION}; // SwitchMode
@@ -206,6 +207,7 @@ struct TIME_T {
struct TimeChangeRule
{
+ uint8_t hemis; // 0-Northern, 1=Southern Hemisphere (=Opposite DST/STD)
uint8_t week; // 1=First, 2=Second, 3=Third, 4=Fourth, or 0=Last week of the month
uint8_t dow; // day of week, 1=Sun, 2=Mon, ... 7=Sat
uint8_t month; // 1=Jan, 2=Feb, ... 12=Dec
@@ -1510,6 +1512,12 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_TIMEZONE "\":%d}"), sysCfg.timezone);
}
+ else if (!strcasecmp_P(type, PSTR(D_CMND_ALTITUDE))) {
+ if ((data_len > 0) && ((payload >= -30000) && (payload <= 30000))) {
+ sysCfg.altitude = payload;
+ }
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_ALTITUDE "\":%d}"), sysCfg.altitude);
+ }
else if (!strcasecmp_P(type, PSTR(D_CMND_LEDPOWER))) {
if ((payload >= 0) && (payload <= 2)) {
sysCfg.ledstate &= 8;
diff --git a/sonoff/support.ino b/sonoff/support.ino
index 3a2ba2250..4ef39057f 100644
--- a/sonoff/support.ino
+++ b/sonoff/support.ino
@@ -1086,8 +1086,13 @@ void rtc_second()
loctime = utctime;
if (loctime > 1451602800) { // 2016-01-01
if (99 == sysCfg.timezone) {
- dstoffset = myDST.offset * SECS_PER_MIN;
- stdoffset = mySTD.offset * SECS_PER_MIN;
+ if (myDST.hemis) {
+ dstoffset = mySTD.offset * SECS_PER_MIN; // Southern hemisphere
+ stdoffset = myDST.offset * SECS_PER_MIN;
+ } else {
+ dstoffset = myDST.offset * SECS_PER_MIN; // Northern hemisphere
+ stdoffset = mySTD.offset * SECS_PER_MIN;
+ }
if ((utctime >= (dsttime - stdoffset)) && (utctime < (stdtime - dstoffset))) {
loctime += dstoffset; // Daylight Saving Time
} else {
diff --git a/sonoff/user_config.h b/sonoff/user_config.h
index c74eb21ec..3afdad2d0 100644
--- a/sonoff/user_config.h
+++ b/sonoff/user_config.h
@@ -131,10 +131,10 @@
#define NTP_SERVER3 "0.nl.pool.ntp.org" // [NtpServer3] Select third NTP server by name or IP address (93.94.224.67)
// -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes
-#define TIME_DST Last, Sun, Mar, 2, +120 // Last sunday in march at 02:00 +120 minutes
+#define TIME_DST North, Last, Sun, Mar, 2, +120 // Northern Hemisphere, Last sunday in march at 02:00 +120 minutes
// -- Time - Start Standard Time and timezone offset from UTC in minutes
-#define TIME_STD Last, Sun, Oct, 3, +60 // Last sunday in october 02:00 +60 minutes
+#define TIME_STD North, Last, Sun, Oct, 3, +60 // Northern Hemisphere, Last sunday in october 02:00 +60 minutes
// -- Application ---------------------------------
#define APP_TIMEZONE 1 // [Timezone] +1 hour (Amsterdam) (-12 .. 12 = hours from UTC, 99 = use TIME_DST/TIME_STD)
diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino
index 9f5f48806..a2b66caaf 100644
--- a/sonoff/webserver.ino
+++ b/sonoff/webserver.ino
@@ -270,6 +270,8 @@ const char HTTP_SNS_HUM[] PROGMEM =
"
%s " D_HUMIDITY " | %s% |
";
const char HTTP_SNS_PRESSURE[] PROGMEM =
"%s " D_PRESSURE " | %s " D_UNIT_PRESSURE " |
";
+const char HTTP_SNS_PRESSUREATSEALEVEL[] PROGMEM =
+ "%s " D_PRESSUREATSEALEVEL " | %s " D_UNIT_PRESSURE " |
";
const char HTTP_SNS_LIGHT[] PROGMEM =
"%s " D_LIGHT " | %d% |
";
const char HTTP_SNS_NOISE[] PROGMEM =
diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino
index 3cdae378d..1391b0f81 100644
--- a/sonoff/xdrv_ir_send.ino
+++ b/sonoff/xdrv_ir_send.ino
@@ -23,31 +23,35 @@
\*********************************************************************************************/
#ifndef USE_IR_HVAC
- #include
+#include
#else
- #include
+#include
- // HVAC TOSHIBA_
- #define HVAC_TOSHIBA_HDR_MARK 4400
- #define HVAC_TOSHIBA_HDR_SPACE 4300
- #define HVAC_TOSHIBA_BIT_MARK 543
- #define HVAC_TOSHIBA_ONE_SPACE 1623
- #define HVAC_MISTUBISHI_ZERO_SPACE 472
- #define HVAC_TOSHIBA_RPT_MARK 440
- #define HVAC_TOSHIBA_RPT_SPACE 7048 // Above original iremote limit
- #define HVAC_TOSHIBA_DATALEN 9
+// HVAC TOSHIBA_
+#define HVAC_TOSHIBA_HDR_MARK 4400
+#define HVAC_TOSHIBA_HDR_SPACE 4300
+#define HVAC_TOSHIBA_BIT_MARK 543
+#define HVAC_TOSHIBA_ONE_SPACE 1623
+#define HVAC_MISTUBISHI_ZERO_SPACE 472
+#define HVAC_TOSHIBA_RPT_MARK 440
+#define HVAC_TOSHIBA_RPT_SPACE 7048 // Above original iremote limit
+#define HVAC_TOSHIBA_DATALEN 9
- IRMitsubishiAC *mitsubir = NULL;
+IRMitsubishiAC *mitsubir = NULL;
- const char FANSPEED[] = "A12345S";
- const char HVACMODE[] = "HDCA";
+const char FANSPEED[] = "A12345S";
+const char HVACMODE[] = "HDCA";
#endif
+/*********************************************************************************************\
+ * IR Send
+\*********************************************************************************************/
+
IRsend *irsend = NULL;
void ir_send_init(void)
{
- irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND
+ irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND
irsend->begin();
#ifdef USE_IR_HVAC
@@ -56,151 +60,110 @@ void ir_send_init(void)
}
#ifdef USE_IR_RECEIVE
-#define IR_TIME_AVOID_DUPLICATE 500 // Milliseconds
+/*********************************************************************************************\
+ * IR Receive
+\*********************************************************************************************/
+
+#define IR_TIME_AVOID_DUPLICATE 500 // Milliseconds
IRrecv *irrecv = NULL;
unsigned long ir_lasttime = 0;
void ir_recv_init(void)
{
- irrecv = new IRrecv(pin[GPIO_IRRECV]); // an IR led is at GPIO_IRRECV
- irrecv->enableIRIn(); // Start the receiver
-// addLog_P(LOG_LEVEL_DEBUG, PSTR("IrReceive initialized"));
-}
-#endif // USE_IR_RECEIVE
+ irrecv = new IRrecv(pin[GPIO_IRRECV]); // an IR led is at GPIO_IRRECV
+ irrecv->enableIRIn(); // Start the receiver
+ // addLog_P(LOG_LEVEL_DEBUG, PSTR("IrReceive initialized"));
+}
+
+void ir_recv_check()
+{
+ char sirtype[100];
+ char *protocol;
+ int8_t iridx = 0;
+
+ decode_results results;
+
+ if (irrecv->decode(&results)) {
+
+ snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_IRR "RawLen %d, Bits %d, Value %08X, Decode %d"),
+ results.rawlen, results.bits, results.value, results.decode_type);
+ addLog(LOG_LEVEL_DEBUG);
+
+ unsigned long now = millis();
+ if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) {
+ ir_lasttime = now;
+
+ iridx = results.decode_type;
+ if ((iridx < 0) || (iridx > 14)) {
+ iridx = 0;
+ }
+ // Based on IRremoteESP8266.h enum decode_type_t
+ snprintf_P(sirtype, sizeof(sirtype), PSTR("UNKNOWN RC5 RC6 NEC SONY PANASONIC JVC SAMSUNG WHYNTER AIWA_RC_T501 LG SANYO MITSUBISHI DISH SHARP"));
+ protocol = strtok(sirtype, " ");
+ while (iridx) {
+ iridx--;
+ protocol = strtok(NULL, " ");
+ }
+
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_IRRECEIVED "\":{\"" D_IR_PROTOCOL "\":\"%s\", \"" D_IR_BITS "\":%d, \"" D_IR_DATA "\":\"%X\"}}"),
+ protocol, results.bits, results.value);
+ mqtt_publish_topic_P(6, PSTR(D_IRRECEIVED));
+#ifdef USE_DOMOTICZ
+ unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28]
+ domoticz_sensor(DZ_COUNT, value); // Send data as Domoticz Counter value
+#endif // USE_DOMOTICZ
+ }
+
+ irrecv->resume();
+ }
+}
+#endif // USE_IR_RECEIVE
+
+#ifdef USE_IR_HVAC
/*********************************************************************************************\
- * Commands
+ * IR Heating, Ventilation and Air Conditioning using IRMitsubishiAC library
\*********************************************************************************************/
-/*
- * ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
- IRsend:
- { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
-
- IRhvac:
- { "Vendor": "", "Power": <0|1>, "Mode": "", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
-*/
-
-boolean ir_send_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload)
-{
- boolean serviced = true;
- boolean error = false;
- const char *protocol;
- uint8_t bits = 0;
- uint32_t data = 0;
-
- const char *HVAC_Mode;
- const char *HVAC_FanMode;
- const char *HVAC_Vendor;
- int HVAC_Temp = 21;
- boolean HVAC_Power = true;
-
- if (!strcasecmp_P(type, PSTR(D_CMND_IRSEND))) {
- if (data_len) {
- StaticJsonBuffer<128> jsonBuf;
- JsonObject &ir_json = jsonBuf.parseObject(dataBuf);
- if (!ir_json.success()) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_INVALID_JSON "\"}")); // JSON decode failed
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_DONE "\"}"));
- protocol = ir_json[D_IR_PROTOCOL];
- bits = ir_json[D_IR_BITS];
- data = ir_json[D_IR_DATA];
- if (protocol && bits && data) {
- if (!strcasecmp_P(protocol, PSTR("NEC"))) irsend->sendNEC(data, bits);
- else if (!strcasecmp_P(protocol, PSTR("SONY"))) irsend->sendSony(data, bits);
- else if (!strcasecmp_P(protocol, PSTR("RC5"))) irsend->sendRC5(data, bits);
- else if (!strcasecmp_P(protocol, PSTR("RC6"))) irsend->sendRC6(data, bits);
- else if (!strcasecmp_P(protocol, PSTR("DISH"))) irsend->sendDISH(data, bits);
- else if (!strcasecmp_P(protocol, PSTR("JVC"))) irsend->sendJVC(data, bits, 1);
- else if (!strcasecmp_P(protocol, PSTR("SAMSUNG"))) irsend->sendSAMSUNG(data, bits);
- else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_PROTOCOL_NOT_SUPPORTED "\"}"));
- }
- } else error = true;
- }
- } else error = true;
- if (error) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_NO " " D_IR_PROTOCOL ", " D_IR_BITS " " D_OR " " D_IR_DATA "\"}"));
- }
- }
-#ifdef USE_IR_HVAC
- else if (!strcasecmp_P(type, PSTR(D_CMND_IRHVAC))) {
- if (data_len) {
- StaticJsonBuffer<164> jsonBufer;
- JsonObject &root = jsonBufer.parseObject(dataBuf);
- if (!root.success()) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_INVALID_JSON "\"}")); // JSON decode failed
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_DONE "\"}"));
- HVAC_Vendor = root[D_IRHVAC_VENDOR];
- HVAC_Power = root[D_IRHVAC_POWER];
- HVAC_Mode = root[D_IRHVAC_MODE];
- HVAC_FanMode = root[D_IRHVAC_FANSPEED];
- HVAC_Temp = root[D_IRHVAC_TEMP];
-
-// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"),
-// HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp);
-// addLog(LOG_LEVEL_DEBUG);
-
- if (HVAC_Vendor == NULL || !strcasecmp_P(HVAC_Vendor, PSTR("TOSHIBA"))) {
- error = ir_hvac_toshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
- }
- else if (!strcasecmp_P(HVAC_Vendor, PSTR("MITSUBISHI"))) {
- error = ir_hvac_mitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
- }
- else error = true;
- }
- } else error = true;
- if (error) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_WRONG " " D_IRHVAC_VENDOR ", " D_IRHVAC_MODE " " D_OR " " D_IRHVAC_FANSPEED "\"}"));
- }
- }
-#endif // USE_IR_HVAC
- else {
- serviced = false; // Unknown command
- }
- return serviced;
-}
-
-#ifdef USE_IR_HVAC
boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp)
{
- unsigned int rawdata[2 + 2*8*HVAC_TOSHIBA_DATALEN + 2];
- byte data[HVAC_TOSHIBA_DATALEN] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00 };
+ unsigned int rawdata[2 + 2 * 8 * HVAC_TOSHIBA_DATALEN + 2];
+ byte data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00};
char *p;
char *token;
uint8_t mode;
if (HVAC_Mode == NULL) {
- p = (char*)HVACMODE; // default HVAC_HOT
- } else {
+ p = (char *)HVACMODE; // default HVAC_HOT
+ }
+ else {
p = strchr(HVACMODE, toupper(HVAC_Mode[0]));
}
if (!p) {
return true;
}
- data[6] = (p - HVACMODE) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00
+ data[6] = (p - HVACMODE) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00
if (!HVAC_Power) {
- data[6] = (byte) 0x07; // Turn OFF HVAC
+ data[6] = (byte)0x07; // Turn OFF HVAC
}
if (HVAC_FanMode == NULL) {
- p = (char*)FANSPEED; // default FAN_SPEED_AUTO
- } else {
+ p = (char *)FANSPEED; // default FAN_SPEED_AUTO
+ }
+ else {
p = strchr(FANSPEED, toupper(HVAC_FanMode[0]));
}
if (!p) {
return true;
}
- mode = p - FANSPEED +1;
+ mode = p - FANSPEED + 1;
if ((1 == mode) || (7 == mode)) {
mode = 0;
}
- mode = mode << 5; // AUTO = 0x00, SPEED = 0x40, 0x60, 0x80, 0xA0, 0xC0, SILENT = 0x00
+ mode = mode << 5; // AUTO = 0x00, SPEED = 0x40, 0x60, 0x80, 0xA0, 0xC0, SILENT = 0x00
data[6] = data[6] | mode;
byte Temp;
@@ -213,11 +176,11 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean
else {
Temp = HVAC_Temp;
}
- data[5] = (byte) Temp - 17 << 4;
+ data[5] = (byte)Temp - 17 << 4;
- data[HVAC_TOSHIBA_DATALEN-1] = 0;
+ data[HVAC_TOSHIBA_DATALEN - 1] = 0;
for (int x = 0; x < HVAC_TOSHIBA_DATALEN - 1; x++) {
- data[HVAC_TOSHIBA_DATALEN-1] = (byte) data[x] ^ data[HVAC_TOSHIBA_DATALEN -1]; // CRC is a simple bits addition
+ data[HVAC_TOSHIBA_DATALEN - 1] = (byte)data[x] ^ data[HVAC_TOSHIBA_DATALEN - 1]; // CRC is a simple bits addition
}
int i = 0;
@@ -246,14 +209,14 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean
rawdata[i++] = HVAC_TOSHIBA_RPT_SPACE;
noInterrupts();
- irsend->sendRaw(rawdata,i,38);
- irsend->sendRaw(rawdata,i,38);
+ irsend->sendRaw(rawdata, i, 38);
+ irsend->sendRaw(rawdata, i, 38);
interrupts();
return false;
}
-boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp)
+boolean ir_hvac_mitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp)
{
char *p;
char *token;
@@ -262,73 +225,159 @@ boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boole
mitsubir->stateReset();
if (HVAC_Mode == NULL) {
- p = (char*)HVACMODE; // default HVAC_HOT
- } else {
+ p = (char *)HVACMODE; // default HVAC_HOT
+ }
+ else {
p = strchr(HVACMODE, toupper(HVAC_Mode[0]));
}
if (!p) {
return true;
}
- mode = (p - HVACMODE +1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20
+ mode = (p - HVACMODE + 1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20
mitsubir->setMode(mode);
mitsubir->setPower(HVAC_Power);
if (HVAC_FanMode == NULL) {
- p = (char*)FANSPEED; // default FAN_SPEED_AUTO
- } else {
+ p = (char *)FANSPEED; // default FAN_SPEED_AUTO
+ }
+ else {
p = strchr(FANSPEED, toupper(HVAC_FanMode[0]));
}
if (!p) {
return true;
}
- mode = p - FANSPEED; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6
+ mode = p - FANSPEED; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6
mitsubir->setFan(mode);
mitsubir->setTemp(HVAC_Temp);
mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO);
mitsubir->send();
-// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"),
-// mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane());
-// addLog(LOG_LEVEL_DEBUG);
+ // snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"),
+ // mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane());
+ // addLog(LOG_LEVEL_DEBUG);
return false;
}
-#endif // USE_IR_HVAC
+#endif // USE_IR_HVAC
-#ifdef USE_IR_RECEIVE
-void ir_recv_check()
+/*********************************************************************************************\
+ * Commands
+\*********************************************************************************************/
+
+/*
+ * ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
+ IRsend:
+ { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
+
+ IRhvac:
+ { "Vendor": "", "Power": <0|1>, "Mode": "", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
+*/
+
+boolean ir_send_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload)
{
- char sirtype[100];
- char *protocol;
- int8_t iridx = 0;
+ boolean serviced = true;
+ boolean error = false;
+ char dataBufUc[data_len];
+ const char *protocol;
+ uint8_t bits = 0;
+ uint32_t data = 0;
- decode_results results;
- if (irrecv->decode(&results)) {
- snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_IRR "RawLen %d, Bits %d, Value %08X, Decode %d"),
- results.rawlen, results.bits, results.value, results.decode_type);
- addLog(LOG_LEVEL_DEBUG);
- unsigned long now = millis();
- if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) {
- ir_lasttime = now;
- iridx = results.decode_type;
- if ((iridx < 0) || (iridx > 14)) {
- iridx = 0;
- }
- // Based on IRremoteESP8266.h enum decode_type_t
- snprintf_P(sirtype, sizeof(sirtype), PSTR("UNKNOWN RC5 RC6 NEC SONY PANASONIC JVC SAMSUNG WHYNTER AIWA_RC_T501 LG SANYO MITSUBISHI DISH SHARP"));
- protocol = strtok(sirtype, " ");
- while (iridx) {
- iridx--;
- protocol = strtok(NULL, " ");
- }
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_IRRECEIVED "\":{\"" D_IR_PROTOCOL "\":\"%s\", \"" D_IR_BITS "\":%d, \"" D_IR_DATA "\":\"%X\"}}"),
- protocol, results.bits, results.value);
- mqtt_publish_topic_P(6, PSTR(D_IRRECEIVED));
- }
- irrecv->resume();
+ const char *HVAC_Mode;
+ const char *HVAC_FanMode;
+ const char *HVAC_Vendor;
+ int HVAC_Temp = 21;
+ boolean HVAC_Power = true;
+
+ for (uint16_t i = 0; i <= sizeof(dataBufUc); i++) {
+ dataBufUc[i] = toupper(dataBuf[i]);
}
+ if (!strcasecmp_P(type, PSTR(D_CMND_IRSEND))) {
+ if (data_len) {
+ StaticJsonBuffer<128> jsonBuf;
+ JsonObject &ir_json = jsonBuf.parseObject(dataBufUc);
+ if (!ir_json.success()) {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_INVALID_JSON "\"}")); // JSON decode failed
+ }
+ else {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_DONE "\"}"));
+ protocol = ir_json[D_IR_PROTOCOL];
+ bits = ir_json[D_IR_BITS];
+ data = ir_json[D_IR_DATA];
+ if (protocol && bits && data) {
+ if (!strcasecmp_P(protocol, PSTR("NEC")))
+ irsend->sendNEC(data, bits);
+ else if (!strcasecmp_P(protocol, PSTR("SONY")))
+ irsend->sendSony(data, bits);
+ else if (!strcasecmp_P(protocol, PSTR("RC5")))
+ irsend->sendRC5(data, bits);
+ else if (!strcasecmp_P(protocol, PSTR("RC6")))
+ irsend->sendRC6(data, bits);
+ else if (!strcasecmp_P(protocol, PSTR("DISH")))
+ irsend->sendDISH(data, bits);
+ else if (!strcasecmp_P(protocol, PSTR("JVC")))
+ irsend->sendJVC(data, bits, 1);
+ else if (!strcasecmp_P(protocol, PSTR("SAMSUNG")))
+ irsend->sendSAMSUNG(data, bits);
+ else {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_PROTOCOL_NOT_SUPPORTED "\"}"));
+ }
+ }
+ else {
+ error = true;
+ }
+ }
+ }
+ else {
+ error = true;
+ }
+ if (error) {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_NO " " D_IR_PROTOCOL ", " D_IR_BITS " " D_OR " " D_IR_DATA "\"}"));
+ }
+ }
+#ifdef USE_IR_HVAC
+ else if (!strcasecmp_P(type, PSTR(D_CMND_IRHVAC))) {
+ if (data_len) {
+ StaticJsonBuffer<164> jsonBufer;
+ JsonObject &root = jsonBufer.parseObject(dataBufUc);
+ if (!root.success()) {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_INVALID_JSON "\"}")); // JSON decode failed
+ }
+ else {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_DONE "\"}"));
+ HVAC_Vendor = root[D_IRHVAC_VENDOR];
+ HVAC_Power = root[D_IRHVAC_POWER];
+ HVAC_Mode = root[D_IRHVAC_MODE];
+ HVAC_FanMode = root[D_IRHVAC_FANSPEED];
+ HVAC_Temp = root[D_IRHVAC_TEMP];
+
+ // snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"),
+ // HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp);
+ // addLog(LOG_LEVEL_DEBUG);
+
+ if (HVAC_Vendor == NULL || !strcasecmp_P(HVAC_Vendor, PSTR("TOSHIBA"))) {
+ error = ir_hvac_toshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
+ }
+ else if (!strcasecmp_P(HVAC_Vendor, PSTR("MITSUBISHI"))) {
+ error = ir_hvac_mitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
+ }
+ else {
+ error = true;
+ }
+ }
+ }
+ else {
+ error = true;
+ }
+ if (error) {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRHVAC "\":\"" D_WRONG " " D_IRHVAC_VENDOR ", " D_IRHVAC_MODE " " D_OR " " D_IRHVAC_FANSPEED "\"}"));
+ }
+ }
+#endif // USE_IR_HVAC
+ else {
+ serviced = false; // Unknown command
+ }
+ return serviced;
}
-#endif // USE_IR_RECEIVE
-#endif // USE_IR_REMOTE
+#endif // USE_IR_REMOTE
diff --git a/sonoff/xdrv_snfbridge.ino b/sonoff/xdrv_snfbridge.ino
index fcdbd13f8..70fdb008d 100644
--- a/sonoff/xdrv_snfbridge.ino
+++ b/sonoff/xdrv_snfbridge.ino
@@ -91,7 +91,7 @@ void sb_received()
mqtt_publish_topic_P(6, PSTR(D_RFRECEIVED));
#ifdef USE_DOMOTICZ
domoticz_sensor(DZ_COUNT, rid); // Send rid as Domoticz Counter value
- #endif // USE_DOMOTICZ
+#endif // USE_DOMOTICZ
}
}
}
diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino
index 58a804592..dcd8be6a5 100644
--- a/sonoff/xdrv_snfled.ino
+++ b/sonoff/xdrv_snfled.ino
@@ -294,6 +294,7 @@ char* sl_getColor(char* scolor)
void sl_prepPower()
{
char scolor[11];
+ char scommand[16];
if (sysCfg.led_dimmer && !(sl_power)) {
do_cmnd_power(Maxdevice, 7); // No publishPowerState
@@ -305,12 +306,14 @@ void sl_prepPower()
// mqtt_publishDomoticzPowerState(1);
domoticz_updatePowerState(Maxdevice);
#endif // USE_DOMOTICZ
+
+ getPowerDevice(scommand, Maxdevice, sizeof(scommand));
if ((sfl_flg &7) > 1) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_RSLT_POWER "\":\"%s\", \"" D_CMND_DIMMER "\":%d, \"" D_CMND_COLOR "\":\"%s\"}"),
- getStateText(sl_power), sysCfg.led_dimmer, sl_getColor(scolor));
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\", \"" D_CMND_DIMMER "\":%d, \"" D_CMND_COLOR "\":\"%s\"}"),
+ scommand, getStateText(sl_power), sysCfg.led_dimmer, sl_getColor(scolor));
} else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_RSLT_POWER "\":\"%s\", \"" D_CMND_DIMMER "\":%d}"),
- getStateText(sl_power), sysCfg.led_dimmer);
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\", \"" D_CMND_DIMMER "\":%d}"),
+ scommand, getStateText(sl_power), sysCfg.led_dimmer);
}
}
diff --git a/sonoff/xsns_bmp.ino b/sonoff/xsns_bmp.ino
index 0d5f2830d..e1bcd7ac8 100644
--- a/sonoff/xsns_bmp.ino
+++ b/sonoff/xsns_bmp.ino
@@ -25,42 +25,41 @@
* Source: Heiko Krupp and Adafruit Industries
\*********************************************************************************************/
-#define BMP_ADDR 0x77
+#define BMP_ADDR 0x77
-#define BMP180_CHIPID 0x55
-#define BMP280_CHIPID 0x58
-#define BME280_CHIPID 0x60
+#define BMP180_CHIPID 0x55
+#define BMP280_CHIPID 0x58
+#define BME280_CHIPID 0x60
-#define BMP_REGISTER_CHIPID 0xD0
+#define BMP_REGISTER_CHIPID 0xD0
+double bmp_sealevel = 0.0;
uint8_t bmpaddr;
uint8_t bmptype = 0;
char bmpstype[7];
/*********************************************************************************************\
* BMP085 and BME180
- *
- * Programmer : Heiko Krupp with changes from Theo Arends
\*********************************************************************************************/
-#define BMP180_REG_CONTROL 0xF4
-#define BMP180_REG_RESULT 0xF6
-#define BMP180_TEMPERATURE 0x2E
-#define BMP180_PRESSURE3 0xF4 // Max. oversampling -> OSS = 3
+#define BMP180_REG_CONTROL 0xF4
+#define BMP180_REG_RESULT 0xF6
+#define BMP180_TEMPERATURE 0x2E
+#define BMP180_PRESSURE3 0xF4 // Max. oversampling -> OSS = 3
-#define BMP180_AC1 0xAA
-#define BMP180_AC2 0xAC
-#define BMP180_AC3 0xAE
-#define BMP180_AC4 0xB0
-#define BMP180_AC5 0xB2
-#define BMP180_AC6 0xB4
-#define BMP180_VB1 0xB6
-#define BMP180_VB2 0xB8
-#define BMP180_MB 0xBA
-#define BMP180_MC 0xBC
-#define BMP180_MD 0xBE
+#define BMP180_AC1 0xAA
+#define BMP180_AC2 0xAC
+#define BMP180_AC3 0xAE
+#define BMP180_AC4 0xB0
+#define BMP180_AC5 0xB2
+#define BMP180_AC6 0xB4
+#define BMP180_VB1 0xB6
+#define BMP180_VB2 0xB8
+#define BMP180_MB 0xBA
+#define BMP180_MC 0xBC
+#define BMP180_MD 0xBE
-#define BMP180_OSS 3
+#define BMP180_OSS 3
int16_t cal_ac1;
int16_t cal_ac2;
@@ -82,29 +81,28 @@ boolean bmp180_calibration()
cal_ac4 = i2c_read16(bmpaddr, BMP180_AC4);
cal_ac5 = i2c_read16(bmpaddr, BMP180_AC5);
cal_ac6 = i2c_read16(bmpaddr, BMP180_AC6);
- cal_b1 = i2c_read16(bmpaddr, BMP180_VB1);
- cal_b2 = i2c_read16(bmpaddr, BMP180_VB2);
- cal_mc = i2c_read16(bmpaddr, BMP180_MC);
- cal_md = i2c_read16(bmpaddr, BMP180_MD);
+ cal_b1 = i2c_read16(bmpaddr, BMP180_VB1);
+ cal_b2 = i2c_read16(bmpaddr, BMP180_VB2);
+ cal_mc = i2c_read16(bmpaddr, BMP180_MC);
+ cal_md = i2c_read16(bmpaddr, 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) {
return false;
}
- if ((cal_ac1 == 0xFFFF)|
- (cal_ac2 == 0xFFFF)|
- (cal_ac3 == 0xFFFF)|
- (cal_ac4 == 0xFFFF)|
- (cal_ac5 == 0xFFFF)|
- (cal_ac6 == 0xFFFF)|
- (cal_b1 == 0xFFFF)|
- (cal_b2 == 0xFFFF)|
- (cal_mc == 0xFFFF)|
+ if ((cal_ac1 == 0xFFFF) |
+ (cal_ac2 == 0xFFFF) |
+ (cal_ac3 == 0xFFFF) |
+ (cal_ac4 == 0xFFFF) |
+ (cal_ac5 == 0xFFFF) |
+ (cal_ac6 == 0xFFFF) |
+ (cal_b1 == 0xFFFF) |
+ (cal_b2 == 0xFFFF) |
+ (cal_mc == 0xFFFF) |
(cal_md == 0xFFFF)) {
return false;
}
-
return true;
}
@@ -114,10 +112,10 @@ double bmp180_readTemperature()
delay(5); // 5ms conversion time
int ut = i2c_read16(bmpaddr, 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;
+ int32_t x2 = ((int32_t)cal_mc << 11) / (x1 + (int32_t)cal_md);
+ bmp180_b5 = x1 + x2;
- return ((bmp180_b5+8)>>4)/10.0;
+ return ((bmp180_b5 + 8) >> 4) / 10.0;
}
double bmp180_readPressure()
@@ -128,25 +126,26 @@ double bmp180_readPressure()
uint8_t xlsb;
i2c_write8(bmpaddr, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution
- delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
+ delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution
uint32_t up = i2c_read24(bmpaddr, BMP180_REG_RESULT);
up >>= (8 - BMP180_OSS);
int32_t b6 = bmp180_b5 - 4000;
- int32_t x1 = ((int32_t)cal_b2 * ( (b6 * b6)>>12 )) >> 11;
+ int32_t x1 = ((int32_t)cal_b2 * ((b6 * b6) >> 12)) >> 11;
int32_t x2 = ((int32_t)cal_ac2 * b6) >> 11;
int32_t x3 = x1 + x2;
- int32_t b3 = ((((int32_t)cal_ac1*4 + x3) << BMP180_OSS) + 2)>>2;
+ int32_t b3 = ((((int32_t)cal_ac1 * 4 + x3) << BMP180_OSS) + 2) >> 2;
x1 = ((int32_t)cal_ac3 * b6) >> 13;
x2 = ((int32_t)cal_b1 * ((b6 * b6) >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
uint32_t b4 = ((uint32_t)cal_ac4 * (uint32_t)(x3 + 32768)) >> 15;
- uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)( 50000UL >> BMP180_OSS);
+ uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)(50000UL >> BMP180_OSS);
if (b7 < 0x80000000) {
p = (b7 * 2) / b4;
- } else {
+ }
+ else {
p = (b7 / b4) * 2;
}
@@ -154,14 +153,14 @@ double bmp180_readPressure()
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
- p += ((x1 + x2 + (int32_t)3791)>>4);
- return p/100.0; // convert to mbar
+ p += ((x1 + x2 + (int32_t)3791) >> 4);
+ return p / 100.0; // convert to mbar
}
double bmp180_calcSealevelPressure(float pAbs, float altitude_meters)
{
- double pressure = pAbs*100.0;
- return (double)(pressure / pow(1.0-altitude_meters/44330, 5.255))/100.0;
+ double pressure = pAbs * 100.0;
+ return (double)(pressure / pow(1.0 - altitude_meters / 44330, 5.255)) / 100.0;
}
/*********************************************************************************************\
@@ -170,58 +169,58 @@ double bmp180_calcSealevelPressure(float pAbs, float altitude_meters)
* Programmer : BMP280/BME280 Datasheet and Adafruit with changes by Theo Arends
\*********************************************************************************************/
-#define BME280_REGISTER_CONTROLHUMID 0xF2
-#define BME280_REGISTER_CONTROL 0xF4
-#define BME280_REGISTER_PRESSUREDATA 0xF7
-#define BME280_REGISTER_TEMPDATA 0xFA
-#define BME280_REGISTER_HUMIDDATA 0xFD
+#define BME280_REGISTER_CONTROLHUMID 0xF2
+#define BME280_REGISTER_CONTROL 0xF4
+#define BME280_REGISTER_PRESSUREDATA 0xF7
+#define BME280_REGISTER_TEMPDATA 0xFA
+#define BME280_REGISTER_HUMIDDATA 0xFD
-#define BME280_REGISTER_DIG_T1 0x88
-#define BME280_REGISTER_DIG_T2 0x8A
-#define BME280_REGISTER_DIG_T3 0x8C
-#define BME280_REGISTER_DIG_P1 0x8E
-#define BME280_REGISTER_DIG_P2 0x90
-#define BME280_REGISTER_DIG_P3 0x92
-#define BME280_REGISTER_DIG_P4 0x94
-#define BME280_REGISTER_DIG_P5 0x96
-#define BME280_REGISTER_DIG_P6 0x98
-#define BME280_REGISTER_DIG_P7 0x9A
-#define BME280_REGISTER_DIG_P8 0x9C
-#define BME280_REGISTER_DIG_P9 0x9E
-#define BME280_REGISTER_DIG_H1 0xA1
-#define BME280_REGISTER_DIG_H2 0xE1
-#define BME280_REGISTER_DIG_H3 0xE3
-#define BME280_REGISTER_DIG_H4 0xE4
-#define BME280_REGISTER_DIG_H5 0xE5
-#define BME280_REGISTER_DIG_H6 0xE7
+#define BME280_REGISTER_DIG_T1 0x88
+#define BME280_REGISTER_DIG_T2 0x8A
+#define BME280_REGISTER_DIG_T3 0x8C
+#define BME280_REGISTER_DIG_P1 0x8E
+#define BME280_REGISTER_DIG_P2 0x90
+#define BME280_REGISTER_DIG_P3 0x92
+#define BME280_REGISTER_DIG_P4 0x94
+#define BME280_REGISTER_DIG_P5 0x96
+#define BME280_REGISTER_DIG_P6 0x98
+#define BME280_REGISTER_DIG_P7 0x9A
+#define BME280_REGISTER_DIG_P8 0x9C
+#define BME280_REGISTER_DIG_P9 0x9E
+#define BME280_REGISTER_DIG_H1 0xA1
+#define BME280_REGISTER_DIG_H2 0xE1
+#define BME280_REGISTER_DIG_H3 0xE3
+#define BME280_REGISTER_DIG_H4 0xE4
+#define BME280_REGISTER_DIG_H5 0xE5
+#define BME280_REGISTER_DIG_H6 0xE7
struct bme280_calib_data
{
uint16_t dig_T1;
- int16_t dig_T2;
- int16_t dig_T3;
+ int16_t dig_T2;
+ int16_t dig_T3;
uint16_t dig_P1;
- int16_t dig_P2;
- int16_t dig_P3;
- int16_t dig_P4;
- int16_t dig_P5;
- int16_t dig_P6;
- int16_t dig_P7;
- int16_t dig_P8;
- int16_t dig_P9;
- uint8_t dig_H1;
- int16_t dig_H2;
- uint8_t dig_H3;
- int16_t dig_H4;
- int16_t dig_H5;
- int8_t dig_H6;
+ int16_t dig_P2;
+ int16_t dig_P3;
+ int16_t dig_P4;
+ int16_t dig_P5;
+ int16_t dig_P6;
+ int16_t dig_P7;
+ int16_t dig_P8;
+ int16_t dig_P9;
+ uint8_t dig_H1;
+ int16_t dig_H2;
+ uint8_t dig_H3;
+ int16_t dig_H4;
+ int16_t dig_H5;
+ int8_t dig_H6;
} _bme280_calib;
int32_t t_fine;
boolean bmp280_calibrate()
{
-// if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BMP280_CHIPID) return false;
+ // if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BMP280_CHIPID) return false;
_bme280_calib.dig_T1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_T1);
_bme280_calib.dig_T2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T2);
@@ -236,15 +235,15 @@ boolean bmp280_calibrate()
_bme280_calib.dig_P8 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P8);
_bme280_calib.dig_P9 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_P9);
-// i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0x3F); // Temp 1x oversampling, Press 16x oversampling, normal mode (Adafruit)
- i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
+ // i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0x3F); // Temp 1x oversampling, Press 16x oversampling, normal mode (Adafruit)
+ i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
return true;
}
boolean bme280_calibrate()
{
-// if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false;
+ // if (i2c_read8(bmpaddr, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false;
_bme280_calib.dig_T1 = i2c_read16_LE(bmpaddr, BME280_REGISTER_DIG_T1);
_bme280_calib.dig_T2 = i2c_readS16_LE(bmpaddr, BME280_REGISTER_DIG_T2);
@@ -266,8 +265,8 @@ boolean bme280_calibrate()
_bme280_calib.dig_H6 = (int8_t)i2c_read8(bmpaddr, BME280_REGISTER_DIG_H6);
// Set before CONTROL_meas (DS 5.4.3)
- i2c_write8(bmpaddr, BME280_REGISTER_CONTROLHUMID, 0x05); // 16x oversampling (Adafruit)
- i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
+ i2c_write8(bmpaddr, BME280_REGISTER_CONTROLHUMID, 0x05); // 16x oversampling (Adafruit)
+ i2c_write8(bmpaddr, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit)
return true;
}
@@ -280,11 +279,12 @@ double bmp280_readTemperature(void)
int32_t adc_T = i2c_read24(bmpaddr, BME280_REGISTER_TEMPDATA);
adc_T >>= 4;
- var1 = ((((adc_T>>3) - ((int32_t)_bme280_calib.dig_T1 <<1))) * ((int32_t)_bme280_calib.dig_T2)) >> 11;
- var2 = (((((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1)) * ((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) *
- ((int32_t)_bme280_calib.dig_T3)) >> 14;
+ var1 = ((((adc_T >> 3) - ((int32_t)_bme280_calib.dig_T1 << 1))) * ((int32_t)_bme280_calib.dig_T2)) >> 11;
+ var2 = (((((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1)) * ((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) *
+ ((int32_t)_bme280_calib.dig_T3)) >>
+ 14;
t_fine = var1 + var2;
- double T = (t_fine * 5 + 128) >> 8;
+ double T = (t_fine * 5 + 128) >> 8;
return T / 100.0;
}
@@ -294,8 +294,8 @@ double bmp280_readPressure(void)
int64_t var2;
int64_t p;
-// Must be done first to get the t_fine variable set up
-// bmp280_readTemperature();
+ // Must be done first to get the t_fine variable set up
+ // bmp280_readTemperature();
int32_t adc_P = i2c_read24(bmpaddr, BME280_REGISTER_PRESSUREDATA);
adc_P >>= 4;
@@ -307,7 +307,7 @@ double bmp280_readPressure(void)
var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) >> 8) + ((var1 * (int64_t)_bme280_calib.dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)_bme280_calib.dig_P1) >> 33;
if (0 == var1) {
- return 0; // avoid exception caused by division by zero
+ return 0; // avoid exception caused by division by zero
}
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
@@ -321,35 +321,67 @@ double bme280_readHumidity(void)
{
int32_t v_x1_u32r;
-// Must be done first to get the t_fine variable set up
-// bmp280_readTemperature();
+ // Must be done first to get the t_fine variable set up
+ // bmp280_readTemperature();
int32_t adc_H = i2c_read16(bmpaddr, BME280_REGISTER_HUMIDDATA);
v_x1_u32r = (t_fine - ((int32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) -
- (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
- (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) *
- (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
- ((int32_t)2097152)) * ((int32_t)_bme280_calib.dig_H2) + 8192) >> 14));
+ (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) +
+ ((int32_t)16384)) >>
+ 15) *
+ (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) *
+ (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >>
+ 10) +
+ ((int32_t)2097152)) *
+ ((int32_t)_bme280_calib.dig_H2) +
+ 8192) >>
+ 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
- ((int32_t)_bme280_calib.dig_H1)) >> 4));
+ ((int32_t)_bme280_calib.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;
+ return h / 1024.0;
}
/*********************************************************************************************\
* BMP
\*********************************************************************************************/
+double fastPrecisePow(double a, double b)
+{
+ // https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
+ // calculate approximation with fraction of the exponent
+ int e = (int)b;
+ union {
+ double d;
+ int x[2];
+ } u = { a };
+ u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
+ u.x[0] = 0;
+ // exponentiation by squaring with the exponent's integer part
+ // double r = u.d makes everything much slower, not sure why
+ double r = 1.0;
+ while (e) {
+ if (e & 1) {
+ r *= a;
+ }
+ a *= a;
+ e >>= 1;
+ }
+ return r * u.d;
+}
+
double bmp_readTemperature(void)
{
double t = NAN;
- switch (bmptype) {
+ switch (bmptype)
+ {
case BMP180_CHIPID:
t = bmp180_readTemperature();
break;
@@ -357,7 +389,8 @@ double bmp_readTemperature(void)
case BME280_CHIPID:
t = bmp280_readTemperature();
}
- if (!isnan(t)) {
+ if (!isnan(t))
+ {
t = convertTemp(t);
return t;
}
@@ -366,14 +399,20 @@ double bmp_readTemperature(void)
double bmp_readPressure(void)
{
+ double pressure = 0.0;
+
switch (bmptype) {
case BMP180_CHIPID:
- return bmp180_readPressure();
+ pressure = bmp180_readPressure();
case BMP280_CHIPID:
case BME280_CHIPID:
- return bmp280_readPressure();
+ pressure = bmp280_readPressure();
}
- return 0;
+ if (pressure != 0.0) {
+// bmp_sealevel = pressure / pow(1.0 - ((float)sysCfg.altitude / 44330.0), 5.255); // Adds 8k to the code
+ bmp_sealevel = (pressure / fastPrecisePow(1.0 - ((float)sysCfg.altitude / 44330.0), 5.255)) - 21.6;
+ }
+ return pressure;
}
double bmp_readHumidity(void)
@@ -419,7 +458,8 @@ boolean bmp_detect()
if (success) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "%s " D_FOUND_AT " 0x%x"), bmpstype, bmpaddr);
addLog(LOG_LEVEL_DEBUG);
- } else {
+ }
+ else {
bmptype = 0;
}
return success;
@@ -429,7 +469,7 @@ boolean bmp_detect()
* Presentation
\*********************************************************************************************/
-void bmp_mqttPresent(uint8_t* djson)
+void bmp_mqttPresent(uint8_t *djson)
{
if (!bmptype) {
return;
@@ -438,6 +478,8 @@ void bmp_mqttPresent(uint8_t* djson)
char stemp1[10];
char stemp2[10];
char stemp3[10];
+ char stemp4[10];
+ char sealevel[40];
double t = bmp_readTemperature();
double p = bmp_readPressure();
@@ -445,17 +487,21 @@ void bmp_mqttPresent(uint8_t* djson)
dtostrfd(t, sysCfg.flag.temperature_resolution, stemp1);
dtostrfd(p, sysCfg.flag.pressure_resolution, stemp2);
dtostrfd(h, sysCfg.flag.humidity_resolution, stemp3);
- if (!strcmp(bmpstype,"BME280")) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_HUMIDITY "\":%s, \"" D_PRESSURE "\":%s}"),
- mqtt_data, bmpstype, stemp1, stemp3, stemp2);
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_PRESSURE "\":%s}"),
- mqtt_data, bmpstype, stemp1, stemp2);
+
+ dtostrfd(bmp_sealevel, sysCfg.flag.pressure_resolution, stemp4);
+ snprintf_P(sealevel, sizeof(sealevel), PSTR(", \"" D_PRESSUREATSEALEVEL "\":%s"), stemp4);
+ if (!strcmp(bmpstype, "BME280")) {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_HUMIDITY "\":%s, \"" D_PRESSURE "\":%s%s}"),
+ mqtt_data, bmpstype, stemp1, stemp3, stemp2, (sysCfg.altitude != 0) ? sealevel : "");
+ }
+ else {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_PRESSURE "\":%s%s}"),
+ mqtt_data, bmpstype, stemp1, stemp2, (sysCfg.altitude != 0) ? sealevel : "");
}
*djson = 1;
#ifdef USE_DOMOTICZ
domoticz_sensor3(stemp1, stemp3, stemp2);
-#endif // USE_DOMOTICZ
+#endif // USE_DOMOTICZ
}
#ifdef USE_WEBSERVER
@@ -472,7 +518,7 @@ String bmp_webPresent()
dtostrfi(t_bmp, sysCfg.flag.temperature_resolution, stemp);
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, bmpstype, stemp, tempUnit());
page += sensor;
- if (!strcmp(bmpstype,"BME280")) {
+ if (!strcmp(bmpstype, "BME280")) {
dtostrfi(h_bmp, sysCfg.flag.humidity_resolution, stemp);
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_HUM, bmpstype, stemp);
page += sensor;
@@ -480,10 +526,14 @@ String bmp_webPresent()
dtostrfi(p_bmp, sysCfg.flag.pressure_resolution, stemp);
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_PRESSURE, bmpstype, stemp);
page += sensor;
+ if (sysCfg.altitude != 0) {
+ dtostrfi(bmp_sealevel, sysCfg.flag.pressure_resolution, stemp);
+ snprintf_P(sensor, sizeof(sensor), HTTP_SNS_PRESSUREATSEALEVEL, bmpstype, stemp);
+ page += sensor;
+ }
}
return page;
}
-#endif // USE_WEBSERVER
-#endif // USE_BMP
-#endif // USE_I2C
-
+#endif // USE_WEBSERVER
+#endif // USE_BMP
+#endif // USE_I2C