Diyless Opentherm to Domoticz

Everything about esp8266 and more.

Moderator: leecollings

Post Reply
Knibor
Posts: 112
Joined: Sunday 20 May 2018 12:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Stable
Location: NL
Contact:

Diyless Opentherm to Domoticz

Post by Knibor »

Hello,

I am experimenting with an OpenTherm board from Diyless ( https://diyless.com/blog/domoticz-opentherm-thermostat) This board is connected to an ESP8266.

The diyless OpenTherm board has a temperature sensor on it.
I ran into the following problem, maybe someone has a solution for the following problem.

The thermostat control from Domoticz to my boiler works. However, the problem is that with this plugin he measures the temperature of the temperature sensor on the print of Diyless Opentherm. However, I would like him to measure the temperature of a Domoticz indoor temperature sensor. In the plugin setup you can specify the IDX of the indoor temperature gauge, but it will still use the temperature sensor on the Diyless board. How to modify the plugin script so that it controls from a Domoticz indoor temperature sensor?

Thanks
Robin
User avatar
waltervl
Posts: 5148
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: Diyless Opentherm to Domoticz

Post by waltervl »

As I understand from the link you gave you will have to rewrite the Arduino sketch so that it uses the temperature sensor of Domoticz by MQTT.

In the sketch it uses the build in temperature sensor to control the boiler based on the setpoint from Domoticz.
So you will have to add a section to also read the Domoticz temperature sensor by MQTT (like the setpoint temp).
Domoticz is sending that temperature already by MQTT.
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
Knibor
Posts: 112
Joined: Sunday 20 May 2018 12:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Stable
Location: NL
Contact:

Re: Diyless Opentherm to Domoticz

Post by Knibor »

Hello,

Thank you for the information. But I have no programming skills. Is there anyone who has an example how to adapt the sketch for a temperature sensor from Domoticz instead of:
" // Temperature sensor pin const int ROOM_TEMP_SENSOR_PIN = 14; //for Arduino, 14 for ESP8266 (D5), 18 for ESP32"

Sketch OpenTherm

Code: Select all

#include <ESP8266WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <OpenTherm.h>

// Your WiFi credentials.
// Set password to "" for open networks.
const char* ssid = "xxxxxx";
const char* pass = "xxxxxx";

// Your MQTT broker address and credentials
const char* mqtt_server = "xxx.xxx.xxx.xxx";
const char* mqtt_user = "xxxxxx";
const char* mqtt_password = "xxxxxx";
const int mqtt_port = 1883;

// Master OpenTherm Shield pins configuration
const int OT_IN_PIN = 4;  //for Arduino, 4 for ESP8266 (D2), 21 for ESP32
const int OT_OUT_PIN = 5; //for Arduino, 5 for ESP8266 (D1), 22 for ESP32

// Temperature sensor pin
const int ROOM_TEMP_SENSOR_PIN = 14; //for Arduino, 14 for ESP8266 (D5), 18 for ESP32

const char* OUT_TOPIC = "domoticz/out";
const char* IN_TOPIC = "domoticz/in";

const String SETPOINT_NORMAL_ID = "xxxxxx";
const String CONTROL_ID = "xxxxxx";


const unsigned long statusUpdateInterval_ms = 1000;

float  sp = 15, //set point
       t = 15, //current temperature
       t_last = 0, //prior temperature
       ierr = 25, //integral error
       dt = 0, //time between measurements
       op = 0; //PID controller output
unsigned long ts = 0, new_ts = 0; //timestamp
unsigned long lastUpdate = 0;
unsigned long lastTempSet = 0;

bool heatingEnabled = true;

#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];

OneWire oneWire(ROOM_TEMP_SENSOR_PIN);
DallasTemperature sensors(&oneWire);
OpenTherm ot(OT_IN_PIN, OT_OUT_PIN);
WiFiClient espClient;
PubSubClient client(espClient);

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

float getTemp() {
  return sensors.getTempCByIndex(0);
}

float pid(float sp, float pv, float pv_last, float& ierr, float dt) {
  float KP = 10;
  float KI = 0.02;
  // upper and lower bounds on heater level
  float ophi = 63;
  float oplo = 20;
  // calculate the error
  float error = sp - pv;
  // calculate the integral error
  ierr = ierr + KI * error * dt;
  // calculate the measurement derivative
  //float dpv = (pv - pv_last) / dt;
  // calculate the PID output
  float P = KP * error; //proportional contribution
  float I = ierr; //integral contribution
  float op = P + I;
  // implement anti-reset windup
  if ((op < oplo) || (op > ophi)) {
    I = I - KI * error * dt;
    // clip output
    op = max(oplo, min(ophi, op));
  }
  ierr = I;

  Serial.println("sp=" + String(sp) + " pv=" + String(pv) + " dt=" + String(dt) + " op=" + String(op) + " P=" + String(P) + " I=" + String(I));

  return op;
}

// This function calculates temperature and sends data to MQTT every second.
void updateData()
{
  //Set/Get Boiler Status
  bool enableHotWater = true;
  bool enableCooling = false;
  unsigned long response = ot.setBoilerStatus(heatingEnabled, enableHotWater, enableCooling);
  OpenThermResponseStatus responseStatus = ot.getLastResponseStatus();
  if (responseStatus != OpenThermResponseStatus::SUCCESS) {
    Serial.println("Error: Invalid boiler response " + String(response, HEX));
  }

  t = getTemp();
  new_ts = millis();
  dt = (new_ts - ts) / 1000.0;
  ts = new_ts;
  if (responseStatus == OpenThermResponseStatus::SUCCESS) {
    op = pid(sp, t, t_last, ierr, dt);
    ot.setBoilerTemperature(op);
  }
  t_last = t;
  sensors.requestTemperatures(); //async temperature request
  Serial.println("Current temperature: " + String(t) + " °C ");
}

String convertPayloadToStr(byte* payload, unsigned int length) {
  char s[length + 1];
  s[length] = 0;
  for (int i = 0; i < length; ++i)
    s[i] = payload[i];
  String tempRequestStr(s);
  return tempRequestStr;
}

DynamicJsonDocument doc(768);

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.println("Callback");

  const String topicStr(topic);
  String payloadStr = convertPayloadToStr(payload, length);

  deserializeJson(doc, payloadStr);

  const String id((const char*)doc["id"]);

  Serial.println("Received, id=" + id);

  if (id == SETPOINT_NORMAL_ID) {
    const String targetTemp((const char*)doc["svalue1"]);
    sp = targetTemp.toFloat();
  }
  else if (id == CONTROL_ID) {
    const String targetMode((const char*)doc["svalue1"]);
    Serial.println("Set mode " + targetMode);
    if (targetMode == "0")
      heatingEnabled = false;
    else if (targetMode == "10" || targetMode == "20")
      heatingEnabled = true;
    else
      Serial.println("Unknown mode");
  }

  doc.clear();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    const char* clientId = "opentherm-thermostat-test";
    if (client.connect(clientId, mqtt_user, mqtt_password)) {
      Serial.println("ok");

      client.subscribe(OUT_TOPIC);
      client.setBufferSize(1024);
    } else {
      Serial.print(" failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
  Serial.begin(115200);

  Serial.println("Connecting to " + String(ssid));
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  int deadCounter = 20;
  while (WiFi.status() != WL_CONNECTED && deadCounter-- > 0) {
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Failed to connect to " + String(ssid));
    while (true);
  }
  else {
    Serial.println("ok");
  }

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  ot.begin(handleInterrupt);

  //Init DS18B20 sensor
  sensors.begin();
  sensors.requestTemperatures();
  sensors.setWaitForConversion(false); //switch to async mode
  t, t_last = getTemp();
  ts = millis();
}

void loop()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  unsigned long now = millis();
  if (now - lastUpdate > statusUpdateInterval_ms) {
    lastUpdate = now;
    updateData();
  }
}
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest