2020-10-25 20:35:34 +01:00
|
|
|
|
/*
|
|
|
|
|
***************************************************************************
|
2020-10-25 22:56:18 +01:00
|
|
|
|
** Program : OTGWStuff
|
2020-12-12 01:37:32 +01:00
|
|
|
|
** Version : v0.4.0
|
2020-10-25 20:35:34 +01:00
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2020 Robert van den Breemen
|
|
|
|
|
** Borrowed from OpenTherm library from:
|
|
|
|
|
** https://github.com/jpraus/arduino-opentherm
|
|
|
|
|
**
|
|
|
|
|
** TERMS OF USE: MIT License. See bottom of file.
|
|
|
|
|
***************************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define EXT_WD_I2C_ADDRESS 0x26
|
|
|
|
|
#define PIN_I2C_SDA 4
|
|
|
|
|
#define PIN_I2C_SCL 5
|
|
|
|
|
|
|
|
|
|
/* --- PRINTF_BYTE_TO_BINARY macro's --- */
|
|
|
|
|
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
|
|
|
|
|
#define PRINTF_BYTE_TO_BINARY_INT8(i) \
|
|
|
|
|
(((i) & 0x80ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x40ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x20ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x10ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x08ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x04ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x02ll) ? '1' : '0'), \
|
|
|
|
|
(((i) & 0x01ll) ? '1' : '0')
|
|
|
|
|
|
|
|
|
|
#define PRINTF_BINARY_PATTERN_INT16 \
|
|
|
|
|
PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_PATTERN_INT8
|
|
|
|
|
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
|
|
|
|
|
PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i)
|
|
|
|
|
#define PRINTF_BINARY_PATTERN_INT32 \
|
|
|
|
|
PRINTF_BINARY_PATTERN_INT16 PRINTF_BINARY_PATTERN_INT16
|
|
|
|
|
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
|
|
|
|
|
PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
|
|
|
|
|
#define PRINTF_BINARY_PATTERN_INT64 \
|
|
|
|
|
PRINTF_BINARY_PATTERN_INT32 PRINTF_BINARY_PATTERN_INT32
|
|
|
|
|
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
|
|
|
|
|
PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
|
|
|
|
|
/* --- Endf of macro's --- */
|
|
|
|
|
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//some variable's
|
2020-11-02 08:09:26 +01:00
|
|
|
|
OpenthermData OTdata;
|
|
|
|
|
DECLARE_TIMER_MS(timerWD, 1000, CATCH_UP_MISSED_TICKS);
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
|
|
|
|
//===================[ Watchdog OTGW ]===============================
|
|
|
|
|
String initWatchDog() {
|
|
|
|
|
// configure hardware pins according to eeprom settings.
|
2020-11-02 08:09:26 +01:00
|
|
|
|
DebugTln(F("INIT : I2C"));
|
|
|
|
|
Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); //configure the I2C bus
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//=============================================
|
|
|
|
|
// I2C Watchdog boot status check
|
|
|
|
|
String ReasonReset = "";
|
|
|
|
|
|
|
|
|
|
delay(500);
|
|
|
|
|
Wire.beginTransmission(EXT_WD_I2C_ADDRESS); // OTGW WD address
|
|
|
|
|
Wire.write(0x83); // command to set pointer
|
|
|
|
|
Wire.write(17); // pointer value to status byte
|
|
|
|
|
Wire.endTransmission();
|
|
|
|
|
|
|
|
|
|
Wire.requestFrom((uint8_t)EXT_WD_I2C_ADDRESS, (uint8_t)1);
|
|
|
|
|
if (Wire.available())
|
|
|
|
|
{
|
|
|
|
|
byte status = Wire.read();
|
|
|
|
|
if (status & 0x1)
|
|
|
|
|
{
|
|
|
|
|
DebugTln(F("INIT : Reset by WD!"));
|
|
|
|
|
ReasonReset = "Reset by External WD";
|
|
|
|
|
//lastReset = BOOT_CAUSE_EXT_WD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ReasonReset;
|
|
|
|
|
//===========================================
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//===[ Feed the WatchDog before it bites! (1x per second) ]===
|
|
|
|
|
void feedWatchDog() {
|
|
|
|
|
//make sure to do this at least once a second
|
|
|
|
|
//==== feed the WD over I2C ====
|
|
|
|
|
// Address: 0x26
|
|
|
|
|
// I2C Watchdog feed
|
2020-11-02 08:09:26 +01:00
|
|
|
|
|
|
|
|
|
if DUE(timerWD)
|
|
|
|
|
{
|
|
|
|
|
Wire.beginTransmission(EXT_WD_I2C_ADDRESS); //Nodoshop design uses the hardware WD on I2C, address 0x26
|
|
|
|
|
Wire.write(0xA5); //Feed the dog, before it bites.
|
|
|
|
|
Wire.endTransmission(); //That's all there is...
|
|
|
|
|
}
|
|
|
|
|
yield();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//==== feed the WD over I2C ====
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-09 00:05:06 +01:00
|
|
|
|
//===================[ END Watchdog OTGW ]===============================
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
|
|
|
|
//=======================================================================
|
|
|
|
|
float OpenthermData::f88() {
|
|
|
|
|
float value = (int8_t) valueHB;
|
|
|
|
|
return value + (float)valueLB / 256.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OpenthermData::f88(float value) {
|
|
|
|
|
if (value >= 0) {
|
|
|
|
|
valueHB = (byte) value;
|
|
|
|
|
float fraction = (value - valueHB);
|
|
|
|
|
valueLB = fraction * 256.0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
valueHB = (byte)(value - 1);
|
|
|
|
|
float fraction = (value - valueHB - 1);
|
|
|
|
|
valueLB = fraction * 256.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t OpenthermData::u16() {
|
|
|
|
|
uint16_t value = valueHB;
|
|
|
|
|
return (value << 8) | valueLB;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OpenthermData::u16(uint16_t value) {
|
|
|
|
|
valueLB = value & 0xFF;
|
|
|
|
|
valueHB = (value >> 8) & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int16_t OpenthermData::s16() {
|
|
|
|
|
int16_t value = valueHB;
|
|
|
|
|
return (value << 8) | valueLB;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OpenthermData::s16(int16_t value) {
|
|
|
|
|
valueLB = value & 0xFF;
|
|
|
|
|
valueHB = (value >> 8) & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//parsing helpers
|
|
|
|
|
const char *statusToString(OpenThermResponseStatus status)
|
|
|
|
|
{
|
|
|
|
|
switch (status) {
|
|
|
|
|
case OT_NONE: return "NONE";
|
2020-10-26 00:00:06 +01:00
|
|
|
|
case OT_SUCCESS: return "SUCCESS";
|
|
|
|
|
case OT_INVALID: return "INVALID";
|
|
|
|
|
case OT_TIMEOUT: return "TIMEOUT";
|
|
|
|
|
default: return "UNKNOWN";
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *messageTypeToString(OpenThermMessageType message_type)
|
|
|
|
|
{
|
|
|
|
|
switch (message_type) {
|
2020-10-26 00:00:06 +01:00
|
|
|
|
case OT_READ_DATA: return "READ_DATA";
|
|
|
|
|
case OT_WRITE_DATA: return "WRITE_DATA";
|
|
|
|
|
case OT_INVALID_DATA: return "INVALID_DATA";
|
|
|
|
|
case OT_RESERVED: return "RESERVED";
|
|
|
|
|
case OT_READ_ACK: return "READ_ACK";
|
|
|
|
|
case OT_WRITE_ACK: return "WRITE_ACK";
|
|
|
|
|
case OT_DATA_INVALID: return "DATA_INVALID";
|
|
|
|
|
case OT_UNKNOWN_DATA_ID: return "UNKNOWN_DATA_ID";
|
|
|
|
|
default: return "UNKNOWN";
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *messageIDToString(OpenThermMessageID message_id){
|
2020-12-12 00:20:31 +01:00
|
|
|
|
if (message_id<=127) {
|
|
|
|
|
return OTmap[message_id].label;
|
|
|
|
|
} else return "Undefined";}
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
|
|
|
|
OpenThermMessageType getMessageType(unsigned long message)
|
|
|
|
|
{
|
|
|
|
|
OpenThermMessageType msg_type = static_cast<OpenThermMessageType>((message >> 28) & 7);
|
|
|
|
|
return msg_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OpenThermMessageID getDataID(unsigned long frame)
|
|
|
|
|
{
|
|
|
|
|
return (OpenThermMessageID)((frame >> 16) & 0xFF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//parsing responses
|
|
|
|
|
|
|
|
|
|
bool isFault(unsigned long response) {
|
|
|
|
|
return response & 0x1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isCentralHeatingActive(unsigned long response) {
|
|
|
|
|
return response & 0x2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isHotWaterActive(unsigned long response) {
|
|
|
|
|
return response & 0x4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isFlameOn(unsigned long response) {
|
|
|
|
|
return response & 0x8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isCoolingActive(unsigned long response) {
|
|
|
|
|
return response & 0x10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isDiagnostic(unsigned long response) {
|
|
|
|
|
return response & 0x40;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 21:13:09 +01:00
|
|
|
|
const char *byte_to_binary(int x)
|
|
|
|
|
{
|
|
|
|
|
static char b[9];
|
|
|
|
|
b[0] = '\0';
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
2020-11-06 21:13:09 +01:00
|
|
|
|
int z;
|
|
|
|
|
for (z = 128; z > 0; z >>= 1) {
|
|
|
|
|
strcat(b, ((x & z) == z) ? "1" : "0");
|
|
|
|
|
}
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
2020-11-06 21:13:09 +01:00
|
|
|
|
return b;
|
|
|
|
|
}
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
float print_f88()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
|
|
|
|
//function to print data
|
2020-12-12 00:20:31 +01:00
|
|
|
|
float _value = round(OTdata.f88()*100.0) / 100.0; // round float 2 digits, like this: x.xx
|
|
|
|
|
// Debugf("%-37s = %3.2f %s\r\n", OTmap[OTdata.id].label, _value , OTmap[OTdata.id].unit);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
char _msg[15] {0};
|
2020-12-12 00:20:31 +01:00
|
|
|
|
dtostrf(_value, 3, 2, _msg);
|
|
|
|
|
Debugf("%-37s = %s %s\r\n", OTmap[OTdata.id].label, _msg , OTmap[OTdata.id].unit);
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//SendMQTT
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return _value;
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
int16_t print_s16()
|
|
|
|
|
{
|
|
|
|
|
int16_t _value = OTdata.s16();
|
|
|
|
|
// Debugf("%-37s = %5d %s\r\n", OTmap[OTdata.id].label, _value, OTmap[OTdata.id].unit);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _msg[15] {0};
|
2020-12-12 00:20:31 +01:00
|
|
|
|
itoa(_value, _msg, 10);
|
|
|
|
|
Debugf("%-37s = %s %s\r\n", OTmap[OTdata.id].label, _msg, OTmap[OTdata.id].unit);
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//SendMQTT
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return _value;
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_s8s8()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = %3d / %3d %s\r\n", OTmap[OTdata.id].label, (int8_t)OTdata.valueHB, (int8_t)OTdata.valueLB, OTmap[OTdata.id].unit);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _msg[15] {0};
|
|
|
|
|
char _topic[50] {0};
|
|
|
|
|
itoa((int8_t)OTdata.valueHB, _msg, 10);
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_value_hb", sizeof(_topic));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = %s %s\r\n", OTmap[OTdata.id].label, _msg, OTmap[OTdata.id].unit);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, _msg);
|
|
|
|
|
//Build string for MQTT
|
|
|
|
|
itoa((int8_t)OTdata.valueLB, _msg, 10);
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_value_lb", sizeof(_topic));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = %s %s\r\n", OTmap[OTdata.id].label, _msg, OTmap[OTdata.id].unit);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_u16()
|
|
|
|
|
{
|
|
|
|
|
uint16_t _value = OTdata.u16();
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _msg[15] {0};
|
2020-12-12 00:20:31 +01:00
|
|
|
|
utoa(_value, _msg, 10);
|
|
|
|
|
Debugf("%-37s = %s %s\r\n", OTmap[OTdata.id].label, _msg, OTmap[OTdata.id].unit);
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//SendMQTT
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return _value;
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_status()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
2020-11-06 21:13:09 +01:00
|
|
|
|
char _flag8_master[8] {0};
|
|
|
|
|
char _flag8_slave[8] {0};
|
|
|
|
|
//bit: [clear/0, set/1]
|
2020-10-25 20:35:34 +01:00
|
|
|
|
// 0: CH enable [ CH is disabled, CH is enabled]
|
|
|
|
|
// 1: DHW enable [ DHW is disabled, DHW is enabled]
|
|
|
|
|
// 2: Cooling enable [ Cooling is disabled, Cooling is enabled]]
|
|
|
|
|
// 3: OTC active [OTC not active, OTC is active]
|
|
|
|
|
// 4: CH2 enable [CH2 is disabled, CH2 is enabled]
|
|
|
|
|
// 5: reserved
|
|
|
|
|
// 6: reserved
|
|
|
|
|
// 7: reserved
|
2020-11-03 01:28:05 +01:00
|
|
|
|
_flag8_master[0] = (((OTdata.valueHB) & 0x01) ? 'C' : '-');
|
|
|
|
|
_flag8_master[1] = (((OTdata.valueHB) & 0x02) ? 'D' : '-');
|
|
|
|
|
_flag8_master[2] = (((OTdata.valueHB) & 0x04) ? 'C' : '-');
|
|
|
|
|
_flag8_master[3] = (((OTdata.valueHB) & 0x08) ? 'O' : '-');
|
|
|
|
|
_flag8_master[4] = (((OTdata.valueHB) & 0x10) ? '2' : '-');
|
|
|
|
|
_flag8_master[5] = (((OTdata.valueHB) & 0x20) ? '.' : '-');
|
|
|
|
|
_flag8_master[6] = (((OTdata.valueHB) & 0x40) ? '.' : '-');
|
|
|
|
|
_flag8_master[7] = (((OTdata.valueHB) & 0x80) ? '.' : '-');
|
2020-11-06 21:13:09 +01:00
|
|
|
|
_flag8_master[8] = '\0';
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = M[%s] \r\n", OTmap[OTdata.id].label, _flag8_master);
|
2020-11-06 21:13:09 +01:00
|
|
|
|
//Master Status
|
2020-11-06 21:58:29 +01:00
|
|
|
|
sendMQTTData("status_master", _flag8_master);
|
2020-11-06 21:13:09 +01:00
|
|
|
|
sendMQTTData("ch_enable", (((OTdata.valueHB) & 0x01) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("dhw_enable", (((OTdata.valueHB) & 0x02) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("cooling_enable", (((OTdata.valueHB) & 0x04) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("otc_active", (((OTdata.valueHB) & 0x08) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("ch2_enable", (((OTdata.valueHB) & 0x10) ? "ON" : "OFF"));
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
2020-11-06 21:13:09 +01:00
|
|
|
|
//Slave
|
2020-10-25 20:35:34 +01:00
|
|
|
|
// 0: fault indication [ no fault, fault ]
|
|
|
|
|
// 1: CH mode [CH not active, CH active]
|
|
|
|
|
// 2: DHW mode [ DHW not active, DHW active]
|
|
|
|
|
// 3: Flame status [ flame off, flame on ]
|
|
|
|
|
// 4: Cooling status [ cooling mode not active, cooling mode active ]
|
|
|
|
|
// 5: CH2 mode [CH2 not active, CH2 active]
|
|
|
|
|
// 6: diagnostic indication [no diagnostics, diagnostic event]
|
|
|
|
|
// 7: reserved
|
2020-11-03 01:28:05 +01:00
|
|
|
|
_flag8_slave[0] = (((OTdata.valueLB) & 0x01) ? 'E' : '-');
|
|
|
|
|
_flag8_slave[1] = (((OTdata.valueLB) & 0x02) ? 'C' : '-');
|
|
|
|
|
_flag8_slave[2] = (((OTdata.valueLB) & 0x04) ? 'W' : '-');
|
|
|
|
|
_flag8_slave[3] = (((OTdata.valueLB) & 0x08) ? 'F' : '-');
|
|
|
|
|
_flag8_slave[4] = (((OTdata.valueLB) & 0x10) ? 'C' : '-');
|
|
|
|
|
_flag8_slave[5] = (((OTdata.valueLB) & 0x20) ? '2' : '-');
|
|
|
|
|
_flag8_slave[6] = (((OTdata.valueLB) & 0x40) ? 'D' : '-');
|
|
|
|
|
_flag8_slave[7] = (((OTdata.valueLB) & 0x80) ? '.' : '-');
|
2020-11-06 21:13:09 +01:00
|
|
|
|
_flag8_slave[8] = '\0';
|
2020-11-03 01:28:05 +01:00
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
DebugTf("%-37s = S[%s] \r\n", OTmap[OTdata.id].label, _flag8_slave);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
|
2020-11-06 21:58:29 +01:00
|
|
|
|
//Slave Status
|
|
|
|
|
sendMQTTData("status_slave", _flag8_slave);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData("fault", (((OTdata.valueLB) & 0x01) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("centralheating", (((OTdata.valueLB) & 0x02) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("domestichotwater", (((OTdata.valueLB) & 0x04) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("flame", (((OTdata.valueLB) & 0x08) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("cooling", (((OTdata.valueLB) & 0x10) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("centralheating2", (((OTdata.valueLB) & 0x20) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("diagnostic_indicator", (((OTdata.valueLB) & 0x40) ? "ON" : "OFF"));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_ASFflags()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = M[%s] OEM fault code [%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueHB), OTdata.valueLB);
|
2020-11-06 21:13:09 +01:00
|
|
|
|
//Build string for MQTT
|
2020-11-06 21:58:29 +01:00
|
|
|
|
char _msg[15] {0};
|
2020-11-06 21:13:09 +01:00
|
|
|
|
//Application Specific Fault
|
2020-11-06 21:58:29 +01:00
|
|
|
|
sendMQTTData("ASF_flags", byte_to_binary(OTdata.valueHB));
|
2020-11-06 21:13:09 +01:00
|
|
|
|
//OEM fault code
|
2020-11-06 21:58:29 +01:00
|
|
|
|
sendMQTTData("ASF_oemfaultcode", _msg);
|
2020-11-06 21:13:09 +01:00
|
|
|
|
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//bit: [clear/0, set/1]
|
2020-11-06 21:13:09 +01:00
|
|
|
|
//bit: [clear/0, set/1]
|
2020-10-25 20:35:34 +01:00
|
|
|
|
//0: Service request [service not req’d, service required]
|
|
|
|
|
//1: Lockout-reset [ remote reset disabled, rr enabled]
|
|
|
|
|
//2: Low water press [ no WP fault, water pressure fault]
|
|
|
|
|
//3: Gas/flame fault [ no G/F fault, gas/flame fault ]
|
|
|
|
|
//4: Air press fault [ no AP fault, air pressure fault ]
|
|
|
|
|
//5: Water over-temp[ no OvT fault, over-temperat. Fault]
|
|
|
|
|
//6: reserved
|
|
|
|
|
//7: reserved
|
2020-11-06 21:13:09 +01:00
|
|
|
|
sendMQTTData("service_request", (((OTdata.valueHB) & 0x01) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("lockout_reset", (((OTdata.valueHB) & 0x02) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("low_water_pressure", (((OTdata.valueHB) & 0x04) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("gas_flame_fault", (((OTdata.valueHB) & 0x08) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("air_pressure_fault", (((OTdata.valueHB) & 0x10) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("water_over-temperature",(((OTdata.valueHB) & 0x20) ? "ON" : "OFF"));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-11-06 21:13:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_slavememberid()
|
2020-11-06 21:13:09 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = Slave Config[%s] MemberID code [%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueHB), OTdata.valueLB);
|
2020-11-06 21:58:29 +01:00
|
|
|
|
//Build string for SendMQTT
|
|
|
|
|
sendMQTTData("slave_configuration", byte_to_binary(OTdata.valueHB));
|
2020-11-06 21:13:09 +01:00
|
|
|
|
char _msg[15] {0};
|
|
|
|
|
utoa(OTdata.valueLB, _msg, 10);
|
2020-11-06 21:58:29 +01:00
|
|
|
|
sendMQTTData("slave_memberid_code", _msg);
|
2020-11-06 21:13:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// bit: description [ clear/0, set/1]
|
|
|
|
|
// 0: DHW present [ dhw not present, dhw is present ]
|
|
|
|
|
// 1: Control type [ modulating, on/off ]
|
|
|
|
|
// 2: Cooling config [ cooling not supported,
|
|
|
|
|
// cooling supported]
|
|
|
|
|
// 3: DHW config [instantaneous or not-specified,
|
|
|
|
|
// storage tank]
|
|
|
|
|
// 4: Master low-off&pump control function [allowed,
|
|
|
|
|
// not allowed]
|
|
|
|
|
// 5: CH2 present [CH2 not present, CH2 present]
|
|
|
|
|
// 6: reserved
|
|
|
|
|
// 7: reserved
|
|
|
|
|
sendMQTTData("dhw_present", (((OTdata.valueHB) & 0x01) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("control_type", (((OTdata.valueHB) & 0x02) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("cooling_config", (((OTdata.valueHB) & 0x04) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("dhw_config", (((OTdata.valueHB) & 0x08) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("master_low_off_pomp_control_function", (((OTdata.valueHB) & 0x10) ? "ON" : "OFF"));
|
|
|
|
|
sendMQTTData("ch2_present", (((OTdata.valueHB) & 0x20) ? "ON" : "OFF"));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-11-06 21:13:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_mastermemberid()
|
2020-11-06 21:13:09 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = Master Config[%s] MemberID code [%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueHB), OTdata.valueLB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _msg[15] {0};
|
2020-11-06 21:58:29 +01:00
|
|
|
|
sendMQTTData("master_configuration", byte_to_binary(OTdata.valueHB));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
utoa(OTdata.valueLB, _msg, 10);
|
2020-11-06 21:58:29 +01:00
|
|
|
|
sendMQTTData("master_memberid_code", _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_flag8u8()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = M[%s] - [%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueHB), OTdata.valueLB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _topic[50] {0};
|
|
|
|
|
//flag8 value
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_flag8", sizeof(_topic));
|
2020-11-06 21:13:09 +01:00
|
|
|
|
sendMQTTData(_topic, byte_to_binary(OTdata.valueHB));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//u8 value
|
|
|
|
|
char _msg[15] {0};
|
|
|
|
|
utoa(OTdata.valueLB, _msg, 10);
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_code", sizeof(_topic));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 21:13:09 +01:00
|
|
|
|
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_flag8()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = flag8 = [%s] - decimal = [%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueLB), OTdata.valueLB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
|
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _topic[50] {0};
|
|
|
|
|
//flag8 value
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_flag8", sizeof(_topic));
|
2020-11-06 21:13:09 +01:00
|
|
|
|
sendMQTTData(_topic, byte_to_binary(OTdata.valueLB));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_flag8flag8()
|
|
|
|
|
{
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _topic[50] {0};
|
|
|
|
|
//flag8 valueHB
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = HB flag8[%s] -[%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueHB), OTdata.valueHB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_hb_flag8", sizeof(_topic));
|
2020-11-06 21:13:09 +01:00
|
|
|
|
sendMQTTData(_topic, byte_to_binary(OTdata.valueHB));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//flag8 valueLB
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = LB flag8[%s] - [%3d]\r\n", OTmap[OTdata.id].label, byte_to_binary(OTdata.valueLB), OTdata.valueLB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_lb_flag8", sizeof(_topic));
|
2020-11-06 21:13:09 +01:00
|
|
|
|
sendMQTTData(_topic, byte_to_binary(OTdata.valueLB));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_u8u8()
|
|
|
|
|
{
|
|
|
|
|
Debugf("%-37s = %3d / %3d %s\r\n", OTmap[OTdata.id].label, (uint8_t)OTdata.valueHB, (uint8_t)OTdata.valueLB, OTmap[OTdata.id].unit);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _topic[50] {0};
|
|
|
|
|
char _msg[10] {0};
|
|
|
|
|
//flag8 valueHB
|
|
|
|
|
utoa((OTdata.valueHB), _msg, 10);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = HB u8[%s] [%3d]\r\n", OTmap[OTdata.id].label, _msg, OTdata.valueHB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_hb_u8", sizeof(_topic));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, _msg);
|
|
|
|
|
//flag8 valueLB
|
|
|
|
|
utoa((OTdata.valueLB), _msg, 10);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
Debugf("%-37s = LB u8[%s] [%3d]\r\n", OTmap[OTdata.id].label, _msg, OTdata.valueLB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_lb_u8", sizeof(_topic));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, _msg);
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return OTdata.u16();
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t print_daytime()
|
2020-10-25 20:35:34 +01:00
|
|
|
|
{
|
|
|
|
|
//function to print data
|
|
|
|
|
const char *dayOfWeekName[] { "Unknown", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag", "Unknown" };
|
2020-12-12 00:20:31 +01:00
|
|
|
|
uint16_t _value = OTdata.u16();
|
|
|
|
|
Debugf("%-37s = %s - %2d:%2d\r\n", OTmap[OTdata.id].label, dayOfWeekName[(OTdata.valueHB >> 5) & 0x7], (OTdata.valueHB & 0x1F), OTdata.valueLB);
|
2020-11-03 01:28:05 +01:00
|
|
|
|
//Build string for MQTT
|
|
|
|
|
char _topic[50] {0};
|
|
|
|
|
char _msg[10] {0};
|
|
|
|
|
//dayofweek
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_dayofweek", sizeof(_topic));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, dayOfWeekName[(OTdata.valueHB >> 5) & 0x7]);
|
|
|
|
|
//dayofweek
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_hour", sizeof(_topic));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, itoa((OTdata.valueHB & 0x1F), _msg, 10));
|
|
|
|
|
//dayofweek
|
|
|
|
|
strlcpy(_topic, messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)), sizeof(_topic));
|
2020-11-06 21:58:29 +01:00
|
|
|
|
strlcat(_topic, "_minutes", sizeof(_topic));
|
2020-11-03 01:28:05 +01:00
|
|
|
|
sendMQTTData(_topic, itoa(OTdata.valueLB, _msg, 10));
|
2020-12-12 00:20:31 +01:00
|
|
|
|
return _value;
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
2020-11-09 00:05:06 +01:00
|
|
|
|
//===================[ OTGW PS=1 Command ]===============================
|
|
|
|
|
void getOTGW_PS_1(){
|
|
|
|
|
DebugTln("PS=1");
|
|
|
|
|
Serial.write("PS=1\r\n");
|
|
|
|
|
delay(100);
|
|
|
|
|
while(Serial.available() > 0)
|
|
|
|
|
{
|
|
|
|
|
String strBuffer = Serial.readStringUntil('\n');
|
|
|
|
|
strBuffer.trim(); //remove LF and CR (and whitespaces)
|
|
|
|
|
DebugTln(strBuffer);
|
|
|
|
|
}
|
|
|
|
|
DebugTln("PS=0");
|
|
|
|
|
Serial.write("PS=0\r\n");
|
|
|
|
|
}
|
|
|
|
|
//===================[ OTGW PS=1 Command ]===============================
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
2020-11-09 00:05:06 +01:00
|
|
|
|
//===================[ Send buffer to OTGW ]=============================
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
2020-11-09 00:05:06 +01:00
|
|
|
|
int sendOTGW(const char* buf, int len)
|
|
|
|
|
{
|
|
|
|
|
//Just send the buffer to OTGW when the Serial interface is available
|
|
|
|
|
if (Serial) {
|
|
|
|
|
//check the write buffer
|
|
|
|
|
if (Serial.availableForWrite()>= (len+2)) {
|
|
|
|
|
//write buffer to serial
|
2020-12-10 00:32:43 +01:00
|
|
|
|
Debugf("Sending command OTGW to [%s]\r\n", buf);
|
2020-11-09 00:05:06 +01:00
|
|
|
|
Serial.write(buf, len);
|
|
|
|
|
// Serial.write("PS=0\r\n");
|
2020-12-13 02:06:05 +01:00
|
|
|
|
Serial.write("\n");
|
2020-11-09 00:05:06 +01:00
|
|
|
|
} else Debugln("Error: Write buffer not big enough!");
|
|
|
|
|
} else Debugln("Error: Serial device not found!");
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 02:06:05 +01:00
|
|
|
|
void processOTGW(const char * buf, int len)
|
|
|
|
|
{
|
|
|
|
|
if (len >= 9)
|
2020-11-19 16:47:10 +01:00
|
|
|
|
{
|
2020-12-13 02:06:05 +01:00
|
|
|
|
//OT protocol messages are 9 chars long
|
|
|
|
|
//parse value
|
|
|
|
|
const char *bufval = buf + 1;
|
|
|
|
|
uint32_t value = strtoul(bufval, NULL, 16);
|
|
|
|
|
// Debugf("Value=[%08x]\r\n", (uint32_t)value);
|
|
|
|
|
//processing message
|
|
|
|
|
// if (strBuffer.charAt(0)=='B')
|
|
|
|
|
// {
|
|
|
|
|
// DebugT("Boiler ");
|
|
|
|
|
// } else
|
|
|
|
|
// if (strBuffer.charAt(0)=='T')
|
|
|
|
|
// {
|
|
|
|
|
// DebugT("Thermostat ");
|
|
|
|
|
// } else
|
|
|
|
|
// if (strBuffer.charAt(0)=='R')
|
|
|
|
|
// {
|
|
|
|
|
// DebugT("Request Boiler ");
|
|
|
|
|
// } else
|
|
|
|
|
// if (strBuffer.charAt(0)=='A')
|
|
|
|
|
// {
|
|
|
|
|
// DebugT("Answer Themostat ");
|
|
|
|
|
// } else
|
|
|
|
|
// if (strBuffer.charAt(0)=='E')
|
|
|
|
|
// {
|
|
|
|
|
// DebugT("Parity error ");
|
|
|
|
|
// } else
|
|
|
|
|
// {
|
|
|
|
|
// DebugTf("Unexpected=[%c] ", strBuffer.charAt(0));
|
|
|
|
|
// }
|
|
|
|
|
DebugTf("msg=[%s] value=[%08x]", bufval, value);
|
|
|
|
|
|
|
|
|
|
//split 32bit value into the relevant OT protocol parts
|
|
|
|
|
OTdata.type = (value >> 28) & 0x7; // byte 1 = take 3 bits that define msg msgType
|
|
|
|
|
OTdata.id = (value >> 16) & 0xFF; // byte 2 = message id 8 bits
|
|
|
|
|
OTdata.valueHB = (value >> 8) & 0xFF; // byte 3 = high byte
|
|
|
|
|
OTdata.valueLB = value & 0xFF; // byte 4 = low byte
|
|
|
|
|
|
|
|
|
|
//print message frame
|
|
|
|
|
Debugf("\ttype[%3d] id[%3d] hb[%3d] lb[%3d]\t", OTdata.type, OTdata.id, OTdata.valueHB, OTdata.valueLB);
|
|
|
|
|
|
|
|
|
|
//print message Type and ID
|
|
|
|
|
Debugf("[%-16s]\t", messageTypeToString(static_cast<OpenThermMessageType>(OTdata.type)));
|
|
|
|
|
Debugf("[%-30s]\t", messageIDToString(static_cast<OpenThermMessageID>(OTdata.id)));
|
|
|
|
|
DebugFlush();
|
|
|
|
|
|
|
|
|
|
//next step interpret the OT protocol
|
|
|
|
|
if (static_cast<OpenThermMessageType>(OTdata.type) == OT_READ_ACK || static_cast<OpenThermMessageType>(OTdata.type) == OT_WRITE_DATA) {
|
|
|
|
|
|
|
|
|
|
//#define OTprint(data, value, text, format) ({ data= value; Debugf("[%37s]", text); Debugf("= [format]", data)})
|
|
|
|
|
//interpret values f8.8
|
|
|
|
|
switch (static_cast<OpenThermMessageID>(OTdata.id)) {
|
|
|
|
|
case TSet: OTdataObject.Tset = print_f88(); break;
|
|
|
|
|
case CoolingControl: OTdataObject.CoolingControl = print_f88(); break;
|
|
|
|
|
case TsetCH2: OTdataObject.TsetCH2 = print_f88(); break;
|
|
|
|
|
case TrOverride: OTdataObject.TrOverride = print_f88(); break;
|
|
|
|
|
case MaxRelModLevelSetting: OTdataObject.MaxRelModLevelSetting = print_f88(); break;
|
|
|
|
|
case TrSet: OTdataObject.TrSet = print_f88(); break;
|
|
|
|
|
case TrSetCH2: OTdataObject.TrSetCH2 = print_f88(); break;
|
|
|
|
|
case RelModLevel: OTdataObject.RelModLevel = print_f88(); break;
|
|
|
|
|
case CHPressure: OTdataObject.CHPressure = print_f88(); break;
|
|
|
|
|
case DHWFlowRate: OTdataObject.DHWFlowRate = print_f88(); break;
|
|
|
|
|
case Tr: OTdataObject.Tr = print_f88(); Debugf("Troom=%f\r\n", OTdataObject.Tr);break;
|
|
|
|
|
case Tboiler: OTdataObject.Tboiler = print_f88(); break;
|
|
|
|
|
case Tdhw: OTdataObject.Tdhw = print_f88(); break;
|
|
|
|
|
case Toutside: OTdataObject.Toutside = print_f88(); break;
|
|
|
|
|
case Tret: OTdataObject.Tret = print_f88(); break;
|
|
|
|
|
case Tstorage: OTdataObject.Tstorage = print_f88(); break;
|
|
|
|
|
case Tcollector: OTdataObject.Tcollector = print_f88(); break;
|
|
|
|
|
case TflowCH2: OTdataObject.TflowCH2 = print_f88(); break;
|
|
|
|
|
case Tdhw2: OTdataObject.Tdhw2 = print_f88(); break;
|
|
|
|
|
case Texhaust: OTdataObject.Texhaust = print_s16(); break;
|
|
|
|
|
case TdhwSet: OTdataObject.TdhwSet = print_f88(); break;
|
|
|
|
|
case MaxTSet: OTdataObject.MaxTSet = print_f88(); break;
|
|
|
|
|
case Hcratio: OTdataObject.Hcratio = print_f88(); break;
|
|
|
|
|
case OpenThermVersionMaster: OTdataObject.OpenThermVersionMaster = print_f88(); break;
|
|
|
|
|
case OpenThermVersionSlave: OTdataObject.OpenThermVersionSlave = print_f88(); break;
|
|
|
|
|
case Status: OTdataObject.Status = print_status(); break;
|
|
|
|
|
case ASFflags: OTdataObject.ASFflags = print_ASFflags(); break;
|
|
|
|
|
case MConfigMMemberIDcode: OTdataObject.MConfigMMemberIDcode = print_mastermemberid(); break;
|
|
|
|
|
case SConfigSMemberIDcode: OTdataObject.SConfigSMemberIDcode = print_slavememberid(); break;
|
|
|
|
|
case Command: OTdataObject.Command = print_u8u8(); break;
|
|
|
|
|
case RBPflags: OTdataObject.RBPflags = print_flag8flag8(); break;
|
|
|
|
|
case TSP: OTdataObject.TSP = print_u8u8(); break;
|
|
|
|
|
case TSPindexTSPvalue: OTdataObject.TSPindexTSPvalue = print_u8u8(); break;
|
|
|
|
|
case FHBsize: OTdataObject.FHBsize = print_u8u8(); break;
|
|
|
|
|
case FHBindexFHBvalue: OTdataObject.FHBindexFHBvalue = print_u8u8(); break;
|
|
|
|
|
case MaxCapacityMinModLevel: OTdataObject.MaxCapacityMinModLevel = print_u8u8(); break;
|
|
|
|
|
case DayTime: OTdataObject.DayTime = print_daytime(); break;
|
|
|
|
|
case Date: OTdataObject.Date = print_u8u8(); break;
|
|
|
|
|
case Year: OTdataObject.Year = print_u16(); break;
|
|
|
|
|
case TdhwSetUBTdhwSetLB: OTdataObject.TdhwSetUBTdhwSetLB = print_s8s8(); break;
|
|
|
|
|
case MaxTSetUBMaxTSetLB: OTdataObject.MaxTSetUBMaxTSetLB = print_s8s8(); break;
|
|
|
|
|
case HcratioUBHcratioLB: OTdataObject.HcratioUBHcratioLB = print_s8s8(); break;
|
|
|
|
|
case RemoteOverrideFunction: OTdataObject.RemoteOverrideFunction = print_flag8(); break;
|
|
|
|
|
case OEMDiagnosticCode: OTdataObject.OEMDiagnosticCode = print_u16(); break;
|
|
|
|
|
case BurnerStarts: OTdataObject.BurnerStarts = print_u16(); break;
|
|
|
|
|
case CHPumpStarts: OTdataObject.CHPumpStarts = print_u16(); break;
|
|
|
|
|
case DHWPumpValveStarts: OTdataObject.DHWPumpValveStarts = print_u16(); break;
|
|
|
|
|
case DHWBurnerStarts: OTdataObject.DHWBurnerStarts = print_u16(); break;
|
|
|
|
|
case BurnerOperationHours: OTdataObject.BurnerOperationHours = print_u16(); break;
|
|
|
|
|
case CHPumpOperationHours: OTdataObject.CHPumpOperationHours = print_u16(); break;
|
|
|
|
|
case DHWPumpValveOperationHours:OTdataObject.DHWPumpValveOperationHours = print_u16(); break;
|
|
|
|
|
case DHWBurnerOperationHours: OTdataObject.DHWBurnerOperationHours = print_u16(); break;
|
|
|
|
|
case MasterVersion: OTdataObject.MasterVersion = print_u8u8(); break;
|
|
|
|
|
case SlaveVersion: OTdataObject.SlaveVersion = print_u8u8(); break;
|
|
|
|
|
}
|
|
|
|
|
} else Debugln(); //next line
|
|
|
|
|
} else DebugTf("[%s] [%d]\r\n", buf, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void handleOTGW()
|
|
|
|
|
{
|
|
|
|
|
//connect the OTmonitor port 1023
|
|
|
|
|
if (OTGWstream.hasClient())
|
|
|
|
|
{ //incoming telnet connection
|
|
|
|
|
if (!OTGWclient || !OTGWclient.connected()){
|
|
|
|
|
if (OTGWclient) OTGWclient.stop();
|
|
|
|
|
OTGWclient = OTGWstream.available();
|
|
|
|
|
OTGWclient.flush();
|
|
|
|
|
}
|
2020-11-19 16:47:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 02:06:05 +01:00
|
|
|
|
//handle serial communication and line processing
|
|
|
|
|
#define MAX_BUFFER 128
|
|
|
|
|
static char sBuf[MAX_BUFFER];
|
|
|
|
|
static size_t bytes_read = 0;
|
|
|
|
|
static uint8_t inByte;
|
|
|
|
|
|
|
|
|
|
//handle incoming data from network sent to OTGW
|
|
|
|
|
if (OTGWclient.connected()){
|
|
|
|
|
while (OTGWclient.available()){
|
|
|
|
|
Serial.write(OTGWclient.read()); //just forward it directly to Serial
|
|
|
|
|
}
|
2020-11-19 16:47:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 02:06:05 +01:00
|
|
|
|
//read a single line and continue
|
|
|
|
|
while(Serial.available())
|
|
|
|
|
{
|
|
|
|
|
inByte = Serial.read();
|
|
|
|
|
if (inByte== '\n')
|
|
|
|
|
{ //line terminator, continue to process incoming message
|
|
|
|
|
if (OTGWclient.connected()){
|
|
|
|
|
OTGWclient.write('\r');
|
|
|
|
|
OTGWclient.write('\n');
|
|
|
|
|
OTGWclient.flush();
|
|
|
|
|
}
|
|
|
|
|
sBuf[bytes_read] = 0;
|
|
|
|
|
processOTGW(sBuf, bytes_read);
|
|
|
|
|
bytes_read = 0;
|
|
|
|
|
break; // to continue processing incoming message
|
|
|
|
|
}
|
|
|
|
|
else if (inByte == '\r')
|
|
|
|
|
{ // just ignore LF...
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (OTGWclient.connected()) OTGWclient.write(inByte);
|
|
|
|
|
if (bytes_read < (MAX_BUFFER-1))
|
|
|
|
|
sBuf[bytes_read++] = inByte;
|
2020-10-25 20:35:34 +01:00
|
|
|
|
}
|
2020-12-13 02:06:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}// END of handleOTGW
|
2020-10-25 20:35:34 +01:00
|
|
|
|
|
2020-12-10 23:55:22 +01:00
|
|
|
|
//functions for REST API
|
2020-12-12 00:20:31 +01:00
|
|
|
|
String getOTGWValue(int msgid)
|
2020-12-11 13:38:56 +01:00
|
|
|
|
{
|
2020-12-12 00:20:31 +01:00
|
|
|
|
switch (static_cast<OpenThermMessageID>(msgid)) {
|
|
|
|
|
case TSet: return String(OTdataObject.Tset); break;
|
|
|
|
|
case CoolingControl: return String(OTdataObject.CoolingControl); break;
|
|
|
|
|
case TsetCH2: return String(OTdataObject.TsetCH2); break;
|
|
|
|
|
case TrOverride: return String(OTdataObject.TrOverride); break;
|
|
|
|
|
case MaxRelModLevelSetting: return String(OTdataObject.MaxRelModLevelSetting); break;
|
|
|
|
|
case TrSet: return String(OTdataObject.TrSet); break;
|
2020-12-13 02:06:05 +01:00
|
|
|
|
case TrSetCH2: return String(OTdataObject.TrSetCH2); break;
|
2020-12-12 00:20:31 +01:00
|
|
|
|
case RelModLevel: return String(OTdataObject.RelModLevel); break;
|
|
|
|
|
case CHPressure: return String(OTdataObject.CHPressure); break;
|
|
|
|
|
case DHWFlowRate: return String(OTdataObject.DHWFlowRate); break;
|
|
|
|
|
case Tr: return String(OTdataObject.Tr); break;
|
|
|
|
|
case Tboiler: return String(OTdataObject.Tboiler); break;
|
|
|
|
|
case Tdhw: return String(OTdataObject.Tdhw); break;
|
|
|
|
|
case Toutside: return String(OTdataObject.Toutside); break;
|
|
|
|
|
case Tret: return String(OTdataObject.Tret); break;
|
|
|
|
|
case Tstorage: return String(OTdataObject.Tstorage); break;
|
|
|
|
|
case Tcollector: return String(OTdataObject.Tcollector); break;
|
|
|
|
|
case TflowCH2: return String(OTdataObject.TflowCH2); break;
|
|
|
|
|
case Tdhw2: return String(OTdataObject.Tdhw2); break;
|
|
|
|
|
case Texhaust: return String(OTdataObject.Texhaust); break;
|
|
|
|
|
case TdhwSet: return String(OTdataObject.TdhwSet); break;
|
|
|
|
|
case MaxTSet: return String(OTdataObject.MaxTSet); break;
|
|
|
|
|
case Hcratio: return String(OTdataObject.Hcratio); break;
|
|
|
|
|
case OpenThermVersionMaster: return String(OTdataObject.OpenThermVersionMaster); break;
|
|
|
|
|
case OpenThermVersionSlave: return String(OTdataObject.OpenThermVersionSlave); break;
|
|
|
|
|
case Status: return String(OTdataObject.Status); break;
|
|
|
|
|
case ASFflags: return String(OTdataObject.ASFflags); break;
|
|
|
|
|
case MConfigMMemberIDcode: return String(OTdataObject.MConfigMMemberIDcode); break;
|
|
|
|
|
case SConfigSMemberIDcode: return String(OTdataObject.SConfigSMemberIDcode); break;
|
|
|
|
|
case Command: return String(OTdataObject.Command); break;
|
|
|
|
|
case RBPflags: return String(OTdataObject.RBPflags); break;
|
|
|
|
|
case TSP: return String(OTdataObject.TSP); break;
|
|
|
|
|
case TSPindexTSPvalue: return String(OTdataObject.TSPindexTSPvalue); break;
|
|
|
|
|
case FHBsize: return String(OTdataObject.FHBsize); break;
|
|
|
|
|
case FHBindexFHBvalue: return String(OTdataObject.FHBindexFHBvalue); break;
|
|
|
|
|
case MaxCapacityMinModLevel: return String(OTdataObject.MaxCapacityMinModLevel); break;
|
|
|
|
|
case DayTime: return String(OTdataObject.DayTime); break;
|
|
|
|
|
case Date: return String(OTdataObject.Date); break;
|
|
|
|
|
case Year: return String(OTdataObject.Year); break;
|
|
|
|
|
case TdhwSetUBTdhwSetLB: return String(OTdataObject.TdhwSetUBTdhwSetLB); break;
|
|
|
|
|
case MaxTSetUBMaxTSetLB: return String(OTdataObject.MaxTSetUBMaxTSetLB); break;
|
|
|
|
|
case HcratioUBHcratioLB: return String(OTdataObject.HcratioUBHcratioLB); break;
|
|
|
|
|
case RemoteOverrideFunction: return String(OTdataObject.RemoteOverrideFunction); break;
|
|
|
|
|
case OEMDiagnosticCode: return String(OTdataObject.OEMDiagnosticCode); break;
|
|
|
|
|
case BurnerStarts: return String(OTdataObject.BurnerStarts); break;
|
|
|
|
|
case CHPumpStarts: return String(OTdataObject.CHPumpStarts); break;
|
|
|
|
|
case DHWPumpValveStarts: return String(OTdataObject.DHWPumpValveStarts); break;
|
|
|
|
|
case DHWBurnerStarts: return String(OTdataObject.DHWBurnerStarts); break;
|
|
|
|
|
case BurnerOperationHours: return String(OTdataObject.BurnerOperationHours); break;
|
|
|
|
|
case CHPumpOperationHours: return String(OTdataObject.CHPumpOperationHours); break;
|
|
|
|
|
case DHWPumpValveOperationHours:return String(OTdataObject.DHWPumpValveOperationHours); break;
|
|
|
|
|
case DHWBurnerOperationHours: return String(OTdataObject.DHWBurnerOperationHours); break;
|
|
|
|
|
case MasterVersion: return String(OTdataObject.MasterVersion); break;
|
|
|
|
|
case SlaveVersion: return String(OTdataObject.SlaveVersion); break;
|
|
|
|
|
default: return "not implemented yet!";
|
|
|
|
|
}
|
2020-12-11 13:38:56 +01:00
|
|
|
|
}
|
2020-12-10 23:55:22 +01:00
|
|
|
|
|
2020-11-16 23:20:30 +01:00
|
|
|
|
void startOTGWstream()
|
|
|
|
|
{
|
|
|
|
|
OTGWstream.begin();
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-25 20:35:34 +01:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
|
* persons to whom the Software is furnished to do so, subject to the
|
|
|
|
|
* following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice shall be included
|
|
|
|
|
* in all copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
|
|
|
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
|
|
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
***************************************************************************/
|