thermostat.ino 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  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. }
  77. else if (preset == 1) { // night/reduction preset
  78. currSetTemp = setTempLow;
  79. }
  80. else if (preset == 2) { // night/reduction 2 preset
  81. currSetTemp = setTempLow2;
  82. }
  83. }
  84. else { // if heatingMode == 0
  85. currSetTemp = DEFAULT_SETTEMP_HEATOFF;
  86. }
  87. }
  88. void thermostat() {
  89. updateCurrSetTemp();
  90. //char tmp_topic_out[50];
  91. if (heatingMode > 0 && turnHeatingOn) {
  92. heatingOnTime = (millis() - heatingLastOnMillis) / 1000;
  93. //char buf[101];
  94. //sprintf(buf, "heating on for %lus", heatingOnTime);
  95. //sendLog(buf, LOGLEVEL_INFO);
  96. }
  97. else if (heatingMode > 0 && !turnHeatingOn) {
  98. heatingOffTime = (millis() - heatingLastOffMillis) / 1000;
  99. //char buf[101];
  100. //sprintf(buf, "heating off for %lus", heatingOffTime);
  101. //sendLog(buf, LOGLEVEL_INFO);
  102. }
  103. //char tmp_topic_out[50];
  104. //sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heating");
  105. if ( lastTempUpdate != 0 && (millis() - lastTempUpdate) <= maxMeasurementAge ) {
  106. // thermostat - only active if measured temperature is < 2 min old
  107. #ifdef DEBUG_VERBOSE
  108. Serial.print("thermostat, lastTempUpdate=");
  109. Serial.print(lastTempUpdate);
  110. Serial.print(", lastTempUpdate_delta=");
  111. long lastTempUpdateDelta = millis() - lastTempUpdate;
  112. Serial.println(lastTempUpdateDelta);
  113. #endif
  114. // thermostat with hysteresis
  115. if ( turnHeatingOn && currTemp >= (currSetTemp - confAdv.setTempDecreaseVal) ) {
  116. turnHeatingOn = false;
  117. heatingLastOffMillis = millis();
  118. digitalWrite(PIN_RELAIS, !RELAISONSTATE);
  119. updateDisplay();
  120. char buf[101];
  121. sprintf_P(buf, "TSTAT: %s OFF, on for %lus", PGMStr_switchHeating, heatingOnTime);
  122. sendLog(buf, LOGLEVEL_INFO);
  123. //Serial.println("heating off");
  124. //mqttclient.publish(tmp_topic_out, "off");
  125. publishCurrentThermostatValues();
  126. }
  127. else if ( !turnHeatingOn && heatingMode > 0 && ( currTemp < (currSetTemp - confAdv.setTempDecreaseVal - confAdv.hysteresis) ) && ( heatingOffTime > confAdv.heatingMinOffTime ) ) {
  128. turnHeatingOn = true;
  129. heatingLastOnMillis = millis();
  130. digitalWrite(PIN_RELAIS, RELAISONSTATE);
  131. updateDisplay();
  132. char buf[101];
  133. sprintf(buf, "TSTAT: switch heating ON, off for %lus", heatingOffTime);
  134. sendLog(buf, LOGLEVEL_INFO);
  135. //Serial.println("heating on");
  136. //mqttclient.publish(tmp_topic_out, "on");
  137. publishCurrentThermostatValues();
  138. }
  139. }
  140. else {
  141. if (turnHeatingOn) {
  142. digitalWrite(PIN_RELAIS, !RELAISONSTATE);
  143. turnHeatingOn = false;
  144. heatingLastOffMillis = millis();
  145. }
  146. if ( lastTempUpdate != 0 ) sendLog(F("TSTAT: heating OFF, temp reading not yet available"), LOGLEVEL_INFO);
  147. else if ( (millis() - lastTempUpdate) > maxMeasurementAge ) sendLog(F("TSTAT: heating OFF, last temp reading too old"), LOGLEVEL_WARN);
  148. //mqttclient.publish(tmp_topic_out, "off");
  149. publishCurrentThermostatValues();
  150. }
  151. }
  152. void toggleOnOff() {
  153. if (heatingMode > 0) {
  154. heatingMode = 0;
  155. lastValueChange = millis();
  156. heatingModeAlreadySaved = false;
  157. }
  158. else {
  159. heatingMode = 1;
  160. lastValueChange = millis();
  161. heatingModeAlreadySaved = false;
  162. }
  163. updateCurrentHeatingModeName();
  164. updateDisplay();
  165. }
  166. void togglePreset() {
  167. //sendLog(F("switch preset to "));
  168. if (pendingPreset < 0 || pendingPreset > 2) pendingPreset = preset;
  169. // if (pendingPresetToggle && preset == 0 && pendingPreset == 0) pendingPreset = 1;
  170. // else if (pendingPresetToggle && preset == 1 && pendingPreset == 1) pendingPreset = 0;
  171. // else if (pendingPreset == 1 && pendingPresetToggle) pendingPreset = 2;
  172. // else if (pendingPreset == 2 && !pendingPresetToggle) pendingPreset = 0;
  173. // else if (pendingPreset == 2 && pendingPresetToggle) pendingPreset = 1;
  174. if (pendingPreset == 0) pendingPreset = 1;
  175. else if (pendingPreset == 1) pendingPreset = 2;
  176. else if (pendingPreset == 2) pendingPreset = 0;
  177. // if (preset == 0 && pendingPreset == 0) pendingPreset = 1;
  178. // else if (preset == 0 && pendingPreset == 1) pendingPreset = 2;
  179. // else if (preset == 1 && pendingPreset == 0) pendingPreset = 2;
  180. // else if (preset == 1 && pendingPreset == 1) pendingPreset = 0;
  181. // else if (preset == 1 && pendingPreset == 2) pendingPreset = 1;
  182. // else if (preset == 1 && pendingPreset == 0) pendingPreset = 1;
  183. // else if (preset == 2 && pendingPreset == 0) pendingPreset = 1;
  184. // else if (preset == 2 && pendingPreset == 1) pendingPreset = 0;
  185. // else if (preset == 2 && pendingPreset == 2) pendingPreset = 0;
  186. lastValueChange = millis();
  187. presetAlreadySaved = false;
  188. updatePendingPresetName();
  189. //updateDisplay();
  190. //pendingPresetToggle = true;
  191. displayShowLine2OverlayMessage(pendingPresetName);
  192. //Serial.print(pendingPreset);
  193. //Serial.print(" - \"");
  194. //Serial.print(currentPresetName);
  195. //Serial.println("\"");
  196. }
  197. void updateCurrentHeatingModeName() {
  198. if (heatingMode == 0) strlcpy(currentModeName, confAdv.modeName0, 14);
  199. else if (heatingMode == 1) strlcpy(currentModeName, confAdv.modeName1, 14);
  200. }
  201. void updateCurrentPresetName() {
  202. if (preset == 0) strlcpy(currentPresetName, confAdv.psetName0, 14);
  203. else if (preset == 1) strlcpy(currentPresetName, confAdv.psetName1, 14);
  204. else if (preset == 2) strlcpy(currentPresetName, confAdv.psetName2, 14);
  205. }
  206. void updatePendingPresetName() {
  207. if (pendingPreset == 0) strlcpy(pendingPresetName, confAdv.psetName0, 14);
  208. else if (pendingPreset == 1) strlcpy(pendingPresetName, confAdv.psetName1, 14);
  209. else if (pendingPreset == 2) strlcpy(pendingPresetName, confAdv.psetName2, 14);
  210. }
  211. void setTempStepUp() {
  212. if (heatingMode == 1) {
  213. sendLog(F("TSTAT: setTemp +0.5"));
  214. if ( setTemp <= (confBas.setTempMax - 0.5)) {
  215. setTemp += 0.5;
  216. lastValueChange = millis();
  217. setTempAlreadySaved = false;
  218. }
  219. updateDisplay();
  220. }
  221. }
  222. void setTempStepDown() {
  223. if (heatingMode == 1) {
  224. sendLog(F("TSTAT: setTemp -0.5"));
  225. if ( setTemp >= (confBas.setTempMin + 0.5)) {
  226. setTemp -= 0.5;
  227. lastValueChange = millis();
  228. setTempAlreadySaved = false;
  229. }
  230. updateDisplay();
  231. }
  232. }
  233. void setTempTo(float setTo) {
  234. boolean changes = false;
  235. float tmpSetTemp;
  236. if(setTo != setTemp) {
  237. if (setTo >= confBas.setTempMin && setTo <= confBas.setTempMax) {
  238. tmpSetTemp = setTo;
  239. changes = true;
  240. }
  241. else if (setTo > confBas.setTempMax) {
  242. tmpSetTemp = confBas.setTempMax;
  243. changes = true;
  244. }
  245. else if (setTo < confBas.setTempMin) {
  246. tmpSetTemp = confBas.setTempMin;
  247. changes = true;
  248. }
  249. if (changes) {
  250. setTemp = tmpSetTemp;
  251. lastValueChange = millis();
  252. setTempAlreadySaved = false;
  253. updateDisplay();
  254. publishCurrentThermostatValues();
  255. char buf1[30];
  256. //sprintf(buf1, "setTemp changed to %2.1f", setTemp);
  257. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTemp, PGMStr_changedTo, setTemp);
  258. //sendLog(F("setTemp changed"));
  259. sendLog(buf1);
  260. }
  261. }
  262. }
  263. void setTempLowStepUp() {
  264. sendLog(F("TSTAT: setTempLow +0.5"));
  265. if ( setTempLow <= (setTempLowMax - 0.5)) {
  266. setTempLow += 0.5;
  267. lastValueChange = millis();
  268. setTempLowAlreadySaved = false;
  269. }
  270. updateDisplay();
  271. }
  272. void setTempLowStepDown() {
  273. sendLog(F("TSTAT: setTempLow -0.5"));
  274. if ( setTempLow >= (setTempLowMin + 0.5)) {
  275. setTempLow -= 0.5;
  276. lastValueChange = millis();
  277. setTempLowAlreadySaved = false;
  278. }
  279. updateDisplay();
  280. }
  281. void setTempLowTo(float setTo) {
  282. boolean changes = false;
  283. float tmp_setTempLow;
  284. if(setTo != setTempLow) {
  285. if (setTo >= setTempLowMin && setTo <= setTempLowMax) {
  286. tmp_setTempLow = setTo;
  287. changes = true;
  288. }
  289. else if (setTo > setTempLowMax) {
  290. tmp_setTempLow = setTempLowMax;
  291. changes = true;
  292. }
  293. else if (setTo < setTempLowMin) {
  294. tmp_setTempLow = setTempLowMin;
  295. changes = true;
  296. }
  297. if (changes) {
  298. setTempLow = tmp_setTempLow;
  299. lastValueChange = millis();
  300. setTempLowAlreadySaved = false;
  301. updateDisplay();
  302. publishCurrentThermostatValues();
  303. //Serial.println("setTempLow CHANGED");
  304. char buf1[30];
  305. //sprintf(buf1, "setTempLow changed to %2.1f", setTempLow);
  306. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow, PGMStr_changedTo, setTempLow);
  307. sendLog(buf1);
  308. }
  309. }
  310. }
  311. void setTempLow2StepUp() {
  312. sendLog(F("TSTAT: setTempLow2 +0.5"));
  313. if ( setTempLow2 <= (setTempLowMax - 0.5)) {
  314. setTempLow2 += 0.5;
  315. lastValueChange = millis();
  316. setTempLow2AlreadySaved = false;
  317. }
  318. updateDisplay();
  319. }
  320. void setTempLow2StepDown() {
  321. sendLog(F("TSTAT: setTempLow2 -0.5"));
  322. if ( setTempLow2 >= (setTempLowMin + 0.5)) {
  323. setTempLow2 -= 0.5;
  324. lastValueChange = millis();
  325. setTempLow2AlreadySaved = false;
  326. }
  327. updateDisplay();
  328. }
  329. void setTempLow2To(float setTo) {
  330. boolean changes = false;
  331. float tmp_setTempLow2;
  332. if(setTo != setTempLow2) {
  333. if (setTo >= setTempLowMin && setTo <= setTempLowMax) {
  334. tmp_setTempLow2 = setTo;
  335. changes = true;
  336. }
  337. else if (setTo > setTempLowMax) {
  338. tmp_setTempLow2 = setTempLowMax;
  339. changes = true;
  340. }
  341. else if (setTo < setTempLowMin) {
  342. tmp_setTempLow2 = setTempLowMin;
  343. changes = true;
  344. }
  345. if (changes) {
  346. setTempLow2 = tmp_setTempLow2;
  347. lastValueChange = millis();
  348. setTempLow2AlreadySaved = false;
  349. updateDisplay();
  350. publishCurrentThermostatValues();
  351. //Serial.println("setTempLow2 CHANGED");
  352. char buf1[30];
  353. //sprintf(buf1, "setTempLow2 changed to %2.1f", setTempLow2);
  354. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow2, PGMStr_changedTo, setTempLow2);
  355. sendLog(buf1);
  356. }
  357. }
  358. }
  359. void setHeatingmodeTo(unsigned char setTo) {
  360. if(setTo != heatingMode) {
  361. heatingMode = setTo;
  362. updateCurrSetTemp();
  363. lastValueChange = millis();
  364. heatingModeAlreadySaved = false;
  365. updateCurrentHeatingModeName();
  366. updateDisplay();
  367. publishCurrentThermostatValues();
  368. //Serial.println("heatingMode CHANGED");
  369. char buf1[30];
  370. //sprintf(buf1, "heatingMode changed to %u", heatingMode);
  371. sprintf_P(buf1, "%s: %s %s %u", PGMStr_thermostat, PGMStr_heatingMode, PGMStr_changedTo, heatingMode);
  372. sendLog(buf1);
  373. }
  374. }
  375. void setPresetTo(unsigned char setTo) {
  376. if(setTo != preset) {
  377. if(setTo >= 0 && setTo <=2) {
  378. preset = setTo;
  379. pendingPreset = setTo;
  380. updateCurrSetTemp();
  381. lastValueChange = millis();
  382. presetAlreadySaved = false;
  383. updateCurrentPresetName();
  384. updateDisplay();
  385. publishCurrentThermostatValues();
  386. //Serial.println("preset CHANGED");
  387. char buf1[30];
  388. sprintf_P(buf1, "%s: %s %s %u", PGMStr_thermostat, PGMStr_preset, PGMStr_changedTo, preset);
  389. sendLog(buf1);
  390. }
  391. }
  392. }
  393. void checkValuesChanged() { // called every second by everySecond() / scheduler.ino
  394. if ( !setTempAlreadySaved || !heatingModeAlreadySaved || !presetAlreadySaved || !setTempLowAlreadySaved || !setTempLow2AlreadySaved ) {
  395. if ( (millis() - lastValueChange) > saveValuesTimeout ) { // value was changed 5s ago. now save if auto-save enabled
  396. if (!setTempAlreadySaved) {
  397. lastUpdate_setTemp = millis();
  398. if (confBas.autoSaveSetTemp && setTemp != setTempSaved) {
  399. saveSetTemp();
  400. sendLog(F("TSTAT: setTemp autosave done"));
  401. }
  402. setTempAlreadySaved = true;
  403. }
  404. if (!setTempLowAlreadySaved) {
  405. lastUpdate_setTempLow = millis();
  406. if (confBas.autoSaveSetTemp && setTempLow != setTempLowSaved) {
  407. saveSetTempLow();
  408. sendLog(F("TSTAT: setTempLow autosave done"));
  409. }
  410. setTempLowAlreadySaved = true;
  411. }
  412. if (!setTempLow2AlreadySaved) {
  413. lastUpdate_setTempLow2 = millis();
  414. if (confBas.autoSaveSetTemp && setTempLow2 != setTempLow2Saved) {
  415. saveSetTempLow2();
  416. sendLog(F("TSTAT: setTempLow2 autosave done"));
  417. }
  418. setTempLow2AlreadySaved = true;
  419. }
  420. if (!heatingModeAlreadySaved) {
  421. lastUpdate_heatingMode = millis();
  422. if (confBas.autoSaveHeatingMode && heatingMode != heatingModeSaved) {
  423. saveHeatingMode();
  424. sendLog(F("TSTAT: heatingMode autosave done"));
  425. }
  426. heatingModeAlreadySaved = true;
  427. }
  428. if (!presetAlreadySaved) {
  429. lastUpdate_preset = millis();
  430. preset = pendingPreset;
  431. if (confBas.autoSaveHeatingMode && preset != presetSaved) {
  432. savePreset();
  433. sendLog(F("TSTAT: preset autosave done"));
  434. }
  435. presetAlreadySaved = true;
  436. }
  437. publishCurrentThermostatValues();
  438. }
  439. }
  440. }