sonoff.ino 120 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844
  1. /*
  2. sonoff.ino - Sonoff-Tasmota firmware for iTead Sonoff, Wemos and NodeMCU hardware
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*====================================================
  16. Prerequisites:
  17. - Change libraries/PubSubClient/src/PubSubClient.h
  18. #define MQTT_MAX_PACKET_SIZE 1000
  19. - Select IDE Tools - Flash Mode: "DOUT"
  20. - Select IDE Tools - Flash Size: "1M (no SPIFFS)"
  21. ====================================================*/
  22. // Location specific includes
  23. #include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
  24. #include "sonoff_version.h" // Sonoff-Tasmota version information
  25. #include "sonoff.h" // Enumeration used in my_user_config.h
  26. #include "my_user_config.h" // Fixed user configurable options
  27. #ifdef USE_CONFIG_OVERRIDE
  28. #include "user_config_override.h" // Configuration overrides for my_user_config.h
  29. #endif
  30. #include "sonoff_post.h" // Configuration overrides for all previous includes
  31. #include "i18n.h" // Language support configured by my_user_config.h
  32. #include "sonoff_template.h" // Hardware configuration
  33. #ifdef ARDUINO_ESP8266_RELEASE_2_4_0
  34. #include "lwip/init.h"
  35. #if LWIP_VERSION_MAJOR != 1
  36. #error Please use stable lwIP v1.4
  37. #endif
  38. #endif
  39. // Libraries
  40. #include <ESP8266HTTPClient.h> // Ota
  41. #include <ESP8266httpUpdate.h> // Ota
  42. #include <StreamString.h> // Webserver, Updater
  43. #include <ArduinoJson.h> // WemoHue, IRremote, Domoticz
  44. #ifdef USE_ARDUINO_OTA
  45. #include <ArduinoOTA.h> // Arduino OTA
  46. #ifndef USE_DISCOVERY
  47. #define USE_DISCOVERY
  48. #endif
  49. #endif // USE_ARDUINO_OTA
  50. #ifdef USE_DISCOVERY
  51. #include <ESP8266mDNS.h> // MQTT, Webserver, Arduino OTA
  52. #endif // USE_DISCOVERY
  53. #ifdef USE_I2C
  54. #include <Wire.h> // I2C support library
  55. #endif // USE_I2C
  56. #ifdef USE_SPI
  57. #include <SPI.h> // SPI support, TFT
  58. #endif // USE_SPI
  59. // Structs
  60. #include "settings.h"
  61. enum TasmotaCommands {
  62. CMND_BACKLOG, CMND_DELAY, CMND_POWER, CMND_FANSPEED, CMND_STATUS, CMND_STATE, CMND_POWERONSTATE, CMND_PULSETIME,
  63. CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SENSOR, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION,
  64. CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_FREQUENCY_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_WEIGHT_RESOLUTION,
  65. CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE,
  66. CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG,
  67. CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
  68. CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE,
  69. CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE,
  70. CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, CMND_DRIVER };
  71. const char kTasmotaCommands[] PROGMEM =
  72. D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_FANSPEED "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|"
  73. D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
  74. D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_WEIGHT_RESOLUTION "|"
  75. 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 "|"
  76. 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 "|"
  77. D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
  78. D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|"
  79. 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 "|"
  80. D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER "|" D_CMND_DRIVER;
  81. const char kSleepMode[] PROGMEM = "Dynamic|Normal";
  82. // Global variables
  83. SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit
  84. WiFiUDP PortUdp; // UDP Syslog and Alexa
  85. unsigned long feature_drv1; // Compiled driver feature map
  86. unsigned long feature_drv2; // Compiled driver feature map
  87. unsigned long feature_sns1; // Compiled sensor feature map
  88. unsigned long feature_sns2; // Compiled sensor feature map
  89. unsigned long serial_polling_window = 0; // Serial polling window
  90. unsigned long state_second = 0; // State second timer
  91. unsigned long state_50msecond = 0; // State 50msecond timer
  92. unsigned long state_100msecond = 0; // State 100msecond timer
  93. unsigned long state_250msecond = 0; // State 250msecond timer
  94. unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer
  95. unsigned long blink_timer = 0; // Power cycle timer
  96. unsigned long backlog_delay = 0; // Command backlog delay
  97. unsigned long button_debounce = 0; // Button debounce timer
  98. unsigned long switch_debounce = 0; // Switch debounce timer
  99. power_t power = 0; // Current copy of Settings.power
  100. power_t blink_power; // Blink power state
  101. power_t blink_mask = 0; // Blink relay active mask
  102. power_t blink_powersave; // Blink start power save state
  103. power_t latching_power = 0; // Power state at latching start
  104. power_t rel_inverted = 0; // Relay inverted flag (1 = (0 = On, 1 = Off))
  105. int baudrate = APP_BAUDRATE; // Serial interface baud rate
  106. int serial_in_byte_counter = 0; // Index in receive buffer
  107. int ota_state_flag = 0; // OTA state flag
  108. int ota_result = 0; // OTA result
  109. int restart_flag = 0; // Sonoff restart flag
  110. int wifi_state_flag = WIFI_RESTART; // Wifi state flag
  111. int tele_period = 1; // Tele period timer
  112. int blinks = 201; // Number of LED blinks
  113. uint32_t uptime = 0; // Counting every second until 4294967295 = 130 year
  114. uint32_t loop_load_avg = 0; // Indicative loop load average
  115. uint32_t global_update = 0; // Timestamp of last global temperature and humidity update
  116. float global_temperature = 0; // Provide a global temperature to be used by some sensors
  117. float global_humidity = 0; // Provide a global humidity to be used by some sensors
  118. char *ota_url; // OTA url string pointer
  119. uint16_t dual_button_code = 0; // Sonoff dual received code
  120. uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command
  121. uint16_t blink_counter = 0; // Number of blink cycles
  122. uint16_t seriallog_timer = 0; // Timer to disable Seriallog
  123. uint16_t syslog_timer = 0; // Timer to re-enable syslog_level
  124. uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold
  125. uint16_t switch_no_pullup = 0; // Switch pull-up bitmask flags
  126. int16_t save_data_counter; // Counter and flag for config save to Flash
  127. RulesBitfield rules_flag; // Rule state flags (16 bits)
  128. uint8_t serial_local = 0; // Handle serial locally;
  129. uint8_t fallback_topic_flag = 0; // Use Topic or FallbackTopic
  130. uint8_t state_250mS = 0; // State 250msecond per second flag
  131. uint8_t latching_relay_pulse = 0; // Latching relay pulse timer
  132. uint8_t backlog_index = 0; // Command backlog index
  133. uint8_t backlog_pointer = 0; // Command backlog pointer
  134. uint8_t backlog_mutex = 0; // Command backlog pending
  135. uint8_t interlock_mutex = 0; // Interlock power command pending
  136. uint8_t sleep; // Current copy of Settings.sleep
  137. uint8_t stop_flash_rotate = 0; // Allow flash configuration rotation
  138. uint8_t blinkstate = 0; // LED state
  139. uint8_t blinkspeed = 1; // LED blink rate
  140. uint8_t lastbutton[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; // Last button states
  141. uint8_t multiwindow[MAX_KEYS] = { 0 }; // Max time between button presses to record press count
  142. uint8_t multipress[MAX_KEYS] = { 0 }; // Number of button presses within multiwindow
  143. uint8_t lastwallswitch[MAX_SWITCHES]; // Last wall switch states
  144. uint8_t holdwallswitch[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold
  145. uint8_t virtualswitch[MAX_SWITCHES]; // Virtual switch states
  146. uint8_t pin[GPIO_MAX]; // Possible pin configurations
  147. uint8_t led_inverted = 0; // LED inverted flag (1 = (0 = On, 1 = Off))
  148. uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted)
  149. uint8_t counter_no_pullup = 0; // Counter input pullup flag (1 = No pullup)
  150. uint8_t dht_flg = 0; // DHT configured
  151. uint8_t energy_flg = 0; // Energy monitor configured
  152. uint8_t i2c_flg = 0; // I2C configured
  153. uint8_t spi_flg = 0; // SPI configured
  154. uint8_t soft_spi_flg = 0; // Software SPI configured
  155. uint8_t light_type = 0; // Light types
  156. uint8_t ntp_force_sync = 0; // Force NTP sync
  157. byte serial_in_byte; // Received byte
  158. byte dual_hex_code = 0; // Sonoff dual input flag
  159. byte ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter
  160. byte web_log_index = 1; // Index in Web log buffer (should never be 0)
  161. byte reset_web_log_flag = 0; // Reset web console log
  162. byte devices_present = 0; // Max number of devices supported
  163. byte seriallog_level; // Current copy of Settings.seriallog_level
  164. byte syslog_level; // Current copy of Settings.syslog_level
  165. byte mdns_delayed_start = 0; // mDNS delayed start
  166. boolean latest_uptime_flag = true; // Signal latest uptime
  167. boolean pwm_present = false; // Any PWM channel configured with SetOption15 0
  168. boolean mdns_begun = false; // mDNS active
  169. mytmplt my_module; // Active copy of Module name and GPIOs (23 x 8 bits)
  170. StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits)
  171. char my_version[33]; // Composed version string
  172. char my_image[33]; // Code image and/or commit
  173. char my_hostname[33]; // Composed Wifi hostname
  174. char mqtt_client[33]; // Composed MQTT Clientname
  175. char mqtt_topic[33]; // Composed MQTT topic
  176. char serial_in_buffer[INPUT_BUFFER_SIZE]; // Receive buffer
  177. char mqtt_data[MESSZ]; // MQTT publish buffer and web page ajax buffer
  178. char log_data[LOGSZ]; // Logging
  179. char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
  180. String backlog[MAX_BACKLOG]; // Command backlog
  181. /********************************************************************************************/
  182. char* Format(char* output, const char* input, int size)
  183. {
  184. char *token;
  185. uint8_t digits = 0;
  186. if (strstr(input, "%")) {
  187. strlcpy(output, input, size);
  188. token = strtok(output, "%");
  189. if (strstr(input, "%") == input) {
  190. output[0] = '\0';
  191. } else {
  192. token = strtok(NULL, "");
  193. }
  194. if (token != NULL) {
  195. digits = atoi(token);
  196. if (digits) {
  197. if (strchr(token, 'd')) {
  198. snprintf_P(output, size, PSTR("%s%c0%dd"), output, '%', digits);
  199. snprintf_P(output, size, output, ESP.getChipId() & 0x1fff); // %04d - short chip ID in dec, like in hostname
  200. } else {
  201. snprintf_P(output, size, PSTR("%s%c0%dX"), output, '%', digits);
  202. snprintf_P(output, size, output, ESP.getChipId()); // %06X - full chip ID in hex
  203. }
  204. } else {
  205. if (strchr(token, 'd')) {
  206. snprintf_P(output, size, PSTR("%s%d"), output, ESP.getChipId()); // %d - full chip ID in dec
  207. digits = 8;
  208. }
  209. }
  210. }
  211. }
  212. if (!digits) strlcpy(output, input, size);
  213. return output;
  214. }
  215. char* GetOtaUrl(char *otaurl, size_t otaurl_size)
  216. {
  217. if (strstr(Settings.ota_url, "%04d") != NULL) { // OTA url contains placeholder for chip ID
  218. snprintf(otaurl, otaurl_size, Settings.ota_url, ESP.getChipId() & 0x1fff);
  219. }
  220. else if (strstr(Settings.ota_url, "%d") != NULL) { // OTA url contains placeholder for chip ID
  221. snprintf_P(otaurl, otaurl_size, Settings.ota_url, ESP.getChipId());
  222. }
  223. else {
  224. snprintf(otaurl, otaurl_size, Settings.ota_url);
  225. }
  226. return otaurl;
  227. }
  228. char* GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic)
  229. {
  230. /* prefix 0 = Cmnd
  231. prefix 1 = Stat
  232. prefix 2 = Tele
  233. prefix 4 = Cmnd fallback
  234. prefix 5 = Stat fallback
  235. prefix 6 = Tele fallback
  236. */
  237. char romram[CMDSZ];
  238. String fulltopic;
  239. snprintf_P(romram, sizeof(romram), subtopic);
  240. if (fallback_topic_flag || (prefix > 3)) {
  241. prefix &= 3;
  242. fulltopic = FPSTR(kPrefixes[prefix]);
  243. fulltopic += F("/");
  244. fulltopic += mqtt_client;
  245. fulltopic += F("_fb"); // cmnd/<mqttclient>_fb
  246. } else {
  247. fulltopic = Settings.mqtt_fulltopic;
  248. if ((0 == prefix) && (-1 == fulltopic.indexOf(F(MQTT_TOKEN_PREFIX)))) {
  249. fulltopic += F("/" MQTT_TOKEN_PREFIX); // Need prefix for commands to handle mqtt topic loops
  250. }
  251. for (byte i = 0; i < 3; i++) {
  252. if ('\0' == Settings.mqtt_prefix[i][0]) {
  253. snprintf_P(Settings.mqtt_prefix[i], sizeof(Settings.mqtt_prefix[i]), kPrefixes[i]);
  254. }
  255. }
  256. fulltopic.replace(F(MQTT_TOKEN_PREFIX), Settings.mqtt_prefix[prefix]);
  257. fulltopic.replace(F(MQTT_TOKEN_TOPIC), topic);
  258. fulltopic.replace(F(MQTT_TOKEN_HOSTNAME), my_hostname);
  259. String token_id = WiFi.macAddress();
  260. token_id.replace(":", "");
  261. fulltopic.replace(F(MQTT_TOKEN_ID), token_id);
  262. }
  263. fulltopic.replace(F("#"), "");
  264. fulltopic.replace(F("//"), "/");
  265. if (!fulltopic.endsWith("/")) fulltopic += "/";
  266. snprintf_P(stopic, TOPSZ, PSTR("%s%s"), fulltopic.c_str(), romram);
  267. return stopic;
  268. }
  269. char* GetFallbackTopic_P(char *stopic, byte prefix, const char* subtopic)
  270. {
  271. return GetTopic_P(stopic, prefix +4, NULL, subtopic);
  272. }
  273. char* GetStateText(byte state)
  274. {
  275. if (state > 3) state = 1;
  276. return Settings.state_text[state];
  277. }
  278. /********************************************************************************************/
  279. void SetLatchingRelay(power_t lpower, uint8_t state)
  280. {
  281. // power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
  282. // power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
  283. // power xx10 - toggle REL1 (Off) and REL4 (On) - device 1 Off, device 2 On
  284. // power xx11 - toggle REL2 (On) and REL4 (On) - device 1 On, device 2 On
  285. if (state && !latching_relay_pulse) { // Set latching relay to power if previous pulse has finished
  286. latching_power = lpower;
  287. latching_relay_pulse = 2; // max 200mS (initiated by stateloop())
  288. }
  289. for (byte i = 0; i < devices_present; i++) {
  290. uint8_t port = (i << 1) + ((latching_power >> i) &1);
  291. if (pin[GPIO_REL1 +port] < 99) {
  292. digitalWrite(pin[GPIO_REL1 +port], bitRead(rel_inverted, port) ? !state : state);
  293. }
  294. }
  295. }
  296. void SetDevicePower(power_t rpower, int source)
  297. {
  298. uint8_t state;
  299. ShowSource(source);
  300. if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { // All on and stay on
  301. power = (1 << devices_present) -1;
  302. rpower = power;
  303. }
  304. if (Settings.flag.interlock) { // Allow only one or no relay set
  305. power_t mask = 1;
  306. uint8_t count = 0;
  307. for (byte i = 0; i < devices_present; i++) {
  308. if (rpower & mask) count++;
  309. mask <<= 1;
  310. }
  311. if (count > 1) {
  312. power = 0;
  313. rpower = 0;
  314. }
  315. }
  316. XdrvMailbox.index = rpower;
  317. XdrvCall(FUNC_SET_POWER); // Signal power state
  318. XdrvMailbox.index = rpower;
  319. XdrvMailbox.payload = source;
  320. if (XdrvCall(FUNC_SET_DEVICE_POWER)) { // Set power state and stop if serviced
  321. // Serviced
  322. }
  323. else if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
  324. Serial.write(0xA0);
  325. Serial.write(0x04);
  326. Serial.write(rpower &0xFF);
  327. Serial.write(0xA1);
  328. Serial.write('\n');
  329. Serial.flush();
  330. }
  331. else if (EXS_RELAY == Settings.module) {
  332. SetLatchingRelay(rpower, 1);
  333. }
  334. else {
  335. for (byte i = 0; i < devices_present; i++) {
  336. state = rpower &1;
  337. if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
  338. digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? !state : state);
  339. }
  340. rpower >>= 1;
  341. }
  342. }
  343. }
  344. void SetLedPower(uint8_t state)
  345. {
  346. if (state) state = 1;
  347. digitalWrite(pin[GPIO_LED1], (bitRead(led_inverted, 0)) ? !state : state);
  348. }
  349. uint8_t GetFanspeed(void)
  350. {
  351. uint8_t fanspeed = 0;
  352. // if (SONOFF_IFAN02 == Settings.module) {
  353. /* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH.
  354. 000x = 0
  355. 001x = 1
  356. 011x = 2
  357. 101x = 3
  358. */
  359. fanspeed = (uint8_t)(power &0xF) >> 1;
  360. if (fanspeed) { fanspeed = (fanspeed >> 1) +1; }
  361. // }
  362. return fanspeed;
  363. }
  364. void SetFanspeed(uint8_t fanspeed)
  365. {
  366. for (byte i = 0; i < MAX_FAN_SPEED -1; i++) {
  367. uint8_t state = kIFan02Speed[fanspeed][i];
  368. // uint8_t state = pgm_read_byte(kIFan02Speed +(speed *3) +i);
  369. ExecuteCommandPower(i +2, state, SRC_IGNORE); // Use relay 2, 3 and 4
  370. }
  371. #ifdef USE_DOMOTICZ
  372. DomoticzUpdateFanState(); // Command FanSpeed feedback
  373. #endif // USE_DOMOTICZ
  374. }
  375. void SetPulseTimer(uint8_t index, uint16_t time)
  376. {
  377. pulse_timer[index] = (time > 111) ? millis() + (1000 * (time - 100)) : (time > 0) ? millis() + (100 * time) : 0L;
  378. }
  379. uint16_t GetPulseTimer(uint8_t index)
  380. {
  381. uint16_t result = 0;
  382. long time = TimePassedSince(pulse_timer[index]);
  383. if (time < 0) {
  384. time *= -1;
  385. result = (time > 11100) ? (time / 1000) + 100 : (time > 0) ? time / 100 : 0;
  386. }
  387. return result;
  388. }
  389. /********************************************************************************************/
  390. void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
  391. {
  392. char *str;
  393. if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1])) {
  394. str = strstr(topic,Settings.mqtt_prefix[0]);
  395. if ((str == topic) && mqtt_cmnd_publish) {
  396. if (mqtt_cmnd_publish > 3) {
  397. mqtt_cmnd_publish -= 3;
  398. } else {
  399. mqtt_cmnd_publish = 0;
  400. }
  401. return;
  402. }
  403. }
  404. char topicBuf[TOPSZ];
  405. char dataBuf[data_len+1];
  406. char command [CMDSZ];
  407. char stemp1[TOPSZ];
  408. char *p;
  409. char *type = NULL;
  410. byte jsflg = 0;
  411. byte lines = 1;
  412. uint8_t grpflg = 0;
  413. // uint8_t user_append_index = 0;
  414. uint16_t i = 0;
  415. uint16_t index;
  416. uint32_t address;
  417. ShowFreeMem(PSTR("MqttDataHandler"));
  418. strlcpy(topicBuf, topic, sizeof(topicBuf));
  419. for (i = 0; i < data_len; i++) {
  420. if (!isspace(data[i])) break;
  421. }
  422. data_len -= i;
  423. memcpy(dataBuf, data +i, sizeof(dataBuf));
  424. dataBuf[sizeof(dataBuf)-1] = 0;
  425. if (topicBuf[0] != '/') { ShowSource(SRC_MQTT); }
  426. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RESULT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s"),
  427. topicBuf, data_len, dataBuf);
  428. AddLog(LOG_LEVEL_DEBUG_MORE);
  429. // if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) Serial.println(dataBuf);
  430. if (XdrvMqttData(topicBuf, sizeof(topicBuf), dataBuf, sizeof(dataBuf))) return;
  431. grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != NULL);
  432. GetFallbackTopic_P(stemp1, CMND, ""); // Full Fallback topic = cmnd/DVES_xxxxxxxx_fb/
  433. fallback_topic_flag = (!strncmp(topicBuf, stemp1, strlen(stemp1)));
  434. type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type)
  435. index = 1;
  436. if (type != NULL) {
  437. type++;
  438. for (i = 0; i < strlen(type); i++) {
  439. type[i] = toupper(type[i]);
  440. }
  441. while (isdigit(type[i-1])) {
  442. i--;
  443. }
  444. if (i < strlen(type)) {
  445. index = atoi(type +i);
  446. // user_append_index = 1;
  447. }
  448. type[i] = '\0';
  449. }
  450. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_RESULT D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " %s, " D_DATA " %s"),
  451. grpflg, index, type, dataBuf);
  452. AddLog(LOG_LEVEL_DEBUG);
  453. if (type != NULL) {
  454. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}"));
  455. if (Settings.ledstate &0x02) blinks++;
  456. if (!strcmp(dataBuf,"?")) data_len = 0;
  457. int16_t payload = -99; // No payload
  458. uint16_t payload16 = 0;
  459. long payload32 = strtol(dataBuf, &p, 10);
  460. if (p != dataBuf) {
  461. payload = (int16_t) payload32; // -32766 - 32767
  462. payload16 = (uint16_t) payload32; // 0 - 65535
  463. } else {
  464. payload32 = 0;
  465. }
  466. backlog_delay = millis() + (100 * MIN_BACKLOG_DELAY);
  467. int temp_payload = GetStateNumber(dataBuf);
  468. if (temp_payload > -1) { payload = temp_payload; }
  469. // snprintf_P(log_data, sizeof(log_data), PSTR("RSLT: Payload %d, Payload16 %d"), payload, payload16);
  470. // AddLog(LOG_LEVEL_DEBUG);
  471. int command_code = GetCommandCode(command, sizeof(command), type, kTasmotaCommands);
  472. if (-1 == command_code) {
  473. if (!XdrvCommand(grpflg, type, index, dataBuf, data_len, payload, payload16)) {
  474. type = NULL; // Unknown command
  475. }
  476. }
  477. else if (CMND_BACKLOG == command_code) {
  478. if (data_len) {
  479. uint8_t bl_pointer = (!backlog_pointer) ? MAX_BACKLOG -1 : backlog_pointer;
  480. bl_pointer--;
  481. char *blcommand = strtok(dataBuf, ";");
  482. while ((blcommand != NULL) && (backlog_index != bl_pointer)) {
  483. while(true) {
  484. blcommand = Trim(blcommand);
  485. if (!strncasecmp_P(blcommand, PSTR(D_CMND_BACKLOG), strlen(D_CMND_BACKLOG))) {
  486. blcommand += strlen(D_CMND_BACKLOG); // Skip unnecessary command Backlog
  487. } else {
  488. break;
  489. }
  490. }
  491. if (*blcommand != '\0') {
  492. backlog[backlog_index] = String(blcommand);
  493. backlog_index++;
  494. if (backlog_index >= MAX_BACKLOG) backlog_index = 0;
  495. }
  496. blcommand = strtok(NULL, ";");
  497. }
  498. // snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_APPENDED);
  499. mqtt_data[0] = '\0';
  500. } else {
  501. uint8_t blflag = (backlog_pointer == backlog_index);
  502. backlog_pointer = backlog_index;
  503. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, blflag ? D_JSON_EMPTY : D_JSON_ABORTED);
  504. }
  505. }
  506. else if (CMND_DELAY == command_code) {
  507. if ((payload >= MIN_BACKLOG_DELAY) && (payload <= 3600)) {
  508. backlog_delay = millis() + (100 * payload);
  509. }
  510. uint16_t bl_delay = 0;
  511. long bl_delta = TimePassedSince(backlog_delay);
  512. if (bl_delta < 0) { bl_delay = (bl_delta *-1) / 100; }
  513. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, bl_delay);
  514. }
  515. else if ((CMND_POWER == command_code) && (index > 0) && (index <= devices_present)) {
  516. if ((payload < 0) || (payload > 4)) payload = 9;
  517. // Settings.flag.device_index_enable = user_append_index;
  518. ExecuteCommandPower(index, payload, SRC_IGNORE);
  519. fallback_topic_flag = 0;
  520. return;
  521. }
  522. else if ((CMND_FANSPEED == command_code) && (SONOFF_IFAN02 == Settings.module)) {
  523. if (data_len > 0) {
  524. if ('-' == dataBuf[0]) {
  525. payload = (int16_t)GetFanspeed() -1;
  526. if (payload < 0) { payload = MAX_FAN_SPEED -1; }
  527. }
  528. else if ('+' == dataBuf[0]) {
  529. payload = GetFanspeed() +1;
  530. if (payload > MAX_FAN_SPEED -1) { payload = 0; }
  531. }
  532. }
  533. if ((payload >= 0) && (payload < MAX_FAN_SPEED) && (payload != GetFanspeed())) {
  534. SetFanspeed(payload);
  535. }
  536. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, GetFanspeed());
  537. }
  538. else if (CMND_STATUS == command_code) {
  539. if ((payload < 0) || (payload > MAX_STATUS)) payload = 99;
  540. PublishStatus(payload);
  541. fallback_topic_flag = 0;
  542. return;
  543. }
  544. else if (CMND_STATE == command_code) {
  545. mqtt_data[0] = '\0';
  546. MqttShowState();
  547. if (Settings.flag3.hass_tele_on_power) {
  548. MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN);
  549. }
  550. }
  551. else if (CMND_SLEEP == command_code) {
  552. if ((payload >= 0) && (payload < 251)) {
  553. Settings.sleep = payload;
  554. sleep = payload;
  555. WiFiSetSleepMode();
  556. }
  557. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_UNIT_NVALUE_UNIT, command, sleep, (Settings.flag.value_units) ? " " D_UNIT_MILLISECOND : "", Settings.sleep, (Settings.flag.value_units) ? " " D_UNIT_MILLISECOND : "");
  558. }
  559. else if ((CMND_UPGRADE == command_code) || (CMND_UPLOAD == command_code)) {
  560. // Check if the payload is numerically 1, and had no trailing chars.
  561. // e.g. "1foo" or "1.2.3" could fool us.
  562. // Check if the version we have been asked to upgrade to is higher than our current version.
  563. // We also need at least 3 chars to make a valid version number string.
  564. if (((1 == data_len) && (1 == payload)) || ((data_len >= 3) && NewerVersion(dataBuf))) {
  565. ota_state_flag = 3;
  566. snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}", command, my_version, GetOtaUrl(stemp1, sizeof(stemp1)));
  567. } else {
  568. snprintf_P(mqtt_data, sizeof(mqtt_data), "{\"%s\":\"" D_JSON_ONE_OR_GT "\"}", command, my_version);
  569. }
  570. }
  571. else if (CMND_OTAURL == command_code) {
  572. if ((data_len > 0) && (data_len < sizeof(Settings.ota_url))) {
  573. strlcpy(Settings.ota_url, (SC_DEFAULT == Shortcut(dataBuf)) ? OTA_URL : dataBuf, sizeof(Settings.ota_url));
  574. }
  575. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.ota_url);
  576. }
  577. else if (CMND_SERIALLOG == command_code) {
  578. if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
  579. Settings.flag.mqtt_serial = 0;
  580. SetSeriallog(payload);
  581. }
  582. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.seriallog_level, seriallog_level);
  583. }
  584. else if (CMND_RESTART == command_code) {
  585. switch (payload) {
  586. case 1:
  587. restart_flag = 2;
  588. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_RESTARTING);
  589. break;
  590. case 99:
  591. AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
  592. EspRestart();
  593. break;
  594. default:
  595. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESTART);
  596. }
  597. }
  598. else if ((CMND_POWERONSTATE == command_code) && (Settings.module != MOTOR)) {
  599. /* 0 = Keep relays off after power on
  600. * 1 = Turn relays on after power on, if PulseTime set wait for PulseTime seconds, and turn relays off
  601. * 2 = Toggle relays after power on
  602. * 3 = Set relays to last saved state after power on
  603. * 4 = Turn relays on and disable any relay control (used for Sonoff Pow to always measure power)
  604. * 5 = Keep relays off after power on, if PulseTime set wait for PulseTime seconds, and turn relays on
  605. */
  606. if ((payload >= POWER_ALL_OFF) && (payload <= POWER_ALL_OFF_PULSETIME_ON)) {
  607. Settings.poweronstate = payload;
  608. if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {
  609. for (byte i = 1; i <= devices_present; i++) {
  610. ExecuteCommandPower(i, POWER_ON, SRC_IGNORE);
  611. }
  612. }
  613. }
  614. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.poweronstate);
  615. }
  616. else if ((CMND_PULSETIME == command_code) && (index > 0) && (index <= MAX_PULSETIMERS)) {
  617. if (data_len > 0) {
  618. Settings.pulse_timer[index -1] = payload16; // 0 - 65535
  619. SetPulseTimer(index -1, payload16);
  620. }
  621. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE, command, index, Settings.pulse_timer[index -1], GetPulseTimer(index -1));
  622. }
  623. else if (CMND_BLINKTIME == command_code) {
  624. if ((payload > 1) && (payload <= 3600)) {
  625. Settings.blinktime = payload;
  626. if (blink_timer > 0) { blink_timer = millis() + (100 * payload); }
  627. }
  628. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.blinktime);
  629. }
  630. else if (CMND_BLINKCOUNT == command_code) {
  631. if (data_len > 0) {
  632. Settings.blinkcount = payload16; // 0 - 65535
  633. if (blink_counter) blink_counter = Settings.blinkcount *2;
  634. }
  635. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.blinkcount);
  636. }
  637. else if (CMND_SAVEDATA == command_code) {
  638. if ((payload >= 0) && (payload <= 3600)) {
  639. Settings.save_data = payload;
  640. save_data_counter = Settings.save_data;
  641. }
  642. SettingsSaveAll();
  643. if (Settings.save_data > 1) {
  644. snprintf_P(stemp1, sizeof(stemp1), PSTR(D_JSON_EVERY " %d " D_UNIT_SECOND), Settings.save_data);
  645. }
  646. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, (Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data));
  647. }
  648. else if ((CMND_SENSOR == command_code) || (CMND_DRIVER == command_code)) {
  649. XdrvMailbox.index = index;
  650. XdrvMailbox.data_len = data_len;
  651. XdrvMailbox.payload16 = payload16;
  652. XdrvMailbox.payload = payload;
  653. XdrvMailbox.grpflg = grpflg;
  654. XdrvMailbox.topic = command;
  655. XdrvMailbox.data = dataBuf;
  656. if (CMND_SENSOR == command_code) {
  657. XsnsCall(FUNC_COMMAND);
  658. } else {
  659. XdrvCall(FUNC_COMMAND);
  660. }
  661. }
  662. else if ((CMND_SETOPTION == command_code) && (index < 82)) {
  663. byte ptype;
  664. byte pindex;
  665. if (index <= 31) { // SetOption0 .. 31 = Settings.flag
  666. ptype = 0;
  667. pindex = index; // 0 .. 31
  668. }
  669. else if (index <= 49) { // SetOption32 .. 49 = Settings.param
  670. ptype = 2;
  671. pindex = index -32; // 0 .. 17 (= PARAM8_SIZE -1)
  672. }
  673. else { // SetOption50 .. 81 = Settings.flag3
  674. ptype = 1;
  675. pindex = index -50; // 0 .. 31
  676. }
  677. if (payload >= 0) {
  678. if (0 == ptype) { // SetOption0 .. 31
  679. if (payload <= 1) {
  680. switch (pindex) {
  681. case 5: // mqtt_power_retain (CMND_POWERRETAIN)
  682. case 6: // mqtt_button_retain (CMND_BUTTONRETAIN)
  683. case 7: // mqtt_switch_retain (CMND_SWITCHRETAIN)
  684. case 9: // mqtt_sensor_retain (CMND_SENSORRETAIN)
  685. case 22: // mqtt_serial (SerialSend and SerialLog)
  686. case 23: // mqtt_serial_raw (SerialSend)
  687. case 25: // knx_enabled (Web config)
  688. case 27: // knx_enable_enhancement (Web config)
  689. ptype = 99; // Command Error
  690. break; // Ignore command SetOption
  691. case 3: // mqtt
  692. case 15: // pwm_control
  693. restart_flag = 2;
  694. default:
  695. bitWrite(Settings.flag.data, pindex, payload);
  696. }
  697. if (12 == pindex) { // stop_flash_rotate
  698. stop_flash_rotate = payload;
  699. SettingsSave(2);
  700. }
  701. #ifdef USE_HOME_ASSISTANT
  702. if ((19 == pindex) || (30 == pindex)) {
  703. HAssDiscovery(1); // hass_discovery or hass_light
  704. }
  705. #endif // USE_HOME_ASSISTANT
  706. }
  707. }
  708. else if (1 == ptype) { // SetOption50 .. 81
  709. if (payload <= 1) {
  710. bitWrite(Settings.flag3.data, pindex, payload);
  711. if (60 == ptype) { // SetOption60 enable or disable traditional sleep
  712. if (payload == 0) { // Dynamic Sleep
  713. WiFiSetSleepMode(); // Update WiFi sleep mode accordingly
  714. } else { // Traditional Sleep //AT
  715. WiFiSetSleepMode(); // Update WiFi sleep mode accordingly
  716. }
  717. }
  718. }
  719. }
  720. else { // SetOption32 .. 49
  721. uint8_t param_low = 0;
  722. uint8_t param_high = 255;
  723. switch (pindex) {
  724. case P_HOLD_TIME:
  725. case P_MAX_POWER_RETRY:
  726. param_low = 1;
  727. param_high = 250;
  728. break;
  729. }
  730. if ((payload >= param_low) && (payload <= param_high)) {
  731. Settings.param[pindex] = payload;
  732. }
  733. }
  734. }
  735. if (ptype < 99) {
  736. if (2 == ptype) snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), Settings.param[pindex]);
  737. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, (2 == ptype) ? stemp1 : (1 == ptype) ? GetStateText(bitRead(Settings.flag3.data, pindex)) : GetStateText(bitRead(Settings.flag.data, pindex)));
  738. }
  739. }
  740. else if (CMND_TEMPERATURE_RESOLUTION == command_code) {
  741. if ((payload >= 0) && (payload <= 3)) {
  742. Settings.flag2.temperature_resolution = payload;
  743. }
  744. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.temperature_resolution);
  745. }
  746. else if (CMND_HUMIDITY_RESOLUTION == command_code) {
  747. if ((payload >= 0) && (payload <= 3)) {
  748. Settings.flag2.humidity_resolution = payload;
  749. }
  750. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.humidity_resolution);
  751. }
  752. else if (CMND_PRESSURE_RESOLUTION == command_code) {
  753. if ((payload >= 0) && (payload <= 3)) {
  754. Settings.flag2.pressure_resolution = payload;
  755. }
  756. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.pressure_resolution);
  757. }
  758. else if (CMND_POWER_RESOLUTION == command_code) {
  759. if ((payload >= 0) && (payload <= 3)) {
  760. Settings.flag2.wattage_resolution = payload;
  761. }
  762. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.wattage_resolution);
  763. }
  764. else if (CMND_VOLTAGE_RESOLUTION == command_code) {
  765. if ((payload >= 0) && (payload <= 3)) {
  766. Settings.flag2.voltage_resolution = payload;
  767. }
  768. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.voltage_resolution);
  769. }
  770. else if (CMND_FREQUENCY_RESOLUTION == command_code) {
  771. if ((payload >= 0) && (payload <= 3)) {
  772. Settings.flag2.frequency_resolution = payload;
  773. }
  774. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.frequency_resolution);
  775. }
  776. else if (CMND_CURRENT_RESOLUTION == command_code) {
  777. if ((payload >= 0) && (payload <= 3)) {
  778. Settings.flag2.current_resolution = payload;
  779. }
  780. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.current_resolution);
  781. }
  782. else if (CMND_ENERGY_RESOLUTION == command_code) {
  783. if ((payload >= 0) && (payload <= 5)) {
  784. Settings.flag2.energy_resolution = payload;
  785. }
  786. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.energy_resolution);
  787. }
  788. else if (CMND_WEIGHT_RESOLUTION == command_code) {
  789. if ((payload >= 0) && (payload <= 3)) {
  790. Settings.flag2.weight_resolution = payload;
  791. }
  792. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.weight_resolution);
  793. }
  794. else if (CMND_MODULE == command_code) {
  795. if ((payload > 0) && (payload <= MAXMODULE)) {
  796. payload--;
  797. Settings.last_module = Settings.module;
  798. Settings.module = payload;
  799. if (Settings.last_module != payload) {
  800. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  801. Settings.my_gp.io[i] = 0;
  802. }
  803. }
  804. restart_flag = 2;
  805. }
  806. snprintf_P(stemp1, sizeof(stemp1), kModules[Settings.module].name);
  807. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, Settings.module +1, stemp1);
  808. }
  809. else if (CMND_MODULES == command_code) {
  810. for (byte i = 0; i < MAXMODULE; i++) {
  811. if (!jsflg) {
  812. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULES "%d\":["), lines);
  813. } else {
  814. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
  815. }
  816. jsflg = 1;
  817. snprintf_P(stemp1, sizeof(stemp1), kModules[i].name);
  818. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, i +1, stemp1);
  819. if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAXMODULE -1)) {
  820. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data);
  821. MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
  822. jsflg = 0;
  823. lines++;
  824. }
  825. }
  826. mqtt_data[0] = '\0';
  827. }
  828. else if ((CMND_GPIO == command_code) && (index < MAX_GPIO_PIN)) {
  829. mytmplt cmodule;
  830. memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule));
  831. if ((GPIO_USER == ValidGPIO(index, cmodule.gp.io[index])) && (payload >= 0) && (payload < GPIO_SENSOR_END)) {
  832. bool present = false;
  833. for (byte i = 0; i < sizeof(kGpioNiceList); i++) {
  834. uint8_t midx = pgm_read_byte(kGpioNiceList + i);
  835. if (midx == payload) { present = true; }
  836. }
  837. if (present) {
  838. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  839. if ((GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) && (Settings.my_gp.io[i] == payload)) {
  840. Settings.my_gp.io[i] = 0;
  841. }
  842. }
  843. Settings.my_gp.io[index] = payload;
  844. restart_flag = 2;
  845. }
  846. }
  847. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
  848. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  849. if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) {
  850. if (jsflg) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
  851. jsflg = 1;
  852. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_GPIO "%d\":\"%d (%s)\""),
  853. mqtt_data, i, Settings.my_gp.io[i], GetTextIndexed(stemp1, sizeof(stemp1), Settings.my_gp.io[i], kSensorNames));
  854. }
  855. }
  856. if (jsflg) {
  857. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
  858. } else {
  859. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_NOT_SUPPORTED);
  860. }
  861. }
  862. else if (CMND_GPIOS == command_code) {
  863. mytmplt cmodule;
  864. memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule));
  865. uint8_t midx;
  866. for (byte i = 0; i < sizeof(kGpioNiceList); i++) {
  867. midx = pgm_read_byte(kGpioNiceList + i);
  868. if (!GetUsedInModule(midx, cmodule.gp.io)) {
  869. if (!jsflg) {
  870. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_GPIOS "%d\":["), lines);
  871. } else {
  872. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
  873. }
  874. jsflg = 1;
  875. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"%d (%s)\""), mqtt_data, midx, GetTextIndexed(stemp1, sizeof(stemp1), midx, kSensorNames));
  876. if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == sizeof(kGpioNiceList) -1)) {
  877. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]}"), mqtt_data);
  878. MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
  879. jsflg = 0;
  880. lines++;
  881. }
  882. }
  883. }
  884. mqtt_data[0] = '\0';
  885. }
  886. else if ((CMND_PWM == command_code) && pwm_present && (index > 0) && (index <= MAX_PWMS)) {
  887. if ((payload >= 0) && (payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + index -1] < 99)) {
  888. Settings.pwm_value[index -1] = payload;
  889. analogWrite(pin[GPIO_PWM1 + index -1], bitRead(pwm_inverted, index -1) ? Settings.pwm_range - payload : payload);
  890. }
  891. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
  892. MqttShowPWMState(); // Render the PWM status to MQTT
  893. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
  894. }
  895. else if (CMND_PWMFREQUENCY == command_code) {
  896. if ((1 == payload) || ((payload >= PWM_MIN) && (payload <= PWM_MAX))) {
  897. Settings.pwm_frequency = (1 == payload) ? PWM_FREQ : payload;
  898. analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
  899. }
  900. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.pwm_frequency);
  901. }
  902. else if (CMND_PWMRANGE == command_code) {
  903. if ((1 == payload) || ((payload > 254) && (payload < 1024))) {
  904. Settings.pwm_range = (1 == payload) ? PWM_RANGE : payload;
  905. for (byte i = 0; i < MAX_PWMS; i++) {
  906. if (Settings.pwm_value[i] > Settings.pwm_range) {
  907. Settings.pwm_value[i] = Settings.pwm_range;
  908. }
  909. }
  910. analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h)
  911. }
  912. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.pwm_range);
  913. }
  914. else if ((CMND_COUNTER == command_code) && (index > 0) && (index <= MAX_COUNTERS)) {
  915. if ((data_len > 0) && (pin[GPIO_CNTR1 + index -1] < 99)) {
  916. if ((dataBuf[0] == '-') || (dataBuf[0] == '+')) {
  917. RtcSettings.pulse_counter[index -1] += payload32;
  918. Settings.pulse_counter[index -1] += payload32;
  919. } else {
  920. RtcSettings.pulse_counter[index -1] = payload32;
  921. Settings.pulse_counter[index -1] = payload32;
  922. }
  923. }
  924. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_LVALUE, command, index, RtcSettings.pulse_counter[index -1]);
  925. }
  926. else if ((CMND_COUNTERTYPE == command_code) && (index > 0) && (index <= MAX_COUNTERS)) {
  927. if ((payload >= 0) && (payload <= 1) && (pin[GPIO_CNTR1 + index -1] < 99)) {
  928. bitWrite(Settings.pulse_counter_type, index -1, payload &1);
  929. RtcSettings.pulse_counter[index -1] = 0;
  930. Settings.pulse_counter[index -1] = 0;
  931. }
  932. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, bitRead(Settings.pulse_counter_type, index -1));
  933. }
  934. else if (CMND_COUNTERDEBOUNCE == command_code) {
  935. if ((data_len > 0) && (payload16 < 32001)) {
  936. Settings.pulse_counter_debounce = payload16;
  937. }
  938. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.pulse_counter_debounce);
  939. }
  940. else if (CMND_BUTTONDEBOUNCE == command_code) {
  941. if ((payload > 39) && (payload < 1001)) {
  942. Settings.button_debounce = payload;
  943. }
  944. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.button_debounce);
  945. }
  946. else if (CMND_SWITCHDEBOUNCE == command_code) {
  947. if ((payload > 39) && (payload < 1001)) {
  948. Settings.switch_debounce = payload;
  949. }
  950. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.switch_debounce);
  951. }
  952. else if (CMND_BAUDRATE == command_code) {
  953. if (payload32 > 0) {
  954. payload32 /= 1200; // Make it a valid baudrate
  955. baudrate = (1 == payload) ? APP_BAUDRATE : payload32 * 1200;
  956. SetSerialBaudrate(baudrate);
  957. }
  958. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.baudrate * 1200);
  959. }
  960. else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 5)) {
  961. SetSeriallog(LOG_LEVEL_NONE);
  962. Settings.flag.mqtt_serial = 1;
  963. Settings.flag.mqtt_serial_raw = (index > 3) ? 1 : 0;
  964. if (data_len > 0) {
  965. if (1 == index) {
  966. Serial.printf("%s\n", dataBuf); // "Hello Tiger\n"
  967. }
  968. else if (2 == index || 4 == index) {
  969. for (int i = 0; i < data_len; i++) {
  970. Serial.write(dataBuf[i]); // "Hello Tiger" or "A0"
  971. }
  972. }
  973. else if (3 == index) {
  974. uint16_t dat_len = data_len;
  975. Serial.printf("%s", Unescape(dataBuf, &dat_len)); // "Hello\f"
  976. }
  977. else if (5 == index) {
  978. SerialSendRaw(RemoveSpace(dataBuf)); // "AA004566"
  979. }
  980. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
  981. }
  982. }
  983. else if (CMND_SERIALDELIMITER == command_code) {
  984. if ((data_len > 0) && (payload < 256)) {
  985. if (payload > 0) {
  986. Settings.serial_delimiter = payload;
  987. } else {
  988. uint16_t dat_len = data_len;
  989. Unescape(dataBuf, &dat_len);
  990. Settings.serial_delimiter = dataBuf[0];
  991. }
  992. }
  993. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.serial_delimiter);
  994. }
  995. else if (CMND_SYSLOG == command_code) {
  996. if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
  997. Settings.syslog_level = payload;
  998. syslog_level = payload;
  999. syslog_timer = 0;
  1000. }
  1001. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.syslog_level, syslog_level);
  1002. }
  1003. else if (CMND_LOGHOST == command_code) {
  1004. if ((data_len > 0) && (data_len < sizeof(Settings.syslog_host))) {
  1005. strlcpy(Settings.syslog_host, (SC_DEFAULT == Shortcut(dataBuf)) ? SYS_LOG_HOST : dataBuf, sizeof(Settings.syslog_host));
  1006. }
  1007. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.syslog_host);
  1008. }
  1009. else if (CMND_LOGPORT == command_code) {
  1010. if (payload16 > 0) {
  1011. Settings.syslog_port = (1 == payload16) ? SYS_LOG_PORT : payload16;
  1012. }
  1013. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.syslog_port);
  1014. }
  1015. else if ((CMND_IPADDRESS == command_code) && (index > 0) && (index <= 4)) {
  1016. if (ParseIp(&address, dataBuf)) {
  1017. Settings.ip_address[index -1] = address;
  1018. // restart_flag = 2;
  1019. }
  1020. snprintf_P(stemp1, sizeof(stemp1), PSTR(" (%s)"), WiFi.localIP().toString().c_str());
  1021. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE_SVALUE, command, index, IPAddress(Settings.ip_address[index -1]).toString().c_str(), (1 == index) ? stemp1:"");
  1022. }
  1023. else if ((CMND_NTPSERVER == command_code) && (index > 0) && (index <= 3)) {
  1024. if ((data_len > 0) && (data_len < sizeof(Settings.ntp_server[0]))) {
  1025. strlcpy(Settings.ntp_server[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1==index)?NTP_SERVER1:(2==index)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(Settings.ntp_server[0]));
  1026. for (i = 0; i < strlen(Settings.ntp_server[index -1]); i++) {
  1027. if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.';
  1028. }
  1029. // restart_flag = 2; // Issue #3890
  1030. ntp_force_sync = 1;
  1031. }
  1032. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.ntp_server[index -1]);
  1033. }
  1034. else if (CMND_AP == command_code) {
  1035. if ((payload >= 0) && (payload <= 2)) {
  1036. switch (payload) {
  1037. case 0: // Toggle
  1038. Settings.sta_active ^= 1;
  1039. break;
  1040. case 1: // AP1
  1041. case 2: // AP2
  1042. Settings.sta_active = payload -1;
  1043. }
  1044. restart_flag = 2;
  1045. }
  1046. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active]);
  1047. }
  1048. else if ((CMND_SSID == command_code) && (index > 0) && (index <= 2)) {
  1049. if ((data_len > 0) && (data_len < sizeof(Settings.sta_ssid[0]))) {
  1050. strlcpy(Settings.sta_ssid[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(Settings.sta_ssid[0]));
  1051. Settings.sta_active = index -1;
  1052. restart_flag = 2;
  1053. }
  1054. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_ssid[index -1]);
  1055. }
  1056. else if ((CMND_PASSWORD == command_code) && (index > 0) && (index <= 2)) {
  1057. if ((data_len > 0) && (data_len < sizeof(Settings.sta_pwd[0]))) {
  1058. strlcpy(Settings.sta_pwd[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0]));
  1059. Settings.sta_active = index -1;
  1060. restart_flag = 2;
  1061. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_pwd[index -1]);
  1062. } else {
  1063. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_ASTERIX, command, index);
  1064. }
  1065. }
  1066. else if ((CMND_HOSTNAME == command_code) && !grpflg) {
  1067. if ((data_len > 0) && (data_len < sizeof(Settings.hostname))) {
  1068. strlcpy(Settings.hostname, (SC_DEFAULT == Shortcut(dataBuf)) ? WIFI_HOSTNAME : dataBuf, sizeof(Settings.hostname));
  1069. if (strstr(Settings.hostname,"%")) {
  1070. strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname));
  1071. }
  1072. restart_flag = 2;
  1073. }
  1074. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.hostname);
  1075. }
  1076. else if (CMND_WIFICONFIG == command_code) {
  1077. if ((payload >= WIFI_RESTART) && (payload < MAX_WIFI_OPTION)) {
  1078. Settings.sta_config = payload;
  1079. wifi_state_flag = Settings.sta_config;
  1080. snprintf_P(stemp1, sizeof(stemp1), kWifiConfig[Settings.sta_config]);
  1081. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WIFICONFIG "\":\"%s " D_JSON_SELECTED "\"}"), stemp1);
  1082. if (WifiState() > WIFI_RESTART) {
  1083. // snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s after restart"), mqtt_data);
  1084. restart_flag = 2;
  1085. }
  1086. } else {
  1087. snprintf_P(stemp1, sizeof(stemp1), kWifiConfig[Settings.sta_config]);
  1088. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_SVALUE, command, Settings.sta_config, stemp1);
  1089. }
  1090. }
  1091. else if ((CMND_FRIENDLYNAME == command_code) && (index > 0) && (index <= MAX_FRIENDLYNAMES)) {
  1092. if ((data_len > 0) && (data_len < sizeof(Settings.friendlyname[0]))) {
  1093. if (1 == index) {
  1094. snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME));
  1095. } else {
  1096. snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME "%d"), index);
  1097. }
  1098. strlcpy(Settings.friendlyname[index -1], (SC_DEFAULT == Shortcut(dataBuf)) ? stemp1 : dataBuf, sizeof(Settings.friendlyname[index -1]));
  1099. }
  1100. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.friendlyname[index -1]);
  1101. }
  1102. else if ((CMND_SWITCHMODE == command_code) && (index > 0) && (index <= MAX_SWITCHES)) {
  1103. if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) {
  1104. Settings.switchmode[index -1] = payload;
  1105. GpioSwitchPinMode(index -1);
  1106. }
  1107. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, Settings.switchmode[index-1]);
  1108. }
  1109. else if (CMND_TELEPERIOD == command_code) {
  1110. if ((payload >= 0) && (payload < 3601)) {
  1111. Settings.tele_period = (1 == payload) ? TELE_PERIOD : payload;
  1112. if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) Settings.tele_period = 10; // Do not allow periods < 10 seconds
  1113. tele_period = Settings.tele_period;
  1114. }
  1115. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_UNIT, command, Settings.tele_period, (Settings.flag.value_units) ? " " D_UNIT_SECOND : "");
  1116. }
  1117. else if (CMND_RESET == command_code) {
  1118. switch (payload) {
  1119. case 1:
  1120. restart_flag = 211;
  1121. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING);
  1122. break;
  1123. case 2:
  1124. case 3:
  1125. case 4:
  1126. case 5:
  1127. restart_flag = 210 + payload;
  1128. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}"));
  1129. break;
  1130. default:
  1131. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_ONE_TO_RESET);
  1132. }
  1133. }
  1134. else if (CMND_TIMEZONE == command_code) {
  1135. if ((data_len > 0) && (payload >= -13)) {
  1136. Settings.timezone = payload;
  1137. Settings.timezone_minutes = 0;
  1138. if (payload < 15) {
  1139. p = strtok (dataBuf, ":");
  1140. if (p) {
  1141. p = strtok (NULL, ":");
  1142. if (p) {
  1143. Settings.timezone_minutes = strtol(p, NULL, 10);
  1144. if (Settings.timezone_minutes > 59) { Settings.timezone_minutes = 59; }
  1145. }
  1146. }
  1147. } else {
  1148. Settings.timezone = 99;
  1149. }
  1150. ntp_force_sync = 1;
  1151. }
  1152. if (99 == Settings.timezone) {
  1153. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.timezone);
  1154. } else {
  1155. snprintf_P(stemp1, sizeof(stemp1), PSTR("%+03d:%02d"), Settings.timezone, Settings.timezone_minutes);
  1156. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, stemp1);
  1157. }
  1158. }
  1159. else if ((CMND_TIMESTD == command_code) || (CMND_TIMEDST == command_code)) {
  1160. // TimeStd 0/1, 0/1/2/3/4, 1..12, 1..7, 0..23, +/-780
  1161. uint8_t ts = 0;
  1162. if (CMND_TIMEDST == command_code) { ts = 1; }
  1163. if (data_len > 0) {
  1164. if (strstr(dataBuf, ",")) { // Process parameter entry
  1165. uint8_t tpos = 0; // Parameter index
  1166. int value = 0;
  1167. p = dataBuf; // Parameters like "1, 2,3 , 4 ,5, -120" or ",,,,,+240"
  1168. char *q = p; // Value entered flag
  1169. while (p && (tpos < 7)) {
  1170. if (p > q) { // Any value entered
  1171. if (1 == tpos) { Settings.tflag[ts].hemis = value &1; }
  1172. if (2 == tpos) { Settings.tflag[ts].week = (value < 0) ? 0 : (value > 4) ? 4 : value; }
  1173. if (3 == tpos) { Settings.tflag[ts].month = (value < 1) ? 1 : (value > 12) ? 12 : value; }
  1174. if (4 == tpos) { Settings.tflag[ts].dow = (value < 1) ? 1 : (value > 7) ? 7 : value; }
  1175. if (5 == tpos) { Settings.tflag[ts].hour = (value < 0) ? 0 : (value > 23) ? 23 : value; }
  1176. if (6 == tpos) { Settings.toffset[ts] = (value < -900) ? -900 : (value > 900) ? 900 : value; }
  1177. }
  1178. p = Trim(p); // Skip spaces
  1179. if (tpos && (*p == ',')) { p++; } // Skip separator
  1180. p = Trim(p); // Skip spaces
  1181. q = p; // Reset any value entered flag
  1182. value = strtol(p, &p, 10);
  1183. tpos++; // Next parameter
  1184. }
  1185. ntp_force_sync = 1;
  1186. } else {
  1187. if (0 == payload) {
  1188. if (0 == ts) {
  1189. SettingsResetStd();
  1190. } else {
  1191. SettingsResetDst();
  1192. }
  1193. }
  1194. ntp_force_sync = 1;
  1195. }
  1196. }
  1197. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"Hemisphere\":%d,\"Week\":%d,\"Month\":%d,\"Day\":%d,\"Hour\":%d,\"Offset\":%d}}"),
  1198. command, Settings.tflag[ts].hemis, Settings.tflag[ts].week, Settings.tflag[ts].month, Settings.tflag[ts].dow, Settings.tflag[ts].hour, Settings.toffset[ts]);
  1199. }
  1200. else if (CMND_ALTITUDE == command_code) {
  1201. if ((data_len > 0) && ((payload >= -30000) && (payload <= 30000))) {
  1202. Settings.altitude = payload;
  1203. }
  1204. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.altitude);
  1205. }
  1206. else if (CMND_LEDPOWER == command_code) {
  1207. if ((payload >= 0) && (payload <= 2)) {
  1208. Settings.ledstate &= 8;
  1209. switch (payload) {
  1210. case 0: // Off
  1211. case 1: // On
  1212. Settings.ledstate = payload << 3;
  1213. break;
  1214. case 2: // Toggle
  1215. Settings.ledstate ^= 8;
  1216. break;
  1217. }
  1218. blinks = 0;
  1219. SetLedPower(Settings.ledstate &8);
  1220. }
  1221. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3)));
  1222. }
  1223. else if (CMND_LEDSTATE == command_code) {
  1224. if ((payload >= 0) && (payload < MAX_LED_OPTION)) {
  1225. Settings.ledstate = payload;
  1226. if (!Settings.ledstate) SetLedPower(0);
  1227. }
  1228. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.ledstate);
  1229. }
  1230. #ifdef USE_I2C
  1231. else if ((CMND_I2CSCAN == command_code) && i2c_flg) {
  1232. I2cScan(mqtt_data, sizeof(mqtt_data));
  1233. }
  1234. #endif // USE_I2C
  1235. else type = NULL; // Unknown command
  1236. }
  1237. if (type == NULL) {
  1238. blinks = 201;
  1239. snprintf_P(topicBuf, sizeof(topicBuf), PSTR(D_JSON_COMMAND));
  1240. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_UNKNOWN "\"}"));
  1241. type = (char*)topicBuf;
  1242. }
  1243. if (mqtt_data[0] != '\0') MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
  1244. fallback_topic_flag = 0;
  1245. }
  1246. /********************************************************************************************/
  1247. boolean SendKey(byte key, byte device, byte state)
  1248. {
  1249. // key 0 = button_topic
  1250. // key 1 = switch_topic
  1251. // state 0 = off
  1252. // state 1 = on
  1253. // state 2 = toggle
  1254. // state 3 = hold
  1255. // state 9 = clear retain flag
  1256. char stopic[TOPSZ];
  1257. char scommand[CMDSZ];
  1258. char key_topic[sizeof(Settings.button_topic)];
  1259. boolean result = false;
  1260. char *tmp = (key) ? Settings.switch_topic : Settings.button_topic;
  1261. Format(key_topic, tmp, sizeof(key_topic));
  1262. if (Settings.flag.mqtt_enabled && MqttIsConnected() && (strlen(key_topic) != 0) && strcmp(key_topic, "0")) {
  1263. if (!key && (device > devices_present)) { device = 1; } // Only allow number of buttons up to number of devices
  1264. GetTopic_P(stopic, CMND, key_topic,
  1265. GetPowerDevice(scommand, device, sizeof(scommand), (key + Settings.flag.device_index_enable))); // cmnd/switchtopic/POWERx
  1266. if (9 == state) {
  1267. mqtt_data[0] = '\0';
  1268. } else {
  1269. if ((Settings.flag3.button_switch_force_local || !strcmp(mqtt_topic, key_topic) || !strcmp(Settings.mqtt_grptopic, key_topic)) && (2 == state)) {
  1270. state = ~(power >> (device -1)) &1;
  1271. }
  1272. snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(state));
  1273. }
  1274. #ifdef USE_DOMOTICZ
  1275. if (!(DomoticzSendKey(key, device, state, strlen(mqtt_data)))) {
  1276. MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain);
  1277. }
  1278. #else
  1279. MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain);
  1280. #endif // USE_DOMOTICZ
  1281. result = !Settings.flag3.button_switch_force_local;
  1282. } else {
  1283. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":{\"State\":%d}}"), (key) ? "Switch" : "Button", device, state);
  1284. result = XdrvRulesProcess();
  1285. }
  1286. #ifdef USE_KNX
  1287. KnxSendButtonPower(key, device, state);
  1288. #endif // USE_KNX
  1289. return result;
  1290. }
  1291. void ExecuteCommandPower(byte device, byte state, int source)
  1292. {
  1293. // device = Relay number 1 and up
  1294. // state 0 = Relay Off
  1295. // state 1 = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
  1296. // state 2 = Toggle relay
  1297. // state 3 = Blink relay
  1298. // state 4 = Stop blinking relay
  1299. // state 6 = Relay Off and no publishPowerState
  1300. // state 7 = Relay On and no publishPowerState
  1301. // state 9 = Show power state
  1302. // ShowSource(source);
  1303. if (SONOFF_IFAN02 == Settings.module) {
  1304. blink_mask &= 1; // No blinking on the fan relays
  1305. Settings.flag.interlock = 0; // No interlock mode as it is already done by the microcontroller
  1306. Settings.pulse_timer[1] = 0; // No pulsetimers on the fan relays
  1307. Settings.pulse_timer[2] = 0;
  1308. Settings.pulse_timer[3] = 0;
  1309. }
  1310. uint8_t publish_power = 1;
  1311. if ((POWER_OFF_NO_STATE == state) || (POWER_ON_NO_STATE == state)) {
  1312. state &= 1;
  1313. publish_power = 0;
  1314. }
  1315. if ((device < 1) || (device > devices_present)) device = 1;
  1316. if (device <= MAX_PULSETIMERS) { SetPulseTimer(device -1, 0); }
  1317. power_t mask = 1 << (device -1);
  1318. if (state <= POWER_TOGGLE) {
  1319. if ((blink_mask & mask)) {
  1320. blink_mask &= (POWER_MASK ^ mask); // Clear device mask
  1321. MqttPublishPowerBlinkState(device);
  1322. }
  1323. if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay
  1324. interlock_mutex = 1;
  1325. for (byte i = 0; i < devices_present; i++) {
  1326. power_t imask = 1 << i;
  1327. if ((power & imask) && (mask != imask)) ExecuteCommandPower(i +1, POWER_OFF, SRC_IGNORE);
  1328. }
  1329. interlock_mutex = 0;
  1330. }
  1331. switch (state) {
  1332. case POWER_OFF: {
  1333. power &= (POWER_MASK ^ mask);
  1334. break; }
  1335. case POWER_ON:
  1336. power |= mask;
  1337. break;
  1338. case POWER_TOGGLE:
  1339. power ^= mask;
  1340. }
  1341. SetDevicePower(power, source);
  1342. #ifdef USE_DOMOTICZ
  1343. DomoticzUpdatePowerState(device);
  1344. #endif // USE_DOMOTICZ
  1345. #ifdef USE_KNX
  1346. KnxUpdatePowerState(device, power);
  1347. #endif // USE_KNX
  1348. if (publish_power && Settings.flag3.hass_tele_on_power) {
  1349. mqtt_data[0] = '\0';
  1350. MqttShowState();
  1351. MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN);
  1352. }
  1353. if (device <= MAX_PULSETIMERS) { // Restart PulseTime if powered On
  1354. SetPulseTimer(device -1, (((POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? ~power : power) & mask) ? Settings.pulse_timer[device -1] : 0);
  1355. }
  1356. }
  1357. else if (POWER_BLINK == state) {
  1358. if (!(blink_mask & mask)) {
  1359. blink_powersave = (blink_powersave & (POWER_MASK ^ mask)) | (power & mask); // Save state
  1360. blink_power = (power >> (device -1))&1; // Prep to Toggle
  1361. }
  1362. blink_timer = millis() + 100;
  1363. blink_counter = ((!Settings.blinkcount) ? 64000 : (Settings.blinkcount *2)) +1;
  1364. blink_mask |= mask; // Set device mask
  1365. MqttPublishPowerBlinkState(device);
  1366. return;
  1367. }
  1368. else if (POWER_BLINK_STOP == state) {
  1369. byte flag = (blink_mask & mask);
  1370. blink_mask &= (POWER_MASK ^ mask); // Clear device mask
  1371. MqttPublishPowerBlinkState(device);
  1372. if (flag) ExecuteCommandPower(device, (blink_powersave >> (device -1))&1, SRC_IGNORE); // Restore state
  1373. return;
  1374. }
  1375. if (publish_power) MqttPublishPowerState(device);
  1376. }
  1377. void StopAllPowerBlink(void)
  1378. {
  1379. power_t mask;
  1380. for (byte i = 1; i <= devices_present; i++) {
  1381. mask = 1 << (i -1);
  1382. if (blink_mask & mask) {
  1383. blink_mask &= (POWER_MASK ^ mask); // Clear device mask
  1384. MqttPublishPowerBlinkState(i);
  1385. ExecuteCommandPower(i, (blink_powersave >> (i -1))&1, SRC_IGNORE); // Restore state
  1386. }
  1387. }
  1388. }
  1389. void ExecuteCommand(char *cmnd, int source)
  1390. {
  1391. char stopic[CMDSZ];
  1392. char svalue[INPUT_BUFFER_SIZE];
  1393. char *start;
  1394. char *token;
  1395. ShowFreeMem(PSTR("ExecuteCommand"));
  1396. ShowSource(source);
  1397. token = strtok(cmnd, " ");
  1398. if (token != NULL) {
  1399. start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble
  1400. if (start) token = start +1;
  1401. }
  1402. snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == NULL) ? "" : token);
  1403. token = strtok(NULL, "");
  1404. // snprintf_P(svalue, sizeof(svalue), (token == NULL) ? "" : token); // Fails with command FullTopic home/%prefix%/%topic% as it processes %p of %prefix%
  1405. strlcpy(svalue, (token == NULL) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b
  1406. MqttDataHandler(stopic, (byte*)svalue, strlen(svalue));
  1407. }
  1408. void PublishStatus(uint8_t payload)
  1409. {
  1410. uint8_t option = STAT;
  1411. char stemp[MAX_FRIENDLYNAMES * (sizeof(Settings.friendlyname[0]) +MAX_FRIENDLYNAMES)];
  1412. char stemp2[MAX_SWITCHES * 3];
  1413. // Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
  1414. if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++; // TELE
  1415. if ((!Settings.flag.mqtt_enabled) && (6 == payload)) payload = 99;
  1416. if (!energy_flg && (9 == payload)) payload = 99;
  1417. if ((0 == payload) || (99 == payload)) {
  1418. uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present;
  1419. if (SONOFF_IFAN02 == Settings.module) { maxfn = 1; }
  1420. stemp[0] = '\0';
  1421. for (byte i = 0; i < maxfn; i++) {
  1422. snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), Settings.friendlyname[i]);
  1423. }
  1424. stemp2[0] = '\0';
  1425. for (byte i = 0; i < MAX_SWITCHES; i++) {
  1426. snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]);
  1427. }
  1428. 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}}"),
  1429. 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);
  1430. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS));
  1431. }
  1432. if ((0 == payload) || (1 == payload)) {
  1433. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\"" D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\",\"" D_JSON_STARTUPUTC "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"),
  1434. baudrate, Settings.mqtt_grptopic, Settings.ota_url, GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep, Settings.bootcount, Settings.save_flag, GetSettingsAddress());
  1435. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1"));
  1436. }
  1437. if ((0 == payload) || (2 == payload)) {
  1438. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\",\"" D_JSON_BOOTVERSION "\":%d,\"" D_JSON_COREVERSION "\":\"" ARDUINO_ESP8266_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\"}}"),
  1439. my_version, my_image, GetBuildDateAndTime().c_str(), ESP.getBootVersion(), ESP.getSdkVersion());
  1440. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "2"));
  1441. }
  1442. if ((0 == payload) || (3 == payload)) {
  1443. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\"" D_CMND_SETOPTION "\":[\"%08X\",\"%08X\",\"%08X\"]}}"),
  1444. Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period, Settings.flag.data, Settings.flag2.data, Settings.flag3.data);
  1445. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3"));
  1446. }
  1447. if ((0 == payload) || (4 == payload)) {
  1448. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\"" D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\"" D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]}}"),
  1449. ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipId(), ESP.getFlashChipMode(), LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2);
  1450. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4"));
  1451. }
  1452. if ((0 == payload) || (5 == payload)) {
  1453. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\"" D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\"" D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d}}"),
  1454. my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(), IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(),
  1455. WiFi.macAddress().c_str(), Settings.webserver, Settings.sta_config);
  1456. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5"));
  1457. }
  1458. if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) {
  1459. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MqttType\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
  1460. Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
  1461. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6"));
  1462. }
  1463. if ((0 == payload) || (7 == payload)) {
  1464. if (99 == Settings.timezone) {
  1465. snprintf_P(stemp, sizeof(stemp), PSTR("%d" ), Settings.timezone);
  1466. } else {
  1467. snprintf_P(stemp, sizeof(stemp), PSTR("\"%s\"" ), GetTimeZone().c_str());
  1468. }
  1469. #if defined(USE_TIMERS) && defined(USE_SUNRISE)
  1470. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\"" D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%s,\"" D_JSON_SUNRISE "\":\"%s\",\"" D_JSON_SUNSET "\":\"%s\"}}"),
  1471. GetTime(0).c_str(), GetTime(1).c_str(), GetTime(2).c_str(), GetTime(3).c_str(), stemp, GetSun(0).c_str(), GetSun(1).c_str());
  1472. #else
  1473. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\"" D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%s}}"),
  1474. GetTime(0).c_str(), GetTime(1).c_str(), GetTime(2).c_str(), GetTime(3).c_str(), stemp);
  1475. #endif // USE_TIMERS and USE_SUNRISE
  1476. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "7"));
  1477. }
  1478. if (energy_flg) {
  1479. if ((0 == payload) || (9 == payload)) {
  1480. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":%d,\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\"" D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"),
  1481. Settings.energy_power_delta, Settings.energy_min_power, Settings.energy_max_power, Settings.energy_min_voltage, Settings.energy_max_voltage, Settings.energy_min_current, Settings.energy_max_current);
  1482. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "9"));
  1483. }
  1484. }
  1485. if ((0 == payload) || (8 == payload) || (10 == payload)) {
  1486. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS10_SENSOR "\":"));
  1487. MqttShowSensor();
  1488. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
  1489. if (8 == payload) {
  1490. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "8"));
  1491. } else {
  1492. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "10"));
  1493. }
  1494. }
  1495. if ((0 == payload) || (11 == payload)) {
  1496. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS11_STATUS "\":"));
  1497. MqttShowState();
  1498. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
  1499. MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "11"));
  1500. }
  1501. }
  1502. void MqttShowPWMState(void)
  1503. {
  1504. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_PWM "\":{"), mqtt_data);
  1505. bool first = true;
  1506. for (byte i = 0; i < MAX_PWMS; i++) {
  1507. if (pin[GPIO_PWM1 + i] < 99) {
  1508. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ",", i+1, Settings.pwm_value[i]);
  1509. first = false;
  1510. }
  1511. }
  1512. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
  1513. }
  1514. void MqttShowState(void)
  1515. {
  1516. char stemp1[33];
  1517. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\""), mqtt_data, GetDateAndTime(DT_LOCAL).c_str(), GetUptime().c_str());
  1518. #ifdef USE_ADC_VCC
  1519. dtostrfd((double)ESP.getVcc()/1000, 3, stemp1);
  1520. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_VCC "\":%s"), mqtt_data, stemp1);
  1521. #endif
  1522. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SleepMode\":\"%s\",\"Sleep\":%u,\"LoadAvg\":%u"),
  1523. mqtt_data, GetTextIndexed(stemp1, sizeof(stemp1), Settings.flag3.sleep_normal, kSleepMode), sleep, loop_load_avg);
  1524. for (byte i = 0; i < devices_present; i++) {
  1525. if (i == light_device -1) {
  1526. LightState(1);
  1527. } else {
  1528. 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)));
  1529. if (SONOFF_IFAN02 == Settings.module) {
  1530. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_FANSPEED "\":%d"), mqtt_data, GetFanspeed());
  1531. break;
  1532. }
  1533. }
  1534. }
  1535. if (pwm_present) {
  1536. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
  1537. MqttShowPWMState();
  1538. }
  1539. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d}}"),
  1540. mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WiFi.BSSIDstr().c_str(), WiFi.channel(), WifiGetRssiAsQuality(WiFi.RSSI()));
  1541. }
  1542. boolean MqttShowSensor(void)
  1543. {
  1544. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{\"" D_JSON_TIME "\":\"%s\""), mqtt_data, GetDateAndTime(DT_LOCAL).c_str());
  1545. int json_data_start = strlen(mqtt_data);
  1546. for (byte i = 0; i < MAX_SWITCHES; i++) {
  1547. #ifdef USE_TM1638
  1548. if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) {
  1549. #else
  1550. if (pin[GPIO_SWT1 +i] < 99) {
  1551. #endif // USE_TM1638
  1552. boolean swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i]));
  1553. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_SWITCH "%d\":\"%s\""), mqtt_data, i +1, GetStateText(swm ^ lastwallswitch[i]));
  1554. }
  1555. }
  1556. XsnsCall(FUNC_JSON_APPEND);
  1557. boolean json_data_available = (strlen(mqtt_data) - json_data_start);
  1558. if (strstr_P(mqtt_data, PSTR(D_JSON_PRESSURE))) {
  1559. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_PRESSURE_UNIT "\":\"%s\""), mqtt_data, PressureUnit().c_str());
  1560. }
  1561. if (strstr_P(mqtt_data, PSTR(D_JSON_TEMPERATURE))) {
  1562. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_TEMPERATURE_UNIT "\":\"%c\""), mqtt_data, TempUnit());
  1563. }
  1564. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
  1565. if (json_data_available) XdrvCall(FUNC_SHOW_SENSOR);
  1566. return json_data_available;
  1567. }
  1568. /********************************************************************************************/
  1569. void PerformEverySecond(void)
  1570. {
  1571. uptime++;
  1572. if (BOOT_LOOP_TIME == uptime) {
  1573. RtcReboot.fast_reboot_count = 0;
  1574. RtcRebootSave();
  1575. Settings.bootcount++; // Moved to here to stop flash writes during start-up
  1576. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BOOT_COUNT " %d"), Settings.bootcount);
  1577. AddLog(LOG_LEVEL_DEBUG);
  1578. }
  1579. if ((4 == uptime) && (SONOFF_IFAN02 == Settings.module)) { // Microcontroller needs 3 seconds before accepting commands
  1580. SetDevicePower(1, SRC_RETRY); // Sync with default power on state microcontroller being Light ON and Fan OFF
  1581. SetDevicePower(power, SRC_RETRY); // Set required power on state
  1582. }
  1583. if (seriallog_timer) {
  1584. seriallog_timer--;
  1585. if (!seriallog_timer) {
  1586. if (seriallog_level) {
  1587. AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SERIAL_LOGGING_DISABLED));
  1588. }
  1589. seriallog_level = 0;
  1590. }
  1591. }
  1592. if (syslog_timer) { // Restore syslog level
  1593. syslog_timer--;
  1594. if (!syslog_timer) {
  1595. syslog_level = Settings.syslog_level;
  1596. if (Settings.syslog_level) {
  1597. AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SYSLOG_LOGGING_REENABLED)); // Might trigger disable again (on purpose)
  1598. }
  1599. }
  1600. }
  1601. ResetGlobalValues();
  1602. if (Settings.tele_period) {
  1603. tele_period++;
  1604. if (tele_period == Settings.tele_period -1) {
  1605. XsnsCall(FUNC_PREP_BEFORE_TELEPERIOD);
  1606. }
  1607. if (tele_period >= Settings.tele_period) {
  1608. tele_period = 0;
  1609. mqtt_data[0] = '\0';
  1610. MqttShowState();
  1611. MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN);
  1612. mqtt_data[0] = '\0';
  1613. if (MqttShowSensor()) {
  1614. MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
  1615. #ifdef USE_RULES
  1616. RulesTeleperiod(); // Allow rule based HA messages
  1617. #endif // USE_RULES
  1618. }
  1619. }
  1620. }
  1621. XdrvCall(FUNC_EVERY_SECOND);
  1622. XsnsCall(FUNC_EVERY_SECOND);
  1623. if ((2 == RtcTime.minute) && latest_uptime_flag) {
  1624. latest_uptime_flag = false;
  1625. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\"}"), GetDateAndTime(DT_LOCAL).c_str(), GetUptime().c_str());
  1626. MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_UPTIME));
  1627. }
  1628. if ((3 == RtcTime.minute) && !latest_uptime_flag) latest_uptime_flag = true;
  1629. }
  1630. /*********************************************************************************************\
  1631. * Button handler with single press only or multi-press and hold on all buttons
  1632. \*********************************************************************************************/
  1633. void ButtonHandler(void)
  1634. {
  1635. uint8_t button = NOT_PRESSED;
  1636. uint8_t button_present = 0;
  1637. uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command
  1638. uint16_t loops_per_second = 1000 / Settings.button_debounce;
  1639. char scmnd[20];
  1640. uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present;
  1641. for (byte button_index = 0; button_index < maxdev; button_index++) {
  1642. button = NOT_PRESSED;
  1643. button_present = 0;
  1644. if (!button_index && ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module))) {
  1645. button_present = 1;
  1646. if (dual_button_code) {
  1647. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code);
  1648. AddLog(LOG_LEVEL_DEBUG);
  1649. button = PRESSED;
  1650. if (0xF500 == dual_button_code) { // Button hold
  1651. holdbutton[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1;
  1652. hold_time_extent = 1;
  1653. }
  1654. dual_button_code = 0;
  1655. }
  1656. } else {
  1657. if (pin[GPIO_KEY1 +button_index] < 99) {
  1658. if (!((uptime < 4) && (0 == pin[GPIO_KEY1 +button_index]))) { // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit
  1659. button_present = 1;
  1660. button = digitalRead(pin[GPIO_KEY1 +button_index]);
  1661. }
  1662. }
  1663. }
  1664. if (button_present) {
  1665. XdrvMailbox.index = button_index;
  1666. XdrvMailbox.payload = button;
  1667. if (XdrvCall(FUNC_BUTTON_PRESSED)) {
  1668. // Serviced
  1669. }
  1670. else if (SONOFF_4CHPRO == Settings.module) {
  1671. if (holdbutton[button_index]) { holdbutton[button_index]--; }
  1672. boolean button_pressed = false;
  1673. if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
  1674. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1);
  1675. AddLog(LOG_LEVEL_DEBUG);
  1676. holdbutton[button_index] = loops_per_second;
  1677. button_pressed = true;
  1678. }
  1679. if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) {
  1680. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1);
  1681. AddLog(LOG_LEVEL_DEBUG);
  1682. if (!holdbutton[button_index]) { button_pressed = true; } // Do not allow within 1 second
  1683. }
  1684. if (button_pressed) {
  1685. if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
  1686. ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
  1687. }
  1688. }
  1689. }
  1690. else {
  1691. if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
  1692. if (Settings.flag.button_single) { // Allow only single button press for immediate action
  1693. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1);
  1694. AddLog(LOG_LEVEL_DEBUG);
  1695. if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
  1696. ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
  1697. }
  1698. } else {
  1699. multipress[button_index] = (multiwindow[button_index]) ? multipress[button_index] +1 : 1;
  1700. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, multipress[button_index]);
  1701. AddLog(LOG_LEVEL_DEBUG);
  1702. multiwindow[button_index] = loops_per_second / 2; // 0.5 second multi press window
  1703. }
  1704. blinks = 201;
  1705. }
  1706. if (NOT_PRESSED == button) {
  1707. holdbutton[button_index] = 0;
  1708. } else {
  1709. holdbutton[button_index]++;
  1710. if (Settings.flag.button_single) { // Allow only single button press for immediate action
  1711. if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer
  1712. // Settings.flag.button_single = 0;
  1713. snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only
  1714. ExecuteCommand(scmnd, SRC_BUTTON);
  1715. }
  1716. } else {
  1717. if (Settings.flag.button_restrict) { // Button restriction
  1718. if (holdbutton[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // Button hold
  1719. multipress[button_index] = 0;
  1720. SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set
  1721. }
  1722. } else {
  1723. if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer
  1724. multipress[button_index] = 0;
  1725. snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
  1726. ExecuteCommand(scmnd, SRC_BUTTON);
  1727. }
  1728. }
  1729. }
  1730. }
  1731. if (!Settings.flag.button_single) { // Allow multi-press
  1732. if (multiwindow[button_index]) {
  1733. multiwindow[button_index]--;
  1734. } else {
  1735. if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) {
  1736. boolean single_press = false;
  1737. if (multipress[button_index] < 3) { // Single or Double press
  1738. if ((SONOFF_DUAL_R2 == Settings.module) || (SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
  1739. single_press = true;
  1740. } else {
  1741. single_press = (Settings.flag.button_swap +1 == multipress[button_index]);
  1742. multipress[button_index] = 1;
  1743. }
  1744. }
  1745. if (single_press && SendKey(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
  1746. // Success
  1747. } else {
  1748. if (multipress[button_index] < 3) { // Single or Double press
  1749. if (WifiState() > WIFI_RESTART) { // WPSconfig, Smartconfig or Wifimanager active
  1750. restart_flag = 1;
  1751. } else {
  1752. ExecuteCommandPower(button_index + multipress[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
  1753. }
  1754. } else { // 3 - 7 press
  1755. if (!Settings.flag.button_restrict) {
  1756. snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[button_index] -3]);
  1757. ExecuteCommand(scmnd, SRC_BUTTON);
  1758. }
  1759. }
  1760. }
  1761. multipress[button_index] = 0;
  1762. }
  1763. }
  1764. }
  1765. }
  1766. }
  1767. lastbutton[button_index] = button;
  1768. }
  1769. }
  1770. /*********************************************************************************************\
  1771. * Switch handler
  1772. \*********************************************************************************************/
  1773. void SwitchHandler(byte mode)
  1774. {
  1775. uint8_t button = NOT_PRESSED;
  1776. uint8_t switchflag;
  1777. uint16_t loops_per_second = 1000 / Settings.switch_debounce;
  1778. for (byte i = 0; i < MAX_SWITCHES; i++) {
  1779. if ((pin[GPIO_SWT1 +i] < 99) || (mode)) {
  1780. if (holdwallswitch[i]) {
  1781. holdwallswitch[i]--;
  1782. if (0 == holdwallswitch[i]) {
  1783. SendKey(1, i +1, 3); // Execute command via MQTT
  1784. }
  1785. }
  1786. if (mode) {
  1787. button = virtualswitch[i];
  1788. } else {
  1789. if (!((uptime < 4) && (0 == pin[GPIO_SWT1 +i]))) { // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit
  1790. button = digitalRead(pin[GPIO_SWT1 +i]);
  1791. }
  1792. }
  1793. if (button != lastwallswitch[i]) {
  1794. switchflag = 3;
  1795. switch (Settings.switchmode[i]) {
  1796. case TOGGLE:
  1797. switchflag = 2; // Toggle
  1798. break;
  1799. case FOLLOW:
  1800. switchflag = button &1; // Follow wall switch state
  1801. break;
  1802. case FOLLOW_INV:
  1803. switchflag = ~button &1; // Follow inverted wall switch state
  1804. break;
  1805. case PUSHBUTTON:
  1806. if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) {
  1807. switchflag = 2; // Toggle with pushbutton to Gnd
  1808. }
  1809. break;
  1810. case PUSHBUTTON_INV:
  1811. if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) {
  1812. switchflag = 2; // Toggle with releasing pushbutton from Gnd
  1813. }
  1814. break;
  1815. case PUSHBUTTON_TOGGLE:
  1816. if (button != lastwallswitch[i]) {
  1817. switchflag = 2; // Toggle with any pushbutton change
  1818. }
  1819. break;
  1820. case PUSHBUTTONHOLD:
  1821. if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) {
  1822. holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10;
  1823. }
  1824. if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) {
  1825. holdwallswitch[i] = 0;
  1826. switchflag = 2; // Toggle with pushbutton to Gnd
  1827. }
  1828. break;
  1829. case PUSHBUTTONHOLD_INV:
  1830. if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) {
  1831. holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10;
  1832. }
  1833. if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) {
  1834. holdwallswitch[i] = 0;
  1835. switchflag = 2; // Toggle with pushbutton to Gnd
  1836. }
  1837. break;
  1838. }
  1839. if (switchflag < 3) {
  1840. if (!SendKey(1, i +1, switchflag)) { // Execute command via MQTT
  1841. ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present)
  1842. }
  1843. }
  1844. lastwallswitch[i] = button;
  1845. }
  1846. }
  1847. }
  1848. }
  1849. /*********************************************************************************************\
  1850. * State loops
  1851. \*********************************************************************************************/
  1852. /*-------------------------------------------------------------------------------------------*\
  1853. * Every 0.1 second
  1854. \*-------------------------------------------------------------------------------------------*/
  1855. void Every100mSeconds(void)
  1856. {
  1857. // As the max amount of sleep = 250 mSec this loop will shift in time...
  1858. power_t power_now;
  1859. if (latching_relay_pulse) {
  1860. latching_relay_pulse--;
  1861. if (!latching_relay_pulse) SetLatchingRelay(0, 0);
  1862. }
  1863. for (byte i = 0; i < MAX_PULSETIMERS; i++) {
  1864. if (pulse_timer[i] != 0L) { // Timer active?
  1865. if (TimeReached(pulse_timer[i])) { // Timer finished?
  1866. pulse_timer[i] = 0L; // Turn off this timer
  1867. ExecuteCommandPower(i +1, (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? POWER_ON : POWER_OFF, SRC_PULSETIMER);
  1868. }
  1869. }
  1870. }
  1871. if (blink_mask) {
  1872. if (TimeReached(blink_timer)) {
  1873. SetNextTimeInterval(blink_timer, 100 * Settings.blinktime);
  1874. blink_counter--;
  1875. if (!blink_counter) {
  1876. StopAllPowerBlink();
  1877. } else {
  1878. blink_power ^= 1;
  1879. power_now = (power & (POWER_MASK ^ blink_mask)) | ((blink_power) ? blink_mask : 0);
  1880. SetDevicePower(power_now, SRC_IGNORE);
  1881. }
  1882. }
  1883. }
  1884. // Backlog
  1885. if (TimeReached(backlog_delay)) {
  1886. if ((backlog_pointer != backlog_index) && !backlog_mutex) {
  1887. backlog_mutex = 1;
  1888. ExecuteCommand((char*)backlog[backlog_pointer].c_str(), SRC_BACKLOG);
  1889. backlog_mutex = 0;
  1890. backlog_pointer++;
  1891. if (backlog_pointer >= MAX_BACKLOG) { backlog_pointer = 0; }
  1892. }
  1893. }
  1894. }
  1895. /*-------------------------------------------------------------------------------------------*\
  1896. * Every 0.25 second
  1897. \*-------------------------------------------------------------------------------------------*/
  1898. void Every250mSeconds(void)
  1899. {
  1900. // As the max amount of sleep = 250 mSec this loop should always be taken...
  1901. uint8_t blinkinterval = 1;
  1902. state_250mS++;
  1903. state_250mS &= 0x3;
  1904. if (mqtt_cmnd_publish) mqtt_cmnd_publish--; // Clean up
  1905. if (!Settings.flag.global_state) { // Problem blinkyblinky enabled
  1906. if (global_state.data) { // Any problem
  1907. if (global_state.mqtt_down) { blinkinterval = 7; } // MQTT problem so blink every 2 seconds (slowest)
  1908. if (global_state.wifi_down) { blinkinterval = 3; } // Wifi problem so blink every second (slow)
  1909. blinks = 201; // Allow only a single blink in case the problem is solved
  1910. }
  1911. }
  1912. if (blinks || restart_flag || ota_state_flag) {
  1913. if (restart_flag || ota_state_flag) { // Overrule blinks and keep led lit
  1914. blinkstate = 1; // Stay lit
  1915. } else {
  1916. blinkspeed--;
  1917. if (!blinkspeed) {
  1918. blinkspeed = blinkinterval; // Set interval to 0.2 (default), 1 or 2 seconds
  1919. blinkstate ^= 1; // Blink
  1920. }
  1921. }
  1922. if ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) {
  1923. // if ( (!Settings.flag.global_state && global_state.data) || ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) ) {
  1924. SetLedPower(blinkstate); // Set led on or off
  1925. }
  1926. if (!blinkstate) {
  1927. blinks--;
  1928. if (200 == blinks) blinks = 0; // Disable blink
  1929. }
  1930. }
  1931. else if (Settings.ledstate &1) {
  1932. boolean tstate = power;
  1933. if ((SONOFF_TOUCH == Settings.module) || (SONOFF_T11 == Settings.module) || (SONOFF_T12 == Settings.module) || (SONOFF_T13 == Settings.module)) {
  1934. tstate = (!power) ? 1 : 0; // As requested invert signal for Touch devices to find them in the dark
  1935. }
  1936. SetLedPower(tstate);
  1937. }
  1938. /*-------------------------------------------------------------------------------------------*\
  1939. * Every second at 0.25 second interval
  1940. \*-------------------------------------------------------------------------------------------*/
  1941. switch (state_250mS) {
  1942. case 0: // Every x.0 second
  1943. PerformEverySecond();
  1944. if (ota_state_flag && (backlog_pointer == backlog_index)) {
  1945. ota_state_flag--;
  1946. if (2 == ota_state_flag) {
  1947. ota_url = Settings.ota_url;
  1948. RtcSettings.ota_loader = 0; // Try requested image first
  1949. ota_retry_counter = OTA_ATTEMPTS;
  1950. ESPhttpUpdate.rebootOnUpdate(false);
  1951. SettingsSave(1); // Free flash for OTA update
  1952. }
  1953. if (ota_state_flag <= 0) {
  1954. #ifdef USE_WEBSERVER
  1955. if (Settings.webserver) StopWebserver();
  1956. #endif // USE_WEBSERVER
  1957. #ifdef USE_ARILUX_RF
  1958. AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine
  1959. #endif // USE_ARILUX_RF
  1960. ota_state_flag = 92;
  1961. ota_result = 0;
  1962. ota_retry_counter--;
  1963. if (ota_retry_counter) {
  1964. strlcpy(mqtt_data, GetOtaUrl(log_data, sizeof(log_data)), sizeof(mqtt_data));
  1965. #ifndef BE_MINIMAL
  1966. if (RtcSettings.ota_loader) {
  1967. char *bch = strrchr(mqtt_data, '/'); // Only consider filename after last backslash prevent change of urls having "-" in it
  1968. char *pch = strrchr((bch != NULL) ? bch : mqtt_data, '-'); // Change from filename-DE.bin into filename-minimal.bin
  1969. char *ech = strrchr((bch != NULL) ? bch : mqtt_data, '.'); // Change from filename.bin into filename-minimal.bin
  1970. if (!pch) pch = ech;
  1971. if (pch) {
  1972. mqtt_data[pch - mqtt_data] = '\0';
  1973. char *ech = strrchr(Settings.ota_url, '.'); // Change from filename.bin into filename-minimal.bin
  1974. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s-" D_JSON_MINIMAL "%s"), mqtt_data, ech); // Minimal filename must be filename-minimal
  1975. }
  1976. }
  1977. #endif // BE_MINIMAL
  1978. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "%s"), mqtt_data);
  1979. AddLog(LOG_LEVEL_DEBUG);
  1980. #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
  1981. ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(mqtt_data));
  1982. #else
  1983. // If using core stage or 2.5.0+ the syntax has changed
  1984. WiFiClient OTAclient;
  1985. ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(OTAclient, mqtt_data));
  1986. #endif
  1987. if (!ota_result) {
  1988. #ifndef BE_MINIMAL
  1989. int ota_error = ESPhttpUpdate.getLastError();
  1990. // snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Ota error %d"), ota_error);
  1991. // AddLog(LOG_LEVEL_DEBUG);
  1992. if ((HTTP_UE_TOO_LESS_SPACE == ota_error) || (HTTP_UE_BIN_FOR_WRONG_FLASH == ota_error)) {
  1993. RtcSettings.ota_loader = 1; // Try minimal image next
  1994. }
  1995. #endif // BE_MINIMAL
  1996. ota_state_flag = 2; // Upgrade failed - retry
  1997. }
  1998. }
  1999. }
  2000. if (90 == ota_state_flag) { // Allow MQTT to reconnect
  2001. ota_state_flag = 0;
  2002. if (ota_result) {
  2003. // SetFlashModeDout(); // Force DOUT for both ESP8266 and ESP8285
  2004. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING));
  2005. } else {
  2006. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_JSON_FAILED " %s"), ESPhttpUpdate.getLastErrorString().c_str());
  2007. }
  2008. restart_flag = 2; // Restart anyway to keep memory clean webserver
  2009. MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_UPGRADE));
  2010. }
  2011. }
  2012. break;
  2013. case 1: // Every x.25 second
  2014. if (MidnightNow()) { CounterSaveState(); }
  2015. if (save_data_counter && (backlog_pointer == backlog_index)) {
  2016. save_data_counter--;
  2017. if (save_data_counter <= 0) {
  2018. if (Settings.flag.save_state) {
  2019. power_t mask = POWER_MASK;
  2020. for (byte i = 0; i < MAX_PULSETIMERS; i++) {
  2021. if ((Settings.pulse_timer[i] > 0) && (Settings.pulse_timer[i] < 30)) { // 3 seconds
  2022. mask &= ~(1 << i);
  2023. }
  2024. }
  2025. if (!((Settings.power &mask) == (power &mask))) {
  2026. Settings.power = power;
  2027. }
  2028. } else {
  2029. Settings.power = 0;
  2030. }
  2031. SettingsSave(0);
  2032. save_data_counter = Settings.save_data;
  2033. }
  2034. }
  2035. if (restart_flag && (backlog_pointer == backlog_index)) {
  2036. if ((214 == restart_flag) || (215 == restart_flag)) {
  2037. char storage[sizeof(Settings.sta_ssid) + sizeof(Settings.sta_pwd)];
  2038. memcpy(storage, Settings.sta_ssid, sizeof(storage)); // Backup current SSIDs and Passwords
  2039. if (215 == restart_flag) {
  2040. SettingsErase(0); // Erase all flash from program end to end of physical flash
  2041. }
  2042. SettingsDefault();
  2043. memcpy(Settings.sta_ssid, storage, sizeof(storage)); // Restore current SSIDs and Passwords
  2044. restart_flag = 2;
  2045. }
  2046. else if (213 == restart_flag) {
  2047. SettingsSdkErase(); // Erase flash SDK parameters
  2048. restart_flag = 2;
  2049. }
  2050. else if (212 == restart_flag) {
  2051. SettingsErase(0); // Erase all flash from program end to end of physical flash
  2052. restart_flag = 211;
  2053. }
  2054. if (211 == restart_flag) {
  2055. SettingsDefault();
  2056. restart_flag = 2;
  2057. }
  2058. SettingsSaveAll();
  2059. restart_flag--;
  2060. if (restart_flag <= 0) {
  2061. AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING));
  2062. EspRestart();
  2063. }
  2064. }
  2065. break;
  2066. case 2: // Every x.5 second
  2067. WifiCheck(wifi_state_flag);
  2068. wifi_state_flag = WIFI_RESTART;
  2069. break;
  2070. case 3: // Every x.75 second
  2071. if (!global_state.wifi_down) { MqttCheck(); }
  2072. break;
  2073. }
  2074. }
  2075. #ifdef USE_ARDUINO_OTA
  2076. /*********************************************************************************************\
  2077. * Allow updating via the Arduino OTA-protocol.
  2078. *
  2079. * - Once started disables current wifi clients and udp
  2080. * - Perform restart when done to re-init wifi clients
  2081. \*********************************************************************************************/
  2082. bool arduino_ota_triggered = false;
  2083. uint16_t arduino_ota_progress_dot_count = 0;
  2084. void ArduinoOTAInit(void)
  2085. {
  2086. ArduinoOTA.setPort(8266);
  2087. ArduinoOTA.setHostname(my_hostname);
  2088. if (Settings.web_password[0] !=0) ArduinoOTA.setPassword(Settings.web_password);
  2089. ArduinoOTA.onStart([]()
  2090. {
  2091. SettingsSave(1); // Free flash for OTA update
  2092. #ifdef USE_WEBSERVER
  2093. if (Settings.webserver) StopWebserver();
  2094. #endif // USE_WEBSERVER
  2095. #ifdef USE_ARILUX_RF
  2096. AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine
  2097. #endif // USE_ARILUX_RF
  2098. if (Settings.flag.mqtt_enabled) MqttDisconnect();
  2099. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_UPLOAD_STARTED));
  2100. AddLog(LOG_LEVEL_INFO);
  2101. arduino_ota_triggered = true;
  2102. arduino_ota_progress_dot_count = 0;
  2103. delay(100); // Allow time for message xfer
  2104. });
  2105. ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
  2106. {
  2107. if ((LOG_LEVEL_DEBUG <= seriallog_level)) {
  2108. arduino_ota_progress_dot_count++;
  2109. Serial.printf(".");
  2110. if (!(arduino_ota_progress_dot_count % 80)) Serial.println();
  2111. }
  2112. });
  2113. ArduinoOTA.onError([](ota_error_t error)
  2114. {
  2115. /*
  2116. From ArduinoOTA.h:
  2117. typedef enum { OTA_AUTH_ERROR, OTA_BEGIN_ERROR, OTA_CONNECT_ERROR, OTA_RECEIVE_ERROR, OTA_END_ERROR } ota_error_t;
  2118. */
  2119. char error_str[100];
  2120. if ((LOG_LEVEL_DEBUG <= seriallog_level) && arduino_ota_progress_dot_count) Serial.println();
  2121. switch (error) {
  2122. case OTA_BEGIN_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_2), sizeof(error_str)); break;
  2123. case OTA_RECEIVE_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_5), sizeof(error_str)); break;
  2124. case OTA_END_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_7), sizeof(error_str)); break;
  2125. default:
  2126. snprintf_P(error_str, sizeof(error_str), PSTR(D_UPLOAD_ERROR_CODE " %d"), error);
  2127. }
  2128. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA %s. " D_RESTARTING), error_str);
  2129. AddLog(LOG_LEVEL_INFO);
  2130. EspRestart();
  2131. });
  2132. ArduinoOTA.onEnd([]()
  2133. {
  2134. if ((LOG_LEVEL_DEBUG <= seriallog_level)) Serial.println();
  2135. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_SUCCESSFUL ". " D_RESTARTING));
  2136. AddLog(LOG_LEVEL_INFO);
  2137. EspRestart();
  2138. });
  2139. ArduinoOTA.begin();
  2140. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_ENABLED " " D_PORT " 8266"));
  2141. AddLog(LOG_LEVEL_INFO);
  2142. }
  2143. #endif // USE_ARDUINO_OTA
  2144. /********************************************************************************************/
  2145. void SerialInput(void)
  2146. {
  2147. while (Serial.available()) {
  2148. yield();
  2149. serial_in_byte = Serial.read();
  2150. /*-------------------------------------------------------------------------------------------*\
  2151. * Sonoff dual and ch4 19200 baud serial interface
  2152. \*-------------------------------------------------------------------------------------------*/
  2153. if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
  2154. if (dual_hex_code) {
  2155. dual_hex_code--;
  2156. if (dual_hex_code) {
  2157. dual_button_code = (dual_button_code << 8) | serial_in_byte;
  2158. serial_in_byte = 0;
  2159. } else {
  2160. if (serial_in_byte != 0xA1) {
  2161. dual_button_code = 0; // 0xA1 - End of Sonoff dual button code
  2162. }
  2163. }
  2164. }
  2165. if (0xA0 == serial_in_byte) { // 0xA0 - Start of Sonoff dual button code
  2166. serial_in_byte = 0;
  2167. dual_button_code = 0;
  2168. dual_hex_code = 3;
  2169. }
  2170. }
  2171. /*-------------------------------------------------------------------------------------------*/
  2172. if (XdrvCall(FUNC_SERIAL)) {
  2173. serial_in_byte_counter = 0;
  2174. Serial.flush();
  2175. return;
  2176. }
  2177. /*-------------------------------------------------------------------------------------------*/
  2178. if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data...
  2179. serial_in_byte_counter = 0;
  2180. Serial.flush();
  2181. return;
  2182. }
  2183. if (!Settings.flag.mqtt_serial) {
  2184. if (isprint(serial_in_byte)) {
  2185. if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
  2186. serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
  2187. } else {
  2188. serial_in_byte_counter = 0;
  2189. }
  2190. }
  2191. } else {
  2192. if (serial_in_byte || Settings.flag.mqtt_serial_raw) {
  2193. if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) &&
  2194. ((serial_in_byte != Settings.serial_delimiter) || Settings.flag.mqtt_serial_raw)) { // add char to string if it still fits
  2195. serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
  2196. serial_polling_window = millis();
  2197. } else {
  2198. serial_polling_window = 0;
  2199. break;
  2200. }
  2201. }
  2202. }
  2203. /*-------------------------------------------------------------------------------------------*\
  2204. * Sonoff SC 19200 baud serial interface
  2205. \*-------------------------------------------------------------------------------------------*/
  2206. if (SONOFF_SC == Settings.module) {
  2207. if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P
  2208. serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
  2209. SonoffScSerialInput(serial_in_buffer);
  2210. serial_in_byte_counter = 0;
  2211. Serial.flush();
  2212. return;
  2213. }
  2214. }
  2215. /*-------------------------------------------------------------------------------------------*/
  2216. else if (!Settings.flag.mqtt_serial && (serial_in_byte == '\n')) {
  2217. serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
  2218. seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level;
  2219. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer);
  2220. AddLog(LOG_LEVEL_INFO);
  2221. ExecuteCommand(serial_in_buffer, SRC_SERIAL);
  2222. serial_in_byte_counter = 0;
  2223. serial_polling_window = 0;
  2224. Serial.flush();
  2225. return;
  2226. }
  2227. }
  2228. if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) {
  2229. serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
  2230. if (!Settings.flag.mqtt_serial_raw) {
  2231. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer);
  2232. } else {
  2233. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\""));
  2234. for (int i = 0; i < serial_in_byte_counter; i++) {
  2235. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%02x"), mqtt_data, serial_in_buffer[i]);
  2236. }
  2237. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}"), mqtt_data);
  2238. }
  2239. MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
  2240. // XdrvRulesProcess();
  2241. serial_in_byte_counter = 0;
  2242. }
  2243. }
  2244. /********************************************************************************************/
  2245. void GpioSwitchPinMode(uint8_t index)
  2246. {
  2247. if (pin[GPIO_SWT1 +index] < 99) {
  2248. pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, index) ? INPUT : INPUT_PULLUP);
  2249. /*
  2250. // Re-enable pull-up on Shelly2 as of 20181110 (#4255)
  2251. uint8_t no_pullup = bitRead(switch_no_pullup, index); // 0 = INPUT_PULLUP, 1 = INPUT
  2252. if (no_pullup) {
  2253. if (SHELLY2 == Settings.module) {
  2254. // Switchmodes : TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION
  2255. no_pullup = (Settings.switchmode[index] < PUSHBUTTON); // INPUT on TOGGLE, FOLLOW and FOLLOW_INV. INPUT_PULLUP on anything else
  2256. }
  2257. }
  2258. pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : (no_pullup) ? INPUT : INPUT_PULLUP);
  2259. */
  2260. }
  2261. }
  2262. void GpioInit(void)
  2263. {
  2264. uint8_t mpin;
  2265. uint8_t key_no_pullup = 0;
  2266. mytmplt def_module;
  2267. if (Settings.module >= MAXMODULE) {
  2268. Settings.module = MODULE;
  2269. Settings.last_module = MODULE;
  2270. }
  2271. if (Settings.module != Settings.last_module) {
  2272. baudrate = APP_BAUDRATE;
  2273. }
  2274. memcpy_P(&def_module, &kModules[Settings.module], sizeof(def_module));
  2275. strlcpy(my_module.name, def_module.name, sizeof(my_module.name));
  2276. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  2277. if (Settings.my_gp.io[i] > GPIO_NONE) {
  2278. my_module.gp.io[i] = Settings.my_gp.io[i];
  2279. }
  2280. if ((def_module.gp.io[i] > GPIO_NONE) && (def_module.gp.io[i] < GPIO_USER)) {
  2281. my_module.gp.io[i] = def_module.gp.io[i];
  2282. }
  2283. }
  2284. for (byte i = 0; i < GPIO_MAX; i++) {
  2285. pin[i] = 99;
  2286. }
  2287. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  2288. mpin = ValidGPIO(i, my_module.gp.io[i]);
  2289. // snprintf_P(log_data, sizeof(log_data), PSTR("DBG: gpio pin %d, mpin %d"), i, mpin);
  2290. // AddLog(LOG_LEVEL_DEBUG);
  2291. if (mpin) {
  2292. if ((mpin >= GPIO_SWT1_NP) && (mpin < (GPIO_SWT1_NP + MAX_SWITCHES))) {
  2293. bitSet(switch_no_pullup, mpin - GPIO_SWT1_NP);
  2294. mpin -= (GPIO_SWT1_NP - GPIO_SWT1);
  2295. }
  2296. else if ((mpin >= GPIO_KEY1_NP) && (mpin < (GPIO_KEY1_NP + MAX_KEYS))) {
  2297. bitSet(key_no_pullup, mpin - GPIO_KEY1_NP);
  2298. mpin -= (GPIO_KEY1_NP - GPIO_KEY1);
  2299. }
  2300. else if ((mpin >= GPIO_REL1_INV) && (mpin < (GPIO_REL1_INV + MAX_RELAYS))) {
  2301. bitSet(rel_inverted, mpin - GPIO_REL1_INV);
  2302. mpin -= (GPIO_REL1_INV - GPIO_REL1);
  2303. }
  2304. else if ((mpin >= GPIO_LED1_INV) && (mpin < (GPIO_LED1_INV + MAX_LEDS))) {
  2305. bitSet(led_inverted, mpin - GPIO_LED1_INV);
  2306. mpin -= (GPIO_LED1_INV - GPIO_LED1);
  2307. }
  2308. else if ((mpin >= GPIO_PWM1_INV) && (mpin < (GPIO_PWM1_INV + MAX_PWMS))) {
  2309. bitSet(pwm_inverted, mpin - GPIO_PWM1_INV);
  2310. mpin -= (GPIO_PWM1_INV - GPIO_PWM1);
  2311. }
  2312. else if ((mpin >= GPIO_CNTR1_NP) && (mpin < (GPIO_CNTR1_NP + MAX_COUNTERS))) {
  2313. bitSet(counter_no_pullup, mpin - GPIO_CNTR1_NP);
  2314. mpin -= (GPIO_CNTR1_NP - GPIO_CNTR1);
  2315. }
  2316. #ifdef USE_DHT
  2317. else if ((mpin >= GPIO_DHT11) && (mpin <= GPIO_SI7021)) {
  2318. if (DhtSetup(i, mpin)) {
  2319. dht_flg = 1;
  2320. mpin = GPIO_DHT11;
  2321. } else {
  2322. mpin = 0;
  2323. }
  2324. }
  2325. #endif // USE_DHT
  2326. }
  2327. if (mpin) pin[mpin] = i;
  2328. }
  2329. if ((2 == pin[GPIO_TXD]) || (H801 == Settings.module)) { Serial.set_tx(2); }
  2330. analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h)
  2331. analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
  2332. #ifdef USE_SPI
  2333. 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)));
  2334. if (spi_flg) {
  2335. for (byte i = 0; i < GPIO_MAX; i++) {
  2336. if ((pin[i] >= 12) && (pin[i] <=14)) pin[i] = 99;
  2337. }
  2338. my_module.gp.io[12] = GPIO_SPI_MISO;
  2339. pin[GPIO_SPI_MISO] = 12;
  2340. my_module.gp.io[13] = GPIO_SPI_MOSI;
  2341. pin[GPIO_SPI_MOSI] = 13;
  2342. my_module.gp.io[14] = GPIO_SPI_CLK;
  2343. pin[GPIO_SPI_CLK] = 14;
  2344. }
  2345. soft_spi_flg = ((pin[GPIO_SSPI_CS] < 99) && (pin[GPIO_SSPI_SCLK] < 99) && ((pin[GPIO_SSPI_MOSI] < 99) || (pin[GPIO_SSPI_MOSI] < 99)));
  2346. #endif // USE_SPI
  2347. #ifdef USE_I2C
  2348. i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99));
  2349. if (i2c_flg) Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]);
  2350. #endif // USE_I2C
  2351. devices_present = 1;
  2352. light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
  2353. if (Settings.flag.pwm_control) {
  2354. for (byte i = 0; i < MAX_PWMS; i++) {
  2355. if (pin[GPIO_PWM1 +i] < 99) light_type++; // Use Dimmer/Color control for all PWM as SetOption15 = 1
  2356. }
  2357. }
  2358. if (SONOFF_BRIDGE == Settings.module) {
  2359. Settings.flag.mqtt_serial = 0;
  2360. baudrate = 19200;
  2361. }
  2362. if (XdrvCall(FUNC_MODULE_INIT)) {
  2363. // Serviced
  2364. }
  2365. else if (SONOFF_DUAL == Settings.module) {
  2366. Settings.flag.mqtt_serial = 0;
  2367. devices_present = 2;
  2368. baudrate = 19200;
  2369. }
  2370. else if (CH4 == Settings.module) {
  2371. Settings.flag.mqtt_serial = 0;
  2372. devices_present = 4;
  2373. baudrate = 19200;
  2374. }
  2375. else if (SONOFF_SC == Settings.module) {
  2376. Settings.flag.mqtt_serial = 0;
  2377. devices_present = 0;
  2378. baudrate = 19200;
  2379. }
  2380. else if (SONOFF_BN == Settings.module) { // PWM Single color led (White)
  2381. light_type = LT_PWM1;
  2382. }
  2383. else if (SONOFF_LED == Settings.module) { // PWM Dual color led (White warm and cold)
  2384. light_type = LT_PWM2;
  2385. }
  2386. else if (AILIGHT == Settings.module) { // RGBW led
  2387. light_type = LT_RGBW;
  2388. }
  2389. else if (SONOFF_B1 == Settings.module) { // RGBWC led
  2390. light_type = LT_RGBWC;
  2391. }
  2392. else {
  2393. if (!light_type) devices_present = 0;
  2394. for (byte i = 0; i < MAX_RELAYS; i++) {
  2395. if (pin[GPIO_REL1 +i] < 99) {
  2396. pinMode(pin[GPIO_REL1 +i], OUTPUT);
  2397. devices_present++;
  2398. if (EXS_RELAY == Settings.module) {
  2399. digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0);
  2400. if (i &1) { devices_present--; }
  2401. }
  2402. }
  2403. }
  2404. }
  2405. for (byte i = 0; i < MAX_KEYS; i++) {
  2406. if (pin[GPIO_KEY1 +i] < 99) {
  2407. pinMode(pin[GPIO_KEY1 +i], (16 == pin[GPIO_KEY1 +i]) ? INPUT_PULLDOWN_16 : bitRead(key_no_pullup, i) ? INPUT : INPUT_PULLUP);
  2408. }
  2409. }
  2410. for (byte i = 0; i < MAX_LEDS; i++) {
  2411. if (pin[GPIO_LED1 +i] < 99) {
  2412. pinMode(pin[GPIO_LED1 +i], OUTPUT);
  2413. digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i));
  2414. }
  2415. }
  2416. for (byte i = 0; i < MAX_SWITCHES; i++) {
  2417. lastwallswitch[i] = 1; // Init global to virtual switch state;
  2418. if (pin[GPIO_SWT1 +i] < 99) {
  2419. GpioSwitchPinMode(i);
  2420. lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // Set global now so doesn't change the saved power state on first switch check
  2421. }
  2422. virtualswitch[i] = lastwallswitch[i];
  2423. }
  2424. #ifdef USE_WS2812
  2425. if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led
  2426. devices_present++;
  2427. light_type = LT_WS2812;
  2428. }
  2429. #endif // USE_WS2812
  2430. if (!light_type) {
  2431. for (byte i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
  2432. if (pin[GPIO_PWM1 +i] < 99) {
  2433. pwm_present = true;
  2434. pinMode(pin[GPIO_PWM1 +i], OUTPUT);
  2435. analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]);
  2436. }
  2437. }
  2438. }
  2439. SetLedPower(Settings.ledstate &8);
  2440. XdrvCall(FUNC_PRE_INIT);
  2441. }
  2442. extern "C" {
  2443. extern struct rst_info resetInfo;
  2444. }
  2445. void setup(void)
  2446. {
  2447. byte idx;
  2448. RtcRebootLoad();
  2449. if (!RtcRebootValid()) { RtcReboot.fast_reboot_count = 0; }
  2450. RtcReboot.fast_reboot_count++;
  2451. RtcRebootSave();
  2452. Serial.begin(baudrate);
  2453. delay(10);
  2454. Serial.println();
  2455. seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded
  2456. snprintf_P(my_version, sizeof(my_version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff); // Release version 6.3.0
  2457. if (VERSION & 0xff) { // Development or patched version 6.3.0.10
  2458. snprintf_P(my_version, sizeof(my_version), PSTR("%s.%d"), my_version, VERSION & 0xff);
  2459. }
  2460. char code_image[20];
  2461. snprintf_P(my_image, sizeof(my_image), PSTR("(%s)"), GetTextIndexed(code_image, sizeof(code_image), CODE_IMAGE, kCodeImage));
  2462. SettingsLoad();
  2463. SettingsDelta();
  2464. OsWatchInit();
  2465. GetFeatures();
  2466. if (1 == RtcReboot.fast_reboot_count) { // Allow setting override only when all is well
  2467. XdrvCall(FUNC_SETTINGS_OVERRIDE);
  2468. }
  2469. baudrate = Settings.baudrate * 1200;
  2470. mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
  2471. seriallog_level = Settings.seriallog_level;
  2472. seriallog_timer = SERIALLOG_TIMER;
  2473. syslog_level = Settings.syslog_level;
  2474. stop_flash_rotate = Settings.flag.stop_flash_rotate;
  2475. save_data_counter = Settings.save_data;
  2476. sleep = Settings.sleep;
  2477. #ifndef USE_EMULATION
  2478. Settings.flag2.emulation = 0;
  2479. #endif // USE_EMULATION
  2480. // Disable functionality as possible cause of fast restart within BOOT_LOOP_TIME seconds (Exception, WDT or restarts)
  2481. if (RtcReboot.fast_reboot_count > 1) { // Restart twice
  2482. Settings.flag3.user_esp8285_enable = 0; // Disable ESP8285 Generic GPIOs interfering with flash SPI
  2483. if (RtcReboot.fast_reboot_count > 2) { // Restart 3 times
  2484. for (byte i = 0; i < MAX_RULE_SETS; i++) {
  2485. if (bitRead(Settings.rule_stop, i)) {
  2486. bitWrite(Settings.rule_enabled, i, 0); // Disable rules causing boot loop
  2487. }
  2488. }
  2489. }
  2490. if (RtcReboot.fast_reboot_count > 3) { // Restarted 4 times
  2491. Settings.rule_enabled = 0; // Disable all rules
  2492. }
  2493. if (RtcReboot.fast_reboot_count > 4) { // Restarted 5 times
  2494. Settings.module = SONOFF_BASIC; // Reset module to Sonoff Basic
  2495. // Settings.last_module = SONOFF_BASIC;
  2496. for (byte i = 0; i < MAX_GPIO_PIN; i++) {
  2497. Settings.my_gp.io[i] = GPIO_NONE; // Reset user defined GPIO disabling sensors
  2498. }
  2499. }
  2500. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d)"), RtcReboot.fast_reboot_count);
  2501. AddLog(LOG_LEVEL_DEBUG);
  2502. }
  2503. Format(mqtt_client, Settings.mqtt_client, sizeof(mqtt_client));
  2504. Format(mqtt_topic, Settings.mqtt_topic, sizeof(mqtt_topic));
  2505. if (strstr(Settings.hostname, "%")) {
  2506. strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname));
  2507. snprintf_P(my_hostname, sizeof(my_hostname)-1, Settings.hostname, mqtt_topic, ESP.getChipId() & 0x1FFF);
  2508. } else {
  2509. snprintf_P(my_hostname, sizeof(my_hostname)-1, Settings.hostname);
  2510. }
  2511. GpioInit();
  2512. SetSerialBaudrate(baudrate);
  2513. WifiConnect();
  2514. if (MOTOR == Settings.module) Settings.poweronstate = POWER_ALL_ON; // Needs always on else in limbo!
  2515. if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {
  2516. SetDevicePower(1, SRC_RESTART);
  2517. } else {
  2518. if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) {
  2519. switch (Settings.poweronstate) {
  2520. case POWER_ALL_OFF:
  2521. case POWER_ALL_OFF_PULSETIME_ON:
  2522. power = 0;
  2523. SetDevicePower(power, SRC_RESTART);
  2524. break;
  2525. case POWER_ALL_ON: // All on
  2526. power = (1 << devices_present) -1;
  2527. SetDevicePower(power, SRC_RESTART);
  2528. break;
  2529. case POWER_ALL_SAVED_TOGGLE:
  2530. power = (Settings.power & ((1 << devices_present) -1)) ^ POWER_MASK;
  2531. if (Settings.flag.save_state) {
  2532. SetDevicePower(power, SRC_RESTART);
  2533. }
  2534. break;
  2535. case POWER_ALL_SAVED:
  2536. power = Settings.power & ((1 << devices_present) -1);
  2537. if (Settings.flag.save_state) {
  2538. SetDevicePower(power, SRC_RESTART);
  2539. }
  2540. break;
  2541. }
  2542. } else {
  2543. power = Settings.power & ((1 << devices_present) -1);
  2544. if (Settings.flag.save_state) {
  2545. SetDevicePower(power, SRC_RESTART);
  2546. }
  2547. }
  2548. }
  2549. // Issue #526 and #909
  2550. for (byte i = 0; i < devices_present; i++) {
  2551. if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
  2552. bitWrite(power, i, digitalRead(pin[GPIO_REL1 +i]) ^ bitRead(rel_inverted, i));
  2553. }
  2554. if ((i < MAX_PULSETIMERS) && (bitRead(power, i) || (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate))) {
  2555. SetPulseTimer(i, Settings.pulse_timer[i]);
  2556. }
  2557. }
  2558. blink_powersave = power;
  2559. char stopic[TOPSZ];
  2560. snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_ESP8266_RELEASE),
  2561. PROJECT, Settings.friendlyname[0], my_version, my_image);
  2562. AddLog(LOG_LEVEL_INFO);
  2563. #ifdef BE_MINIMAL
  2564. snprintf_P(log_data, sizeof(log_data), PSTR(D_WARNING_MINIMAL_VERSION));
  2565. AddLog(LOG_LEVEL_INFO);
  2566. #endif // BE_MINIMAL
  2567. RtcInit();
  2568. #ifdef USE_ARDUINO_OTA
  2569. ArduinoOTAInit();
  2570. #endif // USE_ARDUINO_OTA
  2571. XdrvCall(FUNC_INIT);
  2572. XsnsCall(FUNC_INIT);
  2573. }
  2574. uint32_t _counter = 0;
  2575. void loop(void)
  2576. {
  2577. uint32_t my_sleep = millis();
  2578. XdrvCall(FUNC_LOOP);
  2579. XsnsCall(FUNC_LOOP);
  2580. OsWatchLoop();
  2581. if (TimeReached(button_debounce)) {
  2582. SetNextTimeInterval(button_debounce, Settings.button_debounce);
  2583. ButtonHandler();
  2584. }
  2585. if (TimeReached(switch_debounce)) {
  2586. SetNextTimeInterval(switch_debounce, Settings.switch_debounce);
  2587. SwitchHandler(0);
  2588. }
  2589. if (TimeReached(state_50msecond)) {
  2590. SetNextTimeInterval(state_50msecond, 50);
  2591. XdrvCall(FUNC_EVERY_50_MSECOND);
  2592. XsnsCall(FUNC_EVERY_50_MSECOND);
  2593. }
  2594. if (TimeReached(state_100msecond)) {
  2595. SetNextTimeInterval(state_100msecond, 100);
  2596. Every100mSeconds();
  2597. XdrvCall(FUNC_EVERY_100_MSECOND);
  2598. XsnsCall(FUNC_EVERY_100_MSECOND);
  2599. }
  2600. if (TimeReached(state_250msecond)) {
  2601. SetNextTimeInterval(state_250msecond, 250);
  2602. Every250mSeconds();
  2603. XdrvCall(FUNC_EVERY_250_MSECOND);
  2604. XsnsCall(FUNC_EVERY_250_MSECOND);
  2605. }
  2606. if (!serial_local) SerialInput();
  2607. #ifdef USE_ARDUINO_OTA
  2608. MDNS.update();
  2609. ArduinoOTA.handle();
  2610. // Once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails)
  2611. while (arduino_ota_triggered) ArduinoOTA.handle();
  2612. #endif // USE_ARDUINO_OTA
  2613. uint32_t my_activity = millis() - my_sleep;
  2614. if (Settings.flag3.sleep_normal) {
  2615. // yield(); // yield == delay(0), delay contains yield, auto yield in loop
  2616. delay(sleep); // https://github.com/esp8266/Arduino/issues/2021
  2617. } else {
  2618. if (my_activity < (uint32_t)sleep) {
  2619. delay((uint32_t)sleep - my_activity); // Provide time for background tasks like wifi
  2620. } else {
  2621. if (global_state.wifi_down) {
  2622. delay(my_activity /2); // If wifi down and my_activity > setoption36 then force loop delay to 1/3 of my_activity period
  2623. }
  2624. }
  2625. }
  2626. if (!my_activity) { my_activity++; } // We cannot divide by 0
  2627. uint32_t loop_delay = sleep;
  2628. if (!loop_delay) { loop_delay++; } // We cannot divide by 0
  2629. uint32_t loops_per_second = 1000 / loop_delay; // We need to keep track of this many loops per second
  2630. uint32_t this_cycle_ratio = 100 * my_activity / loop_delay;
  2631. loop_load_avg = loop_load_avg - (loop_load_avg / loops_per_second) + (this_cycle_ratio / loops_per_second); // Take away one loop average away and add the new one
  2632. }