thermostat.ino 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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. // pendingPreset 0 => Normal
  175. // pendingPreset 1 => Reduction 1
  176. // pendingPreset 2 => Reduction 2
  177. if(preset == 0) { // Normal > Reduction 1 > Reduction 2
  178. if (pendingPreset == 0) pendingPreset = 1;
  179. else if (pendingPreset == 1) pendingPreset = 2;
  180. else if (pendingPreset == 2) pendingPreset = 0;
  181. }
  182. else if(preset == 1) { // Reduction 1 > Normal > Reduction 2
  183. if (pendingPreset == 1) pendingPreset = 0;
  184. else if (pendingPreset == 0) pendingPreset = 2;
  185. else if (pendingPreset == 2) pendingPreset = 1;
  186. }
  187. else if(preset == 2) { // Reduction 2 > Normal > Reduction 1
  188. if (pendingPreset == 2) pendingPreset = 0;
  189. else if (pendingPreset == 0) pendingPreset = 1;
  190. else if (pendingPreset == 1) pendingPreset = 2;
  191. }
  192. // if (preset == 0 && pendingPreset == 0) pendingPreset = 1;
  193. // else if (preset == 0 && pendingPreset == 1) pendingPreset = 2;
  194. // else if (preset == 1 && pendingPreset == 0) pendingPreset = 2;
  195. // else if (preset == 1 && pendingPreset == 1) pendingPreset = 0;
  196. // else if (preset == 1 && pendingPreset == 2) pendingPreset = 1;
  197. // else if (preset == 1 && pendingPreset == 0) pendingPreset = 1;
  198. // else if (preset == 2 && pendingPreset == 0) pendingPreset = 1;
  199. // else if (preset == 2 && pendingPreset == 1) pendingPreset = 0;
  200. // else if (preset == 2 && pendingPreset == 2) pendingPreset = 0;
  201. lastValueChange = millis();
  202. presetAlreadySaved = false;
  203. updatePendingPresetName();
  204. //updateDisplay();
  205. //pendingPresetToggle = true;
  206. displayShowLine2OverlayMessage(pendingPresetName);
  207. //Serial.print(pendingPreset);
  208. //Serial.print(" - \"");
  209. //Serial.print(currentPresetName);
  210. //Serial.println("\"");
  211. }
  212. void updateCurrentHeatingModeName() {
  213. if (heatingMode == 0) strlcpy(currentModeName, confAdv.modeName0, 14);
  214. else if (heatingMode == 1) strlcpy(currentModeName, confAdv.modeName1, 14);
  215. }
  216. void updateCurrentPresetName() {
  217. if (preset == 0) strlcpy(currentPresetName, confAdv.psetName0, 14);
  218. else if (preset == 1) strlcpy(currentPresetName, confAdv.psetName1, 14);
  219. else if (preset == 2) strlcpy(currentPresetName, confAdv.psetName2, 14);
  220. }
  221. void updatePendingPresetName() {
  222. if (pendingPreset == 0) strlcpy(pendingPresetName, confAdv.psetName0, 14);
  223. else if (pendingPreset == 1) strlcpy(pendingPresetName, confAdv.psetName1, 14);
  224. else if (pendingPreset == 2) strlcpy(pendingPresetName, confAdv.psetName2, 14);
  225. }
  226. void setTempStepUp() {
  227. if (heatingMode == 1) {
  228. sendLog(F("TSTAT: setTemp +0.5"));
  229. if ( setTemp <= (confBas.setTempMax - 0.5)) {
  230. setTemp += 0.5;
  231. lastValueChange = millis();
  232. setTempAlreadySaved = false;
  233. }
  234. updateDisplay();
  235. }
  236. }
  237. void setTempStepDown() {
  238. if (heatingMode == 1) {
  239. sendLog(F("TSTAT: setTemp -0.5"));
  240. if ( setTemp >= (confBas.setTempMin + 0.5)) {
  241. setTemp -= 0.5;
  242. lastValueChange = millis();
  243. setTempAlreadySaved = false;
  244. }
  245. updateDisplay();
  246. }
  247. }
  248. void setTempTo(float setTo) {
  249. boolean changes = false;
  250. float tmpSetTemp;
  251. if(setTo != setTemp) {
  252. if (setTo >= confBas.setTempMin && setTo <= confBas.setTempMax) {
  253. tmpSetTemp = setTo;
  254. changes = true;
  255. }
  256. else if (setTo > confBas.setTempMax) {
  257. tmpSetTemp = confBas.setTempMax;
  258. changes = true;
  259. }
  260. else if (setTo < confBas.setTempMin) {
  261. tmpSetTemp = confBas.setTempMin;
  262. changes = true;
  263. }
  264. if (changes) {
  265. setTemp = tmpSetTemp;
  266. lastValueChange = millis();
  267. setTempAlreadySaved = false;
  268. updateDisplay();
  269. publishCurrentThermostatValues();
  270. char buf1[30];
  271. //sprintf(buf1, "setTemp changed to %2.1f", setTemp);
  272. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTemp, PGMStr_changedTo, setTemp);
  273. //sendLog(F("setTemp changed"));
  274. sendLog(buf1);
  275. }
  276. }
  277. }
  278. void setTempLowStepUp() {
  279. sendLog(F("TSTAT: setTempLow +0.5"));
  280. if ( setTempLow <= (setTempLowMax - 0.5)) {
  281. setTempLow += 0.5;
  282. lastValueChange = millis();
  283. setTempLowAlreadySaved = false;
  284. }
  285. updateDisplay();
  286. }
  287. void setTempLowStepDown() {
  288. sendLog(F("TSTAT: setTempLow -0.5"));
  289. if ( setTempLow >= (setTempLowMin + 0.5)) {
  290. setTempLow -= 0.5;
  291. lastValueChange = millis();
  292. setTempLowAlreadySaved = false;
  293. }
  294. updateDisplay();
  295. }
  296. void setTempLowTo(float setTo) {
  297. boolean changes = false;
  298. float tmp_setTempLow;
  299. if(setTo != setTempLow) {
  300. if (setTo >= setTempLowMin && setTo <= setTempLowMax) {
  301. tmp_setTempLow = setTo;
  302. changes = true;
  303. }
  304. else if (setTo > setTempLowMax) {
  305. tmp_setTempLow = setTempLowMax;
  306. changes = true;
  307. }
  308. else if (setTo < setTempLowMin) {
  309. tmp_setTempLow = setTempLowMin;
  310. changes = true;
  311. }
  312. if (changes) {
  313. setTempLow = tmp_setTempLow;
  314. lastValueChange = millis();
  315. setTempLowAlreadySaved = false;
  316. updateDisplay();
  317. publishCurrentThermostatValues();
  318. //Serial.println("setTempLow CHANGED");
  319. char buf1[30];
  320. //sprintf(buf1, "setTempLow changed to %2.1f", setTempLow);
  321. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow, PGMStr_changedTo, setTempLow);
  322. sendLog(buf1);
  323. }
  324. }
  325. }
  326. void setTempLow2StepUp() {
  327. sendLog(F("TSTAT: setTempLow2 +0.5"));
  328. if ( setTempLow2 <= (setTempLowMax - 0.5)) {
  329. setTempLow2 += 0.5;
  330. lastValueChange = millis();
  331. setTempLow2AlreadySaved = false;
  332. }
  333. updateDisplay();
  334. }
  335. void setTempLow2StepDown() {
  336. sendLog(F("TSTAT: setTempLow2 -0.5"));
  337. if ( setTempLow2 >= (setTempLowMin + 0.5)) {
  338. setTempLow2 -= 0.5;
  339. lastValueChange = millis();
  340. setTempLow2AlreadySaved = false;
  341. }
  342. updateDisplay();
  343. }
  344. void setTempLow2To(float setTo) {
  345. boolean changes = false;
  346. float tmp_setTempLow2;
  347. if(setTo != setTempLow2) {
  348. if (setTo >= setTempLowMin && setTo <= setTempLowMax) {
  349. tmp_setTempLow2 = setTo;
  350. changes = true;
  351. }
  352. else if (setTo > setTempLowMax) {
  353. tmp_setTempLow2 = setTempLowMax;
  354. changes = true;
  355. }
  356. else if (setTo < setTempLowMin) {
  357. tmp_setTempLow2 = setTempLowMin;
  358. changes = true;
  359. }
  360. if (changes) {
  361. setTempLow2 = tmp_setTempLow2;
  362. lastValueChange = millis();
  363. setTempLow2AlreadySaved = false;
  364. updateDisplay();
  365. publishCurrentThermostatValues();
  366. //Serial.println("setTempLow2 CHANGED");
  367. char buf1[30];
  368. //sprintf(buf1, "setTempLow2 changed to %2.1f", setTempLow2);
  369. sprintf_P(buf1, "%s: %s %s %2.1f", PGMStr_thermostat, PGMStr_setTempLow2, PGMStr_changedTo, setTempLow2);
  370. sendLog(buf1);
  371. }
  372. }
  373. }
  374. void setHeatingmodeTo(unsigned char setTo) {
  375. if(setTo != heatingMode) {
  376. heatingMode = setTo;
  377. updateCurrSetTemp();
  378. lastValueChange = millis();
  379. heatingModeAlreadySaved = false;
  380. updateCurrentHeatingModeName();
  381. updateDisplay();
  382. publishCurrentThermostatValues();
  383. //Serial.println("heatingMode CHANGED");
  384. char buf1[30];
  385. //sprintf(buf1, "heatingMode changed to %u", heatingMode);
  386. sprintf_P(buf1, "%s: %s %s %u", PGMStr_thermostat, PGMStr_heatingMode, PGMStr_changedTo, heatingMode);
  387. sendLog(buf1);
  388. }
  389. }
  390. void setPresetTo(unsigned char setTo) {
  391. if(setTo != preset) {
  392. if(setTo >= 0 && setTo <=2) {
  393. preset = setTo;
  394. pendingPreset = setTo;
  395. updateCurrSetTemp();
  396. lastValueChange = millis();
  397. presetAlreadySaved = false;
  398. updateCurrentPresetName();
  399. updateDisplay();
  400. publishCurrentThermostatValues();
  401. //Serial.println("preset CHANGED");
  402. char buf1[30];
  403. sprintf_P(buf1, "%s: %s %s %u", PGMStr_thermostat, PGMStr_preset, PGMStr_changedTo, preset);
  404. sendLog(buf1);
  405. }
  406. }
  407. }
  408. void checkValuesChanged() { // called every second by everySecond() / scheduler.ino
  409. if ( !setTempAlreadySaved || !heatingModeAlreadySaved || !presetAlreadySaved || !setTempLowAlreadySaved || !setTempLow2AlreadySaved ) {
  410. if ( (millis() - lastValueChange) > saveValuesTimeout ) { // value was changed 5s ago. now save if auto-save enabled
  411. if (!setTempAlreadySaved) {
  412. lastUpdate_setTemp = millis();
  413. if (confBas.autoSaveSetTemp && setTemp != setTempSaved) {
  414. saveSetTemp();
  415. sendLog(F("TSTAT: setTemp autosave done"));
  416. }
  417. setTempAlreadySaved = true;
  418. }
  419. if (!setTempLowAlreadySaved) {
  420. lastUpdate_setTempLow = millis();
  421. if (confBas.autoSaveSetTemp && setTempLow != setTempLowSaved) {
  422. saveSetTempLow();
  423. sendLog(F("TSTAT: setTempLow autosave done"));
  424. }
  425. setTempLowAlreadySaved = true;
  426. }
  427. if (!setTempLow2AlreadySaved) {
  428. lastUpdate_setTempLow2 = millis();
  429. if (confBas.autoSaveSetTemp && setTempLow2 != setTempLow2Saved) {
  430. saveSetTempLow2();
  431. sendLog(F("TSTAT: setTempLow2 autosave done"));
  432. }
  433. setTempLow2AlreadySaved = true;
  434. }
  435. if (!heatingModeAlreadySaved) {
  436. lastUpdate_heatingMode = millis();
  437. if (confBas.autoSaveHeatingMode && heatingMode != heatingModeSaved) {
  438. saveHeatingMode();
  439. sendLog(F("TSTAT: heatingMode autosave done"));
  440. }
  441. heatingModeAlreadySaved = true;
  442. }
  443. if (!presetAlreadySaved) {
  444. lastUpdate_preset = millis();
  445. preset = pendingPreset;
  446. if (confBas.autoSaveHeatingMode && preset != presetSaved) {
  447. savePreset();
  448. sendLog(F("TSTAT: preset autosave done"));
  449. }
  450. presetAlreadySaved = true;
  451. }
  452. publishCurrentThermostatValues();
  453. }
  454. }
  455. }