Термостат OpenTherm на ESP8266

golosun
Offline
Зарегистрирован: 31.10.2016

Я понимаю, что прошивка, в этом и вопрос

golosun
Offline
Зарегистрирован: 31.10.2016

Прошивка, выводящая лог - не моя

tsv_33
Offline
Зарегистрирован: 11.04.2019

golosun пишет:

Прошивка, выводящая лог - не моя

golosun пишет:

 А вот записать - при установке температуры бойлера в НОЛЬ ( ot.setBoilerTemperature(0), нагрев отключается,

О чём тогда лог, если этого в нём не усматривается...

golosun
Offline
Зарегистрирован: 31.10.2016

так и есть

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

да на МQTT у OldNavi много интересного но разсобрать я не мог 

поэтому для своих задач использую   blynk 

делал для включения котла

1. в режиме автоматические

 

  

2. в режиме Термостат

 

Настройка 

для контроля тем. и за ( утечки и угарный газ ) и т.д....

miks69
Offline
Зарегистрирован: 16.02.2020

knt58dualtv, интересно, как вы прикрутили OpenTherm к Blynk, можете выложить код скетча?

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

miks69 пишет:

knt58dualtv, интересно, как вы прикрутили OpenTherm к Blynk, можете выложить код скетча?

НИ ЧЕГО НОВОГО у скетчи 

стандартные 

1.пид

https://github.com/OldNavi/OpenThermController/blob/master/main.ino/OpenThermTask.ino

2.кривая

тут https://github.com/OldNavi/OpenThermController/tree/master/main.ino

3.считать и показать параметры своего котла

ваша ссылка Скачать можно по ссылке https://yadi.sk/d/tPupf8trkyye2w

и тут https://github.com/OldNavi/OpenThermController/blob/master/main.ino/OpenThermTask.ino

getBoilerTemp(),setDHWTemp(float val) .....

все остальные ваши фантазии 

miks69
Offline
Зарегистрирован: 16.02.2020

Я спрашивал про код скетча Blynk, но впрочем это не так важно. Главное, что у вас все получилось и работает.

Blynk хорошая, гибкая платформа для создания отдельных, точечных решений. Но она не предназначена для создания сложных комплексных решений, в которых у вас может быть не один десяток контроллеров, которые должны обмениваться информацией между собой.

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

У блинка нету скетчи
Там только элементы кнопки .....
из Arduino передаим значением которые нам нужные отрабражать в блинку

miks69
Offline
Зарегистрирован: 16.02.2020

knt58dualtv пишет:
У блинка нету скетчи Там только элементы кнопки ..... из Arduino передаим значением которые нам нужные отрабражать в блинку

Так я и спросил как вы из OpenTherm передаете значения в Blynk и как обратно передаете команды?

andreyasb
Offline
Зарегистрирован: 03.09.2019

miks69 пишет:

knt58dualtv пишет:
У блинка нету скетчи Там только элементы кнопки ..... из Arduino передаим значением которые нам нужные отрабражать в блинку

Так я и спросил как вы из OpenTherm передаете значения в Blynk и как обратно передаете команды?

через сервер MQTT ели управлять удаленно  , можно использовать и другие приложения и настраивать в них любые кнопки графики и т.д

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

miks69 пишет:

knt58dualtv пишет:
У блинка нету скетчи Там только элементы кнопки ..... из Arduino передаим значением которые нам нужные отрабражать в блинку

Так я и спросил как вы из OpenTherm передаете значения в Blynk и как обратно передаете команды?

ESP8266

# define VPIN_ID57  V2
 
/ Отправка на сервер при подключении
 
BLYNK_CONNECTED() {
 
  //добавить аналогично, если нужно больше датчиков
  Blynk.virtualWrite(VPIN_ID57, Tset);
  Blynk.syncVirtual(VPIN_ID57);
}
 
.....
 
  //Установка максимальной температуры теплоносителя 53c
 request = ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MaxTSet,     ot.temperatureToData(setTempBoiler));
  response = ot.sendRequest(request);
  if (checkResult(response)) {
   //передавать блинку VPIN_ID57 -значение (response >> 8) & 0xFF
    Blynk.virtualWrite(VPIN_ID57,(response >> 8) & 0xFF);
  } 
 
.....
//Получаем значения в виде Float из приложения Blynk (+ /-) когда мы увеличить 
BLYNK_WRITE(VPIN_ID57 )
 { //привязка виртуального пина к виджету установки температуры  
  if (Error==false){ //если нет ошибки
  Tset = param.asFloat(); // Получаем значение в виде Float из приложения
  updateSetMax(Tset);
  cfgWrite(F("Tset"), String(Tset));  //Запись в конфиг, Сохранение в память. cfgWrite([String], [String])
  Blynk.virtualWrite(VPIN_ID57,String(Tset,1));
  }
 
 у блинка добавить 
Value Display
V2 - максимальной температуры теплоносителя 
параметра - установить каждую 2 сек передавать значение в серверу блинку
когда делаем изменение вызывают
BLYNK_WRITE(VPIN_ID57 ) 
{
 .....
}
 
 
miks69
Offline
Зарегистрирован: 16.02.2020

Мудрено, но выглядит красиво.

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

miks69 пишет:

Мудрено, но выглядит красиво.

очень удобно для новичок и установки на телефон или планшете и т.д....  просто сканировать Q-код и сразу можно управлять на своем смартфоне!

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

andreyasb пишет:

miks69 пишет:

knt58dualtv пишет:
У блинка нету скетчи Там только элементы кнопки ..... из Arduino передаим значением которые нам нужные отрабражать в блинку

Так я и спросил как вы из OpenTherm передаете значения в Blynk и как обратно передаете команды?

через сервер MQTT ели управлять удаленно  , можно использовать и другие приложения и настраивать в них любые кнопки графики и т.д

пока нет времени разсобрать 

но скажите сервер MQTT брокер- только платно ?

а свой локальний надо имеет комтьютер или роутер з прошивки openwrt ?

 

 

miks69
Offline
Зарегистрирован: 16.02.2020

knt58dualtv пишет:

пока нет времени разсобрать 

но скажите сервер MQTT брокер- только платно ?

а свой локальний надо имеет комтьютер или роутер з прошивки openwrt ?

https://mosquitto.org/

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

miks69 пишет:

knt58dualtv пишет:

пока нет времени разсобрать 

но скажите сервер MQTT брокер- только платно ?

а свой локальний надо имеет комтьютер или роутер з прошивки openwrt ?

https://mosquitto.org/

спасибо я понял  про локальну  Eclipse Mosquitto™ 

какие еще для работы з МQTT fix ? 

я думаю что только на 10 виндос   -работают !!!

 

 

andreyasb
Offline
Зарегистрирован: 03.09.2019

можно сервер mqtt сделать на Raspberry Pi

golosun
Offline
Зарегистрирован: 31.10.2016

#499

Так никого и нет, кто может/хочет/знает?

 

tsv_33
Offline
Зарегистрирован: 11.04.2019

golosun, хотите то чего? Телепатов здесь нет.

golosun
Offline
Зарегистрирован: 31.10.2016

Ещё раз, читать все читаю, а записать - срабатывает только установки температуры в ноль, отключается отопление, все остальные значения не воспринимаются, как и не воспринимается установка темп. горячей воды. Делаю всё, как в примере библиотеки.  Прошу помощи, у кого есть опыт с этим котлом. 

tsv_33
Offline
Зарегистрирован: 11.04.2019

golosun пишет:

Делаю всё, как в примере библиотеки. 

Так вставьте сюда свой код.

golosun пишет:

у кого есть опыт с этим котлом. 

Моя прошивка с этим котлом работает.

golosun
Offline
Зарегистрирован: 31.10.2016
    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("Central Heating: " + String(ot.isCentralHeatingActive(response) ? "on" : "off"));
        Serial.println("Hot Water: " + String(ot.isHotWaterActive(response) ? "on" : "off"));
        isFlameOn = ot.isFlameOn(response);
        Serial.println("Flame: " + String(isFlameOn ? "on" : "off"));
    }
    if (responseStatus == OpenThermResponseStatus::NONE) {
        Serial.println("Error: OpenTherm is not initialized");
    }
    else if (responseStatus == OpenThermResponseStatus::INVALID) {
        Serial.println("Error: Invalid response " + String(response, HEX));
    }
    else if (responseStatus == OpenThermResponseStatus::TIMEOUT) {
        Serial.println("Error: Response timeout");
    }
 
    //Set Boiler Temperature to 64 degrees C
ot.setBoilerTemperature(77);
 
    //Get Boiler Temperature
    Temp_obr = ot.getBoilerTemperature();
    Serial.println("CH temperature is " + String(Temp_obr) + " C");
 
    //Set DHW setpoint to 40 degrees C
    ot.setDHWSetpoint(Set_Temp_water);
 
    //Get DHW Temperature
    Temp_water = getDHWSPTemp(); //ot.getDHWTemperature();
get_Year = getYear();    
    Serial.println("DHW temperature is " + String(Temp_water) + " C");
getModulation = ot.getModulation();
Serial.println("getReturnTemperature " + String(ot.getReturnTemperature()));    
     Serial.println("getModulation " + String(getModulation));
     Serial.println("getPressure " + String(ot.getPressure()));
Serial.println("isReady " + String(ot.isReady()));
//Serial.println("isCoolingActive " + String(ot.isCoolingActive() ));
//Serial.println("isDiagnostic " + String(ot.isDiagnostic() ));
Serial.println("getBurnerStarts " + String(getBurnerStarts()));
 
golosun
Offline
Зарегистрирован: 31.10.2016

А эта "Моя прошивка " отличается от примера к библиотеке, или библиотекой?

tsv_33
Offline
Зарегистрирован: 11.04.2019

golosun пишет:

А эта "Моя прошивка " отличается от примера к библиотеке, или библиотекой?

Даже смотреть не буду, вставьте код как полагается.

golosun
Offline
Зарегистрирован: 31.10.2016
Понял, спасибо
 

tsv_33
Offline
Зарегистрирован: 11.04.2019
golosun
Offline
Зарегистрирован: 31.10.2016
#include <ArduinoOTA.h>

#include <PubSubClient.h>

#include <EEPROM.h>

int myio = 2; // GPIO 2

// #include <Wire.h>
#include <ESP8266WiFi.h>

#include "DHT.h"
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(14, DHTTYPE);

bool debug = true;
// Replace with your network details
const char* hname = "boiler";
const char* ssid = "WIFI";
const char* password = "123456";

float Real_Humid, Real_Temp, TempStreet, Set_Temp;
int Set_Temp_water, Set_Temp_obr; 
int Temp_water = 10, Temp_obr = 10;

const char *mqtt_server = "m16.cloudmqtt.com"; // Имя сервера MQTT
const int mqtt_port = 17984; // Порт для подключения к серверу MQTT
const char *mqtt_user = "qwerty"; // Логин от сервер
const char *mqtt_pass = "12345"; // Пароль от сервера
int LastMQTT = 0;
int IsMQTT = 1;
unsigned long LastReal_Temp = 0;
unsigned long LastUpdateWeather = 0;

#include <ESP8266WebServer.h>
ESP8266WebServer server(80);

#include <OpenTherm.h>

const int inPin = 4;  //for Arduino, 4 for ESP8266 (D2), 21 for ESP32
const int outPin = 5; //for Arduino, 5 for ESP8266 (D1), 22 for ESP32
OpenTherm ot(inPin, outPin);

void ICACHE_RAM_ATTR handleInterrupt() {
    ot.handleInterrupt();
}
bool isFlameOn;
int getModulation, get_Year;

// only runs once on boot
void setup() {
  pinMode(myio, OUTPUT);

  // Initializing serial port for debugging purposes
  if (debug) Serial.begin(115200);
  delay(10);
 // Connecting to WiFi network
  if (debug) Serial.println();
  if (debug) Serial.print("Connecting to ");
  if (debug) Serial.println(ssid);
  
  WiFi.mode(WIFI_STA);
  WiFi.hostname(hname);
//  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(myio, LOW);
    delay(500);
    digitalWrite(myio, HIGH);
    delay(500);
    if (debug) Serial.print(".");
  }
  if (debug) Serial.println("");
  if (debug) Serial.println("WiFi connected");
  
  // Starting the web server
  server.on("/", handleRoot);
  
  server.begin();
  if (debug) Serial.println("Web server running. Waiting for the ESP IP...");
  delay(10000);

  // ArduinoOTA.setPort(8266);
  ArduinoOTA.setHostname(hname);
  // ArduinoOTA.setPassword("admin");
  ArduinoOTA.begin();

  
  // Printing the ESP IP address
  if (debug) Serial.println(WiFi.localIP());

  dht.begin();

  EEPROM.begin(64);
  Set_Temp = EEPROM_float_read(0);
  if (Set_Temp < 1) EEPROM_float_write(0, 20); 
  Set_Temp_water = EEPROM_float_read(4);
  if (Set_Temp_water < 1) EEPROM_float_write(4, 40); 

   ot.begin(handleInterrupt);

}

// чтение float
float EEPROM_float_read(int addr) {
  byte raw[4];
  for (byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr + i);
  float &num = (float&)raw;
  return num;
}

// запись float
void EEPROM_float_write(int addr, float num) {
  if (EEPROM_float_read(addr) != num) { //если сохраняемое отличается
    byte raw[4];
    (float&)raw = num;
    for (byte i = 0; i < 4; i++) EEPROM.write(addr + i, raw[i]);
  }
  EEPROM.commit();
}

void getReal_Temp() {
    LastReal_Temp = millis();
    int i = 0;
    do {
      i++;
      if (i > 1) delay(200);
      Real_Humid = dht.readHumidity();
     } while ((i < 10) && (isnan(Real_Humid) == 1));
    i = 0;
    do {
      i++;
      if (i > 1) delay(200);
      Real_Temp = dht.readTemperature();
     } while ((i < 10) && (isnan(Real_Temp) == 1));     
    
}

void callback(const MQTT::Publish& pub) {
 Serial.print("топик-" + pub.topic()); // выводим в сериал порт название топика
 Serial.print(" => ");
 Serial.println(pub.payload_string()); // выводим в сериал порт значение полученных данных

 String payload = pub.payload_string();

 if(String(pub.topic()) == "street/temp") // проверяем из нужного ли нам топика пришли данные 
 {
  TempStreet = payload.toFloat();
  IsMQTT = 0;
 }
}

void getWeather() {
   LastUpdateWeather = millis();
 if (!(IsMQTT == 0)) {
//Serial.println(IsMQTT);
   WiFiClient wclient;
   PubSubClient MQTTclientRead(wclient, mqtt_server, mqtt_port);
  if (!MQTTclientRead.connected()) {
//   Serial.println("Connecting to MQTT server for read");
   if (MQTTclientRead.connect(MQTT::Connect("OpenTermClient") .set_auth(mqtt_user, mqtt_pass))) {
//    Serial.println("Connected to MQTT server for read");
    MQTTclientRead.set_callback(callback);
    MQTTclientRead.subscribe("street/temp"); // подписывааемся по топик с данными
    MQTTclientRead.loop();
//    MQTTclientRead.subscribe("street/p_atm"); // подписывааемся по топик с данными 
//    MQTTclientRead.loop();
    MQTTclientRead.subscribe("street/humidity"); // подписывааемся по топик с данными 
    MQTTclientRead.loop();
    } else {
    Serial.println("Could not connect to MQTT server for read"); 
   }
  }
 } 
}

void Get_Set_Temp_obr() {
  Set_Temp_obr = TempStreet * (-1) + 65;
  if (TempStreet > 20) Set_Temp_obr = 40;
  if (TempStreet < -12) Set_Temp_obr = 80;
  if (Real_Temp < Set_Temp - 1) Set_Temp_obr = 80;
  if (Real_Temp >= Set_Temp ) Set_Temp_obr = 40;
  if (Real_Temp > Set_Temp + 0.5) Set_Temp_obr = 0;
//  if (Set_Temp_obr == 0)   //отключить отопление
//  if (Set_Temp_obr < 40) Set_Temp_obr = 40;
  if (Set_Temp_obr > 80) Set_Temp_obr = 80;
}


void loop() {
  ArduinoOTA.handle();

  Get_Set_Temp_obr();
  

  if ((LastReal_Temp + 60000 < millis()) || (LastReal_Temp == 0) || (isnan(Real_Humid) == 1) || (isnan(Real_Temp) == 1)  ) {
   getReal_Temp();
  } 

  if ((LastUpdateWeather + 600000 < millis() ) || (LastUpdateWeather == 0) || (TempStreet == 0) || (IsMQTT == 1) ) {
Serial.print(String(IsMQTT) + " " + String(LastUpdateWeather) + " ");
   IsMQTT = 1;
   getWeather();
  } 
  

  LastMQTT++;
  if (LastMQTT > 3) {
   
    LastMQTT = 0;
/*  WiFiClient wfclient = server.available();
    PubSubClient MQTTclient(wfclient, mqtt_server, mqtt_port);
     MQTTclient.loop(); 
//     Serial.println("Send to MQTT"); 
     MQTTclient.publish("boiler/RealTemp",String(Real_Temp)); // отправляем в топик для термодатчика значение температуры
     MQTTclient.publish("boiler/RealHumid",String(Real_Humid)); 
     Serial.print("Sended to MQTT");
     Serial.print(" boiler/RealTemp - " + String(Real_Temp)); 
*/     Serial.println(" boiler/RealHumid - " + String(Real_Humid)+ " " + String(TempStreet)); 
   }   




 //Set/Get Boiler Status
    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("Central Heating: " + String(ot.isCentralHeatingActive(response) ? "on" : "off"));
        Serial.println("Hot Water: " + String(ot.isHotWaterActive(response) ? "on" : "off"));
        isFlameOn = ot.isFlameOn(response);
        Serial.println("Flame: " + String(isFlameOn ? "on" : "off"));
    }
    if (responseStatus == OpenThermResponseStatus::NONE) {
        Serial.println("Error: OpenTherm is not initialized");
    }
    else if (responseStatus == OpenThermResponseStatus::INVALID) {
        Serial.println("Error: Invalid response " + String(response, HEX));
    }
    else if (responseStatus == OpenThermResponseStatus::TIMEOUT) {
        Serial.println("Error: Response timeout");
    }

    //Set Boiler Temperature to 64 degrees C
    ot.setBoilerTemperature(Set_Temp_obr);
//ot.setBoilerTemperature(77);

    //Get Boiler Temperature
    Temp_obr = ot.getBoilerTemperature();
    Serial.println("CH temperature is " + String(Temp_obr) + " C");

    //Set DHW setpoint to 40 degrees C
    ot.setDHWSetpoint(Set_Temp_water);

    //Get DHW Temperature
    Temp_water = getDHWSPTemp(); //ot.getDHWTemperature();
get_Year = getYear();    
    Serial.println("DHW temperature is " + String(Temp_water) + " C");
getModulation = ot.getModulation();
Serial.println("getReturnTemperature " + String(ot.getReturnTemperature()));    
     Serial.println("getModulation " + String(getModulation));
     Serial.println("getPressure " + String(ot.getPressure()));
Serial.println("isReady " + String(ot.isReady()));
//Serial.println("isCoolingActive " + String(ot.isCoolingActive() ));
//Serial.println("isDiagnostic " + String(ot.isDiagnostic() ));
Serial.println("getBurnerStarts " + String(getBurnerStarts()));
Serial.println("getYear " + String(get_Year));
Serial.println("");     
Serial.println("");     
Serial.println("");     
Serial.println("");     
Serial.println("");     





  server.handleClient();

   if (millis() > 86400000)  
     ESP.restart(); 

   digitalWrite(myio, LOW);
   delay(10);
   digitalWrite(myio, HIGH);
   delay(1000);


} 

// получение установленной температуры ГВС.
float getDHWSPTemp() {
 unsigned long request56 = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::TdhwSet, 0);
 unsigned long respons56 = ot.sendRequest(request56);
 uint16_t dataValue56 = respons56 & 0xFFFF;
 float result56 = dataValue56 / 256;
 return result56;
}

long getBurnerStarts() {
 unsigned long request56 = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::BurnerStarts, 0);
 unsigned long respons56 = ot.sendRequest(request56);
 uint16_t dataValue56 = respons56 & 0xFFFF;
 float result56 = dataValue56 / 256;
 return dataValue56;
}

long getYear() {
 unsigned long respons = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Year, 0));
 long dataValue = ((respons & 0xFF) << 8) + ((respons >> 8) & 0xFF);
 return dataValue;
}

String SendHTML(){
  String ptr = 
"<html><title>Баня котёл</title>"
" <head>"
"  <meta charset='utf-8'>"
"<meta http-equiv='Refresh' content='15' />"
" </head>"
"<body><h1><font color='blue'> ESP8266 Управление котлом</font></h1>"
"<form action=\"\" method=\"post\">"
"<script language=\"javascript\" type=\"text/javascript\">"
"var d = new Date();"
"function addZero(n) { if (n > 9) return n; else return \"0\" + n;} "
"document.write(addZero(d.getDate()) + \".\" + addZero((d.getMonth() + 1)) + \".\" + d.getFullYear() + \"  \" + addZero(d.getHours()) + \":\" + addZero(d.getMinutes()) + \":\" + addZero(d.getSeconds()) );"
"</script>"
"<table border='1' width='456' cellspacing='0' cellpadding='2'><tbody>"
"<tr height='50'><td></td><td align='center'><font size='4'><b>Факт</td><td align='center'><font size='4'><b>Норма</td></tr>"

"<tr height='40'><td><font size='4'><b>Температура</td>"
"<td align='center'>" + String(Real_Temp) + "&nbsp&deg;C</td>";
  char mstr[6];
  dtostrf(Set_Temp, 2, 1, mstr);
 ptr += "<td align=\"center\" cellpadding=\"1\">"
"<input type=\"number\" class=\"Set_Temp\" size=\"1\" name=\"Set_Temp\" min=\"10\" max=\"40\" value=\"";
ptr += mstr;
ptr += "\"step=\"0.1\" required> <style type='text/css'> .Set_Temp {width: 55px;height: 25px;}</style>  &deg;C &nbsp&nbsp&nbsp"
"<input type=\"submit\" class='Temp_Ok' value='OK'><style type='text/css'> .Temp_Ok {color: #fff; background-color: #00f; width: 35px; height: 25px;}</style></td></tr>"
            
"<tr height='30'><td><font size='4'><b>Влажность</td>"
"<td align='center'>";
ptr += String(Real_Humid);
ptr += "&nbsp%<td></td></tr>"

"<tr height='30'><td><font size='4'><b>Улица</td>"
"<td align='center'>" + String(TempStreet) + "&nbsp&deg;C</td>"
"<td></td></tr>"

"<tr height='40'><td><font size='4'><b>Горячая вода</td>"
"<td align='center'>" + String(Temp_water) + "&nbsp&deg;C</td>"
            
"<td align='center' cellpadding='1'>"
"<input type='number' class=\"Set_Temp_water\" size=\"1\" name=\"Set_Temp_water\" min=\"30\" max=\"57\" value=\"" + String(Set_Temp_water) + "\"step=\"1\" required><style type=\"text/css\">.Set_Temp_water {width: 44px;height: 25px;}</style>  &deg;C &nbsp&nbsp&nbsp"
"<input type='submit' class='TempWater_Ok' value='OK'><style type='text/css'> .TempWater_Ok {color: #fff; background-color: #f00; width: 35px; height: 25px;}</style></td></tr>"

"<tr height='30'><td><font size='4'><b>Обратка</td>"
"<td align='center'>" + String(Temp_obr) + "&nbsp&deg;C</td>"
"<td align='center'>" + String(Set_Temp_obr) + "&nbsp&deg;C</td></tr>"

"<tr height='30'><td><font size='4'><b>Модуляция</td>"
"<td align='center'>";
if (isFlameOn) {
 ptr += " " + String(getModulation) + "%";
 ptr += "<img src='https://yt3.ggpht.com/a/AGF-l789Vm3SxCWQfDNA0upmqmLxFvmukFWsblsQ4A=s48-c-k-c0xffffffff-no-rj-mo'>";
 } else
 ptr += "<img src='https://yt3.ggpht.com/a/AGF-l7_UXVwIn5FLYlVqQM5rOmvngMHx7mdL66AYUA=s48-c-k-c0xffffffff-no-rj-mo'>";
//<img src="data:image/png;base64,iVBORw0KGgoAAA">  //Сохраните изображение в ESP8266 SPIFFS (файловая система SPI Flash)   конвертировать ваши изображения в кодировку base64, перейдите на сайт www.base64-image.de
 ptr += "</td>"
"<td></td></tr>"
"<tr><td>";
  unsigned long response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Date, 0x0000));
  ptr += String((response >> 8) & 0xFF) + "." + String((response) & 0xFF) + ".";
  ptr += String(getYear()) + " ";
  response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::DayTime, 0x0000));
  ptr += String((response) & 0x1F) + ":" + String((response >> 8) & 0xFF);
 ptr += "</td></tr>"
"</tbody></table>"
"</form>"       
"</body></html>";  
  return ptr;
}

void handleRoot() {
//  mhtml =  FPSTR(MAIN_page);
//  server.send(200, "text/html", mhtml);  
if (server.hasArg("Set_Temp")) 
    handleSubmit();
    else server.send(200, "text/html", SendHTML()); 
}

// функция вызывается, когда клиент жмет кнопку
void handleSubmit(){
   String mstr;
   mstr = server.arg("Set_Temp");
   
   EEPROM_float_write(0, mstr.toFloat());
   mstr = server.arg("Set_Temp_water");
   EEPROM_float_write(4, mstr.toInt());
   Set_Temp = EEPROM_float_read(0);
   Set_Temp_water = EEPROM_float_read(4);

   server.send(200, "text/html", SendHTML());
}

 

miks69
Offline
Зарегистрирован: 16.02.2020

golosun пишет:

295 // получение установленной температуры ГВС.
296 float getDHWSPTemp() {
297  unsigned long request56 = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::TdhwSet, 0);
298  unsigned long respons56 = ot.sendRequest(request56);
299  uint16_t dataValue56 = respons56 & 0xFFFF;
300  float result56 = dataValue56 / 256;
301  return result56;
302 }

Данные DHW setpoint (ID=56) задаются и возвращаются в формате f8.8, а вы почему-то используете только дробную часть...

golosun
Offline
Зарегистрирован: 31.10.2016

Похоже косяк, я туда не дошёл, главное установить температуру отопления

 

miks69
Offline
Зарегистрирован: 16.02.2020

Опишите вашу проблему еще раз

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

golosun пишет:

Похоже косяк, я туда не дошёл, главное установить температуру отопления

 

это MQTT или веб интерфейс ?

у меня ни как не получает связать з логальным сервером !

golosun
Offline
Зарегистрирован: 31.10.2016

Это веб (пока), Проблема - я не могу установить температуру отопления (стр. 249), на все значения, кроме нуля, никакой реакции, а  при установке ноль - отключается отопление (эта часть меня устраивает)

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

golosun пишет:

Это веб (пока), Проблема - я не могу установить температуру отопления (стр. 249), на все значения, кроме нуля, никакой реакции, а  при установке ноль - отключается отопление (эта часть меня устраивает)

какой котел ?

miks69
Offline
Зарегистрирован: 16.02.2020

golosun пишет:

Это веб (пока), Проблема - я не могу установить температуру отопления (стр. 249), на все значения, кроме нуля, никакой реакции, а  при установке ноль - отключается отопление (эта часть меня устраивает)

Для начала добавьте вывод в Serial значения Set_Temp_obr, которое вы передаете в ot.setBoilerTemperature(Set_Temp_obr).

Если установка значения не происходит, проверьте, что котел выдает в Max CH water setpoint (ID=57), там должно быть значение больше, чем вы устанавливаете.

Также возможно, что котел не принимает установку CH setpoint, т.к. вы не задали ему MemberID своего устройства (ID=2).

golosun
Offline
Зарегистрирован: 31.10.2016

Я делал и явно - ot.setBoilerTemperature(77) (стр. 250), тот-же результат.

ID=57: Maximum allowable CH water setpoint (°C) -  Data: 80.0 - и здесь всё нормально. (я кидал лог из OpenThermTestIDs  http://arduino.ru/forum/programmirovanie/termostat-opentherm-na-esp8266?...)

А как задать ему MasterID ? (а читать значение может без MasterID)

 

miks69
Offline
Зарегистрирован: 16.02.2020

golosun пишет:

А как задать ему MasterID ? (а читать значение может без MasterID)

request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SConfigSMemberIDcode, 0xFFFF);

response = ot.sendRequest(request);

uint16_t MemberIDcode = response & 0xFF;

request = ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MConfigMMemberIDcode, MemberIDcode);

response = ot.sendRequest(request);

golosun
Offline
Зарегистрирован: 31.10.2016

Спасибо, проверить смогу только завтра

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

miks69 пишет:

golosun пишет:

А как задать ему MasterID ? (а читать значение может без MasterID)

request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SConfigSMemberIDcode, 0xFFFF);

response = ot.sendRequest(request);

uint16_t MemberIDcode = response & 0xFF;

request = ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::MConfigMMemberIDcode, MemberIDcode);

response = ot.sendRequest(request);

 

а если так ?

  // Записать ID-2; мастер-код MemberID
  unsigned int data = 0x0004;
  unsigned long request ot.buildRequest(OpenThermRequestType::WRITE,OpenThermMessageID::MConfigMMemberIDcode, data);
  ot.sendRequest(request);
 
miks69
Offline
Зарегистрирован: 16.02.2020

knt58dualtv пишет:

а если так ?

  // Записать ID-2; мастер-код MemberID
  unsigned int data = 0x0004;
  unsigned long request ot.buildRequest(OpenThermRequestType::WRITE,OpenThermMessageID::MConfigMMemberIDcode, data);
  ot.sendRequest(request);

Я думаю можно и так

golosun
Offline
Зарегистрирован: 31.10.2016

Я правильную использую библиотеку  https://github.com/ihormelnyk/opentherm_library  ?

 

miks69
Offline
Зарегистрирован: 16.02.2020

golosun пишет:

Я правильную использую библиотеку  https://github.com/ihormelnyk/opentherm_library  ?

Ну да, а других и нету

golosun
Offline
Зарегистрирован: 31.10.2016

А ведь 0 записывается (вернее выключает обогрев) и без MemberID 

miks69
Offline
Зарегистрирован: 16.02.2020

Для того чтобы найти ошибку в работе вашего кода, для начала надо сделать полноценную обработку ошибок.

Например, после запроса setBoilerStatus вы проверяете статус ответа, а после других запросов почему-то нет.

Строка 249:

if (!ot.setBoilerTemperature(Set_Temp_obr)) {

    Serial.println("Set Boiler Temp Error");

    Serial.println("Response status: "+String(ot.getLastResponseStatus()));

}

Строка 253:

response = sendRequest(ot.buildGetBoilerTemperatureRequest();

if (ot.isValidResponse(response))

    Temp_obr = ot.getTemperature(response);

else {

    Serial.println("Response status: "+String(ot.getLastResponseStatus()));

}

Ну как-то так...

golosun
Offline
Зарегистрирован: 31.10.2016

Спасибо

miks69
Offline
Зарегистрирован: 16.02.2020

Кроме всего прочего, при использование синхронного режима запросов помимо необходимости обработки каждого ответа вы имеете большие задержки в работе вашего кода, т.к. каждый запрос-ответ занимает у вас около 300 мсек.

Предпочтительнее использовать асинхронный режим запросов, при котором вы можете сделать все проверки в одной процедуре обработки ответа и исключаете ненужные задержки в работе кода.

knt58dualtv
Offline
Зарегистрирован: 08.01.2019

Opentherm есть комманди которіе удалить рабочие ошибки ?

tsv_33
Offline
Зарегистрирован: 11.04.2019

А что об этом пишут в протоколе?

golosun
Offline
Зарегистрирован: 31.10.2016
#include <OpenTherm.h>

const int inPin = 4;  //for Arduino, 4 for ESP8266 (D2), 21 for ESP32
const int outPin = 5; //for Arduino, 5 for ESP8266 (D1), 22 for ESP32
OpenTherm ot(inPin, outPin);


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

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

void loop() {

 //Set/Get Boiler Status
    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("Central Heating: " + String(ot.isCentralHeatingActive(response) ? "on" : "off"));
        Serial.println("Hot Water: " + String(ot.isHotWaterActive(response) ? "on" : "off"));
        Serial.println("Flame: " + String(ot.isFlameOn(response) ? "on" : "off"));
    }
    if (responseStatus == OpenThermResponseStatus::NONE) {
        Serial.println("Error: OpenTherm is not initialized");
    }
    else if (responseStatus == OpenThermResponseStatus::INVALID) {
        Serial.println("Error: Invalid response " + String(response, HEX));
    }
    else if (responseStatus == OpenThermResponseStatus::TIMEOUT) {
        Serial.println("Error: Response timeout");
    }
Serial.println("");
Serial.println("");
MembIDcode();
Serial.println("");


float Set_Temp_obr = 77;
    if (!ot.setBoilerTemperature(Set_Temp_obr)) {
     Serial.print("Set Boiler Temp Error - ");
     Serial.println("Response status: " + String(ot.getLastResponseStatus()) + " - " + ot.statusToString(ot.getLastResponseStatus()) + "__" + String(ot.temperatureToData(Set_Temp_obr)) );
    } else
    Serial.print("Set Boiler Temp - OK");


Serial.println("");

unsigned int data = ot.temperatureToData(Set_Temp_obr);  //(1075395072);
unsigned long request = ot.buildRequest(OpenThermRequestType::WRITE, OpenThermMessageID::TSet, data);
response = ot.sendRequest(request);
 if (!ot.isValidResponse(response)) {
     Serial.print("New Set Boiler Temp Error - ");
     Serial.println("Response status: " + String(ot.getLastResponseStatus()) + " - " + ot.statusToString(ot.getLastResponseStatus()) + "__" + String(data) );
    }else
    Serial.print("New Set Boiler Temp - OK");



Serial.println("");

    //Get Boiler Temperature
//    response = ot.sendRequest(ot.buildGetBoilerTemperatureRequest());
request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Tboiler, 0);
response = ot.sendRequest(request);
    if (ot.isValidResponse(response)) {
//     Temp_obr = ot.getFloat(response); 
    Serial.println("CH temperature is " + String(ot.getFloat(response)) + " C " + String(response));
     }
     else {
      Serial.println("Get Boiler Temperature - Response status: " + String(ot.getLastResponseStatus()));
    }

 response = ot.sendRequest(ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Year, 0));
 Serial.println("Year=" + String( ((response & 0xFF) << 8) + ((response >> 8) & 0xFF)));



Serial.println("");
Serial.println("");
Serial.println("");
Serial.println("");
  delay(1000);

}


void MembIDcode() {
  unsigned int data;
  unsigned long request = ot.buildRequest(OpenThermRequestType::READ, OpenThermMessageID::SConfigSMemberIDcode, 0xFFFF);
  unsigned long response = ot.sendRequest(request);
  if (!ot.isValidResponse(response) ) {
   Serial.print("Error get MemberIDcode - ");
   Serial.println("Response status: " + String(ot.getLastResponseStatus()) + " - " + ot.statusToString(ot.getLastResponseStatus()) );
  } else {
  data = response & 0xFF;
  Serial.println("Get MemberIDcode - OK = " + String(data));
  }
  data = 0x0007;
  request = ot.buildRequest(OpenThermRequestType::WRITE,OpenThermMessageID::MConfigMMemberIDcode, data);
  if (!ot.isValidResponse(response) ) {
     Serial.print("Error set MemberIDcode - ");
     Serial.println("Response status: " + String(ot.getLastResponseStatus()) + " - " + ot.statusToString(ot.getLastResponseStatus()) );
  } else
  Serial.println("set MemberIDcode - OK - " + String(data));
}  

Результат работы

Central Heating: on
Hot Water: off
Flame: on
 
 
Get MemberIDcode - OK = 33
set MemberIDcode - OK - 7
 
Set Boiler Temp Error - Response status: 2 - INVALID__19712
 
New Set Boiler Temp Error - Response status: 2 - INVALID__19712
 
CH temperature is 63.00 C 1075396352
Year=2021
 
 
 
 
Central Heating: on
Hot Water: off
Flame: on
 
 
Get MemberIDcode - OK = 33
set MemberIDcode - OK - 7
 
Set Boiler Temp Error - Response status: 2 - INVALID__19712
 
New Set Boiler Temp Error - Response status: 2 - INVALID__19712
 
CH temperature is 63.00 C 1075396352
Year=2021
 
 
Ставлю MemberIDcode 7, без ошибок, а читается 33
Установить темп. отопления - не получается, хотя читает всё.
 
Куда ещё посмотреть?
 

 

miks69
Offline
Зарегистрирован: 16.02.2020

golosun пишет:

Central Heating: on
Hot Water: off
Flame: on
 
Get MemberIDcode - OK = 33
set MemberIDcode - OK - 7
 
Set Boiler Temp Error - Response status: 2 - INVALID__19712
 
New Set Boiler Temp Error - Response status: 2 - INVALID__19712
 
CH temperature is 63.00 C 1075396352
Year=2021
 
Ставлю MemberIDcode 7, без ошибок, а читается 33
Установить темп. отопления - не получается, хотя читает всё.
 
Куда ещё посмотреть?

Не совсем понял, что означает "19712", попробуйте добавить следующую строку, чтобы увидеть код ответа:

Serial.printf("Response: 0x%08X\r\n", response);