EasyOpenTherm.h
30.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
/*
* https://github.com/Jeroen88/EasyOpenTherm
* https://www.tindie.com/products/Metriot/OpenTherm-adapter/
*
* EasyOpenTherm is a library to communicate with OpenTherm compatible devices
* Copyright (C) 2022 Jeroen Döll <info@metriot.nl>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Primary: thermostat
* Secondary: boiler or HVAC
*/
#pragma once
#include <Arduino.h>
class OTDataLinkLayer; // Forward declaration
class OTPhysicalLayer; // Forward declaration
class OpenTherm {
public:
OpenTherm(uint8_t rxPin,
uint8_t txPin,
time_t timeoutMs = 900,
bool primary = true);
~OpenTherm();
bool status(uint8_t & secondaryFlags);
bool status(uint8_t primaryFlags,
uint8_t & secondaryFlags);
enum class READ_WRITE_DATA_ID; // Forward declaration of DATA-IDs that can be used to write the MSB (Most ignificant Byte) to the boiler and read the LSB from it.
enum class READ_DATA_ID; // Forward declaration of DATA-IDs that can be used to read values from the boiler
enum class WRITE_DATA_ID; // Forward declaration of DATA-IDs that can be used to write values to the boiler
enum class ERROR_CODES; // Forward declaration of ERROR_CODES, like timeouts, returned through the physical layer
bool read(READ_DATA_ID msgID,
uint16_t & value);
bool read(READ_DATA_ID msgID,
int16_t & value);
bool read(READ_DATA_ID msgID,
uint8_t & valueMSB,
uint8_t & valueLSB);
bool read(READ_DATA_ID msgID,
int8_t & valueMSB,
int8_t & valueLSB);
bool read(READ_DATA_ID msgID,
float & value);
bool write(WRITE_DATA_ID msgID,
uint16_t value);
bool write(WRITE_DATA_ID msgID,
uint8_t valueMSB,
uint8_t valueLSB);
bool write(WRITE_DATA_ID msgID,
float value);
bool readWrite(READ_WRITE_DATA_ID msgID,
uint8_t valueMSB,
uint8_t & valueLSB);
ERROR_CODES error();
enum class READ_WRITE_DATA_ID {
// Class 1 : Control and Status Information
STATUS = 0, // flag8, flag8 Mandatory; Primary status, secondary status
// Class 3 : Remote Commands
COMMAND_CODE = 4, // u8, u8 Command code / Response to command
// Incomplete information for all DATA-IDs below. If these DATA-IDs are R, W or R/W is unknown. Also the data type is unknown and deducted from the name. These DATA-IDs are not ordered by class
// Where applicable and available flags and masks are also defined below
// HVAC specific DATA-IDs (ventilation / heat recovery)
HVAC_STATUS = 70, // flag8, flag8 Primary status, secondary status
// Solar specific DATA-IDs
SOLAR_STATUS = 101, // flag8, flag8? MSB Primary Solar Storage Mode, LSB Secondary Solar Storage Mode
};
enum class READ_DATA_ID {
// Class 1 : Control and Status Information
FAULT_FLAGS = 5, // flag8, u8 Application-specific fault flags and OEM fault code
OEM_DIAGNOSTIC = 115, // u16 An OEM-specific diagnostic/service code
// Class 2 : Configuration Information
SECONDARY_CONFIGURATION = 3, // flag8, u8 Mandatory; Secondary Configuration Flags / MemberID Code of the secondary device
OPENTHERM_VERSION_SECONDARY = 125, // f8.8 The implemented version of the OpenTherm Protocol Specification in the secondary device
SECONDARY_PRODUCT_VERSION = 127, // u8, u8 The secondary device product version number and type as defined by the manufacturer
// Class 4 : Sensor and Informational Data
RELATIVE_MODULATION_LEVEL = 17, // f8.8 Mandatory; Percent modulation between min and max modulation levels. i.e. 0% = Minimum modulation level and 100% = Maximum modulation level (%)
CH_WATER_PRESSURE = 18, // f8.8 Water pressure of the boiler CH circuit (bar)
DHW_FLOW_RATE = 19, // f8.8 Water flow rate through the DHW circuit (l/min)
DAY_TIME = 20, // special, u8 Day of Week and Time of Day; special: bit 7,6,5 day of week (1=Monday, etc...., 0=no DoW info available); bit 4,3,2,1,0 hours, LSB is minutes
DATE = 21, // u8, u8 Calendar date: Month, Day of month
YEAR = 22, // u16 Calendar year; note : 1999-2099 will normally be sufficient
BOILER_WATER_TEMP = 25, // f8.8 Mandatory; Flow water temperature from boiler (°C)
DHW_TEMPERATURE = 26, // f8.8 Domestic hot water temperature (°C)
OUTSIDE_TEMPERATURE = 27, // f8.8 Outside air temperature (°C)
RETURN_WATER_TEMPERATURE = 28, // f8.8 Return water temperature to boiler (°C)
SOLAR_STORE_TEMPERATURE = 29, // f8.8 Solar storage temperature (°C)
SOLAR_COLLECTOR_TEMPERATURE = 30, // f8.8 Solar collector temperature (°C)
FLOW_TEMPERATURE_CH2 = 31, // f8.8 Flow water temperature of the second central heating circuit (°C)
DHW2_TEMPERATURE = 32, // f8.8 Domestic hot water temperature 2 (°C)
EXHAUST_TEMPERATURE = 33, // s16 Exhaust temperature (°C)
BURNER_STARTS = 116, // u16 Number of starts burner. Reset by writing zero is optional for the secondary device
CH_PUMP_STARTS = 117, // u16 Number of starts CH pump. Reset by writing zero is optional for the secondary device
DHW_PUMP_VALVE_STARTS = 118, // u16 Number of starts DHW pump/valve. Reset by writing zero is optional for the secondary device
DHW_BURNER_STARTS = 119, // u16 Number of starts burner in DHW mode. Reset by writing zero is optional for the secondary device
BURNER_OPERATION_HOURS = 120, // u16 Number of hours that burner is in operation (i.e. flame on). Reset by writing zero is optional for the secondary device
CH_PUMP_OPERATION_HOURS = 121, // u16 Number of hours that CH pump has been running. Reset by writing zero is optional for the secondary device
DHW_PUMP_VALVE_OPERATION_HOURS = 122, // u16 Number of hours that DHW pump has been running or DHW valve has been opened. Reset by writing zero is optional for the secondary device
DHW_BURNER_OPERATION_HOURS = 123, // u16 Number of hours that burner is in operation during DHW mode. Reset by writing zero is optional for the secondary device
// Class 5 : Pre-Defined Remote Boiler Parameters
REMOTE_PARAMETER = 6, // flag8, flag8 Remote boiler parameter transfer-enable flags, read/write flags
DHW_SETPOINT_BOUNDS = 48, // s8, s8 Upper bound for adjustment of DHW setp (°C), Lower bound for adjustment of DHW setp (°C)
CH_SETPOINT_BOUNDS = 49, // s8, s8 Upper bound for adjustment of maxCH setp (°C), Lower bound for adjustment of maxCH setp (°C)
OTC_CURVE_BOUNDS = 50, // s8, s8 Upper / lower bound
DHW_SETPOINT = 56, // f8.8 Domestic hot water temperature setpoint (Remote parameter 1) (°C)
MAX_CH_WATER_SETPOINT = 57, // f8.8 Maximum allowable CH water setpoint (Remote parameter 2) (°C)
OTC_CURVE_RATIO = 58, // f8.8 OTC heat curve ratio (Remote parameter 3)
// Class 6 : Transparent Secondary Parameters
NUMBER_OF_TSPS = 10, // u8, u8 Number of transparent-secondary-parameter supported by the secondary device, -Reserved-
TSP_COMMAND = 11, // u8, u8 Index number of following TSP, Value of the referenced TSP
// Class 7 : Fault History Data
FAULT_BUFFER_SIZE = 12, // u8, u8 The size of the fault history buffer, -Reserved-
FAULT_BUFFER_DATA = 13, // u8, u8 Index number of Fault Buffer entry, Value of the referenced Fault Buffer entry
// Class 8 : Control of Special Applications
MAX_BOILER_CAPACITY_MIN_MOD_LEV = 15, // u8, u8 MSB : max. boiler capacity (0..255kW), LSB : min. modulation level (0..100%) expressed as a percentage of the maximum capacity
CH_SETPOINT_OVERRIDE = 9, // f8.8 Remote override room setpoint (0 is no override, 1..30 is remote override room setpoint)
REMOTE_OVERRIDE_FUNCTION = 100, // flag8, u8 Bit 0: Manual change priority; bit 1: Program change priority, HSB -Reserved-
// Incomplete information for all DATA-IDs below. If these DATA-IDs are R, W or R/W is unknown. Also the data type is unknown and deducted from the name. These DATA-IDs are not ordered by class
// Where applicable and available flags and masks are also defined below
// Boiler specific DATA-IDs
BOILER_HEAT_EXCHANGER_TEMPERATURE = 34, // f8.8 Boiler heat exchanger temperature (°C)
BOILER_FAN_SPEED_SETPOINT_VALUE = 35, // ? Boiler fan speed Setpoint and actual value
ELECTRICAL_CURRENT_BURNER_FLAME = 36, // ? Electrical current through burner flame (μA)
// HVAC specific DATA-IDs (ventilation / heat recovery)
HVAC_RELATIVE_VENT_SETPOINT = 71, // f8.8 Relative ventilation position (0-100%)
HVAC_FAULT_FLAGS = 72, // flag8, u8 Application-specific fault flags and OEM fault code
HVAC_OEM_DIAGNOSTIC_CODE = 73, // u16 An OEM specific diagnostic/service code
HVAC_SECONDARY_CONFIGURATION = 74, // flag8, u8 Secondary Configuration Flags / MemberID Code of the secondary device
HVAC_OPENTHERM_VERSION_SECONDARY= 75, // f8.8 The implemented version of the OpenTherm Protocol Specification in the secondary device
HVAC_SECONDARY_PRODUCT_VERSION = 76, // u8, u8 The secondary device product version number and type as defined by the manufacturer
HVAC_RELATIVE_VENTILATION = 77, // f8.8 Relative ventilation (0-100%)
HVAC_RELATIVE_HUMIDITY_EXHAUST = 78, // f8.8 Relative humidity exhaust air (0-100%)
HVAC_CO2_LEVEL_EXHAUST_AIR = 79, // ? CO2 level exhaust air (0-2000 ppm)
HVAC_SUPPLY_INLET_TEMPERATURE = 80, // f8.8 Supply inlet temperature (*C)
HVAC_SUPPLY_OUTLET_TEMPERATURE = 81, // f8.8 Supply outlet temperature (*C)
HVAC_EXHAUST_INLET_TEMPERATURE = 82, // f8.8 Exhaust inlet temperature (*C)
HVAC_EXHAUST_OUTLET_TEMPERATURE = 83, // f8.8 Exhaust outlet temperature (*C)
HVAC_EXHAUST_FAN_SPEED = 84, // u16? Exhaust fan speed (rpm)
HVAC_SUPPLY_FAN_SPEED = 85, // u16? Supply fan speed (rpm)
HVAC_REMOTE_PARAMETER = 86, // u8, u8? MSB Remote parameter transfer enable nominal ventilation value, LSB Remote parameter read/write nominal ventilation value
HVAC_NOMINAL_RELATIVE_VENTILATION = 87, // f8.8 Nominal relative value for ventilation (0-100%)
HVAC_NUMBER_OF_TSPS = 88, // u8, u8? Number of transparent-secondary-parameter supported by the secondary device, -Reserved-
HVAC_TSP_COMMAND = 89, // u8, u8 Index number of following TSP, Value of the referenced TSP
HVAC_FAULT_BUFFER_SIZE = 90, // u8, u8? The size of the fault history buffer
HVAC_FAULT_BUFFER_DATA = 91, // u8, u8 Index number of Fault Buffer entry, Value of the referenced Fault Buffer entry
HVAC_RF_STRENGTH_BATTERY_LEVEL = 98, // u8, u8? For a specific RF sensor RF strength and battery level
HVAC_OPERATING_MODE = 99, // ? Operating mode HC1, HC2 / Operating mode DHW
// Solar specific DATA-IDs
SOLAR_FAULT_FLAGS = 102, // flag8, u8 Application-specific fault flags and OEM fault code
SOLAR_SECONDARY_CONFIGURATION = 103, // flag8, u8 Secondary Configuration Flags / MemberID Code of the secondary device
SOLAR_SECONDARY_PRODUCT_VERSION = 104, // u8, u8 The secondary device product version number and type as defined by the manufacturer
SOLAR_NUMBER_OF_TSPS = 105, // u8, u8? Number of transparent-secondary-parameter supported by the secondary device, -Reserved-
SOLAR_TSP_COMMAND = 106, // u8, u8 Index number of following TSP, Value of the referenced TSP
SOLAR_FAULT_BUFFER_SIZE = 107, // u8, u8? The size of the fault history buffer
SOLAR_FAULT_BUFFER_DATA = 108, // u8, u8 Index number of Fault Buffer entry, Value of the referenced Fault Buffer entry
// Electricity specific DATA-IDs
PRODUCER_STARTS = 109, // u16 Electricity producer starts
PRODUCER_HOURS = 110, // u16 Electricity producer hours
PRODUCTION = 111, // u16 Electricity production
CUMULATIVE_PRODUCTION = 112, // u16 Electricity cumulative production
// Boiler specific DATA-IDs
UNSUCCESSFUL_BURNER_STARTS = 113, // u16 Number of unsuccessful burner starts
FLAME_SIGNAL_TOO_LOW = 114, // u16 Number of times flame signal was too low
};
enum class WRITE_DATA_ID {
// Class 1 : Control and Status Information
CONTROL_SETPOINT_CH = 1, // f8.8 Mandatory; Control setpoint (CH water temperature setpoint) (°C)
CONTROL_SETPOINT_CH2 = 8, // f8.8 Control setpoint for 2nd CH circuit (°C)
// Class 2 : Configuration Information
PRIMARY_CONFIGURATION = 2, // flag8, u8 Primary Configuration Flags / MemberID Code of the primary device
OPENTHERM_VERSION_PRIMARY = 124, // f8.8 The implemented version of the OpenTherm Protocol Specification in the primary device
PRIMARY_PRODUCT_VERSION = 126, // u8, u8 The primary device product version number and type as defined by the manufacturer
// Class 4 : Sensor and Informational Data
ROOM_SETPOINT = 16, // f8.8 Current room temperature setpoint (°C)
DAY_TIME = 20, // special, u8 Day of Week and Time of Day; special: bit 7,6,5 day of week (1=Monday, etc...., 0=no DoW info available); bit 4,3,2,1,0 hours, LSB is minutes
DATE = 21, // u8, u8 Calendar date: Month, Day of month
YEAR = 22, // u16 Calendar year; note : 1999-2099 will normally be sufficient
ROOM_SETPOINT_CH2 = 23, // f8.8 Current room Setpoint for 2nd CH circuit (°C)
ROOM_TEMPERATURE = 24, // f8.8 Current sensed room temperature (°C)
BURNER_STARTS = 116, // u16 Number of starts burner. Reset by writing zero is optional for the secondary device
CH_PUMP_STARTS = 117, // u16 Number of starts CH pump. Reset by writing zero is optional for the secondary device
DHW_PUMP_VALVE_STARTS = 118, // u16 Number of starts DHW pump/valve. Reset by writing zero is optional for the secondary device
DHW_BURNER_STARTS = 119, // u16 Number of starts burner in DHW mode. Reset by writing zero is optional for the secondary device
BURNER_OPERATION_HOURS = 120, // u16 Number of hours that burner is in operation (i.e. flame on). Reset by writing zero is optional for the secondary device
CH_PUMP_OPERATION_HOURS = 121, // u16 Number of hours that CH pump has been running. Reset by writing zero is optional for the secondary device
DHW_PUMP_VALVE_OPERATION_HOURS = 122, // u16 Number of hours that DHW pump has been running or DHW valve has been opened. Reset by writing zero is optional for the secondary device
DHW_BURNER_OPERATION_HOURS = 123, // u16 Number of hours that burner is in operation during DHW mode. Reset by writing zero is optional for the secondary device
// Class 5 : Pre-Defined Remote Boiler Parameters
DHW_SETPOINT = 56, // f8.8 Domestic hot water temperature setpoint (Remote parameter 1) (°C)
MAX_CH_WATER_SETPOINT = 57, // f8.8 Maximum allowable CH water setpoint (Remote parameter 2) (°C)
OTC_CURVE_RATIO = 58, // f8.8 OTC heat curve ratio (Remote parameter 3) (°C)
// Class 6 : Transparent Secondary Parameters
TSP_COMMAND = 11, // u8, u8 Index number of following TSP, Value of the referenced TSP
// Class 8 : Control of Special Applications
COOLING_CONTROL = 7, // f8.8 Signal for cooling plant (%)
MAX_MODULATION_LEVEL = 14, // f8.8 Mandatory; Maximum relative boiler modulation level setting for sequencer and off-low & pump control applications (%)
// Incomplete information for DATA-IDs below. If these DATA-IDs are R, W or R/W is unknown. Also the data type is unknown and deducted from the name
// Boiler DATA-ID
ROOM_TEMPERATURE_CH2 = 37, // f8.8 Room temperature for second CH unit(°C)
};
// Flags used by ::status(primaryFlags, secondaryFlags); The flags starting with PRIMARY_ are sent from the thermostat to the boiler and the flgas starting with SECONDARY_ are received
// from the boiler
enum class STATUS_FLAGS {
// Primary device is MSB
PRIMARY_CH_ENABLE = (0b00000001), // CH is Central Heating
PRIMARY_DHW_ENABLE = (0b00000010), // DHW is Domestic Hot Water
PRIMARY_COOLING_ENABLE = (0b00000100),
PRIMARY_OTC_ENABLE = (0b00001000), // OTC is Outside Temperature Compensation
PRIMARY_CH2_ENABLE = (0b00010000),
// Secondary device is LSB
SECONDARY_FAULT_INDICATION = (0b00000001),
SECONDARY_CH_MODE = (0b00000010),
SECONDARY_DHW_MODE = (0b00000100),
SECONDARY_FLAME_STATUS = (0b00001000),
SECONDARY_COOLING_STATUS = (0b00010000),
SECONDARY_CH2_MODE = (0b00100000),
SECONDARY_DIAGNOSTIC_IND = (0b01000000),
};
// Configuration flags returned by calling ::read(OpenTherm::READ_DATA_ID::SECONDARY_CONFIGURATION, configurationFlags, memberID);
enum class CONFIGURATION_FLAGS {
SECONDARY_DHW_PRESENT = (0b00000001),
SECONDARY_CONTROL_TYPE = (0b00000010),
SECONDARY_COOLING = (0b00000100),
SECONDARY_DHW = (0b00001000),
SECONDARY_LOW_OFF_PUMP_CTRL = (0b00010000),
SECONDARY_CH2_PRESENT = (0b00100000),
};
// A few known member IDs returned by calling ::read(OpenTherm::READ_DATA_ID::SECONDARY_CONFIGURATION, configurationFlags, memberID);
enum MEMBER_IDS: uint8_t { // May be extended with other manufacturer OpenTherm member IDs. Maybe incorrect
AWB = 2,
BRINK = 2,
ATAG = 4,
BROTJE = 4,
ELCO = 4,
GEMINOX = 4,
ITHO_DAALDEROP = 5,
IDEAL = 6,
BOSCH = 8,
HOVAL = 8,
FERROLI = 9,
REMEHA = 11,
DE_DIETRICH = 11,
UNICAL = 16,
BULEX = 24,
VAILLANT = 24,
BAXI = 27,
DAALDEROP = 29,
VIESSMANN = 33,
NEFIT = 131,
INTERGAS = 173,
};
// Fault flags returned by calling ::read(OpenTherm::READ_DATA_ID::FAULT_FLAGS, faultFlags, OEMFaultCode);
enum class FAULT_FLAGS {
SERVICE_REQUEST = (0b00000001),
LOCKOUT_RESET = (0b00000010),
LOW_WATER_PRESS = (0b00000100),
GAS_FLAME = (0b00001000),
AIR_PRESS = (0b00010000),
WATER_OVER_TEMP = (0b00100000),
};
// Remote parameter flags returned by calling ::read(OpenTherm::READ_DATA_ID::REMOTE_PARAMETER, remoteParameterTEFlags, remoteParameterRWFlags);
enum class REMOTE_PARAMETER_FLAGS {
TRANSFER_ENABLE_DHW_SETPOINT = (0b00000001),
TRANSFER_ENABLE_MAX_CH_SETPOINT = (0b00000010),
READ_WRITE_DHW_SETPOINT = (0b00000001),
READ_WRITE_MAX_CH_SETPOINT = (0b00000010),
};
// Remote parameter flags returned by calling ::read(OpenTherm::READ_DATA_ID::REMOTE_OVERRIDE_FUNCTION, reserved, remoteOverrideFlags);
enum class REMOTE_OVERRIDE_FLAGS {
MANUAL_CHANGE_PRIORITY = (0b00000001),
REMOTE_CHANGE_PRIORITY = (0b00000010),
};
// Remote parameter flags returned by calling ::readWrite(OpenTherm::READ_WRITE_DATA_ID::COMMAND_CODE, remoteCommand, cmdResponseCode);
enum class REMOTE_COMMANDS {
BLOR = (1), // Boiler Lock-out Reset command
CHWF = (2), // CH water filling
};
// Flags used by ::readWrite(OpenTherm::READ_WRITE_DATA_ID::HVAC_STATUS, primaryFlags, secondaryFlags); The flags starting with PRIMARY_ are sent from the thermostat to the HVAC
// and the flags starting with SECONDARY_ are received from the HVAC. This is comparable to the ::status() call for a boiler.
enum class HVAC_STATUS_FLAGS {
// Primary device is MSB
PRIMARY_VENTILATION_ENABLE = (0b00000001),
PRIMARY_BYPASS_POSTION = (0b00000010),
PRIMARY_BYPASS_MODE = (0b00000100),
PRIMARY_FREE_VENTILATION_MODE = (0b00001000),
// Secondary device is LSB
SECONDARY_FAULT_INDICATION = (0b00000001),
SECONDARY_VENTILATION_MODE = (0b00000010),
SECONDARY_BYPASS_STATUS = (0b00000100),
SECONDARY_BYPASS_AUTOMATIC_STATUS= (0b00001000),
SECONDARY_FREE_VENTILATION_MODE = (0b00010000),
SECONDARY_DIAGNOSTIC_IND = (0b00100000),
};
enum class SOLAR_STATUS_FLAGS {
// Priamry device is MSB
PRIMARY_MODE = (0b00000111),
// Secondary device is LSB
SECONDARY_FAULT_INDICATION = (0b00000001),
SECONDARY_MODE = (0b00001110),
SECONDARY_STATUS = (0b00110000),
};
enum class SOLAR_MODE_FLAGS_AND_MASKS {
SYSTEM_TYPE = (0b00000001),
BYPASS = (0b00000010),
SPEED_CONTROL = (0b00000100),
};
enum class SOLAR_SECONDARY_CONFIGURATION_FLAGS {
SECONDARY_SYSTEM_TYPE = (0b00000001),
};
// ::error(); returns the result of the latest call to ::read();, ::write(); or ::readWrite();
enum class ERROR_CODES {
OK, // Everything is OK
UNKNOWN_DATA_ID, // The DATA-ID sent by the primary to the secondary is not supported by the secondary
INVALID_DATA, // The DATA-ID sent by the primary to the secondary is supported but the sent value is out of bounds
SEND_TIMEOUT, // The primary could not send within timeout period (should not occur if timeouts are reasonable)
RECEIVE_TIMEOUT, // The secondary did not respond within timeout period
PARITY_ERROR, // The secondary's response had a parity error
UNKNOWN_ERROR, // Unknown error (should not occur)
};
private:
bool _execute(OTDataLinkLayer & data);
OTPhysicalLayer * _OTP;
uint8_t _rxPin;
uint8_t _txPin;
time_t _timeoutMs;
bool _primary;
ERROR_CODES _lastError;
};
class OTDataLinkLayer {
public:
enum class MSG_TYPE; // Forward declaration
OTDataLinkLayer();
OTDataLinkLayer(uint32_t frame);
void set(uint32_t frame);
void set(MSG_TYPE msgType,
uint8_t dataID,
uint16_t value);
void set(MSG_TYPE msgType,
uint8_t dataID,
uint8_t valueMSB,
uint8_t valueLSB);
bool parity();
MSG_TYPE type();
uint8_t dataID();
uint16_t value();
uint8_t valueMSB();
uint8_t valueLSB();
uint32_t frame();
bool isValid();
bool dataInvalid();
bool unknownDataID();
enum class MSG_TYPE {
PRIMARY_TO_SECONDARY_READ_DATA = (0b0000000UL << 24), // value >> 28 := 0
PRIMARY_TO_SECONDARY_WRITE_DATA = (0b0010000UL << 24), // value >> 28 := 1
PRIMARY_TO_SECONDARY_INVALID_DATA = (0b0100000UL << 24), // value >> 28 := 2
PRIMARY_TO_SECONDARY_RESERVED = (0b0110000UL << 24), // value >> 28 := 3
SECONDARY_TO_PRIMARY_READ_ACK = (0b1000000UL << 24), // value >> 28 := 4
SECONDARY_TO_PRIMARY_WRITE_ACK = (0b1010000UL << 24), // value >> 28 := 5
SECONDARY_TO_PRIMARY_DATA_INVALID = (0b1100000UL << 24), // value >> 28 := 6
SECONDARY_TO_PRIMARY_UNKNOWN_DATA_ID = (0b1110000UL << 24) // value >> 28 := 7
};
private:
uint32_t _frame;
bool _parity(uint32_t frame);
};
class OTPhysicalLayer {
public:
OTPhysicalLayer(uint8_t rxPin,
uint8_t txPin,
bool primary);
~OTPhysicalLayer();
bool send(uint32_t frame);
bool receive(uint32_t & frame);
void reset();
#if defined(ESP32)
void IRAM_ATTR handleInterrupt();
#elif defined(ESP8266)
void ICACHE_RAM_ATTR handleInterrupt();
#else
void handleInterrupt();
#endif
private:
void sendBit(uint8_t val);
volatile uint32_t _frame;
uint32_t _lastSentTimestampMs;
volatile uint32_t _lastReceivedTimestampMs;
uint8_t _rxPin;
uint8_t _txPin;
bool _primary;
enum class STATE {
INVALID,
READY,
WAITING,
START_BIT,
RECEIVING,
};
volatile STATE _state = STATE::INVALID;
};