You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

zuno-test.ino 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. #include "EEPROM.h"
  2. #include <ZUNO_OneWire.h>
  3. #include <ZUNO_DS18B20.h>
  4. #define PIN_RELAY_BURNER 12
  5. #define PIN_RELAY_WATER_LOAD 11
  6. #define PIN_RELAY_WATER_RECYCLING 10
  7. #define PIN_RELAY_HEAT_PUMP_1 9
  8. #define PIN_INPUT_BURNER_RUNNING 16
  9. #define PIN_INPUT_BURNER_ALARM 17
  10. #define PIN_INPUT_BOILER_ALARM 18
  11. #define PIN_ONEWIRE 15
  12. #define EEPROM_MAGIC_VALUE 0x4242
  13. #define EEPROM_MAGIC_ADDR 0
  14. #define EEPROM_REQUESTED_TEMP_ADDR_BASE (EEPROM_MAGIC_ADDR + 2)
  15. #define EEPROM_THERMOSTAT_MODE_BASE (EEPROM_REQUESTED_TEMP_ADDR_BASE + 4) // req temp is 2 bytes per thermostat
  16. #define ZW_PARAM_BASE 64
  17. #define ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE (ZW_PARAM_BASE) // 64, 65
  18. #define ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE (ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE + 2) // 66, 67
  19. #define ZW_PARAM_MIN_CYCLE_DURATION_BASE (ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE + 2) // 68, 69
  20. #define ZW_PARAM_TOLERANCE_TEMP_BASE (ZW_PARAM_MIN_CYCLE_DURATION_BASE + 2) // 70, 71
  21. #define LOG_INIT() Serial.begin(9600)
  22. #define LOG_WRITE(x) Serial.print(x)
  23. #define LOG_WRITELN(x) Serial.println(x)
  24. //#define LOG_INIT()
  25. //#define LOG_WRITE(x)
  26. //#define LOG_WRITELN(x)
  27. #define DALLAS_ADDR_SIZE 8
  28. struct thermostat_t {
  29. byte dallasAddress[DALLAS_ADDR_SIZE];
  30. word currentTemp;
  31. byte requestedMode;
  32. word requestedTemp;
  33. unsigned long lastZwaveReadTime;
  34. word lastZwaveReadTemp;
  35. word updateUnsolicitedTime;
  36. word updateThresholdTemp;
  37. word minCycleDuration;
  38. word toleranceTemp;
  39. bool requestHeat;
  40. };
  41. struct output_t {
  42. int pin;
  43. bool currentValue;
  44. unsigned long lastChangedTime;
  45. };
  46. OneWire oneWire(PIN_ONEWIRE);
  47. DS18B20Sensor dallas(&oneWire);
  48. #define THERMOSTATS_COUNT 2
  49. #define THERMOSTAT_HEAT_IDX 0
  50. #define THERMOSTAT_WATER_IDX 1
  51. thermostat_t thermostats[THERMOSTATS_COUNT];
  52. #define OUTPUTS_COUNT 4
  53. #define OUTPUT_BURNER_IDX 0
  54. #define OUTPUT_WATER_LOAD_IDX 1
  55. #define OUTPUT_WATER_RECYCLING_IDX 2
  56. #define OUTPUT_HEAT_PUMP_1_IDX 3
  57. output_t outputs[OUTPUTS_COUNT];
  58. ZUNO_SETUP_CHANNELS(
  59. ZUNO_THERMOSTAT(THERMOSTAT_FLAGS_OFF | THERMOSTAT_FLAGS_HEAT, THERMOSTAT_UNITS_CELSIUS, THERMOSTAT_RANGE_POS, 10, getHeaterMode, setHeaterMode, getHeaterTemp, setHeaterTemp), // Heater
  60. ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_WATER_TEMPERATURE, SENSOR_MULTILEVEL_SCALE_CELSIUS, METER_SIZE_TWO_BYTES, SENSOR_MULTILEVEL_PRECISION_TWO_DECIMALS, getHeaterCurrentTemp), // Heater temp
  61. ZUNO_THERMOSTAT(THERMOSTAT_FLAGS_OFF | THERMOSTAT_FLAGS_HEAT, THERMOSTAT_UNITS_CELSIUS, THERMOSTAT_RANGE_POS, 10, getWaterMode, setWaterMode, getWaterTemp, setWaterTemp), // Water
  62. ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_WATER_TEMPERATURE, SENSOR_MULTILEVEL_SCALE_CELSIUS, METER_SIZE_TWO_BYTES, SENSOR_MULTILEVEL_PRECISION_TWO_DECIMALS, getWaterCurrentTemp), // Water temp
  63. ZUNO_SWITCH_BINARY(getRelayBurner, setRelayBurner), // Burner
  64. ZUNO_SWITCH_BINARY(getRelayWaterLoad, setRelayWaterLoad), // Water load pump
  65. ZUNO_SWITCH_BINARY(getRelayWaterRecycling, setRelayWaterRecycling), // Water recycling pump
  66. ZUNO_SWITCH_BINARY(getRelayHeatPump1, setRelayHeatPump1), // Heater pump Floor 1
  67. ZUNO_SENSOR_BINARY(ZUNO_SENSOR_BINARY_TYPE_GENERAL_PURPOSE, getInputBurnerRunning), // Burner running
  68. ZUNO_SENSOR_BINARY(ZUNO_SENSOR_BINARY_TYPE_GENERAL_PURPOSE, getInputBurnerAlarm), // Burner alarm
  69. ZUNO_SENSOR_BINARY(ZUNO_SENSOR_BINARY_TYPE_GENERAL_PURPOSE, getInputBoilerAlarm) // Boiler alarm
  70. );
  71. ZUNO_SETUP_CFGPARAMETER_HANDLER(config_parameter_changed);
  72. byte EEPROM_put(dword address, void * value, word val_size) {
  73. byte res = EEPROM.put(address, value, val_size);
  74. if (!res) {
  75. LOG_WRITELN("EEPROM put: FAIL");
  76. }
  77. return res;
  78. }
  79. byte EEPROM_get(dword address, void * value, word val_size) {
  80. byte res = EEPROM.get(address, value, val_size);
  81. if (!res) {
  82. LOG_WRITELN("EEPROM put: FAIL");
  83. }
  84. return res;
  85. }
  86. word abs_diff(word v1, word v2) {
  87. if (v1 > v2) {
  88. return v1 - v2;
  89. }
  90. return v2 - v1;
  91. }
  92. void setup() {
  93. delay(2000);
  94. LOG_INIT();
  95. LOG_WRITELN("setup BEGIN");
  96. pinMode(PIN_INPUT_BURNER_RUNNING, INPUT);
  97. pinMode(PIN_INPUT_BURNER_ALARM, INPUT);
  98. pinMode(PIN_INPUT_BOILER_ALARM, INPUT);
  99. word magic_value[1] = {0};
  100. EEPROM_get(EEPROM_MAGIC_ADDR, magic_value, sizeof(magic_value));
  101. if (magic_value[0] != EEPROM_MAGIC_VALUE) {
  102. LOG_WRITE("First init: ");
  103. LOG_WRITELN((int)magic_value[0]);
  104. zunoSaveCFGParam(ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE + 0, 600); // 10 min
  105. zunoSaveCFGParam(ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE + 1, 600); // 10 min
  106. zunoSaveCFGParam(ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE + 0, 50); // 0.5 °C
  107. zunoSaveCFGParam(ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE + 1, 50); // 0.5 °C
  108. zunoSaveCFGParam(ZW_PARAM_MIN_CYCLE_DURATION_BASE + 0, 60); // 1 min
  109. zunoSaveCFGParam(ZW_PARAM_MIN_CYCLE_DURATION_BASE + 1, 60); // 1 min
  110. zunoSaveCFGParam(ZW_PARAM_TOLERANCE_TEMP_BASE + 0, 2000); // 20 °C
  111. zunoSaveCFGParam(ZW_PARAM_TOLERANCE_TEMP_BASE + 1, 1000); // 10 °C
  112. word requestedTemps[2] = {8000, 3000}; // 80 °C; 30 °C
  113. EEPROM_put(EEPROM_REQUESTED_TEMP_ADDR_BASE, requestedTemps, sizeof(requestedTemps));
  114. byte modes[2] = {THERMOSTAT_MODE_OFF, THERMOSTAT_MODE_OFF};
  115. EEPROM_put(EEPROM_THERMOSTAT_MODE_BASE, modes, sizeof(modes));
  116. magic_value[0] = EEPROM_MAGIC_VALUE;
  117. EEPROM_put(EEPROM_MAGIC_ADDR, magic_value, sizeof(magic_value));
  118. }
  119. byte dallasAddresses[DALLAS_ADDR_SIZE * 2];
  120. byte dallasAddressesCount = dallas.findAllSensors(dallasAddresses); // TODO retry if not 2
  121. LOG_WRITE("Found ");
  122. LOG_WRITE(dallasAddressesCount);
  123. LOG_WRITELN(" sensors");
  124. word requestedTemps[2] = {8000, 3000};
  125. EEPROM_get(EEPROM_REQUESTED_TEMP_ADDR_BASE, requestedTemps, sizeof(requestedTemps));
  126. byte modes[2] = {THERMOSTAT_MODE_OFF, THERMOSTAT_MODE_OFF};
  127. EEPROM_get(EEPROM_THERMOSTAT_MODE_BASE, modes, sizeof(modes));
  128. for (int ti = 0; ti < THERMOSTATS_COUNT; ++ti) {
  129. memcpy(thermostats[ti].dallasAddress, &dallasAddresses[ti * DALLAS_ADDR_SIZE], DALLAS_ADDR_SIZE);
  130. thermostats[ti].currentTemp = BAD_TEMP;
  131. thermostats[ti].requestedMode = modes[ti];
  132. thermostats[ti].requestedTemp = requestedTemps[ti];
  133. thermostats[ti].lastZwaveReadTime = 0;
  134. thermostats[ti].lastZwaveReadTemp = BAD_TEMP;
  135. thermostats[ti].updateUnsolicitedTime = zunoLoadCFGParam(ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE + ti);
  136. thermostats[ti].updateThresholdTemp = zunoLoadCFGParam(ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE + ti);
  137. thermostats[ti].minCycleDuration = zunoLoadCFGParam(ZW_PARAM_MIN_CYCLE_DURATION_BASE + ti);
  138. thermostats[ti].toleranceTemp = zunoLoadCFGParam(ZW_PARAM_TOLERANCE_TEMP_BASE + ti);
  139. thermostats[ti].requestHeat = false;
  140. }
  141. outputs[OUTPUT_BURNER_IDX].pin = PIN_RELAY_BURNER;
  142. outputs[OUTPUT_WATER_LOAD_IDX].pin = PIN_RELAY_WATER_LOAD;
  143. outputs[OUTPUT_WATER_RECYCLING_IDX].pin = PIN_RELAY_WATER_RECYCLING;
  144. outputs[OUTPUT_HEAT_PUMP_1_IDX].pin = PIN_RELAY_HEAT_PUMP_1;
  145. for (int oi = 0; oi < OUTPUTS_COUNT; ++oi) {
  146. outputs[oi].currentValue = 0;
  147. outputs[oi].lastChangedTime = 0;
  148. pinMode(outputs[oi].pin, OUTPUT);
  149. digitalWrite(outputs[oi].pin, 0);
  150. }
  151. LOG_WRITELN("setup END");
  152. }
  153. void updateValues() {
  154. // Temp sensors
  155. for (int ti = 0; ti < THERMOSTATS_COUNT; ++ti) {
  156. word newValue = BAD_TEMP;
  157. for (int j = 0; j < 3 && (newValue == BAD_TEMP || newValue == 0); ++j) {
  158. newValue = dallas.getTemperature(thermostats[ti].dallasAddress) * 100;
  159. }
  160. thermostats[ti].currentTemp = newValue;
  161. if (thermostats[ti].requestedMode == THERMOSTAT_MODE_HEAT) {
  162. if (thermostats[ti].currentTemp <= thermostats[ti].requestedTemp - thermostats[ti].toleranceTemp && !thermostats[ti].requestHeat) { // TODO Check overflow
  163. LOG_WRITE("Thermostat ");
  164. LOG_WRITE(ti);
  165. LOG_WRITE(" is too low: ");
  166. LOG_WRITE((int)thermostats[ti].currentTemp);
  167. LOG_WRITE(" << ");
  168. LOG_WRITELN((int)thermostats[ti].requestedTemp);
  169. thermostats[ti].requestHeat = true;
  170. }
  171. else if (thermostats[ti].currentTemp >= thermostats[ti].requestedTemp && thermostats[ti].requestHeat) {
  172. LOG_WRITE("Thermostat ");
  173. LOG_WRITE(ti);
  174. LOG_WRITE(" is acceptable: ");
  175. LOG_WRITE((int)thermostats[ti].currentTemp);
  176. LOG_WRITE(" >= ");
  177. LOG_WRITELN((int)thermostats[ti].requestedTemp);
  178. thermostats[ti].requestHeat = false;
  179. }
  180. }
  181. else {
  182. if (thermostats[ti].requestHeat) {
  183. LOG_WRITE("Thermostat ");
  184. LOG_WRITE(ti);
  185. LOG_WRITELN(" has been turned OFF");
  186. thermostats[ti].requestHeat = false;
  187. setRelayManual(OUTPUT_BURNER_IDX, 0);
  188. setRelayManual(OUTPUT_WATER_LOAD_IDX, 0);
  189. }
  190. }
  191. }
  192. }
  193. void updateZwave() {
  194. for (int ti = 0; ti < THERMOSTATS_COUNT; ++ti) {
  195. const word oldValue = thermostats[ti].lastZwaveReadTemp;
  196. const word newValue = thermostats[ti].currentTemp;
  197. if (abs_diff(newValue, oldValue) > thermostats[ti].updateThresholdTemp) {
  198. LOG_WRITE("Sensor ");
  199. LOG_WRITE(ti);
  200. LOG_WRITE(" value changed from ");
  201. LOG_WRITE((int)oldValue);
  202. LOG_WRITE(" to ");
  203. LOG_WRITELN((int)newValue);
  204. zunoSendReport(2 + (ti * 2)); // 2 or 4
  205. }
  206. else if (millis() - thermostats[ti].lastZwaveReadTime > (unsigned long)thermostats[ti].updateUnsolicitedTime * 1000) {
  207. LOG_WRITE("Sensor ");
  208. LOG_WRITE(ti);
  209. LOG_WRITE(" unsolicited update to ");
  210. LOG_WRITELN((int)newValue);
  211. zunoSendReport(2 + (ti * 2)); // 2 or 4
  212. }
  213. }
  214. }
  215. void updateOutputs() {
  216. // TODO Handle min cycle
  217. bool burnerRequested = thermostats[THERMOSTAT_HEAT_IDX].requestHeat || (thermostats[THERMOSTAT_WATER_IDX].requestHeat && thermostats[THERMOSTAT_HEAT_IDX].currentTemp < thermostats[THERMOSTAT_WATER_IDX].requestedTemp);
  218. bool waterLoadRequested = thermostats[THERMOSTAT_WATER_IDX].requestHeat && thermostats[THERMOSTAT_HEAT_IDX].currentTemp > thermostats[THERMOSTAT_WATER_IDX].currentTemp;
  219. if (thermostats[THERMOSTAT_HEAT_IDX].requestedMode == THERMOSTAT_MODE_HEAT || thermostats[THERMOSTAT_WATER_IDX].requestedMode == THERMOSTAT_MODE_HEAT) {
  220. setRelay(OUTPUT_BURNER_IDX, burnerRequested);
  221. }
  222. if (thermostats[THERMOSTAT_WATER_IDX].requestedMode == THERMOSTAT_MODE_HEAT) {
  223. setRelay(OUTPUT_WATER_LOAD_IDX, waterLoadRequested);
  224. }
  225. }
  226. void loop() {
  227. updateValues();
  228. updateZwave();
  229. updateOutputs();
  230. delay(100);
  231. }
  232. // ZWave callbacks
  233. void config_parameter_changed(byte param, word value) {
  234. LOG_WRITE("Zwave param ");
  235. LOG_WRITE((int)param);
  236. LOG_WRITE(": ");
  237. LOG_WRITELN((int)value);
  238. if (param >= ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE && param < ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE + THERMOSTATS_COUNT) {
  239. thermostats[param - ZW_PARAM_UPDATE_UNSOLICITED_TIME_BASE].updateUnsolicitedTime = value;
  240. }
  241. else if (param >= ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE && param < ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE + THERMOSTATS_COUNT) {
  242. thermostats[param - ZW_PARAM_UPDATE_THRESHOLD_TEMP_BASE].updateThresholdTemp = value;
  243. }
  244. else if (param >= ZW_PARAM_MIN_CYCLE_DURATION_BASE && param < ZW_PARAM_MIN_CYCLE_DURATION_BASE + THERMOSTATS_COUNT) {
  245. thermostats[param - ZW_PARAM_MIN_CYCLE_DURATION_BASE].minCycleDuration = value;
  246. }
  247. else if (param >= ZW_PARAM_TOLERANCE_TEMP_BASE && param < ZW_PARAM_TOLERANCE_TEMP_BASE + THERMOSTATS_COUNT) {
  248. thermostats[param - ZW_PARAM_TOLERANCE_TEMP_BASE].toleranceTemp = value;
  249. }
  250. }
  251. // Thermostats
  252. void setMode(int ti, byte mode) {
  253. LOG_WRITE("Thermostat ");
  254. LOG_WRITE(ti);
  255. LOG_WRITE(" update: mode: ");
  256. LOG_WRITELN((int)mode);
  257. thermostats[ti].requestedMode = mode;
  258. EEPROM_put(EEPROM_THERMOSTAT_MODE_BASE + (sizeof(thermostats[ti].requestedMode) * ti), &thermostats[ti].requestedMode, sizeof(thermostats[ti].requestedMode));
  259. }
  260. byte getMode(int ti) {
  261. return thermostats[ti].requestedMode;
  262. }
  263. void setTemp(int ti, byte mode, word temp) {
  264. LOG_WRITE("Thermostat ");
  265. LOG_WRITE(ti);
  266. LOG_WRITE(" update: mode: ");
  267. LOG_WRITE((int)mode);
  268. LOG_WRITE(" temp: ");
  269. LOG_WRITELN((int)temp);
  270. thermostats[ti].requestedMode = mode;
  271. EEPROM_put(EEPROM_THERMOSTAT_MODE_BASE + (sizeof(thermostats[ti].requestedMode) * ti), &thermostats[ti].requestedMode, sizeof(thermostats[ti].requestedMode));
  272. if (mode == THERMOSTAT_MODE_HEAT) {
  273. thermostats[ti].requestedTemp = temp * 10;// Z-Wave thermostat precision is 0.1
  274. EEPROM_put(EEPROM_REQUESTED_TEMP_ADDR_BASE + (sizeof(thermostats[ti].requestedTemp) * ti), &thermostats[ti].requestedTemp, sizeof(thermostats[ti].requestedTemp));
  275. }
  276. }
  277. word getTemp(int ti, byte mode) {
  278. if (mode == THERMOSTAT_MODE_HEAT) {
  279. return thermostats[ti].requestedTemp / 10;// Z-Wave thermostat precision is 0.1
  280. }
  281. return 0;
  282. }
  283. word getCurrentTemp(int ti) {
  284. LOG_WRITE("Sensor ");
  285. LOG_WRITE(ti);
  286. LOG_WRITELN(" Zwave update");
  287. thermostats[ti].lastZwaveReadTime = millis();
  288. thermostats[ti].lastZwaveReadTemp = thermostats[ti].currentTemp;
  289. return thermostats[ti].lastZwaveReadTemp;
  290. }
  291. // Heater
  292. void setHeaterMode(byte mode) {
  293. setMode(THERMOSTAT_HEAT_IDX, mode);
  294. }
  295. byte getHeaterMode(){
  296. return getMode(THERMOSTAT_HEAT_IDX);
  297. }
  298. void setHeaterTemp(byte mode, word temp) {
  299. setTemp(THERMOSTAT_HEAT_IDX, mode, temp);
  300. }
  301. word getHeaterTemp(byte mode) {
  302. return getTemp(THERMOSTAT_HEAT_IDX, mode);
  303. }
  304. word getHeaterCurrentTemp() {
  305. return getCurrentTemp(THERMOSTAT_HEAT_IDX);
  306. }
  307. // Water
  308. void setWaterMode(byte mode) {
  309. setMode(THERMOSTAT_WATER_IDX, mode);
  310. }
  311. byte getWaterMode(){
  312. return getMode(THERMOSTAT_WATER_IDX);
  313. }
  314. void setWaterTemp(byte mode, word temp) {
  315. setTemp(THERMOSTAT_WATER_IDX, mode, temp);
  316. }
  317. word getWaterTemp(byte mode) {
  318. return getTemp(THERMOSTAT_WATER_IDX, mode);
  319. }
  320. word getWaterCurrentTemp() {
  321. return getCurrentTemp(THERMOSTAT_WATER_IDX);
  322. }
  323. // Raw outputs
  324. void setRelay(int oi, bool value) {
  325. if (value != outputs[oi].currentValue) {
  326. LOG_WRITE("Output ");
  327. LOG_WRITE(oi);
  328. LOG_WRITE(" update: value: ");
  329. LOG_WRITELN((int)value);
  330. outputs[oi].currentValue = value;
  331. outputs[oi].lastChangedTime = millis();
  332. digitalWrite(outputs[oi].pin, value);
  333. zunoSendReport(5 + oi); // 5 to 8
  334. }
  335. }
  336. byte getRelay(int oi) {
  337. return outputs[oi].currentValue;
  338. }
  339. void setRelayManual(int oi, byte value) {
  340. if (oi == OUTPUT_BURNER_IDX && (thermostats[THERMOSTAT_HEAT_IDX].requestedMode == THERMOSTAT_MODE_HEAT || thermostats[THERMOSTAT_WATER_IDX].requestedMode == THERMOSTAT_MODE_HEAT)) {
  341. return;
  342. }
  343. if (oi == OUTPUT_WATER_LOAD_IDX && thermostats[THERMOSTAT_WATER_IDX].requestedMode == THERMOSTAT_MODE_HEAT) {
  344. return;
  345. }
  346. setRelay(oi, value ? 1 : 0);
  347. }
  348. byte getRelayZwave(int oi) {
  349. return getRelay(oi) ? 255 : 0;
  350. }
  351. void setRelayBurner(byte value) {
  352. setRelayManual(OUTPUT_BURNER_IDX, value);
  353. }
  354. byte getRelayBurner() {
  355. return getRelayZwave(OUTPUT_BURNER_IDX);
  356. }
  357. void setRelayWaterLoad(byte value) {
  358. setRelayManual(OUTPUT_WATER_LOAD_IDX, value);
  359. }
  360. byte getRelayWaterLoad() {
  361. return getRelayZwave(OUTPUT_WATER_LOAD_IDX);
  362. }
  363. void setRelayWaterRecycling(byte value) {
  364. setRelayManual(OUTPUT_WATER_RECYCLING_IDX, value);
  365. }
  366. byte getRelayWaterRecycling() {
  367. return getRelayZwave(OUTPUT_WATER_RECYCLING_IDX);
  368. }
  369. void setRelayHeatPump1(byte value) {
  370. setRelayManual(OUTPUT_HEAT_PUMP_1_IDX, value);
  371. }
  372. byte getRelayHeatPump1() {
  373. return getRelayZwave(OUTPUT_HEAT_PUMP_1_IDX);
  374. }
  375. // Raw inputs
  376. byte getInputBurnerRunning() {
  377. return !digitalRead(PIN_INPUT_BURNER_RUNNING);
  378. }
  379. byte getInputBurnerAlarm() {
  380. return !digitalRead(PIN_INPUT_BURNER_ALARM);
  381. }
  382. byte getInputBoilerAlarm() {
  383. return !digitalRead(PIN_INPUT_BOILER_ALARM);
  384. }