thermostat.ino 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. float tmpHum, tmpTemp;
  2. int DHTreadRetries = 2;
  3. //int DHTreadDelay = 20;
  4. void readDHTsensorTemp() {
  5. //delay(DHTreadDelay);
  6. tmpTemp = dht.readTemperature(); // Read temperature as Celsius (the default)
  7. }
  8. void readDHTsensorHum() {
  9. //delay(DHTreadDelay);
  10. tmpHum = dht.readHumidity();
  11. }
  12. void measureTempHum() {
  13. for (int i = 0; i < DHTreadRetries; i++) {
  14. readDHTsensorTemp();
  15. if (!isnan(tmpTemp)) {
  16. sendLog(F("DHT: reading Temp OK"), LOGLEVEL_VERBOSE);
  17. i = DHTreadRetries;
  18. }
  19. else {
  20. sendLog(F("DHT: reading Temp failed - retrying.."), LOGLEVEL_INFO);
  21. }
  22. }
  23. //
  24. for (int i = 0; i < DHTreadRetries; i++) {
  25. readDHTsensorHum();
  26. if (!isnan(tmpHum)) {
  27. sendLog(F("DHT: reading Hum OK"), LOGLEVEL_VERBOSE);
  28. i = DHTreadRetries;
  29. }
  30. else {
  31. sendLog(F("DHT: reading Hum failed - retrying.."), LOGLEVEL_INFO);
  32. }
  33. }
  34. // Check if any reads failed
  35. if (isnan(tmpHum) || isnan(tmpTemp)) {
  36. //Serial.println("Failed to read from DHT sensor!");
  37. sendLog(F("Error: Failed to read from DHT sensor!"), LOGLEVEL_ERROR);
  38. }
  39. else {
  40. tmpTemp = tmpTemp + confAdv.tempCorrVal;
  41. tmpHum = round(tmpHum) + confAdv.humCorrVal;
  42. int tmpHumInt = tmpHum;
  43. if (tmpTemp < 50.0 && tmpTemp > -20.0) {
  44. // measurement is in range
  45. currTemp_raw = tmpTemp;
  46. currHum_raw = tmpHumInt;
  47. if ( lastTempUpdate > 0 && tmpTemp <= ( currTemp + 2.0 ) && tmpTemp >= ( currTemp - 2.0 ) ) {
  48. // temp has already been measured - only accept new measurement if it does not differ much from the last value
  49. //Temp = (Temp * (FilterFaktor -1) + AktuellerMesswert) / FilterFaktor;
  50. //temperature = tmpTemp;
  51. currTemp = (currTemp * 9 + tmpTemp) / 10; // filter
  52. currHum = (currHum * 9 + tmpHumInt) / 10; // filter
  53. lastTempUpdate = millis();
  54. }
  55. else if ( lastTempUpdate == 0 || (millis() - lastTempUpdate) > maxMeasurementAge ) {
  56. // this is the first measurement or the last one is older than 5m - then accept this measurement
  57. currTemp = tmpTemp + confAdv.tempCorrVal;
  58. currHum = tmpHumInt + confAdv.humCorrVal;
  59. lastTempUpdate = millis();
  60. }
  61. // skip in all other cases
  62. //#ifdef DEBUG_VERBOSE
  63. // Serial.print("lastTempUpdate: ");
  64. // long lastTempUpdateDelta = millis() - lastTempUpdate;
  65. // Serial.print(lastTempUpdateDelta / 1000);
  66. // Serial.println("s ago");
  67. //#endif
  68. }
  69. }
  70. }
  71. void updateCurrSetTemp() {
  72. // set target temp for heating mode
  73. if (heatingMode > 0) { // heating on
  74. if (preset == 0) { // normal/day preset
  75. currSetTemp = setTemp;
  76. currActualSetTemp = setTemp - confAdv.setTempDecreaseVal;
  77. }
  78. else if (preset == 1) { // night/reduction preset
  79. currSetTemp = setTempLow;
  80. currActualSetTemp = setTempLow - confAdv.setTempDecreaseVal;
  81. }
  82. else if (preset == 2) { // night/reduction 2 preset
  83. currSetTemp = setTempLow2;
  84. currActualSetTemp = setTempLow2 - confAdv.setTempDecreaseVal;
  85. }
  86. }
  87. else { // if heatingMode == 0
  88. currSetTemp = DEFAULT_SETTEMP_HEATOFF;
  89. currActualSetTemp = currSetTemp;
  90. }
  91. }
  92. void thermostat() {
  93. updateCurrSetTemp();
  94. //char tmp_topic_out[50];
  95. if (heatingMode > 0 && turnHeatingOn) {
  96. heatingOnTime = (millis() - heatingLastOnMillis) / 1000;
  97. //char buf[101];
  98. //sprintf(buf, "heating on for %lus", heatingOnTime);
  99. //sendLog(buf, LOGLEVEL_INFO);
  100. }
  101. else if (heatingMode > 0 && !turnHeatingOn) {
  102. if(heatingLastOnMillis > 0) {
  103. // prevent locking the heating after a reboot
  104. heatingOffTime = (millis() - heatingLastOffMillis) / 1000;
  105. }
  106. //char buf[101];
  107. //sprintf(buf, "heating off for %lus", heatingOffTime);
  108. //sendLog(buf, LOGLEVEL_INFO);
  109. }
  110. //char tmp_topic_out[50];
  111. //sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heating");
  112. if ( lastTempUpdate != 0 && (millis() - lastTempUpdate) <= maxMeasurementAge ) {
  113. // thermostat - only active if measured temperature is < 2 min old
  114. #ifdef DEBUG_VERBOSE
  115. Serial.print("thermostat, lastTempUpdate=");
  116. Serial.print(lastTempUpdate);
  117. Serial.print(", lastTempUpdate_delta=");
  118. long lastTempUpdateDelta = millis() - lastTempUpdate;
  119. Serial.println(lastTempUpdateDelta);
  120. #endif
  121. // thermostat with hysteresis
  122. if ( turnHeatingOn && currTemp >= currActualSetTemp ) {
  123. turnHeatingOn = false;
  124. heatingLastOffMillis = millis();
  125. heatingLockTime = confAdv.heatingMinOffTime;
  126. digitalWrite(PIN_RELAIS, !RELAISONSTATE);
  127. updateDisplay();
  128. char buf[101];
  129. sprintf_P(buf, "TSTAT: %s OFF, on for %lus", PGMStr_switchHeating, heatingOnTime);
  130. sendLog(buf, LOGLEVEL_INFO);
  131. //Serial.println("heating off");
  132. //mqttclient.publish(tmp_topic_out, "off");
  133. publishCurrentThermostatValues();
  134. }
  135. else if ( !turnHeatingOn && heatingMode > 0 && heatingLockTime == 0 && heatingPause == 0 && ( currTemp < (currActualSetTemp - confAdv.hysteresis) ) ) {
  136. if ( heatingOffTime > confAdv.heatingMinOffTime || heatingLastOnMillis == 0) {
  137. turnHeatingOn = true;
  138. //heatingLockTimeActive = false;
  139. //heatingLockTime = 0;
  140. heatingLastOnMillis = millis();
  141. digitalWrite(PIN_RELAIS, RELAISONSTATE);
  142. updateDisplay();
  143. char buf[101];
  144. sprintf(buf, "TSTAT: switch heating ON, off for %lus", heatingOffTime);
  145. sendLog(buf, LOGLEVEL_INFO);
  146. //Serial.println("heating on");
  147. //mqttclient.publish(tmp_topic_out, "on");
  148. publishCurrentThermostatValues();
  149. }
  150. //else {
  151. // // heating should run BUT lock time is active
  152. // heatingLockTimeActive = true;
  153. // heatingLockTime = confAdv.heatingMinOffTime - heatingOffTime;
  154. // updateDisplay();
  155. //}
  156. }
  157. else if (heatingPause > 0) {
  158. turnHeatingOn = false;
  159. heatingLastOffMillis = millis();
  160. digitalWrite(PIN_RELAIS, !RELAISONSTATE);
  161. updateDisplay();
  162. }
  163. }
  164. else {
  165. // turn off as no temp reading is available
  166. if (turnHeatingOn) {
  167. digitalWrite(PIN_RELAIS, !RELAISONSTATE);
  168. turnHeatingOn = false;
  169. heatingLastOffMillis = millis();
  170. }
  171. if ( lastTempUpdate != 0 ) sendLog(F("TSTAT: heating OFF, temp reading not yet available"), LOGLEVEL_INFO);
  172. else if ( (millis() - lastTempUpdate) > maxMeasurementAge ) sendLog(F("TSTAT: heating OFF, last temp reading too old"), LOGLEVEL_WARN);
  173. //mqttclient.publish(tmp_topic_out, "off");
  174. publishCurrentThermostatValues();
  175. }
  176. }
  177. void toggleOnOff() {
  178. if (heatingMode > 0) {
  179. heatingMode = 0;
  180. heatingPause = 0;
  181. heatingLockTime = 0;
  182. lastValueChange = millis();
  183. heatingModeAlreadySaved = false;
  184. }
  185. else {
  186. heatingMode = 1;
  187. heatingPause = 0;
  188. heatingLockTime = 0;
  189. lastValueChange = millis();
  190. heatingModeAlreadySaved = false;
  191. }
  192. updateCurrentHeatingModeName();
  193. updateDisplay();
  194. }
  195. void togglePreset() {
  196. //sendLog(F("switch preset to "));
  197. if (pendingPreset < 0 || pendingPreset > 2) pendingPreset = preset;
  198. // if (pendingPresetToggle && preset == 0 && pendingPreset == 0) pendingPreset = 1;
  199. // else if (pendingPresetToggle && preset == 1 && pendingPreset == 1) pendingPreset = 0;
  200. // else if (pendingPreset == 1 && pendingPresetToggle) pendingPreset = 2;
  201. // else if (pendingPreset == 2 && !pendingPresetToggle) pendingPreset = 0;
  202. // else if (pendingPreset == 2 && pendingPresetToggle) pendingPreset = 1;
  203. // pendingPreset 0 => Normal
  204. // pendingPreset 1 => Reduction 1
  205. // pendingPreset 2 => Reduction 2
  206. if(preset == 0) { // Normal > Reduction 1 > Reduction 2
  207. if (pendingPreset == 0) pendingPreset = 1;
  208. else if (pendingPreset == 1) pendingPreset = 2;
  209. else if (pendingPreset == 2) pendingPreset = 0;
  210. }
  211. else if(preset == 1) { // Reduction 1 > Normal > Reduction 2
  212. if (pendingPreset == 1) pendingPreset = 0;
  213. else if (pendingPreset == 0) pendingPreset = 2;
  214. else if (pendingPreset == 2) pendingPreset = 1;
  215. }
  216. else if(preset == 2) { // Reduction 2 > Normal > Reduction 1
  217. if (pendingPreset == 2) pendingPreset = 0;
  218. else if (pendingPreset == 0) pendingPreset = 1;
  219. else if (pendingPreset == 1) pendingPreset = 2;
  220. }
  221. // if (preset == 0 && pendingPreset == 0) pendingPreset = 1;
  222. // else if (preset == 0 && pendingPreset == 1) pendingPreset = 2;
  223. // else if (preset == 1 && pendingPreset == 0) pendingPreset = 2;
  224. // else if (preset == 1 && pendingPreset == 1) pendingPreset = 0;
  225. // else if (preset == 1 && pendingPreset == 2) pendingPreset = 1;
  226. // else if (preset == 1 && pendingPreset == 0) pendingPreset = 1;
  227. // else if (preset == 2 && pendingPreset == 0) pendingPreset = 1;
  228. // else if (preset == 2 && pendingPreset == 1) pendingPreset = 0;
  229. // else if (preset == 2 && pendingPreset == 2) pendingPreset = 0;
  230. lastValueChange = millis();
  231. presetAlreadySaved = false;
  232. updatePendingPresetName();
  233. //updateDisplay();
  234. //pendingPresetToggle = true;
  235. displayShowLine2OverlayMessage(pendingPresetName);
  236. //Serial.print(pendingPreset);
  237. //Serial.print(" - \"");
  238. //Serial.print(currentPresetName);
  239. //Serial.println("\"");
  240. }
  241. void updateCurrentHeatingModeName() {
  242. if (heatingMode == 0) strlcpy(currentModeName, confAdv.modeName0, 14);
  243. else if (heatingMode == 1) strlcpy(currentModeName, confAdv.modeName1, 14);
  244. }
  245. void updateCurrentPresetName() {
  246. if (preset == 0) strlcpy(currentPresetName, confAdv.psetName0, 14);
  247. else if (preset == 1) strlcpy(currentPresetName, confAdv.psetName1, 14);
  248. else if (preset == 2) strlcpy(currentPresetName, confAdv.psetName2, 14);
  249. }
  250. void updatePendingPresetName() {
  251. if (pendingPreset == 0) strlcpy(pendingPresetName, confAdv.psetName0, 14);
  252. else if (pendingPreset == 1) strlcpy(pendingPresetName, confAdv.psetName1, 14);
  253. else if (pendingPreset == 2) strlcpy(pendingPresetName, confAdv.psetName2, 14);
  254. }
  255. void setTempStepUp() {
  256. if (heatingMode == 1) {
  257. sendLog(F("TSTAT: setTemp +0.5"));
  258. if ( setTemp <= (confBas.setTempMax - 0.5)) {
  259. setTemp += 0.5;
  260. lastValueChange = millis();
  261. setTempAlreadySaved = false;
  262. }
  263. updateDisplay();
  264. }
  265. }
  266. void setTempStepDown() {
  267. if (heatingMode == 1) {
  268. sendLog(F("TSTAT: setTemp -0.5"));
  269. if ( setTemp >= (confBas.setTempMin + 0.5)) {
  270. setTemp -= 0.5;
  271. lastValueChange = millis();
  272. setTempAlreadySaved = false;
  273. }
  274. updateDisplay();
  275. }
  276. }
  277. void setTempTo(float setTo) {
  278. boolean changes = false;
  279. float tmpSetTemp;
  280. if(setTo != setTemp) {
  281. if (setTo >= confBas.setTempMin && setTo <= confBas.setTempMax) {
  282. tmpSetTemp = setTo;
  283. changes = true;
  284. }
  285. else if (setTo > confBas.setTempMax) {
  286. tmpSetTemp = confBas.setTempMax;
  287. changes = true;
  288. }
  289. else if (setTo < confBas.setTempMin) {
  290. tmpSetTemp = confBas.setTempMin;
  291. changes = true;
  292. }
  293. if (changes) {
  294. setTemp = tmpSetTemp;
  295. lastValueChange = millis();
  296. setTempAlreadySaved = false;
  297. updateDisplay();
  298. publishCurrentThermostatValues();
  299. char buf1[30];
  300. //sprintf(buf1, "setTemp changed to %2.1f", setTemp);
  301. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTemp, PGMStr_changedTo, setTemp);
  302. //sendLog(F("setTemp changed"));
  303. sendLog(buf1);
  304. }
  305. }
  306. }
  307. void setTempLowStepUp() {
  308. sendLog(F("TSTAT: setTempLow +0.5"));
  309. if ( setTempLow <= (setTempLowMax - 0.5)) {
  310. setTempLow += 0.5;
  311. lastValueChange = millis();
  312. setTempLowAlreadySaved = false;
  313. }
  314. updateDisplay();
  315. }
  316. void setTempLowStepDown() {
  317. sendLog(F("TSTAT: setTempLow -0.5"));
  318. if ( setTempLow >= (setTempLowMin + 0.5)) {
  319. setTempLow -= 0.5;
  320. lastValueChange = millis();
  321. setTempLowAlreadySaved = false;
  322. }
  323. updateDisplay();
  324. }
  325. void setTempLowTo(float setTo) {
  326. boolean changes = false;
  327. float tmp_setTempLow;
  328. if(setTo != setTempLow) {
  329. if (setTo >= setTempLowMin && setTo <= setTempLowMax) {
  330. tmp_setTempLow = setTo;
  331. changes = true;
  332. }
  333. else if (setTo > setTempLowMax) {
  334. tmp_setTempLow = setTempLowMax;
  335. changes = true;
  336. }
  337. else if (setTo < setTempLowMin) {
  338. tmp_setTempLow = setTempLowMin;
  339. changes = true;
  340. }
  341. if (changes) {
  342. setTempLow = tmp_setTempLow;
  343. lastValueChange = millis();
  344. setTempLowAlreadySaved = false;
  345. updateDisplay();
  346. publishCurrentThermostatValues();
  347. //Serial.println("setTempLow CHANGED");
  348. char buf1[30];
  349. //sprintf(buf1, "setTempLow changed to %2.1f", setTempLow);
  350. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow, PGMStr_changedTo, setTempLow);
  351. sendLog(buf1);
  352. }
  353. }
  354. }
  355. void setTempLow2StepUp() {
  356. sendLog(F("TSTAT: setTempLow2 +0.5"));
  357. if ( setTempLow2 <= (setTempLowMax - 0.5)) {
  358. setTempLow2 += 0.5;
  359. lastValueChange = millis();
  360. setTempLow2AlreadySaved = false;
  361. }
  362. updateDisplay();
  363. }
  364. void setTempLow2StepDown() {
  365. sendLog(F("TSTAT: setTempLow2 -0.5"));
  366. if ( setTempLow2 >= (setTempLowMin + 0.5)) {
  367. setTempLow2 -= 0.5;
  368. lastValueChange = millis();
  369. setTempLow2AlreadySaved = false;
  370. }
  371. updateDisplay();
  372. }
  373. void setTempLow2To(float setTo) {
  374. boolean changes = false;
  375. float tmp_setTempLow2;
  376. if(setTo != setTempLow2) {
  377. if (setTo >= setTempLowMin && setTo <= setTempLowMax) {
  378. tmp_setTempLow2 = setTo;
  379. changes = true;
  380. }
  381. else if (setTo > setTempLowMax) {
  382. tmp_setTempLow2 = setTempLowMax;
  383. changes = true;
  384. }
  385. else if (setTo < setTempLowMin) {
  386. tmp_setTempLow2 = setTempLowMin;
  387. changes = true;
  388. }
  389. if (changes) {
  390. setTempLow2 = tmp_setTempLow2;
  391. lastValueChange = millis();
  392. setTempLow2AlreadySaved = false;
  393. updateDisplay();
  394. publishCurrentThermostatValues();
  395. //Serial.println("setTempLow2 CHANGED");
  396. char buf1[30];
  397. //sprintf(buf1, "setTempLow2 changed to %2.1f", setTempLow2);
  398. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow2, PGMStr_changedTo, setTempLow2);
  399. sendLog(buf1);
  400. }
  401. }
  402. }
  403. void setHeatingmodeTo(unsigned char setTo) {
  404. if(setTo != heatingMode) {
  405. heatingMode = setTo;
  406. heatingPause = 0;
  407. heatingLockTime = 0;
  408. updateCurrSetTemp();
  409. lastValueChange = millis();
  410. heatingModeAlreadySaved = false;
  411. updateCurrentHeatingModeName();
  412. updateDisplay();
  413. publishCurrentThermostatValues();
  414. //Serial.println("heatingMode CHANGED");
  415. char buf1[30];
  416. //sprintf(buf1, "heatingMode changed to %u", heatingMode);
  417. sprintf_P(buf1, "%s: %s %s %u", PGMStr_thermostat, PGMStr_heatingMode, PGMStr_changedTo, heatingMode);
  418. sendLog(buf1);
  419. }
  420. }
  421. void setHeatingPause(uint8_t _setTo) {
  422. bool _change = false;
  423. char _buf1[30];
  424. if(_setTo == 0) {
  425. heatingPause = 0;
  426. _change = true;
  427. sprintf_P(_buf1, "%s: %s %s", PGMStr_thermostat, PGMStr_heatingPause, PGMStr_disabled);
  428. }
  429. else if (_setTo == 1 && heatingPause == 0) {
  430. heatingPause = confAdv.pauseTout;
  431. _change = true;
  432. sprintf_P(_buf1, "%s: %s %s", PGMStr_thermostat, PGMStr_heatingPause, PGMStr_enabled);
  433. }
  434. if(_change) {
  435. lastValueChange = millis();
  436. thermostat();
  437. updateDisplay();
  438. publishCurrentThermostatValues();
  439. sendLog(_buf1);
  440. }
  441. }
  442. void setPresetTo(unsigned char setTo) {
  443. if(setTo != preset) {
  444. if(setTo >= 0 && setTo <=2) {
  445. preset = setTo;
  446. pendingPreset = setTo;
  447. updateCurrSetTemp();
  448. lastValueChange = millis();
  449. presetAlreadySaved = false;
  450. updateCurrentPresetName();
  451. updateDisplay();
  452. publishCurrentThermostatValues();
  453. //Serial.println("preset CHANGED");
  454. char buf1[30];
  455. sprintf_P(buf1, "%s: %s %s %u", PGMStr_thermostat, PGMStr_preset, PGMStr_changedTo, preset);
  456. sendLog(buf1);
  457. }
  458. }
  459. }
  460. void checkValuesChanged() { // called every second by everySecond() / scheduler.ino
  461. if ( !setTempAlreadySaved || !heatingModeAlreadySaved || !presetAlreadySaved || !setTempLowAlreadySaved || !setTempLow2AlreadySaved ) {
  462. if ( (millis() - lastValueChange) > saveValuesTimeout ) { // value was changed 5s ago. now save if auto-save enabled
  463. if (!setTempAlreadySaved) {
  464. lastUpdate_setTemp = millis();
  465. if (confBas.autoSaveSetTemp && setTemp != setTempSaved) {
  466. saveSetTemp();
  467. sendLog(F("TSTAT: setTemp autosave done"));
  468. }
  469. setTempAlreadySaved = true;
  470. }
  471. if (!setTempLowAlreadySaved) {
  472. lastUpdate_setTempLow = millis();
  473. if (confBas.autoSaveSetTemp && setTempLow != setTempLowSaved) {
  474. saveSetTempLow();
  475. sendLog(F("TSTAT: setTempLow autosave done"));
  476. }
  477. setTempLowAlreadySaved = true;
  478. }
  479. if (!setTempLow2AlreadySaved) {
  480. lastUpdate_setTempLow2 = millis();
  481. if (confBas.autoSaveSetTemp && setTempLow2 != setTempLow2Saved) {
  482. saveSetTempLow2();
  483. sendLog(F("TSTAT: setTempLow2 autosave done"));
  484. }
  485. setTempLow2AlreadySaved = true;
  486. }
  487. if (!heatingModeAlreadySaved) {
  488. lastUpdate_heatingMode = millis();
  489. if (confBas.autoSaveHeatingMode && heatingMode != heatingModeSaved) {
  490. saveHeatingMode();
  491. sendLog(F("TSTAT: heatingMode autosave done"));
  492. }
  493. heatingModeAlreadySaved = true;
  494. }
  495. if (!presetAlreadySaved) {
  496. lastUpdate_preset = millis();
  497. preset = pendingPreset;
  498. if (confBas.autoSaveHeatingMode && preset != presetSaved) {
  499. savePreset();
  500. sendLog(F("TSTAT: preset autosave done"));
  501. }
  502. presetAlreadySaved = true;
  503. }
  504. publishCurrentThermostatValues();
  505. }
  506. }
  507. }