diff --git a/README.md b/README.md index 1d3c365bb..716cda074 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.9.1a** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. +Current version is **5.9.1b** - 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 ccd0e8d18..dffc8a805 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,8 @@ -/* 5.9.1a +/* 5.9.1b + * Remove spaces in JSON messages + * Add support for INA219 Voltage and Current sensor to be enabled in user_config.h + * + * 5.9.1a * Fix PWM watchdog timeout if Dimmer is set to 100 or Color set to 0xFF (#1146) * * 5.9.1 20171107 diff --git a/sonoff/i18n.h b/sonoff/i18n.h index ff4cdc0e1..f7bebbbf8 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -77,7 +77,7 @@ const char S_JSON_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"%s%d\":%d}"; const char S_JSON_COMMAND_INDEX_SVALUE[] PROGMEM = "{\"%s%d\":\"%s\"}"; const char S_JSON_COMMAND_INDEX_SVALUE_SVALUE[] PROGMEM = "{\"%s%d\":\"%s%s\"}"; -const char JSON_SNS_TEMPHUM[] PROGMEM = "%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_HUMIDITY "\":%s}"; +const char JSON_SNS_TEMPHUM[] PROGMEM = "%s,\"%s\":{\"" D_TEMPERATURE "\":%s,\"" D_HUMIDITY "\":%s}"; const char S_LOG_I2C_FOUND_AT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x"; diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 2dffab394..b249bf1f7 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -573,6 +573,7 @@ #define D_CMND_PRESSURE_RESOLUTION "PressRes" #define D_CMND_POWER_RESOLUTION "WattRes" #define D_CMND_VOLTAGE_RESOLUTION "VoltRes" +#define D_CMND_CURRENT_RESOLUTION "AmpRes" #define D_CMND_ENERGY_RESOLUTION "EnergyRes" #define D_CMND_MODULE "Module" #define D_CMND_MODULES "Modules" @@ -629,6 +630,7 @@ #define D_CMND_LEDSTATE "LedState" #define D_CMND_CFGDUMP "CfgDump" #define D_CMND_I2CSCAN "I2CScan" +#define D_CMND_INA219MODE "Ina219Mode" #define D_CMND_EXCEPTION "Exception" // Commands xdrv_domoticz.ino diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 695ac4301..35116fd04 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -573,6 +573,7 @@ #define D_CMND_PRESSURE_RESOLUTION "PressRes" #define D_CMND_POWER_RESOLUTION "WattRes" #define D_CMND_VOLTAGE_RESOLUTION "VoltRes" +#define D_CMND_CURRENT_RESOLUTION "AmpRes" #define D_CMND_ENERGY_RESOLUTION "EnergyRes" #define D_CMND_MODULE "Module" #define D_CMND_MODULES "Modules" @@ -629,6 +630,7 @@ #define D_CMND_LEDSTATE "LedState" #define D_CMND_CFGDUMP "CfgDump" #define D_CMND_I2CSCAN "I2CScan" +#define D_CMND_INA219MODE "Ina219Mode" #define D_CMND_EXCEPTION "Exception" // Commands xdrv_domoticz.ino diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 03e925839..09679d660 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -573,6 +573,7 @@ #define D_CMND_PRESSURE_RESOLUTION "PressRes" #define D_CMND_POWER_RESOLUTION "WattRes" #define D_CMND_VOLTAGE_RESOLUTION "VoltRes" +#define D_CMND_CURRENT_RESOLUTION "AmpRes" #define D_CMND_ENERGY_RESOLUTION "EnergyRes" #define D_CMND_MODULE "Module" #define D_CMND_MODULES "Modules" @@ -629,6 +630,7 @@ #define D_CMND_LEDSTATE "LedState" #define D_CMND_CFGDUMP "CfgDump" #define D_CMND_I2CSCAN "I2CScan" +#define D_CMND_INA219MODE "Ina219Mode" #define D_CMND_EXCEPTION "Exception" // Commands xdrv_domoticz.ino diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index f37ccfaa7..542f49a6d 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -573,6 +573,7 @@ #define D_CMND_PRESSURE_RESOLUTION "PressRes" #define D_CMND_POWER_RESOLUTION "WattRes" #define D_CMND_VOLTAGE_RESOLUTION "VoltRes" +#define D_CMND_CURRENT_RESOLUTION "AmpRes" #define D_CMND_ENERGY_RESOLUTION "EnergyRes" #define D_CMND_MODULE "Module" #define D_CMND_MODULES "Modules" @@ -629,6 +630,7 @@ #define D_CMND_LEDSTATE "LedState" #define D_CMND_CFGDUMP "CfgDump" #define D_CMND_I2CSCAN "I2CScan" +#define D_CMND_INA219MODE "Ina219Mode" #define D_CMND_EXCEPTION "Exception" // Commands xdrv_domoticz.ino diff --git a/sonoff/settings.h b/sonoff/settings.h index e71a8fee5..3f4cfe525 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -44,6 +44,20 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) uint32_t decimal_text : 1; // bit 17 (v5.8.1) uint32_t spare18 : 1; + uint32_t spare19 : 1; + uint32_t voltage_resolution : 1; + uint32_t spare21 : 1; + uint32_t spare22 : 1; + uint32_t spare23 : 1; + uint32_t spare24 : 1; + uint32_t spare25 : 1; + uint32_t spare26 : 1; + uint32_t spare27 : 1; + uint32_t spare28 : 1; + uint32_t spare29 : 1; + uint32_t spare30 : 1; + uint32_t spare31 : 1; + /* uint32_t wattage_resolution : 1; uint32_t voltage_resolution : 1; uint32_t emulation : 2; @@ -51,9 +65,39 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t pressure_resolution : 2; uint32_t humidity_resolution : 2; uint32_t temperature_resolution : 2; +*/ }; } SysBitfield; +typedef union { + uint32_t data; // Allow bit manipulation using SetOption + struct { + uint32_t spare00 : 1; + uint32_t spare01 : 1; + uint32_t spare02 : 1; + uint32_t spare03 : 1; + uint32_t spare04 : 1; + uint32_t spare05 : 1; + uint32_t spare06 : 1; + uint32_t spare07 : 1; + uint32_t spare08 : 1; + uint32_t spare09 : 1; + uint32_t spare10 : 1; + uint32_t spare11 : 1; + uint32_t spare12 : 1; + uint32_t spare13 : 1; + uint32_t spare14 : 1; + uint32_t current_resolution : 2; + uint32_t voltage_resolution : 2; + uint32_t wattage_resolution : 2; + uint32_t emulation : 2; + uint32_t energy_resolution : 3; + uint32_t pressure_resolution : 2; + uint32_t humidity_resolution : 2; + uint32_t temperature_resolution : 2; + }; +} SysBitfield2; + struct SYSCFG { unsigned long cfg_holder; // 000 unsigned long save_flag; // 004 @@ -188,7 +232,7 @@ struct SYSCFG { uint8_t switchmode[MAX_SWITCHES]; // 4CA char ntp_server[3][33]; // 4CE - byte free_531[1]; // 531 + byte ina219_mode; // 531 uint16_t pulse_timer[MAX_PULSETIMERS]; // 532 @@ -196,9 +240,9 @@ struct SYSCFG { uint32_t ip_address[4]; // 544 unsigned long hlw_kWhtotal; // 554 - char mqtt_fulltopic[101]; // 558 + char mqtt_fulltopic[100]; // 558 - byte free_5BD[3]; // 5BD + SysBitfield2 flag2; // 5BC Add flag2 since 5.9.2 unsigned long pulse_counter[MAX_COUNTERS]; // 5C0 uint16_t pulse_counter_type; // 5D0 diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 3c0607873..848c3d1f7 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -391,7 +391,7 @@ void SettingsDefaultSet2() Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN; Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN; - Settings.flag.emulation = EMULATION; + Settings.flag2.emulation = EMULATION; Settings.save_data = SAVE_DATA; Settings.timezone = APP_TIMEZONE; @@ -513,6 +513,9 @@ void SettingsDefaultSet2() Settings.pwm_frequency = PWM_FREQ; Settings.pwm_range = PWM_RANGE; SettingsDefaultSet_5_8_1(); + + // 5.9.2 + Settings.flag2.current_resolution = 3; } /********************************************************************************************/ @@ -599,10 +602,10 @@ void SettingsDefaultSet_4_1_1() void SettingsDefaultSet_5_0_2() { Settings.flag.temperature_conversion = TEMP_CONVERSION; - Settings.flag.temperature_resolution = TEMP_RESOLUTION; - Settings.flag.humidity_resolution = HUMIDITY_RESOLUTION; - Settings.flag.pressure_resolution = PRESSURE_RESOLUTION; - Settings.flag.energy_resolution = ENERGY_RESOLUTION; + Settings.flag2.temperature_resolution = TEMP_RESOLUTION; + Settings.flag2.humidity_resolution = HUMIDITY_RESOLUTION; + Settings.flag2.pressure_resolution = PRESSURE_RESOLUTION; + Settings.flag2.energy_resolution = ENERGY_RESOLUTION; } void SettingsDefaultSet_5_8_1() @@ -688,7 +691,7 @@ void SettingsDelta() // Settings.flag.mqtt_power_retain = 0; // Settings.flag.mqtt_button_retain = 0; Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN; - Settings.flag.emulation = EMULATION; + Settings.flag2.emulation = EMULATION; SettingsDefaultSet_5_0_2(); @@ -773,6 +776,13 @@ void SettingsDelta() if (Settings.version < 0x0508000E) { SettingsDefaultSet_5_8_1(); } + if (Settings.version < 0x05090102) { + Settings.flag2.data = Settings.flag.data; + Settings.flag2.data &= 0xFFE80000; + Settings.flag2.voltage_resolution = Settings.flag.voltage_resolution; + Settings.flag2.current_resolution = 3; + Settings.ina219_mode = 0; + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 11fb88901..70aed3b2a 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05090101 // 5.9.1a +#define VERSION 0x05090102 // 5.9.1b // Location specific includes #include "sonoff.h" // Enumaration used in user_config.h @@ -67,23 +67,23 @@ enum TasmotaCommands { CMND_BACKLOG, CMND_DELAY, CMND_POWER, CMND_STATUS, CMND_POWERONSTATE, CMND_PULSETIME, CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION, - CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_MODULE, CMND_MODULES, + CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE, CMND_COUNTERDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG, CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME, CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_EMULATION, CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE, - CMND_CFGDUMP, CMND_I2CSCAN, CMND_EXCEPTION }; + CMND_CFGDUMP, CMND_I2CSCAN, CMND_INA219MODE, CMND_EXCEPTION }; const char kTasmotaCommands[] PROGMEM = D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|" - D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_MODULE "|" D_CMND_MODULES "|" + D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|" D_CMND_COUNTERDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_EMULATION "|" D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" - D_CMND_CFGDUMP "|" D_CMND_I2CSCAN + D_CMND_CFGDUMP "|" D_CMND_I2CSCAN "|" D_CMND_INA219MODE #ifdef DEBUG_THEO "|" D_CMND_EXCEPTION #endif @@ -419,7 +419,7 @@ void MqttPublishPowerState(byte device) } GetPowerDevice(scommand, device, sizeof(scommand)); GetTopic_P(stopic, 1, Settings.mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\"}"), scommand, GetStateText(bitRead(power, device -1))); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1))); MqttPublish(stopic); GetTopic_P(stopic, 1, Settings.mqtt_topic, scommand); @@ -466,12 +466,12 @@ void MqttConnected() } if (mqtt_connection_flag) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULE "\":\"%s\", \"" D_VERSION "\":\"%s\", \"" D_FALLBACKTOPIC "\":\"%s\", \"" D_CMND_GROUPTOPIC "\":\"%s\"}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_VERSION "\":\"%s\",\"" D_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"), my_module.name, version, mqtt_client, Settings.mqtt_grptopic); MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_INFO "1")); #ifdef USE_WEBSERVER if (Settings.webserver) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_WEBSERVER_MODE "\":\"%s\", \"" D_CMND_HOSTNAME "\":\"%s\", \"" D_CMND_IPADDRESS "\":\"%s\"}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"), (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str()); MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_INFO "2")); } @@ -1044,39 +1044,45 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) } else if (CMND_TEMPERATURE_RESOLUTION == command_code) { if ((payload >= 0) && (payload <= 3)) { - Settings.flag.temperature_resolution = payload; + Settings.flag2.temperature_resolution = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.temperature_resolution); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.temperature_resolution); } else if (CMND_HUMIDITY_RESOLUTION == command_code) { if ((payload >= 0) && (payload <= 3)) { - Settings.flag.humidity_resolution = payload; + Settings.flag2.humidity_resolution = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.humidity_resolution); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.humidity_resolution); } else if (CMND_PRESSURE_RESOLUTION == command_code) { if ((payload >= 0) && (payload <= 3)) { - Settings.flag.pressure_resolution = payload; + Settings.flag2.pressure_resolution = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.pressure_resolution); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.pressure_resolution); } else if (CMND_POWER_RESOLUTION == command_code) { - if ((payload >= 0) && (payload <= 1)) { - Settings.flag.wattage_resolution = payload; + if ((payload >= 0) && (payload <= 3)) { + Settings.flag2.wattage_resolution = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.wattage_resolution); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.wattage_resolution); } else if (CMND_VOLTAGE_RESOLUTION == command_code) { - if ((payload >= 0) && (payload <= 1)) { - Settings.flag.voltage_resolution = payload; + if ((payload >= 0) && (payload <= 3)) { + Settings.flag2.voltage_resolution = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.voltage_resolution); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.voltage_resolution); + } + else if (CMND_CURRENT_RESOLUTION == command_code) { + if ((payload >= 0) && (payload <= 3)) { + Settings.flag2.current_resolution = payload; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.current_resolution); } else if (CMND_ENERGY_RESOLUTION == command_code) { if ((payload >= 0) && (payload <= 5)) { - Settings.flag.energy_resolution = payload; + Settings.flag2.energy_resolution = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.energy_resolution); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.energy_resolution); } else if (CMND_MODULE == command_code) { if ((payload > 0) && (payload <= MAXMODULE)) { @@ -1098,7 +1104,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) if (!jsflg) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULES "%d\":\""), lines); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, "), mqtt_data); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), kModules[i].name); @@ -1129,7 +1135,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) for (byte i = 0; i < MAX_GPIO_PIN; i++) { if (GPIO_USER == cmodule.gp.io[i]) { if (jsflg) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, "), mqtt_data); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), kSensors[Settings.my_gp.io[i]]); @@ -1147,7 +1153,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) if (!jsflg) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_GPIOS "%d\":\""), lines); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, "), mqtt_data); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), kSensors[i]); @@ -1170,7 +1176,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) bool first = true; for (byte i = 0; i < MAX_PWMS; i++) { if(pin[GPIO_PWM1 + i] < 99) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ", ", i+1, Settings.pwm_value[i]); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ",", i+1, Settings.pwm_value[i]); first = false; } } @@ -1254,7 +1260,7 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) else if (CMND_SYSLOG == command_code) { if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) { Settings.syslog_level = payload; - syslog_level = (Settings.flag.emulation) ? 0 : payload; + syslog_level = (Settings.flag2.emulation) ? 0 : payload; syslog_timer = 0; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.syslog_level, syslog_level); @@ -1390,10 +1396,10 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) #ifdef USE_EMULATION else if (CMND_EMULATION == command_code) { if ((payload >= EMUL_NONE) && (payload < EMUL_MAX)) { - Settings.flag.emulation = payload; + Settings.flag2.emulation = payload; restart_flag = 2; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag.emulation); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.emulation); } #endif // USE_EMULATION #endif // USE_WEBSERVER @@ -1477,6 +1483,20 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) SettingsDump(dataBuf); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_DONE); } +#ifdef USE_I2C + else if ((CMND_I2CSCAN == command_code) && i2c_flg) { + I2cScan(mqtt_data, sizeof(mqtt_data)); + } +#endif // USE_I2C +#ifdef USE_INA219 + else if (CMND_INA219MODE == command_code) { + if ((payload >= 0) && (payload <= 2)) { + Settings.ina219_mode = payload; + restart_flag = 2; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.ina219_mode); + } +#endif // USE_INA219 else if (Settings.flag.mqtt_enabled && MqttCommand(grpflg, type, index, dataBuf, data_len, payload, payload16)) { // Serviced } @@ -1486,11 +1506,6 @@ void MqttDataCallback(char* topic, byte* data, unsigned int data_len) else if ((SONOFF_BRIDGE == Settings.module) && SonoffBridgeCommand(type, index, dataBuf, data_len, payload)) { // Serviced } -#ifdef USE_I2C - else if ((CMND_I2CSCAN == command_code) && i2c_flg) { - I2cScan(mqtt_data, sizeof(mqtt_data)); - } -#endif // USE_I2C #ifdef USE_IR_REMOTE else if ((pin[GPIO_IRSEND] < 99) && IrSendCommand(type, index, dataBuf, data_len, payload)) { // Serviced @@ -1697,50 +1712,50 @@ void PublishStatus(uint8_t payload) } if ((0 == payload) || (99 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d, \"" D_CMND_FRIENDLYNAME "\":\"%s\", \"" D_CMND_TOPIC "\":\"%s\", \"" D_CMND_BUTTONTOPIC "\":\"%s\", \"" D_CMND_POWER "\":%d, \"" D_CMND_POWERONSTATE "\":%d, \"" D_CMND_LEDSTATE "\":%d, \"" D_CMND_SAVEDATA "\":%d, \"" D_SAVESTATE "\":%d, \"" D_CMND_BUTTONRETAIN "\":%d, \"" D_CMND_POWERRETAIN "\":%d}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":\"%s\",\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_SAVESTATE "\":%d,\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), Settings.module +1, Settings.friendlyname[0], Settings.mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_power_retain); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS)); } if ((0 == payload) || (1 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_BAUDRATE "\":%d, \"" D_CMND_GROUPTOPIC "\":\"%s\", \"" D_CMND_OTAURL "\":\"%s\", \"" D_UPTIME "\":%d, \"" D_CMND_SLEEP "\":%d, \"" D_BOOTCOUNT "\":%d, \"" D_SAVECOUNT "\":%d, \"" D_SAVEADDRESS "\":\"%X\"}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_BAUDRATE "\":%d,\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\"" D_UPTIME "\":%d,\"" D_CMND_SLEEP "\":%d,\"" D_BOOTCOUNT "\":%d,\"" D_SAVECOUNT "\":%d,\"" D_SAVEADDRESS "\":\"%X\"}}"), baudrate, Settings.mqtt_grptopic, Settings.ota_url, uptime, Settings.sleep, Settings.bootcount, Settings.save_flag, GetSettingsAddress()); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1")); } if ((0 == payload) || (2 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_VERSION "\":\"%s\", \"" D_BUILDDATETIME "\":\"%s\", \"" D_BOOTVERSION "\":%d, \"" D_COREVERSION "\":\"%s\", \"" D_SDKVERSION "\":\"%s\"}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_VERSION "\":\"%s\",\"" D_BUILDDATETIME "\":\"%s\",\"" D_BOOTVERSION "\":%d,\"" D_COREVERSION "\":\"%s\",\"" D_SDKVERSION "\":\"%s\"}}"), version, GetBuildDateAndTime().c_str(), ESP.getBootVersion(), ESP.getCoreVersion().c_str(), ESP.getSdkVersion()); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "2")); } if ((0 == payload) || (3 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d, \"" D_CMND_WEBLOG "\":%d, \"" D_CMND_SYSLOG "\":%d, \"" D_CMND_LOGHOST "\":\"%s\", \"" D_CMND_LOGPORT "\":%d, \"" D_CMND_SSID "1\":\"%s\", \"" D_CMND_SSID "2\":\"%s\", \"" D_CMND_TELEPERIOD "\":%d, \"" D_CMND_SETOPTION "\":\"%08X\"}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "1\":\"%s\",\"" D_CMND_SSID "2\":\"%s\",\"" D_CMND_TELEPERIOD "\":%d,\"" D_CMND_SETOPTION "\":\"%08X\"}}"), Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period, Settings.flag.data); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3")); } if ((0 == payload) || (4 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_PROGRAMSIZE "\":%d, \"" D_FREEMEMORY "\":%d, \"" D_HEAPSIZE "\":%d, \"" D_PROGRAMFLASHSIZE "\":%d, \"" D_FLASHSIZE "\":%d, \"" D_FLASHMODE "\":%d}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_PROGRAMSIZE "\":%d,\"" D_FREEMEMORY "\":%d,\"" D_HEAPSIZE "\":%d,\"" D_PROGRAMFLASHSIZE "\":%d,\"" D_FLASHSIZE "\":%d,\"" D_FLASHMODE "\":%d}}"), ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipMode()); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4")); } if ((0 == payload) || (5 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\", \"" D_CMND_IPADDRESS "\":\"%s\", \"" D_GATEWAY "\":\"%s\", \"" D_SUBNETMASK "\":\"%s\", \"" D_DNSSERVER "\":\"%s\", \"" D_MAC "\":\"%s\", \"" D_CMND_WEBSERVER "\":%d, \"" D_CMND_WIFICONFIG "\":%d}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_GATEWAY "\":\"%s\",\"" D_SUBNETMASK "\":\"%s\",\"" D_DNSSERVER "\":\"%s\",\"" D_MAC "\":\"%s\",\"" D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d}}"), my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(), IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(), Settings.webserver, Settings.sta_config); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5")); } if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\", \"" D_CMND_MQTTPORT "\":%d, \"" D_CMND_MQTTCLIENT D_MASK "\":\"%s\", \"" D_CMND_MQTTCLIENT "\":\"%s\", \"" D_CMND_MQTTUSER "\":\"%s\", \"MAX_PACKET_SIZE\":%d, \"KEEPALIVE\":%d}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"), Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6")); } if ((0 == payload) || (7 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_UTC_TIME "\":\"%s\", \"" D_LOCAL_TIME "\":\"%s\", \"" D_STARTDST "\":\"%s\", \"" D_ENDDST "\":\"%s\", \"" D_CMND_TIMEZONE "\":%d}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_UTC_TIME "\":\"%s\",\"" D_LOCAL_TIME "\":\"%s\",\"" D_STARTDST "\":\"%s\",\"" D_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%d}}"), GetTime(0).c_str(), GetTime(1).c_str(), GetTime(2).c_str(), GetTime(3).c_str(), Settings.timezone); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "7")); } @@ -1752,7 +1767,7 @@ void PublishStatus(uint8_t payload) } if ((0 == payload) || (9 == payload)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERLOW "\":%d, \"" D_CMND_POWERHIGH "\":%d, \"" D_CMND_VOLTAGELOW "\":%d, \"" D_CMND_VOLTAGEHIGH "\":%d, \"" D_CMND_CURRENTLOW "\":%d, \"" D_CMND_CURRENTHIGH "\":%d}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\"" D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"), Settings.hlw_pmin, Settings.hlw_pmax, Settings.hlw_umin, Settings.hlw_umax, Settings.hlw_imin, Settings.hlw_imax); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "9")); } @@ -1778,15 +1793,15 @@ void MqttShowState() { char stemp1[16]; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_TIME "\":\"%s\", \"" D_UPTIME "\":%d"), mqtt_data, GetDateAndTime().c_str(), uptime); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_TIME "\":\"%s\",\"" D_UPTIME "\":%d"), mqtt_data, GetDateAndTime().c_str(), uptime); #ifdef USE_ADC_VCC dtostrfd((double)ESP.getVcc()/1000, 3, stemp1); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_VCC "\":%s"), mqtt_data, stemp1); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_VCC "\":%s"), mqtt_data, stemp1); #endif for (byte i = 0; i < devices_present; i++) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1)), GetStateText(bitRead(power, i))); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1)), GetStateText(bitRead(power, i))); } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_WIFI "\":{\"" D_AP "\":%d, \"" D_SSID "\":\"%s\", \"" D_RSSI "\":%d, \"" D_APMAC_ADDRESS "\":\"%s\"}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_WIFI "\":{\"" D_AP "\":%d,\"" D_SSID "\":\"%s\",\"" D_RSSI "\":%d,\"" D_APMAC_ADDRESS "\":\"%s\"}}"), mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WifiGetRssiAsQuality(WiFi.RSSI()), WiFi.BSSIDstr().c_str()); } @@ -1797,13 +1812,13 @@ boolean MqttShowSensor() for (byte i = 0; i < MAX_SWITCHES; i++) { if (pin[GPIO_SWT1 +i] < 99) { boolean swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i])); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_SWITCH "%d\":\"%s\""), mqtt_data, i +1, GetStateText(swm ^ lastwallswitch[i])); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_SWITCH "%d\":\"%s\""), mqtt_data, i +1, GetStateText(swm ^ lastwallswitch[i])); } } XsnsCall(FUNC_XSNS_JSON_APPEND); boolean json_data_available = (strlen(mqtt_data) - json_data_start); if (strstr_P(mqtt_data, PSTR(D_TEMPERATURE))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_TEMPERATURE_UNIT "\":\"%c\""), mqtt_data, TempUnit()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_TEMPERATURE_UNIT "\":\"%c\""), mqtt_data, TempUnit()); } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); return json_data_available; @@ -1836,7 +1851,7 @@ void PerformEverySecond() if (syslog_timer) { // Restore syslog level syslog_timer--; if (!syslog_timer) { - syslog_level = (Settings.flag.emulation) ? 0 : Settings.syslog_level; + syslog_level = (Settings.flag2.emulation) ? 0 : Settings.syslog_level; if (Settings.syslog_level) { AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SYSLOG_LOGGING_REENABLED)); // Might trigger disable again (on purpose) } @@ -1884,7 +1899,7 @@ void PerformEverySecond() if ((2 == RtcTime.minute) && latest_uptime_flag) { latest_uptime_flag = false; uptime++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_TIME "\":\"%s\", \"" D_UPTIME "\":%d}"), GetDateAndTime().c_str(), uptime); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_TIME "\":\"%s\",\"" D_UPTIME "\":%d}"), GetDateAndTime().c_str(), uptime); MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_UPTIME)); } if ((3 == RtcTime.minute) && !latest_uptime_flag) { @@ -2611,8 +2626,6 @@ void GpioInit() #endif // USE_IR_REMOTE hlw_flg = ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)); - -// XSnsInit(); } extern "C" { @@ -2642,9 +2655,9 @@ void setup() seriallog_level = Settings.seriallog_level; seriallog_timer = SERIALLOG_TIMER; #ifndef USE_EMULATION - Settings.flag.emulation = 0; + Settings.flag2.emulation = 0; #endif // USE_EMULATION - syslog_level = (Settings.flag.emulation) ? 0 : Settings.syslog_level; + syslog_level = (Settings.flag2.emulation) ? 0 : Settings.syslog_level; stop_flash_rotate = Settings.flag.stop_flash_rotate; save_data_counter = Settings.save_data; sleep = Settings.sleep; @@ -2726,11 +2739,7 @@ void setup() blink_powersave = power; -// if (SONOFF_SC == Settings.module) { -// SonoffScInit(); -// } XSnsInit(); - RtcInit(); snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s (" D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " %s"), @@ -2747,7 +2756,7 @@ void loop() #endif // USE_WEBSERVER #ifdef USE_EMULATION - if (Settings.flag.emulation) { + if (Settings.flag2.emulation) { PollUdp(); } #endif // USE_EMULATION diff --git a/sonoff/support.ino b/sonoff/support.ino index aab885334..6aef28aff 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -629,7 +629,7 @@ void WifiCheck(uint8_t param) StopWebserver(); } #ifdef USE_EMULATION - if (Settings.flag.emulation) { + if (Settings.flag2.emulation) { UdpConnect(); } #endif // USE_EMULATION @@ -756,14 +756,34 @@ int32_t I2cRead24(uint8_t addr, uint8_t reg) { return I2cRead(addr, reg, 3); } +/* +void I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) +{ + byte x = I2C_RETRY_COUNTER; + int32_t data = val; + do { + Wire.beginTransmission((uint8_t)addr); // start transmission to device + Wire.write(reg); // sends register address to read from + + for (byte i = 0; i < size; i++) { + + } + + Wire.write((val >> 8) & 0xFF); // write data + Wire.write(val); // write data + + x--; + } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission +} +*/ void I2cWrite8v(uint8_t addr, uint8_t val) { byte x = I2C_RETRY_COUNTER; do { Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(val); // write data + Wire.write(val); // write data x--; } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission } @@ -774,12 +794,26 @@ void I2cWrite8(uint8_t addr, uint8_t reg, uint8_t val) do { Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(reg); // sends register address to read from - Wire.write(val); // write data + Wire.write(reg); // sends register address to write to + Wire.write(val); // write data x--; } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission } +bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val) +{ + byte x = I2C_RETRY_COUNTER; + + do { + Wire.beginTransmission((uint8_t)addr); // start transmission to device + Wire.write(reg); // sends register address to write to + Wire.write((val >> 8) & 0xFF); // write data + Wire.write(val & 0xFF); // write data + x--; + } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission + return (x); +} + void I2cScan(char *devs, unsigned int devs_len) { byte error; @@ -1249,7 +1283,7 @@ void AdcShow(boolean json) analog >>= 5; if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_ANALOG_INPUT "0\":%d"), mqtt_data, analog); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_ANALOG_INPUT "0\":%d"), mqtt_data, analog); #ifdef USE_WEBSERVER } else { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ANALOG, mqtt_data, "", 0, analog); diff --git a/sonoff/user_config.h b/sonoff/user_config.h index ad8faf8f0..77f482f19 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -172,6 +172,7 @@ #define USE_BH1750 // Add I2C code for BH1750 sensor // #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0.5k code) // #define USE_ADS1115 // Add I2C code for ADS1x15 16 bit A/D converter using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code) + #define USE_INA219 // Add I2C code for INA219 Low voltage and current sensor (+1k code) #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+3k code, 0.3k mem) // #define USE_IR_HVAC // Support for HVAC system using IR (+2k code) diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 6764a9cde..a079153ca 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -332,12 +332,12 @@ void StartWebserver(int type, IPAddress ipweb) WebServer->on("/rb", HandleRestart); WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. #ifdef USE_EMULATION - if (EMUL_WEMO == Settings.flag.emulation) { + if (EMUL_WEMO == Settings.flag2.emulation) { WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); WebServer->on("/eventservice.xml", HandleUpnpService); WebServer->on("/setup.xml", HandleUpnpSetupWemo); } - if (EMUL_HUE == Settings.flag.emulation) { + if (EMUL_HUE == Settings.flag2.emulation) { WebServer->on("/description.xml", HandleUpnpSetupHue); } #endif // USE_EMULATION @@ -890,7 +890,7 @@ void HandleOtherConfiguration() for (byte i = 0; i < EMUL_MAX; i++) { page += FPSTR(HTTP_FORM_OTHER3b); page.replace(F("{1"), String(i)); - page.replace(F("{2"), (i == Settings.flag.emulation) ? F(" checked") : F("")); + page.replace(F("{2"), (i == Settings.flag2.emulation) ? F(" checked") : F("")); page.replace(F("{3"), (i == EMUL_NONE) ? F(D_NONE) : (i == EMUL_WEMO) ? F(D_BELKIN_WEMO) : F(D_HUE_BRIDGE)); page.replace(F("{4"), (i == EMUL_NONE) ? F("") : (i == EMUL_WEMO) ? F(" " D_SINGLE_DEVICE) : F(" " D_MULTI_DEVICE)); } @@ -1015,14 +1015,14 @@ snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D strlcpy(Settings.web_password, (!strlen(WebServer->arg("p1").c_str())) ? WEB_PASSWORD : (!strcmp(WebServer->arg("p1").c_str(),"0")) ? "" : WebServer->arg("p1").c_str(), sizeof(Settings.web_password)); Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); #ifdef USE_EMULATION - Settings.flag.emulation = (!strlen(WebServer->arg("b2").c_str())) ? 0 : atoi(WebServer->arg("b2").c_str()); + Settings.flag2.emulation = (!strlen(WebServer->arg("b2").c_str())) ? 0 : atoi(WebServer->arg("b2").c_str()); #endif // USE_EMULATION strlcpy(Settings.friendlyname[0], (!strlen(WebServer->arg("a1").c_str())) ? FRIENDLY_NAME : WebServer->arg("a1").c_str(), sizeof(Settings.friendlyname[0])); strlcpy(Settings.friendlyname[1], (!strlen(WebServer->arg("a2").c_str())) ? FRIENDLY_NAME"2" : WebServer->arg("a2").c_str(), sizeof(Settings.friendlyname[1])); strlcpy(Settings.friendlyname[2], (!strlen(WebServer->arg("a3").c_str())) ? FRIENDLY_NAME"3" : WebServer->arg("a3").c_str(), sizeof(Settings.friendlyname[2])); strlcpy(Settings.friendlyname[3], (!strlen(WebServer->arg("a4").c_str())) ? FRIENDLY_NAME"4" : WebServer->arg("a4").c_str(), sizeof(Settings.friendlyname[3])); snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME " %s, %s, %s, %s"), - GetStateText(Settings.flag.mqtt_enabled), Settings.flag.emulation, Settings.friendlyname[0], Settings.friendlyname[1], Settings.friendlyname[2], Settings.friendlyname[3]); + GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation, Settings.friendlyname[0], Settings.friendlyname[1], Settings.friendlyname[2], Settings.friendlyname[3]); AddLog(LOG_LEVEL_INFO); break; case 6: @@ -1522,10 +1522,10 @@ void HandleInformation() func += F("}1}2 "); // Empty line func += F("}1" D_EMULATION "}2"); #ifdef USE_EMULATION - if (EMUL_WEMO == Settings.flag.emulation) { + if (EMUL_WEMO == Settings.flag2.emulation) { func += F(D_BELKIN_WEMO); } - else if (EMUL_HUE == Settings.flag.emulation) { + else if (EMUL_HUE == Settings.flag2.emulation) { func += F(D_HUE_BRIDGE); } else { @@ -1596,7 +1596,7 @@ void HandleNotFound() #ifdef USE_EMULATION String path = WebServer->uri(); - if ((EMUL_HUE == Settings.flag.emulation) && (path.startsWith("/api"))) { + if ((EMUL_HUE == Settings.flag2.emulation) && (path.startsWith("/api"))) { HandleHueApi(&path); } else #endif // USE_EMULATION diff --git a/sonoff/xdrv_domoticz.ino b/sonoff/xdrv_domoticz.ino index f66683f02..1a0a1c0ac 100644 --- a/sonoff/xdrv_domoticz.ino +++ b/sonoff/xdrv_domoticz.ino @@ -45,6 +45,8 @@ enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, D const char kDomoticzSensors[] PROGMEM = D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|" D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT ; +const char S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DOMOTICZ "%s%d\":%d}"; + char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; char domoticz_out_topic[] = DOMOTICZ_OUT_TOPIC; @@ -206,25 +208,25 @@ boolean DomoticzCommand(const char *type, uint16_t index, char *dataBuf, uint16_ Settings.domoticz_relay_idx[index -1] = payload; restart_flag = 2; } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DOMOTICZ "%s%d\":%d}"), command, index, Settings.domoticz_relay_idx[index -1]); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, index, Settings.domoticz_relay_idx[index -1]); } else if ((CMND_KEYIDX == command_code) && (index > 0) && (index <= MAX_DOMOTICZ_IDX)) { if (payload >= 0) { Settings.domoticz_key_idx[index -1] = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DOMOTICZ "%s%d\":%d}"), command, index, Settings.domoticz_key_idx[index -1]); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, index, Settings.domoticz_key_idx[index -1]); } else if ((CMND_SWITCHIDX == command_code) && (index > 0) && (index <= MAX_DOMOTICZ_IDX)) { if (payload >= 0) { Settings.domoticz_switch_idx[index -1] = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DOMOTICZ "%s%d\":%d}"), command, index, Settings.domoticz_key_idx[index -1]); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, index, Settings.domoticz_key_idx[index -1]); } else if ((CMND_SENSORIDX == command_code) && (index > 0) && (index <= DZ_MAX_SENSORS)) { if (payload >= 0) { Settings.domoticz_sensor_idx[index -1] = payload; } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DOMOTICZ "%s%d\":%d}"), command, index, Settings.domoticz_sensor_idx[index -1]); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, index, Settings.domoticz_sensor_idx[index -1]); } else if (CMND_UPDATETIMER == command_code) { if ((payload >= 0) && (payload < 3601)) { diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino index fc88ed980..a171b440b 100644 --- a/sonoff/xdrv_ir_send.ino +++ b/sonoff/xdrv_ir_send.ino @@ -102,7 +102,7 @@ void IrReceiveCheck() if ((iridx < 0) || (iridx > 14)) { iridx = 0; } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_IRRECEIVED "\":{\"" D_IR_PROTOCOL "\":\"%s\", \"" D_IR_BITS "\":%d, \"" D_IR_DATA "\":\"%X\"}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_IRRECEIVED "\":{\"" D_IR_PROTOCOL "\":\"%s\",\"" D_IR_BITS "\":%d,\"" D_IR_DATA "\":\"%X\"}}"), GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, results.value); MqttPublishPrefixTopic_P(6, PSTR(D_IRRECEIVED)); #ifdef USE_DOMOTICZ diff --git a/sonoff/xdrv_snfbridge.ino b/sonoff/xdrv_snfbridge.ino index 96e78e3f5..84acb3ea8 100644 --- a/sonoff/xdrv_snfbridge.ino +++ b/sonoff/xdrv_snfbridge.ino @@ -90,7 +90,7 @@ void SonoffBridgeReceived() } } } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_RFRECEIVED "\":{\"" D_SYNC "\":%d, \"" D_LOW "\":%d, \"" D_HIGH "\":%d, \"" D_DATA "\":\"%06X\", \"" D_CMND_RFKEY "\":%s}}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_RFRECEIVED "\":{\"" D_SYNC "\":%d,\"" D_LOW "\":%d,\"" D_HIGH "\":%d,\"" D_DATA "\":\"%06X\",\"" D_CMND_RFKEY "\":%s}}"), sync_time, low_time, high_time, received_id, rfkey); MqttPublishPrefixTopic_P(6, PSTR(D_RFRECEIVED)); #ifdef USE_DOMOTICZ diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino index e35d0098c..2731892a4 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -336,10 +336,10 @@ void LightPreparePower() GetPowerDevice(scommand, devices_present, sizeof(scommand)); if (light_subtype > LST_SINGLE) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\", \"" D_CMND_DIMMER "\":%d, \"" D_CMND_COLOR "\":\"%s\"}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d,\"" D_CMND_COLOR "\":\"%s\"}"), scommand, GetStateText(light_power), Settings.light_dimmer, LightGetColor(0, scolor)); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\", \"" D_CMND_DIMMER "\":%d}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d}"), scommand, GetStateText(light_power), Settings.light_dimmer); } } @@ -782,7 +782,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le } } if (!valid_entry && (1 == index)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\"}"), command, LightGetColor(0, scolor)); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, LightGetColor(0, scolor)); } if (index > 1) { scolor[0] = '\0'; @@ -908,7 +908,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le else if (CMND_UNDOCA == command_code) { // Theos legacy status LightGetColor(1, scolor); scolor[6] = '\0'; // RGB only - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, %d, %d, %d, %d, %d"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,%d,%d,%d,%d,%d"), scolor, Settings.light_fade, Settings.light_correction, Settings.light_scheme, Settings.light_speed, Settings.light_width); MqttPublishPrefixTopic_P(1, type); mqtt_data[0] = '\0'; diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino index 73b8d4f3a..9fbb3cd35 100755 --- a/sonoff/xdrv_wemohue.ino +++ b/sonoff/xdrv_wemohue.ino @@ -28,7 +28,7 @@ boolean udp_connected = false; char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP packet -IPAddress ipMulticast(239, 255, 255, 250); // Simple Service Discovery Protocol (SSDP) +IPAddress ipMulticast(239,255,255,250); // Simple Service Discovery Protocol (SSDP) uint32_t port_multicast = 1900; // Multicast address and port /*********************************************************************************************\ @@ -220,10 +220,10 @@ void PollUdp() // AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet received")); // AddLog_P(LOG_LEVEL_DEBUG_MORE, request.c_str()); - if ((EMUL_WEMO == Settings.flag.emulation) && (request.indexOf(F("urn:belkin:device:**")) > 0)) { + if ((EMUL_WEMO == Settings.flag2.emulation) && (request.indexOf(F("urn:belkin:device:**")) > 0)) { WemoRespondToMSearch(); } - else if ((EMUL_HUE == Settings.flag.emulation) && + else if ((EMUL_HUE == Settings.flag2.emulation) && ((request.indexOf(F("st:urn:schemas-upnp-org:device:basic:1")) > 0) || (request.indexOf(F("st:upnp:rootdevice")) > 0) || (request.indexOf(F("st:ssdpsearch:all")) > 0) || diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index 6b38ba3c3..5cac3011e 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -47,13 +47,13 @@ struct ColorScheme { uint8_t count; }; -WsColor kIncandescent[2] = { 255, 140, 20, 0, 0, 0 }; -WsColor kRgb[3] = { 255, 0, 0, 0, 255, 0, 0, 0, 255 }; -WsColor kChristmas[2] = { 255, 0, 0, 0, 255, 0 }; -WsColor kHanukkah[2] = { 0, 0, 255, 255, 255, 255 }; -WsColor kwanzaa[3] = { 255, 0, 0, 0, 0, 0, 0, 255, 0 }; -WsColor kRainbow[7] = { 255, 0, 0, 255, 128, 0, 255, 255, 0, 0, 255, 0, 0, 0, 255, 128, 0, 255, 255, 0, 255 }; -WsColor kFire[3] = { 255, 0, 0, 255, 102, 0, 255, 192, 0 }; +WsColor kIncandescent[2] = { 255,140,20, 0,0,0 }; +WsColor kRgb[3] = { 255,0,0, 0,255,0, 0,0,255 }; +WsColor kChristmas[2] = { 255,0,0, 0,255,0 }; +WsColor kHanukkah[2] = { 0,0,255, 255,255,255 }; +WsColor kwanzaa[3] = { 255,0,0, 0,0,0, 0,255,0 }; +WsColor kRainbow[7] = { 255,0,0, 255,128,0, 255,255,0, 0,255,0, 0,0,255, 128,0,255, 255,0,255 }; +WsColor kFire[3] = { 255,0,0, 255,102,0, 255,192,0 }; ColorScheme kSchemes[7] = { kIncandescent, 2, kRgb, 3, diff --git a/sonoff/xsns_01_counter.ino b/sonoff/xsns_01_counter.ino index 974ff33c9..0b263611f 100644 --- a/sonoff/xsns_01_counter.ino +++ b/sonoff/xsns_01_counter.ino @@ -103,7 +103,7 @@ void CounterShow(boolean json) } if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_COUNTER "%d\":%s"), mqtt_data, i +1, counter); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_COUNTER "%d\":%s"), mqtt_data, i +1, counter); #ifdef USE_DOMOTICZ if (1 == dsxflg) { DomoticzSensor(DZ_COUNT, RtcSettings.pulse_counter[i]); diff --git a/sonoff/xsns_03_hlw8012.ino b/sonoff/xsns_03_hlw8012.ino index 58c8258e5..0d1ffc411 100644 --- a/sonoff/xsns_03_hlw8012.ino +++ b/sonoff/xsns_03_hlw8012.ino @@ -354,27 +354,27 @@ void HlwMarginCheck() snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{")); jsonflg = 0; if (HlwMargin(0, Settings.hlw_pmin, uwatts, flag, hlw_pmin_flag)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_POWERLOW "\":\"%s\""), mqtt_data, (jsonflg)?", ":"", GetStateText(flag)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_POWERLOW "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag)); jsonflg = 1; } if (HlwMargin(1, Settings.hlw_pmax, uwatts, flag, hlw_pmax_flag)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_POWERHIGH "\":\"%s\""), mqtt_data, (jsonflg)?", ":"", GetStateText(flag)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_POWERHIGH "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag)); jsonflg = 1; } if (HlwMargin(0, Settings.hlw_umin, uvoltage, flag, hlw_umin_flag)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), mqtt_data, (jsonflg)?", ":"", GetStateText(flag)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag)); jsonflg = 1; } if (HlwMargin(1, Settings.hlw_umax, uvoltage, flag, hlw_umax_flag)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), mqtt_data, (jsonflg)?", ":"", GetStateText(flag)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag)); jsonflg = 1; } if (HlwMargin(0, Settings.hlw_imin, ucurrent, flag, hlw_imin_flag)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), mqtt_data, (jsonflg)?", ":"", GetStateText(flag)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag)); jsonflg = 1; } if (HlwMargin(1, Settings.hlw_imax, ucurrent, flag, hlw_imax_flag)) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), mqtt_data, (jsonflg)?", ":"", GetStateText(flag)); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), mqtt_data, (jsonflg)?",":"", GetStateText(flag)); jsonflg = 1; } if (jsonflg) { @@ -526,10 +526,10 @@ boolean HlwCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_len, char syesterday_energy[10]; char stoday_energy[10]; char stotal_energy[10]; - dtostrfd((float)Settings.hlw_kWhyesterday / 100000000, Settings.flag.energy_resolution, syesterday_energy); - dtostrfd((float)RtcSettings.hlw_kWhtoday / 100000000, Settings.flag.energy_resolution, stoday_energy); - dtostrfd((float)(RtcSettings.hlw_kWhtotal + (hlw_kWhtoday / 1000)) / 100000, Settings.flag.energy_resolution, stotal_energy); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"" D_TOTAL "\":%s, \"" D_YESTERDAY "\":%s, \"" D_TODAY "\":%s}}"), + dtostrfd((float)Settings.hlw_kWhyesterday / 100000000, Settings.flag2.energy_resolution, syesterday_energy); + dtostrfd((float)RtcSettings.hlw_kWhtoday / 100000000, Settings.flag2.energy_resolution, stoday_energy); + dtostrfd((float)(RtcSettings.hlw_kWhtotal + (hlw_kWhtoday / 1000)) / 100000, Settings.flag2.energy_resolution, stotal_energy); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"" D_TOTAL "\":%s,\"" D_YESTERDAY "\":%s,\"" D_TODAY "\":%s}}"), command, stotal_energy, syesterday_energy, stoday_energy); status_flag = 1; } @@ -686,18 +686,18 @@ void HlwShow(boolean json, boolean option) char speriod[20]; HlwReadEnergy(option, total_energy, daily_energy, energy, watts, voltage, current, power_factor); - dtostrfd(total_energy, Settings.flag.energy_resolution, stotal_energy); - dtostrfd(daily_energy, Settings.flag.energy_resolution, sdaily_energy); - dtostrfd(energy, Settings.flag.wattage_resolution, senergy); - dtostrfd(watts, Settings.flag.wattage_resolution, swatts); - dtostrfd(voltage, Settings.flag.voltage_resolution, svoltage); - dtostrfd(current, 3, scurrent); + dtostrfd(total_energy, Settings.flag2.energy_resolution, stotal_energy); + dtostrfd(daily_energy, Settings.flag2.energy_resolution, sdaily_energy); + dtostrfd(energy, Settings.flag2.wattage_resolution, senergy); + dtostrfd(watts, Settings.flag2.wattage_resolution, swatts); + dtostrfd(voltage, Settings.flag2.voltage_resolution, svoltage); + dtostrfd(current, Settings.flag2.current_resolution, scurrent); dtostrfd(power_factor, 2, spower_factor); - dtostrfd((float)Settings.hlw_kWhyesterday / 100000000, Settings.flag.energy_resolution, syesterday_energy); + dtostrfd((float)Settings.hlw_kWhyesterday / 100000000, Settings.flag2.energy_resolution, syesterday_energy); if (json) { - snprintf_P(speriod, sizeof(speriod), PSTR(", \"" D_PERIOD "\":%s"), senergy); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_TOTAL "\":%s, \"" D_YESTERDAY "\":%s, \"" D_TODAY "\":%s%s, \"" D_POWERUSAGE "\":%s, \"" D_POWERFACTOR "\":%s, \"" D_VOLTAGE "\":%s, \"" D_CURRENT "\":%s}"), + snprintf_P(speriod, sizeof(speriod), PSTR(",\"" D_PERIOD "\":%s"), senergy); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_TOTAL "\":%s,\"" D_YESTERDAY "\":%s,\"" D_TODAY "\":%s%s,\"" D_POWERUSAGE "\":%s,\"" D_POWERFACTOR "\":%s,\"" D_VOLTAGE "\":%s,\"" D_CURRENT "\":%s}"), mqtt_data, stotal_energy, syesterday_energy, sdaily_energy, (option) ? speriod : "", swatts, spower_factor, svoltage, scurrent); #ifdef USE_DOMOTICZ if (option) { // Only send if telemetry @@ -720,7 +720,7 @@ void MqttShowHlw8012(byte option) * option 1 = show period energy usage */ // {"Time":"2017-03-04T13:37:24", "Total":0.013, "Yesterday":0.013, "Today":0.000, "Period":0, "Power":0, "Factor":0.00, "Voltage":0, "Current":0.000} - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_TIME "\":\"%s\", "), GetDateAndTime().c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_TIME "\":\"%s\","), GetDateAndTime().c_str()); HlwShow(1, option); MqttPublishPrefixTopic_P(2, PSTR(D_RSLT_ENERGY), Settings.flag.mqtt_sensor_retain); } diff --git a/sonoff/xsns_04_snfsc.ino b/sonoff/xsns_04_snfsc.ino index 28453d5da..fbe2a2e8a 100644 --- a/sonoff/xsns_04_snfsc.ino +++ b/sonoff/xsns_04_snfsc.ino @@ -116,11 +116,11 @@ void SonoffScShow(boolean json) float t = ConvertTemp(sc_value[1]); float h = sc_value[0]; - dtostrfd(t, Settings.flag.temperature_resolution, temperature); - dtostrfd(h, Settings.flag.humidity_resolution, humidity); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + dtostrfd(h, Settings.flag2.humidity_resolution, humidity); if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_TEMPERATURE "\":%s, \"" D_HUMIDITY "\":%s, \"" D_LIGHT "\":%d, \"" D_NOISE "\":%d, \"" D_AIRQUALITY "\":%d"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_TEMPERATURE "\":%s,\"" D_HUMIDITY "\":%s,\"" D_LIGHT "\":%d,\"" D_NOISE "\":%d,\"" D_AIRQUALITY "\":%d"), mqtt_data, temperature, humidity, sc_value[2], sc_value[3], sc_value[4]); #ifdef USE_DOMOTICZ DomoticzTempHumSensor(temperature, humidity); diff --git a/sonoff/xsns_05_ds18b20.ino b/sonoff/xsns_05_ds18b20.ino index 0a037aeef..30fb23cc8 100644 --- a/sonoff/xsns_05_ds18b20.ino +++ b/sonoff/xsns_05_ds18b20.ino @@ -190,10 +190,10 @@ void Ds18b20Show(boolean json) if (Ds18b20ReadTemperature(t)) { // Check if read failed char temperature[10]; - dtostrfi(t, Settings.flag.temperature_resolution, temperature); + dtostrfi(t, Settings.flag2.temperature_resolution, temperature); if(json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"DS18B20\":{\"" D_TEMPERATURE "\":%s}"), mqtt_data, temperature); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18B20\":{\"" D_TEMPERATURE "\":%s}"), mqtt_data, temperature); #ifdef USE_DOMOTICZ DomoticzSensor(DZ_TEMP, temperature); #endif // USE_DOMOTICZ diff --git a/sonoff/xsns_05_ds18x20.ino b/sonoff/xsns_05_ds18x20.ino index dfb463be1..6f2a04be9 100644 --- a/sonoff/xsns_05_ds18x20.ino +++ b/sonoff/xsns_05_ds18x20.ino @@ -171,17 +171,17 @@ void Ds18x20Show(boolean json) for (byte i = 0; i < Ds18x20Sensors(); i++) { if (Ds18x20Read(i, t)) { // Check if read failed Ds18x20Type(i); - dtostrfd(t, Settings.flag.temperature_resolution, temperature); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); if (json) { if (!dsxflg) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"DS18x20\":{"), mqtt_data); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18x20\":{"), mqtt_data); stemp[0] = '\0'; } dsxflg++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"DS%d\":{\"" D_TYPE "\":\"%s\", \"" D_ADDRESS "\":\"%s\", \"" D_TEMPERATURE "\":%s}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"DS%d\":{\"" D_TYPE "\":\"%s\",\"" D_ADDRESS "\":\"%s\",\"" D_TEMPERATURE "\":%s}"), mqtt_data, stemp, i +1, ds18x20_types, Ds18x20Addresses(i).c_str(), temperature); - strcpy(stemp, ", "); + strcpy(stemp, ","); #ifdef USE_DOMOTICZ if (1 == dsxflg) { DomoticzSensor(DZ_TEMP, temperature); diff --git a/sonoff/xsns_06_dht.ino b/sonoff/xsns_06_dht.ino index c86e727ba..036dc873d 100644 --- a/sonoff/xsns_06_dht.ino +++ b/sonoff/xsns_06_dht.ino @@ -37,7 +37,7 @@ byte dht_sensors = 0; struct DHTSTRUCT { byte pin; byte type; - char stype[10]; + char stype[12]; uint32_t lastreadtime; uint8_t lastresult; float t; @@ -204,16 +204,7 @@ void DhtInit() pinMode(Dht[i].pin, INPUT_PULLUP); Dht[i].lastreadtime = 0; Dht[i].lastresult = 0; - switch (Dht[i].type) { - case GPIO_DHT11: - strcpy_P(Dht[i].stype, PSTR("DHT11")); - break; - case GPIO_DHT21: - strcpy_P(Dht[i].stype, PSTR("AM2301")); - break; - case GPIO_DHT22: - strcpy_P(Dht[i].stype, PSTR("DHT22")); - } + strcpy_P(Dht[i].stype, kSensors[Dht[i].type]); if (dht_sensors > 1) { snprintf_P(Dht[i].stype, sizeof(Dht[i].stype), PSTR("%s-%02d"), Dht[i].stype, Dht[i].pin); } @@ -230,8 +221,8 @@ void DhtShow(boolean json) byte dsxflg = 0; for (byte i = 0; i < dht_sensors; i++) { if (DhtReadTempHum(i, t, h)) { // Read temperature - dtostrfd(t, Settings.flag.temperature_resolution, temperature); - dtostrfd(h, Settings.flag.humidity_resolution, humidity); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + dtostrfd(h, Settings.flag2.humidity_resolution, humidity); if (json) { snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, Dht[i].stype, temperature, humidity); diff --git a/sonoff/xsns_07_sht1x.ino b/sonoff/xsns_07_sht1x.ino index c259bcdf6..db1ad3717 100644 --- a/sonoff/xsns_07_sht1x.ino +++ b/sonoff/xsns_07_sht1x.ino @@ -24,6 +24,8 @@ * * Reading temperature and humidity takes about 320 milliseconds! * Source: Marinus vd Broek https://github.com/ESP8266nu/ESPEasy + * + * I2C Address: None \*********************************************************************************************/ enum { @@ -161,10 +163,10 @@ boolean ShtReadTempHum(float &t, float &h) /********************************************************************************************/ -boolean ShtDetect() +void ShtDetect() { if (sht_type) { - return true; + return; } float t; @@ -179,7 +181,6 @@ boolean ShtDetect() Wire.begin(sht_sda_pin, sht_scl_pin); sht_type = 0; } - return sht_type; } void ShtShow(boolean json) @@ -192,8 +193,8 @@ void ShtShow(boolean json) char temperature[10]; char humidity[10]; - dtostrfd(t, Settings.flag.temperature_resolution, temperature); - dtostrfd(h, Settings.flag.humidity_resolution, humidity); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + dtostrfd(h, Settings.flag2.humidity_resolution, humidity); if (json) { snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, "SHT1X", temperature, humidity); diff --git a/sonoff/xsns_08_htu21.ino b/sonoff/xsns_08_htu21.ino index 22c86a09d..6a1053145 100644 --- a/sonoff/xsns_08_htu21.ino +++ b/sonoff/xsns_08_htu21.ino @@ -23,6 +23,8 @@ * HTU21 - Temperature and Humidy * * Source: Heiko Krupp + * + * I2C Address: 0x40 \*********************************************************************************************/ #define HTU21_ADDR 0x40 @@ -52,6 +54,8 @@ #define HTU21_CRC8_POLYNOM 0x13100 +const char kHtuTypes[] PROGMEM = "HTU21|SI7013|SI7020|SI7021|T/RH?"; + uint8_t htu_address; uint8_t htu_type = 0; uint8_t delay_temp; @@ -95,8 +99,8 @@ uint8_t HtuReadDeviceId(void) void HtuSetResolution(uint8_t resolution) { uint8_t current = I2cRead8(HTU21_ADDR, HTU21_READREG); - current &= 0x7E; // Replace current resolution bits with 0 - current |= resolution; // Add new resolution bits to register + current &= 0x7E; // Replace current resolution bits with 0 + current |= resolution; // Add new resolution bits to register I2cWrite8(HTU21_ADDR, HTU21_WRITEREG, current); } @@ -124,12 +128,11 @@ void HtuHeater(uint8_t heater) I2cWrite8(HTU21_ADDR, HTU21_WRITEREG, current); } -boolean HtuInit() +void HtuInit() { HtuReset(); HtuHeater(HTU21_HEATER_OFF); HtuSetResolution(HTU21_RES_RH12_T14); - return true; } float HtuReadHumidity(void) @@ -207,50 +210,40 @@ float HtuCompensatedHumidity(float humidity, float temperature) /********************************************************************************************/ -uint8_t HtuDetect() +void HtuDetect() { if (htu_type) { - return true; + return; } - boolean success = false; - htu_address = HTU21_ADDR; htu_type = HtuReadDeviceId(); - success = HtuInit(); - switch (htu_type) { - case HTU21_CHIPID: - strcpy_P(htu_types, PSTR("HTU21")); - delay_temp=50; - delay_humidity=16; - break; - case SI7013_CHIPID: - strcpy_P(htu_types, PSTR("SI7013")); - delay_temp=12; - delay_humidity=23; - break; - case SI7020_CHIPID: - strcpy_P(htu_types, PSTR("SI7020")); - delay_temp=12; - delay_humidity=23; - break; - case SI7021_CHIPID: - strcpy_P(htu_types, PSTR("SI7021")); - delay_temp=12; - delay_humidity=23; - break; - default: - strcpy_P(htu_types, PSTR("T/RH?")); - delay_temp=50; - delay_humidity=23; - } - if (success) { + if (htu_type) { + uint8_t index = 0; + HtuInit(); + switch (htu_type) { + case HTU21_CHIPID: + delay_temp = 50; + delay_humidity = 16; + break; + case SI7021_CHIPID: + index++; // 3 + case SI7020_CHIPID: + index++; // 2 + case SI7013_CHIPID: + index++; // 1 + delay_temp = 12; + delay_humidity = 23; + break; + default: + index = 4; + delay_temp = 50; + delay_humidity = 23; + } + GetTextIndexed(htu_types, sizeof(htu_types), index, kHtuTypes); snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, htu_types, htu_address); AddLog(LOG_LEVEL_DEBUG); - } else { - htu_type = 0; } - return success; } void HtuShow(boolean json) @@ -262,8 +255,8 @@ void HtuShow(boolean json) float t = HtuReadTemperature(); float h = HtuReadHumidity(); h = HtuCompensatedHumidity(h, t); - dtostrfd(t, Settings.flag.temperature_resolution, temperature); - dtostrfd(h, Settings.flag.humidity_resolution, humidity); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + dtostrfd(h, Settings.flag2.humidity_resolution, humidity); if (json) { snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, htu_types, temperature, humidity); diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino index 0a8480cb2..4a2cafc53 100644 --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -23,9 +23,12 @@ * BMP085, BMP180, BMP280, BME280 - Pressure and Temperature and Humidy (BME280 only) * * Source: Heiko Krupp and Adafruit Industries + * + * I2C Address: 0x76 or 0x77 \*********************************************************************************************/ -#define BMP_ADDR 0x77 +#define BMP_ADDR1 0x77 +#define BMP_ADDR2 0x76 #define BMP180_CHIPID 0x55 #define BMP280_CHIPID 0x58 @@ -33,11 +36,15 @@ #define BMP_REGISTER_CHIPID 0xD0 -double bmp_sealevel = 0.0; -uint8_t bmp_address; +const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280"; + uint8_t bmp_type = 0; +uint8_t bmp_address; +uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 }; char bmp_types[7]; +double bmp_sealevel = 0.0; + /*********************************************************************************************\ * BMP085 and BME180 \*********************************************************************************************/ @@ -371,42 +378,41 @@ double BmpReadHumidity(void) /********************************************************************************************/ -boolean BmpDetect() +void BmpDetect() { if (bmp_type) { - return true; + return; } - boolean success = false; - - bmp_address = BMP_ADDR; - bmp_type = I2cRead8(bmp_address, BMP_REGISTER_CHIPID); - if (!bmp_type) { - bmp_address--; + for (byte i = 0; i < sizeof(bmp_addresses); i++) { + bmp_address = bmp_addresses[i]; bmp_type = I2cRead8(bmp_address, BMP_REGISTER_CHIPID); + if (bmp_type) { + break; + } } - strcpy_P(bmp_types, PSTR("BMP")); - switch (bmp_type) { - case BMP180_CHIPID: - success = Bmp180Calibration(); - strcpy_P(bmp_types, PSTR("BMP180")); - break; - case BMP280_CHIPID: - success = Bmx280Calibrate(); - strcpy_P(bmp_types, PSTR("BMP280")); - break; - case BME280_CHIPID: - success = Bmx280Calibrate(); - strcpy_P(bmp_types, PSTR("BME280")); + if (bmp_type) { + boolean success = false; + uint8_t index = 0; + switch (bmp_type) { + case BMP180_CHIPID: + success = Bmp180Calibration(); + break; + case BME280_CHIPID: + index++; // 2 + case BMP280_CHIPID: + index++; // 1 + success = Bmx280Calibrate(); + } + if (success) { + GetTextIndexed(bmp_types, sizeof(bmp_types), index, kBmpTypes); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_types, bmp_address); + AddLog(LOG_LEVEL_DEBUG); + } + else { + bmp_type = 0; + } } - if (success) { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, bmp_types, bmp_address); - AddLog(LOG_LEVEL_DEBUG); - } - else { - bmp_type = 0; - } - return success; } void BmpShow(boolean json) @@ -421,19 +427,19 @@ void BmpShow(boolean json) double t = BmpReadTemperature(); double p = BmpReadPressure(); double h = BmpReadHumidity(); - dtostrfd(t, Settings.flag.temperature_resolution, temperature); - dtostrfd(p, Settings.flag.pressure_resolution, pressure); - dtostrfd(h, Settings.flag.humidity_resolution, humidity); - dtostrfd(bmp_sealevel, Settings.flag.pressure_resolution, sea_pressure); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + dtostrfd(p, Settings.flag2.pressure_resolution, pressure); + dtostrfd(h, Settings.flag2.humidity_resolution, humidity); + dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure); if (json) { - snprintf_P(sealevel, sizeof(sealevel), PSTR(", \"" D_PRESSUREATSEALEVEL "\":%s"), sea_pressure); + snprintf_P(sealevel, sizeof(sealevel), PSTR(",\"" D_PRESSUREATSEALEVEL "\":%s"), sea_pressure); if (BME280_CHIPID == bmp_type) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_HUMIDITY "\":%s, \"" D_PRESSURE "\":%s%s}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_TEMPERATURE "\":%s,\"" D_HUMIDITY "\":%s,\"" D_PRESSURE "\":%s%s}"), mqtt_data, bmp_types, temperature, humidity, pressure, (Settings.altitude != 0) ? sealevel : ""); } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_TEMPERATURE "\":%s, \"" D_PRESSURE "\":%s%s}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_TEMPERATURE "\":%s,\"" D_PRESSURE "\":%s%s}"), mqtt_data, bmp_types, temperature, pressure, (Settings.altitude != 0) ? sealevel : ""); } #ifdef USE_DOMOTICZ diff --git a/sonoff/xsns_10_bh1750.ino b/sonoff/xsns_10_bh1750.ino index 28cee8941..8055cdfe8 100644 --- a/sonoff/xsns_10_bh1750.ino +++ b/sonoff/xsns_10_bh1750.ino @@ -21,6 +21,8 @@ #ifdef USE_BH1750 /*********************************************************************************************\ * BH1750 - Ambient Light Intensity + * + * I2C Address: 0x23 or 0x5C \*********************************************************************************************/ #define BH1750_ADDR1 0x23 @@ -28,8 +30,9 @@ #define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 // Start measurement at 1lx resolution. Measurement time is approx 120ms. -uint8_t bh1750_address; uint8_t bh1750_type = 0; +uint8_t bh1750_address; +uint8_t bh1750_addresses[] = { BH1750_ADDR1, BH1750_ADDR2 }; uint16_t Bh1750ReadLux() { @@ -42,36 +45,25 @@ uint16_t Bh1750ReadLux() /********************************************************************************************/ -boolean Bh1750Detect() +void Bh1750Detect() { if (bh1750_type) { - return true; + return; } - uint8_t status; - boolean success = false; - - bh1750_address = BH1750_ADDR1; - Wire.beginTransmission(bh1750_address); - Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE); - status = Wire.endTransmission(); - if (status) { - bh1750_address = BH1750_ADDR2; + for (byte i = 0; i < sizeof(bh1750_addresses); i++) { + bh1750_address = bh1750_addresses[i]; Wire.beginTransmission(bh1750_address); Wire.write(BH1750_CONTINUOUS_HIGH_RES_MODE); - status = Wire.endTransmission(); + if (!Wire.endTransmission()) { + bh1750_type = 1; + break; + } } - if (!status) { - success = true; - bh1750_type = 1; - } - if (success) { + if (bh1750_type) { snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "BH1750", bh1750_address); AddLog(LOG_LEVEL_DEBUG); - } else { - bh1750_type = 0; } - return success; } #ifdef USE_WEBSERVER @@ -85,7 +77,7 @@ void Bh1750Show(boolean json) uint16_t illuminance = Bh1750ReadLux(); if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"BH1750\":{\"" D_ILLUMINANCE "\":%d}"), mqtt_data, illuminance); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"BH1750\":{\"" D_ILLUMINANCE "\":%d}"), mqtt_data, illuminance); #ifdef USE_DOMOTICZ DomoticzSensor(DZ_ILLUMINANCE, illuminance); #endif // USE_DOMOTICZ diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index 00530d768..31a72e960 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -21,6 +21,8 @@ #ifdef USE_VEML6070 /*********************************************************************************************\ * VEML6070 - Ultra Violet Light Intensity + * + * I2C Address: 0x38 and 0x39 \*********************************************************************************************/ #define VEML6070_ADDR_H 0x39 @@ -88,7 +90,7 @@ void Veml6070Show(boolean json) uint16_t uvlevel = Veml6070ReadUv(); if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_UV_LEVEL "\":%d}"), mqtt_data, veml6070_types, uvlevel); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_UV_LEVEL "\":%d}"), mqtt_data, veml6070_types, uvlevel); #ifdef USE_DOMOTICZ DomoticzSensor(DZ_ILLUMINANCE, uvlevel); #endif // USE_DOMOTICZ diff --git a/sonoff/xsns_12_ads1115.ino b/sonoff/xsns_12_ads1115.ino index 60d2029ce..3a9d48760 100644 --- a/sonoff/xsns_12_ads1115.ino +++ b/sonoff/xsns_12_ads1115.ino @@ -24,6 +24,8 @@ * * Required library: https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/ADS1115 * + * I2C Address: 0x48, 0x49, 0x4A or 0x4B + * * The ADC input range (or gain) can be changed via the following * functions, but be careful never to exceed VDD +0.3V max, or to * exceed the upper and lower limits if you adjust the input range! @@ -42,9 +44,8 @@ ADS1115 adc0; -uint8_t ads1115_address; uint8_t ads1115_type = 0; - +uint8_t ads1115_address; uint8_t ads1115_addresses[] = { ADS1115_ADDRESS_ADDR_GND, // address pin low (GND) ADS1115_ADDRESS_ADDR_VDD, // address pin high (VCC) @@ -72,16 +73,13 @@ int16_t Ads1115GetConversion(byte channel) /********************************************************************************************/ -boolean Ads1115Detect() +void Ads1115Detect() { if (ads1115_type) { - return true; + return; } - uint8_t status; - boolean success = false; - - for (byte i = 0; i < 4; i++) { + for (byte i = 0; i < sizeof(ads1115_addresses); i++) { ads1115_address = ads1115_addresses[i]; ADS1115 adc0(ads1115_address); if (adc0.testConnection()) { @@ -89,16 +87,14 @@ boolean Ads1115Detect() adc0.setGain(ADS1115_PGA_2P048); // Set the gain (PGA) +/-4.096V adc0.setRate(ADS1115_RATE_860); adc0.setMode(ADS1115_MODE_CONTINUOUS); - success = true; ads1115_type = 1; break; } } - if (success) { + if (ads1115_type) { snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "ADS1115", ads1115_address); AddLog(LOG_LEVEL_DEBUG); } - return success; } void Ads1115Show(boolean json) @@ -112,12 +108,12 @@ void Ads1115Show(boolean json) if (json) { if (!dsxflg ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"ADS1115\":{"), mqtt_data); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"ADS1115\":{"), mqtt_data); stemp[0] = '\0'; } dsxflg++; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_ANALOG_INPUT "%d\":%d"), mqtt_data, stemp, i, adc_value); - strcpy(stemp, ", "); + strcpy(stemp, ","); #ifdef USE_WEBSERVER } else { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ANALOG, mqtt_data, "ADS1115", i, adc_value); diff --git a/sonoff/xsns_13_ina219.ino b/sonoff/xsns_13_ina219.ino new file mode 100644 index 000000000..1a0d4e597 --- /dev/null +++ b/sonoff/xsns_13_ina219.ino @@ -0,0 +1,243 @@ +/* + xsns_13_ina219.ino - INA219 Current Sensor support for Sonoff-Tasmota + + Copyright (C) 2017 Stefan Bode and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_INA219 +/*********************************************************************************************\ + * INA219 - Low voltage (max 32V!) Current sensor + * + * Source: Adafruit Industries + * + * I2C Address: 0x40, 0x41 0x44 or 0x45 +\*********************************************************************************************/ + +#define INA219_ADDRESS1 (0x40) // 1000000 (A0+A1=GND) +#define INA219_ADDRESS2 (0x41) // 1000000 (A0=Vcc, A1=GND) +#define INA219_ADDRESS3 (0x44) // 1000000 (A0=GND, A1=Vcc) +#define INA219_ADDRESS4 (0x45) // 1000000 (A0+A1=Vcc) + +#define INA219_READ (0x01) +#define INA219_REG_CONFIG (0x00) + +#define INA219_CONFIG_RESET (0x8000) // Reset Bit + +#define INA219_CONFIG_BVOLTAGERANGE_MASK (0x2000) // Bus Voltage Range Mask +#define INA219_CONFIG_BVOLTAGERANGE_16V (0x0000) // 0-16V Range +#define INA219_CONFIG_BVOLTAGERANGE_32V (0x2000) // 0-32V Range + +#define INA219_CONFIG_GAIN_MASK (0x1800) // Gain Mask +#define INA219_CONFIG_GAIN_1_40MV (0x0000) // Gain 1, 40mV Range +#define INA219_CONFIG_GAIN_2_80MV (0x0800) // Gain 2, 80mV Range +#define INA219_CONFIG_GAIN_4_160MV (0x1000) // Gain 4, 160mV Range +#define INA219_CONFIG_GAIN_8_320MV (0x1800) // Gain 8, 320mV Range + +#define INA219_CONFIG_BADCRES_MASK (0x0780) // Bus ADC Resolution Mask +#define INA219_CONFIG_BADCRES_9BIT (0x0080) // 9-bit bus res = 0..511 +#define INA219_CONFIG_BADCRES_10BIT (0x0100) // 10-bit bus res = 0..1023 +#define INA219_CONFIG_BADCRES_11BIT (0x0200) // 11-bit bus res = 0..2047 +#define INA219_CONFIG_BADCRES_12BIT (0x0400) // 12-bit bus res = 0..4097 + +#define INA219_CONFIG_SADCRES_MASK (0x0078) // Shunt ADC Resolution and Averaging Mask +#define INA219_CONFIG_SADCRES_9BIT_1S_84US (0x0000) // 1 x 9-bit shunt sample +#define INA219_CONFIG_SADCRES_10BIT_1S_148US (0x0008) // 1 x 10-bit shunt sample +#define INA219_CONFIG_SADCRES_11BIT_1S_276US (0x0010) // 1 x 11-bit shunt sample +#define INA219_CONFIG_SADCRES_12BIT_1S_532US (0x0018) // 1 x 12-bit shunt sample +#define INA219_CONFIG_SADCRES_12BIT_2S_1060US (0x0048) // 2 x 12-bit shunt samples averaged together +#define INA219_CONFIG_SADCRES_12BIT_4S_2130US (0x0050) // 4 x 12-bit shunt samples averaged together +#define INA219_CONFIG_SADCRES_12BIT_8S_4260US (0x0058) // 8 x 12-bit shunt samples averaged together +#define INA219_CONFIG_SADCRES_12BIT_16S_8510US (0x0060) // 16 x 12-bit shunt samples averaged together +#define INA219_CONFIG_SADCRES_12BIT_32S_17MS (0x0068) // 32 x 12-bit shunt samples averaged together +#define INA219_CONFIG_SADCRES_12BIT_64S_34MS (0x0070) // 64 x 12-bit shunt samples averaged together +#define INA219_CONFIG_SADCRES_12BIT_128S_69MS (0x0078) // 128 x 12-bit shunt samples averaged together + +#define INA219_CONFIG_MODE_MASK (0x0007) // Operating Mode Mask +#define INA219_CONFIG_MODE_POWERDOWN (0x0000) +#define INA219_CONFIG_MODE_SVOLT_TRIGGERED (0x0001) +#define INA219_CONFIG_MODE_BVOLT_TRIGGERED (0x0002) +#define INA219_CONFIG_MODE_SANDBVOLT_TRIGGERED (0x0003) +#define INA219_CONFIG_MODE_ADCOFF (0x0004) +#define INA219_CONFIG_MODE_SVOLT_CONTINUOUS (0x0005) +#define INA219_CONFIG_MODE_BVOLT_CONTINUOUS (0x0006) +#define INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS (0x0007) + +#define INA219_REG_SHUNTVOLTAGE (0x01) +#define INA219_REG_BUSVOLTAGE (0x02) +#define INA219_REG_POWER (0x03) +#define INA219_REG_CURRENT (0x04) +#define INA219_REG_CALIBRATION (0x05) + +uint8_t ina219_type = 0; +uint8_t ina219_address; +uint8_t ina219_addresses[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; + +uint32_t ina219_cal_value = 0; +// The following multiplier is used to convert raw current values to mA, taking into account the current config settings +uint32_t ina219_current_divider_ma = 0; + +bool Ina219SetCalibration(uint8_t mode) +{ + uint16_t config = 0; + + switch (mode &3) { + case 0: // 32V 2A + case 3: + ina219_cal_value = 4096; + ina219_current_divider_ma = 10; // Current LSB = 100uA per bit (1000/100 = 10) + config = INA219_CONFIG_BVOLTAGERANGE_32V | INA219_CONFIG_GAIN_8_320MV | INA219_CONFIG_BADCRES_12BIT | INA219_CONFIG_SADCRES_12BIT_1S_532US | INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + break; + case 1: // 32V 1A + ina219_cal_value = 10240; + ina219_current_divider_ma = 25; // Current LSB = 40uA per bit (1000/40 = 25) + config |= INA219_CONFIG_BVOLTAGERANGE_32V | INA219_CONFIG_GAIN_8_320MV | INA219_CONFIG_BADCRES_12BIT | INA219_CONFIG_SADCRES_12BIT_1S_532US | INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + break; + case 2: // 16V 0.4A + ina219_cal_value = 8192; + ina219_current_divider_ma = 20; // Current LSB = 50uA per bit (1000/50 = 20) + config |= INA219_CONFIG_BVOLTAGERANGE_16V | INA219_CONFIG_GAIN_1_40MV | INA219_CONFIG_BADCRES_12BIT | INA219_CONFIG_SADCRES_12BIT_1S_532US | INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + break; + } + // Set Calibration register to 'Cal' calculated above + bool success = I2cWrite16(ina219_address, INA219_REG_CALIBRATION, ina219_cal_value); + if (success) { + // Set Config register to take into account the settings above + I2cWrite16(ina219_address, INA219_REG_CONFIG, config); + } + return success; +} + +float Ina219GetShuntVoltage_mV() +{ + // raw shunt voltage (16-bit signed integer, so +-32767) + int16_t value = I2cReadS16(ina219_address, INA219_REG_SHUNTVOLTAGE); + // shunt voltage in mV (so +-327mV) + return value * 0.01; +} + +float Ina219GetBusVoltage_V() +{ + // Shift to the right 3 to drop CNVR and OVF and multiply by LSB + // raw bus voltage (16-bit signed integer, so +-32767) + int16_t value = (int16_t)(((uint16_t)I2cReadS16(ina219_address, INA219_REG_BUSVOLTAGE) >> 3) * 4); + // bus voltage in volts + return value * 0.001; +} + +float Ina219GetCurrent_mA() +{ + // Sometimes a sharp load will reset the INA219, which will reset the cal register, + // meaning CURRENT and POWER will not be available ... avoid this by always setting + // a cal value even if it's an unfortunate extra step + I2cWrite16(ina219_address, INA219_REG_CALIBRATION, ina219_cal_value); + // Now we can safely read the CURRENT register! + // raw current value (16-bit signed integer, so +-32767) + float value = I2cReadS16(ina219_address, INA219_REG_CURRENT); + value /= ina219_current_divider_ma; + // current value in mA, taking into account the config settings and current LSB + return value; +} + +/********************************************************************************************/ + +void Ina219Detect() +{ + if (ina219_type) { + return; + } + + for (byte i = 0; i < sizeof(ina219_addresses); i++) { + ina219_address = ina219_addresses[i]; + if (Ina219SetCalibration(Settings.ina219_mode)) { + ina219_type = 1; + break; + } + } + if (ina219_type) { + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "INA219", ina219_address); + AddLog(LOG_LEVEL_DEBUG); + } +} + +#ifdef USE_WEBSERVER +const char HTTP_SNS_INA219_DATA[] PROGMEM = "%s" + "{s}INA219 " D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}" + "{s}INA219 " D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}" + "{s}INA219 " D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; +#endif // USE_WEBSERVER + +void Ina219Show(boolean json) +{ + if (ina219_type) { + char voltage[10]; + char current[10]; + char power[10]; + + float fvoltage = Ina219GetBusVoltage_V() + (Ina219GetShuntVoltage_mV() / 1000); + float fcurrent = Ina219GetCurrent_mA() / 1000; + float fpower = fvoltage * fcurrent; + dtostrfd(fvoltage, Settings.flag2.voltage_resolution, voltage); + dtostrfd(fpower, Settings.flag2.wattage_resolution, power); + dtostrfd(fcurrent, Settings.flag2.current_resolution, current); + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"INA219\":{\"" D_VOLTAGE "\":%s,\"" D_CURRENT "\":%s,\"" D_POWERUSAGE "\":%s}"), + mqtt_data, voltage, current, power); +#ifdef USE_DOMOTICZ + DomoticzSensor(DZ_VOLTAGE, voltage); + DomoticzSensor(DZ_CURRENT, current); +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_INA219_DATA, mqtt_data, voltage, current, power); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_13 + +boolean Xsns13(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { +// case FUNC_XSNS_INIT: +// break; + case FUNC_XSNS_PREP: + Ina219Detect(); + break; + case FUNC_XSNS_JSON_APPEND: + Ina219Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_XSNS_WEB: + Ina219Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_INA219 +#endif // USE_I2C