diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index b14bbbf60..12e639ddc 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.4.1.15 20190208 +/* 6.4.1.16 20190211 + * Initial support for online template change using command Template (#5177) + * + * 6.4.1.15 20190208 * Change image name BE_MINIMAL to FIRMWARE_MINIMAL (#5106) * Change image names USE_xyz to FIRMWARE_xyz (#5106) * Add command SerialDelimiter 128 to filter reception of only characters between ASCII 32 and 127 (#5131) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 7eace1215..b4b3b1df7 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -170,6 +170,8 @@ #define D_RSLT_UPTIME "UPTIME" #define D_RSLT_WARNING "WARNING" +#define D_LOG_SOME_SETTINGS_RESET "Some settings have been reset" + // Commands sonoff.ino #define D_CMND_BACKLOG "Backlog" #define D_CMND_DELAY "Delay" @@ -261,7 +263,11 @@ #define D_CMND_SERIALSEND "SerialSend" #define D_CMND_SERIALDELIMITER "SerialDelimiter" #define D_CMND_BAUDRATE "Baudrate" -#define D_LOG_SOME_SETTINGS_RESET "Some settings have been reset" +#define D_CMND_TEMPLATE "Template" + #define D_JSON_NAME "NAME" + #define D_JSON_GPIO "GPIO" + #define D_JSON_FLAG "FLAG" + #define D_JSON_BASE "BASE" // Commands xdrv_01_mqtt.ino #define D_CMND_MQTTHOST "MqttHost" diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 292a61b18..176d45fb9 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 48e34a4c3..6f298912d 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 98d3cf16f..a71b01406 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 8acf24fa7..316421146 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 2d07be421..156117bac 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index b8b2f5950..68bacd865 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 2b71e0066..0e0a9ed99 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index eb4feb449..23e2f784a 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index cf924b2ac..8a093ccb3 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 3698bc57d..411087ea3 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index e33a5cf90..a5de69158 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -481,7 +481,6 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" - // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box #define D_SENSOR_NONE "Geen" #define D_SENSOR_DHT11 "DHT11" @@ -559,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index b2847923b..a501ac2fd 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -481,7 +481,6 @@ #define D_TX20_SOUTH "S" #define D_TX20_WEST "W" - // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box #define D_SENSOR_NONE "Brak" #define D_SENSOR_DHT11 "DHT11" @@ -559,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index d66ed8589..f94c0724b 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index a9d22221f..9f5516661 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index 762bfe1f5..ec8ef8543 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/sk-SK.h b/sonoff/language/sk-SK.h index 0c8d0f428..6be3edf86 100644 --- a/sonoff/language/sk-SK.h +++ b/sonoff/language/sk-SK.h @@ -481,7 +481,6 @@ #define D_TX20_SOUTH "J" #define D_TX20_WEST "Z" - // sonoff_template.h - keep them as short as possible to be able to fit them in GUI drop down box #define D_SENSOR_NONE "Žiaden" #define D_SENSOR_DHT11 "DHT11" @@ -559,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index 2c36c1d8b..ec0c9bc98 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index b41e57f10..f41f89f5a 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 47b62987b..c571a1593 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 5a581d0da..50804d307 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 602ecbe4d..46527a789 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -558,6 +558,12 @@ #define D_SENSOR_SM16716_CLK "SM16716 CLK" #define D_SENSOR_SM16716_DAT "SM16716 DAT" #define D_SENSOR_SM16716_POWER "SM16716 PWR" +#define D_SENSOR_MY92X1_DI "MY92x1 DI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_TXD "Serial Tx" +#define D_SENSOR_RXD "Serial Rx" +#define D_SENSOR_ROTARY "Rotary" // Suffix "1A" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/settings.h b/sonoff/settings.h index 22f6d940d..1698c582e 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -176,7 +176,7 @@ typedef union { uint8_t mhz19b_abc_disable : 1; // Disable ABC (Automatic Baseline Correction for MHZ19(B) (0 = Enabled (default), 1 = Disabled with Sensor15 command) }; } SensorCfg1; - + /* struct SYSCFG { unsigned long cfg_holder; // 000 Pre v6 header @@ -326,11 +326,12 @@ struct SYSCFG { Mcp230xxCfg mcp230xx_config[16]; // 6F6 uint8_t mcp230xx_int_prio; // 716 SensorCfg1 SensorBits1; // 717 On/Off settings used by Sensor Commands - uint16_t mcp230xx_int_timer; // 718 uint8_t rgbwwTable[5]; // 71A + uint8_t user_template_base; // 71F + mytmplt user_template; // 720 29 bytes - uint8_t free_71F[117]; // 71F + uint8_t free_73D[87]; // 73D uint32_t drivers[3]; // 794 uint32_t monitors; // 7A0 diff --git a/sonoff/settings.ino b/sonoff/settings.ino index b3192d50a..e15701e0b 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -596,6 +596,7 @@ void SettingsDefaultSet2(void) // Settings.flag.interlock = 0; Settings.interlock[0] = 0xFF; // Legacy support using all relays in one interlock group Settings.module = MODULE; + ModuleDefault(WEMOS); // for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { Settings.my_gp.io[i] = GPIO_NONE; } strlcpy(Settings.friendlyname[0], FRIENDLY_NAME, sizeof(Settings.friendlyname[0])); strlcpy(Settings.friendlyname[1], FRIENDLY_NAME"2", sizeof(Settings.friendlyname[1])); @@ -1050,6 +1051,9 @@ void SettingsDelta(void) if (Settings.version < 0x0604010D) { Settings.param[P_BOOT_LOOP_OFFSET] = BOOT_LOOP_OFFSET; } + if (Settings.version < 0x06040110) { + ModuleDefault(WEMOS); + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 26f03a096..f496b82e6 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -75,7 +75,7 @@ enum TasmotaCommands { CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE, CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, 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_INTERLOCK, + CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_INTERLOCK, CMND_TEMPLATE, CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE, CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, CMND_DRIVER }; const char kTasmotaCommands[] PROGMEM = @@ -85,7 +85,7 @@ const char kTasmotaCommands[] PROGMEM = 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_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" 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_INTERLOCK "|" + D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TEMPLATE "|" D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER "|" D_CMND_DRIVER; @@ -152,6 +152,7 @@ uint8_t web_log_index = 1; // Index in Web log buffer (should n uint8_t devices_present = 0; // Max number of devices supported uint8_t seriallog_level; // Current copy of Settings.seriallog_level uint8_t syslog_level; // Current copy of Settings.syslog_level +uint8_t my_module_type; // Current copy of Settings.module or user template type //uint8_t mdns_delayed_start = 0; // mDNS delayed start bool serial_local = false; // Handle serial locally; bool fallback_topic_flag = false; // Use Topic or FallbackTopic @@ -343,7 +344,7 @@ void SetDevicePower(power_t rpower, int source) if (XdrvCall(FUNC_SET_DEVICE_POWER)) { // Set power state and stop if serviced // Serviced } - else if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { + else if ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { Serial.write(0xA0); Serial.write(0x04); Serial.write(rpower &0xFF); @@ -351,7 +352,7 @@ void SetDevicePower(power_t rpower, int source) Serial.write('\n'); Serial.flush(); } - else if (EXS_RELAY == Settings.module) { + else if (EXS_RELAY == my_module_type) { SetLatchingRelay(rpower, 1); } else { @@ -384,7 +385,7 @@ uint8_t GetFanspeed(void) { uint8_t fanspeed = 0; -// if (SONOFF_IFAN02 == Settings.module) { +// if (SONOFF_IFAN02 == my_module_type) { /* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH. 000x = 0 001x = 1 @@ -577,7 +578,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) fallback_topic_flag = false; return; } - else if ((CMND_FANSPEED == command_code) && (SONOFF_IFAN02 == Settings.module)) { + else if ((CMND_FANSPEED == command_code) && (SONOFF_IFAN02 == my_module_type)) { if (data_len > 0) { if ('-' == dataBuf[0]) { payload = (int16_t)GetFanspeed() -1; @@ -653,7 +654,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESTART); } } - else if ((CMND_POWERONSTATE == command_code) && (Settings.module != MOTOR)) { + else if ((CMND_POWERONSTATE == command_code) && (my_module_type != MOTOR)) { /* 0 = Keep relays off after power on * 1 = Turn relays on after power on, if PulseTime set wait for PulseTime seconds, and turn relays off * 2 = Toggle relays after power on @@ -855,10 +856,12 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.weight_resolution); } else if (CMND_MODULE == command_code) { - if ((payload > 0) && (payload <= MAXMODULE)) { + if ((payload >= 0) && (payload <= MAXMODULE)) { + if (0 == payload) { payload = 256; } payload--; Settings.last_module = Settings.module; Settings.module = payload; + SetModuleType(); if (Settings.last_module != payload) { for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { Settings.my_gp.io[i] = GPIO_NONE; @@ -866,18 +869,22 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } restart_flag = 2; } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, Settings.module +1, ModuleName().c_str()); + uint8_t module = Settings.module; + if (USER_MODULE == Settings.module) { module = 0; } else { module++; } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, module, ModuleName().c_str()); } else if (CMND_MODULES == command_code) { - for (uint8_t i = 0; i < MAXMODULE; i++) { + for (uint8_t i = 0; i <= MAXMODULE; i++) { 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); } jsflg = true; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i +1, AnyModuleName(i).c_str()); - if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAXMODULE -1)) { + uint8_t j = i; + if (0 == i) { j = USER_MODULE; } else { j--; } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i, AnyModuleName(j).c_str()); + if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAXMODULE)) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data); MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); jsflg = false; @@ -889,7 +896,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) else if ((CMND_GPIO == command_code) && (index < sizeof(Settings.my_gp))) { myio cmodule; ModuleGpios(&cmodule); - if ((GPIO_USER == ValidGPIO(index, cmodule.io[index])) && (payload >= 0) && (payload < GPIO_SENSOR_END)) { + if (ValidGPIO(index, cmodule.io[index]) && (payload >= 0) && (payload < GPIO_SENSOR_END)) { bool present = false; for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { uint8_t midx = pgm_read_byte(kGpioNiceList + i); @@ -897,7 +904,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } if (present) { for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { - if ((GPIO_USER == ValidGPIO(i, cmodule.io[i])) && (Settings.my_gp.io[i] == payload)) { + if (ValidGPIO(i, cmodule.io[i]) && (Settings.my_gp.io[i] == payload)) { Settings.my_gp.io[i] = GPIO_NONE; } } @@ -907,7 +914,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{")); for (uint8_t i = 0; i < sizeof(Settings.my_gp); i++) { - if (GPIO_USER == ValidGPIO(i, cmodule.io[i])) { + if (ValidGPIO(i, cmodule.io[i])) { if (jsflg) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); jsflg = true; snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_GPIO "%d\":\"%d (%s)\""), @@ -927,7 +934,6 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { midx = pgm_read_byte(kGpioNiceList + i); if (!GetUsedInModule(midx, cmodule.io)) { - if (!jsflg) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_GPIOS "%d\":["), lines); } else { @@ -943,9 +949,89 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } } } - mqtt_data[0] = '\0'; } + else if (CMND_TEMPLATE == command_code) { + // {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"TYPE":255} + bool error = false; + if (!strstr(dataBuf, "{")) { // If no JSON it must be parameter + bool update = false; + if ((payload > 0) && (payload <= MAXMODULE)) { + ModuleDefault(payload -1); // Copy template module + if (USER_MODULE == Settings.module) { restart_flag = 2; } + } + else if (0 == payload) { // Copy current module with user configured GPIO + if (Settings.module < USER_MODULE) { + ModuleDefault(Settings.module); + update = true; + } + } + if (USER_MODULE == Settings.module) { // Update with latest changes + update = true; + } + if (update) { + uint8_t src = 0; + for (uint8_t dst = 0; dst < sizeof(mycfgio); dst++) { + if (6 == dst) { src = 9; } + if (8 == dst) { src = 12; } + if (Settings.my_gp.io[src] > GPIO_NONE) { + if (Settings.user_template.gp.io[dst] != Settings.my_gp.io[src]) { + Settings.user_template.gp.io[dst] = Settings.my_gp.io[src]; + if (USER_MODULE == Settings.module) { restart_flag = 2; } + } + } + src++; + } + } + } + else if (data_len > 9) { // Workaround exception if empty JSON like {} - Needs checks + StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/ + JsonObject& obj = jb.parseObject(dataBuf); + if (!obj.success()) { + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON); + error = true; + } else { + // All parameters are optional allowing for partial changes + const char* name = obj[D_JSON_NAME]; + if (name != nullptr) { + strlcpy(Settings.user_template.name, name, sizeof(Settings.user_template.name)); + } + if (obj[D_JSON_GPIO].success()) { + for (uint8_t i = 0; i < sizeof(mycfgio); i++) { + Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0; + } + } + if (obj[D_JSON_FLAG].success()) { + uint8_t flag = obj[D_JSON_FLAG] | 0; + memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag)); + } + if (obj[D_JSON_BASE].success()) { + uint8_t base = obj[D_JSON_BASE]; + if ((0 == base) || (base >= MAXMODULE)) { base = 17; } else { base--; } + Settings.user_template_base = base; // Default WEMOS + } + + // Validate GPIO +// for (uint8_t i = 0; i < sizeof(mycfgio); i++) { + // For now do not allow non-user configurable GPIO +// if ((Settings.user_template.gp.io[i] > GPIO_FIX_START) && (Settings.user_template.gp.io[i] < GPIO_USER)) { +// Settings.user_template.gp.io[i] = GPIO_NONE; +// }; +// } + if (USER_MODULE == Settings.module) { restart_flag = 2; } + } + } + if (!error) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), Settings.user_template.name); + for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", Settings.user_template.gp.io[i]); + } +// snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":\"%d (%s)\"}"), +// mqtt_data, Settings.user_template.flag, Settings.user_template_base +1, AnyModuleName(Settings.user_template_base).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), + mqtt_data, Settings.user_template.flag, Settings.user_template_base +1); + } + } else if ((CMND_PWM == command_code) && pwm_present && (index > 0) && (index <= MAX_PWMS)) { if ((payload >= 0) && (payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + index -1] < 99)) { Settings.pwm_value[index -1] = payload; @@ -1440,7 +1526,7 @@ void ExecuteCommandPower(uint8_t device, uint8_t state, int source) // ShowSource(source); - if (SONOFF_IFAN02 == Settings.module) { + if (SONOFF_IFAN02 == my_module_type) { blink_mask &= 1; // No blinking on the fan relays Settings.flag.interlock = 0; // No interlock mode as it is already done by the microcontroller Settings.pulse_timer[1] = 0; // No pulsetimers on the fan relays @@ -1576,7 +1662,7 @@ void PublishStatus(uint8_t payload) if ((0 == payload) || (99 == payload)) { uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; - if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; } + if (SONOFF_IFAN02 == my_module_type) { maxfn = 1; } stemp[0] = '\0'; for (uint8_t i = 0; i < maxfn; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), Settings.friendlyname[i]); @@ -1586,7 +1672,7 @@ void PublishStatus(uint8_t payload) snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]); } 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_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), - Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain); + (USER_MODULE == Settings.module)?0:Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS)); } @@ -1707,7 +1793,7 @@ void MqttShowState(void) LightState(1); } else { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1), Settings.flag.device_index_enable), GetStateText(bitRead(power, i))); - if (SONOFF_IFAN02 == Settings.module) { + if (SONOFF_IFAN02 == my_module_type) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_FANSPEED "\":%d"), mqtt_data, GetFanspeed()); break; } @@ -1766,7 +1852,7 @@ void PerformEverySecond(void) AddLog(LOG_LEVEL_DEBUG); } - if ((4 == uptime) && (SONOFF_IFAN02 == Settings.module)) { // Microcontroller needs 3 seconds before accepting commands + if ((4 == uptime) && (SONOFF_IFAN02 == my_module_type)) { // Microcontroller needs 3 seconds before accepting commands SetDevicePower(1, SRC_RETRY); // Sync with default power on state microcontroller being Light ON and Fan OFF SetDevicePower(power, SRC_RETRY); // Set required power on state } @@ -1922,7 +2008,7 @@ void Every250mSeconds(void) } else if (Settings.ledstate &1) { bool tstate = power; - if ((SONOFF_TOUCH == Settings.module) || (SONOFF_T11 == Settings.module) || (SONOFF_T12 == Settings.module) || (SONOFF_T13 == Settings.module)) { + if ((SONOFF_TOUCH == my_module_type) || (SONOFF_T11 == my_module_type) || (SONOFF_T12 == my_module_type) || (SONOFF_T13 == my_module_type)) { tstate = (!power) ? 1 : 0; // As requested invert signal for Touch devices to find them in the dark } SetLedPower(tstate); @@ -2157,7 +2243,7 @@ void SerialInput(void) /*-------------------------------------------------------------------------------------------*\ * Sonoff dual and ch4 19200 baud serial interface \*-------------------------------------------------------------------------------------------*/ - if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { + if ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { serial_in_byte = ButtonSerial(serial_in_byte); } @@ -2202,7 +2288,7 @@ void SerialInput(void) /*-------------------------------------------------------------------------------------------*\ * Sonoff SC 19200 baud serial interface \*-------------------------------------------------------------------------------------------*/ - if (SONOFF_SC == Settings.module) { + if (SONOFF_SC == my_module_type) { if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P serial_in_buffer[serial_in_byte_counter] = 0; // Serial data completed SonoffScSerialInput(serial_in_buffer); @@ -2250,10 +2336,12 @@ void GpioInit(void) { uint8_t mpin; - if (Settings.module >= MAXMODULE) { + if ((Settings.module >= MAXMODULE) && (Settings.module < USER_MODULE)) { Settings.module = MODULE; Settings.last_module = MODULE; } + SetModuleType(); + if (Settings.module != Settings.last_module) { baudrate = APP_BAUDRATE; } @@ -2266,15 +2354,18 @@ void GpioInit(void) } if ((def_gp.io[i] > GPIO_NONE) && (def_gp.io[i] < GPIO_USER)) { my_module.io[i] = def_gp.io[i]; + if (USER_MODULE == Settings.module) { + Settings.my_gp.io[i] = def_gp.io[i]; // Copy user template settings + } } } my_module_flag = ModuleFlag(); - for (uint8_t i = 0; i < GPIO_MAX; i++) { + for (uint16_t i = 0; i < GPIO_MAX; i++) { pin[i] = 99; } for (uint8_t i = 0; i < sizeof(my_module.io); i++) { - mpin = ValidGPIO(i, my_module.io[i]); + mpin = ValidPin(i, my_module.io[i]); // snprintf_P(log_data, sizeof(log_data), PSTR("DBG: gpio pin %d, mpin %d"), i, mpin); // AddLog(LOG_LEVEL_DEBUG); @@ -2327,7 +2418,7 @@ void GpioInit(void) if (mpin) pin[mpin] = i; } - if ((2 == pin[GPIO_TXD]) || (H801 == Settings.module)) { Serial.set_tx(2); } + if ((2 == pin[GPIO_TXD]) || (H801 == my_module_type)) { Serial.set_tx(2); } analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) @@ -2335,7 +2426,7 @@ void GpioInit(void) #ifdef USE_SPI spi_flg = ((((pin[GPIO_SPI_CS] < 99) && (pin[GPIO_SPI_CS] > 14)) || (pin[GPIO_SPI_CS] < 12)) || (((pin[GPIO_SPI_DC] < 99) && (pin[GPIO_SPI_DC] > 14)) || (pin[GPIO_SPI_DC] < 12))); if (spi_flg) { - for (uint8_t i = 0; i < GPIO_MAX; i++) { + for (uint16_t i = 0; i < GPIO_MAX; i++) { if ((pin[i] >= 12) && (pin[i] <=14)) pin[i] = 99; } my_module.io[12] = GPIO_SPI_MISO; @@ -2362,7 +2453,7 @@ void GpioInit(void) } } - if (SONOFF_BRIDGE == Settings.module) { + if (SONOFF_BRIDGE == my_module_type) { Settings.flag.mqtt_serial = 0; baudrate = 19200; } @@ -2370,34 +2461,34 @@ void GpioInit(void) if (XdrvCall(FUNC_MODULE_INIT)) { // Serviced } - else if (YTF_IR_BRIDGE == Settings.module) { + else if (YTF_IR_BRIDGE == my_module_type) { ClaimSerial(); // Stop serial loopback mode } - else if (SONOFF_DUAL == Settings.module) { + else if (SONOFF_DUAL == my_module_type) { Settings.flag.mqtt_serial = 0; devices_present = 2; baudrate = 19200; } - else if (CH4 == Settings.module) { + else if (CH4 == my_module_type) { Settings.flag.mqtt_serial = 0; devices_present = 4; baudrate = 19200; } - else if (SONOFF_SC == Settings.module) { + else if (SONOFF_SC == my_module_type) { Settings.flag.mqtt_serial = 0; devices_present = 0; baudrate = 19200; } - else if (SONOFF_BN == Settings.module) { // PWM Single color led (White) + else if (SONOFF_BN == my_module_type) { // PWM Single color led (White) light_type = LT_PWM1; } - else if (SONOFF_LED == Settings.module) { // PWM Dual color led (White warm and cold) + else if (SONOFF_LED == my_module_type) { // PWM Dual color led (White warm and cold) light_type = LT_PWM2; } - else if (AILIGHT == Settings.module) { // RGBW led + else if (AILIGHT == my_module_type) { // RGBW led light_type = LT_RGBW; } - else if (SONOFF_B1 == Settings.module) { // RGBWC led + else if (SONOFF_B1 == my_module_type) { // RGBWC led light_type = LT_RGBWC; } else { @@ -2406,7 +2497,7 @@ void GpioInit(void) if (pin[GPIO_REL1 +i] < 99) { pinMode(pin[GPIO_REL1 +i], OUTPUT); devices_present++; - if (EXS_RELAY == Settings.module) { + if (EXS_RELAY == my_module_type) { digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0); if (i &1) { devices_present--; } } @@ -2542,7 +2633,7 @@ void setup(void) WifiConnect(); - if (MOTOR == Settings.module) { Settings.poweronstate = POWER_ALL_ON; } // Needs always on else in limbo! + if (MOTOR == my_module_type) { Settings.poweronstate = POWER_ALL_ON; } // Needs always on else in limbo! if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { SetDevicePower(1, SRC_RESTART); } else { diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 64681ea91..6d48cded2 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -167,23 +167,26 @@ enum UserSelectablePins { GPIO_SM16716_CLK, // SM16716 CLOCK GPIO_SM16716_DAT, // SM16716 DATA GPIO_SM16716_SEL, // SM16716 SELECT + GPIO_DI, // my92x1 PWM input + GPIO_DCKI, // my92x1 CLK input + GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2) + GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2) + GPIO_ARIRFRCV, // AliLux RF Receive input + GPIO_TXD, // Serial interface + GPIO_RXD, // Serial interface + GPIO_ROT1A, // Rotary switch1 A Pin + GPIO_ROT1B, // Rotary switch1 B Pin + GPIO_ROT2A, // Rotary switch2 A Pin + GPIO_ROT2B, // Rotary switch2 B Pin GPIO_SENSOR_END }; -// Programmer selectable GPIO functionality offset by user selectable GPIOs +// Programmer selectable GPIO functionality enum ProgramSelectablePins { - GPIO_RXD = GPIO_SENSOR_END, // Serial interface - GPIO_TXD, // Serial interface + GPIO_FIX_START = 251, GPIO_SPI_MISO, // SPI MISO library fixed pin GPIO12 GPIO_SPI_MOSI, // SPI MOSI library fixed pin GPIO13 GPIO_SPI_CLK, // SPI Clk library fixed pin GPIO14 - GPIO_DI, // my92x1 PWM input - GPIO_DCKI, // my92x1 CLK input - GPIO_ARIRFRCV, // AliLux RF Receive input - GPIO_ROT_A, // Rotary switch A Pin - GPIO_ROT_B, // Rotary switch B Pin - GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2) - GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2) - GPIO_USER, // User configurable + GPIO_USER, // User configurable needs to be 255 GPIO_MAX }; // Text in webpage Module Parameters and commands GPIOS and GPIO @@ -233,7 +236,11 @@ const char kSensorNames[] PROGMEM = D_SENSOR_NRG_SEL "|" D_SENSOR_NRG_SEL "i|" D_SENSOR_NRG_CF1 "|" D_SENSOR_HLW_CF "|" D_SENSOR_HJL_CF "|" D_SENSOR_MCP39F5_TX "|" D_SENSOR_MCP39F5_RX "|" D_SENSOR_MCP39F5_RST "|" D_SENSOR_PN532_TX "|" D_SENSOR_PN532_RX "|" - D_SENSOR_SM16716_CLK "|" D_SENSOR_SM16716_DAT "|" D_SENSOR_SM16716_POWER + D_SENSOR_SM16716_CLK "|" D_SENSOR_SM16716_DAT "|" D_SENSOR_SM16716_POWER "|" + D_SENSOR_MY92X1_DI "|" D_SENSOR_MY92X1_DCKI "|" + D_SENSOR_CSE7766_TX "|" D_SENSOR_CSE7766_RX "|" + D_SENSOR_ARIRFRCV "|" D_SENSOR_TXD "|" D_SENSOR_RXD "|" + D_SENSOR_ROTARY "1a|" D_SENSOR_ROTARY "1b|" D_SENSOR_ROTARY "2a|" D_SENSOR_ROTARY "2b|" ; /********************************************************************************************/ @@ -311,6 +318,8 @@ enum SupportedModules { SYF05, MAXMODULE }; +#define USER_MODULE 255 + /********************************************************************************************/ #define MAX_GPIO_PIN 17 // Number of supported GPIO @@ -431,6 +440,8 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_CNTR3_NP, GPIO_CNTR4, GPIO_CNTR4_NP, + GPIO_TXD, // Serial interface + GPIO_RXD, // Serial interface #ifdef USE_I2C GPIO_I2C_SCL, // I2C SCL GPIO_I2C_SDA, // I2C SDA @@ -487,6 +498,8 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_HLW_CF, // HLW8012 CF power GPIO_HJL_CF, // HJL-01/BL0937 CF power #endif + GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2) + GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2) #if defined(USE_ENERGY_SENSOR) && defined(USE_MCP39F501) GPIO_MCP39F5_TX, // MCP39F501 Serial interface (Shelly2) GPIO_MCP39F5_RX, // MCP39F501 Serial interface (Shelly2) @@ -558,11 +571,18 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_MAX31855CLK, // MAX31855 Serial interface GPIO_MAX31855DO, // MAX31855 Serial interface #endif + GPIO_DI, // my92x1 PWM input + GPIO_DCKI, // my92x1 CLK input #ifdef USE_SM16716 GPIO_SM16716_CLK, // SM16716 CLOCK GPIO_SM16716_DAT, // SM16716 DATA GPIO_SM16716_SEL, // SM16716 SELECT #endif // USE_SM16716 + GPIO_ROT1A, // Rotary switch1 A Pin + GPIO_ROT1B, // Rotary switch1 B Pin + GPIO_ROT2A, // Rotary switch2 A Pin + GPIO_ROT2B, // Rotary switch2 B Pin + GPIO_ARIRFRCV // AliLux RF Receive input }; const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { @@ -1832,8 +1852,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) // GPIO11 (SD_CMD Flash) - GPIO_ROT_A, // GPIO12 Rotary switch A pin - GPIO_ROT_B, // GPIO13 Rotary switch B pin + GPIO_ROT1A, // GPIO12 Rotary switch A pin + GPIO_ROT1B, // GPIO13 Rotary switch B pin 0, 0, 0, 0 }, { "SP10", // Tuya SP10 (BL0937 Energy Monitoring) diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 9afa3f2b2..2c221bd1b 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0604010F +#define VERSION 0x06040110 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index b2e74addc..d915832aa 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -507,12 +507,16 @@ String PressureUnit(void) String AnyModuleName(uint8_t index) { - return FPSTR(kModules[index].name); + if (USER_MODULE == index) { + return String(Settings.user_template.name); + } else { + return FPSTR(kModules[index].name); + } } String ModuleName() { - return FPSTR(kModules[Settings.module].name); + return AnyModuleName(Settings.module); } void ModuleGpios(myio *gp) @@ -521,21 +525,22 @@ void ModuleGpios(myio *gp) memset(dest, GPIO_NONE, sizeof(myio)); uint8_t src[sizeof(mycfgio)]; - memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio)); + if (USER_MODULE == Settings.module) { +// src = Settings.user_template.gp; + memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio)); + } else { + memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio)); + } // 11 85 00 85 85 00 00 00 15 38 85 00 00 81 // AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio)); + uint8_t j = 0; for (uint8_t i = 0; i < sizeof(mycfgio); i++) { - if (i < 6) { - dest[i] = src[i]; // GPIO00 - GPIO05 - } - else if (i < 8) { - dest[i +3] = src[i]; // GPIO09 - GPIO10 - } - else { - dest[i +4] = src[i]; // GPIO12 - GPIO16 and ADC0 - } + if (6 == i) { j = 9; } + if (8 == i) { j = 12; } + dest[j] = src[i]; + j++; } // 11 85 00 85 85 00 00 00 00 00 00 00 15 38 85 00 00 81 @@ -546,10 +551,116 @@ gpio_flag ModuleFlag() { gpio_flag flag; - memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag)); + if (USER_MODULE == Settings.module) { + flag = Settings.user_template.flag; + } else { + memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag)); + } + return flag; } +void ModuleDefault(uint8_t module) +{ + if (USER_MODULE == module) { module = WEMOS; } // Generic + Settings.user_template_base = module; + memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt)); +} + +void SetModuleType() +{ + my_module_type = (USER_MODULE == Settings.module) ? Settings.user_template_base : Settings.module; +} + +uint8_t ValidPin(uint8_t pin, uint8_t gpio) +{ + uint8_t result = gpio; + if ((pin > 5) && (pin < 12)) { + result = GPIO_NONE; // Disable all flash pins + } + if (Settings.flag3.user_esp8285_enable) { + if ((pin == 9) || (pin == 10)) { + result = gpio; // Allow optional flash pins + } + } + return result; +} + +bool ValidGPIO(uint8_t pin, uint8_t gpio) +{ + bool result = false; + + if (USER_MODULE == Settings.module) { + result = (ValidPin(pin, gpio) > GPIO_NONE); // Allow any pin + } else { + result = (GPIO_USER == ValidPin(pin, gpio)); // Only allow GPIO_USER pins + } + return result; +} + +bool GetUsedInModule(uint8_t val, uint8_t *arr) +{ + int offset = 0; + + if (USER_MODULE == Settings.module) { return false; } + + if (!val) { return false; } // None + + if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) { + offset = (GPIO_KEY1_NP - GPIO_KEY1); + } + if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) { + offset = -(GPIO_KEY1_NP - GPIO_KEY1); + } + if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) { + offset = -(GPIO_KEY1_INV - GPIO_KEY1); + } + if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) { + offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1); + } + + if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) { + offset = (GPIO_SWT1_NP - GPIO_SWT1); + } + if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) { + offset = -(GPIO_SWT1_NP - GPIO_SWT1); + } + + if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) { + offset = (GPIO_REL1_INV - GPIO_REL1); + } + if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) { + offset = -(GPIO_REL1_INV - GPIO_REL1); + } + + if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) { + offset = (GPIO_LED1_INV - GPIO_LED1); + } + if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) { + offset = -(GPIO_LED1_INV - GPIO_LED1); + } + + if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) { + offset = (GPIO_PWM1_INV - GPIO_PWM1); + } + if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) { + offset = -(GPIO_PWM1_INV - GPIO_PWM1); + } + + if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) { + offset = (GPIO_CNTR1_NP - GPIO_CNTR1); + } + if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) { + offset = -(GPIO_CNTR1_NP - GPIO_CNTR1); + } + + for (uint8_t i = 0; i < MAX_GPIO_PIN; i++) { + if (arr[i] == val) { return true; } + if (arr[i] == val + offset) { return true; } + } + return false; +} + void SetGlobalValues(float temperature, float humidity) { global_update = uptime; @@ -701,67 +812,6 @@ int GetStateNumber(char *state_text) return state_number; } -bool GetUsedInModule(uint8_t val, uint8_t *arr) -{ - int offset = 0; - - if (!val) { return false; } // None - - if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) { - offset = (GPIO_KEY1_NP - GPIO_KEY1); - } - if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) { - offset = -(GPIO_KEY1_NP - GPIO_KEY1); - } - if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) { - offset = -(GPIO_KEY1_INV - GPIO_KEY1); - } - if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) { - offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1); - } - - if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) { - offset = (GPIO_SWT1_NP - GPIO_SWT1); - } - if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) { - offset = -(GPIO_SWT1_NP - GPIO_SWT1); - } - - if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) { - offset = (GPIO_REL1_INV - GPIO_REL1); - } - if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) { - offset = -(GPIO_REL1_INV - GPIO_REL1); - } - - if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) { - offset = (GPIO_LED1_INV - GPIO_LED1); - } - if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) { - offset = -(GPIO_LED1_INV - GPIO_LED1); - } - - if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) { - offset = (GPIO_PWM1_INV - GPIO_PWM1); - } - if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) { - offset = -(GPIO_PWM1_INV - GPIO_PWM1); - } - - if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) { - offset = (GPIO_CNTR1_NP - GPIO_CNTR1); - } - if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) { - offset = -(GPIO_CNTR1_NP - GPIO_CNTR1); - } - - for (uint8_t i = 0; i < MAX_GPIO_PIN; i++) { - if (arr[i] == val) { return true; } - if (arr[i] == val + offset) { return true; } - } - return false; -} - void SetSerialBaudrate(int baudrate) { Settings.baudrate = baudrate / 1200; @@ -822,15 +872,6 @@ void ShowSource(int source) } } -uint8_t ValidGPIO(uint8_t pin, uint8_t gpio) -{ - uint8_t result = gpio; - if ((WEMOS == Settings.module) && (!Settings.flag3.user_esp8285_enable)) { - if ((pin == 9) || (pin == 10)) { result = GPIO_NONE; } // Disable possible flash GPIO9 and GPIO10 - } - return result; -} - /*********************************************************************************************\ * Sleep aware time scheduler functions borrowed from ESPEasy \*********************************************************************************************/ diff --git a/sonoff/support_button.ino b/sonoff/support_button.ino index 4ed30b469..b0e6e695c 100644 --- a/sonoff/support_button.ino +++ b/sonoff/support_button.ino @@ -106,7 +106,7 @@ void ButtonHandler(void) button = NOT_PRESSED; button_present = 0; - if (!button_index && ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module))) { + if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) { button_present = 1; if (dual_button_code) { snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code); @@ -131,7 +131,7 @@ void ButtonHandler(void) if (XdrvCall(FUNC_BUTTON_PRESSED)) { // Serviced } - else if (SONOFF_4CHPRO == Settings.module) { + else if (SONOFF_4CHPRO == my_module_type) { if (holdbutton[button_index]) { holdbutton[button_index]--; } bool button_pressed = false; @@ -202,14 +202,14 @@ void ButtonHandler(void) if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) { bool single_press = false; if (multipress[button_index] < 3) { // Single or Double press - if ((SONOFF_DUAL_R2 == Settings.module) || (SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { + if ((SONOFF_DUAL_R2 == my_module_type) || (SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { single_press = true; } else { single_press = (Settings.flag.button_swap +1 == multipress[button_index]); multipress[button_index] = 1; } } - if ((MI_DESK_LAMP == Settings.module) && (button_index == 0) && (rotary_changed) && (light_power)) { + if ((MI_DESK_LAMP == my_module_type) && (button_index == 0) && (rotary_changed) && (light_power)) { rotary_changed = 0; // Color temp changed, no need to turn of the light } else { if (single_press && SendKey(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set diff --git a/sonoff/support_rotary.ino b/sonoff/support_rotary.ino index 726f45379..c8178586a 100644 --- a/sonoff/support_rotary.ino +++ b/sonoff/support_rotary.ino @@ -42,8 +42,8 @@ void update_position(void) */ s = rotary_state & 3; - if (digitalRead(pin[GPIO_ROT_A])) s |= 4; - if (digitalRead(pin[GPIO_ROT_B])) s |= 8; + if (digitalRead(pin[GPIO_ROT1A])) s |= 4; + if (digitalRead(pin[GPIO_ROT1B])) s |= 8; switch (s) { case 0: case 5: case 10: case 15: break; @@ -61,7 +61,7 @@ void update_position(void) void update_rotary(void) { - if (MI_DESK_LAMP == Settings.module){ + if (MI_DESK_LAMP == my_module_type){ if (light_power) { update_position(); } @@ -71,20 +71,20 @@ void update_rotary(void) void RotaryInit(void) { rotaries_found = 0; - if ((pin[GPIO_ROT_A] < 99) && (pin[GPIO_ROT_B] < 99)) { + if ((pin[GPIO_ROT1A] < 99) && (pin[GPIO_ROT1B] < 99)) { rotaries_found++; - pinMode(pin[GPIO_ROT_A], INPUT_PULLUP); - pinMode(pin[GPIO_ROT_B], INPUT_PULLUP); + pinMode(pin[GPIO_ROT1A], INPUT_PULLUP); + pinMode(pin[GPIO_ROT1B], INPUT_PULLUP); // GPIO6-GPIO11 are typically used to interface with the flash memory IC on // most esp8266 modules, so we should avoid adding interrupts to these pins. - if ((pin[GPIO_ROT_A] < 6) || (pin[GPIO_ROT_A] > 11)) { - attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT_A]), update_rotary, CHANGE); + if ((pin[GPIO_ROT1A] < 6) || (pin[GPIO_ROT1A] > 11)) { + attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT1A]), update_rotary, CHANGE); interrupts_in_use++; } - if ((pin[GPIO_ROT_B] < 6) || (pin[GPIO_ROT_B] > 11)) { - attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT_B]), update_rotary, CHANGE); + if ((pin[GPIO_ROT1B] < 6) || (pin[GPIO_ROT1B] > 11)) { + attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT1B]), update_rotary, CHANGE); interrupts_in_use++; } } @@ -103,7 +103,7 @@ void RotaryHandler(void) noInterrupts(); } if (rotary_last_position != rotary_position) { - if (MI_DESK_LAMP == Settings.module) { // Mi Desk lamp + if (MI_DESK_LAMP == my_module_type) { // Mi Desk lamp if (holdbutton[0]) { rotary_changed = 1; // button1 is pressed: set color temperature diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index 449ae6e35..756805425 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -640,7 +640,7 @@ void HandleRoot(void) } page += FPSTR(HTTP_TABLE100); page += F("
%s " D_GPIO "%d %s |