2020-10-25 20:35:34 +01:00
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2021-01-30 15:24:54 +01:00
* * Program : OTGW - Core . ino
2021-02-28 15:44:53 +01:00
* * Version : v0 .8 .0
2020-10-25 20:35:34 +01:00
* *
2021-01-11 00:37:30 +01:00
* * Copyright ( c ) 2021 Robert van den Breemen
2020-10-25 20:35:34 +01:00
* * Borrowed from OpenTherm library from :
* * https : //github.com/jpraus/arduino-opentherm
* *
* * TERMS OF USE : MIT License . See bottom of file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2021-01-30 15:24:54 +01:00
//define Nodoshop OTGW hardware
2021-02-08 00:13:52 +01:00
# define OTGW_BUTTON 0 //D3
# define OTGW_RESET 14 //D5
# define OTGW_LED1 2 //D4
# define OTGW_LED2 16 //D0
2021-02-01 23:40:05 +01:00
2021-01-30 15:24:54 +01:00
//external watchdog
2021-02-02 00:22:46 +01:00
# define EXT_WD_I2C_ADDRESS 0x26
2021-02-08 00:13:52 +01:00
# define PIN_I2C_SDA 4 //D2
# define PIN_I2C_SCL 5 //D1
2021-01-30 15:24:54 +01:00
2021-02-14 14:31:21 +01:00
//used by update firmware functions
const char * hexheaders [ ] = {
" Last-Modified " ,
" X-Version "
} ;
2021-01-30 15:24:54 +01:00
//Macro to Feed the Watchdog
2021-02-02 00:22:46 +01:00
# define FEEDWATCHDOGNOW Wire.beginTransmission(EXT_WD_I2C_ADDRESS); Wire.write(0xA5); Wire.endTransmission();
2020-10-25 20:35:34 +01:00
/* --- 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 ' )
2021-01-30 15:24:54 +01:00
# 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)
2020-10-25 20:35:34 +01:00
/* --- 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 ;
2020-10-25 20:35:34 +01:00
2021-02-08 01:46:11 +01:00
# define OTGW_BANNER "OpenTherm Gateway"
2021-02-08 00:13:52 +01:00
2021-01-18 21:53:53 +01:00
//===================[ Reset OTGW ]===============================
void resetOTGW ( ) {
2021-02-08 23:44:19 +01:00
OTGWSerial . resetPic ( ) ;
2021-02-09 22:01:16 +01:00
//then read the first response of the firmware to make sure it reads it
2021-02-08 23:44:19 +01:00
String resp = OTGWSerial . readStringUntil ( ' \n ' ) ;
DebugTf ( " Received firmware version: [%s] [%s] (%d) \r \n " , CSTR ( resp ) , OTGWSerial . firmwareVersion ( ) , strlen ( OTGWSerial . firmwareVersion ( ) ) ) ;
bOTGWonline = ( strlen ( OTGWSerial . firmwareVersion ( ) ) > 0 ) ;
2021-02-08 00:13:52 +01:00
if ( bOTGWonline ) {
2021-02-08 23:44:19 +01:00
if ( resp . length ( ) > 0 ) {
sPICfwversion = String ( OTGWSerial . firmwareVersion ( ) ) ;
} else sPICfwversion = " No version found " ;
2021-02-09 23:29:39 +01:00
} else sPICfwversion = " No OTGW connected! " ;
2021-02-08 00:13:52 +01:00
DebugTf ( " Current firmware version: %s \r \n " , CSTR ( sPICfwversion ) ) ;
2021-01-18 21:53:53 +01:00
}
2021-01-31 23:43:52 +01:00
//===================[ getpicfwversion ]===========================
String getpicfwversion ( ) {
String _ret = " " ;
2021-02-08 00:13:52 +01:00
2021-02-01 00:02:46 +01:00
String line = executeCommand ( " PR=A " ) ;
2021-02-08 00:13:52 +01:00
int p = line . indexOf ( OTGW_BANNER ) ;
2021-01-31 23:43:52 +01:00
if ( p > = 0 ) {
2021-02-08 00:13:52 +01:00
p + = sizeof ( OTGW_BANNER ) ;
2021-01-31 23:43:52 +01:00
_ret = line . substring ( p ) ;
2021-02-02 21:21:46 +01:00
} else _ret = " No version found " ;
2021-02-08 00:13:52 +01:00
DebugTf ( " Current firmware version: %s \r \n " , CSTR ( _ret ) ) ;
2021-01-31 23:43:52 +01:00
_ret . trim ( ) ;
return _ret ;
}
2021-03-06 10:52:51 +01:00
//===================[ checkOTWGpicforupdate ]=====================
void checkOTWGpicforupdate ( ) {
DebugTf ( " OTGW PIC firmware version = [%s] \r \n " , CSTR ( sPICfwversion ) ) ;
String latest = checkforupdatepic ( " gateway.hex " ) ;
if ( ! bOTGWonline ) {
sMessage = sPICfwversion ;
} else if ( latest ! = sPICfwversion ) {
sMessage = " New PIC version " + latest + " available! " ;
}
}
2021-01-31 23:43:52 +01:00
//===================[ OTGW Command & Response ]===================
2021-01-31 23:44:58 +01:00
String executeCommand ( const String sCmd ) {
2021-02-01 23:03:07 +01:00
//send command to OTGW
2021-02-02 00:56:38 +01:00
DebugTf ( " OTGW Send Cmd [%s] \r \n " , CSTR ( sCmd ) ) ;
2021-02-08 00:13:52 +01:00
OTGWSerial . setTimeout ( 1000 ) ;
2021-02-02 08:46:24 +01:00
DECLARE_TIMER_MS ( tmrWaitForIt , 1000 ) ;
2021-02-08 00:13:52 +01:00
while ( ( OTGWSerial . availableForWrite ( ) < sCmd . length ( ) + 2 ) & & ! DUE ( tmrWaitForIt ) ) {
2021-02-01 23:03:07 +01:00
feedWatchDog ( ) ;
}
2021-02-08 00:13:52 +01:00
OTGWSerial . write ( CSTR ( sCmd ) ) ;
OTGWSerial . write ( " \r \n " ) ;
OTGWSerial . flush ( ) ;
2021-02-01 23:03:07 +01:00
//wait for response
2021-02-02 11:32:49 +01:00
RESTART_TIMER ( tmrWaitForIt ) ;
2021-02-08 00:13:52 +01:00
while ( ! OTGWSerial . available ( ) & & ! DUE ( tmrWaitForIt ) ) {
2021-02-01 23:03:07 +01:00
feedWatchDog ( ) ;
}
2021-02-02 21:21:46 +01:00
String _cmd = sCmd . substring ( 0 , 2 ) ;
2021-02-01 23:03:07 +01:00
DebugTf ( " Send command: [%s] \r \n " , CSTR ( _cmd ) ) ;
//fetch a line
2021-02-08 00:13:52 +01:00
String line = OTGWSerial . readStringUntil ( ' \n ' ) ;
2021-02-02 08:46:24 +01:00
line . trim ( ) ;
2021-02-01 23:03:07 +01:00
String _ret = " " ;
if ( line . startsWith ( _cmd ) ) {
// Responses: When a serial command is accepted by the gateway, it responds with the two letters of the command code, a colon, and the interpreted data value.
// Command: "TT=19.125"
// Response: "TT: 19.13"
// [XX:response string]
_ret = line . substring ( 3 ) ;
} else if ( line . startsWith ( " NG " ) ) {
_ret = " NG - No Good. The command code is unknown. " ;
} else if ( line . startsWith ( " SE " ) ) {
_ret = " SE - Syntax Error. The command contained an unexpected character or was incomplete. " ;
} else if ( line . startsWith ( " BV " ) ) {
_ret = " BV - Bad Value. The command contained a data value that is not allowed. " ;
} else if ( line . startsWith ( " OR " ) ) {
_ret = " OR - Out of Range. A number was specified outside of the allowed range. " ;
} else if ( line . startsWith ( " NS " ) ) {
_ret = " NS - No Space. The alternative Data-ID could not be added because the table is full. " ;
} else if ( line . startsWith ( " NF " ) ) {
_ret = " NF - Not Found. The specified alternative Data-ID could not be removed because it does not exist in the table. " ;
} else if ( line . startsWith ( " OE " ) ) {
_ret = " OE - Overrun Error. The processor was busy and failed to process all received characters. " ;
2021-02-02 21:21:46 +01:00
} else if ( line . length ( ) = = 0 ) {
//just an empty line... most likely it's a timeout situation
_ret = " TO - Timeout. No response. " ;
2021-02-01 23:03:07 +01:00
} else {
2021-02-02 22:50:25 +01:00
_ret = line ; //some commands return a string, just return that.
2021-02-01 23:03:07 +01:00
}
2021-02-02 21:21:46 +01:00
DebugTf ( " Command send [%s]-[%s] - Response line: [%s] - Returned value: [%s] \r \n " , CSTR ( sCmd ) , CSTR ( _cmd ) , CSTR ( line ) , CSTR ( _ret ) ) ;
2021-02-01 23:03:07 +01:00
return _ret ;
}
2021-02-08 00:13:52 +01:00
// String executeCommandCstyle(const String sCmd){
// return executeCommandCstyle(CSTR(sCmd), sCmd.length());
// }
// String executeCommandCstyle(const char* sCmd, size_t len){
// char _cmd[2];
// char line[80];
// char _ret[80];
// //send command to OTGW
// DebugTf("OTGW Send Cmd [%s]=[%s]\r\n", sCmd);
// while(OTGWSerial.availableForWrite() < len+2){
// feedWatchDog();
// }
// OTGWSerial.write(sCmd, len);
// OTGWSerial.write("\r\n");
// OTGWSerial.flush();
// //wait for response
// OTGWSerial.setTimeout(3000);
// while(!OTGWSerial.available()) {
// feedWatchDog();
// }
// // DebugTf("Send command: [%s]\r\n", _cmd);
// //fetch a line
// size_t l = OTGWSerial.readBytesUntil('\n', line, sizeof(line)-1);
// line[l]='\0';
// _cmd[0]='\0';
// if (l > 0) {
// strcpy(_cmd,strtok(line,":"));
// }
// if (prefix(_cmd, sCmd)){
// // Responses: When a serial command is accepted by the gateway, it responds with the two letters of the command code, a colon, and the interpreted data value.
// // Command: "TT=19.125"
// // Response: "TT: 19.13"
// // [XX:response string]
// strcpy(_ret,strtok(NULL,":"));
// } else if (prefix("NG", _cmd)){
// strlcpy(_ret, "NG - No Good. The command code is unknown.", sizeof(_ret));
// } else if (prefix("SE", _cmd)){
// strlcpy(_ret, "SE - Syntax Error. The command contained an unexpected character or was incomplete.", sizeof(_ret));
// } else if (prefix("BV", _cmd)){
// strlcpy(_ret, "BV - Bad Value. The command contained a data value that is not allowed.", sizeof(_ret));
// } else if (prefix("OR", _cmd)){
// strlcpy(_ret, "OR - Out of Range. A number was specified outside of the allowed range.", sizeof(_ret));
// } else if (prefix("NS", _cmd)){
// strlcpy(_ret, "NS - No Space. The alternative Data-ID could not be added because the table is full.", sizeof(_ret));
// } else if (prefix("NF", _cmd)){
// strlcpy(_ret, "NF - Not Found. The specified alternative Data-ID could not be removed because it does not exist in the table.", sizeof(_ret));
// } else if (prefix("OE", _cmd)){
// strlcpy(_ret, "OE - Overrun Error. The processor was busy and failed to process all received characters.", sizeof(_ret));
// } else {
// strlcpy(_ret, "Error: Different command response [", sizeof(_ret));
// strlcat(_ret, _cmd, sizeof(_ret));
// strlcat(_ret, "] Cmd send [", sizeof(_ret));
// strlcat(_ret, sCmd, sizeof(_ret));
// strlcat(_ret, "]", sizeof(_ret));
// }
// DebugTf("Command send - Response returned: [%s]:[%s] - line: [%s]\r\n", _cmd, _ret, line);
// return _ret;
// }
2021-01-31 23:43:52 +01:00
//===================[ OTGW PS=1 Command ]===============================
void getOTGW_PS_1 ( ) {
DebugTln ( " PS=1 " ) ;
2021-02-08 00:13:52 +01:00
OTGWSerial . write ( " PS=1 \r \n " ) ;
OTGWSerial . flush ( ) ;
2021-01-31 23:43:52 +01:00
2021-02-08 00:13:52 +01:00
while ( ! OTGWSerial . available ( ) ) {
2021-01-31 23:43:52 +01:00
feedWatchDog ( ) ;
}
2021-02-08 00:13:52 +01:00
String line = OTGWSerial . readStringUntil ( ' \n ' ) ;
2021-01-31 23:43:52 +01:00
line . trim ( ) ; //remove LF and CR (and whitespaces)
DebugTln ( line ) ;
DebugTln ( " PS=0 " ) ;
2021-02-08 00:13:52 +01:00
OTGWSerial . write ( " PS=0 \r \n " ) ;
OTGWSerial . flush ( ) ;
2021-01-31 23:43:52 +01:00
}
//===================[ OTGW PS=1 Command ]===============================
2020-10-25 20:35:34 +01:00
//===================[ Watchdog OTGW ]===============================
String initWatchDog ( ) {
2021-01-30 15:24:54 +01:00
// Hardware WatchDog is based on:
// https://github.com/rvdbreemen/ESPEasySlaves/tree/master/TinyI2CWatchdog
// Code here is based on ESPEasy code, modified to work in the project.
2021-02-02 00:22:46 +01:00
2021-01-30 15:24:54 +01:00
// configure hardware pins according to eeprom settings.
2021-02-19 01:48:31 +01:00
DebugTln ( " Setup Watchdog " ) ;
2021-02-02 00:22:46 +01:00
DebugTln ( F ( " INIT : I2C " ) ) ;
Wire . begin ( PIN_I2C_SDA , PIN_I2C_SCL ) ; //configure the I2C bus
//=============================================
// I2C Watchdog boot status check
String ReasonReset = " " ;
2020-10-25 20:35:34 +01:00
delay ( 500 ) ;
2021-02-02 00:22:46 +01:00
Wire . beginTransmission ( EXT_WD_I2C_ADDRESS ) ; // OTGW WD address
2020-10-25 20:35:34 +01:00
Wire . write ( 0x83 ) ; // command to set pointer
Wire . write ( 17 ) ; // pointer value to status byte
Wire . endTransmission ( ) ;
2021-02-02 00:22:46 +01:00
Wire . requestFrom ( ( uint8_t ) EXT_WD_I2C_ADDRESS , ( uint8_t ) 1 ) ;
2020-10-25 20:35:34 +01:00
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 ;
2021-02-02 00:22:46 +01:00
//===========================================
2020-10-25 20:35:34 +01:00
}
2021-02-02 00:22:46 +01:00
2020-10-25 20:35:34 +01:00
//===[ 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
2021-02-02 00:22:46 +01:00
DECLARE_TIMER_MS ( timerWD , 1000 , CATCH_UP_MISSED_TICKS ) ;
2020-11-02 08:09:26 +01:00
if DUE ( timerWD )
{
2021-02-02 00:22:46 +01:00
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...
2021-03-04 22:54:22 +01:00
if ( settingLEDblink ) blinkLEDnow ( LED1 ) ;
2020-11-02 08:09:26 +01:00
}
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 ) {
2021-01-20 08:50:35 +01:00
if ( message_id < = OT_MSGID_MAX ) {
2020-12-12 00:20:31 +01:00
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 ) ;
}
2021-01-03 23:12:19 +01:00
//parsing responses - helper functions
// 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
bool isCentralHeatingEnabled ( ) {
return OTdataObject . Status & 0x0100 ;
}
bool isDomesticHotWaterEnabled ( ) {
return OTdataObject . Status & 0x0200 ;
}
bool isCoolingEnabled ( ) {
return OTdataObject . Status & 0x0400 ;
}
bool isOutsideTemperatureCompensationActive ( ) {
return OTdataObject . Status & 0x0800 ;
}
bool isCentralHeating2enabled ( ) {
return OTdataObject . Status & 0x1000 ;
}
2020-10-25 20:35:34 +01:00
2021-01-03 23:12:19 +01:00
//Slave
// 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
bool isFaultIndicator ( ) {
return OTdataObject . Status & 0x001 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isCentralHeatingActive ( ) {
return OTdataObject . Status & 0x002 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isDomesticHotWaterActive ( ) {
return OTdataObject . Status & 0x004 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isFlameStatus ( ) {
return OTdataObject . Status & 0x008 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isCoolingActive ( ) {
return OTdataObject . Status & 0x0010 ;
2020-10-25 20:35:34 +01:00
}
2021-02-10 00:56:33 +01:00
bool isCentralHeating2Active ( ) {
return OTdataObject . Status & 0x0020 ;
}
2021-01-03 23:12:19 +01:00
bool isDiagnosticIndicator ( ) {
return OTdataObject . Status & 0x0040 ;
2020-10-25 20:35:34 +01:00
}
2021-02-10 00:56:33 +01:00
//bit: [clear/0, set/1]
//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
bool isServiceRequest ( ) {
2021-02-28 21:18:20 +01:00
return OTdataObject . ASFflags & 0x0100 ;
2021-02-10 00:56:33 +01:00
}
bool isLockoutReset ( ) {
2021-02-28 21:18:20 +01:00
return OTdataObject . ASFflags & 0x0200 ;
2021-02-10 00:56:33 +01:00
}
bool isLowWaterPressure ( ) {
2021-02-28 21:18:20 +01:00
return OTdataObject . ASFflags & 0x0400 ;
2021-02-10 00:56:33 +01:00
}
bool isGasFlameFault ( ) {
2021-02-28 21:18:20 +01:00
return OTdataObject . ASFflags & 0x0800 ;
2021-02-10 00:56:33 +01:00
}
bool isAirTemperature ( ) {
2021-02-28 21:18:20 +01:00
return OTdataObject . ASFflags & 0x1000 ;
2021-02-10 00:56:33 +01:00
}
bool isWaterOverTemperature ( ) {
2021-02-28 21:18:20 +01:00
return OTdataObject . ASFflags & 0x2000 ;
2021-02-10 00:56:33 +01:00
}
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
}
2021-01-31 23:43:52 +01:00
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 )
{
2021-01-21 08:23:08 +01:00
//Send the buffer to OTGW when the Serial interface is available
2021-02-24 08:13:46 +01:00
if ( OTGWSerial . availableForWrite ( ) > = len + 2 ) {
2020-11-09 00:05:06 +01:00
//check the write buffer
2021-02-24 08:13:46 +01:00
//Debugf("Serial Write Buffer space = [%d] - needed [%d]\r\n",OTGWSerial.availableForWrite(), (len+2));
2020-12-13 03:53:47 +01:00
DebugT ( " Sending to Serial [ " ) ;
for ( int i = 0 ; i < len ; i + + ) {
Debug ( ( char ) buf [ i ] ) ;
}
Debug ( " ] ( " ) ; Debug ( len ) ; Debug ( " ) " ) ; Debugln ( ) ;
2021-02-08 00:13:52 +01:00
while ( OTGWSerial . availableForWrite ( ) = = ( len + 2 ) ) {
2021-01-21 08:23:08 +01:00
//cannot write, buffer full, wait for some space in serial out buffer
feedWatchDog ( ) ; //this yields for other processes
}
2021-02-08 00:13:52 +01:00
if ( OTGWSerial . availableForWrite ( ) > = ( len + 2 ) ) {
2020-11-09 00:05:06 +01:00
//write buffer to serial
2021-02-08 00:13:52 +01:00
OTGWSerial . write ( buf , len ) ;
// OTGWSerial.write("PS=0\r\n");
OTGWSerial . write ( ' \r ' ) ;
OTGWSerial . write ( ' \n ' ) ;
OTGWSerial . flush ( ) ;
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 )
{
2021-02-10 01:47:02 +01:00
if ( strstr ( buf , " Error 01 " ) ! = NULL ) OTdataObject . error01 + + ;
if ( strstr ( buf , " Error 02 " ) ! = NULL ) OTdataObject . error02 + + ;
if ( strstr ( buf , " Error 03 " ) ! = NULL ) OTdataObject . error03 + + ;
if ( strstr ( buf , " Error 04 " ) ! = NULL ) OTdataObject . error04 + + ;
2021-02-08 02:06:04 +01:00
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
2021-01-07 19:17:23 +01:00
sendMQTTData ( " otmessage " , buf ) ;
2021-02-08 02:06:04 +01:00
// source of otmsg
if ( buf [ 0 ] = = ' B ' )
{
DebugT ( " Boiler " ) ;
} else if ( buf [ 0 ] = = ' T ' )
{
DebugT ( " Thermostat " ) ;
} else if ( buf [ 0 ] = = ' R ' )
{
DebugT ( " Request Boiler " ) ;
} else if ( buf [ 0 ] = = ' A ' )
{
DebugT ( " Answer Themostat " ) ;
} else if ( buf [ 0 ] = = ' E ' )
{
DebugT ( " Parity error " ) ;
} else
{
DebugTf ( " Unexpected=[%c] " , buf [ 0 ] ) ;
}
2020-12-13 02:06:05 +01:00
const char * bufval = buf + 1 ;
uint32_t value = strtoul ( bufval , NULL , 16 ) ;
2021-02-08 02:06:04 +01:00
Debugf ( " msg=[%s] value=[%08x] " , bufval , value ) ;
2020-12-13 02:06:05 +01:00
//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 ( " \t type[%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 ( ) ;
2021-02-21 09:44:57 +01:00
//keep track of update
msglastupdated [ OTdata . id ] = now ( ) ;
2020-12-13 02:06:05 +01:00
//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
2021-01-20 19:46:31 +01:00
switch ( static_cast < OpenThermMessageID > ( OTdata . id ) ) {
2021-02-21 09:44:57 +01:00
case TSet : OTdataObject . TSet = print_f88 ( ) ; break ;
2021-01-20 19:46:31 +01:00
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 ( ) ; 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 ;
case StatusVH : OTdataObject . StatusVH = print_flag8flag8 ( ) ; break ;
case ControlSetpointVH : OTdataObject . ControlSetpointVH = print_u8u8 ( ) ; break ;
case FaultFlagsCodeVH : OTdataObject . FaultFlagsCodeVH = print_flag8u8 ( ) ; break ;
case DiagnosticCodeVH : OTdataObject . DiagnosticCodeVH = print_u16 ( ) ; break ;
case ConfigMemberIDVH : OTdataObject . ConfigMemberIDVH = print_flag8u8 ( ) ; break ;
case OpenthermVersionVH : OTdataObject . OpenthermVersionVH = print_f88 ( ) ; break ;
case VersionTypeVH : OTdataObject . VersionTypeVH = print_u8u8 ( ) ; break ;
case RelativeVentilation : OTdataObject . RelativeVentilation = print_u8u8 ( ) ; break ;
case RelativeHumidityVH : OTdataObject . RelativeHumidityVH = print_u8u8 ( ) ; break ;
case CO2LevelVH : OTdataObject . CO2LevelVH = print_u16 ( ) ; break ;
case SupplyInletTemperature : OTdataObject . SupplyInletTemperature = print_f88 ( ) ; break ;
case SupplyOutletTemperature : OTdataObject . SupplyOutletTemperature = print_f88 ( ) ; break ;
case ExhaustInletTemperature : OTdataObject . ExhaustInletTemperature = print_f88 ( ) ; break ;
case ExhaustOutletTemperature : OTdataObject . ExhaustOutletTemperature = print_f88 ( ) ; break ;
case ActualExhaustFanSpeed : OTdataObject . ActualExhaustFanSpeed = print_u16 ( ) ; break ;
case ActualInletFanSpeed : OTdataObject . ActualInletFanSpeed = print_u16 ( ) ; break ;
case RemoteParameterSettingVH : OTdataObject . RemoteParameterSettingVH = print_flag8flag8 ( ) ; break ;
case NominalVentilationValue : OTdataObject . NominalVentilationValue = print_u8u8 ( ) ; break ;
case TSPNumberVH : OTdataObject . TSPNumberVH = print_u8u8 ( ) ; break ;
case TSPEntryVH : OTdataObject . TSPEntryVH = print_u8u8 ( ) ; break ;
case FaultBufferSizeVH : OTdataObject . FaultBufferSizeVH = print_u8u8 ( ) ; break ;
case FaultBufferEntryVH : OTdataObject . FaultBufferEntryVH = print_u8u8 ( ) ; break ;
case FanSpeed : OTdataObject . FanSpeed = print_u16 ( ) ; break ;
case ElectricalCurrentBurnerFlame : OTdataObject . ElectricalCurrentBurnerFlame = print_f88 ( ) ; break ;
case TRoomCH2 : OTdataObject . TRoomCH2 = print_f88 ( ) ; break ;
case RelativeHumidity : OTdataObject . RelativeHumidity = print_u8u8 ( ) ; break ;
case RFstrengthbatterylevel : OTdataObject . RFstrengthbatterylevel = print_u8u8 ( ) ; break ;
case OperatingMode_HC1_HC2_DHW : OTdataObject . OperatingMode_HC1_HC2_DHW = print_u8u8 ( ) ; break ;
case ElectricityProducerStarts : OTdataObject . ElectricityProducerStarts = print_u16 ( ) ; break ;
case ElectricityProducerHours : OTdataObject . ElectricityProducerHours = print_u16 ( ) ; break ;
case ElectricityProduction : OTdataObject . ElectricityProduction = print_u16 ( ) ; break ;
case CumulativElectricityProduction : OTdataObject . CumulativElectricityProduction = print_u16 ( ) ; break ;
case RemehadFdUcodes : OTdataObject . RemehadFdUcodes = print_u8u8 ( ) ; break ;
case RemehaServicemessage : OTdataObject . RemehaServicemessage = print_u8u8 ( ) ; break ;
case RemehaDetectionConnectedSCU : OTdataObject . RemehaDetectionConnectedSCU = print_u8u8 ( ) ; break ;
2020-12-13 02:06:05 +01:00
}
} else Debugln ( ) ; //next line
2021-02-08 02:06:04 +01:00
} else DebugTf ( " received from OTGW => [%s] [%d] \r \n " , buf , len ) ;
2020-12-13 02:06:05 +01:00
}
2020-12-28 21:02:37 +01:00
//====================[ HandleOTGW ]====================
/*
* * This is the core of the OTGW firmware .
* * This code basically reads from serial , connected to the OTGW hardware , and
* * processes each OT message coming . It can also be used to send data into the
* * OpenTherm Gateway .
* *
* * The main purpose is to read each OT Msg ( 9 bytes ) , or anything that comes
* * from the OTGW hardware firmware . Default it assumes raw OT messages , however
* * it can handle the other messages to , like PS = 1 / PS = 0 etc .
* *
2021-02-01 23:40:05 +01:00
* * Also , this code bit implements the serial 2 network ( port 25238 ) . The serial port
* * is forwarded to port 25238 , and visavera . So you can use it with OTmonitor ( the
2020-12-28 21:02:37 +01:00
* * original OpenTherm program that comes with the hardware ) . The serial port and
2021-02-01 23:40:05 +01:00
* * ser2net port 25238 are both " line read " into the read buffer ( coming from OTGW
* * thru serial ) and write buffer ( coming from 25238 going to serial ) .
2020-12-28 21:02:37 +01:00
* *
2021-02-01 23:40:05 +01:00
* * The write buffer ( incoming from port 25238 ) is also line printed to the Debug ( port 23 ) .
2020-12-28 21:02:37 +01:00
* * The read line buffer is per line parsed by the proces OT parser code ( processOTGW ( buf , len ) ) .
*/
2020-12-13 02:06:05 +01:00
void handleOTGW ( )
{
//handle serial communication and line processing
2020-12-28 21:02:37 +01:00
# define MAX_BUFFER_READ 256
2021-01-24 22:10:57 +01:00
# define MAX_BUFFER_WRITE 128
2020-12-28 21:02:37 +01:00
static char sRead [ MAX_BUFFER_READ ] ;
static char sWrite [ MAX_BUFFER_WRITE ] ;
2020-12-13 02:06:05 +01:00
static size_t bytes_read = 0 ;
2020-12-13 03:53:47 +01:00
static size_t bytes_write = 0 ;
2020-12-13 02:06:05 +01:00
static uint8_t inByte ;
2020-12-13 03:53:47 +01:00
static uint8_t outByte ;
2021-02-01 23:40:05 +01:00
//handle incoming data from network (port 25238) sent to serial port OTGW (WRITE BUFFER)
2020-12-13 03:53:47 +01:00
while ( OTGWstream . available ( ) ) {
2021-02-08 00:13:52 +01:00
//OTGWSerial.write(OTGWstream.read()); //just forward it directly to Serial
2021-02-01 23:40:05 +01:00
outByte = OTGWstream . read ( ) ; // read from port 25238
2021-02-08 00:13:52 +01:00
while ( OTGWSerial . availableForWrite ( ) = = 0 ) {
2021-01-21 08:23:08 +01:00
//cannot write, buffer full, wait for some space in serial out buffer
feedWatchDog ( ) ; //this yields for other processes
}
2021-02-08 00:13:52 +01:00
OTGWSerial . write ( outByte ) ; // write to serial port
OTGWSerial . flush ( ) ; // wait for write to serial
2020-12-13 03:53:47 +01:00
if ( outByte = = ' \n ' )
2021-01-24 23:47:26 +01:00
{ //on newline, do something...
2020-12-13 03:53:47 +01:00
sWrite [ bytes_write ] = 0 ;
DebugTf ( " Net2Ser: Sending to OTGW: [%s] (%d) \r \n " , sWrite , bytes_write ) ;
2021-01-31 23:43:52 +01:00
//check for reset command
2021-01-24 22:10:03 +01:00
if ( stricmp ( sWrite , " GW=R " ) = = 0 ) {
//detect [GW=R], then reset the gateway the gpio way
DebugTln ( " Detected: GW=R. Reset gateway command executed. " ) ;
resetOTGW ( ) ;
}
2020-12-13 03:53:47 +01:00
bytes_write = 0 ; //start next line
} else if ( outByte = = ' \r ' )
{
// skip LF
}
else
{
2020-12-28 21:02:37 +01:00
if ( bytes_write < ( MAX_BUFFER_WRITE - 1 ) )
2020-12-13 03:53:47 +01:00
sWrite [ bytes_write + + ] = outByte ;
2020-12-13 02:06:05 +01:00
}
2020-11-19 16:47:10 +01:00
}
2020-12-13 03:53:47 +01:00
2020-12-28 21:02:37 +01:00
//Handle incoming data from OTGW through serial port (READ BUFFER)
2021-02-08 00:13:52 +01:00
while ( OTGWSerial . available ( ) )
2020-12-13 02:06:05 +01:00
{
2021-02-08 00:13:52 +01:00
inByte = OTGWSerial . read ( ) ; // read from serial port
2021-02-01 23:40:05 +01:00
OTGWstream . write ( inByte ) ; // write to port 25238
2020-12-13 02:06:05 +01:00
if ( inByte = = ' \n ' )
{ //line terminator, continue to process incoming message
2020-12-13 03:53:47 +01:00
sRead [ bytes_read ] = 0 ;
2021-03-04 22:54:22 +01:00
blinkLEDnow ( LED2 ) ;
2020-12-13 03:53:47 +01:00
processOTGW ( sRead , bytes_read ) ;
2020-12-13 02:06:05 +01:00
bytes_read = 0 ;
break ; // to continue processing incoming message
}
else if ( inByte = = ' \r ' )
{ // just ignore LF...
}
else
{
2020-12-28 21:02:37 +01:00
if ( bytes_read < ( MAX_BUFFER_READ - 1 ) )
2020-12-13 03:53:47 +01:00
sRead [ 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-28 21:02:37 +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 ) ) {
2021-02-21 09:44:57 +01:00
case TSet : return String ( OTdataObject . TSet ) ; break ;
2021-01-20 19:46:31 +01:00
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 ;
case TrSetCH2 : return String ( OTdataObject . TrSetCH2 ) ; break ;
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 ;
case StatusVH : return String ( OTdataObject . StatusVH ) ; break ;
case ControlSetpointVH : return String ( OTdataObject . ControlSetpointVH ) ; break ;
case FaultFlagsCodeVH : return String ( OTdataObject . FaultFlagsCodeVH ) ; break ;
case DiagnosticCodeVH : return String ( OTdataObject . DiagnosticCodeVH ) ; break ;
case ConfigMemberIDVH : return String ( OTdataObject . ConfigMemberIDVH ) ; break ;
case OpenthermVersionVH : return String ( OTdataObject . OpenthermVersionVH ) ; break ;
case VersionTypeVH : return String ( OTdataObject . VersionTypeVH ) ; break ;
case RelativeVentilation : return String ( OTdataObject . RelativeVentilation ) ; break ;
case RelativeHumidityVH : return String ( OTdataObject . RelativeHumidityVH ) ; break ;
case CO2LevelVH : return String ( OTdataObject . CO2LevelVH ) ; break ;
case SupplyInletTemperature : return String ( OTdataObject . SupplyInletTemperature ) ; break ;
case SupplyOutletTemperature : return String ( OTdataObject . SupplyOutletTemperature ) ; break ;
case ExhaustInletTemperature : return String ( OTdataObject . ExhaustInletTemperature ) ; break ;
case ExhaustOutletTemperature : return String ( OTdataObject . ExhaustOutletTemperature ) ; break ;
case ActualExhaustFanSpeed : return String ( OTdataObject . ActualExhaustFanSpeed ) ; break ;
case ActualInletFanSpeed : return String ( OTdataObject . ActualInletFanSpeed ) ; break ;
case RemoteParameterSettingVH : return String ( OTdataObject . RemoteParameterSettingVH ) ; break ;
case NominalVentilationValue : return String ( OTdataObject . NominalVentilationValue ) ; break ;
case TSPNumberVH : return String ( OTdataObject . TSPNumberVH ) ; break ;
case TSPEntryVH : return String ( OTdataObject . TSPEntryVH ) ; break ;
case FaultBufferSizeVH : return String ( OTdataObject . FaultBufferSizeVH ) ; break ;
case FaultBufferEntryVH : return String ( OTdataObject . FaultBufferEntryVH ) ; break ;
case FanSpeed : return String ( OTdataObject . FanSpeed ) ; break ;
case ElectricalCurrentBurnerFlame : return String ( OTdataObject . ElectricalCurrentBurnerFlame ) ; break ;
case TRoomCH2 : return String ( OTdataObject . TRoomCH2 ) ; break ;
case RelativeHumidity : return String ( OTdataObject . RelativeHumidity ) ; break ;
case RFstrengthbatterylevel : return String ( OTdataObject . RFstrengthbatterylevel ) ; break ;
case OperatingMode_HC1_HC2_DHW : return String ( OTdataObject . OperatingMode_HC1_HC2_DHW ) ; break ;
case ElectricityProducerStarts : return String ( OTdataObject . ElectricityProducerStarts ) ; break ;
case ElectricityProducerHours : return String ( OTdataObject . ElectricityProducerHours ) ; break ;
case ElectricityProduction : return String ( OTdataObject . ElectricityProduction ) ; break ;
case CumulativElectricityProduction : return String ( OTdataObject . CumulativElectricityProduction ) ; break ;
case RemehadFdUcodes : return String ( OTdataObject . RemehadFdUcodes ) ; break ;
case RemehaServicemessage : return String ( OTdataObject . RemehaServicemessage ) ; break ;
case RemehaDetectionConnectedSCU : return String ( OTdataObject . RemehaDetectionConnectedSCU ) ; break ;
2020-12-12 00:20:31 +01:00
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 ( ) ;
}
2021-02-18 01:13:54 +01:00
void upgradepicnow ( const char * filename ) {
2021-02-08 00:13:52 +01:00
if ( OTGWSerial . busy ( ) ) return ; // if already in programming mode, never call it twice
DebugTln ( " Start PIC upgrade now. " ) ;
2021-02-18 01:13:54 +01:00
fwupgradestart ( filename ) ;
2021-02-08 00:13:52 +01:00
while ( OTGWSerial . busy ( ) ) {
feedWatchDog ( ) ;
2021-02-08 01:35:51 +01:00
//blink the led during flash...
DECLARE_TIMER_MS ( timerUpgrade , 500 ) ;
if ( DUE ( timerUpgrade ) ) {
blinkLEDnow ( LED2 ) ;
}
2021-02-08 00:13:52 +01:00
}
// When you are done, then reset the PIC one more time, to capture the actual fwversion of the OTGW
resetOTGW ( ) ;
}
2021-02-08 01:35:51 +01:00
void fwupgradedone ( OTGWError result , short errors = 0 , short retries = 0 ) {
DebugTf ( " Upgrade finished: Errorcode = %d - %d retries, %d errors \n " , result , retries , errors ) ;
switch ( result ) {
case OTGW_ERROR_NONE : errorupgrade = " PIC upgrade was succesful. " ; break ;
case OTGW_ERROR_MEMORY : errorupgrade = " Not enough memory available. " ; break ;
case OTGW_ERROR_INPROG : errorupgrade = " Firmware upgrade in progress. " ; break ;
case OTGW_ERROR_HEX_ACCESS : errorupgrade = " Could not open hex file. " ; break ;
case OTGW_ERROR_HEX_FORMAT : errorupgrade = " Invalid format of hex file. " ; break ;
case OTGW_ERROR_HEX_DATASIZE : errorupgrade = " Wrong data size in hex file. " ; break ;
case OTGW_ERROR_HEX_CHECKSUM : errorupgrade = " Bad checksum in hex file. " ; break ;
case OTGW_ERROR_MAGIC : errorupgrade = " Hex file does not contain expected data. " ; break ;
case OTGW_ERROR_RESET : errorupgrade = " PIC reset failed. " ; break ;
case OTGW_ERROR_RETRIES : errorupgrade = " Too many retries. " ; break ;
case OTGW_ERROR_MISMATCHES : errorupgrade = " Too many mismatches. " ; break ;
default : errorupgrade = " Unknown state. " ; break ;
}
}
2021-02-14 14:31:21 +01:00
// Schelte's firmware integration
2021-02-08 01:35:51 +01:00
void fwupgradestart ( const char * hexfile ) {
OTGWError result ;
digitalWrite ( LED1 , LOW ) ;
result = OTGWSerial . startUpgrade ( hexfile ) ;
if ( result ! = OTGW_ERROR_NONE ) {
fwupgradedone ( result ) ;
} else {
OTGWSerial . registerFinishedCallback ( fwupgradedone ) ;
}
}
2021-02-20 17:49:56 +01:00
String checkforupdatepic ( String filename ) {
2021-02-19 12:44:45 +01:00
WiFiClient client ;
2021-02-19 01:48:31 +01:00
HTTPClient http ;
2021-02-20 17:49:56 +01:00
String latest = " " ;
2021-02-19 01:48:31 +01:00
int code ;
http . begin ( client , " http://otgw.tclcode.com/download/ " + filename ) ;
http . collectHeaders ( hexheaders , 2 ) ;
code = http . sendRequest ( " HEAD " ) ;
if ( code = = HTTP_CODE_OK ) {
for ( int i = 0 ; i < http . headers ( ) ; i + + ) {
2021-02-28 15:44:53 +01:00
DebugTf ( " %s: %s \r \n " , hexheaders [ i ] , http . header ( i ) . c_str ( ) ) ;
2021-02-19 01:48:31 +01:00
}
latest = http . header ( 1 ) ;
2021-02-28 15:44:53 +01:00
DebugTf ( " Update %s -> %s \r \n " , filename . c_str ( ) , latest . c_str ( ) ) ;
2021-02-19 01:48:31 +01:00
http . end ( ) ;
}
2021-02-20 17:49:56 +01:00
return latest ;
2021-02-19 01:48:31 +01:00
}
2021-02-14 14:31:21 +01:00
2021-02-18 01:13:54 +01:00
void refreshpic ( String filename , String version ) {
2021-02-14 14:31:21 +01:00
WiFiClient client ;
HTTPClient http ;
String latest ;
int code ;
2021-02-19 12:44:45 +01:00
2021-02-20 17:49:56 +01:00
if ( latest = checkforupdatepic ( filename ) ! = " " ) {
2021-02-14 14:31:21 +01:00
if ( latest ! = version ) {
2021-02-28 15:44:53 +01:00
DebugTf ( " Update %s: %s -> %s \r \n " , filename . c_str ( ) , version . c_str ( ) , latest . c_str ( ) ) ;
2021-02-14 14:31:21 +01:00
http . begin ( client , " http://otgw.tclcode.com/download/ " + filename ) ;
code = http . GET ( ) ;
if ( code = = HTTP_CODE_OK ) {
File f = LittleFS . open ( " / " + filename , " w " ) ;
if ( f ) {
http . writeToStream ( & f ) ;
f . close ( ) ;
String verfile = " / " + filename ;
verfile . replace ( " .hex " , " .ver " ) ;
f = LittleFS . open ( verfile , " w " ) ;
if ( f ) {
f . print ( latest + " \n " ) ;
f . close ( ) ;
DebugTf ( " Update successful \n " ) ;
}
}
}
}
}
http . end ( ) ;
}
2021-02-18 01:13:54 +01:00
void upgradepic ( ) {
2021-02-14 14:31:21 +01:00
String action = httpServer . arg ( " action " ) ;
String filename = httpServer . arg ( " name " ) ;
String version = httpServer . arg ( " version " ) ;
2021-02-18 01:13:54 +01:00
DebugTf ( " Action: %s %s %s \r \n " , action . c_str ( ) , filename . c_str ( ) , version . c_str ( ) ) ;
if ( action = = " upgrade " ) {
upgradepicnow ( String ( " / " + filename ) . c_str ( ) ) ;
} else if ( action = = " refresh " ) {
refreshpic ( filename , version ) ;
2021-02-14 14:31:21 +01:00
} else if ( action = = " delete " ) {
String path = " / " + filename ;
LittleFS . remove ( path ) ;
path . replace ( " .hex " , " .ver " ) ;
LittleFS . remove ( path ) ;
}
2021-02-19 00:28:21 +01:00
httpServer . sendHeader ( " Location " , " index.html#tabPICflash " , true ) ;
httpServer . send ( 303 , " text/html " , " <a href='index.html#tabPICflash'>Return</a> " ) ;
2021-02-14 14:31:21 +01:00
}
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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */