4.1.1 20170329
* Fix default Telemetry for command Prefix3
* Fix webserver Module parameters for disabled select
* Fix sensor status for enabled switches
* Remove Light as alternative for Power (save code space)
* Remove migration option from pre V3 (code cleanup)
* Remove unofficial SPIFFS support (code cleanup)
* Remove command list when unknown command is entered (save code space)
* Rename Status11 json from StatusPWR to unique StatusSTS
* Rename command Gateway to IPAddres2, Subnetmask to IPAddress3 and
DnsServer to IPAddress4 (save code space)
* Add Command MqttResponse to select either command or RESULT topic as
response (#258)
* Add command StateText1 to StateText3 to assign MQTT_STATUS_OFF,
MQTT_STATUS_ON and MQTT_CMND_TOGGLE respectively (#286)
* Remove restart after IPAddress changes (#292)
* Add support for MAX31850 in xsns_ds18x20.ino (#295)
* Fix possible uptime update misses (#302)
This commit is contained in:
arendst 2017-03-29 18:42:05 +02:00
parent 81eb44aa8c
commit a8f2293a66
15 changed files with 400 additions and 450 deletions

View File

@ -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 **4.1.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
Current version is **4.1.1** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
- This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic.
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,20 @@
/* 4.1.0 20170325
/* 4.1.1 20170329
* Fix default Telemetry for command Prefix3
* Fix webserver Module parameters for disabled select
* Fix sensor status for enabled switches
* Remove Light as alternative for Power (save code space)
* Remove migration option from pre V3 (code cleanup)
* Remove unofficial SPIFFS support (code cleanup)
* Remove command list when unknown command is entered (save code space)
* Rename Status11 json from StatusPWR to unique StatusSTS
* Rename command Gateway to IPAddres2, Subnetmask to IPAddress3 and DnsServer to IPAddress4 (save code space)
* Add Command MqttResponse to select either command or RESULT topic as response (#258)
* Add command StateText1 to StateText3 to assign MQTT_STATUS_OFF, MQTT_STATUS_ON and MQTT_CMND_TOGGLE respectively (#286)
* Remove restart after IPAddress changes (#292)
* Add support for MAX31850 in xsns_ds18x20.ino (#295)
* Fix possible uptime update misses (#302)
*
* 4.1.0 20170325
* Change static IP addresses in user_config.h from list (using commas) to string (using dots)
* Unify display result of commands Modules, Module and Gpios
* Rewrite Module selection web page to bring size down from 18651 to 4319 bytes (!) (#234, #240)

View File

@ -2,76 +2,6 @@
* Config settings
\*********************************************************************************************/
#ifdef ALLOW_MIGRATE_TO_V3
struct SYSCFG2 { // Version 2.x (old)
unsigned long cfg_holder;
unsigned long saveFlag;
unsigned long version;
byte seriallog_level;
byte syslog_level;
char syslog_host[32];
char sta_ssid1[32];
char sta_pwd1[64];
char otaUrl[80];
char mqtt_host[32];
char mqtt_grptopic[32];
char mqtt_topic[32];
char mqtt_topic2[32];
char mqtt_subtopic[32];
int8_t timezone;
uint8_t power;
uint8_t ledstate;
uint16_t mqtt_port;
char mqtt_client[33];
char mqtt_user[33];
char mqtt_pwd[33];
uint8_t webserver;
unsigned long bootcount;
char hostname[33];
uint16_t syslog_port;
byte weblog_level;
uint16_t tele_period;
uint8_t sta_config;
int16_t savedata;
byte model;
byte mqtt_retain;
byte savestate;
unsigned long hlw_pcal;
unsigned long hlw_ucal;
unsigned long hlw_ical;
unsigned long hlw_kWhyesterday;
byte value_units;
uint16_t hlw_pmin;
uint16_t hlw_pmax;
uint16_t hlw_umin;
uint16_t hlw_umax;
uint16_t hlw_imin;
uint16_t hlw_imax;
uint16_t hlw_mpl; // MaxPowerLimit
uint16_t hlw_mplh; // MaxPowerLimitHold
uint16_t hlw_mplw; // MaxPowerLimitWindow
uint16_t hlw_mspl; // MaxSafePowerLimit
uint16_t hlw_msplh; // MaxSafePowerLimitHold
uint16_t hlw_msplw; // MaxSafePowerLimitWindow
uint16_t hlw_mkwh; // MaxEnergy
uint16_t hlw_mkwhs; // MaxEnergyStart
char domoticz_in_topic[33];
char domoticz_out_topic[33];
uint16_t domoticz_update_timer;
unsigned long domoticz_relay_idx[4];
unsigned long domoticz_key_idx[4];
byte message_format; // Not used since 3.2.6a
unsigned long hlw_kWhtoday;
uint16_t hlw_kWhdoy;
uint8_t switchmode;
char mqtt_fingerprint[60];
byte sta_active;
char sta_ssid2[33];
char sta_pwd2[65];
} sysCfg2;
#endif // ALLOW_MIGRATE_TO_V3
struct SYSCFG {
unsigned long cfg_holder;
unsigned long saveFlag;
@ -80,7 +10,7 @@ struct SYSCFG {
byte migflg; // Not used since 3.9.1
int16_t savedata;
byte savestate;
byte model; // Not used since 3.9.1
byte mqtt_response; // was model until 3.9.1
int8_t timezone;
char otaUrl[101];
@ -108,7 +38,7 @@ struct SYSCFG {
char mqtt_topic[33];
char button_topic[33];
char mqtt_grptopic[33];
char mqtt_subtopic[33];
char state_text[3][11]; // was ex_mqtt_subtopic[33] until 4.1.1
byte mqtt_button_retain;
byte mqtt_power_retain;
byte value_units;
@ -212,7 +142,6 @@ struct SYSCFG {
uint16_t pwmvalue[5];
// 4.0.9
// uint8_t ip_address[4][4];
uint32_t ip_address[4];
} sysCfg;

View File

@ -114,12 +114,6 @@ extern "C" {
#define SPIFFS_START ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE
#define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE
#ifdef ALLOW_MIGRATE_TO_V3
// Version 2.x config
#define SPIFFS_CONFIG2 "/config.ini"
#define CFG_LOCATION2 SPIFFS_END - 2
#endif // ALLOW_MIGRATE_TO_V3
// Version 3.x config
#define SPIFFS_CONFIG "/cfg.ini"
#define CFG_LOCATION SPIFFS_END - 4
@ -182,24 +176,10 @@ void CFG_Save()
{
char log[LOGSZ];
#ifndef BE_MINIMAL
if ((getHash() != _cfgHash) && (spiffsPresent())) {
if (!spiffsflag) {
#ifdef USE_SPIFFS
sysCfg.saveFlag++;
File f = SPIFFS.open(SPIFFS_CONFIG, "r+");
if (f) {
uint8_t *bytes = (uint8_t*)&sysCfg;
for (int i = 0; i < sizeof(SYSCFG); i++) f.write(bytes[i]);
f.close();
snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to spiffs count %d"), sizeof(SYSCFG), sysCfg.saveFlag);
addLog(LOG_LEVEL_DEBUG, log);
} else {
addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Saving configuration failed"));
}
} else {
#endif // USE_SPIFFS
noInterrupts();
// if (sysCfg.module != SONOFF_LED) noInterrupts();
if (sysCfg.saveFlag == 0) { // Handle default and rollover
spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1));
spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
@ -208,12 +188,12 @@ void CFG_Save()
spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1));
spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
interrupts();
// if (sysCfg.module != SONOFF_LED) interrupts();
snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to flash at %X and count %d"), sizeof(SYSCFG), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag);
addLog(LOG_LEVEL_DEBUG, log);
}
_cfgHash = getHash();
}
#endif // BE_MINIMAL
RTC_Save();
}
@ -223,19 +203,6 @@ void CFG_Load()
if (spiffsPresent()) {
if (!spiffsflag) {
#ifdef USE_SPIFFS
File f = SPIFFS.open(SPIFFS_CONFIG, "r+");
if (f) {
uint8_t *bytes = (uint8_t*)&sysCfg;
for (int i = 0; i < sizeof(SYSCFG); i++) bytes[i] = f.read();
f.close();
snprintf_P(log, sizeof(log), PSTR("Config: Loaded configuration from spiffs count %d"), sysCfg.saveFlag);
addLog(LOG_LEVEL_DEBUG, log);
} else {
addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Loading configuration failed"));
}
} else {
#endif // USE_SPIFFS
struct SYSCFGH {
unsigned long cfg_holder;
unsigned long saveFlag;
@ -251,70 +218,12 @@ void CFG_Load()
addLog(LOG_LEVEL_DEBUG, log);
}
}
#ifdef ALLOW_MIGRATE_TO_V3
// snprintf_P(log, sizeof(log), PSTR("Config: Check 1 for migration (%08X)"), sysCfg.version);
// addLog(LOG_LEVEL_NONE, log);
if (sysCfg.cfg_holder != CFG_HOLDER) {
if ((sysCfg.version < 0x03000000) || (sysCfg.version > 0x73000000)) {
CFG_Migrate(); // Config may be present with versions below 3.0.0
} else {
CFG_Default();
}
}
#else
if (sysCfg.cfg_holder != CFG_HOLDER) CFG_Default();
#endif // ALLOW_MIGRATE_TO_V3
_cfgHash = getHash();
RTC_Load();
}
#ifdef ALLOW_MIGRATE_TO_V3
void CFG_Migrate()
{
char log[LOGSZ];
if (spiffsPresent()) {
if (!spiffsflag) {
#ifdef USE_SPIFFS
File f = SPIFFS.open(SPIFFS_CONFIG2, "r+");
if (f) {
uint8_t *bytes = (uint8_t*)&sysCfg2;
for (int i = 0; i < sizeof(SYSCFG2); i++) bytes[i] = f.read();
f.close();
snprintf_P(log, sizeof(log), PSTR("Config: Loaded previous configuration from spiffs count %d"), sysCfg2.saveFlag);
addLog(LOG_LEVEL_DEBUG, log);
} else {
addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Loading previous configuration failed"));
}
} else {
#endif // USE_SPIFFS
struct SYSCFGH {
unsigned long cfg_holder;
unsigned long saveFlag;
} _sysCfgH;
noInterrupts();
spi_flash_read((CFG_LOCATION2) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg2, sizeof(SYSCFG2));
spi_flash_read((CFG_LOCATION2 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH));
if (sysCfg2.saveFlag < _sysCfgH.saveFlag)
spi_flash_read((CFG_LOCATION2 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg2, sizeof(SYSCFG2));
interrupts();
snprintf_P(log, sizeof(log), PSTR("Config: Loaded previous configuration from flash at %X and count %d"), CFG_LOCATION2 + (sysCfg2.saveFlag &1), sysCfg2.saveFlag);
addLog(LOG_LEVEL_DEBUG, log);
}
}
// snprintf_P(log, sizeof(log), PSTR("Config: Check 2 for migration (%08X)"), sysCfg2.version);
// addLog(LOG_LEVEL_NONE, log);
if ((sysCfg2.version > 0x01000000) && (sysCfg2.version < 0x03000000)) {
CFG_Migrate_Part2(); // Config is present between version 1.0.0 and 3.0.0
} else {
CFG_Default();
}
_cfgHash = getHash();
}
#endif // ALLOW_MIGRATE_TO_V3
void CFG_Erase()
{
char log[LOGSZ];
@ -371,37 +280,6 @@ void CFG_Dump()
}
}
#ifdef USE_SPIFFS
void initSpiffs()
{
spiffsflag = 0;
if (!spiffsPresent()) {
spiffsflag = 1;
} else {
if (!SPIFFS.begin()) {
addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: WARNING - Failed to mount file system. Will use flash"));
spiffsflag = 2;
} else {
addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Mount successful"));
File f = SPIFFS.open(SPIFFS_CONFIG, "r");
if (!f) {
addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Formatting..."));
SPIFFS.format();
addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Formatted"));
File f = SPIFFS.open(SPIFFS_CONFIG, "w");
if (f) {
for (int i = 0; i < sizeof(SYSCFG); i++) f.write(0);
f.close();
} else {
addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: WARNING - Failed to init config file. Will use flash"));
spiffsflag = 3;
}
}
}
}
}
#endif // USE_SPIFFS
/********************************************************************************************/
void CFG_DefaultSet1()
@ -418,7 +296,6 @@ void CFG_DefaultSet2()
{
sysCfg.savedata = SAVE_DATA;
sysCfg.savestate = SAVE_STATE;
// sysCfg.model = 0;
sysCfg.timezone = APP_TIMEZONE;
strlcpy(sysCfg.otaUrl, OTA_URL, sizeof(sysCfg.otaUrl));
@ -445,7 +322,6 @@ void CFG_DefaultSet2()
strlcpy(sysCfg.mqtt_topic, MQTT_TOPIC, sizeof(sysCfg.mqtt_topic));
strlcpy(sysCfg.button_topic, "0", sizeof(sysCfg.button_topic));
strlcpy(sysCfg.mqtt_grptopic, MQTT_GRPTOPIC, sizeof(sysCfg.mqtt_grptopic));
strlcpy(sysCfg.mqtt_subtopic, MQTT_SUBTOPIC, sizeof(sysCfg.mqtt_subtopic));
sysCfg.mqtt_button_retain = MQTT_BUTTON_RETAIN;
sysCfg.mqtt_power_retain = MQTT_POWER_RETAIN;
sysCfg.value_units = 0;
@ -515,6 +391,10 @@ void CFG_DefaultSet2()
// 4.0.9
CFG_DefaultSet_4_0_9();
// 4.1.1
CFG_DefaultSet_4_1_1();
}
void CFG_DefaultSet_3_2_4()
@ -574,6 +454,14 @@ void CFG_DefaultSet_4_0_9()
parseIP(&sysCfg.ip_address[3], WIFI_DNS);
}
void CFG_DefaultSet_4_1_1()
{
sysCfg.mqtt_response = 0;
strlcpy(sysCfg.state_text[0], MQTT_STATUS_OFF, sizeof(sysCfg.state_text[0]));
strlcpy(sysCfg.state_text[1], MQTT_STATUS_ON, sizeof(sysCfg.state_text[1]));
strlcpy(sysCfg.state_text[2], MQTT_CMND_TOGGLE, sizeof(sysCfg.state_text[2]));
}
void CFG_Default()
{
addLog_P(LOG_LEVEL_NONE, PSTR("Config: Use default configuration"));
@ -582,117 +470,6 @@ void CFG_Default()
CFG_Save();
}
#ifdef ALLOW_MIGRATE_TO_V3
void CFG_Migrate_Part2()
{
addLog_P(LOG_LEVEL_NONE, PSTR("Config: Migrating configuration"));
CFG_DefaultSet1();
CFG_DefaultSet2();
sysCfg.seriallog_level = sysCfg2.seriallog_level;
sysCfg.syslog_level = sysCfg2.syslog_level;
strlcpy(sysCfg.syslog_host, sysCfg2.syslog_host, sizeof(sysCfg.syslog_host));
strlcpy(sysCfg.sta_ssid[0], sysCfg2.sta_ssid1, sizeof(sysCfg.sta_ssid[0]));
strlcpy(sysCfg.sta_pwd[0], sysCfg2.sta_pwd1, sizeof(sysCfg.sta_pwd[0]));
strlcpy(sysCfg.otaUrl, sysCfg2.otaUrl, sizeof(sysCfg.otaUrl));
strlcpy(sysCfg.mqtt_host, sysCfg2.mqtt_host, sizeof(sysCfg.mqtt_host));
strlcpy(sysCfg.mqtt_grptopic, sysCfg2.mqtt_grptopic, sizeof(sysCfg.mqtt_grptopic));
strlcpy(sysCfg.mqtt_topic, sysCfg2.mqtt_topic, sizeof(sysCfg.mqtt_topic));
strlcpy(sysCfg.button_topic, sysCfg2.mqtt_topic2, sizeof(sysCfg.button_topic));
strlcpy(sysCfg.mqtt_subtopic, sysCfg2.mqtt_subtopic, sizeof(sysCfg.mqtt_subtopic));
sysCfg.timezone = sysCfg2.timezone;
sysCfg.power = sysCfg2.power;
if (sysCfg2.version >= 0x01000D00) { // 1.0.13
sysCfg.ledstate = sysCfg2.ledstate;
}
if (sysCfg2.version >= 0x01001600) { // 1.0.22
sysCfg.mqtt_port = sysCfg2.mqtt_port;
strlcpy(sysCfg.mqtt_client, sysCfg2.mqtt_client, sizeof(sysCfg.mqtt_client));
strlcpy(sysCfg.mqtt_user, sysCfg2.mqtt_user, sizeof(sysCfg.mqtt_user));
strlcpy(sysCfg.mqtt_pwd, sysCfg2.mqtt_pwd, sizeof(sysCfg.mqtt_pwd));
strlcpy(sysCfg.friendlyname[0], sysCfg2.mqtt_client, sizeof(sysCfg.friendlyname[0]));
}
if (sysCfg2.version >= 0x01001700) { // 1.0.23
sysCfg.webserver = sysCfg2.webserver;
}
if (sysCfg2.version >= 0x01001A00) { // 1.0.26
sysCfg.bootcount = sysCfg2.bootcount;
strlcpy(sysCfg.hostname, sysCfg2.hostname, sizeof(sysCfg.hostname));
sysCfg.syslog_port = sysCfg2.syslog_port;
}
if (sysCfg2.version >= 0x01001B00) { // 1.0.27
sysCfg.weblog_level = sysCfg2.weblog_level;
}
if (sysCfg2.version >= 0x01001C00) { // 1.0.28
sysCfg.tele_period = sysCfg2.tele_period;
if ((sysCfg.tele_period > 0) && (sysCfg.tele_period < 10)) sysCfg.tele_period = 10; // Do not allow periods < 10 seconds
}
if (sysCfg2.version >= 0x01002000) { // 1.0.32
sysCfg.sta_config = sysCfg2.sta_config;
}
if (sysCfg2.version >= 0x01002300) { // 1.0.35
sysCfg.savedata = sysCfg2.savedata;
}
if (sysCfg2.version >= 0x02000000) { // 2.0.0
sysCfg.model = sysCfg2.model;
}
if (sysCfg2.version >= 0x02000300) { // 2.0.3
sysCfg.mqtt_button_retain = sysCfg2.mqtt_retain;
sysCfg.savestate = sysCfg2.savestate;
}
if (sysCfg2.version >= 0x02000500) { // 2.0.5
sysCfg.hlw_pcal = sysCfg2.hlw_pcal;
sysCfg.hlw_ucal = sysCfg2.hlw_ucal;
sysCfg.hlw_ical = sysCfg2.hlw_ical;
sysCfg.hlw_kWhyesterday = sysCfg2.hlw_kWhyesterday;
sysCfg.value_units = sysCfg2.value_units;
}
if (sysCfg2.version >= 0x02000600) { // 2.0.6
sysCfg.hlw_pmin = sysCfg2.hlw_pmin;
sysCfg.hlw_pmax = sysCfg2.hlw_pmax;
sysCfg.hlw_umin = sysCfg2.hlw_umin;
sysCfg.hlw_umax = sysCfg2.hlw_umax;
sysCfg.hlw_imin = sysCfg2.hlw_imin;
sysCfg.hlw_imax = sysCfg2.hlw_imax;
}
if (sysCfg2.version >= 0x02000700) { // 2.0.7
// sysCfg.message_format = 0;
strlcpy(sysCfg.domoticz_in_topic, sysCfg2.domoticz_in_topic, sizeof(sysCfg.domoticz_in_topic));
strlcpy(sysCfg.domoticz_out_topic, sysCfg2.domoticz_out_topic, sizeof(sysCfg.domoticz_out_topic));
sysCfg.domoticz_update_timer = sysCfg2.domoticz_update_timer;
for (byte i = 0; i < 4; i++) {
sysCfg.domoticz_relay_idx[i] = sysCfg2.domoticz_relay_idx[i];
sysCfg.domoticz_key_idx[i] = sysCfg2.domoticz_key_idx[i];
}
sysCfg.hlw_mpl = sysCfg2.hlw_mpl; // MaxPowerLimit
sysCfg.hlw_mplh = sysCfg2.hlw_mplh;
sysCfg.hlw_mplw = sysCfg2.hlw_mplw;
sysCfg.hlw_mspl = sysCfg2.hlw_mspl; // MaxSafePowerLimit
sysCfg.hlw_msplh = sysCfg2.hlw_msplh;
sysCfg.hlw_msplw = sysCfg2.hlw_msplw;
sysCfg.hlw_mkwh = sysCfg2.hlw_mkwh; // MaxEnergy
sysCfg.hlw_mkwhs = sysCfg2.hlw_mkwhs; // MaxEnergyStart
}
if (sysCfg2.version >= 0x02001000) { // 2.0.16
sysCfg.hlw_kWhtoday = sysCfg2.hlw_kWhtoday;
sysCfg.hlw_kWhdoy = sysCfg2.hlw_kWhdoy;
}
if (sysCfg2.version >= 0x02001200) { // 2.0.18
sysCfg.switchmode[0] = sysCfg2.switchmode;
}
if (sysCfg2.version >= 0x02010000) { // 2.1.0
strlcpy(sysCfg.mqtt_fingerprint, sysCfg2.mqtt_fingerprint, sizeof(sysCfg.mqtt_fingerprint));
}
if (sysCfg2.version >= 0x02010200) { // 2.1.2
sysCfg.sta_active = sysCfg2.sta_active;
strlcpy(sysCfg.sta_ssid[1], sysCfg2.sta_ssid2, sizeof(sysCfg.sta_ssid[1]));
strlcpy(sysCfg.sta_pwd[1], sysCfg2.sta_pwd2, sizeof(sysCfg.sta_pwd[1]));
}
CFG_Save();
}
#endif // ALLOW_MIGRATE_TO_V3
/********************************************************************************************/
void CFG_Delta()
@ -753,6 +530,9 @@ void CFG_Delta()
if (sysCfg.version < 0x04000804) {
CFG_DefaultSet_4_0_9();
}
if (sysCfg.version < 0x04010100) {
CFG_DefaultSet_4_1_1();
}
sysCfg.version = VERSION;
}
}

View File

@ -10,12 +10,7 @@
* ====================================================
*/
//#define ALLOW_MIGRATE_TO_V3
#ifdef ALLOW_MIGRATE_TO_V3
#define VERSION 0x03092000 // 3.9.32
#else
#define VERSION 0x04010000 // 4.1.0
#endif // ALLOW_MIGRATE_TO_V3
#define VERSION 0x04010100 // 4.1.1
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL};
enum week_t {Last, First, Second, Third, Fourth};
@ -31,12 +26,6 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#include "user_config.h"
#include "user_config_override.h"
/*********************************************************************************************\
* Enable feature by removing leading // or disable feature by adding leading //
\*********************************************************************************************/
//#define USE_SPIFFS // Switch persistent configuration from flash to spiffs (+24k code, +0.6k mem)
/*********************************************************************************************\
* No user configurable items below
\*********************************************************************************************/
@ -108,7 +97,6 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#define HLW_UREF_PULSE 1950 // was 1666us = 600Hz = 220V
#define HLW_IREF_PULSE 3500 // was 1666us = 600Hz = 4.545A
#define MQTT_SUBTOPIC "POWER" // Default MQTT subtopic (POWER or LIGHT)
#define MQTT_RETRY_SECS 10 // Seconds to retry MQTT connection
#define APP_POWER 0 // Default saved power state Off
#define MAX_DEVICE 1 // Max number of devices
@ -164,9 +152,6 @@ enum butt_t {PRESSED, NOT_PRESSED};
#ifdef USE_DISCOVERY
#include <ESP8266mDNS.h> // MQTT, Webserver
#endif // USE_DISCOVERY
#ifdef USE_SPIFFS
#include <FS.h> // Config
#endif // USE_SPIFFS
#ifdef USE_I2C
#include <Wire.h> // I2C support library
#endif // USE_I2C
@ -232,6 +217,7 @@ byte otaretry = OTA_ATTEMPTS; // OTA retry counter
int restartflag = 0; // Sonoff restart flag
int wificheckflag = WIFI_RESTART; // Wifi state flag
int uptime = 0; // Current uptime in hours
boolean uptime_flg = true; // Signal latest uptime
int tele_period = 0; // Tele period timer
String Log[MAX_LOG_LINES]; // Web log buffer
byte logidx = 0; // Index in Web log buffer
@ -407,6 +393,12 @@ void json2legacy(char* stopic, char* svalue)
}
}
char* getStateText(byte state)
{
if (state > 2) state = 1;
return sysCfg.state_text[state];
}
/********************************************************************************************/
void mqtt_publish_sec(const char* topic, const char* data, boolean retained)
@ -448,7 +440,8 @@ void mqtt_publish_topic_P(uint8_t prefix, const char* subtopic, const char* data
{
char romram[16], stopic[TOPSZ];
snprintf_P(romram, sizeof(romram), subtopic);
snprintf_P(romram, sizeof(romram), ((prefix > 3) && !sysCfg.mqtt_response) ? PSTR("RESULT") : subtopic);
prefix &= 1;
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), sysCfg.mqtt_prefix[prefix +1], sysCfg.mqtt_topic, romram);
mqtt_publish(stopic, data);
}
@ -459,9 +452,10 @@ void mqtt_publishPowerState(byte device)
if ((device < 1) || (device > Maxdevice)) device = 1;
snprintf_P(sdevice, sizeof(sdevice), PSTR("%d"), device);
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"%s%s\":\"%s\"}"),
sysCfg.mqtt_subtopic, (Maxdevice > 1) ? sdevice : "", (power & (0x01 << (device -1))) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"),
sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (sysCfg.mqtt_response)?"POWER":"RESULT");
snprintf_P(svalue, sizeof(svalue), PSTR("{\"POWER%s\":\"%s\"}"),
(Maxdevice > 1) ? sdevice : "", getStateText(bitRead(power, device -1)));
mqtt_publish(stopic, svalue);
json2legacy(stopic, svalue);
mqtt_publish(stopic, svalue, sysCfg.mqtt_power_retain);
@ -473,9 +467,9 @@ void mqtt_publishPowerBlinkState(byte device)
if ((device < 1) || (device > Maxdevice)) device = 1;
snprintf_P(sdevice, sizeof(sdevice), PSTR("%d"), device);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"%s%s\":\"BLINK %s\"}"),
sysCfg.mqtt_subtopic, (Maxdevice > 1) ? sdevice : "", (blink_mask & (0x01 << (device -1))) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"POWER%s\":\"BLINK %s\"}"),
(Maxdevice > 1) ? sdevice : "", getStateText(bitRead(blink_mask, device -1)));
mqtt_publish_topic_P(4, PSTR("POWER"), svalue);
}
void mqtt_connected()
@ -610,6 +604,19 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf,
}
snprintf_P(svalue, ssvalue, PSTR("{\"MqttPort\":%d}"), sysCfg.mqtt_port);
}
else if (!strcmp(type,"MQTTRESPONSE")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
sysCfg.mqtt_response = payload;
}
snprintf_P(svalue, ssvalue, PSTR("{\"MqttResponse\":\"%s\"}"), getStateText(sysCfg.mqtt_response));
}
else if (!strcmp(type,"STATETEXT") && (index > 0) && (index <= 3)) {
if ((data_len > 0) && (data_len < sizeof(sysCfg.state_text[0]))) {
for(i = 0; i <= data_len; i++) if (dataBuf[i] == ' ') dataBuf[i] = '_';
strlcpy(sysCfg.state_text[index -1], (payload == 1) ? (index==1)?MQTT_STATUS_OFF:(index==2)?MQTT_STATUS_ON:MQTT_CMND_TOGGLE : dataBuf, sizeof(sysCfg.state_text[0]));
}
snprintf_P(svalue, ssvalue, PSTR("{\"StateText%d\":\"%s\"}"), index, getStateText(index -1));
}
#ifdef USE_MQTT_TLS
else if (!strcmp(type,"MQTTFINGERPRINT")) {
if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_fingerprint))) {
@ -645,7 +652,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf,
for(i = 0; i <= data_len; i++)
// if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_';
if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_';
strlcpy(sysCfg.mqtt_prefix[index -1], (payload == 1) ? (index==1)?SUB_PREFIX:(index==2)?PUB_PREFIX:PUB_PREFIX : dataBuf, sizeof(sysCfg.mqtt_prefix[0]));
strlcpy(sysCfg.mqtt_prefix[index -1], (payload == 1) ? (index==1)?SUB_PREFIX:(index==2)?PUB_PREFIX:PUB_PREFIX2 : dataBuf, sizeof(sysCfg.mqtt_prefix[0]));
// if (sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] == '/') sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] = 0;
restartflag = 2;
}
@ -699,7 +706,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf,
}
sysCfg.mqtt_button_retain = payload;
}
snprintf_P(svalue, ssvalue, PSTR("{\"ButtonRetain\":\"%s\"}"), (sysCfg.mqtt_button_retain) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"ButtonRetain\":\"%s\"}"), getStateText(sysCfg.mqtt_button_retain));
}
else if (!strcmp(type,"SWITCHRETAIN")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
@ -711,23 +718,20 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf,
}
sysCfg.mqtt_switch_retain = payload;
}
snprintf_P(svalue, ssvalue, PSTR("{\"SwitchRetain\":\"%s\"}"), (sysCfg.mqtt_switch_retain) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"SwitchRetain\":\"%s\"}"), getStateText(sysCfg.mqtt_switch_retain));
}
else if (!strcmp(type,"POWERRETAIN") || !strcmp(type,"LIGHTRETAIN")) {
else if (!strcmp(type,"POWERRETAIN")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
if (!payload) {
for(i = 1; i <= Maxdevice; i++) { // Clear MQTT retain in broker
snprintf_P(stemp2, sizeof(stemp2), PSTR("%d"), i);
snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/POWER%s"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : "");
mqtt_publish(stemp1, "", sysCfg.mqtt_power_retain);
snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/LIGHT%s"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : "");
mqtt_publish(stemp1, "", sysCfg.mqtt_power_retain);
}
}
sysCfg.mqtt_power_retain = payload;
}
snprintf_P(stemp1, sizeof(stemp1), PSTR("%s"), (!strcmp(sysCfg.mqtt_subtopic,"POWER")) ? "Power" : "Light");
snprintf_P(svalue, ssvalue, PSTR("{\"%sRetain\":\"%s\"}"), stemp1, (sysCfg.mqtt_power_retain) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"PowerRetain\":\"%s\"}"), getStateText(sysCfg.mqtt_power_retain));
}
#ifdef USE_DOMOTICZ
else if (domoticz_command(type, index, dataBuf, data_len, payload, svalue, ssvalue)) {
@ -815,8 +819,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
if (!strcmp(dataBufUc,"BLINK")) payload = 3;
if (!strcmp(dataBufUc,"BLINKOFF")) payload = 4;
if ((!strcmp(type,"POWER") || !strcmp(type,"LIGHT")) && (index > 0) && (index <= Maxdevice)) {
snprintf_P(sysCfg.mqtt_subtopic, sizeof(sysCfg.mqtt_subtopic), PSTR("%s"), type);
if (!strcmp(type,"POWER") && (index > 0) && (index <= Maxdevice)) {
if ((data_len == 0) || (payload > 4)) payload = 9;
do_cmnd_power(index, payload);
return;
@ -864,32 +867,32 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
if (sysCfg.savestate) sysCfg.power = power;
CFG_Save();
if (sysCfg.savedata > 1) snprintf_P(stemp1, sizeof(stemp1), PSTR("Every %d seconds"), sysCfg.savedata);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveData\":\"%s\"}"), (sysCfg.savedata) ? (sysCfg.savedata > 1) ? stemp1 : MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveData\":\"%s\"}"), (sysCfg.savedata > 1) ? stemp1 : getStateText(sysCfg.savedata));
}
else if (!strcmp(type,"SAVESTATE")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
sysCfg.savestate = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveState\":\"%s\"}"), (sysCfg.savestate) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveState\":\"%s\"}"), getStateText(sysCfg.savestate));
}
else if (!strcmp(type,"BUTTONRESTRICT")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
sysCfg.button_restrict = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"ButtonRestrict\":\"%s\"}"), (sysCfg.button_restrict) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"ButtonRestrict\":\"%s\"}"), getStateText(sysCfg.button_restrict));
}
else if (!strcmp(type,"UNITS")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
sysCfg.value_units = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Units\":\"%s\"}"), (sysCfg.value_units) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Units\":\"%s\"}"), getStateText(sysCfg.value_units));
}
else if (!strcmp(type,"MQTT")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
sysCfg.mqtt_enabled = payload;
restartflag = 2;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Mqtt\":\"%s\"}"), (sysCfg.mqtt_enabled) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Mqtt\":\"%s\"}"), getStateText(sysCfg.mqtt_enabled));
}
else if (!strcmp(type,"MODULE")) {
if ((data_len > 0) && (payload > 0) && (payload <= MAXMODULE)) {
@ -912,7 +915,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i +1, stemp1);
}
snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue);
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
mqtt_publish_topic_P(4, type, svalue);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Modules2\":\""), svalue);
jsflg = 0;
for (byte i = MAXMODULE /2; i < MAXMODULE; i++) {
@ -959,7 +962,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i, stemp1);
}
snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue);
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
mqtt_publish_topic_P(4, type, svalue);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"GPIOs2\":\""), svalue);
jsflg = 0;
for (byte i = GPIO_SENSOR_END /2; i < GPIO_SENSOR_END; i++) {
@ -1041,33 +1044,13 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"LogPort\":%d}"), sysCfg.syslog_port);
}
else if (!strcmp(type,"IPADDRESS")) {
else if (!strcmp(type,"IPADDRESS") && (index > 0) && (index <= 4)) {
if (parseIP(&address, dataBuf)) {
sysCfg.ip_address[0] = address;
restartflag = 2;
sysCfg.ip_address[index -1] = address;
// restartflag = 2;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"IPAddress\":\"%s (%s)\"}"), IPAddress(sysCfg.ip_address[0]).toString().c_str(), WiFi.localIP().toString().c_str());
}
else if (!strcmp(type,"GATEWAY")) {
if (parseIP(&address, dataBuf)) {
sysCfg.ip_address[1] = address;
restartflag = 2;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Gateway\":\"%s\"}"), IPAddress(sysCfg.ip_address[1]).toString().c_str());
}
else if (!strcmp(type,"SUBNETMASK")) {
if (parseIP(&address, dataBuf)) {
sysCfg.ip_address[2] = address;
restartflag = 2;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Subnetmask\":\"%s\"}"), IPAddress(sysCfg.ip_address[2]).toString().c_str());
}
else if (!strcmp(type,"DNSSERVER")) {
if (parseIP(&address, dataBuf)) {
sysCfg.ip_address[3] = address;
restartflag = 2;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"DnsServer\":\"%s\"}"), IPAddress(sysCfg.ip_address[3]).toString().c_str());
snprintf_P(stemp1, sizeof(stemp1), PSTR(" (%s)"), WiFi.localIP().toString().c_str());
snprintf_P(svalue, sizeof(svalue), PSTR("{\"IPAddress%d\":\"%s%s\"}"), index, IPAddress(sysCfg.ip_address[index -1]).toString().c_str(), (index == 1) ? stemp1:"");
}
else if (!strcmp(type,"NTPSERVER") && (index > 0) && (index <= 3)) {
if ((data_len > 0) && (data_len < sizeof(sysCfg.ntp_server[0]))) {
@ -1156,7 +1139,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Webserver\":\"Active for %s on %s with IP address %s\"}"),
(sysCfg.webserver == 2) ? "ADMIN" : "USER", Hostname, WiFi.localIP().toString().c_str());
} else {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Webserver\":\"%s\"}"), MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Webserver\":\"%s\"}"), getStateText(0));
}
}
else if (!strcmp(type,"WEBPASSWORD")) {
@ -1238,7 +1221,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
blinks = 0;
setLed(sysCfg.ledstate &8);
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"LedPower\":\"%s\"}"), (sysCfg.ledstate &8) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"LedPower\":\"%s\"}"), getStateText(bitRead(sysCfg.ledstate, 3)));
}
else if (!strcmp(type,"LEDSTATE")) {
if ((data_len > 0) && (payload >= 0) && (payload < MAX_LED_OPTION)) {
@ -1284,17 +1267,14 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
}
if (type == NULL) {
blinks = 201;
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands1\":\"Status, SaveData, SaveSate, Sleep, Upgrade, Otaurl, Restart, Reset, WifiConfig, Seriallog, Syslog, LogHost, LogPort, SSId1, SSId2, Password1, Password2, AP%s\"}"), (!grpflg) ? ", Hostname, Module, Modules, GPIO, GPIOs" : "");
/*
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands1\":\"Status, SaveData, SaveSate, Sleep, Upgrade, Otaurl, Restart, Reset, WifiConfig, Seriallog, Syslog, LogHost, LogPort, SSId, Password, AP, IPAddres, NTPServer, Hostname, Module, Modules, GPIO, GPIOs\"}"));
mqtt_publish_topic_P(0, PSTR("COMMANDS1"), svalue);
if (sysCfg.mqtt_enabled) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands2\":\"Mqtt, MqttHost, MqttPort, MqttUser, MqttPassword%s, GroupTopic, Units, Timezone, LedState, LedPower, TelePeriod\"}"), (!grpflg) ? ", MqttClient, Topic, ButtonTopic, ButtonRetain, SwitchTopic, SwitchRetain, PowerRetain" : "");
} else {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands2\":\"Mqtt, Units, Timezone, LedState, LedPower, TelePeriod\"}"), (!grpflg) ? ", MqttClient" : "");
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands2\":\"Mqtt, MqttResponse, MqttHost, MqttPort, MqttUser, MqttPassword, MqttClient, Topic, GroupTopic, ButtonTopic, ButtonRetain, SwitchTopic, SwitchRetain, PowerRetain, Units, Timezone, LedState, LedPower, TelePeriod\"}"));
mqtt_publish_topic_P(0, PSTR("COMMANDS2"), svalue);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands3\":\"%s%s, PulseTime, BlinkTime, BlinkCount, ButtonRestrict, NtpServer"), (Maxdevice == 1) ? "Power, Light" : "Power1, Power2, Light1 Light2", (sysCfg.module != MOTOR) ? ", PowerOnState" : "");
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands3\":\"Power%s, PulseTime, BlinkTime, BlinkCount, ButtonRestrict"), (sysCfg.module != MOTOR) ? ", PowerOnState" : "");
#ifdef USE_WEBSERVER
snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, WebPassword, Emulation"), svalue);
#endif
@ -1322,8 +1302,11 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
hlw_commands(svalue, sizeof(svalue));
mqtt_publish_topic_P(0, PSTR("COMMANDS5"), svalue);
}
*/
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Invalid command\"}"));
mqtt_publish_topic_P(0, PSTR("COMMAND"), svalue);
} else {
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
mqtt_publish_topic_P(4, type, svalue);
}
}
@ -1338,8 +1321,8 @@ void send_button_power(byte key, byte device, byte state)
if (!key && (device > Maxdevice)) device = 1;
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), device);
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s%s"),
sysCfg.mqtt_prefix[0], (key) ? sysCfg.switch_topic : sysCfg.button_topic, sysCfg.mqtt_subtopic, (key || (Maxdevice > 1)) ? stemp1 : "");
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/POWER%s"),
sysCfg.mqtt_prefix[0], (key) ? sysCfg.switch_topic : sysCfg.button_topic, (key || (Maxdevice > 1)) ? stemp1 : "");
if (state == 3) {
svalue[0] = '\0';
@ -1347,7 +1330,7 @@ void send_button_power(byte key, byte device, byte state)
if (!strcmp(sysCfg.mqtt_topic,(key) ? sysCfg.switch_topic : sysCfg.button_topic) && (state == 2)) {
state = ~(power >> (device -1)) & 0x01;
}
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), (state) ? (state == 2) ? MQTT_CMND_TOGGLE : MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), getStateText(state));
}
#ifdef USE_DOMOTICZ
if (!(domoticz_button(key, device, state, strlen(svalue)))) {
@ -1456,8 +1439,8 @@ void publish_status(uint8_t payload)
if ((!hlw_flg) && ((payload == 8) || (payload == 9))) payload = 99;
if ((payload == 0) || (payload == 99)) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Status\":{\"Module\":%d, \"FriendlyName\":\"%s\", \"Topic\":\"%s\", \"ButtonTopic\":\"%s\", \"Subtopic\":\"%s\", \"Power\":%d, \"PowerOnState\":%d, \"LedState\":%d, \"SaveData\":%d, \"SaveState\":%d, \"ButtonRetain\":%d, \"PowerRetain\":%d}}"),
sysCfg.module +1, sysCfg.friendlyname[0], sysCfg.mqtt_topic, sysCfg.button_topic, sysCfg.mqtt_subtopic, power, sysCfg.poweronstate, sysCfg.ledstate, sysCfg.savedata, sysCfg.savestate, sysCfg.mqtt_button_retain, sysCfg.mqtt_power_retain);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Status\":{\"Module\":%d, \"FriendlyName\":\"%s\", \"Topic\":\"%s\", \"ButtonTopic\":\"%s\", \"Power\":%d, \"PowerOnState\":%d, \"LedState\":%d, \"SaveData\":%d, \"SaveState\":%d, \"ButtonRetain\":%d, \"PowerRetain\":%d}}"),
sysCfg.module +1, sysCfg.friendlyname[0], sysCfg.mqtt_topic, sysCfg.button_topic, power, sysCfg.poweronstate, sysCfg.ledstate, sysCfg.savedata, sysCfg.savestate, sysCfg.mqtt_button_retain, sysCfg.mqtt_power_retain);
mqtt_publish_topic_P(option, PSTR("STATUS"), svalue);
}
@ -1529,7 +1512,7 @@ void publish_status(uint8_t payload)
}
if ((payload == 0) || (payload == 11)) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPWR\":"));
snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusSTS\":"));
state_mqttPresent(svalue, sizeof(svalue));
snprintf_P(svalue, sizeof(svalue), PSTR("%s}"), svalue);
mqtt_publish_topic_P(option, PSTR("STATUS11"), svalue);
@ -1548,11 +1531,11 @@ void state_mqttPresent(char* svalue, uint16_t ssvalue)
#endif
for (byte i = 0; i < Maxdevice; i++) {
if (Maxdevice == 1) { // Legacy
snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":"), svalue, sysCfg.mqtt_subtopic);
snprintf_P(svalue, ssvalue, PSTR("%s, \"POWER\":"), svalue);
} else {
snprintf_P(svalue, ssvalue, PSTR("%s, \"%s%d\":"), svalue, sysCfg.mqtt_subtopic, i +1);
snprintf_P(svalue, ssvalue, PSTR("%s, \"POWER%d\":"), svalue, i +1);
}
snprintf_P(svalue, ssvalue, PSTR("%s\"%s\""), svalue, (power & (0x01 << i)) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("%s\"%s\""), svalue, getStateText(bitRead(power, i)));
}
snprintf_P(svalue, ssvalue, PSTR("%s, \"Wifi\":{\"AP\":%d, \"SSID\":\"%s\", \"RSSI\":%d}}"),
svalue, sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], WIFI_getRSSIasQuality(WiFi.RSSI()));
@ -1563,9 +1546,9 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, getDateTime().c_str());
for (byte i = 0; i < 4; i++) {
if (pin[GPIO_SWT1 +i] < 99) {
byte swm = ((sysCfg.switchmode[i] == FOLLOW_INV)||(sysCfg.switchmode[i] == PUSHBUTTON_INV));
snprintf_P(svalue, ssvalue, PSTR("%s, \"Switch%d\":\"%s\""),
svalue, i +1, (lastwallswitch[i]) ? (swm) ? MQTT_STATUS_ON : MQTT_STATUS_OFF : (swm) ? MQTT_STATUS_OFF : MQTT_STATUS_ON);
boolean swm = ((sysCfg.switchmode[i] == FOLLOW_INV)||(sysCfg.switchmode[i] == PUSHBUTTON_INV));
snprintf_P(svalue, ssvalue, PSTR("%s, \"Switch%d\":\"%s\""), svalue, i +1, getStateText(swm ^ lastwallswitch[i]));
*djson = 1;
}
}
#ifndef USE_ADC_VCC
@ -1693,11 +1676,13 @@ void every_second()
if (hlw_flg) hlw_margin_chk();
if ((rtcTime.Minute == 2) && (rtcTime.Second == 30)) {
if ((rtcTime.Minute == 2) && uptime_flg) {
uptime_flg = false;
uptime++;
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", \"Uptime\":%d}"), getDateTime().c_str(), uptime);
mqtt_publish_topic_P(1, PSTR("UPTIME"), svalue);
}
if ((rtcTime.Minute == 3) && !uptime_flg) uptime_flg = true;
}
void stateloop()
@ -2154,9 +2139,6 @@ void setup()
}
if (!spiffsPresent())
addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: ERROR - No spiffs present. Please reflash with at least 16K SPIFFS"));
#ifdef USE_SPIFFS
initSpiffs();
#endif
CFG_Load();
CFG_Delta();

View File

@ -17,10 +17,10 @@
#define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable)
// -- Wifi ----------------------------------------
#define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress] Set to 0.0.0.0 for using DHCP or IP address
#define WIFI_GATEWAY "192.168.2.254" // {Gateway] If not using DHCP set Gateway IP address
#define WIFI_SUBNETMASK "255.255.255.0" // [Subnetmask] If not using DHCP set Network mask
#define WIFI_DNS "192.168.2.27" // [DnsServer] If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY)
#define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress1] Set to 0.0.0.0 for using DHCP or IP address
#define WIFI_GATEWAY "192.168.2.254" // {IpAddress2] If not using DHCP set Gateway IP address
#define WIFI_SUBNETMASK "255.255.255.0" // [IpAddress3] If not using DHCP set Network mask
#define WIFI_DNS "192.168.2.27" // [IpAddress4] If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY)
#define STA_SSID1 "indebuurt1" // [Ssid1] Wifi SSID
#define STA_PASS1 "VnsqrtnrsddbrN" // [Password1] Wifi password
@ -69,9 +69,9 @@
#define MQTT_POWER_RETAIN 0 // [PowerRetain] Power status message may send retain flag (0 = off, 1 = on)
#define MQTT_SWITCH_RETAIN 0 // [SwitchRetain] Switch may send retain flag (0 = off, 1 = on)
#define MQTT_STATUS_OFF "OFF" // Command or Status result when turned off (needs to be a string like "0" or "Off")
#define MQTT_STATUS_ON "ON" // Command or Status result when turned on (needs to be a string like "1" or "On")
#define MQTT_CMND_TOGGLE "TOGGLE" // Command to send when toggling (needs to be a string like "2" or "Toggle")
#define MQTT_STATUS_OFF "OFF" // [StateText1] Command or Status result when turned off (needs to be a string like "0" or "Off")
#define MQTT_STATUS_ON "ON" // [StateText2] Command or Status result when turned on (needs to be a string like "1" or "On")
#define MQTT_CMND_TOGGLE "TOGGLE" // [StateText3] Command to send when toggling (needs to be a string like "2" or "Toggle")
// -- MQTT - Telemetry ----------------------------
#define TELE_PERIOD 300 // [TelePeriod] Telemetry (0 = disable, 10 - 3600 seconds)
@ -137,7 +137,7 @@
#define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor
#define USE_SHT // Add I2C emulating code for SHT1X sensor
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0.3k mem)
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+3k code, 0.3k mem)
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+8k code, +1k mem) - Disable by //
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB)

View File

@ -130,6 +130,14 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"return false;"
"}"
"</script>";
const char HTTP_SCRIPT_MODULE[] PROGMEM =
"var os;"
"function sk(s,g){"
"var o=os.replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");"
"document.getElementById('g'+g).innerHTML=o;"
"}"
"function sl(){"
"var o0=\"";
const char HTTP_LNK_STYLE[] PROGMEM =
".q{float:right;width:64px;text-align:right;}"
".l{background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6O"
@ -521,6 +529,16 @@ void handleConfig()
boolean inModule(byte val, uint8_t *arr)
{
if (!val) return false; // None
#ifndef USE_I2C
if (val == GPIO_I2C_SCL) return true;
if (val == GPIO_I2C_SDA) return true;
#endif
#ifndef USE_WS2812
if (val == GPIO_WS2812) return true;
#endif
#ifndef USE_IR_REMOTE
if (val == GPIO_IRSEND) return true;
#endif
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (arr[i] == val) return true;
}
@ -551,13 +569,15 @@ void handleModule()
mytmplt cmodule;
memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule));
String func = F("var os;function sk(s,g){var o=os.replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");document.getElementById('g'+g).innerHTML=o;}function sl(){var o0=\"");
String func = FPSTR(HTTP_SCRIPT_MODULE);
for (byte j = 0; j < GPIO_SENSOR_END; j++) {
if (!inModule(j, cmodule.gp.io)) {
snprintf_P(stemp, sizeof(stemp), sensors[j]);
snprintf_P(line, sizeof(line), PSTR("%s'%d'>%02d %s-2"),
(inModule(j, cmodule.gp.io))?"<options disabled value=":"-1", j, j, stemp);
snprintf_P(line, sizeof(line), PSTR("-1'%d'>%02d %s-2"), j, j, stemp);
func += line;
}
}
func += F("\";os=o0.replace(/-1/g,\"<option value=\").replace(/-2/g,\"</option>\");");
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (cmodule.gp.io[i] == GPIO_USER) {
@ -874,7 +894,7 @@ void handleSave()
strlcpy(sysCfg.friendlyname[2], (!strlen(webServer->arg("a3").c_str())) ? FRIENDLY_NAME"3" : webServer->arg("a3").c_str(), sizeof(sysCfg.friendlyname[2]));
strlcpy(sysCfg.friendlyname[3], (!strlen(webServer->arg("a4").c_str())) ? FRIENDLY_NAME"4" : webServer->arg("a4").c_str(), sizeof(sysCfg.friendlyname[3]));
snprintf_P(log, sizeof(log), PSTR("HTTP: Other MQTT Enable %s, Emulation %d, Friendly Names %s, %s, %s and %s"),
(sysCfg.mqtt_enabled) ? MQTT_STATUS_ON : MQTT_STATUS_OFF, sysCfg.emulation, sysCfg.friendlyname[0], sysCfg.friendlyname[1], sysCfg.friendlyname[2], sysCfg.friendlyname[3]);
getStateText(sysCfg.mqtt_enabled), sysCfg.emulation, sysCfg.friendlyname[0], sysCfg.friendlyname[1], sysCfg.friendlyname[2], sysCfg.friendlyname[3]);
addLog(LOG_LEVEL_INFO, log);
break;
case 6:

View File

@ -150,8 +150,8 @@ boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uin
found = 1;
} else {
if (((power >> i) &1) == nvalue) return 1;
snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/%s%s"),
sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, sysCfg.mqtt_subtopic, (Maxdevice > 1) ? stemp1 : "");
snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/POWER%s"),
sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp1 : "");
snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue);
found = 1;
}

View File

@ -28,7 +28,24 @@ POSSIBILITY OF SUCH DAMAGE.
* IR Remote send using IRremoteESP8266 library
\*********************************************************************************************/
// * Add support for Toshiba and Mitsubishi HVAC IR control (#257)
// #define USE_IR_HVAC // Support for HVAC system using IR (+2k code)
#ifndef USE_IR_HVAC
#include <IRremoteESP8266.h>
#else
#include <IRMitsubishiAC.h> // Currently firmware.elf section `.text' will not fit in region `iram1_0_seg'
// 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;
#endif
IRsend *irsend = NULL;
@ -36,6 +53,10 @@ void ir_send_init(void)
{
irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND
irsend->begin();
#ifdef USE_IR_HVAC
mitsubir = new IRMitsubishiAC(pin[GPIO_IRSEND]);
#endif //USE_IR_HVAC
}
/*********************************************************************************************\
@ -43,8 +64,12 @@ void ir_send_init(void)
\*********************************************************************************************/
/*
* ArduinoJSON IRsend entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
* ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
IRsend:
{ "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
IRhvac:
{ "Vendor": "<Toshiba|Mitsubishi>", "Power": <0|1>, "Mode": "<Hot|Cold|Dry|Auto>", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
*/
boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
@ -55,6 +80,14 @@ boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t da
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;
// char log[LOGSZ];
if (!strcmp(type,"IRSEND")) {
if (data_len) {
StaticJsonBuffer<128> jsonBuf;
@ -82,9 +115,191 @@ boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t da
} else error = true;
if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"No protocol, bits or data\"}"));
}
#ifdef USE_IR_HVAC
else if (!strcmp(type,"IRHVAC")) {
if (data_len) {
StaticJsonBuffer<164> jsonBufer;
JsonObject &root = jsonBufer.parseObject(dataBufUc);
if (!root.success()) {
snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Invalid JSON\"}")); // JSON decode failed
} else {
snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Done\"}"));
HVAC_Vendor = root["VENDOR"];
HVAC_Power = root["POWER"];
HVAC_Mode = root["MODE"];
HVAC_FanMode = root["FANSPEED"];
HVAC_Temp = root["TEMP"];
// snprintf_P(log, sizeof(log), 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, log);
if (HVAC_Vendor == NULL || !strcmp(HVAC_Vendor,"TOSHIBA")) {
error = ir_hvac_toshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
}
else if (!strcmp(HVAC_Vendor,"MITSUBISHI")) {
error = ir_hvac_mitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
}
else error = true;
}
} else error = true;
if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Wrong parameters value for Vendor, Mode and/or 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 };
boolean error = false;
if (HVAC_Mode == NULL || !strcmp(HVAC_Mode,"HOT")) { //default HVAC_HOT
data[6] = (byte) B00000011;
}
else if (HVAC_Mode && !strcmp(HVAC_Mode,"COLD")) {
data[6] = (byte) B00000001;
}
else if (HVAC_Mode && !strcmp(HVAC_Mode,"DRY")) {
data[6] = (byte) B00000010;
}
else if (HVAC_Mode && !strcmp(HVAC_Mode,"AUTO")) {
data[6] = (byte) B00000000;
}
else error = true;
if (!HVAC_Power) data[6] = (byte) 0x07; // Turn OFF HVAC
if (HVAC_FanMode && !strcmp(HVAC_FanMode,"1")) {
data[6] = data[6] | (byte) B01000000;
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"2")) {
data[6] = data[6] | (byte) B01100000;
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"3")) {
data[6] = data[6] | (byte) B10000000;
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"4")) {
data[6] = data[6] | (byte) B10100000;
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"5")) {
data[6] = data[6] | (byte) B11000000;
}
else if (HVAC_FanMode == NULL || !strcmp(HVAC_FanMode,"AUTO")) { // default FAN_SPEED_AUTO
data[6] = data[6] | (byte) B00000000;
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"SILENT")) {
data[6] = data[6] | (byte) B00000000;
}
else error = true;
byte Temp;
if (HVAC_Temp > 30) {
Temp = 30;
}
else if (HVAC_Temp < 17) {
Temp = 17;
}
else Temp = HVAC_Temp;
data[5] = (byte) Temp - 17 << 4;
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
}
int i = 0;
byte mask = 1;
//header
rawdata[i++] = HVAC_TOSHIBA_HDR_MARK;
rawdata[i++] = HVAC_TOSHIBA_HDR_SPACE;
//data
for (int b = 0; b < HVAC_TOSHIBA_DATALEN; b++) {
for (mask = B10000000; mask > 0; mask >>= 1) { //iterate through bit mask
if (data[b] & mask) { // Bit ONE
rawdata[i++] = HVAC_TOSHIBA_BIT_MARK;
rawdata[i++] = HVAC_TOSHIBA_ONE_SPACE;
}
else { // Bit ZERO
rawdata[i++] = HVAC_TOSHIBA_BIT_MARK;
rawdata[i++] = HVAC_MISTUBISHI_ZERO_SPACE;
}
}
}
//trailer
rawdata[i++] = HVAC_TOSHIBA_RPT_MARK;
rawdata[i++] = HVAC_TOSHIBA_RPT_SPACE;
noInterrupts();
irsend->sendRaw(rawdata,i,38);
irsend->sendRaw(rawdata,i,38);
interrupts();
return error;
}
boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp)
{
boolean error = false;
char log[LOGSZ];
mitsubir->stateReset();
if (HVAC_Mode == NULL || !strcmp(HVAC_Mode,"HOT")) { // default HVAC_HOT
mitsubir->setMode(MITSUBISHI_AC_HEAT);
}
else if (HVAC_Mode && !strcmp(HVAC_Mode,"COLD")) {
mitsubir->setMode(MITSUBISHI_AC_COOL);
}
else if (HVAC_Mode && !strcmp(HVAC_Mode,"DRY")) {
mitsubir->setMode(MITSUBISHI_AC_DRY);
}
else if (HVAC_Mode && !strcmp(HVAC_Mode,"AUTO")) {
mitsubir->setMode(MITSUBISHI_AC_AUTO);
} else error = true;
mitsubir->setPower(~HVAC_Power);
if (HVAC_FanMode && !strcmp(HVAC_FanMode,"1")) {
mitsubir->setFan(1);
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"2")) {
mitsubir->setFan(2);
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"3")) {
mitsubir->setFan(3);
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"4")) {
mitsubir->setFan(4);
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"5")) {
mitsubir->setFan(5);
}
else if (HVAC_FanMode == NULL || !strcmp(HVAC_FanMode,"AUTO")) { // default FAN_SPEED_AUTO
mitsubir->setFan(MITSUBISHI_AC_FAN_AUTO);
}
else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"SILENT")) {
mitsubir->setFan(MITSUBISHI_AC_FAN_SILENT);
}
else error = true;
mitsubir->setTemp(HVAC_Temp);
mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO);
mitsubir->send();
snprintf_P(log, sizeof(log), PSTR("IRHVAC: Sent to 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, log);
return error;
}
#endif // USE_IR_HVAC
#endif // USE_IR_REMOTE

View File

@ -235,7 +235,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le
}
sl_any = 1;
}
snprintf_P(svalue, ssvalue, PSTR("{\"LedTable\":\"%s\"}"), (sysCfg.led_table) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"LedTable\":\"%s\"}"), getStateText(sysCfg.led_table));
}
else if (!strcmp(type,"FADE")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 2)) {
@ -249,7 +249,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le
break;
}
}
snprintf_P(svalue, ssvalue, PSTR("{\"Fade\":\"%s\"}"), (sysCfg.led_fade) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"Fade\":\"%s\"}"), getStateText(sysCfg.led_fade));
}
else if (!strcmp(type,"SPEED")) { // 1 - fast, 8 - slow
if ((data_len > 0) && (payload > 0) && (payload <= 8)) {
@ -283,7 +283,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le
uint16_t color = (uint16_t)sl_dcolor[0] << 8;
color += (uint16_t)sl_dcolor[1];
snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d, \"Color\":\"%04X\"}"),
(power &1)?MQTT_STATUS_ON:MQTT_STATUS_OFF, sysCfg.led_dimmer[0], color);
getStateText(power &1), sysCfg.led_dimmer[0], color);
}
return serviced;
}

View File

@ -539,7 +539,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_
}
ws2812_update();
}
snprintf_P(svalue, ssvalue, PSTR("{\"LedTable\":\"%s\"}"), (sysCfg.ws_ledtable) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"LedTable\":\"%s\"}"), getStateText(sysCfg.ws_ledtable));
}
else if (!strcmp(type,"FADE")) {
if ((data_len > 0) && (payload >= 0) && (payload <= 2)) {
@ -553,7 +553,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_
break;
}
}
snprintf_P(svalue, ssvalue, PSTR("{\"Fade\":\"%s\"}"), (sysCfg.ws_fade) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, ssvalue, PSTR("{\"Fade\":\"%s\"}"), getStateText(sysCfg.ws_fade));
}
else if (!strcmp(type,"SPEED")) { // 1 - fast, 5 - slow
if ((data_len > 0) && (payload > 0) && (payload <= 5)) {

View File

@ -28,6 +28,10 @@ POSSIBILITY OF SUCH DAMAGE.
* DS18B20 - Temperature
\*********************************************************************************************/
#define DS18S20_CHIPID 0x10
#define DS18B20_CHIPID 0x28
#define MAX31850_CHIPID 0x3B
#define W1_SKIP_ROM 0xCC
#define W1_CONVERT_TEMP 0x44
#define W1_READ_SCRATCHPAD 0xBE
@ -41,7 +45,7 @@ OneWire *ds = NULL;
uint8_t ds18x20_addr[DS18X20_MAX_SENSORS][8];
uint8_t ds18x20_idx[DS18X20_MAX_SENSORS];
uint8_t ds18x20_snsrs = 0;
char dsbstype[8];
char dsbstype[9];
void ds18x20_init()
{
@ -61,9 +65,9 @@ void ds18x20_search()
ds->reset_search();
break;
}
// If CRC Ok and Type DS18S20 or DS18B20
// If CRC Ok and Type DS18S20, DS18B20 or MAX31850
if ((OneWire::crc8(ds18x20_addr[num_sensors], 7) == ds18x20_addr[num_sensors][7]) &&
((ds18x20_addr[num_sensors][0]==0x10) || (ds18x20_addr[num_sensors][0]==0x28)))
((ds18x20_addr[num_sensors][0]==DS18S20_CHIPID) || (ds18x20_addr[num_sensors][0]==DS18B20_CHIPID) || (ds18x20_addr[num_sensors][0]==MAX31850_CHIPID)))
num_sensors++;
}
for (int i = 0; i < num_sensors; i++) ds18x20_idx[i] = i;
@ -121,7 +125,7 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t)
for (i = 0; i < 9; i++) data[i] = ds->read();
if (OneWire::crc8(data, 8) == data[8]) {
switch(ds18x20_addr[ds18x20_idx[sensor]][0]) {
case 0x10: // DS18S20
case DS18S20_CHIPID: // DS18S20
/*
// App_note AN162.pdf page 9
int temp_lsb, temp_msb;
@ -148,7 +152,8 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t)
t = (temp9 - 0.25) + ((16.0 - data[6]) / 16.0);
if(S) t = ds18x20_convertCtoF(t);
break;
case 0x28: // DS18B20
case DS18B20_CHIPID: // DS18B20
case MAX31850_CHIPID: // MAX31850
t = ((data[1] << 8) + data[0]) * 0.0625;
if(S) t = ds18x20_convertCtoF(t);
break;
@ -165,12 +170,15 @@ void ds18x20_type(uint8_t sensor)
{
strcpy_P(dsbstype, PSTR("DS18x20"));
switch(ds18x20_addr[ds18x20_idx[sensor]][0]) {
case 0x10:
case DS18S20_CHIPID:
strcpy_P(dsbstype, PSTR("DS18S20"));
break;
case 0x28:
case DS18B20_CHIPID:
strcpy_P(dsbstype, PSTR("DS18B20"));
break;
case MAX31850_CHIPID:
strcpy_P(dsbstype, PSTR("MAX31850"));
break;
}
}

View File

@ -285,7 +285,7 @@ void hlw_margin_chk()
char log[LOGSZ], svalue[200]; // was MESSZ
float ped, pi, pc;
uint16_t uped, piv, pe, pw, pu;
byte flag, jsonflg;
boolean flag, jsonflg;
if (power_steady_cntr) {
power_steady_cntr--;
@ -302,27 +302,27 @@ void hlw_margin_chk()
snprintf_P(svalue, sizeof(svalue), PSTR("{"));
jsonflg = 0;
if (hlw_margin(0, sysCfg.hlw_pmin, pw, flag, hlw_pminflg)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PowerLow\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PowerLow\":\"%s\""), svalue, (jsonflg)?", ":"", getStateText(flag));
jsonflg = 1;
}
if (hlw_margin(1, sysCfg.hlw_pmax, pw, flag, hlw_pmaxflg)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PowerHigh\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PowerHigh\":\"%s\""), svalue, (jsonflg)?", ":"", getStateText(flag));
jsonflg = 1;
}
if (hlw_margin(0, sysCfg.hlw_umin, pu, flag, hlw_uminflg)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"VoltageLow\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"VoltageLow\":\"%s\""), svalue, (jsonflg)?", ":"", getStateText(flag));
jsonflg = 1;
}
if (hlw_margin(1, sysCfg.hlw_umax, pw, flag, hlw_umaxflg)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"VoltageHigh\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"VoltageHigh\":\"%s\""), svalue, (jsonflg)?", ":"", getStateText(flag));
jsonflg = 1;
}
if (hlw_margin(0, sysCfg.hlw_imin, piv, flag, hlw_iminflg)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"CurrentLow\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"CurrentLow\":\"%s\""), svalue, (jsonflg)?", ":"", getStateText(flag));
jsonflg = 1;
}
if (hlw_margin(1, sysCfg.hlw_imax, piv, flag, hlw_imaxflg)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"CurrentHigh\":\"%s\""), svalue, (jsonflg)?", ":"", (flag) ? MQTT_STATUS_ON : MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"CurrentHigh\":\"%s\""), svalue, (jsonflg)?", ":"", getStateText(flag));
jsonflg = 1;
}
if (jsonflg) {
@ -360,11 +360,11 @@ void hlw_margin_chk()
if (hlw_mplr_counter) {
hlw_mplr_counter--;
if (hlw_mplr_counter) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"PowerMonitor\":\"%s\"}"), MQTT_STATUS_ON);
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"PowerMonitor\":\"%s\"}"), getStateText(1));
mqtt_publish_topic_P(4, PSTR("POWERMONITOR"), svalue);
do_cmnd_power(1, 1);
} else {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReachedRetry\":\"%s\"}"), MQTT_STATUS_OFF);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReachedRetry\":\"%s\"}"), getStateText(0));
mqtt_publish_topic_P(0, PSTR("WARNING"), svalue);
}
}
@ -377,8 +377,8 @@ void hlw_margin_chk()
uped = (uint16_t)(ped * 1000);
if (!hlw_mkwh_state && (rtcTime.Hour == sysCfg.hlw_mkwhs)) {
hlw_mkwh_state = 1;
snprintf_P(svalue, sizeof(svalue), PSTR("{\"EnergyMonitor\":\"%s\"}"), MQTT_STATUS_ON);
mqtt_publish_topic_P(0, PSTR("RESULT"), svalue);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"EnergyMonitor\":\"%s\"}"), getStateText(1));
mqtt_publish_topic_P(4, PSTR("ENERGYMONITOR"), svalue);
do_cmnd_power(1, 1);
}
else if ((hlw_mkwh_state == 1) && (uped >= sysCfg.hlw_mkwh)) {