WiFiThermostat.ino 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. // pre compiletime config
  2. //#define DEBUG_VERBOSE
  3. #define SPIFFS_DBG
  4. #define SPIFFS_USE_MAGIC
  5. #define FIRMWARE_NAME "WiFiThermostat"
  6. #define VERSION "0.2.2"
  7. // default values, can later be overridden via configuration (conf)
  8. #define DEVICE_NAME "WiFi-Thermostat-1"
  9. #define DEFAULT_HTTP_USER ""
  10. #define DEFAULT_HTTP_PASS ""
  11. #define HTTP_SET_TOKEN "grzbrz"
  12. #define MQTT_SERVER "10.1.1.11"
  13. #define MQTT_PORT 1883
  14. #define MQTT_USER ""
  15. #define MQTT_PASS ""
  16. #define MQTT_TOPIC_IN "Test/Thermostat"
  17. #define MQTT_TOPIC_OUT "Test/Thermostat/status"
  18. #define MQTT_OUT_RETAIN false
  19. #define MQTT_WILLTOPIC "Test/Thermostat/availability"
  20. #define MQTT_WILLQOS 2
  21. #define MQTT_WILLRETAIN false
  22. #define MQTT_WILLMSG "offline"
  23. #define MQTT_CONNMSG "online"
  24. #define DOMOTICZ_OUT_TOPIC "domoticz/out"
  25. // default values, can later be overridden via configuration (conf2)
  26. #define DOMOTICZ_IDX_THERMOSTAT 0
  27. #define DOMOTICZ_IDX_THERMOSTATMODE 0
  28. #define DOMOTICZ_IDX_TEMPHUMSENSOR 0
  29. #define DOMOTICZ_IDX_HEATING 0
  30. #define DOMOTICZ_IDX_PIR 0
  31. #define OUTTEMP_TOPIC_IN ""
  32. #define OUTHUM_TOPIC_IN ""
  33. #define MQTT_TOPIC_PIR "" // extra publish topic for PIR sensor
  34. #define AUTOSAVE_SETTEMP true
  35. #define AUTOSAVE_SETMODE true
  36. #define DEFAULT_HEATING_MIN_OFFTIME 120 // minimal time the heating keeps turned off in s
  37. #define DEFAULT_SETTEMP_MIN 16.0 // minimal temperature that can be set
  38. #define DEFAULT_SETTEMP_MAX 25.0 // maximal temperature that can be set
  39. #define DEFAULT_SETTEMP_LOW 18.0 // set temperature in night/low mode
  40. #define DEFAULT_SETTEMP_LOW2 20.0 // set temperature in night/low mode
  41. #define DEFAULT_HYSTERESIS 0.1 // hysteresis, normally 0.1 - 0.5
  42. #define SETTEMP_DECREASE_VALUE 0.0 // decreases the set temp to overcome further temperature rise when the heating is already switched off
  43. #define TEMPSENSOR_CORRECTION_VALUE 0.0 // correction value for temperature sensor reading
  44. #define HUMSENSOR_CORRECTION_VALUE 0 // correction value for humidity sensor reading
  45. #define DEFAULT_MEASURE_INTERVAL 15 // interval for temp/hum measurement
  46. #define DEFAULT_DISPLAY_INTERVAL 5 // interval for display updates (if out-temp is active, display will toggle in this interval)
  47. #define DEFAULT_DISPLAY_TIMEOUT 30 // display timeout after keypress (illumination)
  48. #define DEFAULT_PIR_ENABLES_DISPLAY false
  49. #define MODE_NAME_0 "Heizung aus"
  50. #define MODE_NAME_1 "Heizen"
  51. #define MODE_NAME_2 "Absenkung 1"
  52. #define MODE_NAME_3 "Absenkung 2"
  53. // default initial values
  54. #define DEFAULT_SETTEMP 21.5
  55. #define DEFAULT_HEATINGMODE 1
  56. // default values that can only be configured at compile time / hardware configuration
  57. #define CLEARCONF_TOKEN "DOIT!" // Token used to reset configuration via http call on http://<IP>/delconf?token=<TOKEN> (use when password is forgotten)
  58. #define BUTTON_DEBOUNCE_TIME 120
  59. #define BUTTON_HOLD_TIME 750
  60. #define DOMOTICZ_IN_TOPIC "domoticz/in" // if Domoticz IDXes are configured, updates will be sent to this topic
  61. #define SETTEMP_LOW_MIN 14.0 // minimal configurable temperature for reduction mode
  62. #define SETTEMP_LOW_MAX 20.0 // maximal configurable temperature for reduction mode
  63. #define DOMOTICZ_DISMISSUPDATE_TIMEOUT 2500 // after a value was changed by data from domoticz/out, domoticz/out parsing for this device will be turned off for this time to prevent infinite loops
  64. #define DOMOTICZ_FORCEUPDATE_INTERVAL 15 // interval in min to force update of domoticz devices
  65. #define MQTT_HEARTBEAT_MAXAGE 180000 // interval for MQTT heartbeat message. only applicable if MQTT IN-topic is defined. after this timeout MQTT reconnect is forced
  66. // pin assignments and I2C addresses
  67. #define PIN_DHTSENSOR 13
  68. #define PIN_RELAIS 15 //16
  69. #define PIN_BUTTON_PLUS 2
  70. #define PIN_BUTTON_MINUS 0
  71. #define PIN_BUTTON_MODE 14
  72. #define PIN_PIRSENSOR 12
  73. #define DHTTYPE DHT22 // DHT sensor type
  74. #define LCDADDR 0x27 // I2C address LCD
  75. #define LCDCOLS 16
  76. #define LCDLINES 2
  77. // default logic levels
  78. #define RELAISONSTATE HIGH
  79. #define BUTTONONSTATE LOW
  80. #include <Button.h>
  81. #include <ButtonEventCallback.h>
  82. #include <PushButton.h>
  83. #include <Bounce2.h>
  84. PushButton buttonPlus = PushButton(PIN_BUTTON_PLUS, ENABLE_INTERNAL_PULLUP);
  85. PushButton buttonMinus = PushButton(PIN_BUTTON_MINUS, ENABLE_INTERNAL_PULLUP);
  86. PushButton buttonMode = PushButton(PIN_BUTTON_MODE, ENABLE_INTERNAL_PULLUP);
  87. PushButton pirSensor = PushButton(PIN_PIRSENSOR, PRESSED_WHEN_HIGH);
  88. #include <PersWiFiManager.h>
  89. #include <ArduinoJson.h>
  90. #include <ESP8266WiFi.h>
  91. #include <WiFiClient.h>
  92. #include <ESP8266WebServer.h>
  93. #include <ESP8266mDNS.h>
  94. #include <ESP8266HTTPUpdateServer.h>
  95. #include "PubSubClient.h"
  96. #include <DNSServer.h>
  97. #include <FS.h>
  98. #include <Wire.h>
  99. #include <LiquidCrystal_I2C.h>
  100. #include <DHT.h>
  101. #ifndef MESSZ
  102. #define MESSZ 405 // Max number of characters in JSON message string (4 x DS18x20 sensors)
  103. #endif
  104. // Max message size calculated by PubSubClient is (MQTT_MAX_PACKET_SIZE < 5 + 2 + strlen(topic) + plength)
  105. #if (MQTT_MAX_PACKET_SIZE -TOPSZ -7) < MESSZ // If the max message size is too small, throw an error at compile time
  106. // See pubsubclient.c line 359
  107. #error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 512"
  108. #endif
  109. bool serialdebug = true;
  110. bool mqttdebug = true;
  111. // config variables - do not change here!
  112. //conf
  113. char deviceName[31]; // device name - just for web interface
  114. char http_user[31];
  115. char http_pass[31];
  116. char http_token[31];
  117. char mqtt_server[41];
  118. int mqtt_port = MQTT_PORT;
  119. char mqtt_user[31];
  120. char mqtt_pass[31];
  121. char mqtt_topic_in[51]; // MQTT in topic for commands
  122. char mqtt_topic_out[51]; // MQTT out base topic, will be extended by various value names
  123. boolean mqtt_outRetain = MQTT_OUT_RETAIN; // send MQTT out with retain flag
  124. char mqtt_willTopic[51]; // MQTT Last Will topic
  125. int mqtt_willQos = MQTT_WILLQOS; // MQTT Last Will topic QOS
  126. boolean mqtt_willRetain = MQTT_WILLRETAIN; // MQTT Last Will retain
  127. char mqtt_willMsg[31]; // MQTT Last Will payload
  128. char mqtt_connMsg[31];
  129. char domoticz_out_topic[55]; // domoticz out topic to subscribe to (only applicable if domoticzIdx_Thermostat and/or domoticzIdx_ThermostatMode is set to >0)
  130. char mqtt_topic_in_cmd[61];
  131. char mqtt_topic_in_setTemp[61];
  132. char mqtt_topic_in_setMode[61];
  133. //conf2
  134. int domoticzIdx_Thermostat = DOMOTICZ_IDX_THERMOSTAT;
  135. int domoticzIdx_ThermostatMode = DOMOTICZ_IDX_THERMOSTATMODE;
  136. int domoticzIdx_TempHumSensor = DOMOTICZ_IDX_TEMPHUMSENSOR;
  137. int domoticzIdx_Heating = DOMOTICZ_IDX_HEATING;
  138. int domoticzIdx_PIR = DOMOTICZ_IDX_PIR;
  139. char outTemp_topic_in[51];
  140. char outHum_topic_in[51];
  141. char mqtt_topic_pir[51];
  142. boolean autoSaveSetTemp = AUTOSAVE_SETTEMP;
  143. boolean autoSaveHeatingMode = AUTOSAVE_SETMODE;
  144. int heatingMinOffTime = DEFAULT_HEATING_MIN_OFFTIME; // minimal time the heating keeps turned off in s
  145. float setTempMin = DEFAULT_SETTEMP_MIN; // minimal temperature that can be set
  146. float setTempMax = DEFAULT_SETTEMP_MAX; // maximal temperature that can be set
  147. float setTempLow = DEFAULT_SETTEMP_LOW; // set temperature in night/low mode
  148. float setTempLow2 = DEFAULT_SETTEMP_LOW2; // set temperature in night/low mode
  149. float hysteresis = DEFAULT_HYSTERESIS; // hysteresis, normally 0.1 - 0.5
  150. float setTempDecreaseVal = SETTEMP_DECREASE_VALUE; // decreases the set temp to overcome further temperature rise when the heating is already switched off
  151. float tempCorrVal = TEMPSENSOR_CORRECTION_VALUE; // correction value for temperature sensor reading
  152. int humCorrVal = HUMSENSOR_CORRECTION_VALUE; // correction value for humidity sensor reading
  153. int measureInterval = DEFAULT_MEASURE_INTERVAL; // interval for temp/hum measurement
  154. int displayInterval = DEFAULT_DISPLAY_INTERVAL; // interval for display updates (if out-temp is active, display will toggle in this interval)
  155. int displayTimeout = DEFAULT_DISPLAY_TIMEOUT; // display timeout after keypress (illumination)
  156. boolean PIR_enablesDisplay = DEFAULT_PIR_ENABLES_DISPLAY; // PIR sensor enables display illumination
  157. char modename0[15];
  158. char modename1[15];
  159. char modename2[15];
  160. char modename3[15];
  161. //set values
  162. float setTemp = DEFAULT_SETTEMP;
  163. byte heatingMode = DEFAULT_HEATINGMODE; // 0 = off, 1 = normal/day, 2 = night/reduction
  164. float setTempSaved;
  165. byte heatingModeSaved; // 0 = off, 1 = normal/day, 2 = night/reduction
  166. // not changeable via configuration
  167. float setTempLowMin = SETTEMP_LOW_MIN;
  168. float setTempLowMax = SETTEMP_LOW_MAX;
  169. boolean debug = true;
  170. int debounceTime = BUTTON_DEBOUNCE_TIME;
  171. int buttonHoldTime = BUTTON_HOLD_TIME;
  172. // global variables
  173. float currTemp; // last reading from DHT sensor
  174. float currTemp_raw; // last reading from DHT sensor
  175. int currHum; // last reading from DHT sensor
  176. int currHum_raw; // last reading from DHT sensor
  177. bool turnHeatingOn = false; // true if heating is active (relais switched on)
  178. unsigned long heatingLastOnMillis; // last time heating was switched on
  179. unsigned long heatingLastOffMillis; // last time heating was switched off
  180. float outTemp; // outside temp (via MQTT if enabled and in-topic configured)
  181. int outHum; // outside temp (via MQTT if enabled and in-topic configured)
  182. long outTempHumLastUpdate; // last reading from out temp/hum source
  183. char outTemp_newValue[6];
  184. bool outTemp_parseNewValue;
  185. char outHum_newValue[4];
  186. bool outHum_parseNewValue;
  187. char currentModeName[15];
  188. byte whichTempToDisplay; // 1=temp inside (from DHT sensor), 2= temp outside (via MQTT) - if out temp/hum available this value and the displayed value pair toggles with every displayInterval
  189. unsigned long lastMeasure = 0; // millis of last temp/hum measurement
  190. unsigned long lastDisplayUpdate = 0; // millis of last display update
  191. unsigned long lastDisplayToggle = 0; // millis of last display toggle
  192. unsigned long lastTempUpdate = 0; // last update time of DHT reading
  193. char msg[50]; // buffer MQTT in payload
  194. char topic[50]; // buffer MQTT in topic
  195. bool displayActive = false; // gets true when button is pressed. display light gets switched on until timeout. button actions are only performed while display is active
  196. bool PIRSensorOn = false;
  197. unsigned long heatingOnTime, heatingOffTime;
  198. boolean useDomoticz = false; // will be set to true in setup() if idx-values other than 0 are configured
  199. boolean domoticzOutParseData = false; // indicates that domoticz/out json data is buffered, will then be parsed in next loop() run
  200. boolean domoticzOutParserBusy = false; // indicates that domoticz/out json data is currently processed - no futher data will be accepted until finished
  201. char domoticzOutPayload[450]; // buffer for domoticz/out data
  202. int dismissUpdateFromDomoticzTimeout = DOMOTICZ_DISMISSUPDATE_TIMEOUT; // after a value was changed by data from domoticz/out, domoticz/out parsing for this device will be turned off for this time to prevent infinite loops
  203. unsigned long lastUpdate_setTemp = 0; // set to millis() every time setTemp value is changed. next update from domoticz/out will be rejected for dismissUpdateFromDomoticzTimeout in this case
  204. unsigned long lastUpdate_heatingMode = 0; // set to millis() every time heatingMode value is changed. next update from domoticz/out will be rejected for dismissUpdateFromDomoticzTimeout in this case
  205. bool lastUpdateFromDomoticz_setTemp = false;
  206. bool lastUpdateFromDomoticz_heatingMode = false;
  207. int domoticzUpdateInterval = DOMOTICZ_FORCEUPDATE_INTERVAL; // interval in min to force update of domoticz devices
  208. char cmdPayload[101]; // buffer for commands
  209. boolean cmdInQueue = false; // command is queued and will be processed next loop() run
  210. bool saveConfigToFlash = false; // conf is saved in next loop() run
  211. bool saveConfig2ToFlash = false; // conf2 is saved in next loop() run
  212. unsigned int saveValuesTimeout = 5000;
  213. unsigned long lastValueChange; // is set to millis() whenever setTemp value and/or heatingMode value is changed. used for autoSave function with hardcoded 5s timeout
  214. bool setTempAlreadySaved = true; // only save if not yet done
  215. bool heatingModeAlreadySaved = true; // only save if not yet done
  216. byte mqttMode = 0;
  217. unsigned long mqttLastReconnectAttempt = 0;
  218. int mqttReconnectAttempts = 0;
  219. int mqttReconnects = 0;
  220. unsigned long mqttLastHeartbeat;
  221. bool mqttInTopicSubscribed = false;
  222. DHT dht(PIN_DHTSENSOR, DHTTYPE);
  223. LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDLINES); // set the LCD address to 0x27 for a 16 chars and 2 line display
  224. WiFiClient espClient;
  225. void mqttCallback(char* topic, byte* payload, unsigned int length);
  226. PubSubClient mqttclient(espClient);
  227. ESP8266WebServer httpServer(80);
  228. DNSServer dnsServer;
  229. PersWiFiManager persWM(httpServer, dnsServer);
  230. ESP8266HTTPUpdateServer httpUpdater;
  231. void setup() {
  232. Serial.begin(115200);
  233. delay(500);
  234. Serial.println();
  235. Serial.print(FIRMWARE_NAME);
  236. Serial.print(" v");
  237. Serial.print(VERSION);
  238. Serial.println("starting...");
  239. pinMode(PIN_RELAIS, OUTPUT);
  240. digitalWrite(PIN_RELAIS, !RELAISONSTATE);
  241. pinMode(PIN_PIRSENSOR, INPUT);
  242. buttonPlus.configureButton(configurePushButton);
  243. //buttonPlus.onPress(onButtonPressed); // When the button is first pressed, call the function onButtonPressed (further down the page)
  244. buttonPlus.onHoldRepeat(1000, 350, onButtonHeld); // Once the button has been held for 1 second (1000ms) call onButtonHeld. Call it again every 350ms until it is let go
  245. buttonPlus.onRelease(50, 500, onButtonReleased); // When the button is held >50ms and released after <500ms, call onButtonReleased
  246. buttonMinus.configureButton(configurePushButton);
  247. //buttonMinus.onPress(onButtonPressed); // When the button is first pressed, call the function onButtonPressed (further down the page)
  248. buttonMinus.onHoldRepeat(1000, 350, onButtonHeld); // Once the button has been held for 1 second (1000ms) call onButtonHeld. Call it again every 350ms until it is let go
  249. buttonMinus.onRelease(50, 500, onButtonReleased); // When the button is held >50ms and released after <500ms, call onButtonReleased
  250. buttonMode.configureButton(configurePushButton);
  251. //buttonMode.onPress(onButtonPressed); // When the button is first pressed, call the function onButtonPressed (further down the page)
  252. buttonMode.onHold(1000, onButtonHeldNoRepeat); // Once the button has been held for 1 second (1000ms) call onButtonHeld
  253. buttonMode.onRelease(50, 500, onButtonReleased); // When the button is held >50ms and released after <500ms, call onButtonReleased
  254. pirSensor.configureButton(configurePushButton);
  255. //pirSensor.onPress(onButtonPressed); // When the button is first pressed, call the function onButtonPressed (further down the page)
  256. pirSensor.onHold(500, onButtonHeldNoRepeat); // Once the button has been held for 1 second (1000ms) call onButtonHeld
  257. pirSensor.onRelease(500, onButtonReleased); // When the button is held >50ms and released after <500ms, call onButtonReleased
  258. //set conf default values (bool, int and float variables are set at declaration)
  259. strlcpy(deviceName, DEVICE_NAME, 31);
  260. strlcpy(http_user, DEFAULT_HTTP_USER, 31);
  261. strlcpy(http_pass, DEFAULT_HTTP_PASS, 31);
  262. strlcpy(http_token, HTTP_SET_TOKEN, 31);
  263. strlcpy(mqtt_server, MQTT_SERVER, 41);
  264. strlcpy(mqtt_user, MQTT_USER, 31);
  265. strlcpy(mqtt_pass, MQTT_PASS, 31);
  266. strlcpy(mqtt_topic_in, MQTT_TOPIC_IN, 51);
  267. strlcpy(mqtt_topic_out, MQTT_TOPIC_OUT, 51);
  268. strlcpy(mqtt_willTopic, MQTT_WILLTOPIC, 51);
  269. strlcpy(mqtt_willMsg, MQTT_WILLMSG, 31);
  270. strlcpy(mqtt_connMsg, MQTT_CONNMSG, 31);
  271. strlcpy(domoticz_out_topic, DOMOTICZ_OUT_TOPIC, 51); // changeable subscription topic, as domoticz supports different flat/hierarchical out-topics
  272. //set conf2 default values (bool, int and float variables are set at declaration)
  273. strlcpy(outTemp_topic_in, OUTTEMP_TOPIC_IN, 51);
  274. strlcpy(outHum_topic_in, OUTHUM_TOPIC_IN, 51);
  275. strlcpy(mqtt_topic_pir, MQTT_TOPIC_PIR, 51);
  276. strlcpy(modename0, MODE_NAME_0, 14);
  277. strlcpy(modename1, MODE_NAME_1, 14);
  278. strlcpy(modename2, MODE_NAME_2, 14);
  279. strlcpy(modename3, MODE_NAME_3, 14);
  280. Serial.println("default config values loaded..");
  281. Serial.println("Mounting FS...");
  282. if (!SPIFFS.begin()) {
  283. Serial.println("Failed to mount file system");
  284. return;
  285. }
  286. //uncomment for initial SPIFFS format
  287. //SPIFFS.format();
  288. //Serial.print("Format SPIFFS complete.");
  289. if (!SPIFFS.exists("/formatComplete.txt")) {
  290. Serial.println("Please wait 30 secs for SPIFFS to be formatted");
  291. SPIFFS.format();
  292. Serial.println("Spiffs formatted");
  293. File f = SPIFFS.open("/formatComplete.txt", "w");
  294. if (!f) {
  295. Serial.println("file open failed");
  296. } else {
  297. f.println("Format Complete");
  298. }
  299. f.close();
  300. } else {
  301. Serial.println("SPIFFS is formatted. Moving along...");
  302. }
  303. // // load config from SPIFFS if files exist
  304. if (!loadConfig()) {
  305. Serial.println("Failed to load conf.json");
  306. } else {
  307. Serial.println("conf.json loaded");
  308. }
  309. if (!loadConfig2()) {
  310. Serial.println("Failed to load conf2.json");
  311. } else {
  312. Serial.println("conf2.json loaded");
  313. }
  314. if (!loadSetTemp()) {
  315. Serial.println("Failed to load file 'setTemp'");
  316. } else {
  317. Serial.println("file 'setTemp' loaded");
  318. }
  319. if (!loadHeatingMode()) {
  320. Serial.println("Failed to load file 'heatingMode'");
  321. } else {
  322. Serial.println("file 'heatingMode' loaded");
  323. }
  324. setTempSaved = setTemp;
  325. heatingModeSaved = heatingMode;
  326. updateCurrentHeatingModeName();
  327. // initialize DHT11/22 temp/hum sensor
  328. dht.begin();
  329. mqttPrepareSubscribeTopics();
  330. checkUseDomoticz();
  331. delay(500);
  332. //optional code handlers to run everytime wifi is connected...
  333. persWM.onConnect([]() {
  334. Serial.println("wifi connected");
  335. Serial.println(WiFi.SSID());
  336. Serial.println(WiFi.localIP());
  337. });
  338. //...or AP mode is started
  339. persWM.onAp([]() {
  340. Serial.println("AP MODE");
  341. Serial.println(persWM.getApSsid());
  342. });
  343. //sets network name for AP mode
  344. persWM.setApCredentials(DEVICE_NAME);
  345. //persWM.setApCredentials(DEVICE_NAME, "password"); optional password
  346. //make connecting/disconnecting non-blocking
  347. persWM.setConnectNonBlock(true);
  348. //in non-blocking mode, program will continue past this point without waiting
  349. persWM.begin();
  350. delay(500);
  351. httpServerInit();
  352. mqttPrepareConnection();
  353. mqttClientInit();
  354. initDisplay();
  355. Serial.println("setup complete.");
  356. //delay(1000);
  357. } //void setup
  358. void loop() {
  359. checkMillis();
  360. persWM.handleWiFi(); //in non-blocking mode, handleWiFi must be called in the main loop
  361. yield();
  362. mqttHandleConnection();
  363. yield();
  364. outTempHum_updateOnNewValue();
  365. yield();
  366. dnsServer.processNextRequest();
  367. httpServer.handleClient();
  368. buttonPlus.update();
  369. buttonMinus.update();
  370. buttonMode.update();
  371. pirSensor.update();
  372. yield();
  373. evalCmd();
  374. yield();
  375. if ( domoticzOutParseData ) {
  376. parseDomoticzOut();
  377. yield();
  378. }
  379. if (Serial.available()) {
  380. serialEvent();
  381. yield();
  382. }
  383. } //void loop