mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 18:56:38 +00:00
Latest opentherm (#23704)
* Revert "Build firmware from Master branch" * Updated workflows * Added ENS160 (Air quality) and ENS210 (Temperature & Humidity) sensor * Revert "Added ENS160 (Air quality) and ENS210 (Temperature & Humidity) sensor" * pre-release 9.3.0 * Update README.md * Update xsns_05_ds18x20.ino Fix DS18x20 driver timing issue (#11270) * Prep release 9.4.0 * Prep 9.4.0 * Update Spanish and Italian * Update languages * Push rebuild * Update changelog * Update tasmota_version.h * Update CHANGELOG.md * Update README.md * Prep v10.1.0 * revert xlgt_01_ws2812 * Update xsns_69_opentherm.ino Add variable overrides * Revert "Update xsns_69_opentherm.ino" * Prep release * Prep release * Prep release 11.1 * Prep release 12.0 * Fix resolving MQTT and NTP servers - Fix resolving MQTT and NTP servers (#15816) - Bump version to v12.0.1 * Update RELEASENOTES.md * Update CHANGELOG.md * Release 12.1 * Release 12.1 * Revert camera changes * Prep v12.1.1 * Prep v12.1.1 * Prep v12.1.1 * OT bugfix * Prep release v12.2.0 * Prep v12.3.0 release * Revert Tuya change * add safeboot to release (#17393) * Update Tasmota_build_master.yml * Fix ESP8266 zifbee exception 3 * Update RELEASENOTES.md * fix needed depend. base32-images (#17406) * Fix ESP32 uploads * Create TASMOTA_FullLogo_Vector_White.svg * Fix support for non-sequential buttons and switches Fix support for non-sequential buttons and switches (#17967) * Fix duplicate EnergyTotal update * Update README.md * New workflow for release (#18722) * Update CHANGELOG.md * Update CHANGELOG.md * fix rs485 transmit * fix modbus * prep v13.1 * Prep v13.2.0 * Prep v13.3 * Update to v13.4.0 * Prep release v14.0.0 * Prep release v14.0.0 * Prep v14.1.0 * Prep v14.2.0 * Update CHANGELOG.md * Prep 14.4 * Update changelog * Prep v14.5.0 * remove abs from analog sensor * Update CHANGELOG.md * Prep release v14.6.0 * Update CHANGELOG.md * Prep v15.0.0 * change opentherm library * fixes for new open therm library * remove changes * remove changes --------- Co-authored-by: Jason2866 <24528715+Jason2866@users.noreply.github.com> Co-authored-by: Theo Arends <11044339+arendst@users.noreply.github.com> Co-authored-by: chrfriese123 <christoph@frieseonline.de> Co-authored-by: Alexey Pavlov <ap@profi.ru> Co-authored-by: Serge <60098151+Xjeater@users.noreply.github.com>
This commit is contained in:
parent
aa7d74dec0
commit
6080bdc472
@ -1,410 +0,0 @@
|
|||||||
/*
|
|
||||||
OpenTherm.cpp - OpenTherm Communication Library For Arduino, ESP8266
|
|
||||||
Copyright 2018, Ihor Melnyk
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "OpenTherm.h"
|
|
||||||
|
|
||||||
OpenTherm::OpenTherm(int inPin, int outPin, bool isSlave):
|
|
||||||
status(OpenThermStatus::OPTH_NOT_INITIALIZED),
|
|
||||||
inPin(inPin),
|
|
||||||
outPin(outPin),
|
|
||||||
isSlave(isSlave),
|
|
||||||
response(0),
|
|
||||||
responseStatus(OpenThermResponseStatus::OPTH_NONE),
|
|
||||||
responseTimestamp(0),
|
|
||||||
handleInterruptCallback(NULL),
|
|
||||||
processResponseCallback(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::begin(void(*handleInterruptCallback)(void), void(*processResponseCallback)(unsigned long, int))
|
|
||||||
{
|
|
||||||
pinMode(inPin, INPUT);
|
|
||||||
pinMode(outPin, OUTPUT);
|
|
||||||
if (handleInterruptCallback != NULL) {
|
|
||||||
this->handleInterruptCallback = handleInterruptCallback;
|
|
||||||
attachInterrupt(digitalPinToInterrupt(inPin), handleInterruptCallback, CHANGE);
|
|
||||||
}
|
|
||||||
activateBoiler();
|
|
||||||
status = OpenThermStatus::OPTH_READY;
|
|
||||||
this->processResponseCallback = processResponseCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::begin(void(*handleInterruptCallback)(void))
|
|
||||||
{
|
|
||||||
begin(handleInterruptCallback, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICACHE_RAM_ATTR OpenTherm::isReady()
|
|
||||||
{
|
|
||||||
return status == OpenThermStatus::OPTH_READY;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ICACHE_RAM_ATTR OpenTherm::readState() {
|
|
||||||
return digitalRead(inPin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::setActiveState() {
|
|
||||||
digitalWrite(outPin, LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::setIdleState() {
|
|
||||||
digitalWrite(outPin, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::activateBoiler() {
|
|
||||||
setIdleState();
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::sendBit(bool high) {
|
|
||||||
if (high) setActiveState(); else setIdleState();
|
|
||||||
delayMicroseconds(500);
|
|
||||||
if (high) setIdleState(); else setActiveState();
|
|
||||||
delayMicroseconds(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::sendRequestAync(unsigned long request)
|
|
||||||
{
|
|
||||||
//Serial.println("Request: " + String(request, HEX));
|
|
||||||
noInterrupts();
|
|
||||||
const bool ready = isReady();
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
if (!ready)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
status = OpenThermStatus::OPTH_REQUEST_SENDING;
|
|
||||||
response = 0;
|
|
||||||
responseStatus = OpenThermResponseStatus::OPTH_NONE;
|
|
||||||
|
|
||||||
sendBit(HIGH); //start bit
|
|
||||||
for (int i = 31; i >= 0; i--) {
|
|
||||||
sendBit(bitRead(request, i));
|
|
||||||
}
|
|
||||||
sendBit(HIGH); //stop bit
|
|
||||||
setIdleState();
|
|
||||||
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_WAITING;
|
|
||||||
responseTimestamp = micros();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::sendRequest(unsigned long request)
|
|
||||||
{
|
|
||||||
if (!sendRequestAync(request)) return 0;
|
|
||||||
while (!isReady()) {
|
|
||||||
process();
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::sendResponse(unsigned long request)
|
|
||||||
{
|
|
||||||
status = OpenThermStatus::OPTH_REQUEST_SENDING;
|
|
||||||
response = 0;
|
|
||||||
responseStatus = OpenThermResponseStatus::OPTH_NONE;
|
|
||||||
|
|
||||||
sendBit(HIGH); //start bit
|
|
||||||
for (int i = 31; i >= 0; i--) {
|
|
||||||
sendBit(bitRead(request, i));
|
|
||||||
}
|
|
||||||
sendBit(HIGH); //stop bit
|
|
||||||
setIdleState();
|
|
||||||
status = OpenThermStatus::OPTH_READY;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenThermResponseStatus OpenTherm::getLastResponseStatus()
|
|
||||||
{
|
|
||||||
return responseStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR OpenTherm::handleInterrupt()
|
|
||||||
{
|
|
||||||
if (isReady())
|
|
||||||
{
|
|
||||||
if (isSlave && readState() == HIGH) {
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_WAITING;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long newTs = micros();
|
|
||||||
if (status == OpenThermStatus::OPTH_RESPONSE_WAITING) {
|
|
||||||
if (readState() == HIGH) {
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_START_BIT;
|
|
||||||
responseTimestamp = newTs;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_INVALID;
|
|
||||||
responseTimestamp = newTs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (status == OpenThermStatus::OPTH_RESPONSE_START_BIT) {
|
|
||||||
if ((newTs - responseTimestamp < 750) && readState() == LOW) {
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_RECEIVING;
|
|
||||||
responseTimestamp = newTs;
|
|
||||||
responseBitIndex = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_INVALID;
|
|
||||||
responseTimestamp = newTs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (status == OpenThermStatus::OPTH_RESPONSE_RECEIVING) {
|
|
||||||
if ((newTs - responseTimestamp) > 750) {
|
|
||||||
if (responseBitIndex < 32) {
|
|
||||||
response = (response << 1) | !readState();
|
|
||||||
responseTimestamp = newTs;
|
|
||||||
responseBitIndex++;
|
|
||||||
}
|
|
||||||
else { //stop bit
|
|
||||||
status = OpenThermStatus::OPTH_RESPONSE_READY;
|
|
||||||
responseTimestamp = newTs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::process()
|
|
||||||
{
|
|
||||||
noInterrupts();
|
|
||||||
OpenThermStatus st = status;
|
|
||||||
unsigned long ts = responseTimestamp;
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
if (st == OpenThermStatus::OPTH_READY) return;
|
|
||||||
unsigned long newTs = micros();
|
|
||||||
if (st != OpenThermStatus::OPTH_NOT_INITIALIZED && (newTs - ts) > 1000000) {
|
|
||||||
status = OpenThermStatus::OPTH_READY;
|
|
||||||
responseStatus = OpenThermResponseStatus::OPTH_TIMEOUT;
|
|
||||||
if (processResponseCallback != NULL) {
|
|
||||||
processResponseCallback(response, responseStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (st == OpenThermStatus::OPTH_RESPONSE_INVALID) {
|
|
||||||
status = OpenThermStatus::OPTH_DELAY;
|
|
||||||
responseStatus = OpenThermResponseStatus::OPTH_INVALID;
|
|
||||||
if (processResponseCallback != NULL) {
|
|
||||||
processResponseCallback(response, responseStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (st == OpenThermStatus::OPTH_RESPONSE_READY) {
|
|
||||||
status = OpenThermStatus::OPTH_DELAY;
|
|
||||||
responseStatus = (isSlave ? isValidRequest(response) : isValidResponse(response)) ? OpenThermResponseStatus::OPTH_SUCCESS : OpenThermResponseStatus::OPTH_INVALID;
|
|
||||||
if (processResponseCallback != NULL) {
|
|
||||||
processResponseCallback(response, responseStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (st == OpenThermStatus::OPTH_DELAY) {
|
|
||||||
if ((newTs - ts) > 100000) {
|
|
||||||
status = OpenThermStatus::OPTH_READY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::parity(unsigned long frame) //odd parity
|
|
||||||
{
|
|
||||||
byte p = 0;
|
|
||||||
while (frame > 0)
|
|
||||||
{
|
|
||||||
if (frame & 1) p++;
|
|
||||||
frame = frame >> 1;
|
|
||||||
}
|
|
||||||
return (p & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenThermMessageType OpenTherm::getMessageType(unsigned long message)
|
|
||||||
{
|
|
||||||
OpenThermMessageType msg_type = static_cast<OpenThermMessageType>((message >> 28) & 7);
|
|
||||||
return msg_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenThermMessageID OpenTherm::getDataID(unsigned long frame)
|
|
||||||
{
|
|
||||||
return (OpenThermMessageID)((frame >> 16) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data)
|
|
||||||
{
|
|
||||||
unsigned long request = data;
|
|
||||||
if (type == OpenThermMessageType::OPTH_WRITE_DATA) {
|
|
||||||
request |= 1ul << 28;
|
|
||||||
}
|
|
||||||
request |= ((unsigned long)id) << 16;
|
|
||||||
if (OpenTherm::parity(request)) request |= (1ul << 31);
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data)
|
|
||||||
{
|
|
||||||
unsigned long response = data;
|
|
||||||
response |= type << 28;
|
|
||||||
response |= ((unsigned long)id) << 16;
|
|
||||||
if (OpenTherm::parity(response)) response |= (1ul << 31);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isValidResponse(unsigned long response)
|
|
||||||
{
|
|
||||||
if (OpenTherm::parity(response)) return false;
|
|
||||||
byte msgType = (response << 1) >> 29;
|
|
||||||
return msgType == OPTH_READ_ACK || msgType == OPTH_WRITE_ACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isValidRequest(unsigned long request)
|
|
||||||
{
|
|
||||||
if (OpenTherm::parity(request)) return false;
|
|
||||||
byte msgType = (request << 1) >> 29;
|
|
||||||
return msgType == OPTH_READ_DATA || msgType == OPTH_WRITE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenTherm::end() {
|
|
||||||
if (this->handleInterruptCallback != NULL) {
|
|
||||||
detachInterrupt(digitalPinToInterrupt(inPin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *OpenTherm::statusToString(OpenThermResponseStatus status)
|
|
||||||
{
|
|
||||||
switch (status) {
|
|
||||||
case OPTH_NONE: return "NONE";
|
|
||||||
case OPTH_SUCCESS: return "SUCCESS";
|
|
||||||
case OPTH_INVALID: return "INVALID";
|
|
||||||
case OPTH_TIMEOUT: return "TIMEOUT";
|
|
||||||
default: return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *OpenTherm::messageTypeToString(OpenThermMessageType message_type)
|
|
||||||
{
|
|
||||||
switch (message_type) {
|
|
||||||
case OPTH_READ_DATA: return "READ_DATA";
|
|
||||||
case OPTH_WRITE_DATA: return "WRITE_DATA";
|
|
||||||
case OPTH_INVALID_DATA: return "INVALID_DATA";
|
|
||||||
case OPTH_RESERVED: return "RESERVED";
|
|
||||||
case OPTH_READ_ACK: return "READ_ACK";
|
|
||||||
case OPTH_WRITE_ACK: return "WRITE_ACK";
|
|
||||||
case OPTH_DATA_INVALID: return "DATA_INVALID";
|
|
||||||
case OPTH_UNKNOWN_DATA_ID: return "UNKNOWN_DATA_ID";
|
|
||||||
default: return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//building requests
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2) {
|
|
||||||
unsigned int data = enableCentralHeating | (enableHotWater << 1) | (enableCooling << 2) | (enableOutsideTemperatureCompensation << 3) | (enableCentralHeating2 << 4);
|
|
||||||
data <<= 8;
|
|
||||||
return buildRequest(OpenThermMessageType::OPTH_READ_DATA, OpenThermMessageID::Status, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildSetBoilerTemperatureRequest(float temperature) {
|
|
||||||
unsigned int data = temperatureToData(temperature);
|
|
||||||
return buildRequest(OpenThermMessageType::OPTH_WRITE_DATA, OpenThermMessageID::TSet, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildSetHotWaterTemperatureRequest(float temperature) {
|
|
||||||
unsigned int data = temperatureToData(temperature);
|
|
||||||
return buildRequest(OpenThermMessageType::OPTH_WRITE_DATA, OpenThermMessageID::TdhwSet, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildGetBoilerTemperatureRequest() {
|
|
||||||
return buildRequest(OpenThermMessageType::OPTH_READ_DATA, OpenThermMessageID::Tboiler, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::buildSlaveConfigurationRequest() {
|
|
||||||
return buildRequest(OpenThermMessageType::OPTH_READ_DATA, OpenThermMessageID::SConfigSMemberIDcode, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//parsing responses
|
|
||||||
bool OpenTherm::isFault(unsigned long response) {
|
|
||||||
return response & 0x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isCentralHeatingActive(unsigned long response) {
|
|
||||||
return response & 0x2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isHotWaterActive(unsigned long response) {
|
|
||||||
return response & 0x4;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isFlameOn(unsigned long response) {
|
|
||||||
return response & 0x8;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isCoolingActive(unsigned long response) {
|
|
||||||
return response & 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::isDiagnostic(unsigned long response) {
|
|
||||||
return response & 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t OpenTherm::getUInt(const unsigned long response) {
|
|
||||||
const uint16_t u88 = response & 0xffff;
|
|
||||||
return u88;
|
|
||||||
}
|
|
||||||
|
|
||||||
float OpenTherm::getFloat(const unsigned long response) {
|
|
||||||
const uint16_t u88 = getUInt(response);
|
|
||||||
const float f = (u88 & 0x8000) ? -(0x10000L - u88) / 256.0f : u88 / 256.0f;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int OpenTherm::temperatureToData(float temperature) {
|
|
||||||
if (temperature < 0) temperature = 0;
|
|
||||||
if (temperature > 100) temperature = 100;
|
|
||||||
unsigned int data = (unsigned int)(temperature * 256);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//basic requests
|
|
||||||
|
|
||||||
unsigned long OpenTherm::setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2) {
|
|
||||||
return sendRequest(buildSetBoilerStatusRequest(enableCentralHeating, enableHotWater, enableCooling, enableOutsideTemperatureCompensation, enableCentralHeating2));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::setBoilerTemperature(float temperature) {
|
|
||||||
unsigned long response = sendRequest(buildSetBoilerTemperatureRequest(temperature));
|
|
||||||
return isValidResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenTherm::setHotWaterTemperature(float temperature) {
|
|
||||||
unsigned long response = sendRequest(buildSetHotWaterTemperatureRequest(temperature));
|
|
||||||
return isValidResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
float OpenTherm::getBoilerTemperature() {
|
|
||||||
unsigned long response = sendRequest(buildGetBoilerTemperatureRequest());
|
|
||||||
return isValidResponse(response) ? getFloat(response) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float OpenTherm::getReturnTemperature() {
|
|
||||||
unsigned long response = sendRequest(buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::Tret, 0));
|
|
||||||
return isValidResponse(response) ? getFloat(response) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float OpenTherm::getModulation() {
|
|
||||||
unsigned long response = sendRequest(buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::RelModLevel, 0));
|
|
||||||
return isValidResponse(response) ? getFloat(response) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float OpenTherm::getPressure() {
|
|
||||||
unsigned long response = sendRequest(buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::CHPressure, 0));
|
|
||||||
return isValidResponse(response) ? getFloat(response) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char OpenTherm::getFault() {
|
|
||||||
return ((sendRequest(buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::ASFflags, 0)) >> 8) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long OpenTherm::getSlaveConfiguration() {
|
|
||||||
return sendRequest(buildSlaveConfigurationRequest());
|
|
||||||
}
|
|
@ -1,193 +0,0 @@
|
|||||||
/*
|
|
||||||
OpenTherm.h - OpenTherm Library for the ESP8266/Arduino platform
|
|
||||||
https://github.com/ihormelnyk/OpenTherm
|
|
||||||
http://ihormelnyk.com/pages/OpenTherm
|
|
||||||
Licensed under MIT license
|
|
||||||
Copyright 2018, Ihor Melnyk
|
|
||||||
|
|
||||||
Frame Structure:
|
|
||||||
P MGS-TYPE SPARE DATA-ID DATA-VALUE
|
|
||||||
0 000 0000 00000000 00000000 00000000
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OpenTherm_h
|
|
||||||
#define OpenTherm_h
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
enum OpenThermResponseStatus {
|
|
||||||
OPTH_NONE,
|
|
||||||
OPTH_SUCCESS,
|
|
||||||
OPTH_INVALID,
|
|
||||||
OPTH_TIMEOUT
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum OpenThermMessageType {
|
|
||||||
/* Master to Slave */
|
|
||||||
OPTH_READ_DATA = B000,
|
|
||||||
OPTH_READ = OPTH_READ_DATA, // for backwared compatibility
|
|
||||||
OPTH_WRITE_DATA = B001,
|
|
||||||
OPTH_WRITE = OPTH_WRITE_DATA, // for backwared compatibility
|
|
||||||
OPTH_INVALID_DATA = B010,
|
|
||||||
OPTH_RESERVED = B011,
|
|
||||||
/* Slave to Master */
|
|
||||||
OPTH_READ_ACK = B100,
|
|
||||||
OPTH_WRITE_ACK = B101,
|
|
||||||
OPTH_DATA_INVALID = B110,
|
|
||||||
OPTH_UNKNOWN_DATA_ID = B111
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef OpenThermMessageType OpenThermRequestType; // for backwared compatibility
|
|
||||||
|
|
||||||
enum OpenThermMessageID {
|
|
||||||
Status, // flag8 / flag8 Master and Slave Status flags.
|
|
||||||
TSet, // f8.8 Control setpoint ie CH water temperature setpoint (°C)
|
|
||||||
MConfigMMemberIDcode, // flag8 / u8 Master Configuration Flags / Master MemberID Code
|
|
||||||
SConfigSMemberIDcode, // flag8 / u8 Slave Configuration Flags / Slave MemberID Code
|
|
||||||
Command, // u8 / u8 Remote Command
|
|
||||||
ASFflags, // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code
|
|
||||||
RBPflags, // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags
|
|
||||||
CoolingControl, // f8.8 Cooling control signal (%)
|
|
||||||
TsetCH2, // f8.8 Control setpoint for 2e CH circuit (°C)
|
|
||||||
TrOverride, // f8.8 Remote override room setpoint
|
|
||||||
TSP, // u8 / u8 Number of Transparent-Slave-Parameters supported by slave
|
|
||||||
TSPindexTSPvalue, // u8 / u8 Index number / Value of referred-to transparent slave parameter.
|
|
||||||
FHBsize, // u8 / u8 Size of Fault-History-Buffer supported by slave
|
|
||||||
FHBindexFHBvalue, // u8 / u8 Index number / Value of referred-to fault-history buffer entry.
|
|
||||||
MaxRelModLevelSetting, // f8.8 Maximum relative modulation level setting (%)
|
|
||||||
MaxCapacityMinModLevel, // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%)
|
|
||||||
TrSet, // f8.8 Room Setpoint (°C)
|
|
||||||
RelModLevel, // f8.8 Relative Modulation Level (%)
|
|
||||||
CHPressure, // f8.8 Water pressure in CH circuit (bar)
|
|
||||||
DHWFlowRate, // f8.8 Water flow rate in DHW circuit. (litres/minute)
|
|
||||||
DayTime, // special / u8 Day of Week and Time of Day
|
|
||||||
Date, // u8 / u8 Calendar date
|
|
||||||
Year, // u16 Calendar year
|
|
||||||
TrSetCH2, // f8.8 Room Setpoint for 2nd CH circuit (°C)
|
|
||||||
Tr, // f8.8 Room temperature (°C)
|
|
||||||
Tboiler, // f8.8 Boiler flow water temperature (°C)
|
|
||||||
Tdhw, // f8.8 DHW temperature (°C)
|
|
||||||
Toutside, // f8.8 Outside temperature (°C)
|
|
||||||
Tret, // f8.8 Return water temperature (°C)
|
|
||||||
Tstorage, // f8.8 Solar storage temperature (°C)
|
|
||||||
Tcollector, // f8.8 Solar collector temperature (°C)
|
|
||||||
TflowCH2, // f8.8 Flow water temperature CH2 circuit (°C)
|
|
||||||
Tdhw2, // f8.8 Domestic hot water temperature 2 (°C)
|
|
||||||
Texhaust, // s16 Boiler exhaust temperature (°C)
|
|
||||||
TdhwSetUBTdhwSetLB = 48, // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C)
|
|
||||||
MaxTSetUBMaxTSetLB, // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C)
|
|
||||||
HcratioUBHcratioLB, // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment
|
|
||||||
TdhwSet = 56, // f8.8 DHW setpoint (°C) (Remote parameter 1)
|
|
||||||
MaxTSet, // f8.8 Max CH water setpoint (°C) (Remote parameters 2)
|
|
||||||
Hcratio, // f8.8 OTC heat curve ratio (°C) (Remote parameter 3)
|
|
||||||
RemoteOverrideFunction = 100, // flag8 / - Function of manual and program changes in master and remote room setpoint.
|
|
||||||
OEMDiagnosticCode = 115, // u16 OEM-specific diagnostic/service code
|
|
||||||
BurnerStarts, // u16 Number of starts burner
|
|
||||||
CHPumpStarts, // u16 Number of starts CH pump
|
|
||||||
DHWPumpValveStarts, // u16 Number of starts DHW pump/valve
|
|
||||||
DHWBurnerStarts, // u16 Number of starts burner during DHW mode
|
|
||||||
BurnerOperationHours, // u16 Number of hours that burner is in operation (i.e. flame on)
|
|
||||||
CHPumpOperationHours, // u16 Number of hours that CH pump has been running
|
|
||||||
DHWPumpValveOperationHours, // u16 Number of hours that DHW pump has been running or DHW valve has been opened
|
|
||||||
DHWBurnerOperationHours, // u16 Number of hours that burner is in operation during DHW mode
|
|
||||||
OpenThermVersionMaster, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master.
|
|
||||||
OpenThermVersionSlave, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave.
|
|
||||||
MasterVersion, // u8 / u8 Master product version number and type
|
|
||||||
SlaveVersion, // u8 / u8 Slave product version number and type
|
|
||||||
};
|
|
||||||
|
|
||||||
enum OpenThermStatus {
|
|
||||||
OPTH_NOT_INITIALIZED,
|
|
||||||
OPTH_READY,
|
|
||||||
OPTH_DELAY,
|
|
||||||
OPTH_REQUEST_SENDING,
|
|
||||||
OPTH_RESPONSE_WAITING,
|
|
||||||
OPTH_RESPONSE_START_BIT,
|
|
||||||
OPTH_RESPONSE_RECEIVING,
|
|
||||||
OPTH_RESPONSE_READY,
|
|
||||||
OPTH_RESPONSE_INVALID
|
|
||||||
};
|
|
||||||
|
|
||||||
class OpenTherm
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false);
|
|
||||||
volatile OpenThermStatus status;
|
|
||||||
void begin(void(*handleInterruptCallback)(void));
|
|
||||||
void begin(void(*handleInterruptCallback)(void), void(*processResponseCallback)(unsigned long, int));
|
|
||||||
bool isReady();
|
|
||||||
unsigned long sendRequest(unsigned long request);
|
|
||||||
bool sendResponse(unsigned long request);
|
|
||||||
bool sendRequestAync(unsigned long request);
|
|
||||||
static unsigned long buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
|
|
||||||
static unsigned long buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
|
|
||||||
OpenThermResponseStatus getLastResponseStatus();
|
|
||||||
const char *statusToString(OpenThermResponseStatus status);
|
|
||||||
void handleInterrupt();
|
|
||||||
void process();
|
|
||||||
void end();
|
|
||||||
|
|
||||||
static bool parity(unsigned long frame);
|
|
||||||
OpenThermMessageType getMessageType(unsigned long message);
|
|
||||||
OpenThermMessageID getDataID(unsigned long frame);
|
|
||||||
const char *messageTypeToString(OpenThermMessageType message_type);
|
|
||||||
bool isValidRequest(unsigned long request);
|
|
||||||
bool isValidResponse(unsigned long response);
|
|
||||||
|
|
||||||
//requests
|
|
||||||
unsigned long buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false);
|
|
||||||
unsigned long buildSetBoilerTemperatureRequest(float temperature);
|
|
||||||
unsigned long buildGetBoilerTemperatureRequest();
|
|
||||||
unsigned long buildSetHotWaterTemperatureRequest(float temperature);
|
|
||||||
unsigned long buildSlaveConfigurationRequest();
|
|
||||||
|
|
||||||
|
|
||||||
//responses
|
|
||||||
static bool isFault(unsigned long response);
|
|
||||||
static bool isCentralHeatingActive(unsigned long response);
|
|
||||||
static bool isHotWaterActive(unsigned long response);
|
|
||||||
static bool isFlameOn(unsigned long response);
|
|
||||||
static bool isCoolingActive(unsigned long response);
|
|
||||||
static bool isDiagnostic(unsigned long response);
|
|
||||||
static uint16_t getUInt(const unsigned long response);
|
|
||||||
static float getFloat(const unsigned long response);
|
|
||||||
static unsigned int temperatureToData(float temperature);
|
|
||||||
|
|
||||||
//basic requests
|
|
||||||
unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false);
|
|
||||||
bool setBoilerTemperature(float temperature);
|
|
||||||
bool setHotWaterTemperature(float temperature);
|
|
||||||
float getBoilerTemperature();
|
|
||||||
float getReturnTemperature();
|
|
||||||
float getModulation();
|
|
||||||
float getPressure();
|
|
||||||
unsigned char getFault();
|
|
||||||
unsigned long getSlaveConfiguration();
|
|
||||||
|
|
||||||
private:
|
|
||||||
const int inPin;
|
|
||||||
const int outPin;
|
|
||||||
const bool isSlave;
|
|
||||||
|
|
||||||
volatile unsigned long response;
|
|
||||||
volatile OpenThermResponseStatus responseStatus;
|
|
||||||
volatile unsigned long responseTimestamp;
|
|
||||||
volatile byte responseBitIndex;
|
|
||||||
|
|
||||||
int readState();
|
|
||||||
void setActiveState();
|
|
||||||
void setIdleState();
|
|
||||||
void activateBoiler();
|
|
||||||
|
|
||||||
void sendBit(bool high);
|
|
||||||
void(*handleInterruptCallback)();
|
|
||||||
void(*processResponseCallback)(unsigned long, int);
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef ICACHE_RAM_ATTR
|
|
||||||
#define ICACHE_RAM_ATTR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // OpenTherm_h
|
|
@ -1,29 +0,0 @@
|
|||||||
Attention when updating library. Changes in lib needed!!
|
|
||||||
All OpenTherm constants shall be prepended with `OPTH_` to avoid conflicts with other libs.
|
|
||||||
|
|
||||||
See commit https://github.com/arendst/Tasmota/commit/960291729ccc7cb4da50108e5299d44a79cb06de
|
|
||||||
|
|
||||||
As of OpenTherm-0.9.0, hte list is:
|
|
||||||
OPTH_NONE
|
|
||||||
OPTH_SUCCESS
|
|
||||||
OPTH_INVALID
|
|
||||||
OPTH_TIMEOUT
|
|
||||||
OPTH_READ_DATA
|
|
||||||
OPTH_READ
|
|
||||||
OPTH_WRITE_DATA
|
|
||||||
OPTH_WRITE
|
|
||||||
OPTH_INVALID_DATA
|
|
||||||
OPTH_RESERVED
|
|
||||||
OPTH_READ_ACK
|
|
||||||
OPTH_WRITE_ACK
|
|
||||||
OPTH_DATA_INVALID
|
|
||||||
OPTH_UNKNOWN_DATA_ID
|
|
||||||
OPTH_NOT_INITIALIZED
|
|
||||||
OPTH_READY
|
|
||||||
OPTH_DELAY
|
|
||||||
OPTH_REQUEST_SENDING
|
|
||||||
OPTH_RESPONSE_WAITING
|
|
||||||
OPTH_RESPONSE_START_BIT
|
|
||||||
OPTH_RESPONSE_RECEIVING
|
|
||||||
OPTH_RESPONSE_READY
|
|
||||||
OPTH_RESPONSE_INVALID
|
|
@ -1,8 +1,8 @@
|
|||||||
# OpenTherm Arduino/ESP8266 Library
|
# OpenTherm Arduino/ESP8266/ESP32 Library
|
||||||
|
|
||||||
This library provides implementation of OpenTherm protocol.
|
This library provides implementation of OpenTherm protocol.
|
||||||
|
|
||||||
OpenTherm Library is based on OpenTherm protocol specification v2.2 and works with all OpenTherm compatible boilers. Library can be easily installed into Arduino IDE and compiled for Arduino, ESP8266 and other similar controllers.
|
OpenTherm Library is based on OpenTherm protocol specification v2.2 and works with all OpenTherm compatible boilers. Library can be easily installed into Arduino IDE and compiled for Arduino, ESP8266/ESP32 and other similar controllers.
|
||||||
|
|
||||||
OpenTherm protocol requires simple low voltage twowire connection to boiler, but voltage levels (7..15V) still much higher than Arduino/ESP8266 levels, which requires [OpenTherm Adapter](http://ihormelnyk.com/opentherm_adapter).
|
OpenTherm protocol requires simple low voltage twowire connection to boiler, but voltage levels (7..15V) still much higher than Arduino/ESP8266 levels, which requires [OpenTherm Adapter](http://ihormelnyk.com/opentherm_adapter).
|
||||||
|
|
@ -30,6 +30,8 @@ doSomething KEYWORD2
|
|||||||
setBoilerStatus KEYWORD2
|
setBoilerStatus KEYWORD2
|
||||||
setBoilerTemperature KEYWORD2
|
setBoilerTemperature KEYWORD2
|
||||||
getBoilerTemperature KEYWORD2
|
getBoilerTemperature KEYWORD2
|
||||||
|
setDHWSetpoint KEYWORD2
|
||||||
|
getDHWTemperature KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Instances (KEYWORD2)
|
# Instances (KEYWORD2)
|
@ -1,8 +1,8 @@
|
|||||||
name=OpenTherm Library
|
name=OpenTherm Library
|
||||||
version=0.9.0
|
version=1.1.5
|
||||||
author=Ihor Melnyk <ihor.melnyk@gmail.com>
|
author=Ihor Melnyk <ihor.melnyk@gmail.com>
|
||||||
maintainer=Ihor Melnyk <ihor.melnyk@gmail.com>
|
maintainer=Ihor Melnyk <ihor.melnyk@gmail.com>
|
||||||
sentence=OpenTherm Library for HVAC system control communication using Arduino and ESP8266 hardware.
|
sentence=OpenTherm Library for HVAC system control communication using Arduino and ESP8266/ESP32 hardware.
|
||||||
paragraph=OpenTherm Library is based on OpenTherm protocol specification v2.2 and works with all OpenTherm compatible boilers.
|
paragraph=OpenTherm Library is based on OpenTherm protocol specification v2.2 and works with all OpenTherm compatible boilers.
|
||||||
category=Communication
|
category=Communication
|
||||||
url=https://github.com/ihormelnyk/opentherm_library
|
url=https://github.com/ihormelnyk/opentherm_library
|
578
lib/lib_div/OpenTherm-1.1.5/src/OpenTherm.cpp
Normal file
578
lib/lib_div/OpenTherm-1.1.5/src/OpenTherm.cpp
Normal file
@ -0,0 +1,578 @@
|
|||||||
|
/*
|
||||||
|
OpenTherm.cpp - OpenTherm Communication Library For Arduino, ESP8266, ESP32
|
||||||
|
Copyright 2023, Ihor Melnyk
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "OpenTherm.h"
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
#include "FunctionalInterrupt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OpenTherm::OpenTherm(int inPin, int outPin, bool isSlave) :
|
||||||
|
status(OpenThermStatus::NOT_INITIALIZED),
|
||||||
|
inPin(inPin),
|
||||||
|
outPin(outPin),
|
||||||
|
isSlave(isSlave),
|
||||||
|
response(0),
|
||||||
|
responseStatus(OpenThermResponseStatus::NONE),
|
||||||
|
responseTimestamp(0),
|
||||||
|
processResponseCallback(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::begin(void (*handleInterruptCallback)(void))
|
||||||
|
{
|
||||||
|
pinMode(inPin, INPUT);
|
||||||
|
pinMode(outPin, OUTPUT);
|
||||||
|
if (handleInterruptCallback != NULL)
|
||||||
|
{
|
||||||
|
attachInterrupt(digitalPinToInterrupt(inPin), handleInterruptCallback, CHANGE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
attachInterruptArg(
|
||||||
|
digitalPinToInterrupt(inPin),
|
||||||
|
OpenTherm::handleInterruptHelper,
|
||||||
|
this,
|
||||||
|
CHANGE
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
activateBoiler();
|
||||||
|
status = OpenThermStatus::READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::begin(void (*handleInterruptCallback)(void), void (*processResponseCallback)(unsigned long, int))
|
||||||
|
{
|
||||||
|
begin(handleInterruptCallback);
|
||||||
|
this->processResponseCallback = processResponseCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
void OpenTherm::begin()
|
||||||
|
{
|
||||||
|
begin(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::begin(std::function<void(unsigned long, OpenThermResponseStatus)> processResponseFunction)
|
||||||
|
{
|
||||||
|
begin();
|
||||||
|
this->processResponseFunction = processResponseFunction;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool IRAM_ATTR OpenTherm::isReady()
|
||||||
|
{
|
||||||
|
return status == OpenThermStatus::READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IRAM_ATTR OpenTherm::readState()
|
||||||
|
{
|
||||||
|
return digitalRead(inPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::setActiveState()
|
||||||
|
{
|
||||||
|
digitalWrite(outPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::setIdleState()
|
||||||
|
{
|
||||||
|
digitalWrite(outPin, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::activateBoiler()
|
||||||
|
{
|
||||||
|
setIdleState();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::sendBit(bool high)
|
||||||
|
{
|
||||||
|
if (high)
|
||||||
|
setActiveState();
|
||||||
|
else
|
||||||
|
setIdleState();
|
||||||
|
delayMicroseconds(500);
|
||||||
|
if (high)
|
||||||
|
setIdleState();
|
||||||
|
else
|
||||||
|
setActiveState();
|
||||||
|
delayMicroseconds(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::sendRequestAsync(unsigned long request)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
const bool ready = isReady();
|
||||||
|
|
||||||
|
if (!ready)
|
||||||
|
{
|
||||||
|
interrupts();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = OpenThermStatus::REQUEST_SENDING;
|
||||||
|
response = 0;
|
||||||
|
responseStatus = OpenThermResponseStatus::NONE;
|
||||||
|
|
||||||
|
#ifdef INC_FREERTOS_H
|
||||||
|
BaseType_t schedulerState = xTaskGetSchedulerState();
|
||||||
|
if (schedulerState == taskSCHEDULER_RUNNING)
|
||||||
|
{
|
||||||
|
vTaskSuspendAll();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
sendBit(HIGH); // start bit
|
||||||
|
for (int i = 31; i >= 0; i--)
|
||||||
|
{
|
||||||
|
sendBit(bitRead(request, i));
|
||||||
|
}
|
||||||
|
sendBit(HIGH); // stop bit
|
||||||
|
setIdleState();
|
||||||
|
|
||||||
|
responseTimestamp = micros();
|
||||||
|
status = OpenThermStatus::RESPONSE_WAITING;
|
||||||
|
|
||||||
|
#ifdef INC_FREERTOS_H
|
||||||
|
if (schedulerState == taskSCHEDULER_RUNNING) {
|
||||||
|
xTaskResumeAll();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long OpenTherm::sendRequest(unsigned long request)
|
||||||
|
{
|
||||||
|
if (!sendRequestAsync(request))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!isReady())
|
||||||
|
{
|
||||||
|
process();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::sendResponse(unsigned long request)
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
const bool ready = isReady();
|
||||||
|
|
||||||
|
if (!ready)
|
||||||
|
{
|
||||||
|
interrupts();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = OpenThermStatus::REQUEST_SENDING;
|
||||||
|
response = 0;
|
||||||
|
responseStatus = OpenThermResponseStatus::NONE;
|
||||||
|
|
||||||
|
#ifdef INC_FREERTOS_H
|
||||||
|
BaseType_t schedulerState = xTaskGetSchedulerState();
|
||||||
|
if (schedulerState == taskSCHEDULER_RUNNING)
|
||||||
|
{
|
||||||
|
vTaskSuspendAll();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
sendBit(HIGH); // start bit
|
||||||
|
for (int i = 31; i >= 0; i--)
|
||||||
|
{
|
||||||
|
sendBit(bitRead(request, i));
|
||||||
|
}
|
||||||
|
sendBit(HIGH); // stop bit
|
||||||
|
setIdleState();
|
||||||
|
status = OpenThermStatus::READY;
|
||||||
|
|
||||||
|
#ifdef INC_FREERTOS_H
|
||||||
|
if (schedulerState == taskSCHEDULER_RUNNING) {
|
||||||
|
xTaskResumeAll();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long OpenTherm::getLastResponse()
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenThermResponseStatus OpenTherm::getLastResponseStatus()
|
||||||
|
{
|
||||||
|
return responseStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR OpenTherm::handleInterrupt()
|
||||||
|
{
|
||||||
|
if (isReady())
|
||||||
|
{
|
||||||
|
if (isSlave && readState() == HIGH)
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::RESPONSE_WAITING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long newTs = micros();
|
||||||
|
if (status == OpenThermStatus::RESPONSE_WAITING)
|
||||||
|
{
|
||||||
|
if (readState() == HIGH)
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::RESPONSE_START_BIT;
|
||||||
|
responseTimestamp = newTs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::RESPONSE_INVALID;
|
||||||
|
responseTimestamp = newTs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (status == OpenThermStatus::RESPONSE_START_BIT)
|
||||||
|
{
|
||||||
|
if ((newTs - responseTimestamp < 750) && readState() == LOW)
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::RESPONSE_RECEIVING;
|
||||||
|
responseTimestamp = newTs;
|
||||||
|
responseBitIndex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::RESPONSE_INVALID;
|
||||||
|
responseTimestamp = newTs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (status == OpenThermStatus::RESPONSE_RECEIVING)
|
||||||
|
{
|
||||||
|
if ((newTs - responseTimestamp) > 750)
|
||||||
|
{
|
||||||
|
if (responseBitIndex < 32)
|
||||||
|
{
|
||||||
|
response = (response << 1) | !readState();
|
||||||
|
responseTimestamp = newTs;
|
||||||
|
responseBitIndex = responseBitIndex + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // stop bit
|
||||||
|
status = OpenThermStatus::RESPONSE_READY;
|
||||||
|
responseTimestamp = newTs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
void IRAM_ATTR OpenTherm::handleInterruptHelper(void* ptr)
|
||||||
|
{
|
||||||
|
static_cast<OpenTherm*>(ptr)->handleInterrupt();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void OpenTherm::processResponse()
|
||||||
|
{
|
||||||
|
if (processResponseCallback != NULL)
|
||||||
|
{
|
||||||
|
processResponseCallback(response, (int)responseStatus);
|
||||||
|
}
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
if (this->processResponseFunction != NULL)
|
||||||
|
{
|
||||||
|
processResponseFunction(response, responseStatus);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::process()
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
OpenThermStatus st = status;
|
||||||
|
unsigned long ts = responseTimestamp;
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
if (st == OpenThermStatus::READY)
|
||||||
|
return;
|
||||||
|
unsigned long newTs = micros();
|
||||||
|
if (st != OpenThermStatus::NOT_INITIALIZED && st != OpenThermStatus::DELAY && (newTs - ts) > 1000000)
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::READY;
|
||||||
|
responseStatus = OpenThermResponseStatus::TIMEOUT;
|
||||||
|
processResponse();
|
||||||
|
}
|
||||||
|
else if (st == OpenThermStatus::RESPONSE_INVALID)
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::DELAY;
|
||||||
|
responseStatus = OpenThermResponseStatus::INVALID;
|
||||||
|
processResponse();
|
||||||
|
}
|
||||||
|
else if (st == OpenThermStatus::RESPONSE_READY)
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::DELAY;
|
||||||
|
responseStatus = (isSlave ? isValidRequest(response) : isValidResponse(response)) ? OpenThermResponseStatus::SUCCESS : OpenThermResponseStatus::INVALID;
|
||||||
|
processResponse();
|
||||||
|
}
|
||||||
|
else if (st == OpenThermStatus::DELAY)
|
||||||
|
{
|
||||||
|
if ((newTs - ts) > (isSlave ? 20000 : 100000))
|
||||||
|
{
|
||||||
|
status = OpenThermStatus::READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::parity(unsigned long frame) // odd parity
|
||||||
|
{
|
||||||
|
byte p = 0;
|
||||||
|
while (frame > 0)
|
||||||
|
{
|
||||||
|
if (frame & 1)
|
||||||
|
p++;
|
||||||
|
frame = frame >> 1;
|
||||||
|
}
|
||||||
|
return (p & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenThermMessageType OpenTherm::getMessageType(unsigned long message)
|
||||||
|
{
|
||||||
|
OpenThermMessageType msg_type = static_cast<OpenThermMessageType>((message >> 28) & 7);
|
||||||
|
return msg_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenThermMessageID OpenTherm::getDataID(unsigned long frame)
|
||||||
|
{
|
||||||
|
return (OpenThermMessageID)((frame >> 16) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long OpenTherm::buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data)
|
||||||
|
{
|
||||||
|
unsigned long request = data;
|
||||||
|
if (type == OpenThermMessageType::WRITE_DATA)
|
||||||
|
{
|
||||||
|
request |= 1ul << 28;
|
||||||
|
}
|
||||||
|
request |= ((unsigned long)id) << 16;
|
||||||
|
if (parity(request))
|
||||||
|
request |= (1ul << 31);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long OpenTherm::buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data)
|
||||||
|
{
|
||||||
|
unsigned long response = data;
|
||||||
|
response |= ((unsigned long)type) << 28;
|
||||||
|
response |= ((unsigned long)id) << 16;
|
||||||
|
if (parity(response))
|
||||||
|
response |= (1ul << 31);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isValidResponse(unsigned long response)
|
||||||
|
{
|
||||||
|
if (parity(response))
|
||||||
|
return false;
|
||||||
|
byte msgType = (response << 1) >> 29;
|
||||||
|
return msgType == (byte)OpenThermMessageType::READ_ACK || msgType == (byte)OpenThermMessageType::WRITE_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isValidRequest(unsigned long request)
|
||||||
|
{
|
||||||
|
if (parity(request))
|
||||||
|
return false;
|
||||||
|
byte msgType = (request << 1) >> 29;
|
||||||
|
return msgType == (byte)OpenThermMessageType::READ_DATA || msgType == (byte)OpenThermMessageType::WRITE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenTherm::end()
|
||||||
|
{
|
||||||
|
detachInterrupt(digitalPinToInterrupt(inPin));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenTherm::~OpenTherm()
|
||||||
|
{
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *OpenTherm::statusToString(OpenThermResponseStatus status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case OpenThermResponseStatus::NONE:
|
||||||
|
return "NONE";
|
||||||
|
case OpenThermResponseStatus::SUCCESS:
|
||||||
|
return "SUCCESS";
|
||||||
|
case OpenThermResponseStatus::INVALID:
|
||||||
|
return "INVALID";
|
||||||
|
case OpenThermResponseStatus::TIMEOUT:
|
||||||
|
return "TIMEOUT";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *OpenTherm::messageTypeToString(OpenThermMessageType message_type)
|
||||||
|
{
|
||||||
|
switch (message_type)
|
||||||
|
{
|
||||||
|
case OpenThermMessageType::READ_DATA:
|
||||||
|
return "READ_DATA";
|
||||||
|
case OpenThermMessageType::WRITE_DATA:
|
||||||
|
return "WRITE_DATA";
|
||||||
|
case OpenThermMessageType::INVALID_DATA:
|
||||||
|
return "INVALID_DATA";
|
||||||
|
case OpenThermMessageType::RESERVED:
|
||||||
|
return "RESERVED";
|
||||||
|
case OpenThermMessageType::READ_ACK:
|
||||||
|
return "READ_ACK";
|
||||||
|
case OpenThermMessageType::WRITE_ACK:
|
||||||
|
return "WRITE_ACK";
|
||||||
|
case OpenThermMessageType::DATA_INVALID:
|
||||||
|
return "DATA_INVALID";
|
||||||
|
case OpenThermMessageType::UNKNOWN_DATA_ID:
|
||||||
|
return "UNKNOWN_DATA_ID";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// building requests
|
||||||
|
|
||||||
|
unsigned long OpenTherm::buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2)
|
||||||
|
{
|
||||||
|
unsigned int data = enableCentralHeating | (enableHotWater << 1) | (enableCooling << 2) | (enableOutsideTemperatureCompensation << 3) | (enableCentralHeating2 << 4);
|
||||||
|
data <<= 8;
|
||||||
|
return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Status, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long OpenTherm::buildSetBoilerTemperatureRequest(float temperature)
|
||||||
|
{
|
||||||
|
unsigned int data = temperatureToData(temperature);
|
||||||
|
return buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TSet, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long OpenTherm::buildGetBoilerTemperatureRequest()
|
||||||
|
{
|
||||||
|
return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Tboiler, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsing responses
|
||||||
|
bool OpenTherm::isFault(unsigned long response)
|
||||||
|
{
|
||||||
|
return response & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isCentralHeatingActive(unsigned long response)
|
||||||
|
{
|
||||||
|
return response & 0x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isHotWaterActive(unsigned long response)
|
||||||
|
{
|
||||||
|
return response & 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isFlameOn(unsigned long response)
|
||||||
|
{
|
||||||
|
return response & 0x8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isCoolingActive(unsigned long response)
|
||||||
|
{
|
||||||
|
return response & 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::isDiagnostic(unsigned long response)
|
||||||
|
{
|
||||||
|
return response & 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t OpenTherm::getUInt(const unsigned long response)
|
||||||
|
{
|
||||||
|
const uint16_t u88 = response & 0xffff;
|
||||||
|
return u88;
|
||||||
|
}
|
||||||
|
|
||||||
|
float OpenTherm::getFloat(const unsigned long response)
|
||||||
|
{
|
||||||
|
const uint16_t u88 = getUInt(response);
|
||||||
|
const float f = (u88 & 0x8000) ? -(0x10000L - u88) / 256.0f : u88 / 256.0f;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int OpenTherm::temperatureToData(float temperature)
|
||||||
|
{
|
||||||
|
if (temperature < 0)
|
||||||
|
temperature = 0;
|
||||||
|
if (temperature > 100)
|
||||||
|
temperature = 100;
|
||||||
|
unsigned int data = (unsigned int)(temperature * 256);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// basic requests
|
||||||
|
|
||||||
|
unsigned long OpenTherm::setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2)
|
||||||
|
{
|
||||||
|
return sendRequest(buildSetBoilerStatusRequest(enableCentralHeating, enableHotWater, enableCooling, enableOutsideTemperatureCompensation, enableCentralHeating2));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::setBoilerTemperature(float temperature)
|
||||||
|
{
|
||||||
|
unsigned long response = sendRequest(buildSetBoilerTemperatureRequest(temperature));
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
float OpenTherm::getBoilerTemperature()
|
||||||
|
{
|
||||||
|
unsigned long response = sendRequest(buildGetBoilerTemperatureRequest());
|
||||||
|
return isValidResponse(response) ? getFloat(response) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float OpenTherm::getReturnTemperature()
|
||||||
|
{
|
||||||
|
unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Tret, 0));
|
||||||
|
return isValidResponse(response) ? getFloat(response) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenTherm::setDHWSetpoint(float temperature)
|
||||||
|
{
|
||||||
|
unsigned int data = temperatureToData(temperature);
|
||||||
|
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TdhwSet, data));
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
float OpenTherm::getDHWTemperature()
|
||||||
|
{
|
||||||
|
unsigned long response = sendRequest(buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Tdhw, 0));
|
||||||
|
return isValidResponse(response) ? getFloat(response) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float OpenTherm::getModulation()
|
||||||
|
{
|
||||||
|
unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::RelModLevel, 0));
|
||||||
|
return isValidResponse(response) ? getFloat(response) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float OpenTherm::getPressure()
|
||||||
|
{
|
||||||
|
unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::CHPressure, 0));
|
||||||
|
return isValidResponse(response) ? getFloat(response) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char OpenTherm::getFault()
|
||||||
|
{
|
||||||
|
return ((sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0)) >> 8) & 0xff);
|
||||||
|
}
|
256
lib/lib_div/OpenTherm-1.1.5/src/OpenTherm.h
Normal file
256
lib/lib_div/OpenTherm-1.1.5/src/OpenTherm.h
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
OpenTherm.h - OpenTherm Library for the ESP8266/ESP32/Arduino platform
|
||||||
|
https://github.com/ihormelnyk/OpenTherm
|
||||||
|
http://ihormelnyk.com/pages/OpenTherm
|
||||||
|
Licensed under MIT license
|
||||||
|
Copyright 2023, Ihor Melnyk
|
||||||
|
|
||||||
|
Frame Structure:
|
||||||
|
P MGS-TYPE SPARE DATA-ID DATA-VALUE
|
||||||
|
0 000 0000 00000000 00000000 00000000
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OpenTherm_h
|
||||||
|
#define OpenTherm_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
enum class OpenThermResponseStatus : byte
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
SUCCESS,
|
||||||
|
INVALID,
|
||||||
|
TIMEOUT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OpenThermMessageType : byte
|
||||||
|
{
|
||||||
|
/* Master to Slave */
|
||||||
|
READ_DATA = 0b000,
|
||||||
|
READ = READ_DATA, // for backwared compatibility
|
||||||
|
WRITE_DATA = 0b001,
|
||||||
|
WRITE = WRITE_DATA, // for backwared compatibility
|
||||||
|
INVALID_DATA = 0b010,
|
||||||
|
RESERVED = 0b011,
|
||||||
|
/* Slave to Master */
|
||||||
|
READ_ACK = 0b100,
|
||||||
|
WRITE_ACK = 0b101,
|
||||||
|
DATA_INVALID = 0b110,
|
||||||
|
UNKNOWN_DATA_ID = 0b111
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef OpenThermMessageType OpenThermRequestType; // for backwared compatibility
|
||||||
|
|
||||||
|
enum class OpenThermMessageID : byte
|
||||||
|
{
|
||||||
|
Status = 0, // flag8/flag8 Master and Slave Status flags.
|
||||||
|
TSet = 1, // f8.8 Control Setpoint i.e.CH water temperature Setpoint(°C)
|
||||||
|
MConfigMMemberIDcode = 2, // flag8/u8 Master Configuration Flags / Master MemberID Code
|
||||||
|
SConfigSMemberIDcode = 3, // flag8/u8 Slave Configuration Flags / Slave MemberID Code
|
||||||
|
RemoteRequest = 4, // u8/u8 Remote Request
|
||||||
|
ASFflags = 5, // flag8/u8 Application - specific fault flags and OEM fault code
|
||||||
|
RBPflags = 6, // flag8/flag8 Remote boiler parameter transfer - enable & read / write flags
|
||||||
|
CoolingControl = 7, // f8.8 Cooling control signal(%)
|
||||||
|
TsetCH2 = 8, // f8.8 Control Setpoint for 2e CH circuit(°C)
|
||||||
|
TrOverride = 9, // f8.8 Remote override room Setpoint
|
||||||
|
TSP = 10, // u8/u8 Number of Transparent - Slave - Parameters supported by slave
|
||||||
|
TSPindexTSPvalue = 11, // u8/u8 Index number / Value of referred - to transparent slave parameter.
|
||||||
|
FHBsize = 12, // u8/u8 Size of Fault - History - Buffer supported by slave
|
||||||
|
FHBindexFHBvalue = 13, // u8/u8 Index number / Value of referred - to fault - history buffer entry.
|
||||||
|
MaxRelModLevelSetting = 14, // f8.8 Maximum relative modulation level setting(%)
|
||||||
|
MaxCapacityMinModLevel = 15, // u8/u8 Maximum boiler capacity(kW) / Minimum boiler modulation level(%)
|
||||||
|
TrSet = 16, // f8.8 Room Setpoint(°C)
|
||||||
|
RelModLevel = 17, // f8.8 Relative Modulation Level(%)
|
||||||
|
CHPressure = 18, // f8.8 Water pressure in CH circuit(bar)
|
||||||
|
DHWFlowRate = 19, // f8.8 Water flow rate in DHW circuit. (litres / minute)
|
||||||
|
DayTime = 20, // special/u8 Day of Week and Time of Day
|
||||||
|
Date = 21, // u8/u8 Calendar date
|
||||||
|
Year = 22, // u16 Calendar year
|
||||||
|
TrSetCH2 = 23, // f8.8 Room Setpoint for 2nd CH circuit(°C)
|
||||||
|
Tr = 24, // f8.8 Room temperature(°C)
|
||||||
|
Tboiler = 25, // f8.8 Boiler flow water temperature(°C)
|
||||||
|
Tdhw = 26, // f8.8 DHW temperature(°C)
|
||||||
|
Toutside = 27, // f8.8 Outside temperature(°C)
|
||||||
|
Tret = 28, // f8.8 Return water temperature(°C)
|
||||||
|
Tstorage = 29, // f8.8 Solar storage temperature(°C)
|
||||||
|
Tcollector = 30, // f8.8 Solar collector temperature(°C)
|
||||||
|
TflowCH2 = 31, // f8.8 Flow water temperature CH2 circuit(°C)
|
||||||
|
Tdhw2 = 32, // f8.8 Domestic hot water temperature 2 (°C)
|
||||||
|
Texhaust = 33, // s16 Boiler exhaust temperature(°C)
|
||||||
|
TboilerHeatExchanger = 34, // f8.8 Boiler heat exchanger temperature(°C)
|
||||||
|
BoilerFanSpeedSetpointAndActual = 35, // u8/u8 Boiler fan speed Setpoint and actual value
|
||||||
|
FlameCurrent = 36, // f8.8 Electrical current through burner flame[μA]
|
||||||
|
TrCH2 = 37, // f8.8 Room temperature for 2nd CH circuit(°C)
|
||||||
|
RelativeHumidity = 38, // f8.8 Actual relative humidity as a percentage
|
||||||
|
TrOverride2 = 39, // f8.8 Remote Override Room Setpoint 2
|
||||||
|
TdhwSetUBTdhwSetLB = 48, // s8/s8 DHW Setpoint upper & lower bounds for adjustment(°C)
|
||||||
|
MaxTSetUBMaxTSetLB = 49, // s8/s8 Max CH water Setpoint upper & lower bounds for adjustment(°C)
|
||||||
|
TdhwSet = 56, // f8.8 DHW Setpoint(°C) (Remote parameter 1)
|
||||||
|
MaxTSet = 57, // f8.8 Max CH water Setpoint(°C) (Remote parameters 2)
|
||||||
|
StatusVentilationHeatRecovery = 70, // flag8/flag8 Master and Slave Status flags ventilation / heat - recovery
|
||||||
|
Vset = 71, // -/u8 Relative ventilation position (0-100%). 0% is the minimum set ventilation and 100% is the maximum set ventilation.
|
||||||
|
ASFflagsOEMfaultCodeVentilationHeatRecovery = 72, // flag8/u8 Application-specific fault flags and OEM fault code ventilation / heat-recovery
|
||||||
|
OEMDiagnosticCodeVentilationHeatRecovery = 73, // u16 An OEM-specific diagnostic/service code for ventilation / heat-recovery system
|
||||||
|
SConfigSMemberIDCodeVentilationHeatRecovery = 74, // flag8/u8 Slave Configuration Flags / Slave MemberID Code ventilation / heat-recovery
|
||||||
|
OpenThermVersionVentilationHeatRecovery = 75, // f8.8 The implemented version of the OpenTherm Protocol Specification in the ventilation / heat-recovery system.
|
||||||
|
VentilationHeatRecoveryVersion = 76, // u8/u8 Ventilation / heat-recovery product version number and type
|
||||||
|
RelVentLevel = 77, // -/u8 Relative ventilation (0-100%)
|
||||||
|
RHexhaust = 78, // -/u8 Relative humidity exhaust air (0-100%)
|
||||||
|
CO2exhaust = 79, // u16 CO2 level exhaust air (0-2000 ppm)
|
||||||
|
Tsi = 80, // f8.8 Supply inlet temperature (°C)
|
||||||
|
Tso = 81, // f8.8 Supply outlet temperature (°C)
|
||||||
|
Tei = 82, // f8.8 Exhaust inlet temperature (°C)
|
||||||
|
Teo = 83, // f8.8 Exhaust outlet temperature (°C)
|
||||||
|
RPMexhaust = 84, // u16 Exhaust fan speed in rpm
|
||||||
|
RPMsupply = 85, // u16 Supply fan speed in rpm
|
||||||
|
RBPflagsVentilationHeatRecovery = 86, // flag8/flag8 Remote ventilation / heat-recovery parameter transfer-enable & read/write flags
|
||||||
|
NominalVentilationValue = 87, // u8/- Nominal relative value for ventilation (0-100 %)
|
||||||
|
TSPventilationHeatRecovery = 88, // u8/u8 Number of Transparent-Slave-Parameters supported by TSP’s ventilation / heat-recovery
|
||||||
|
TSPindexTSPvalueVentilationHeatRecovery = 89, // u8/u8 Index number / Value of referred-to transparent TSP’s ventilation / heat-recovery parameter.
|
||||||
|
FHBsizeVentilationHeatRecovery = 90, // u8/u8 Size of Fault-History-Buffer supported by ventilation / heat-recovery
|
||||||
|
FHBindexFHBvalueVentilationHeatRecovery = 91, // u8/u8 Index number / Value of referred-to fault-history buffer entry ventilation / heat-recovery
|
||||||
|
Brand = 93, // u8/u8 Index number of the character in the text string ASCII character referenced by the above index number
|
||||||
|
BrandVersion = 94, // u8/u8 Index number of the character in the text string ASCII character referenced by the above index number
|
||||||
|
BrandSerialNumber = 95, // u8/u8 Index number of the character in the text string ASCII character referenced by the above index number
|
||||||
|
CoolingOperationHours = 96, // u16 Number of hours that the slave is in Cooling Mode. Reset by zero is optional for slave
|
||||||
|
PowerCycles = 97, // u16 Number of Power Cycles of a slave (wake-up after Reset), Reset by zero is optional for slave
|
||||||
|
RFsensorStatusInformation = 98, // special/special For a specific RF sensor the RF strength and battery level is written
|
||||||
|
RemoteOverrideOperatingModeHeatingDHW = 99, // special/special Operating Mode HC1, HC2/ Operating Mode DHW
|
||||||
|
RemoteOverrideFunction = 100, // flag8/- Function of manual and program changes in master and remote room Setpoint
|
||||||
|
StatusSolarStorage = 101, // flag8/flag8 Master and Slave Status flags Solar Storage
|
||||||
|
ASFflagsOEMfaultCodeSolarStorage = 102, // flag8/u8 Application-specific fault flags and OEM fault code Solar Storage
|
||||||
|
SConfigSMemberIDcodeSolarStorage = 103, // flag8/u8 Slave Configuration Flags / Slave MemberID Code Solar Storage
|
||||||
|
SolarStorageVersion = 104, // u8/u8 Solar Storage product version number and type
|
||||||
|
TSPSolarStorage = 105, // u8/u8 Number of Transparent - Slave - Parameters supported by TSP’s Solar Storage
|
||||||
|
TSPindexTSPvalueSolarStorage = 106, // u8/u8 Index number / Value of referred - to transparent TSP’s Solar Storage parameter.
|
||||||
|
FHBsizeSolarStorage = 107, // u8/u8 Size of Fault - History - Buffer supported by Solar Storage
|
||||||
|
FHBindexFHBvalueSolarStorage = 108, // u8/u8 Index number / Value of referred - to fault - history buffer entry Solar Storage
|
||||||
|
ElectricityProducerStarts = 109, // U16 Number of start of the electricity producer.
|
||||||
|
ElectricityProducerHours = 110, // U16 Number of hours the electricity produces is in operation
|
||||||
|
ElectricityProduction = 111, // U16 Current electricity production in Watt.
|
||||||
|
CumulativElectricityProduction = 112, // U16 Cumulative electricity production in KWh.
|
||||||
|
UnsuccessfulBurnerStarts = 113, // u16 Number of un - successful burner starts
|
||||||
|
FlameSignalTooLowNumber = 114, // u16 Number of times flame signal was too low
|
||||||
|
OEMDiagnosticCode = 115, // u16 OEM - specific diagnostic / service code
|
||||||
|
SuccessfulBurnerStarts = 116, // u16 Number of succesful starts burner
|
||||||
|
CHPumpStarts = 117, // u16 Number of starts CH pump
|
||||||
|
DHWPumpValveStarts = 118, // u16 Number of starts DHW pump / valve
|
||||||
|
DHWBurnerStarts = 119, // u16 Number of starts burner during DHW mode
|
||||||
|
BurnerOperationHours = 120, // u16 Number of hours that burner is in operation(i.e.flame on)
|
||||||
|
CHPumpOperationHours = 121, // u16 Number of hours that CH pump has been running
|
||||||
|
DHWPumpValveOperationHours = 122, // u16 Number of hours that DHW pump has been running or DHW valve has been opened
|
||||||
|
DHWBurnerOperationHours = 123, // u16 Number of hours that burner is in operation during DHW mode
|
||||||
|
OpenThermVersionMaster = 124, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master.
|
||||||
|
OpenThermVersionSlave = 125, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave.
|
||||||
|
MasterVersion = 126, // u8/u8 Master product version number and type
|
||||||
|
SlaveVersion = 127, // u8/u8 Slave product version number and type
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OpenThermStatus : byte
|
||||||
|
{
|
||||||
|
NOT_INITIALIZED,
|
||||||
|
READY,
|
||||||
|
DELAY,
|
||||||
|
REQUEST_SENDING,
|
||||||
|
RESPONSE_WAITING,
|
||||||
|
RESPONSE_START_BIT,
|
||||||
|
RESPONSE_RECEIVING,
|
||||||
|
RESPONSE_READY,
|
||||||
|
RESPONSE_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenTherm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false);
|
||||||
|
~OpenTherm();
|
||||||
|
volatile OpenThermStatus status;
|
||||||
|
void begin(void (*handleInterruptCallback)(void));
|
||||||
|
void begin(void (*handleInterruptCallback)(void), void (*processResponseCallback)(unsigned long, int));
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
void begin();
|
||||||
|
void begin(std::function<void(unsigned long, OpenThermResponseStatus)> processResponseFunction);
|
||||||
|
#endif
|
||||||
|
bool isReady();
|
||||||
|
unsigned long sendRequest(unsigned long request);
|
||||||
|
bool sendResponse(unsigned long request);
|
||||||
|
bool sendRequestAsync(unsigned long request);
|
||||||
|
static unsigned long buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
|
||||||
|
static unsigned long buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
|
||||||
|
unsigned long getLastResponse();
|
||||||
|
OpenThermResponseStatus getLastResponseStatus();
|
||||||
|
static const char *statusToString(OpenThermResponseStatus status);
|
||||||
|
void handleInterrupt();
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
static void handleInterruptHelper(void* ptr);
|
||||||
|
#endif
|
||||||
|
void process();
|
||||||
|
void end();
|
||||||
|
|
||||||
|
static bool parity(unsigned long frame);
|
||||||
|
static OpenThermMessageType getMessageType(unsigned long message);
|
||||||
|
static OpenThermMessageID getDataID(unsigned long frame);
|
||||||
|
static const char *messageTypeToString(OpenThermMessageType message_type);
|
||||||
|
static bool isValidRequest(unsigned long request);
|
||||||
|
static bool isValidResponse(unsigned long response);
|
||||||
|
|
||||||
|
// requests
|
||||||
|
static unsigned long buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false);
|
||||||
|
static unsigned long buildSetBoilerTemperatureRequest(float temperature);
|
||||||
|
static unsigned long buildGetBoilerTemperatureRequest();
|
||||||
|
|
||||||
|
// responses
|
||||||
|
static bool isFault(unsigned long response);
|
||||||
|
static bool isCentralHeatingActive(unsigned long response);
|
||||||
|
static bool isHotWaterActive(unsigned long response);
|
||||||
|
static bool isFlameOn(unsigned long response);
|
||||||
|
static bool isCoolingActive(unsigned long response);
|
||||||
|
static bool isDiagnostic(unsigned long response);
|
||||||
|
static uint16_t getUInt(const unsigned long response);
|
||||||
|
static float getFloat(const unsigned long response);
|
||||||
|
static unsigned int temperatureToData(float temperature);
|
||||||
|
|
||||||
|
// basic requests
|
||||||
|
unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false);
|
||||||
|
bool setBoilerTemperature(float temperature);
|
||||||
|
float getBoilerTemperature();
|
||||||
|
float getReturnTemperature();
|
||||||
|
bool setDHWSetpoint(float temperature);
|
||||||
|
float getDHWTemperature();
|
||||||
|
float getModulation();
|
||||||
|
float getPressure();
|
||||||
|
unsigned char getFault();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int inPin;
|
||||||
|
const int outPin;
|
||||||
|
const bool isSlave;
|
||||||
|
|
||||||
|
volatile unsigned long response;
|
||||||
|
volatile OpenThermResponseStatus responseStatus;
|
||||||
|
volatile unsigned long responseTimestamp;
|
||||||
|
volatile byte responseBitIndex;
|
||||||
|
|
||||||
|
int readState();
|
||||||
|
void setActiveState();
|
||||||
|
void setIdleState();
|
||||||
|
void activateBoiler();
|
||||||
|
|
||||||
|
void sendBit(bool high);
|
||||||
|
void processResponse();
|
||||||
|
void (*processResponseCallback)(unsigned long, int);
|
||||||
|
#if !defined(__AVR__)
|
||||||
|
std::function<void(unsigned long, OpenThermResponseStatus)> processResponseFunction;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef ICACHE_RAM_ATTR
|
||||||
|
#define ICACHE_RAM_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IRAM_ATTR
|
||||||
|
#define IRAM_ATTR ICACHE_RAM_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // OpenTherm_h
|
@ -191,7 +191,7 @@ void sns_opentherm_processResponseCallback(unsigned long response, int st)
|
|||||||
|
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case OpenThermResponseStatus::OPTH_SUCCESS:
|
case OpenThermResponseStatus::SUCCESS:
|
||||||
if (sns_ot_master->isValidResponse(response))
|
if (sns_ot_master->isValidResponse(response))
|
||||||
{
|
{
|
||||||
sns_opentherm_process_success_response(&sns_ot_boiler_status, response);
|
sns_opentherm_process_success_response(&sns_ot_boiler_status, response);
|
||||||
@ -200,7 +200,7 @@ void sns_opentherm_processResponseCallback(unsigned long response, int st)
|
|||||||
sns_ot_timeout_before_disconnect = SNS_OT_MAX_TIMEOUTS_BEFORE_DISCONNECT;
|
sns_ot_timeout_before_disconnect = SNS_OT_MAX_TIMEOUTS_BEFORE_DISCONNECT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpenThermResponseStatus::OPTH_INVALID:
|
case OpenThermResponseStatus::INVALID:
|
||||||
sns_opentherm_check_retry_request();
|
sns_opentherm_check_retry_request();
|
||||||
sns_ot_connection_status = OpenThermConnectionStatus::OTC_READY;
|
sns_ot_connection_status = OpenThermConnectionStatus::OTC_READY;
|
||||||
sns_ot_timeout_before_disconnect = SNS_OT_MAX_TIMEOUTS_BEFORE_DISCONNECT;
|
sns_ot_timeout_before_disconnect = SNS_OT_MAX_TIMEOUTS_BEFORE_DISCONNECT;
|
||||||
@ -210,7 +210,7 @@ void sns_opentherm_processResponseCallback(unsigned long response, int st)
|
|||||||
// In this case we do reconnect.
|
// In this case we do reconnect.
|
||||||
// If this command will timeout multiple times, it will be excluded from the rotation later on
|
// If this command will timeout multiple times, it will be excluded from the rotation later on
|
||||||
// after couple of failed attempts. See sns_opentherm_check_retry_request logic
|
// after couple of failed attempts. See sns_opentherm_check_retry_request logic
|
||||||
case OpenThermResponseStatus::OPTH_TIMEOUT:
|
case OpenThermResponseStatus::TIMEOUT:
|
||||||
sns_opentherm_check_retry_request();
|
sns_opentherm_check_retry_request();
|
||||||
if (--sns_ot_timeout_before_disconnect == 0)
|
if (--sns_ot_timeout_before_disconnect == 0)
|
||||||
{
|
{
|
||||||
@ -326,8 +326,8 @@ void sns_ot_start_handshake()
|
|||||||
|
|
||||||
sns_opentherm_protocol_reset();
|
sns_opentherm_protocol_reset();
|
||||||
|
|
||||||
sns_ot_master->sendRequestAync(
|
sns_ot_master->sendRequestAsync(
|
||||||
OpenTherm::buildRequest(OpenThermMessageType::OPTH_READ_DATA, OpenThermMessageID::SConfigSMemberIDcode, 0));
|
OpenTherm::buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::SConfigSMemberIDcode, 0));
|
||||||
|
|
||||||
sns_ot_connection_status = OpenThermConnectionStatus::OTC_HANDSHAKE;
|
sns_ot_connection_status = OpenThermConnectionStatus::OTC_HANDSHAKE;
|
||||||
}
|
}
|
||||||
@ -335,8 +335,7 @@ void sns_ot_start_handshake()
|
|||||||
void sns_ot_process_handshake(unsigned long response, int st)
|
void sns_ot_process_handshake(unsigned long response, int st)
|
||||||
{
|
{
|
||||||
OpenThermResponseStatus status = (OpenThermResponseStatus)st;
|
OpenThermResponseStatus status = (OpenThermResponseStatus)st;
|
||||||
|
if (status != OpenThermResponseStatus::SUCCESS || !sns_ot_master->isValidResponse(response))
|
||||||
if (status != OpenThermResponseStatus::OPTH_SUCCESS || !sns_ot_master->isValidResponse(response))
|
|
||||||
{
|
{
|
||||||
AddLog(LOG_LEVEL_ERROR,
|
AddLog(LOG_LEVEL_ERROR,
|
||||||
PSTR("[OTH]: getSlaveConfiguration failed. Status=%s"),
|
PSTR("[OTH]: getSlaveConfiguration failed. Status=%s"),
|
||||||
@ -609,7 +608,7 @@ bool Xsns69(uint32_t function)
|
|||||||
unsigned long request = sns_opentherm_get_next_request(&sns_ot_boiler_status);
|
unsigned long request = sns_opentherm_get_next_request(&sns_ot_boiler_status);
|
||||||
if (-1 != request)
|
if (-1 != request)
|
||||||
{
|
{
|
||||||
sns_ot_master->sendRequestAync(request);
|
sns_ot_master->sendRequestAsync(request);
|
||||||
sns_ot_connection_status = OpenThermConnectionStatus::OTC_INFLIGHT;
|
sns_ot_connection_status = OpenThermConnectionStatus::OTC_INFLIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef USE_OPENTHERM
|
#ifdef USE_OPENTHERM
|
||||||
|
|
||||||
#include "OpenTherm.h"
|
#include "OpenTherm.h"
|
||||||
@ -214,7 +213,7 @@ OpenThermCommand sns_opentherm_commands[] = {
|
|||||||
.m_ot_appent_telemetry = sns_opentherm_tele_generic_u16},
|
.m_ot_appent_telemetry = sns_opentherm_tele_generic_u16},
|
||||||
{// Number of starts burner
|
{// Number of starts burner
|
||||||
.m_command_name = "OT116",
|
.m_command_name = "OT116",
|
||||||
.m_command_code = (uint8_t)OpenThermMessageID::BurnerStarts,
|
.m_command_code = (uint8_t)OpenThermMessageID::SuccessfulBurnerStarts,
|
||||||
.m_flags = 0,
|
.m_flags = 0,
|
||||||
.m_results = {{.m_u8 = 0}, {.m_u8 = 0}},
|
.m_results = {{.m_u8 = 0}, {.m_u8 = 0}},
|
||||||
.m_ot_make_request = sns_opentherm_get_generic_u16,
|
.m_ot_make_request = sns_opentherm_get_generic_u16,
|
||||||
@ -246,7 +245,7 @@ OpenThermCommand sns_opentherm_commands[] = {
|
|||||||
.m_ot_appent_telemetry = sns_opentherm_tele_generic_u16},
|
.m_ot_appent_telemetry = sns_opentherm_tele_generic_u16},
|
||||||
{// Boiler Lock-out Reset command
|
{// Boiler Lock-out Reset command
|
||||||
.m_command_name = "BLOR",
|
.m_command_name = "BLOR",
|
||||||
.m_command_code = (uint8_t)OpenThermMessageID::Command,
|
.m_command_code = (uint8_t)OpenThermMessageID::RemoteRequest,
|
||||||
.m_flags = {.skip = 1},
|
.m_flags = {.skip = 1},
|
||||||
.m_results = {{.m_u8 = 0}, {.m_u8 = 0}},
|
.m_results = {{.m_u8 = 0}, {.m_u8 = 0}},
|
||||||
.m_ot_make_request = sns_opentherm_send_blor,
|
.m_ot_make_request = sns_opentherm_send_blor,
|
||||||
@ -284,7 +283,7 @@ unsigned long sns_opentherm_set_slave_flags(struct OpenThermCommandT *self, stru
|
|||||||
|
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
|
|
||||||
return OpenTherm::buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::Status, data);
|
return OpenTherm::buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Status, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sns_opentherm_parse_slave_flags(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_slave_flags(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
@ -330,7 +329,7 @@ unsigned long sns_opentherm_set_boiler_temperature(struct OpenThermCommandT *sel
|
|||||||
self->m_results[0].m_float = status->m_boilerSetpoint;
|
self->m_results[0].m_float = status->m_boilerSetpoint;
|
||||||
|
|
||||||
unsigned int data = OpenTherm::temperatureToData(status->m_boilerSetpoint);
|
unsigned int data = OpenTherm::temperatureToData(status->m_boilerSetpoint);
|
||||||
return OpenTherm::buildRequest(OpenThermMessageType::OPTH_WRITE_DATA, OpenThermMessageID::TSet, data);
|
return OpenTherm::buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TSet, data);
|
||||||
}
|
}
|
||||||
void sns_opentherm_parse_set_boiler_temperature(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_set_boiler_temperature(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
{
|
{
|
||||||
@ -370,7 +369,7 @@ unsigned long sns_opentherm_set_boiler_dhw_temperature(struct OpenThermCommandT
|
|||||||
self->m_results[0].m_float = status->m_hotWaterSetpoint;
|
self->m_results[0].m_float = status->m_hotWaterSetpoint;
|
||||||
|
|
||||||
unsigned int data = OpenTherm::temperatureToData(status->m_hotWaterSetpoint);
|
unsigned int data = OpenTherm::temperatureToData(status->m_hotWaterSetpoint);
|
||||||
return OpenTherm::buildRequest(OpenThermMessageType::OPTH_WRITE_DATA, OpenThermMessageID::TdhwSet, data);
|
return OpenTherm::buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TdhwSet, data);
|
||||||
}
|
}
|
||||||
void sns_opentherm_parse_boiler_dhw_temperature(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_boiler_dhw_temperature(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
{
|
{
|
||||||
@ -391,7 +390,7 @@ void sns_opentherm_tele_boiler_dhw_temperature(struct OpenThermCommandT *self)
|
|||||||
/////////////////////////////////// App Specific Fault Flags //////////////////////////////////////////////////
|
/////////////////////////////////// App Specific Fault Flags //////////////////////////////////////////////////
|
||||||
unsigned long sns_opentherm_get_flags(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
unsigned long sns_opentherm_get_flags(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
||||||
{
|
{
|
||||||
return OpenTherm::buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::ASFflags, 0);
|
return OpenTherm::buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sns_opentherm_parse_flags(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_flags(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
@ -426,7 +425,7 @@ void sns_opentherm_tele_u16(struct OpenThermCommandT *self)
|
|||||||
/////////////////////////////////// OEM Diag Code //////////////////////////////////////////////////
|
/////////////////////////////////// OEM Diag Code //////////////////////////////////////////////////
|
||||||
unsigned long sns_opentherm_get_oem_diag(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
unsigned long sns_opentherm_get_oem_diag(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
||||||
{
|
{
|
||||||
return OpenTherm::buildRequest(OpenThermRequestType::OPTH_READ, OpenThermMessageID::OEMDiagnosticCode, 0);
|
return OpenTherm::buildRequest(OpenThermRequestType::READ, OpenThermMessageID::OEMDiagnosticCode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sns_opentherm_parse_oem_diag(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_oem_diag(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
@ -450,7 +449,7 @@ unsigned long sns_opentherm_send_blor(struct OpenThermCommandT *self, struct OT_
|
|||||||
|
|
||||||
unsigned int data = 1; //1 : “BLOR”= Boiler Lock-out Reset command
|
unsigned int data = 1; //1 : “BLOR”= Boiler Lock-out Reset command
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
return OpenTherm::buildRequest(OpenThermMessageType::OPTH_WRITE_DATA, OpenThermMessageID::Command, data);
|
return OpenTherm::buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::RemoteRequest, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sns_opentherm_call_blor()
|
bool sns_opentherm_call_blor()
|
||||||
@ -470,7 +469,7 @@ bool sns_opentherm_call_blor()
|
|||||||
/////////////////////////////////// Generic Single Float /////////////////////////////////////////////////
|
/////////////////////////////////// Generic Single Float /////////////////////////////////////////////////
|
||||||
unsigned long sns_opentherm_get_generic_float(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
unsigned long sns_opentherm_get_generic_float(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
||||||
{
|
{
|
||||||
return OpenTherm::buildRequest(OpenThermRequestType::OPTH_READ, (OpenThermMessageID)self->m_command_code, 0);
|
return OpenTherm::buildRequest(OpenThermRequestType::READ, (OpenThermMessageID)self->m_command_code, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sns_opentherm_parse_generic_float(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_generic_float(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
@ -488,7 +487,7 @@ void sns_opentherm_tele_generic_float(struct OpenThermCommandT *self)
|
|||||||
/////////////////////////////////// Generic U16 /////////////////////////////////////////////////
|
/////////////////////////////////// Generic U16 /////////////////////////////////////////////////
|
||||||
unsigned long sns_opentherm_get_generic_u16(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
unsigned long sns_opentherm_get_generic_u16(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *)
|
||||||
{
|
{
|
||||||
return OpenTherm::buildRequest(OpenThermRequestType::OPTH_READ, (OpenThermMessageID)self->m_command_code, 0);
|
return OpenTherm::buildRequest(OpenThermRequestType::READ, (OpenThermMessageID)self->m_command_code, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sns_opentherm_parse_generic_u16(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
void sns_opentherm_parse_generic_u16(struct OpenThermCommandT *self, struct OT_BOILER_STATUS_T *boilerStatus, unsigned long response)
|
||||||
@ -559,7 +558,7 @@ void sns_opentherm_check_retry_request()
|
|||||||
|
|
||||||
bool canRetry = ++cmd->m_flags.retryCount < 3;
|
bool canRetry = ++cmd->m_flags.retryCount < 3;
|
||||||
// In case of last retry and if this command never respond successfully, set notSupported flag
|
// In case of last retry and if this command never respond successfully, set notSupported flag
|
||||||
if (!canRetry && !cmd->m_flags.supported)
|
if (!cmd->m_flags.supported)
|
||||||
{
|
{
|
||||||
cmd->m_flags.notSupported = true;
|
cmd->m_flags.notSupported = true;
|
||||||
AddLog(LOG_LEVEL_ERROR,
|
AddLog(LOG_LEVEL_ERROR,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user