[Железо] Управление обогревом в доме

Работа с конкретным оборудованием

Модераторы: immortal, newz20

Ответить
kotbrs
Сообщения: 18
Зарегистрирован: Сб авг 20, 2016 5:58 pm
Благодарил (а): 3 раза
Поблагодарили: 2 раза

[Железо] Управление обогревом в доме

Сообщение kotbrs » Пн ноя 28, 2016 5:26 pm

Имеем:
Водяные теплые полы 1-ый этаж;
Батареи на первом и втором этаже (на первом меньше за счет теплого пола);
Газовый котел, который греет воду для теплого пола, батарей и нагрева горячей воды.

Хочется:
Управлять температурой нагрева теплого пола и батарей, чтоб не было душно или холодно в доме, в зависимости от внешней температуры.

Проблема:
Крутить температуру нагрева воды на газовом котле не хочется, потому как котел греет воду в том числе и для нагрева горячей воды которая течет из крана (используется бойлер на 300 л, через него и пропускается горячая вода из газового котла, которая нагревает воду поступающую в краны). Соответственно, если буду крутить температуру нагрева воды, то и в кране будет меняться температура воды, а этого не хочется.

Реализация:
Нагретая вода из газового котла (замкнутый контур нагреваемой воды) поступает в раздаточный коллектор и оттуда идет в контур водяных полов, контур отопления (батареи) и контур нагрева горячей воды в бойлере. Каждый отвод соединен с магистральным насосом который прокачивает воду в своем контуре и по обратке вода поступает опять в котел для нагрева.
Для раздачи воды на теплые полы (после насоса) стоит гребенка с кранами на которых можно порегулировать напор (и соответственно температуру) для теплых полов в разных помещениях(их есть три отдельных контура). Очень не хочется ставить управление на эти краны и постоянно их дрюкать, да и не копеечные они.
Решил управлять временем работы насосов для теплых полов и батарей, каждым отдельно.
Идея следующая – берем период повторения регулировки 1 час. То есть в течении часа, если нагрев полов 0%, то насос 60 минут отключен, если ставим нагрев 17%, то насос в течении часа 5 мин работает 25 мин отдыхает, затем опять 5 мин работает 25 мин отдыхает. Если 34% нагрев, то насос в течении часа 10 мин работает 20 мин отдыхает, затем опять 10 мин работает 20 мин отдыхает. На 50% нагрева насос 10 мин работает, 10 отдыхает и так до смены режима нагрева. Надеюсь идея понятна.
В железе реализовано следующим образом:
Arduino UNO (потому что использую для защиты от зависаний сторожевой таймер)
через реле управляет насосом;
через отдельные кнопки для теплых полов и для батарей устанавливается режим отдельно для каждого контура (по кольцу можно перебирать 6 режимов нагрева);
на индикаторе LCD1604 отображается текущий режим для пола и для батарей, а также знак включенного насоса соответствующего контура;
есть светодиод, моргающий с секундным интервалом, для контроля, что скетч на ардуине крутится;
через RX/TX передаются на ESP8266 (прошивка wifi-iot) текущий режим нагрева теплого пола и отопления в разных переменных, далее в Majordomo;
через ESP8266 посредством RX/TX принимаются режимы нагрева для теплого пола и отопления и отображаются на индикаторе LCD1604;
текущим режимом нагрева является последний введенный либо с кнопок, либо полученный от Majordomo через ESP8266;
Majordomo каждые 7 минут (устанавливается в ESP8266) получает текущие режимы нагрева.

Таким образом контроллер может автономно управляться с кнопок и работать самостоятельно, также воспринимает команды от Majordomo и меняет режим.

Код: Выделить всё

#include <avr/wdt.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//+++++++++++++++++++
#include <RBD_Timer.h>  
#include <RBD_Button.h> 
#define wf_num_modes 6 // максимальный номер режима
short int wf_max_mode = wf_num_modes + 1; // вспомогательная переменная
int wf_butt = 0; // текущий режим
int wf_butt_temp = 0;
byte wf_buttChar = 'a';
byte wf_buttChar_temp = 'a';

#define rd_num_modes 6 // максимальный номер режима
short int rd_max_mode = rd_num_modes + 1; // вспомогательная переменная
int rd_butt = 0; // текущий режим
int rd_butt_temp = 0;
byte rd_buttChar = 'k';
byte rd_buttChar_temp = 'k';
// input pullup enabled by default
RBD::Button wf_button(9);
RBD::Button rd_button(12);

char esp_serial = 'a';
char wf_common = 'a';
char rd_common = 'k';

//+++++++++++++++++++
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
//*******************
// Эти переменные хранят временной шаблон для интервалов включения
// и текущее состояние насоса
int wf_relayPin = 10; // номер пина с реле насоса ТП
int rd_relayPin = 8; // номер пина с реле насоса батарей
int ledPin = 11; // номер пина с контрольным светодиодом

int wf_relayState = LOW; // состояние реле насоса ТП
int rd_relayState = LOW; // состояние реле насоса батарей
int ledState = LOW; // состояние контрольного светодиода

// последний момент времени, когда состояние реле насоса изменялось
unsigned long wf_previousMillis = 0;
unsigned long rd_previousMillis = 0;
unsigned long led_previousMillis = 0;
long wf_OnTime = 0; // длительность включения насоса ТП (в миллисекундах)
long wf_OffTime = 36000; // длительность выключения насоса ТП (в миллисекундах)
long rd_OnTime = 0; // длительность включения насоса батарей (в миллисекундах)
long rd_OffTime = 36000; // длительность выключения насоса батарей (в миллисекундах)
int led_OnTime = 1000; // Контрольный светодиод вкл
int led_OffTime = 1000; // Контрольные светодиод выкл

//*******************
//-------------------
//Счетчик для отправки в UART
unsigned long uart_previousMillis;
#define uart_interval 600000 //10 мин интервал отправки данных в Majordomo
//#define uart_interval 5000 //5 сек интервал отправки данных в Majordomo для теста
//-------------------

void setup() {
  wdt_disable();
  
  Serial.begin(9600);


  pinMode(wf_relayPin, OUTPUT);
  pinMode(rd_relayPin, OUTPUT);  
  pinMode(ledPin, OUTPUT);


  lcd.init();
  lcd.backlight();// Включаем подсветку дисплея
  lcd.print("Floor");
  lcd.setCursor(1, 1);  //setCursor(column, row) upper-0, left-0
  lcd.print("min");
  lcd.setCursor(10, 0);
  lcd.print("Radiat");
  lcd.setCursor(11, 1);  //setCursor(column, row) upper-0, left-0
  lcd.print("min");  

  delay(3000);
  
  wdt_enable(WDTO_4S);
  
}


void loop() {

  if (Serial.available() > 0)
  {
    esp_serial = Serial.read(); //Чтение последнего символа из Serial
    if (byte(esp_serial) > 96 & byte(esp_serial) < 104) {
    wf_common = esp_serial;
    wf_switchCommon();
    }
    
    if (byte(esp_serial) > 106 & byte(esp_serial) < 114) {
    rd_common = esp_serial;
    rd_switchCommon();
    }
    
  }

  
  if(wf_button.onPressed()) {
    wf_butt++;                     // увеличиваем счетчик текушего режима
    wf_butt %= wf_max_mode;           // остаток от целочисленного деления
    if (wf_butt == 0) wf_butt = 0; // режим меняется от 0 до wf_num_modes
    wf_buttChar = 97 + wf_butt;
    wf_common = char(wf_buttChar);
    wf_switchCommon();
  }
     
  if(rd_button.onPressed()) {
    rd_butt++;                     // увеличиваем счетчик текушего режима
    rd_butt %= rd_max_mode;           // остаток от целочисленного деления
    if (rd_butt == 0) rd_butt = 0; // режим меняется от 0 до wf_num_modes
    rd_buttChar = 107 + rd_butt;
    rd_common = char(rd_buttChar);
    rd_switchCommon();
  }

  // выясняем не настал ли момент сменить состояние насоса ТП
  unsigned long currentMillis = millis(); // текущее время в миллисекундах

  // Проверка не пора ли выключать
  // если насос включен и работает больше чем надо
  if ((wf_relayState == HIGH) && (currentMillis - wf_previousMillis >= wf_OnTime))
  {
    wf_relayState = LOW; // выключаем
    lcd.setCursor(0, 1);
    lcd.print(" ");
    wf_previousMillis = currentMillis; // запоминаем момент времени
    digitalWrite(wf_relayPin, wf_relayState); // реализуем новое состояние реле насоса

  }

  // Проверка не пора ли включать
  else if ((wf_relayState == LOW) && (currentMillis - wf_previousMillis >= wf_OffTime))
  {
    wf_relayState = HIGH; // включаем
    lcd.setCursor(0, 1);
    lcd.print("*");    
    wf_previousMillis = currentMillis ; // запоминаем момент времени
    digitalWrite(wf_relayPin, wf_relayState); // реализуем новое состояние реле насоса

  }

  // выясняем не настал ли момент сменить состояние насоса батарей
  currentMillis = millis(); // текущее время в миллисекундах

  // Проверка не пора ли выключать
  // если насос включен и работает больше чем надо
  if ((rd_relayState == HIGH) && (currentMillis - rd_previousMillis >= rd_OnTime))
  {
    rd_relayState = LOW; // выключаем
    lcd.setCursor(15, 1);
    lcd.print(" ");
    rd_previousMillis = currentMillis; // запоминаем момент времени
    digitalWrite(rd_relayPin, rd_relayState); // реализуем новое состояние реле насоса
  }

  // Проверка не пора ли включать
  else if ((rd_relayState == LOW) && (currentMillis - rd_previousMillis >= rd_OffTime))
  {
    rd_relayState = HIGH; // включаем
    lcd.setCursor(15, 1);
    lcd.print("*");    
    rd_previousMillis = currentMillis ; // запоминаем момент времени
    digitalWrite(rd_relayPin, rd_relayState); // реализуем новое состояние реле насоса
  }

  currentMillis = millis(); // текущее время в миллисекундах
  // Светодиод выкл
  if ((ledState == HIGH) && (currentMillis - led_previousMillis >= led_OnTime))
  {
    ledState = LOW; // выключаем
    led_previousMillis = currentMillis; // запоминаем момент времени
    digitalWrite(ledPin, ledState); // реализуем новое состояние
  }

  // Проверка не пора ли светодиод включать
  else if ((ledState == LOW) && (currentMillis - led_previousMillis >= led_OffTime))
  {
    ledState = HIGH; // выключаем
    led_previousMillis = currentMillis; // запоминаем момент времени
    digitalWrite(ledPin, ledState); // реализуем новое состояние
  }

  currentMillis = millis(); // текущее время в миллисекундах

  if (currentMillis >= (uart_previousMillis + uart_interval))   // сравниваем текущий таймер с переменной loopTimeUART
  {            

// отправка текущего режима в UART  
  
  Serial.print("&wf=");
  Serial.print(wf_common);
  Serial.print("&rd=");
  Serial.println(rd_common);
  uart_previousMillis = currentMillis;
   }  

   
//   Serial.print("State WF_common after switch: ");
//   Serial.println(wf_common);     
//   Serial.print("On Time WF: ");
//   Serial.println(OnTime);
//   Serial.print("Off Time WF: ");
//   Serial.println(OffTime);
//   Serial.print("State RD_common after switch: ");
//   Serial.println(rd_common);     
//   Serial.print("On Time RD: ");
//   Serial.println(OnTime_rd);
//   Serial.print("Off Time RD: ");
//   Serial.println(OffTime_rd);


   wdt_reset();

}
//////////////////////////////////////////////////////////////////////////////////////////
//   Finish
//////////////////////////////////////////////////////////////////////////////////////////
void wf_switchCommon(){
  
   switch (wf_common)
  {
    case 'a':
      // насос отключен
      wf_OnTime = 0;
      wf_OffTime = 3600000;
      lcd.setCursor(1, 1);
      lcd.print("min");
      break;

    case 'b':
      // насос 17% On - 83% Off
      wf_OnTime = 300000;
      wf_OffTime = 1500000;
      lcd.setCursor(1, 1);
      lcd.print("17%");
      break;

    case 'c':
      // насос 34% On - 66% Off
      wf_OnTime = 600000;
      wf_OffTime = 1200000;
      lcd.setCursor(1, 1);
      lcd.print("34%");
      break;

    case 'd':
      // насос 50% On - 50% Off
      wf_OnTime = 900000;
      wf_OffTime = 900000;
      lcd.setCursor(1, 1);
      lcd.print("50%");
      break;

    case 'e':
      // насос 66% On - 34% Off
      wf_OnTime = 1200000;
      wf_OffTime = 600000;
      lcd.setCursor(1, 1);
      lcd.print("66%");
      break;

    case 'f':
      // насос 83% On - 17% Off
      wf_OnTime = 1500000;
      wf_OffTime = 300000;
      lcd.setCursor(1, 1);
      lcd.print("83%");
      break;

    case 'g':
      // насос постоянно включен
      wf_OnTime = 3600000;
      wf_OffTime = 0;
      lcd.setCursor(1, 1);
      lcd.print("max");
      break;

   }
}


void rd_switchCommon(){
  
   switch (rd_common)
  {
    case 'k':
      // насос отключен
      rd_OnTime = 0;
      rd_OffTime = 3600000;
      lcd.setCursor(11, 1);
      lcd.print("min");
      break;

    case 'l':
      // насос 17% On - 83% Off
      rd_OnTime = 300000;
      rd_OffTime = 1500000;
      lcd.setCursor(11, 1);
      lcd.print("17%");
      break;

    case 'm':
      // насос 34% On - 66% Off
      rd_OnTime = 600000;
      rd_OffTime = 1200000;
      lcd.setCursor(11, 1);
      lcd.print("34%");
      break;

    case 'n':
      // насос 50% On - 50% Off
      rd_OnTime = 900000;
      rd_OffTime = 900000;
      lcd.setCursor(11, 1);
      lcd.print("50%");
      break;

    case 'o':
      // насос 66% On - 34% Off
      rd_OnTime = 1200000;
      rd_OffTime = 600000;
      lcd.setCursor(11, 1);
      lcd.print("66%");
      break;

    case 'p':
      // насос 83% On - 17% Off
      rd_OnTime = 1500000;
      rd_OffTime = 300000;
      lcd.setCursor(11, 1);
      lcd.print("83%");
      break;

    case 'q':
      // насос постоянно включен
      rd_OnTime = 3600000;
      rd_OffTime = 0;
      lcd.setCursor(11, 1);
      lcd.print("max");
      break;

   }
}
 
За это сообщение автора kotbrs поблагодарили (всего 2):
zaxar (Сб апр 27, 2019 8:15 pm) • Nika01 (Вт дек 29, 2020 12:06 am)
Рейтинг: 2.33%
Jager
Сообщения: 708
Зарегистрирован: Сб авг 18, 2012 10:21 am
Благодарил (а): 26 раз
Поблагодарили: 183 раза

Re: Управление обогревом в доме

Сообщение Jager » Пн ноя 28, 2016 9:19 pm

kotbrs писал(а):Нагретая вода из газового котла (замкнутый контур нагреваемой воды) поступает в раздаточный коллектор и оттуда идет в контур водяных полов, контур отопления (батареи) и контур нагрева гоДля раздачи воды на теплые полы (после насоса) стоит гребенка с кранами на которых можно порегулировать напор (и соответственно температуру) для теплых полов в разных помещениях(их есть три отдельных контура). Очень не хочется ставить управление на эти краны и постоянно их дрюкать, да и не копеечные они.
Судя по вашему описанию, это простите мой французский «Пиз@#ц какой то». Кто это монтировал?
На теплые полы ставится смесительный узел, в составе которого есть трехходовой клапан который и регулирует температуру теплоносителя для теплого пола, в том числе подмешивая обратку. Он может быть как ручным так и с термостатом.
Крутить температуру нагрева воды на газовом котле не хочется, потому как котел греет воду в том числе и для нагрева горячей воды которая течет из крана (используется бойлер на 300 л, через него и пропускается горячая вода из газового котла, которая нагревает воду поступающую в краны). Соответственно, если буду крутить температуру нагрева воды, то и в кране будет меняться температура воды, а этого не хочется.
Температуру теплоносителя котла обычно регулирует автоматика, чем холоднее на улице тем выше температура. У вас бойлер косвенного нагрева и нагревом воды управляет другой канал этой автоматики, который кстати имеет приоритет перед отоплением. Если это все правильно обвязано то температура горячей воды никак не зависит от температуры контура котла.
Бросьте все эти мысли про ардуино и esp, позовите нормального специалиста он все исправит и будет вам счастье.
Кстати, как вы пишете у вас бойлер на 300 литров.. надеюсь у вас котел минимум на 50кВт или живете в Краснодарском крае.
kotbrs
Сообщения: 18
Зарегистрирован: Сб авг 20, 2016 5:58 pm
Благодарил (а): 3 раза
Поблагодарили: 2 раза

Re: Управление обогревом в доме

Сообщение kotbrs » Вт ноя 29, 2016 8:09 am

Jager писал(а):
kotbrs писал(а):Нагретая вода из газового котла (замкнутый контур нагреваемой воды) поступает в раздаточный коллектор и оттуда идет в контур водяных полов, контур отопления (батареи) и контур нагрева ....
Судя по вашему описанию, это простите мой французский «Пиз@#ц какой то». Кто это монтировал?
На теплые полы ставится смесительный узел, в составе которого есть трехходовой клапан который и регулирует температуру теплоносителя для теплого пола, в том числе подмешивая обратку.
Крутить температуру нагрева воды на газовом котле не хочется, потому как котел греет воду в том числе и для нагрева горячей воды которая течет из крана (используется бойлер на 300 л, через него и пропускается горячая вода из газового котла, которая нагревает воду поступающую в краны). Соответственно, если буду крутить температуру нагрева воды, то и в кране будет меняться температура воды, а этого не хочется.
Температуру теплоносителя котла обычно регулирует автоматика, чем холоднее на улице тем выше температура. У вас бойлер косвенного нагрева и нагревом воды управляет другой канал этой автоматики, который кстати имеет приоритет перед отоплением. Если это все правильно обвязано то температура горячей воды никак не зависит от температуры контура котла.
Бросьте все эти мысли про ардуино и esp, позовите нормального специалиста он все исправит и будет вам счастье.
Кстати, как вы пишете у вас бойлер на 300 литров.. надеюсь у вас котел минимум на 50кВт или живете в Краснодарском крае.
Досталось уже смонтированая система.
Котел про внешнюю температуру не знает.
Беда в том, что контур нагрева воды для пола, батарей и нагрева бойлера - один.
На теплое время года я перекрываю кранами подачу воды для пола и батарей, также выключаю их насосы.
Живу в Подмосковье, горячей воды хватает, я ж не сразу ее выливаю ;)
Jager
Сообщения: 708
Зарегистрирован: Сб авг 18, 2012 10:21 am
Благодарил (а): 26 раз
Поблагодарили: 183 раза

Re: Управление обогревом в доме

Сообщение Jager » Вт ноя 29, 2016 10:05 am

kotbrs писал(а):Беда в том, что контур нагрева воды для пола, батарей и нагрева бойлера - один.
На теплое время года я перекрываю кранами подачу воды для пола и батарей, также выключаю их насосы.
Установите на теплый пол например это
Изображение
и у вас всегда будет стабильная температура пола, независимо от того сколько в котле градусов.
Последовательно с насосом который включается при запросе тепла от бойлера установите нормально закрытый клапан и запитайте его от того же насоса.
В результате у вас в бойлере будет та температура которую вы задали для горячей воды.
Эти минимальные телодвижения решат ваши проблемы.
Ответить