2020-10-25 20:35:34 +01:00
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2021-01-30 15:24:54 +01:00
* * Program : OTGW - Core . ino
2021-11-06 16:03:20 +01:00
* * Version : v0 .9 .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-03-27 22:26:11 +01:00
# define OTGWDebugTln(...) ({ if (bDebugOTmsg) DebugTln(__VA_ARGS__); })
# define OTGWDebugln(...) ({ if (bDebugOTmsg) Debugln(__VA_ARGS__); })
# define OTGWDebugTf(...) ({ if (bDebugOTmsg) DebugTf(__VA_ARGS__); })
# define OTGWDebugf(...) ({ if (bDebugOTmsg) Debugf(__VA_ARGS__); })
# define OTGWDebugT(...) ({ if (bDebugOTmsg) DebugT(__VA_ARGS__); })
# define OTGWDebug(...) ({ if (bDebugOTmsg) Debug(__VA_ARGS__); })
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-04-04 23:15:22 +02:00
sPICfwversion = " No version found " ; //reset versionstring
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 ' ) ;
2021-03-07 00:55:53 +01:00
resp . trim ( ) ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Received firmware version: [%s] [%s] (%d) \r \n " , CSTR ( resp ) , OTGWSerial . firmwareVersion ( ) , strlen ( OTGWSerial . firmwareVersion ( ) ) ) ;
2021-04-03 23:11:50 +02:00
bOTGWonline = ( resp . length ( ) > 0 ) ;
2021-04-04 23:15:22 +02:00
if ( bOTGWonline ) sPICfwversion = String ( OTGWSerial . firmwareVersion ( ) ) ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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 ( ) {
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " OTGW PIC firmware version = [%s] \r \n " , CSTR ( sPICfwversion ) ) ;
2021-03-06 10:52:51 +01:00
String latest = checkforupdatepic ( " gateway.hex " ) ;
if ( ! bOTGWonline ) {
sMessage = sPICfwversion ;
} else if ( latest ! = sPICfwversion ) {
sMessage = " New PIC version " + latest + " available! " ;
}
2021-03-15 22:50:59 +01:00
if ( ! checklittlefshash ( ) ) sMessage = " Flash your littleFS with matching version! " ;
2021-03-06 10:52:51 +01:00
}
2021-03-14 23:05:56 +01:00
//===================[ checkOTWGpicforupdate ]=====================
void sendOTGWbootcmd ( ) {
if ( ! settingOTGWcommandenable ) return ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " OTGW boot message = [%s] \r \n " , CSTR ( settingOTGWcommands ) ) ;
2021-03-14 23:05:56 +01:00
OTGWSerial . write ( CSTR ( settingOTGWcommands ) ) ;
OTGWSerial . flush ( ) ;
}
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-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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-03-27 22:26:11 +01:00
OTGWDebugTf ( " Send command: [%s] \r \n " , CSTR ( _cmd ) ) ;
2021-02-01 23:03:07 +01:00
//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-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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 ;
}
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-10-23 21:18:41 +02:00
OTGWDebugTln ( F ( " Setup Watchdog " ) ) ;
2021-03-27 22:26:11 +01:00
OTGWDebugTln ( F ( " INIT : I2C " ) ) ;
2021-02-02 00:22:46 +01:00
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 )
{
2021-03-27 22:26:11 +01:00
OTGWDebugTln ( F ( " INIT : Reset by WD! " ) ) ;
2020-10-25 20:35:34 +01:00
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-09-10 00:57:56 +02:00
void WatchDogEnabled ( byte stateWatchdog ) {
Wire . beginTransmission ( EXT_WD_I2C_ADDRESS ) ; //Nodoshop design uses the hardware WD on I2C, address 0x26
Wire . write ( 7 ) ; //Write to register 7, the action register
Wire . write ( stateWatchdog ) ; //1 = armed to reset, 0 = turned off
Wire . endTransmission ( ) ; //That's all there is...
}
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
}
2021-03-18 00:53:30 +01:00
yield ( ) ;
2020-10-25 20:35:34 +01:00
}
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 ;
2021-03-23 21:47:36 +01:00
return ( ( value < < 8 ) + valueLB ) ;
2020-10-25 20:35:34 +01:00
}
void OpenthermData : : u16 ( uint16_t value ) {
valueLB = value & 0xFF ;
valueHB = ( value > > 8 ) & 0xFF ;
}
int16_t OpenthermData : : s16 ( ) {
int16_t value = valueHB ;
2021-03-23 21:47:36 +01:00
return ( ( value < < 8 ) + valueLB ) ;
2020-10-25 20:35:34 +01:00
}
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 ) {
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ message_id ] , OTlookupitem ) ;
return OTlookupitem . label ;
2020-12-12 00:20:31 +01:00
} 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
2021-03-22 20:21:22 +01:00
// bit: description [ clear/0, set/1]
// 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
2021-01-03 23:12:19 +01:00
bool isCentralHeatingEnabled ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . MasterStatus & 0x01 ;
2021-01-03 23:12:19 +01:00
}
bool isDomesticHotWaterEnabled ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . MasterStatus & 0x02 ;
2021-01-03 23:12:19 +01:00
}
bool isCoolingEnabled ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . MasterStatus & 0x04 ;
2021-01-03 23:12:19 +01:00
}
bool isOutsideTemperatureCompensationActive ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . MasterStatus & 0x08 ;
2021-01-03 23:12:19 +01:00
}
bool isCentralHeating2enabled ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . MasterStatus & 0x10 ;
2021-01-03 23:12:19 +01:00
}
2020-10-25 20:35:34 +01:00
2021-01-03 23:12:19 +01:00
//Slave
2021-03-22 20:21:22 +01:00
// bit: description [ clear/0, set/1]
// 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
2021-01-03 23:12:19 +01:00
bool isFaultIndicator ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x01 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isCentralHeatingActive ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x02 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isDomesticHotWaterActive ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x04 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isFlameStatus ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x08 ;
2020-10-25 20:35:34 +01:00
}
2021-01-03 23:12:19 +01:00
bool isCoolingActive ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x10 ;
2020-10-25 20:35:34 +01:00
}
2021-02-10 00:56:33 +01:00
bool isCentralHeating2Active ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x20 ;
2021-02-10 00:56:33 +01:00
}
2021-01-03 23:12:19 +01:00
bool isDiagnosticIndicator ( ) {
2021-10-31 17:30:16 +01:00
return OTdataObject . SlaveStatus & 0x40 ;
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 ;
2021-03-18 00:53:30 +01:00
} //byte_to_binary
2020-10-25 20:35:34 +01:00
2021-03-23 21:47:36 +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
2021-10-31 17:30:16 +01:00
// OTGWDebugf("%s = %3.2f %s\r\n", OTlookupitem.label, _value , OTlookupitem.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 ) ;
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %s %s \r \n " , OTlookupitem . label , _msg , OTlookupitem . unit ) ;
2020-10-25 20:35:34 +01:00
//SendMQTT
2021-03-09 18:56:22 +01:00
sendMQTTData ( messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , _msg ) ;
2021-03-23 21:47:36 +01:00
return _value ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
int16_t print_s16 ( )
2020-12-12 00:20:31 +01:00
{
int16_t _value = OTdata . s16 ( ) ;
2021-10-31 17:30:16 +01:00
// OTGWDebugf("%s = %5d %s\r\n", OTlookupitem.label, _value, OTlookupitem.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 ) ;
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %s %s \r \n " , OTlookupitem . label , _msg , OTlookupitem . unit ) ;
2020-10-25 20:35:34 +01:00
//SendMQTT
2021-03-09 18:56:22 +01:00
sendMQTTData ( messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , _msg ) ;
2021-03-23 21:47:36 +01:00
return _value ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_s8s8 ( )
2021-10-22 00:24:44 +02:00
{
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %3d / %3d %s \r \n " , OTlookupitem . label , ( int8_t ) OTdata . valueHB , ( int8_t ) OTdata . valueLB , OTlookupitem . 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 ) ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %s %s \r \n " , OTlookupitem . label , _msg , OTlookupitem . unit ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2020-11-03 01:28:05 +01:00
//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 ) ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %s %s \r \n " , OTlookupitem . label , _msg , OTlookupitem . unit ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_u16 ( )
2020-12-12 00:20:31 +01:00
{
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 ) ;
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %s %s \r \n " , OTlookupitem . label , _msg , OTlookupitem . unit ) ;
2020-10-25 20:35:34 +01:00
//SendMQTT
2021-03-09 18:56:22 +01:00
sendMQTTData ( messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , _msg ) ;
2021-03-23 21:47:36 +01:00
return _value ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_status ( )
2021-11-03 19:01:02 +01:00
{
2020-11-06 21:13:09 +01:00
char _flag8_master [ 8 ] { 0 } ;
char _flag8_slave [ 8 ] { 0 } ;
2021-10-31 17:30:16 +01:00
2021-11-02 23:00:43 +01:00
if ( OTdata . masterslave = = 0 ) {
2021-10-30 17:50:01 +02:00
// Parse master bits
//bit: [clear/0, set/1]
// 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: Summer/winter mode [Summertime, Wintertime]
// 6: DHW blocking [ DHW not blocking, DHW blocking ]
// 7: reserved
_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 ) ? ' W ' : ' S ' ) ;
_flag8_master [ 6 ] = ( ( ( OTdata . valueHB ) & 0x40 ) ? ' B ' : ' - ' ) ;
_flag8_master [ 7 ] = ( ( ( OTdata . valueHB ) & 0x80 ) ? ' . ' : ' - ' ) ;
_flag8_master [ 8 ] = ' \0 ' ;
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = Master [%s] \r \n " , OTlookupitem . label , _flag8_master ) ;
2021-10-30 17:50:01 +02:00
//Master Status
sendMQTTData ( F ( " status_master " ) , _flag8_master ) ;
sendMQTTData ( F ( " ch_enable " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " dhw_enable " ) , ( ( ( OTdata . valueHB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " cooling_enable " ) , ( ( ( OTdata . valueHB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " otc_active " ) , ( ( ( OTdata . valueHB ) & 0x08 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " ch2_enable " ) , ( ( ( OTdata . valueHB ) & 0x10 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " summerwintertime " ) , ( ( ( OTdata . valueHB ) & 0x20 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " dhw_blocking " ) , ( ( ( OTdata . valueHB ) & 0x40 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-10-31 17:30:16 +01:00
OTdataObject . MasterStatus = OTdata . valueHB ;
2021-11-02 23:00:43 +01:00
} else {
2021-10-30 17:50:01 +02:00
// Parse slave bits
// 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: Electricity production [no eletric production, eletric production]
_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 ) ? ' P ' : ' - ' ) ;
_flag8_slave [ 8 ] = ' \0 ' ;
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = Slave [%s] \r \n " , OTlookupitem . label , _flag8_slave ) ;
2021-10-30 17:50:01 +02:00
//Slave Status
sendMQTTData ( F ( " status_slave " ) , _flag8_slave ) ;
sendMQTTData ( F ( " fault " ) , ( ( ( OTdata . valueLB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " centralheating " ) , ( ( ( OTdata . valueLB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " domestichotwater " ) , ( ( ( OTdata . valueLB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " flame " ) , ( ( ( OTdata . valueLB ) & 0x08 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " cooling " ) , ( ( ( OTdata . valueLB ) & 0x10 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " centralheating2 " ) , ( ( ( OTdata . valueLB ) & 0x20 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " diagnostic_indicator " ) , ( ( ( OTdata . valueLB ) & 0x40 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " eletric_production " ) , ( ( ( OTdata . valueLB ) & 0x80 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-05-01 21:36:22 +02:00
2021-10-31 17:30:16 +01:00
OTdataObject . SlaveStatus = OTdata . valueLB ;
}
2021-11-02 23:00:43 +01:00
2021-05-01 21:36:22 +02:00
uint16_t _value = OTdata . u16 ( ) ;
OTGWDebugTf ( " Status u16 [%04x] _value [%04x] hb [%02x] lb [%02x] \r \n " , OTdata . u16 ( ) , _value , OTdata . valueHB , OTdata . valueLB ) ;
return _value ;
}
uint16_t print_solar_storage_status ( )
{
char _msg [ 15 ] { 0 } ;
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-05-01 21:36:22 +02:00
2021-11-02 23:00:43 +01:00
if ( OTdata . masterslave = = 0 ) {
2021-10-31 17:30:16 +01:00
// Master Solar Storage
// ID101:HB012: Master Solar Storage: Solar mode
uint8_t MasterSolarMode = ( OTdata . valueHB ) & 0x7 ;
OTGWDebugf ( " %s = Solar Storage Master Mode [%d] \r \n " , OTlookupitem . label , MasterSolarMode ) ;
sendMQTTData ( F ( " solar_storage_master_mode " ) , itoa ( MasterSolarMode , _msg , 10 ) ) ; delayms ( 50 ) ;
OTdataObject . SolarMasterStatus = OTdata . valueHB ;
2021-11-02 23:00:43 +01:00
} else {
2021-10-31 17:30:16 +01:00
//Slave
// ID101:LB0: Slave Solar Storage: Fault indication
uint8_t SlaveSolarFaultIndicator = ( OTdata . valueLB ) & 0x01 ;
// ID101:LB123: Slave Solar Storage: Solar mode status
uint8_t SlaveSolarModeStatus = ( OTdata . valueLB > > 1 ) & 0x07 ;
// ID101:LB45: Slave Solar Storage: Solar status
uint8_t SlaveSolarStatus = ( OTdata . valueLB > > 4 ) & 0x03 ;
OTGWDebugf ( " %s = Slave Solar Fault Indicator [%d] \r \n " , OTlookupitem . label , SlaveSolarFaultIndicator ) ;
OTGWDebugf ( " %s = Slave Solar Mode Status [%d] \r \n " , OTlookupitem . label , SlaveSolarModeStatus ) ;
OTGWDebugf ( " %s = Slave Solar Status [%d] \r \n " , OTlookupitem . label , SlaveSolarStatus ) ;
sendMQTTData ( F ( " solar_storage_slave_fault_incidator " ) , ( ( SlaveSolarFaultIndicator ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " solar_storage_mode_status " ) , itoa ( SlaveSolarModeStatus , _msg , 10 ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " solar_storage_slave_status " ) , itoa ( SlaveSolarStatus , _msg , 10 ) ) ; delayms ( 50 ) ;
OTdataObject . SolarSlaveStatus = OTdata . valueLB ;
2021-11-02 23:00:43 +01:00
}
2021-05-01 21:36:22 +02:00
uint16_t _value = OTdata . u16 ( ) ;
OTGWDebugTf ( " Solar Storage Master / Slave Mode u16 [%04x] _value [%04x] hb [%02x] lb [%02x] \r \n " , OTdata . u16 ( ) , _value , OTdata . valueHB , OTdata . valueLB ) ;
return _value ;
}
uint16_t print_statusVH ( )
{
char _flag8_master [ 8 ] { 0 } ;
char _flag8_slave [ 8 ] { 0 } ;
2021-11-02 23:00:43 +01:00
if ( OTdata . masterslave = = 0 ) {
2021-10-30 17:50:01 +02:00
// Parse master bits
//bit: [clear/0, set/1]
// ID70:HB0: Master status ventilation / heat-recovery: Ventilation enable
// ID70:HB1: Master status ventilation / heat-recovery: Bypass postion
// ID70:HB2: Master status ventilation / heat-recovery: Bypass mode
// ID70:HB3: Master status ventilation / heat-recovery: Free ventilation mode
// 4: reserved
// 5: reserved
// 6: reserved
// 7: reserved
_flag8_master [ 0 ] = ( ( ( OTdata . valueHB ) & 0x01 ) ? ' V ' : ' - ' ) ;
_flag8_master [ 1 ] = ( ( ( OTdata . valueHB ) & 0x02 ) ? ' P ' : ' - ' ) ;
_flag8_master [ 2 ] = ( ( ( OTdata . valueHB ) & 0x04 ) ? ' M ' : ' - ' ) ;
_flag8_master [ 3 ] = ( ( ( OTdata . valueHB ) & 0x08 ) ? ' F ' : ' - ' ) ;
_flag8_master [ 4 ] = ( ( ( OTdata . valueHB ) & 0x10 ) ? ' . ' : ' - ' ) ;
_flag8_master [ 5 ] = ( ( ( OTdata . valueHB ) & 0x20 ) ? ' . ' : ' - ' ) ;
_flag8_master [ 6 ] = ( ( ( OTdata . valueHB ) & 0x40 ) ? ' . ' : ' - ' ) ;
_flag8_master [ 7 ] = ( ( ( OTdata . valueHB ) & 0x80 ) ? ' . ' : ' - ' ) ;
_flag8_master [ 8 ] = ' \0 ' ;
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = VH Master [%s] \r \n " , OTlookupitem . label , _flag8_master ) ;
2021-10-30 17:50:01 +02:00
//Master Status
sendMQTTData ( F ( " status_vh_master " ) , _flag8_master ) ;
sendMQTTData ( F ( " vh_ventilation_enabled " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_bypass_position " ) , ( ( ( OTdata . valueHB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_bypass_mode " ) , ( ( ( OTdata . valueHB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_free_ventlation_mode " ) , ( ( ( OTdata . valueHB ) & 0x08 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-10-31 17:30:16 +01:00
OTdataObject . MasterStatusVH = OTdata . valueLB ;
2021-11-02 23:00:43 +01:00
} else {
2021-10-30 17:50:01 +02:00
// Parse slave bits
// ID70:LB0: Slave status ventilation / heat-recovery: Fault indication
// ID70:LB1: Slave status ventilation / heat-recovery: Ventilation mode
// ID70:LB2: Slave status ventilation / heat-recovery: Bypass status
// ID70:LB3: Slave status ventilation / heat-recovery: Bypass automatic status
// ID70:LB4: Slave status ventilation / heat-recovery: Free ventilation status
// ID70:LB6: Slave status ventilation / heat-recovery: Diagnostic indication
_flag8_slave [ 0 ] = ( ( ( OTdata . valueLB ) & 0x01 ) ? ' F ' : ' - ' ) ;
_flag8_slave [ 1 ] = ( ( ( OTdata . valueLB ) & 0x02 ) ? ' V ' : ' - ' ) ;
_flag8_slave [ 2 ] = ( ( ( OTdata . valueLB ) & 0x04 ) ? ' P ' : ' - ' ) ;
_flag8_slave [ 3 ] = ( ( ( OTdata . valueLB ) & 0x08 ) ? ' A ' : ' - ' ) ;
_flag8_slave [ 4 ] = ( ( ( OTdata . valueLB ) & 0x10 ) ? ' F ' : ' - ' ) ;
_flag8_slave [ 5 ] = ( ( ( OTdata . valueLB ) & 0x20 ) ? ' . ' : ' - ' ) ;
_flag8_slave [ 6 ] = ( ( ( OTdata . valueLB ) & 0x40 ) ? ' D ' : ' - ' ) ;
_flag8_slave [ 7 ] = ( ( ( OTdata . valueLB ) & 0x80 ) ? ' . ' : ' - ' ) ;
_flag8_slave [ 8 ] = ' \0 ' ;
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = VH Slave [%s] \r \n " , OTlookupitem . label , _flag8_slave ) ;
2021-10-30 17:50:01 +02:00
//Slave Status
sendMQTTData ( F ( " status_vh_slave " ) , _flag8_slave ) ;
sendMQTTData ( F ( " vh_fault " ) , ( ( ( OTdata . valueLB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_ventlation_mode " ) , ( ( ( OTdata . valueLB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_bypass_status " ) , ( ( ( OTdata . valueLB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_bypass_automatic_status " ) , ( ( ( OTdata . valueLB ) & 0x08 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_free_ventliation_status " ) , ( ( ( OTdata . valueLB ) & 0x10 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_diagnostic_indicator " ) , ( ( ( OTdata . valueLB ) & 0x40 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-10-31 17:30:16 +01:00
OTdataObject . SlaveStatusVH = OTdata . valueLB ;
2021-10-30 17:50:01 +02:00
}
2021-03-13 10:35:18 +01:00
2021-03-24 21:23:22 +01:00
uint16_t _value = OTdata . u16 ( ) ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Status u16 [%04x] _value [%04x] hb [%02x] lb [%02x] \r \n " , OTdata . u16 ( ) , _value , OTdata . valueHB , OTdata . valueLB ) ;
2021-03-23 21:47:36 +01:00
return _value ;
2020-10-25 20:35:34 +01:00
}
2021-05-01 21:36:22 +02:00
2021-03-23 21:47:36 +01:00
uint16_t print_ASFflags ( )
2020-10-25 20:35:34 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = ASF flags[%s] OEM fault code [%3d] \r \n " , OTlookupitem . 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
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " ASF_flags " ) , byte_to_binary ( OTdata . valueHB ) ) ;
2020-11-06 21:13:09 +01:00
//OEM fault code
2021-03-07 00:44:28 +01:00
utoa ( OTdata . valueLB , _msg , 10 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " 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
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " service_request " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " lockout_reset " ) , ( ( ( OTdata . valueHB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " low_water_pressure " ) , ( ( ( OTdata . valueHB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " gas_flame_fault " ) , ( ( ( OTdata . valueHB ) & 0x08 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " air_pressure_fault " ) , ( ( ( OTdata . valueHB ) & 0x10 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " water_over_temperature " ) , ( ( ( OTdata . valueHB ) & 0x20 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-05-01 21:36:22 +02:00
return OTdata . u16 ( ) ;
}
uint16_t print_RBPflags ( )
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = M[%s] OEM fault code [%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueHB ) , OTdata . valueLB ) ;
2021-05-01 21:36:22 +02:00
//Build string for MQTT
char _msg [ 15 ] { 0 } ;
//Remote Boiler Paramaters
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " RBP_flags_transfer_enable " ) , byte_to_binary ( OTdata . valueHB ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " RBP_flags_read_write " ) , byte_to_binary ( OTdata . valueLB ) ) ; delayms ( 50 ) ;
2021-05-01 21:36:22 +02:00
//bit: [clear/0, set/1]
//0: DHW setpoint
//1: max CH setpoint
//2: reserved
//3: reserved
//4: reserved
//5: reserved
//6: reserved
//7: reserved
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " rbp_dhw_setpoint " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " rbp_max_ch_setpoint " ) , ( ( ( OTdata . valueHB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-05-01 21:36:22 +02:00
//bit: [clear/0, set/1]
//0: read write DHW setpoint
//1: read write max CH setpoint
//2: reserved
//3: reserved
//4: reserved
//5: reserved
//6: reserved
//7: reserved
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " rbp_rw_dhw_setpoint " ) , ( ( ( OTdata . valueLB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " rbp_rw_max_ch_setpoint " ) , ( ( ( OTdata . valueLB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-05-01 21:36:22 +02:00
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-11-06 21:13:09 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_slavememberid ( )
2020-11-06 21:13:09 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = Slave Config[%s] MemberID code [%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueHB ) , OTdata . valueLB ) ;
2020-11-06 21:58:29 +01:00
//Build string for SendMQTT
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " slave_configuration " ) , byte_to_binary ( OTdata . valueHB ) ) ;
2020-11-06 21:13:09 +01:00
char _msg [ 15 ] { 0 } ;
utoa ( OTdata . valueLB , _msg , 10 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " 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]
2021-05-01 21:36:22 +02:00
// 6: Remote water filling function
// 7: Heat/cool mode control
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " dhw_present " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " control_type_modulation " ) , ( ( ( OTdata . valueHB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " cooling_config " ) , ( ( ( OTdata . valueHB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " dhw_config " ) , ( ( ( OTdata . valueHB ) & 0x08 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " master_low_off_pump_control_function " ) , ( ( ( OTdata . valueHB ) & 0x10 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " ch2_present " ) , ( ( ( OTdata . valueHB ) & 0x20 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " remote_water_filling_function " ) , ( ( ( OTdata . valueHB ) & 0x40 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " heat_cool_mode_control " ) , ( ( ( OTdata . valueHB ) & 0x80 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-11-06 21:13:09 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_mastermemberid ( )
2020-11-06 21:13:09 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = Master Config[%s] MemberID code [%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueHB ) , OTdata . valueLB ) ;
2020-11-03 01:28:05 +01:00
//Build string for MQTT
char _msg [ 15 ] { 0 } ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " master_configuration " ) , byte_to_binary ( OTdata . valueHB ) ) ;
sendMQTTData ( F ( " master_configuration_smart_power " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ;
2021-05-01 21:36:22 +02:00
2020-11-03 01:28:05 +01:00
utoa ( OTdata . valueLB , _msg , 10 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " master_memberid_code " ) , _msg ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-10-25 20:35:34 +01:00
}
2021-05-01 21:36:22 +02:00
uint16_t print_vh_configmemberid ( )
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = VH Config[%s] MemberID code [%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueHB ) , OTdata . valueLB ) ;
2021-05-01 21:36:22 +02:00
//Build string for MQTT
char _msg [ 15 ] { 0 } ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " vh_configuration " ) , byte_to_binary ( OTdata . valueHB ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_configuration_system_type " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_configuration_bypass " ) , ( ( ( OTdata . valueHB ) & 0x02 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
sendMQTTData ( F ( " vh_configuration_speed_control " ) , ( ( ( OTdata . valueHB ) & 0x04 ) ? " ON " : " OFF " ) ) ; delayms ( 50 ) ;
2021-05-01 21:36:22 +02:00
utoa ( OTdata . valueLB , _msg , 10 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " vh_memberid_code " ) , _msg ) ;
2021-05-01 21:36:22 +02:00
return OTdata . u16 ( ) ;
}
uint16_t print_solarstorage_slavememberid ( )
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = Solar Storage Slave Config[%s] MemberID code [%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueHB ) , OTdata . valueLB ) ;
2021-05-01 21:36:22 +02:00
//Build string for SendMQTT
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " solar_storage_slave_configuration " ) , byte_to_binary ( OTdata . valueHB ) ) ;
2021-05-01 21:36:22 +02:00
char _msg [ 15 ] { 0 } ;
utoa ( OTdata . valueLB , _msg , 10 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " solar_storage_slave_memberid_code " ) , _msg ) ;
2021-05-01 21:36:22 +02:00
//ID103:HB0: Slave Configuration Solar Storage: System type1
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " solar_storage_system_type " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ;
2021-05-01 21:36:22 +02:00
return OTdata . u16 ( ) ;
}
2021-03-23 21:47:36 +01:00
uint16_t print_flag8u8 ( )
2020-10-25 20:35:34 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = M[%s] - [%3d] \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2021-03-24 21:23:22 +01:00
uint16_t _value = OTdata . u16 ( ) ;
2021-03-23 21:47:36 +01:00
return _value ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_flag8 ( )
2020-10-25 20:35:34 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = flag8 = [%s] - decimal = [%3d] \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , byte_to_binary ( OTdata . valueLB ) ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_flag8flag8 ( )
2021-03-09 00:32:27 +01:00
{
2020-11-03 01:28:05 +01:00
//Build string for MQTT
char _topic [ 50 ] { 0 } ;
//flag8 valueHB
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = HB flag8[%s] -[%3d] \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , byte_to_binary ( OTdata . valueHB ) ) ;
2020-11-03 01:28:05 +01:00
//flag8 valueLB
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = LB flag8[%s] - [%3d] \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , byte_to_binary ( OTdata . valueLB ) ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-10-25 20:35:34 +01:00
}
2021-05-01 21:36:22 +02:00
uint16_t print_vh_remoteparametersetting ( )
{
//Build string for MQTT
char _topic [ 50 ] { 0 } ;
//flag8 valueHB
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = HB flag8[%s] -[%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueHB ) , OTdata . valueHB ) ;
2021-05-01 21:36:22 +02:00
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _hb_flag8 " , sizeof ( _topic ) ) ;
sendMQTTData ( _topic , byte_to_binary ( OTdata . valueHB ) ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " vh_tramfer_enble_nominal_ventlation_value " ) , ( ( ( OTdata . valueHB ) & 0x01 ) ? " ON " : " OFF " ) ) ;
2021-05-01 21:36:22 +02:00
//flag8 valueLB
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = LB flag8[%s] - [%3d] \r \n " , OTlookupitem . label , byte_to_binary ( OTdata . valueLB ) , OTdata . valueLB ) ;
2021-05-01 21:36:22 +02:00
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _lb_flag8 " , sizeof ( _topic ) ) ;
sendMQTTData ( _topic , byte_to_binary ( OTdata . valueLB ) ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " vh_rw_nominal_ventlation_value " ) , ( ( ( OTdata . valueLB ) & 0x01 ) ? " ON " : " OFF " ) ) ;
2021-05-01 21:36:22 +02:00
return OTdata . u16 ( ) ;
}
uint16_t print_command ( )
{
//Known Commands
// ID4 (HB=1): Remote Request Boiler Lockout-reset
// ID4 (HB=2): Remote Request Water filling
// ID4 (HB=10): Remote Request Service request reset
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %3d / %3d %s \r \n " , OTlookupitem . label , ( uint8_t ) OTdata . valueHB , ( uint8_t ) OTdata . valueLB , OTlookupitem . unit ) ;
2021-05-01 21:36:22 +02:00
//Build string for MQTT
char _topic [ 50 ] { 0 } ;
char _msg [ 10 ] { 0 } ;
//flag8 valueHB
utoa ( ( OTdata . valueHB ) , _msg , 10 ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = HB u8[%s] [%3d] \r \n " , OTlookupitem . label , _msg , OTdata . valueHB ) ;
2021-05-01 21:36:22 +02:00
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _hb_u8 " , sizeof ( _topic ) ) ;
sendMQTTData ( _topic , _msg ) ;
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _remote_command " , sizeof ( _topic ) ) ;
switch ( OTdata . valueHB ) {
2021-10-31 17:30:16 +01:00
case 1 : sendMQTTData ( _topic , " Remote Request Boiler Lockout-reset " ) ; OTGWDebugf ( " %s = remote command [%s] \r \n " , OTlookupitem . label , " Remote Request Boiler Lockout-reset " ) ; break ;
case 2 : sendMQTTData ( _topic , " Remote Request Water filling " ) ; OTGWDebugf ( " %s = remote command [%s] \r \n " , OTlookupitem . label , " Remote Request Water filling " ) ; break ;
case 10 : sendMQTTData ( _topic , " Remote Request Service request reset " ) ; OTGWDebugf ( " %s = remote command [%s] \r \n " , OTlookupitem . label , " Remote Request Service request reset " ) ; break ;
default : sendMQTTData ( _topic , " Unknown command " ) ; OTGWDebugf ( " %s = remote command [%s] \r \n " , OTlookupitem . label , " Unknown command " ) ; break ;
2021-05-01 21:36:22 +02:00
}
//flag8 valueLB
utoa ( ( OTdata . valueLB ) , _msg , 10 ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = LB u8[%s] [%3d] \r \n " , OTlookupitem . label , _msg , OTdata . valueLB ) ;
2021-05-01 21:36:22 +02:00
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _lb_u8 " , sizeof ( _topic ) ) ;
sendMQTTData ( _topic , _msg ) ;
return OTdata . u16 ( ) ;
}
2021-03-23 21:47:36 +01:00
uint16_t print_u8u8 ( )
2021-03-09 00:32:27 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %3d / %3d %s \r \n " , OTlookupitem . label , ( uint8_t ) OTdata . valueHB , ( uint8_t ) OTdata . valueLB , OTlookupitem . 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 ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = HB u8[%s] [%3d] \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2020-11-03 01:28:05 +01:00
//flag8 valueLB
utoa ( ( OTdata . valueLB ) , _msg , 10 ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = LB u8[%s] [%3d] \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-10-25 20:35:34 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_date ( )
2021-03-09 18:52:58 +01:00
{
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %3d / %3d %s \r \n " , OTlookupitem . label , ( uint8_t ) OTdata . valueHB , ( uint8_t ) OTdata . valueLB , OTlookupitem . unit ) ;
2021-03-09 18:52:58 +01:00
//Build string for MQTT
char _topic [ 50 ] { 0 } ;
char _msg [ 10 ] { 0 } ;
//flag8 valueHB
utoa ( ( OTdata . valueHB ) , _msg , 10 ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = HB u8[%s] [%3d] \r \n " , OTlookupitem . label , _msg , OTdata . valueHB ) ;
2021-03-09 18:52:58 +01:00
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _month " , sizeof ( _topic ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2021-03-09 18:52:58 +01:00
//flag8 valueLB
utoa ( ( OTdata . valueLB ) , _msg , 10 ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = LB u8[%s] [%3d] \r \n " , OTlookupitem . label , _msg , OTdata . valueLB ) ;
2021-03-09 18:52:58 +01:00
strlcpy ( _topic , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) , sizeof ( _topic ) ) ;
strlcat ( _topic , " _day_of_month " , sizeof ( _topic ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , _msg ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2021-03-09 18:52:58 +01:00
}
2021-03-23 21:47:36 +01:00
uint16_t print_daytime ( )
2020-10-25 20:35:34 +01:00
{
//function to print data
2021-11-24 22:33:07 +01:00
const char * dayOfWeekName [ ] { " Unknown " , " Monday " , " Tuesday " , " Wednesday " , " Thursday " , " Friday " , " Saturday " , " Sunday " , " Unknown " } ;
2021-10-22 00:24:44 +02:00
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " %s = %s - %2d:%2d \r \n " , OTlookupitem . 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 ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , dayOfWeekName [ ( OTdata . valueHB > > 5 ) & 0x7 ] ) ;
2021-03-09 00:32:27 +01:00
//hour
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 , " _hour " , sizeof ( _topic ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , itoa ( ( OTdata . valueHB & 0x0F ) , _msg , 10 ) ) ;
2021-03-09 00:32:27 +01:00
//min
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 , " _minutes " , sizeof ( _topic ) ) ;
2021-03-09 18:56:22 +01:00
sendMQTTData ( _topic , itoa ( ( OTdata . valueLB ) , _msg , 10 ) ) ;
2021-03-30 23:37:52 +02:00
return OTdata . u16 ( ) ;
2020-10-25 20:35:34 +01:00
}
2021-01-31 23:43:52 +01:00
2020-10-25 20:35:34 +01:00
2021-06-30 21:51:31 +02:00
//===================[ Command Queue implementatoin ]=============================
2021-03-19 00:24:35 +01:00
# define OTGW_CMD_RETRY 5
2021-06-30 19:37:52 +02:00
# define OTGW_CMD_INTERVAL_MS 5000
2021-06-30 21:51:31 +02:00
# define OTGW_DELAY_SEND_MS 1000
2021-11-02 23:00:43 +01:00
# define MAX_QUEUE_MSGSIZE 127
2021-06-30 21:51:31 +02:00
/*
addOTWGcmdtoqueue adds a command to the queue .
First it checks the queue , if the command is in the queue , it ' s updated .
Otherwise it ' s simply added to the queue , unless there are no free queue slots .
*/
2021-11-15 21:32:19 +01:00
void addOTWGcmdtoqueue ( const char * buf , const int len , const bool force = false ) {
2021-03-19 00:24:35 +01:00
if ( ( len < 3 ) | | ( buf [ 2 ] ! = ' = ' ) ) {
//no valid command of less then 2 bytes
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " CmdQueue: Error:Not a valid command=[ " ) ;
2021-03-22 20:21:22 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebug ( ( char ) buf [ i ] ) ;
2021-03-22 20:21:22 +01:00
}
2021-03-27 22:26:11 +01:00
OTGWDebugf ( " ] (%d) \r \n " , len ) ;
2021-03-19 00:24:35 +01:00
}
//check to see if the cmd is in queue
bool foundcmd = false ;
int8_t insertptr = cmdptr ; //set insertprt to next empty slot
2021-11-15 21:32:19 +01:00
if ( ! force ) {
char cmd [ 2 ] ; memset ( cmd , 0 , sizeof ( cmd ) ) ;
memcpy ( cmd , buf , 2 ) ;
for ( int i = 0 ; i < cmdptr ; i + + ) {
if ( strstr ( cmdqueue [ i ] . cmd , cmd ) ) {
//found cmd exists, set the inertptr to found slot
foundcmd = true ;
insertptr = i ;
break ;
}
}
2021-03-19 00:24:35 +01:00
}
2021-03-27 22:26:11 +01:00
if ( foundcmd ) OTGWDebugTf ( " CmdQueue: Found cmd exists in slot [%d] \r \n " , insertptr ) ;
else OTGWDebugTf ( " CmdQueue: Adding cmd end of queue, slot [%d] \r \n " , insertptr ) ;
2021-03-19 23:50:52 +01:00
2021-03-19 00:24:35 +01:00
//insert to the queue
2021-06-30 19:37:52 +02:00
OTGWDebugTf ( " CmdQueue: Insert queue in slot[%d]: " , insertptr ) ;
OTGWDebug ( " cmd[ " ) ;
for ( int i = 0 ; i < len ; i + + ) {
OTGWDebug ( ( char ) buf [ i ] ) ;
}
OTGWDebugf ( " ] (%d) \r \n " , len ) ;
2021-11-15 21:32:19 +01:00
//copy the command into the queue
int cmdlen = min ( ( int ) len , ( int ) ( sizeof ( cmdqueue [ insertptr ] . cmd ) - 1 ) ) ;
memset ( cmdqueue [ insertptr ] . cmd , 0 , cmdlen + 1 ) ;
memcpy ( cmdqueue [ insertptr ] . cmd , buf , cmdlen ) ;
cmdqueue [ insertptr ] . cmdlen = cmdlen ;
2021-03-19 00:24:35 +01:00
cmdqueue [ insertptr ] . retrycnt = 0 ;
2021-06-30 19:37:52 +02:00
cmdqueue [ insertptr ] . due = millis ( ) + OTGW_DELAY_SEND_MS ; //due right away
2021-03-22 20:21:22 +01:00
2021-03-19 00:24:35 +01:00
//if not found
if ( ! foundcmd ) {
//if not reached max of queue
if ( cmdptr < CMDQUEUE_MAX ) {
cmdptr + + ; //next free slot
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Next free queue slot: [%d] \r \n " , cmdptr ) ;
2021-10-23 21:18:41 +02:00
} else OTGWDebugTln ( F ( " CmdQueue: Error: Reached max queue " ) ) ;
2021-03-27 22:26:11 +01:00
} else OTGWDebugTf ( " CmdQueue: Found command at: [%d] - [%d] \r \n " , insertptr , cmdptr ) ;
2021-03-18 00:53:30 +01:00
}
2021-03-19 00:24:35 +01:00
/*
handleOTGWqueue should be called every second from main loop .
This checks the queue for message are due to be resent .
If retry max is reached the cmd is delete from the queue
*/
2021-03-18 00:53:30 +01:00
void handleOTGWqueue ( ) {
2021-11-02 23:00:43 +01:00
// OTGWDebugTf("CmdQueue: Commands in queue [%d]\r\n", (int)cmdptr);
2021-03-22 20:21:22 +01:00
for ( int i = 0 ; i < cmdptr ; i + + ) {
2021-10-31 17:30:16 +01:00
OTGWDebugTf ( " CmdQueue: Checking due in queue slot[%d]:[%lu]=>[%lu] \r \n " , ( int ) i , ( unsigned long ) millis ( ) , ( unsigned long ) cmdqueue [ i ] . due ) ;
2021-06-30 19:37:52 +02:00
if ( millis ( ) > = cmdqueue [ i ] . due ) {
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Queue slot [%d] due \r \n " , i ) ;
2021-03-18 00:53:30 +01:00
sendOTGW ( cmdqueue [ i ] . cmd , cmdqueue [ i ] . cmdlen ) ;
2021-03-19 00:24:35 +01:00
cmdqueue [ i ] . retrycnt + + ;
2021-06-30 19:37:52 +02:00
cmdqueue [ i ] . due = millis ( ) + OTGW_CMD_INTERVAL_MS ;
2021-03-18 00:53:30 +01:00
if ( cmdqueue [ i ] . retrycnt > = OTGW_CMD_RETRY ) {
//max retry reached, so delete command from queue
2021-03-22 20:21:22 +01:00
for ( int j = i ; j < cmdptr ; j + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Moving [%d] => [%d] \r \n " , j + 1 , j ) ;
2021-03-18 00:53:30 +01:00
strlcpy ( cmdqueue [ j ] . cmd , cmdqueue [ j + 1 ] . cmd , sizeof ( cmdqueue [ i ] . cmd ) ) ;
cmdqueue [ j ] . cmdlen = cmdqueue [ j + 1 ] . cmdlen ;
cmdqueue [ j ] . retrycnt = cmdqueue [ j + 1 ] . retrycnt ;
cmdqueue [ j ] . due = cmdqueue [ j + 1 ] . due ;
}
cmdptr - - ;
}
2021-03-19 23:50:52 +01:00
// //exit queue handling, after 1 command
// return;
2021-03-18 00:53:30 +01:00
}
}
}
2021-03-19 00:24:35 +01:00
/*
checkOTGWcmdqueue ( buf , len )
This takes response from otgw and checks to see if the command was accepted .
Checks the response , and finds the command ( if it ' s there ) .
Then checks if incoming response matches what was to be set .
Only then it ' s deleted from the queue .
*/
void checkOTGWcmdqueue ( const char * buf , int len ) {
if ( ( len < 3 ) | | ( buf [ 2 ] ! = ' : ' ) ) {
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " CmdQueue: Error: Not a command response [ " ) ;
2021-03-22 20:21:22 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebug ( ( char ) buf [ i ] ) ;
2021-03-22 20:21:22 +01:00
}
2021-03-27 22:26:11 +01:00
OTGWDebugf ( " ] (%d) \r \n " , len ) ;
2021-03-19 00:24:35 +01:00
return ; //not a valid command response
}
2021-03-22 20:21:22 +01:00
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " CmdQueue: Checking if command is in in queue [ " ) ;
2021-03-22 20:21:22 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebug ( ( char ) buf [ i ] ) ;
2021-03-22 20:21:22 +01:00
}
2021-03-27 22:26:11 +01:00
OTGWDebugf ( " ] (%d) \r \n " , len ) ;
2021-03-22 20:21:22 +01:00
char cmd [ 3 ] ; memset ( cmd , 0 , sizeof ( cmd ) ) ;
char value [ 11 ] ; memset ( value , 0 , sizeof ( value ) ) ;
2021-03-18 00:53:30 +01:00
memcpy ( cmd , buf , 2 ) ;
2021-11-02 23:00:43 +01:00
memcpy ( value , buf + 3 , ( len - 3 < sizeof ( value ) - 1 ) ? ( len - 3 ) : ( sizeof ( value ) - 1 ) ) ;
2021-03-18 00:53:30 +01:00
for ( int i = 0 ; i < cmdptr ; i + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Checking [%2s]==>[%d]:[%s] from queue \r \n " , cmd , i , cmdqueue [ i ] . cmd ) ;
2021-03-18 00:53:30 +01:00
if ( strstr ( cmdqueue [ i ] . cmd , cmd ) ) {
//command found, check value
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Found cmd [%2s]==>[%d]:[%s] \r \n " , cmd , i , cmdqueue [ i ] . cmd ) ;
2021-03-22 20:21:22 +01:00
// if(strstr(cmdqueue[i].cmd, value)){
2021-03-18 00:53:30 +01:00
//value found, thus remove command from queue
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Found value [%s]==>[%d]:[%s] \r \n " , value , i , cmdqueue [ i ] . cmd ) ;
OTGWDebugTf ( " CmdQueue: Remove from queue [%d]:[%s] from queue \r \n " , i , cmdqueue [ i ] . cmd ) ;
2021-03-23 22:28:07 +01:00
for ( int j = i ; j < cmdptr ; j + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " CmdQueue: Moving [%d] => [%d] \r \n " , j + 1 , j ) ;
2021-03-18 00:53:30 +01:00
strlcpy ( cmdqueue [ j ] . cmd , cmdqueue [ j + 1 ] . cmd , sizeof ( cmdqueue [ i ] . cmd ) ) ;
cmdqueue [ j ] . cmdlen = cmdqueue [ j + 1 ] . cmdlen ;
cmdqueue [ j ] . retrycnt = cmdqueue [ j + 1 ] . retrycnt ;
cmdqueue [ j ] . due = cmdqueue [ j + 1 ] . due ;
}
cmdptr - - ;
2021-03-27 22:26:11 +01:00
// } else OTGWDebugTf("Error: Did not find value [%s]==>[%d]:[%s]\r\n", value, i, cmdqueue[i].cmd);
2021-03-18 00:53:30 +01:00
}
}
}
2020-10-25 20:35:34 +01:00
2021-06-30 21:51:31 +02:00
//===================[ Send buffer to OTGW ]=============================
/*
sendOTGW ( const char * buf , int len ) sends a string to the serial OTGW device .
The buffer is send out to OTGW on the serial device instantly , as long as there is space in the buffer .
*/
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-03-27 22:26:11 +01:00
//OTGWDebugf("Serial Write Buffer space = [%d] - needed [%d]\r\n",OTGWSerial.availableForWrite(), (len+2));
OTGWDebugT ( " Sending to Serial [ " ) ;
2020-12-13 03:53:47 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2021-03-27 22:26:11 +01:00
OTGWDebug ( ( char ) buf [ i ] ) ;
2020-12-13 03:53:47 +01:00
}
2021-03-27 22:26:11 +01:00
OTGWDebug ( " ] ( " ) ; OTGWDebug ( len ) ; OTGWDebug ( " ) " ) ; OTGWDebugln ( ) ;
2020-12-13 03:53:47 +01:00
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 ( ) ;
2021-03-27 22:26:11 +01:00
} else OTGWDebugln ( " Error: Write buffer not big enough! " ) ;
} else OTGWDebugln ( " Error: Serial device not found! " ) ;
2020-11-09 00:05:06 +01:00
}
2021-03-08 02:15:28 +01:00
/*
This function checks if the string received is a valid " raw OT message " .
Raw OTmessages are 9 chars long and start with TBARE when talking to OTGW PIC .
2021-06-30 21:51:31 +02:00
Message is not an OTmessage if length is not 9 long OR 3 th char is ' : ' ( = OTGW command response )
2021-03-08 02:15:28 +01:00
*/
bool isvalidotmsg ( const char * buf , int len ) {
char * chk = " TBARE " ;
2021-06-30 19:37:52 +02:00
bool _ret = ( len = = 9 ) ; //check 9 chars long
_ret & = ( buf [ 2 ] ! = ' : ' ) ; //not a otgw command response
_ret & = ( strchr ( chk , buf [ 0 ] ) ! = NULL ) ; //1 char matches any of 'B', 'T', 'A', 'R' or 'E'
2021-03-08 02:15:28 +01:00
return _ret ;
}
/*
Process OTGW messages coming from the PIC .
It knows about :
- raw OTmsg format
- error format
- . . .
*/
2021-03-18 00:53:30 +01:00
void processOTGW ( const char * buf , int len ) {
2021-03-28 18:45:15 +02:00
static timer_t epochBoilerlastseen = 0 ;
static timer_t epochThermostatlastseen = 0 ;
2021-10-24 10:53:18 +02:00
static bool bOTGWboilerpreviousstate = false ;
static bool bOTGWthermostatpreviousstate = false ;
2021-03-28 18:45:15 +02:00
static bool bOTGWpreviousstate = false ;
2021-03-08 02:15:28 +01:00
if ( isvalidotmsg ( buf , len ) ) {
2020-12-13 02:06:05 +01:00
//OT protocol messages are 9 chars long
2021-10-24 10:53:18 +02:00
if ( settingMQTTOTmessage ) sendMQTTData ( F ( " otmessage " ) , buf ) ;
//counter of number of OT messages processed
// static int32_t cntOTmessagesprocessed = 0;
// cntOTmessagesprocessed++;
// char _msg[15] {0};
// sendMQTTData(F("otmsg_count"), itoa(cntOTmessagesprocessed, _msg, 10));
2021-02-08 02:06:04 +01:00
// source of otmsg
if ( buf [ 0 ] = = ' B ' )
{
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " Boiler " ) ;
2021-05-02 18:43:17 +02:00
epochBoilerlastseen = now ( ) ;
2021-02-08 02:06:04 +01:00
} else if ( buf [ 0 ] = = ' T ' )
{
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " Thermostat " ) ;
2021-03-28 18:45:15 +02:00
epochThermostatlastseen = now ( ) ;
2021-03-08 02:15:28 +01:00
} else if ( buf [ 0 ] = = ' R ' )
2021-02-08 02:06:04 +01:00
{
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " Request Boiler " ) ;
2021-05-02 18:43:17 +02:00
epochBoilerlastseen = now ( ) ;
2021-02-08 02:06:04 +01:00
} else if ( buf [ 0 ] = = ' A ' )
{
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " Answer Themostat " ) ;
2021-03-28 18:45:15 +02:00
epochThermostatlastseen = now ( ) ;
2021-02-08 02:06:04 +01:00
} else if ( buf [ 0 ] = = ' E ' )
{
2021-03-27 22:26:11 +01:00
OTGWDebugT ( " Parity error " ) ;
2021-03-08 02:15:28 +01:00
}
2021-02-08 02:06:04 +01:00
2021-03-28 18:45:15 +02:00
//If the Boiler or Thermostat messages have not been seen for 30 seconds, then set the state to false.
bOTGWboilerstate = ( now ( ) < ( epochBoilerlastseen + 30 ) ) ;
2021-10-24 10:53:18 +02:00
if ( bOTGWboilerstate ! = bOTGWboilerpreviousstate ) {
sendMQTTData ( F ( " otgw-pic/boiler_connected " ) , CBOOLEAN ( bOTGWboilerstate ) ) ;
bOTGWboilerpreviousstate = bOTGWboilerstate ;
}
2021-03-28 18:45:15 +02:00
bOTGWthermostatstate = ( now ( ) < ( epochThermostatlastseen + 30 ) ) ;
2021-10-24 10:53:18 +02:00
if ( bOTGWthermostatstate ! = bOTGWthermostatpreviousstate ) {
sendMQTTData ( F ( " otgw-pic/thermostat_connected " ) , CBOOLEAN ( bOTGWthermostatstate ) ) ;
bOTGWthermostatpreviousstate = bOTGWthermostatstate ;
}
2021-03-28 18:45:15 +02:00
//If either Boiler or Thermostat is offline, then the OTGW is considered offline as a whole.
bOTGWonline = bOTGWboilerstate & & bOTGWthermostatstate ;
if ( bOTGWonline ! = bOTGWpreviousstate ) {
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " otgw-pic/pic_connected " ) , CBOOLEAN ( bOTGWonline ) ) ;
2021-03-31 08:39:34 +02:00
sendMQTT ( CSTR ( MQTTPubNamespace ) , CBOOLEAN ( bOTGWonline ) ) ;
// nodeMCU online/offline zelf naar 'otgw-firmware/' pushen
2021-03-28 18:45:15 +02:00
bOTGWpreviousstate = bOTGWonline ; //remember state, so we can detect statechanges
}
2020-12-13 02:06:05 +01:00
const char * bufval = buf + 1 ;
2021-11-06 16:02:32 +01:00
//uint32_t value = strtoul(bufval, NULL, 16);
uint32_t value = 0 ;
sscanf ( bufval , " %8x " , & value ) ;
//print OTmessage to debug
char otmsg [ 15 ] = { 0 } ;
memcpy ( otmsg , buf , len ) ;
OTGWDebugf ( " %s (%d) " , otmsg , len ) ;
OTGWDebugf ( " [%08x] " , value ) ;
2020-12-13 02:06:05 +01:00
//split 32bit value into the relevant OT protocol parts
2021-11-02 23:00:43 +01:00
OTdata . type = ( value > > 28 ) & 0x7 ; // byte 1 = take 3 bits that define msg msgType
OTdata . masterslave = ( OTdata . type > > 2 ) & 0x1 ; // MSB from type --> 0 = master and 1 = slave
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
2020-12-13 02:06:05 +01:00
//print message frame
2021-03-30 21:33:37 +02:00
//OTGWDebugf("\ttype[%3d] id[%3d] hb[%3d] lb[%3d]\t", OTdata.type, OTdata.id, OTdata.valueHB, OTdata.valueLB);
2020-12-13 02:06:05 +01:00
//print message Type and ID
2021-10-31 17:30:16 +01:00
OTGWDebugf ( " [MsgID=%3d] " , OTdata . id ) ;
OTGWDebugf ( " [%-16s] " , messageTypeToString ( static_cast < OpenThermMessageType > ( OTdata . type ) ) ) ;
OTGWDebugf ( " [%-30s] " , messageIDToString ( static_cast < OpenThermMessageID > ( OTdata . id ) ) ) ;
// OTGWDebugf("[M=%d]",OTdata.master);
OTGWDebug ( " \t " ) ;
2020-12-13 02:06:05 +01:00
2021-02-21 09:44:57 +01:00
//keep track of update
msglastupdated [ OTdata . id ] = now ( ) ;
2021-10-30 17:50:01 +02:00
//Read information from this OT message ready for use...
PROGMEM_readAnything ( & OTmap [ OTdata . id ] , OTlookupitem ) ;
//next step interpret the OT protocol
2021-11-02 23:00:43 +01:00
//On OT_WRITE_ACK or READ_ACK, or, status msgid's, then parse.
if ( ( static_cast < OpenThermMessageType > ( OTdata . type ) = = OT_READ_ACK ) & & ( ( OTlookupitem . msg = = OT_READ ) | | ( OTlookupitem . msg = = OT_RW ) ) | |
( static_cast < OpenThermMessageType > ( OTdata . type ) = = OT_WRITE_ACK ) & & ( ( OTlookupitem . msg = = OT_WRITE ) | | ( OTlookupitem . msg = = OT_RW ) ) | |
( static_cast < OpenThermMessageID > ( OTdata . id ) = = OT_Statusflags ) | |
( static_cast < OpenThermMessageID > ( OTdata . id ) = = OT_StatusVH ) | |
( static_cast < OpenThermMessageID > ( OTdata . id ) = = OT_SolarStorageMaster ) ) {
2021-10-30 17:50:01 +02:00
2021-03-27 22:26:11 +01:00
//#define OTprint(data, value, text, format) ({ data= value; OTGWDebugf("[%37s]", text); OTGWDebugf("= [format]", data)})
2020-12-13 02:06:05 +01:00
//interpret values f8.8
2021-03-31 08:39:34 +02:00
2021-01-20 19:46:31 +01:00
switch ( static_cast < OpenThermMessageID > ( OTdata . id ) ) {
2021-10-30 17:50:01 +02:00
case OT_Statusflags : OTdataObject . Statusflags = print_status ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_TSet : OTdataObject . TSet = print_f88 ( ) ; break ;
case OT_CoolingControl : OTdataObject . CoolingControl = print_f88 ( ) ; break ;
case OT_TsetCH2 : OTdataObject . TsetCH2 = print_f88 ( ) ; break ;
case OT_TrOverride : OTdataObject . TrOverride = print_f88 ( ) ; break ;
case OT_MaxRelModLevelSetting : OTdataObject . MaxRelModLevelSetting = print_f88 ( ) ; break ;
case OT_TrSet : OTdataObject . TrSet = print_f88 ( ) ; break ;
case OT_TrSetCH2 : OTdataObject . TrSetCH2 = print_f88 ( ) ; break ;
case OT_RelModLevel : OTdataObject . RelModLevel = print_f88 ( ) ; break ;
case OT_CHPressure : OTdataObject . CHPressure = print_f88 ( ) ; break ;
case OT_DHWFlowRate : OTdataObject . DHWFlowRate = print_f88 ( ) ; break ;
case OT_Tr : OTdataObject . Tr = print_f88 ( ) ; break ;
case OT_Tboiler : OTdataObject . Tboiler = print_f88 ( ) ; break ;
case OT_Tdhw : OTdataObject . Tdhw = print_f88 ( ) ; break ;
case OT_Toutside : OTdataObject . Toutside = print_f88 ( ) ; break ;
case OT_Tret : OTdataObject . Tret = print_f88 ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_Tsolarstorage : OTdataObject . Tsolarstorage = print_f88 ( ) ; break ;
case OT_Tsolarcollector : OTdataObject . Tsolarcollector = print_s16 ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_TflowCH2 : OTdataObject . TflowCH2 = print_f88 ( ) ; break ;
case OT_Tdhw2 : OTdataObject . Tdhw2 = print_f88 ( ) ; break ;
case OT_Texhaust : OTdataObject . Texhaust = print_s16 ( ) ; break ;
case OT_TdhwSet : OTdataObject . TdhwSet = print_f88 ( ) ; break ;
case OT_MaxTSet : OTdataObject . MaxTSet = print_f88 ( ) ; break ;
case OT_Hcratio : OTdataObject . Hcratio = print_f88 ( ) ; break ;
case OT_OpenThermVersionMaster : OTdataObject . OpenThermVersionMaster = print_f88 ( ) ; break ;
case OT_OpenThermVersionSlave : OTdataObject . OpenThermVersionSlave = print_f88 ( ) ; break ;
case OT_ASFflags : OTdataObject . ASFflags = print_ASFflags ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_MasterConfigMemberIDcode : OTdataObject . MasterConfigMemberIDcode = print_mastermemberid ( ) ; break ;
case OT_SlaveConfigMemberIDcode : OTdataObject . SlaveConfigMemberIDcode = print_slavememberid ( ) ; break ;
case OT_Command : OTdataObject . Command = print_command ( ) ; break ;
case OT_RBPflags : OTdataObject . RBPflags = print_RBPflags ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_TSP : OTdataObject . TSP = print_u8u8 ( ) ; break ;
case OT_TSPindexTSPvalue : OTdataObject . TSPindexTSPvalue = print_u8u8 ( ) ; break ;
case OT_FHBsize : OTdataObject . FHBsize = print_u8u8 ( ) ; break ;
case OT_FHBindexFHBvalue : OTdataObject . FHBindexFHBvalue = print_u8u8 ( ) ; break ;
case OT_MaxCapacityMinModLevel : OTdataObject . MaxCapacityMinModLevel = print_u8u8 ( ) ; break ;
case OT_DayTime : OTdataObject . DayTime = print_daytime ( ) ; break ;
case OT_Date : OTdataObject . Date = print_date ( ) ; break ;
case OT_Year : OTdataObject . Year = print_u16 ( ) ; break ;
case OT_TdhwSetUBTdhwSetLB : OTdataObject . TdhwSetUBTdhwSetLB = print_s8s8 ( ) ; break ;
case OT_MaxTSetUBMaxTSetLB : OTdataObject . MaxTSetUBMaxTSetLB = print_s8s8 ( ) ; break ;
case OT_HcratioUBHcratioLB : OTdataObject . HcratioUBHcratioLB = print_s8s8 ( ) ; break ;
case OT_RemoteOverrideFunction : OTdataObject . RemoteOverrideFunction = print_flag8 ( ) ; break ;
case OT_OEMDiagnosticCode : OTdataObject . OEMDiagnosticCode = print_u16 ( ) ; break ;
case OT_BurnerStarts : OTdataObject . BurnerStarts = print_u16 ( ) ; break ;
case OT_CHPumpStarts : OTdataObject . CHPumpStarts = print_u16 ( ) ; break ;
case OT_DHWPumpValveStarts : OTdataObject . DHWPumpValveStarts = print_u16 ( ) ; break ;
case OT_DHWBurnerStarts : OTdataObject . DHWBurnerStarts = print_u16 ( ) ; break ;
case OT_BurnerOperationHours : OTdataObject . BurnerOperationHours = print_u16 ( ) ; break ;
case OT_CHPumpOperationHours : OTdataObject . CHPumpOperationHours = print_u16 ( ) ; break ;
case OT_DHWPumpValveOperationHours : OTdataObject . DHWPumpValveOperationHours = print_u16 ( ) ; break ;
case OT_DHWBurnerOperationHours : OTdataObject . DHWBurnerOperationHours = print_u16 ( ) ; break ;
case OT_MasterVersion : OTdataObject . MasterVersion = print_u8u8 ( ) ; break ;
case OT_SlaveVersion : OTdataObject . SlaveVersion = print_u8u8 ( ) ; break ;
2021-11-02 23:00:43 +01:00
case OT_StatusVH : OTdataObject . StatusVH = print_statusVH ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_ControlSetpointVH : OTdataObject . ControlSetpointVH = print_u8u8 ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_ASFFaultCodeVH : OTdataObject . ASFFaultCodeVH = print_flag8u8 ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_DiagnosticCodeVH : OTdataObject . DiagnosticCodeVH = print_u16 ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_ConfigMemberIDVH : OTdataObject . ConfigMemberIDVH = print_vh_configmemberid ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_OpenthermVersionVH : OTdataObject . OpenthermVersionVH = print_f88 ( ) ; break ;
case OT_VersionTypeVH : OTdataObject . VersionTypeVH = print_u8u8 ( ) ; break ;
case OT_RelativeVentilation : OTdataObject . RelativeVentilation = print_u8u8 ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_RelativeHumidityExhaustAir : OTdataObject . RelativeHumidityExhaustAir = print_u8u8 ( ) ; break ;
case OT_CO2LevelExhaustAir : OTdataObject . CO2LevelExhaustAir = print_u16 ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_SupplyInletTemperature : OTdataObject . SupplyInletTemperature = print_f88 ( ) ; break ;
case OT_SupplyOutletTemperature : OTdataObject . SupplyOutletTemperature = print_f88 ( ) ; break ;
case OT_ExhaustInletTemperature : OTdataObject . ExhaustInletTemperature = print_f88 ( ) ; break ;
case OT_ExhaustOutletTemperature : OTdataObject . ExhaustOutletTemperature = print_f88 ( ) ; break ;
case OT_ActualExhaustFanSpeed : OTdataObject . ActualExhaustFanSpeed = print_u16 ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_ActualSupplyFanSpeed : OTdataObject . ActualSupplyFanSpeed = print_u16 ( ) ; break ;
case OT_RemoteParameterSettingVH : OTdataObject . RemoteParameterSettingVH = print_vh_remoteparametersetting ( ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_NominalVentilationValue : OTdataObject . NominalVentilationValue = print_u8u8 ( ) ; break ;
case OT_TSPNumberVH : OTdataObject . TSPNumberVH = print_u8u8 ( ) ; break ;
case OT_TSPEntryVH : OTdataObject . TSPEntryVH = print_u8u8 ( ) ; break ;
case OT_FaultBufferSizeVH : OTdataObject . FaultBufferSizeVH = print_u8u8 ( ) ; break ;
case OT_FaultBufferEntryVH : OTdataObject . FaultBufferEntryVH = print_u8u8 ( ) ; break ;
case OT_FanSpeed : OTdataObject . FanSpeed = print_u16 ( ) ; break ;
case OT_ElectricalCurrentBurnerFlame : OTdataObject . ElectricalCurrentBurnerFlame = print_f88 ( ) ; break ;
case OT_TRoomCH2 : OTdataObject . TRoomCH2 = print_f88 ( ) ; break ;
case OT_RelativeHumidity : OTdataObject . RelativeHumidity = print_u8u8 ( ) ; break ;
case OT_RFstrengthbatterylevel : OTdataObject . RFstrengthbatterylevel = print_u8u8 ( ) ; break ;
case OT_OperatingMode_HC1_HC2_DHW : OTdataObject . OperatingMode_HC1_HC2_DHW = print_u8u8 ( ) ; break ;
case OT_ElectricityProducerStarts : OTdataObject . ElectricityProducerStarts = print_u16 ( ) ; break ;
case OT_ElectricityProducerHours : OTdataObject . ElectricityProducerHours = print_u16 ( ) ; break ;
case OT_ElectricityProduction : OTdataObject . ElectricityProduction = print_u16 ( ) ; break ;
case OT_CumulativElectricityProduction : OTdataObject . CumulativElectricityProduction = print_u16 ( ) ; break ;
case OT_RemehadFdUcodes : OTdataObject . RemehadFdUcodes = print_u8u8 ( ) ; break ;
case OT_RemehaServicemessage : OTdataObject . RemehaServicemessage = print_u8u8 ( ) ; break ;
case OT_RemehaDetectionConnectedSCU : OTdataObject . RemehaDetectionConnectedSCU = print_u8u8 ( ) ; break ;
2021-10-31 17:30:16 +01:00
case OT_SolarStorageMaster : OTdataObject . SolarStorageStatus = print_solar_storage_status ( ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_SolarStorageASFflags : OTdataObject . SolarStorageASFflags = print_flag8u8 ( ) ; break ;
case OT_SolarStorageSlaveConfigMemberIDcode : OTdataObject . SolarStorageSlaveConfigMemberIDcode = print_solarstorage_slavememberid ( ) ; break ;
case OT_SolarStorageVersionType : OTdataObject . SolarStorageVersionType = print_u8u8 ( ) ; break ;
case OT_SolarStorageTSP : OTdataObject . SolarStorageTSP = print_u8u8 ( ) ; break ;
case OT_SolarStorageTSPindexTSPvalue : OTdataObject . SolarStorageTSPindexTSPvalue = print_u8u8 ( ) ; break ;
case OT_SolarStorageFHBsize : OTdataObject . SolarStorageFHBsize = print_u8u8 ( ) ; break ;
case OT_SolarStorageFHBindexFHBvalue : OTdataObject . SolarStorageFHBindexFHBvalue = print_u8u8 ( ) ; break ;
case OT_BurnerUnsuccessfulStarts : OTdataObject . BurnerUnsuccessfulStarts = print_u16 ( ) ; break ;
case OT_FlameSignalTooLow : OTdataObject . FlameSignalTooLow = print_u16 ( ) ; break ;
2021-03-30 21:33:37 +02:00
default : DebugTf ( " Unknown message [%02d] value [%04X] \r \n " ) ; break ;
2020-12-13 02:06:05 +01:00
}
2021-10-31 17:30:16 +01:00
} else OTGWDebugf ( " hb[%3d] lb[%3d] \r \n " , OTdata . valueHB , OTdata . valueLB ) ;
2021-03-18 00:53:30 +01:00
} else if ( buf [ 2 ] = = ' : ' ) { //seems to be a response to a command, so check to verify if it was
2021-03-19 00:24:35 +01:00
checkOTGWcmdqueue ( buf , len ) ;
2021-03-08 03:00:56 +01:00
} else if ( strstr ( buf , " Error 01 " ) ! = NULL ) {
2021-03-08 02:15:28 +01:00
OTdataObject . error01 + + ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Error 01 = %d \r \n " , OTdataObject . error01 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " Error 01 " ) , String ( OTdataObject . error01 ) ) ;
2021-03-08 03:00:56 +01:00
} else if ( strstr ( buf , " Error 02 " ) ! = NULL ) {
2021-03-08 02:15:28 +01:00
OTdataObject . error02 + + ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Error 02 = %d \r \n " , OTdataObject . error02 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " Error 02 " ) , String ( OTdataObject . error02 ) ) ;
2021-03-08 03:00:56 +01:00
} else if ( strstr ( buf , " Error 03 " ) ! = NULL ) {
2021-03-08 02:15:28 +01:00
OTdataObject . error03 + + ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Error 03 = %d \r \n " , OTdataObject . error03 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " Error 03 " ) , String ( OTdataObject . error03 ) ) ;
2021-03-08 03:00:56 +01:00
} else if ( strstr ( buf , " Error 04 " ) ! = NULL ) {
2021-03-08 02:15:28 +01:00
OTdataObject . error04 + + ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Error 04 = %d \r \n " , OTdataObject . error04 ) ;
2021-10-24 10:53:18 +02:00
sendMQTTData ( F ( " Error 04 " ) , String ( OTdataObject . error04 ) ) ;
2021-03-27 22:26:11 +01:00
} else OTGWDebugTf ( " Not processed, received from OTGW => [%s] [%d] \r \n " , buf , len ) ;
2021-03-08 02:15:28 +01:00
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
2021-11-02 23:00:43 +01:00
if ( outByte = = ' \r ' )
{ //on CR, do something...
2020-12-13 03:53:47 +01:00
sWrite [ bytes_write ] = 0 ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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 ) {
2021-04-23 00:24:04 +02:00
//detected [GW=R], then reset the gateway the gpio way
2021-10-23 21:18:41 +02:00
OTGWDebugTln ( F ( " Detected: GW=R. Reset gateway command executed. " ) ) ;
2021-01-24 22:10:03 +01:00
resetOTGW ( ) ;
2021-04-23 00:24:04 +02:00
} else if ( stricmp ( sWrite , " PS=1 " ) = = 0 ) {
//detected [PS=1], then PrintSummary mode = true --> From this point on you need to ask for summary.
bPrintSummarymode = true ;
//reset all msglastupdated in webui
for ( int i = 0 ; i < = OT_MSGID_MAX ; i + + ) {
msglastupdated [ i ] = 0 ; //clear epoch values
}
sMessage = " PS=1 mode; No UI updates. " ;
} else if ( stricmp ( sWrite , " PS=0 " ) = = 0 ) {
//detected [PS=0], then PrintSummary mode = OFF --> Raw mode is turned on again.
bPrintSummarymode = false ;
sMessage = " " ;
2021-01-24 22:10:03 +01:00
}
2020-12-13 03:53:47 +01:00
bytes_write = 0 ; //start next line
2021-11-02 23:00:43 +01:00
} else if ( outByte = = ' \n ' )
2020-12-13 03:53:47 +01:00
{
2021-11-02 23:00:43 +01:00
// on LF, skip
2020-12-13 03:53:47 +01:00
}
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
2021-11-02 23:00:43 +01:00
if ( inByte = = ' \r ' )
{ //on CR, 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
}
2021-11-02 23:00:43 +01:00
else if ( inByte = = ' \n ' )
{ // on LF, just ignore...
2020-12-13 02:06:05 +01:00
}
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-03-23 21:47:36 +01:00
case OT_TSet : return String ( OTdataObject . TSet ) ; break ;
case OT_CoolingControl : return String ( OTdataObject . CoolingControl ) ; break ;
case OT_TsetCH2 : return String ( OTdataObject . TsetCH2 ) ; break ;
case OT_TrOverride : return String ( OTdataObject . TrOverride ) ; break ;
case OT_MaxRelModLevelSetting : return String ( OTdataObject . MaxRelModLevelSetting ) ; break ;
case OT_TrSet : return String ( OTdataObject . TrSet ) ; break ;
case OT_TrSetCH2 : return String ( OTdataObject . TrSetCH2 ) ; break ;
case OT_RelModLevel : return String ( OTdataObject . RelModLevel ) ; break ;
case OT_CHPressure : return String ( OTdataObject . CHPressure ) ; break ;
case OT_DHWFlowRate : return String ( OTdataObject . DHWFlowRate ) ; break ;
case OT_Tr : return String ( OTdataObject . Tr ) ; break ;
case OT_Tboiler : return String ( OTdataObject . Tboiler ) ; break ;
case OT_Tdhw : return String ( OTdataObject . Tdhw ) ; break ;
case OT_Toutside : return String ( OTdataObject . Toutside ) ; break ;
case OT_Tret : return String ( OTdataObject . Tret ) ; break ;
2021-04-05 21:43:49 +02:00
case OT_Tsolarstorage : return String ( OTdataObject . Tsolarstorage ) ; break ;
case OT_Tsolarcollector : return String ( OTdataObject . Tsolarcollector ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_TflowCH2 : return String ( OTdataObject . TflowCH2 ) ; break ;
case OT_Tdhw2 : return String ( OTdataObject . Tdhw2 ) ; break ;
case OT_Texhaust : return String ( OTdataObject . Texhaust ) ; break ;
case OT_TdhwSet : return String ( OTdataObject . TdhwSet ) ; break ;
case OT_MaxTSet : return String ( OTdataObject . MaxTSet ) ; break ;
case OT_Hcratio : return String ( OTdataObject . Hcratio ) ; break ;
case OT_OpenThermVersionMaster : return String ( OTdataObject . OpenThermVersionMaster ) ; break ;
case OT_OpenThermVersionSlave : return String ( OTdataObject . OpenThermVersionSlave ) ; break ;
case OT_Statusflags : return String ( OTdataObject . Statusflags ) ; break ;
case OT_ASFflags : return String ( OTdataObject . ASFflags ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_MasterConfigMemberIDcode : return String ( OTdataObject . MasterConfigMemberIDcode ) ; break ;
case OT_SlaveConfigMemberIDcode : return String ( OTdataObject . SlaveConfigMemberIDcode ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_Command : return String ( OTdataObject . Command ) ; break ;
case OT_RBPflags : return String ( OTdataObject . RBPflags ) ; break ;
case OT_TSP : return String ( OTdataObject . TSP ) ; break ;
case OT_TSPindexTSPvalue : return String ( OTdataObject . TSPindexTSPvalue ) ; break ;
case OT_FHBsize : return String ( OTdataObject . FHBsize ) ; break ;
case OT_FHBindexFHBvalue : return String ( OTdataObject . FHBindexFHBvalue ) ; break ;
case OT_MaxCapacityMinModLevel : return String ( OTdataObject . MaxCapacityMinModLevel ) ; break ;
case OT_DayTime : return String ( OTdataObject . DayTime ) ; break ;
case OT_Date : return String ( OTdataObject . Date ) ; break ;
case OT_Year : return String ( OTdataObject . Year ) ; break ;
case OT_TdhwSetUBTdhwSetLB : return String ( OTdataObject . TdhwSetUBTdhwSetLB ) ; break ;
case OT_MaxTSetUBMaxTSetLB : return String ( OTdataObject . MaxTSetUBMaxTSetLB ) ; break ;
case OT_HcratioUBHcratioLB : return String ( OTdataObject . HcratioUBHcratioLB ) ; break ;
case OT_RemoteOverrideFunction : return String ( OTdataObject . RemoteOverrideFunction ) ; break ;
case OT_OEMDiagnosticCode : return String ( OTdataObject . OEMDiagnosticCode ) ; break ;
case OT_BurnerStarts : return String ( OTdataObject . BurnerStarts ) ; break ;
case OT_CHPumpStarts : return String ( OTdataObject . CHPumpStarts ) ; break ;
case OT_DHWPumpValveStarts : return String ( OTdataObject . DHWPumpValveStarts ) ; break ;
case OT_DHWBurnerStarts : return String ( OTdataObject . DHWBurnerStarts ) ; break ;
case OT_BurnerOperationHours : return String ( OTdataObject . BurnerOperationHours ) ; break ;
case OT_CHPumpOperationHours : return String ( OTdataObject . CHPumpOperationHours ) ; break ;
case OT_DHWPumpValveOperationHours : return String ( OTdataObject . DHWPumpValveOperationHours ) ; break ;
case OT_DHWBurnerOperationHours : return String ( OTdataObject . DHWBurnerOperationHours ) ; break ;
case OT_MasterVersion : return String ( OTdataObject . MasterVersion ) ; break ;
case OT_SlaveVersion : return String ( OTdataObject . SlaveVersion ) ; break ;
case OT_StatusVH : return String ( OTdataObject . StatusVH ) ; break ;
case OT_ControlSetpointVH : return String ( OTdataObject . ControlSetpointVH ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_ASFFaultCodeVH : return String ( OTdataObject . ASFFaultCodeVH ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_DiagnosticCodeVH : return String ( OTdataObject . DiagnosticCodeVH ) ; break ;
case OT_ConfigMemberIDVH : return String ( OTdataObject . ConfigMemberIDVH ) ; break ;
case OT_OpenthermVersionVH : return String ( OTdataObject . OpenthermVersionVH ) ; break ;
case OT_VersionTypeVH : return String ( OTdataObject . VersionTypeVH ) ; break ;
case OT_RelativeVentilation : return String ( OTdataObject . RelativeVentilation ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_RelativeHumidityExhaustAir : return String ( OTdataObject . RelativeHumidityExhaustAir ) ; break ;
case OT_CO2LevelExhaustAir : return String ( OTdataObject . CO2LevelExhaustAir ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_SupplyInletTemperature : return String ( OTdataObject . SupplyInletTemperature ) ; break ;
case OT_SupplyOutletTemperature : return String ( OTdataObject . SupplyOutletTemperature ) ; break ;
case OT_ExhaustInletTemperature : return String ( OTdataObject . ExhaustInletTemperature ) ; break ;
case OT_ExhaustOutletTemperature : return String ( OTdataObject . ExhaustOutletTemperature ) ; break ;
case OT_ActualExhaustFanSpeed : return String ( OTdataObject . ActualExhaustFanSpeed ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_ActualSupplyFanSpeed : return String ( OTdataObject . ActualSupplyFanSpeed ) ; break ;
2021-03-23 21:47:36 +01:00
case OT_RemoteParameterSettingVH : return String ( OTdataObject . RemoteParameterSettingVH ) ; break ;
case OT_NominalVentilationValue : return String ( OTdataObject . NominalVentilationValue ) ; break ;
case OT_TSPNumberVH : return String ( OTdataObject . TSPNumberVH ) ; break ;
case OT_TSPEntryVH : return String ( OTdataObject . TSPEntryVH ) ; break ;
case OT_FaultBufferSizeVH : return String ( OTdataObject . FaultBufferSizeVH ) ; break ;
case OT_FaultBufferEntryVH : return String ( OTdataObject . FaultBufferEntryVH ) ; break ;
case OT_FanSpeed : return String ( OTdataObject . FanSpeed ) ; break ;
case OT_ElectricalCurrentBurnerFlame : return String ( OTdataObject . ElectricalCurrentBurnerFlame ) ; break ;
case OT_TRoomCH2 : return String ( OTdataObject . TRoomCH2 ) ; break ;
case OT_RelativeHumidity : return String ( OTdataObject . RelativeHumidity ) ; break ;
case OT_RFstrengthbatterylevel : return String ( OTdataObject . RFstrengthbatterylevel ) ; break ;
case OT_OperatingMode_HC1_HC2_DHW : return String ( OTdataObject . OperatingMode_HC1_HC2_DHW ) ; break ;
case OT_ElectricityProducerStarts : return String ( OTdataObject . ElectricityProducerStarts ) ; break ;
case OT_ElectricityProducerHours : return String ( OTdataObject . ElectricityProducerHours ) ; break ;
case OT_ElectricityProduction : return String ( OTdataObject . ElectricityProduction ) ; break ;
case OT_CumulativElectricityProduction : return String ( OTdataObject . CumulativElectricityProduction ) ; break ;
case OT_RemehadFdUcodes : return String ( OTdataObject . RemehadFdUcodes ) ; break ;
case OT_RemehaServicemessage : return String ( OTdataObject . RemehaServicemessage ) ; break ;
case OT_RemehaDetectionConnectedSCU : return String ( OTdataObject . RemehaDetectionConnectedSCU ) ; break ;
2021-10-31 17:30:16 +01:00
case OT_SolarStorageMaster : return String ( OTdataObject . SolarStorageStatus ) ; break ;
2021-05-01 21:36:22 +02:00
case OT_SolarStorageASFflags : return String ( OTdataObject . SolarStorageASFflags ) ; break ;
case OT_SolarStorageSlaveConfigMemberIDcode : return String ( OTdataObject . SolarStorageSlaveConfigMemberIDcode ) ; break ;
case OT_SolarStorageVersionType : return String ( OTdataObject . SolarStorageVersionType ) ; break ;
case OT_SolarStorageTSP : return String ( OTdataObject . SolarStorageTSP ) ; break ;
case OT_SolarStorageTSPindexTSPvalue : return String ( OTdataObject . SolarStorageTSPindexTSPvalue ) ; break ;
case OT_SolarStorageFHBsize : return String ( OTdataObject . SolarStorageFHBsize ) ; break ;
case OT_SolarStorageFHBindexFHBvalue : return String ( OTdataObject . SolarStorageFHBindexFHBvalue ) ; break ;
2021-03-30 21:33:37 +02:00
default : return " Error: not implemented yet! \r \n " ;
2020-12-12 00:20:31 +01:00
}
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
2021-10-23 21:18:41 +02:00
OTGWDebugTln ( F ( " 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 ) {
2021-03-20 00:48:39 +01:00
2021-02-08 01:35:51 +01:00
switch ( result ) {
2021-03-20 00:48:39 +01:00
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-08 01:35:51 +01:00
}
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Upgrade finished: Errorcode = %d - %s - %d retries, %d errors \n " , result , CSTR ( errorupgrade ) , retries , errors ) ;
2021-02-08 01:35:51 +01:00
}
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-03-27 22:26:11 +01:00
OTGWDebugTf ( " %s: %s \r \n " , hexheaders [ i ] , http . header ( i ) . c_str ( ) ) ;
2021-02-19 01:48:31 +01:00
}
latest = http . header ( 1 ) ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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-03-27 22:26:11 +01:00
OTGWDebugTf ( " 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 ( ) ;
2021-03-27 22:26:11 +01:00
OTGWDebugTf ( " Update successful \n " ) ;
2021-02-14 14:31:21 +01:00
}
}
}
}
}
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-03-27 22:26:11 +01:00
OTGWDebugTf ( " Action: %s %s %s \r \n " , action . c_str ( ) , filename . c_str ( ) , version . c_str ( ) ) ;
2021-02-18 01:13:54 +01:00
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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */