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