Giter Site home page Giter Site logo

ihormelnyk / opentherm_library Goto Github PK

View Code? Open in Web Editor NEW
202.0 26.0 88.0 54 KB

Arduino/ESP8266/ESP32 OpenTherm Library for HVAC system control communication

License: MIT License

C++ 99.46% CMake 0.54%
opentherm opentherm-gateway opentherm-monitor opentherm-master opentherm-slave

opentherm_library's People

Contributors

chupaka avatar deff001 avatar dwrobel avatar ihormelnyk avatar laxilef avatar vkornev-work avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

opentherm_library's Issues

Setting hot water temperature fails (Tasmota)

Hi Ihor,

I recently bought one of your shields, thanks for your effort.
Sadly, it seems that setting the DHW, or hot water temperature, does not play nice with my boiler.
This seems odd as this is a mandatory parameter and otgw explicitly mentions that my boiler supports it.
http://otgw.tclcode.com/matrix.cgi#boilers

Potentially something else may be not playing nice here.

I should mention that I'm using this with Tasmota, this is slightly outdated,
https://github.com/arendst/Tasmota/tree/development/lib/lib_div/OpenTherm-0.9.0
Jan 30 to be exact.

Any thoughts or maybe that this has already been fixed?
I'm an (ex) embedded developer myself, so I have some tools to get dirty with it (if necessary).

Edit: It seems that Tasmota tries to be "smart" by not trying to configure a parameter that has failed enough times before. This logic seems to be propagated from this library actually, so it could be that that's the problem as well.

Problem with De Dietrich Innovens (MCA 35) boiler communication.

OpenTherm v. 1.1.0
I'm trying to interface with De Dietrich MCA 35 Innovens, which claims is compatible with OpenTherm. The issue is that after a few successfull answers from boiler I'm experiencing no answers for following messages. I'm using template sketch "OpenThermMaster_Demo.ino". Anyone had success witch interfacing this boiler?

Optimising script speed?

Hi there,

I've had a lot of fun using your OpenTherm project, so much so that I've attempted to implement it in a project for Homebridge integration via a NodeMCU which works almost perfectly (you can find the project here). However, when implementing with Homebridge, response time is extremely important. One problem I have noticed is that when the NodeMCU is communicating with the boiler, this takes a while and means that HTTP requests are unable to be handled. Here is a small example snipped of code I have made up to illustrate my point:

void loop() {
  if (new_ts - ts > 1000) {
    bool enableCentralHeating = true;
    bool enableHotWater = true;
    bool enableCooling = false;
    unsigned long response = ot.setBoilerStatus(enableCentralHeating, enableHotWater, enableCooling);
    OpenThermResponseStatus responseStatus = ot.getLastResponseStatus();

    if (responseStatus != OpenThermResponseStatus::SUCCESS) {
      Serial.println("Error: Invalid boiler response " + String(response, HEX));
    } else {
      ot.setBoilerTemperature(boilerTargetTemp);
    }
  }

  if (request.indexOf("/targetTemperature") != -1)  {
     tempString = "";
     tempString = (request.substring(23,25));
     tempString.trim();
     boilerTargetTemp = tempString.toFloat();
  }
}

As you can see, every 1s, the boiler is contacted to set the statuses as well as the temperature. Also note that on every repeat, the NodeMCU checks to see if /targetTemperature has been requested via HTTP. If it has, it sets the boiler temperature variable to the desired value included in the HTTP request.

Now, whilst the NodeMCU has not reached a full second (when it would then need to communicate with the boiler), it will simply check if an HTTP request has been made, skipping the if (new_ts - ts > 1000) { boiler control section. At this point, the NodeMCU responds straight away with no problems. However, the problem comes when an HTTP request is made whilst the boiler control function is in progress. At this point, the HTTP request is put on hold and is only responded to once the boiler control function has finished (which can take a while and make Homebridge unhappy).

Thus, would it be possible to remove or enhance some of the boiler control function to reduce this 'hanging' time? For instance, could the code be simplified down to:

void loop() {
  if (new_ts - ts > 1000) {
    bool enableCentralHeating = true;
    bool enableHotWater = true;
    bool enableCooling = false;
    unsigned long response = ot.setBoilerStatus(enableCentralHeating, enableHotWater, enableCooling);
    ot.setBoilerTemperature(boilerTargetTemp);
    }

  if (request.indexOf("/targetTemperature") != -1)  {
     tempString = "";
     tempString = (request.substring(23,25));
     tempString.trim();
     boilerTargetTemp = tempString.toFloat();
  }
}

I.e. removing the reading of a response status? My question is, will removing these lines of code reduce the amount of time spent in this section of the code? I am asking because I am unaware at exactly which point the status is read. For example, after running unsigned long response = ot.setBoilerStatus(enableCentralHeating, enableHotWater, enableCooling); does the code automatically wait 1s for a response or does this only happen when I explicitly specify if (responseStatus != OpenThermResponseStatus::SUCCESS) {?

Thank you in advance for your help

Typo and misleading function names

There is a typo in a function name: sendRequestAync should be sendRequestAsync.

The following function names are misleading because the Slave status flag in the response doesn't have *enabled flags, it has *active flags:
isCentralHeatingEnabled -> isCentralHeatingActive
isHotWaterEnabled -> isHotWaterActive
isCoolingEnabled -> isCoolingActive

Nest Thermostat

Hi

I am on the steeping learning curve of OpenTherm and currently struggling to get a slave to master communication setup and working.

My hardware
Nest GenIII Smart Thermostat (Master)
Wemos D1 with an Opentherm Slave shield https://www.tindie.com/products/thehognl/opentherm-slave-shield-for-wemoslolin/

Code
https://github.com/ihormelnyk/opentherm_library/blob/master/examples/OpenThermSlave_Demo/OpenThermSlave_Demo.ino

Pin definitions
const int inPin = 4;
const int outPin = 5;

It looks like the code is running and talking to the shield as I do get a response (which freezes if I do remove opentherm wiring to Nest thermostat).

However , all I get on the serial monitor is
..T0
..Bf0000000
..T0
..Bf0000000
..T0
..Bf0000000

Also, the Nest Thermostat states that it cannot locate an OpenTherm device when scrolling through its setup menu.

Seems that there maybe a need for a handshake maybe?

Any help is appreciated or a pointer to a forum where there are similar users active online.

thanks in advance....

strange return value

Hello! Thank you so much for your development!
I use an example of your code to get the value of the boiler modulation and get a strange value, if it is divided by 256 then do not get a number from 0 to 100%

  unsigned int data = 0xFFFF;
  unsigned long request = ot.buildRequest(
  OpenThermRequestType::READ,
  OpenThermMessageID::RelModLevel,
  data);
  Serial.println("mod:"+String(ot.sendRequest(request)));
Central Heating: on
Hot Water: off
Flame: off
diagnost: 0
fault: 0
**mod:3222339584**
Boiler temperature is 36.80 degrees C

Asynchronous requests example?

Hi there,

I'm currently developing a script which aims to integrate an OpenTherm boiler with Homebridge.

In this script, I attempt to make quite a few requests at the same time and have noticed that there is a large delay in doing so, causing the script to run slowly. After doing some looking around, I saw that you mentioned asynchronous requests on your website and assume that these will be able to fix the issue by implementing them on all of the requests I make to OpenTherm.

However, whilst you did write some basic instructions on how to implement these requests, I am still struggling to understand exactly how to do so. Would you be able to give a short example showing how exactly to implement asynchronous requests?

To help illustrate, here is a simplified version of my script (delay(1000); is purely there for simplicity - look here for clarity):

#include <OpenTherm.h>

const int inPin = 4;
const int outPin = 5;
OpenTherm ot(inPin, outPin);

unsigned long request, response;
float boilerTempCurrent, dhwTemp;
int currentHeatingCoolingState, domesticHotWater;

bool enableCentralHeating = true;
bool enableHotWater = true;
bool enableCooling = false;
float dhwSetPoint = 50;
float boilerTargetTemp = 90;

void handleInterrupt() {
  ot.handleInterrupt();
}

void setup() {
  ot.begin(handleInterrupt);
}

void loop() {

  //Set statuses
  response = ot.setBoilerStatus(enableCentralHeating, enableHotWater, enableCooling);
  OpenThermResponseStatus responseStatus = ot.getLastResponseStatus();
  if (responseStatus != OpenThermResponseStatus::SUCCESS) {
    Serial.println("Error: Invalid boiler response " + String(response, HEX));
  } else {

   //Get CH temperature
    boilerTempCurrent = ot.getBoilerTemperature();

    //Set CH temperature
    ot.setBoilerTemperature(boilerTargetTemp);

    //Get CH state
    currentHeatingCoolingState = ot.isCentralHeatingEnabled(response);

    //Get DHW state
    domesticHotWater = ot.isHotWaterEnabled(response);

    // Set DHW temperature
    unsigned int data = ot.temperatureToData(dhwSetPoint);
    request = ot.buildRequest(
      OpenThermRequestType::WRITE,
      OpenThermMessageID::TdhwSet,
      data
    );
    ot.sendRequest(request);

    // Get DHW temperature
    request = ot.buildRequest(
      OpenThermRequestType::READ,
      OpenThermMessageID::Tdhw,
      0x0000
    );
    response = ot.sendRequest(request);
    dhwTemp = ot.getTemperature(response);
  }
  //Simulate `milis()`
  delay(1000);
}

Thank you in advance for your help,

Kind regards, Tom

Protocol instability, request for help

I've built a gateway using this library. One end is connected to a Google Nest, and another to a boiler. I'm seeing a lot of instability in the messages. Examples are: invalid thermostat and boiler messages, timeouts, duplicate boiler responses, boiler response being received after the thermostat has sent a new message (so, a response to the previous thermostat request).

My best guess is that the cause of this issue is the other stuff I'm doing on the Arduino Nano Every. It's a ZigBee device (ZHA connected to Home Assistant). I'm using SoftwareSerial to connect to the XBee radio and I'm (currently) printing a lot to Serial.

Could this be the cause of the instability I'm seeing, or does the problem likely lie elsewhere? If this is the cause of the issue, are there known ways in which I can solve this issue? I can attach a log of the messages, but honestly it's all over the place.

The code of my project is here: https://github.com/pvginkel/ZigBeeHomeAutomation/tree/master/ThermostatProxy.

UPDATE

I should have checked this before I created the ticket. I've tested the program with XBee, SoftwareSerial and ZHA disabled, and removing all Serial print messages until after I send back the response of the boiler to the thermostat. This works better. At least the boiler is now responding to commands by the thermostat.

However, I'm still seeing errors. Sporadic ones and sometimes a flurry of them. And other times I see no errors for a prolonged duration.

I still have the following questions:

  • Are sporadic errors to be expected?
  • What's the best way handling doing both OpenTherm and SoftwareSerial on the same device?

Room thermostat values not available

I received the slave shield today, but i noticed the API doesn't support retrieving the following values from my thermostat:

  • TrSet
  • DayTime
  • Day
  • Year
  • Tr

I would like to use my thermostat as a simple temperature GUI to control my domotica.

Additionally, does OpenTherm implement a signal that tells me to start heating or start cooling? I also can find the implementation for that.

Not compiling when "thingProperties.h" is used.

When using
#include "thingProperties.h"
#include <OpenTherm.h>
an error is generated when compiling the code.
There seems to be a redeclaration of ' READ' (already used in ThingProperties).

Probably easy to solve but I'm new to all this and don't know how. Any suggestions welcome.

Can you add the possibility to invert the Pin signals, as some schematics are different

enum class OpenThermMode : bool
{
    SLAVE = false,
    MASTER = true
};

OpenTherm(int inPin = 4, int outPin = 5, OpenThermMode isSlave = OpenThermMode::MASTER, bool InvIn = false, bool InvOut = false);

OpenTherm::OpenTherm(int inPin, int outPin, OpenThermMode isSlave , bool InvIn , bool InvOut ) : 
    status(OpenThermStatus::NOT_INITIALIZED),
    inPin(inPin),
    outPin(outPin),
	InvIn(InvIn),
	InvOut(InvOut),

int IRAM_ATTR OpenTherm::readState() {
	if (InvIn)
		return 1 ^ digitalRead(inPin);
	else
		return digitalRead(inPin);
}

void OpenTherm::setActiveState() {
	if (InvOut)
		digitalWrite(outPin, LOW);
	else 
		digitalWrite(outPin, HIGH);
}

void OpenTherm::setIdleState() {
	if (InvOut)
		digitalWrite(outPin, HIGH);
	else
		digitalWrite(outPin, LOW);
}

Heating start / stop (no enable /disable)

Hi
First of all, thanks for the great job with this library, it's really nice have an open source alternative to communicate with the boilers.

Recently I install a BAXI-ROCA boiler, compatible with opentherm and I bought the opentherm adapter with shield for ESP8266. From the examples available, I created a fork with MQTT to integrate it to Home Assistant and use as temperature reference different sensors.

Almost everything it's working fine (enable / disable hot water, set temperature of hot water, enable / disable heating, setting the temperature of heating with PID) except the most important, tell to boiler when must start heating or stop, in other words, the thermostat. If I enable the heating, it's start heating and if I disable heating it stops, but I think that is not the correct way.....

Without the opentherm connected I can use a relay to start or stop the heating keeping the heating enabled, so I know that it's something that I miss in the code, but I cant' find it in the library definition.

any help will be welcome ;)

Thanks in advance

[question] Data timing

Hi!

I was reading through the library code, trying to comprehend the timing it applies, specifically the usage of 750μs here and here.

If I understand the code and the OpenTherm specification correctly, shouldn't that be 650μs (500μs nominal plus an additional 150μs for the maximum transition period)?

image

Also, strictly speaking, shouldn't a timeout occur after 1150μs instead of 1000μs as it does now?

Reason I'm asking is because I'm trying to track down some issues with invalid messages being received from my thermostat. I'll try and see if changing the timing fixes them, but just wondering if I understand the code correctly 😊

Setting the correct temperature and controlling central heating

Hi there,

I love this project and have really enjoyed playing around with it. I've successfully been able to interface with my boiler and have been able to do a few things like getting and setting the temperature. My aim with the project is to integrate it with homebridge-thermostat using a NodeMCU in order to expose it to my iPhone.

Like I mentioned, I have been successfully able to use some of the functionality of your library but still have 4 questions remaining:

  1. When returning the statuses of things like the flame and the central heating, everything seems normal (on). However, Hot Water get reported as off, which it is not. This is not too much of an issue because the hot water still seems to work fine from taps but I thought it was curious. Is is that my boiler does have the ability to manage the Hot Water and this is why it appears as off?

  2. During the summer, how do I turn off the central heating whilst retaining hot water? I have tried setting bool enableCentralHeating = false; then calling ot.setBoilerStatus(enableCentralHeating, enableHotWater, enableCooling); again yet the Central Heating stays on. Is it possible to turn off the central heating or is it the case that I need to set the temperature to a really low value or something of that nature?

  3. What exactly is boiler cooling? I see that it is a status you can check (mine shows as off no matter what temperature is set), yet once again, as with enableCentralHeating, enableCooling seems to be another thing I can't control with the steps mentioned above. Is this once again functionality that my boiler doesn't have?

  4. Finally, and most difficulty I suppose; if I would like to set the house temperature to 23 C for example, how do I control the boiler in such a way to achieve this? As in, I would assume that I need a thermometer as mentioned in your guide, yet it is not clear how I would go from the raw current temperature of the room to the temperature I would need to set the boiler. Surely it is not the case that you just turn on the boiler to full until you reach the desired temperature then repeat this if the temperature drops below that temperature? I have tried reading through your Arduino code on the guide and have seen that you set the temperature to op, yet it is not clear exactly how you derive this number.

I feel that much of my confusion comes from a lack of understanding of how exactly to use your library which is why I was hoping that you could help.

Thank you in advance for your help,

Kind regards, Tom

OpenThermMessageID 50 missing

You are missing the id 50 in the OpenThermMessageID
HcratioUBHcratioLB = 50, // s8/s8 OTC heat curve ratio upper & lower bounds for adjustment

ISR not in IRAM!

Hi,

great work here. since i want to connect my boiler to my domoticz installation, i purchased your opentherm adapter and shield.

My approach is to get your opentherm thermostat sample up and running and then change it so i can manage the boiler temperature from my domoticz instance.

so i followed the steps to get the example up and running, it fails to start. It just starts rebooting all over again on an ISR not in Iram exception, with the following loglines endlessly repeated in the serial monitor:

........
Connected to <mySSiD>
IP address: <MyIP>
MDNS responder started
HTTP server started
ISR not in IRAM!

User exception (panic/abort/assert)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Abort called

>>>stack>>>

ctx: cont
sp: 3ffffe90 end: 3fffffc0 offset: 0000
3ffffe90:  00000005 00000040 00000020 00000000  
3ffffea0:  000000fe 00000000 00000000 00000000  
3ffffeb0:  00000000 00000000 00000000 00ff0000  
3ffffec0:  5ffffe00 5ffffe00 3ffefa64 00000000  
3ffffed0:  00000003 00000004 3ffee444 4020d1f2  
3ffffee0:  4010076e 00000000 4bc6a7f0 4020d204  
3ffffef0:  00000000 4bc6a7f0 3ffee444 4020d711  
3fffff00:  00000000 00000000 4bc6a7f0 00000000  
3fffff10:  3fffff40 3ffee46c 40100504 3ffefa30  
3fffff20:  00000000 402010c0 3ffee444 4020d7c0  
3fffff30:  0019e0aa 3ffee4a0 3ffee46c 4020ac5d  
3fffff40:  00000001 3ffee4a0 3ffee46c 4020ac88  
3fffff50:  00000001 3ffee4a0 3ffee46c 40201ded  
3fffff60:  402035e0 0502a8c0 4020e7d4 4020e7c0  
3fffff70:  4020ef48 6d657400 feef0070 80efeffe  
3fffff80:  3ffefa30 00000000 feefeffe feefeffe  
3fffff90:  feefeffe feefeffe feefeffe 3ffee6c8  
3fffffa0:  3fffdad0 00000000 3ffee688 4020cbc0  
3fffffb0:  feefeffe feefeffe 3ffe84f0 40101069  
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 3584, room 16 
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld

I did some tracing, it fails the statement "ot.begin(handleInterrupt);"

any idea how to make the sample work?

Some MessageId 's are wrong

In your enum for the MessageId you have to skip some id's

I changed it like this:
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 };

ICACHE_RAM_ATTR is deprecated

OpenTherm Library/src/OpenTherm.cpp:97:18: warning: 'bool OpenTherm::isReady()' is deprecated: Use IRAM_ATTR in place of ICACHE_RAM_ATTR to move functions into IRAM [-Wdeprecated-declarations]
97 | while (!isReady()) {

so change ICACHE_RAM_ATTR to IRAM_ATTR

OpenTherm v3.0 Compatibility?

I understand this might be the wrong repository to ask such a question, however I was wondering if you have any information about compatibility with OpenTherm protocol specification v3.0. Unfortunately I can not find the specification information online but as I understand the signal low and signal high voltages are higher then with specification V2.2.

If I measure the voltage between the OpenTherm connections on my central heating unit/boiler I measure around 26.5V. Would it be possible to switch out the Zeners to higher value ones? Furthermore does anyone happen to know what the signal low and signal high values for V3.0 are? I assume the signal low will be around that 26.5V, but is there a method to also measure the signal high voltage?

Help would be greatly appreciated however please do not hesitate to close this issue since it is not directly related to the OpenTherm library.

Small error in OpenThermMaster_Demo example

In OpenThermMaster_Demo.ino lines 58 onwards read

    else if (responseStatus == OpenThermResponseStatus::INVALID) {
        Serial.println("Error: Invalid response " + String(response, HEX));
    }

I believe this is printing the wrong variable, it should be

    else if (responseStatus == OpenThermResponseStatus::INVALID) {
        Serial.println("Error: Invalid response " + String(responseStatus, HEX));
    }

Querying/Controlling ventilation system

I'm trying to query/set my Wolf CWL300 (also known as Viessmann Vitovent etc.) home ventilation system via opentherm. Do you have any experience which parameters I can use, or any example code?

Add method getLastResponse

Hello.
Please add the getLastResponse method to the OpenTherm class:

unsigned long OpenTherm::getLastResponse()
{
	return response;
}

This is necessary to change the class to work in "async" mode (ESP8266Scheduler).
Now response is private and it's impossible to get its value by inheritance. Without these changes, the sendRequest method will block other tasks while waiting for a response.

My example:

#include <OpenTherm.h>

class CustomOpenTherm : public OpenTherm {
private:
  unsigned long send_ts = millis();
  void(*handleSendRequestCallback)(unsigned long, unsigned long, OpenThermResponseStatus status, byte attempt);
  
public:
  CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
  void setHandleSendRequestCallback(void(*handleSendRequestCallback)(unsigned long, unsigned long, OpenThermResponseStatus status, byte attempt)){
    this->handleSendRequestCallback = handleSendRequestCallback;
  }
  
  unsigned long sendRequest(unsigned long request, byte attempts = 5, byte _attempt = 0) {
    _attempt++;
    while (send_ts > 0 && millis() - send_ts < 200) {
      Scheduler.yield();
    }
    
    //unsigned long response = OpenTherm::sendRequest(request);
    unsigned long _response;
    if (!sendRequestAync(request)) {
      _response = 0;
    } else {
      while (!isReady()) {
        Scheduler.yield();
        process();
      }

      _response = getLastResponse();
    }

    if (handleSendRequestCallback != NULL) {
      handleSendRequestCallback(request, _response, getLastResponseStatus(), _attempt);
    }
    
    send_ts = millis();
    if ( getLastResponseStatus() == OpenThermResponseStatus::SUCCESS || _attempt >= attempts ) {
      return _response;
    } else {
      return sendRequest(request, attempts, _attempt);
    }
  }
};

Boot loop (solved).

Hi :-)
My ESP8266s keep rebooting after "OpenThermMaster_Demo.ino" upload with message:
"
ets Jan 8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 1392, room 16
tail 0
chksum 0xd0
csum 0xd0
v3d128e5c
~ld
"
My environment:

  • ESP-12E (different modules),
  • Arduino v. 1.8.12, ESP8266 v. 2.6.3,
  • OpenTherm v. 1.1.0,
  • inPin = 4,
  • outPin = 5.

Please help :-)
Regards
MK

Help needed - boiler not starting - viessman vitodens 100-w

Hi, i have a viessmann vitodens 100-w with underfloor heating, i have successfully connected via opentherm to the boiler, i ca set direct hot water temperature and boiler temperature and successfully updates on the boiler lcd screen.

I have a few problems i cannot seems to manage and any help will be appreciated (bare with me, i'm a new to codding) :

  1. changing heating and water temperature works but looks like the boiler is not starting, no flame and no pump running, i have tried to send the commands mentions in this issue #40 but i always get an error 40000302 (not sure how to decode this)

  2. from time to time, my boiler starts and ramps temperature to ~80C and waits to cool, i have no idea why this is happening since hot water is set to 45c and boiler is set to 35C.

  3. is there a way to tell the boiler max modulation to heat the water? eg like ~20% ? i want to stay as low as possible since i don't need high temp with underfloor heating

Thanks again for any help/explanation, your time is appreciated.

OpenTherm/Lite

Is this library compatible with OpenTherm/Lite (PWM Control)?

Re-Order Error using platformio

When I try to compile your example using 'platformio' IDE, I get few errors :

Compiling .pio\build\esp32doit-devkit-v1\lib7f8\OpenTherm Library_ID5483\OpenTherm.cpp.o
In file included from .pio\libdeps\esp32doit-devkit-v1\OpenTherm Library_ID5483\src\OpenTherm.cpp:6:0:
.pio\libdeps\esp32doit-devkit-v1\OpenTherm Library_ID5483\src\OpenTherm.h: In constructor 'OpenTherm::OpenTherm(int, int, bool)':
.pio\libdeps\esp32doit-devkit-v1\OpenTherm Library_ID5483\src\OpenTherm.h:134:27: error: 'OpenTherm::status' will be initialized after [-Werror=reorder]
  volatile OpenThermStatus status;
                           ^
.pio\libdeps\esp32doit-devkit-v1\OpenTherm Library_ID5483\src\OpenTherm.h:119:25: error:   'volatile long unsigned int OpenTherm::response' [-Werror=reorder]
  volatile unsigned long response;
                         ^
.pio\libdeps\esp32doit-devkit-v1\OpenTherm Library_ID5483\src\OpenTherm.cpp:7:1: error:   when initialized here [-Werror=reorder]
 OpenTherm::OpenTherm(int inPin, int outPin, bool isSlave):
 ^
cc1plus.exe: some warnings being treated as errors
*** [.pio\build\esp32doit-devkit-v1\lib7f8\OpenTherm Library_ID5483\OpenTherm.cpp.o] Error 1
================================================================================================== [FAILED] Took 4.28 seconds ==================================================================================================
The terminal process terminated with exit code: 1

I just switch private and public properties declaration in OpenTherm.h, and moved volatile OpenThermStatus status like this :

/*
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::NOT_INITIALIZED),
	inPin(inPin),
	outPin(outPin),
	isSlave(isSlave),
	response(0),
	responseStatus(OpenThermResponseStatus::NONE),
	responseTimestamp(0),
	handleInterruptCallback(NULL),
	processResponseCallback(NULL)
{
}
/* (...) */
/*
OpenTherm.h - OpenTherm Library for the ESP8266/Arduino platform
/* (...) */
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, OpenThermResponseStatus));
	bool isReady();
	unsigned long sendRequest(unsigned long request);
	bool sendResponse(unsigned long request);
	bool sendRequestAsync(unsigned long request);
	unsigned long buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
	unsigned long buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
	OpenThermResponseStatus getLastResponseStatus();
	const char *statusToString(OpenThermResponseStatus status);
	void handleInterrupt();	
	void process();
	void end();

	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();    

	//responses    
	bool isFault(unsigned long response);
	bool isCentralHeatingActive(unsigned long response);
	bool isHotWaterActive(unsigned long response);
	bool isFlameOn(unsigned long response);
	bool isCoolingActive(unsigned long response);
	bool isDiagnostic(unsigned long response);
	uint16_t getUInt(const unsigned long response) const;
	float getFloat(const unsigned long response) const;
	float getTemperature(unsigned long response);
	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();
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, OpenThermResponseStatus);
};
/*  (...)  */

And errors disappear...

ISR not in IRAM issue ESP8266

Hi there,

I'm having problems using the library with the newest ESP8266 release (v2.5.1). Specifically, when trying to call:

void handleInterrupt() {
  ot.handleInterrupt();
}

It seems others have been having this issue in similar situations as you can see here. I get a very similar error message to the one I linked - something like:

ISR not in IRAM!

Abort called

>>>stack>>>

As I understand it, the correct way to solve this issue is to change the library to move the ISR into IRAM, otherwise the script never proceeds past this interrupt function. However, I'm unsure how you would do this otherwise I would've made a pull request to resolve the issue.

Do you have any ideas?

Kind regards,
Tom

P.S. I am using ESP8266 v2.5.0 for now as the issue is only with the newest version

OpenTherm monitor

I've got a Baxi 824 System Boiler with Weather Compensation and a Hive Thermostat which is not OpenTherm capable. As my boiler is in my loft, I'd like to be able to view boiler status information such as flow and return temps, weather compensation temp, boiler on/off status etc. I don't plan on changing the Hive Thermostat for the time being. I've ordered a couple of the Master OpenTherm Shields to go with a few ESP32s I've got.
Do you know if I can just use the OpenTherm shield as a monitor and continue to control the boiler via the (230v) Hive controls, or will using the OpenTherm Shield take complete control of the boiler?

[HELP] OpenTherm Master Schematic

I all guys, i need a big help to make my project work.

I replicated the electrical schematic of the OpenTherm Master in my own board with an ESP32 but for some reason is not working (working fine using the opentherm master board that i bought from the website).

Here my schematic:

image

Here the component list:
image

What could be wrong?

Class extension/inheritance

Hello everyone, I was trying to extend OpenTherm class by adding additional requests. Unfortunately when I run the extended class communication with boiler does not work. Exemplary code is attached here below. Do I do something wrong?

Du summarise. When I run
OpenTherm *ot = new OpenTherm(1,2); ot->begin(handler);
it works. When I use the extension i.e.
OpenThermExtension *ot = new OpenThermExtension(1,2); ot->begin(handler);
it does not. Obviously it compiles without any warning.

`
class OpenThermExtension : public OpenTherm {
public:
OpenThermExtension(int in, int out);
float getOutsideTemperature();
};

OpenThermExtension::OpenThermExtension(int in, int out) {
OpenTherm(in, out, false);
}

float OpenThermExtension::getOutsideTemperature() {
unsigned long request = buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Toutside, 0);
unsigned long response = sendRequest(request);
Serial.println("Response: " + String(response));
float temp = getTemperature(request);
return temp;

}
`

SetActiveState and SetIdleState are inverted

Hello, I noticed that these two functions should be inverted, since in OpenTherm documentation, idle state is defined as LOW level and active state as HIGH level.

I'm not sure how this works with real boilers and thermostats, because I only tried this library between two ESP8266 (one as boiler/slave, one as thermostat/master, tested also with ESP32) and with original code, messages received on slave were vastly different than those sent from master. And after I inverted these two functions, it worked perfectly and messages were correct.

Viessmann Vitodens 100

Спасибо за полезную библиотеку.
Вижу, что в Тасмота для реализации OpenTherm используется именно она.
У меня возникло несколько вопросов по использованию библиотеки.

  1. В момент опроса котла Viessmann по протоколу OPENTHERM перестаёт работать управление котлом через копки на его панели. Можно ли это исправить каким-то иным режимом?
  2. При подключении к котлу сразу задаются установки теплоносителя. Можно ли сначала считать имеющиеся параметры, а затем, при необходимости их менять? Возможно, это вопрос по настройке Тасмота, но всё же надеюсь на помощь автора и сообщества, которому интересна работа по OpenTherm.
  3. При отключении OpenTherm котел реализует погодозависимую теплогенерацию. С панели задаю температуру ГВС и параметр кривой отопления, от которого зависит текущая температура теплоносителя с учетом наружной температуры. Наружная текущая температура также отражается на дисплее котла.
    3.1. Возможно ли получить по OpenTherm текущую наружную температуру?
    3.2. Возможно ли считать и менять через OpenTherm параметр кривой отопления по которому меняется погодозависимая теплогенерация?

Compilation issue in Tasmota ESP32 build with BLE and OpenTherm enabled

Hi all,

I'm trying to build the Tasmota firmware with both BLE and Open Therm enabled:
#define USE_OPENTHERM
#undef USE_IBEACON
#define USE_BLE_ESP32 // Enable new BLE driver
#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)

I got following error output. I was trying to fix it with the namespaces, but failed. Any suggestions how to avoid the naming conflict ?

Compiling .pio/build/tasmota32/src/tasmota.ino.cpp.o
In file included from /workspace/Tasmota/tasmota/xsns_69_opentherm.ino:24:0:
lib/lib_div/OpenTherm-0.9.0/src/OpenTherm.h:30:20: error: redeclaration of 'READ'
READ = READ_DATA, // for backwared compatibility
^
In file included from lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.h:24:0,
from lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h:26,
from lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h:35,
from /workspace/Tasmota/tasmota/xdrv_79_esp32_ble.ino:148:
lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.h:29:5: note: previous declaration 'NIMBLE_PROPERTY READ'
READ = BLE_GATT_CHR_F_READ,
^
In file included from /workspace/Tasmota/tasmota/xsns_69_opentherm.ino:24:0:
lib/lib_div/OpenTherm-0.9.0/src/OpenTherm.h:32:20: error: redeclaration of 'WRITE'
WRITE = WRITE_DATA, // for backwared compatibility
^
In file included from lib/libesp32_div/NimBLE-Arduino/src/NimBLEService.h:24:0,
from lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h:26,
from lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h:35,
from /workspace/Tasmota/tasmota/xdrv_79_esp32_ble.ino:148:
lib/libesp32_div/NimBLE-Arduino/src/NimBLECharacteristic.h:33:5: note: previous declaration 'NIMBLE_PROPERTY WRITE'
WRITE = BLE_GATT_CHR_F_WRITE,

[question] Async response handler: sending back responses doesn't work without delay

I have an issue with sending back responses from an async response handler. My code looks like this:

void ICACHE_RAM_ATTR handleInterrupt() {
  ot.handleInterrupt();
}

void processRequest(unsigned long request, OpenThermResponseStatus status) {
  if (status != OpenThermResponseStatus::SUCCESS) return;

  auto dataId = ot.getDataID(request);
  auto response;

  if (dataId == 0) {
    response = ot.buildResponse(…);
  } else if (dataId == 1) {
    response = ot.buildResponse(…);
  } else { … }

  ot.sendResponse(response);
}

void setup() {
  ot.begin(handleInterrupt, processRequest);
}

void loop() {
  ot.process();
}

Basically, I'm trying to build a (very minimal) boiler simulator by responding to commands sent by a thermostat.

The issue is that unless I add a delay (of about 200ms) before ot.sendResponse(), the response seems to put the thermostat in an error mode. Do I have to wait for a specific event before I can send back a response? Or am I doing something wrong entirely?

For what it's worth, the thermostat is sending quite a lot of messages, mostly READ_DATA for different types of data ID's.

Cannot communicate with Intergas Kompakt HR 22

I have an Intergas Kompakt HR 22 and normally it's connected to a Honeywell T87M OpenTherm thermostat.

I've put this basic OpenTherm sketch onto an ESP8266 (Wemos D1 mini) which has a DIYLESS Master OpenTherm Shield on it, connected it to the boiler instead of the Honeywell thermostat, and all I get is:

Error: Invalid boiler response 0

Pins are correctly configured:

const int inPin = 4; // D2
const int outPin = 5; // D1

I'm not entirely sure how to move forward with debugging, any help would be appreciated 😢

Only getting invalid response on Master side

Hello @ihormelnyk and everyone, thank you for providing this library to use for free. I'm trying to use the Slave example as a way to simulate a boiler. The Slave is receiving the requests from the Master without any problems. Unfortunately, the responses I have sent out from the Slave back to the Master has always been considered as invalid responses by the Master. Debugging the response frame showed me that I'm only receiving 0s from the Slave. I would appreciate it if anyone who has had this problem to be able to give me tips on what they did to fix the problem. Thank you and kind regards.

Ameer

Can't build in Platformio, getTemperature is missing in cpp

I download the master version of your lib to my project (I'am using platformio 5.0.1), I'm just updating an existing project that used OpenTherm::getTemperature().
The signature OpenTherm::getTemperature is present in your headers (l153), but not in your cpp...??

I fix it by adding this :

float OpenTherm::getTemperature(unsigned long response) {
	float temperature = isValidResponse(response) ? getFloat(response) : 0;
	return temperature;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.