На этот раз хочу описать контроллер и обвес для котельной, который я с переменным успехом ваяю уже с полгода. ESP32, Kinkony A16, Modbus, тепломер, Arduino в слейв-режиме по i2c, ШИМ-управляемые насосы, дашборд, ну и MQTT. Тупой газовый котёл, гидрострелка, тёплые полы. Если эти слова вам близки, или хотя бы интересны - может и моя статья пригодится.
Начиналось всё как всегда, со статьи на Хабре. Кажется вот этой: Kincony KC868-A16: контроллер 16-го уровня. Ну или даже нет, если быть совсем точным, началось всё с комментария в одной из статей, откуда я узнал что эта железка на озоне продается дешевле полутора тысяч рублей. В тот момент я еще не очень понимал, зачем мне эта штуковина, но решил взять, просто чтобы было.
Дальше кинкони прилегла в долгий ящик, пришла зима, а с ней - некоторый дубак в цеху, где я работаю. Дубак удивительный - там на 400 квадратных метров стоит котёл 80 кВт, так что по всем прикидкам должен справляться. К сожалению, котёл еще и очень умный и дорогой, инсталляторы закрыли его и запретили в него лазить от слова совсем - по осени они приезжали, обслуживали его, тупо включали на 70 градусов и уезжали. Но в цеху-то холодно. И я решил посмотреть - что же реально происходит в теплосистеме.
Купил WirenBoard MAI6, 2 датчика давления, 2 датчика температуры, достал из загашника водосчетчик, и все собрал. Оказалось что инсталляторы по осени почистили так себе, перепад давлений на обратке и подаче - полтора очка, поток - меньше куба, и котел банально не отдает больше 40 кВт. Натыкал в готовые цифры инсталляторов, полечили, потеплело. Народ возрадовался и возжелал такую систему сгородить для всех котлов в компании, я принял к сведению. В процессе поиска водосчетчиков на поток побольше, обнаружил в продаже на том же озоне теплосчетчик Эко Ном СТУ-20 RS485 - готовый прибор, который сочетает ультразвуковой датчик расхода воды с 2 термометрами и контроллером, при этом умеет отдавать накопленные данные в RS485. На тот момент он еще и стоил 3650, так что я купил несколько штук на работу, ну и себе одну штучку - на побаловаться и интегрировать в свой УД.
Надо сказать, что когда я подключал газ и ставил котел, я не думал об автоматизации вообще. Поэтому взял то, что всунули монтажники - Celtic DS Platinum, он же Seoul Master Gas, он же еще несколько наименований. Котел туп как пробка, под автоматизацию не задуман, только встроенная автоматика с выносным пультом на проприетарном протоколе. Поэтому дома я оказался в уже знакомой по работе ситуации - котёл есть, но в плане интеграции его как бы и нет.
Решил повторить уже пройденный на работе опыт. Но наверное логично не тянуть RS485 из котельной до сервера, а ставить в котельной локальный контроллер, который соберёт все данные, отправит их, примет команды, и поставит их на исполнение.
Гидравлическая часть
Сердце системы - котёл Celtic DS Platinum 3.35 номинальной мощностью 40,7 кВт. Брал с запасом, дом 250 квадратов, но запас карман не тянет.
От котла - гидрострелка на 2 контура, 1 и 2 этаж. Второй этаж не эксплуатируется, контур не подключен. На обратках контуров непосредственно перед гидрострелкой - стандартные трехскоростные насосы.
Каждый контур - только тёплые полы, на каждый этаж по 6 контуров, расходомеры, электротермические приводы головок на каждом контуре.
Обращаю внимание: никаких трехходовых клапанов в принципе. Поскольку все отопление на теплых полах, нет нужды обеспечивать несколько температурных режимов, по наивности своей я думал что котёл мне отдаст сколько попрошу теплоносителя сносной для ТП температуры - градусов 45-50, дальше в гидрострелке подмешаю. О наивность!
Формулируем ТЗ
И что нам нужно, и что мы имеем в котельной? Ну ок, давайте списком:
Температура подачи и обратки
Поток теплоносителя
Давление в системе отопления
Мощность котла
Раз уж мы в котельной - можно оглянуться вокруг и добавить:
Импульсы счетчика газа
Импульсы счетчика воды
Давление подачи воды
Температуру в помещении
Температуру на улице
Температур подачи и обратки на вторичных контурах
Ну, вроде кинкони справится. Давления - на AI (и еще 2 останется), счетчики - на DI, температуры - на 1-wire, Эко Ном - на RS485. Можно начинать.
Собираем, итерация 1
Первая итерация - на моей универсальной прошивке для ESP ваяю на коленке дополнительный модуль RS485 для кинкони. Просто мост - принять от Эко Нома по RS485, отдать в IOBroker по Modbus TCP. Первая же проблема - Эко Ном живет на скорости 2400, а я поставил задержку чтения стандартную в 10 мс, и ответ просто не успевал приходить. Вылечил задержкой в 50 мс, данные пошли. Ну, на столе пошли. На радостях собрал для кинкони красивую шкурку из обрезков пластика

Хорошо, докупаем арматуру (ЭкоНом поставляется с термометром для обратки на 1/8", в обычных магазинах тройник 1"-1/8"-1" не встречается, пришлось заказывать), монтируем.
Вешаем кинкони на стену, собираем, подключаем, видим реальность:
22:20:32→ 01 03 00 00 00 0C 45 CF 22:20:32← 01 03 18 00 00 32 2D 00 00 00 00 00 00 0B 15 00 00 0B 11 00 00 00 04 00 00 07 DF 3C C6
Разбираем, и видим вполне вменяемые данные - температуры подачи и обратки, поток теплоносителя, вычисленную мощность, выработанную энергию и так далее. Лепота.
Монтируем датчики давления воды и отопления - на специальный отвод водопроводной гребенки и на гидрострелку соответственно. Датчики - с того же озона, рублей по 750, стандартные 4-20 мА 10 Бар, 1/4".

Счетчик воды я изначально брал с импульсным выходом, поэтому проблем не было - немножко нарастил провод и воткнул в кинкони.
А вот счетчик газа меня сначала привел в замешательство. Как я уже писал, на момент монтажа газового хозяйства я не интересовался автоматизацией, и счетчик Тритон-газ СГМ-4 выглядел примерно как реквизит из Фоллаута. Я уже было начал искать счетчики с импульсным выходом, чтобы поставить последовательно, но мне это все сильно не нравилось - у нас газовщики очень плохо смотрят на самодеятельность в газовой трассе, даже если после счетчика. Благо, сообразил поискать по картинкам. Оказалось что это реплика известной модели, в счетчике есть магнитик в последней циферке, и под него на thingverse есть хренова гора держателей герконов. Но естественно, все они не подошли. Пластилин и скотч мне не понравились, поэтому я взял просто кусок губчатой резины, прижал геркон в посадочном окне в спозиционированном по мультиметру состоянии, и закрыл родную заглушку.

Термодатчки - стандартные DS18B20 в китайском исполнении, завел на разные GPIO, чтобы не путаться и не связываться с привязкой по 1-wire ID.
И вот - почти всё вроде бы работает. Импульсы считаются, темературы на малом круге и в помещении меряются (на трассы до ТП пока решил не ставить). Я начинаю пристально вглядываться в показания и натыкаюсь на
Непреодолимые грабли
Поток через котел по расходомеру - 400 литров в час в прыжке. Как несложно посчитать, при дельте температур в 30 градусов это около 14 кВт. И это всё что мы можем себе позволить со штатным насосом котла. Делать дельту больше - это не вариант для тёплых полов, ножкам будет горячо.
Ок, лечение понятно - дополнительный насос. И заодно поменять насос на контуре - ему надо прокачивать столько же, если не больше, теплоносителя.
Путем беглого гуглежа по существующим на рынке насосам обнаруживаю что китайцы двигают BLDC в массы. И там, где раньше для управления требовался частотник и немаленький асинхронник, теперь стоят компактные, энергоэффективные, а главное - управляемые BLDC. Хорошо, смотрю отзывы, беру на озоне Shimge APE-A 25-6-130 ... и, конечно, промахиваюсь. Оказывается что у Shimge есть APE-A и APE - это разные штуки, и та, которая с A - это не от слова "автоматизируемый", а от слова "абычный". Ну и ладно, все равно мне в котел управление и не нужно - надо просто продавить куб в час. Заказываю для контура ТП уже настоящий APE 32-8-180.

Зато с Shimge APE-A 25-6-130, установленном на малом контуре, в режиме половинной мощности удалось добиться куба с лишним в час. А на полной при включенном в помощь насосе котла - расходомер зашкалило (у него предел 3 м3/час).
Доработка ТЗ
Ну вот, грабли надо интегрировать. Получается что нам надо 2 генератора ШИМ, частота порядка килогерца, и 2 быстрых входа для обратной связи от контурных насосов, частота 75 Гц. У кинкони DI и DO идут через мультиплексоры, поэтому воспользоваться ими не получится. А отдавать на ШИМ дефицитные GPIO не хочется, да и напряжение на них 3.3В, непонятно как насос к этому отнесется.
Кроме того, к этому моменту я уже натанцевался с littleFS и флашами, и решил что я НЕ ХОЧУ логировать данные на самом ESP32, но хочу как минимум не терять данные о накопленных импульсах счетчиков. Поэтому дополняем ТЗ:
управление как минимум 2 ШИМ 1000Гц, прием 2 ШИМ-сигналов 75Гц
ИБП
Arduino часть
Ардуинка подцепляется к Kinkony в штатный i2c разъем. Как я понимаю, это общая шина с мультиплексорами, но ничего страшного, обмен данным идовольно медленный.
Поскольку я домовитый, на ту же ардуинку я решил прикрутить 4 терморезистора NTC 10K, разгрузив 1-wire и создав общий "модуль на 2 контура", каждому контуру по 2 термометра, управлению и фидбеку.
Скетч получился совсем простой, но не с первого раза - клод забыл разделить чтение ADC, показания прыгали.
// ============================================================ // pump_slave.ino v1.3 // Arduino Pro Mini 5V/16MHz — I2C slave для KC868-A16 // // Пины: // D9 — PWM насос 1 (выход) // D10 — PWM насос 2 (выход) // D3 — feedback насос 1 (вход, INT1) // D2 — feedback насос 2 (вход, INT0) // A0-A3 — NTC термометры // A4/A5 — I2C SDA/SCL // // I2C адрес: 0x30 // Serial 9600: команды "1:XX" "2:XX" (duty 0-100) // // v1.3 — два фикса при вводе в эксплуатацию (см. чат с Михаилом, // реальный насос + термисторы подключены впервые): // 1. FB1/FB2 переведены с INPUT на INPUT_PULLUP. Фидбек насоса, // похоже, open-collector (просто "притапливает" линию к GND, сам // не может выдать чистый HIGH) — без подтяжки цифровой вход не // видел настоящих переходов и duty всегда считался 0%. Если // фидбек на самом деле push-pull — внутренняя подтяжка (~20-50кОм) // слишком слабая, чтобы чему-то помешать, менять безопасно в любом // случае. // 2. NTC: добавлено "прогревочное" чтение перед реальным на каждом // канале. Раньше analogRead() шёл по кругу A0→A1→A2→A3 без паузы — // классический кроссталк АЦП АVR: заряд конденсатора выборки- // хранения от предыдущего (низкоомного, если термистор реально // подключён) канала утекает в следующий, если тот висит в воздухе // (высокий импеданс, долго "забывает" чужой заряд). Именно поэтому // подключение ОДНОГО термистора портило показания на ВСЕХ // остальных, независимо от того, в какой канал его воткнули. // ============================================================ #include <Wire.h> #define I2C_ADDR 0x30 #define PIN_PWM1 9 #define PIN_PWM2 10 #define PIN_FB1 3 // INT1 #define PIN_FB2 2 // INT0 #define PIN_NTC0 A0 #define PIN_NTC1 A1 #define PIN_NTC2 A2 #define PIN_NTC3 A3 #define PWM_TOP 1999 // 16MHz / (8 * 2000) = 1000 Hz // ── Состояние ──────────────────────────────────────────────── volatile uint8_t g_duty1 = 95; volatile uint8_t g_duty2 = 95; // Feedback: измеряем через digitalRead в ISR volatile uint32_t g_fb1_rise_us = 0; // момент последнего RISING volatile uint32_t g_fb1_last_fall_us = 0; // момент последнего FALLING volatile uint32_t g_fb1_high_us = 0; // длительность HIGH volatile uint32_t g_fb1_period_us = 0; // период (FALLING → FALLING) volatile uint32_t g_fb2_rise_us = 0; volatile uint32_t g_fb2_last_fall_us = 0; volatile uint32_t g_fb2_high_us = 0; volatile uint32_t g_fb2_period_us = 0; volatile uint32_t g_fb1_last_us = 0; // для детекции тишины volatile uint32_t g_fb2_last_us = 0; uint8_t g_fb1_duty = 0, g_fb2_duty = 0; uint16_t g_ntc[4] = {0, 0, 0, 0}; uint8_t g_tx[10]; const uint8_t NTC_PINS[4] = {PIN_NTC0, PIN_NTC1, PIN_NTC2, PIN_NTC3}; uint32_t g_last_print = 0; String g_serial_buf = ""; // ============================================================ // PWM: Timer1, Fast PWM mode 14, prescaler 8 → 1000 Hz // ============================================================ uint16_t dutyToOcr(uint8_t duty) { if (duty > 100) duty = 100; return (uint32_t)duty * PWM_TOP / 100; } void pwmSetup() { pinMode(PIN_PWM1, OUTPUT); pinMode(PIN_PWM2, OUTPUT); TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); ICR1 = PWM_TOP; OCR1A = dutyToOcr(g_duty1); OCR1B = dutyToOcr(g_duty2); } void applyDuty() { OCR1A = dutyToOcr(g_duty1); OCR1B = dutyToOcr(g_duty2); } // ============================================================ // Feedback ISR — определяем фронт через digitalRead // ============================================================ void fb1_isr() { uint32_t now = micros(); g_fb1_last_us = now; if (digitalRead(PIN_FB1)) { // RISING — запоминаем начало HIGH g_fb1_rise_us = now; } else { // FALLING — считаем длительность HIGH и период if (g_fb1_rise_us > 0) g_fb1_high_us = now - g_fb1_rise_us; if (g_fb1_last_fall_us > 0) g_fb1_period_us = now - g_fb1_last_fall_us; g_fb1_last_fall_us = now; } } void fb2_isr() { uint32_t now = micros(); g_fb2_last_us = now; if (digitalRead(PIN_FB2)) { g_fb2_rise_us = now; } else { if (g_fb2_rise_us > 0) g_fb2_high_us = now - g_fb2_rise_us; if (g_fb2_last_fall_us > 0) g_fb2_period_us = now - g_fb2_last_fall_us; g_fb2_last_fall_us = now; } } uint8_t calcDuty(volatile uint32_t& high_us, volatile uint32_t& period_us) { uint32_t h, p; noInterrupts(); h = high_us; p = period_us; interrupts(); if (p == 0) return 0; uint32_t d = (uint32_t)h * 100 / p; if (d > 100) d = 100; return (uint8_t)d; } // ============================================================ // I2C // ============================================================ void onReceive(int bytes) { if (bytes < 2) { while (Wire.available()) Wire.read(); return; } uint8_t d1 = Wire.read(); uint8_t d2 = Wire.read(); while (Wire.available()) Wire.read(); g_duty1 = constrain(d1, 0, 100); g_duty2 = constrain(d2, 0, 100); applyDuty(); } void onRequest() { g_tx[0] = g_fb1_duty; g_tx[1] = g_fb2_duty; for (int i = 0; i < 4; i++) { g_tx[2 + i*2] = g_ntc[i] >> 8; g_tx[2 + i*2 + 1] = g_ntc[i] & 0xFF; } Wire.write(g_tx, 10); } // ============================================================ // Serial команды // ============================================================ void handleSerial() { while (Serial.available()) { char c = Serial.read(); if (c == '\n' || c == '\r') { g_serial_buf.trim(); if (g_serial_buf.length() >= 3 && g_serial_buf[1] == ':') { int pump = g_serial_buf[0] - '0'; int duty = g_serial_buf.substring(2).toInt(); duty = constrain(duty, 0, 100); if (pump == 1) { g_duty1 = duty; applyDuty(); Serial.print("PWM1 = "); Serial.println(duty); } if (pump == 2) { g_duty2 = duty; applyDuty(); Serial.print("PWM2 = "); Serial.println(duty); } } g_serial_buf = ""; } else { g_serial_buf += c; } } } // ============================================================ // SETUP / LOOP // ============================================================ void setup() { Serial.begin(9600); Serial.println("pump_slave v1.3"); Serial.println("Commands: 1:XX or 2:XX (duty 0-100, >=95=stop)"); // v1.3: INPUT_PULLUP вместо INPUT — см. changelog вверху файла. pinMode(PIN_FB1, INPUT_PULLUP); pinMode(PIN_FB2, INPUT_PULLUP); pwmSetup(); attachInterrupt(digitalPinToInterrupt(PIN_FB1), fb1_isr, CHANGE); attachInterrupt(digitalPinToInterrupt(PIN_FB2), fb2_isr, CHANGE); Wire.begin(I2C_ADDR); Wire.onReceive(onReceive); Wire.onRequest(onRequest); Serial.println("Ready."); } void loop() { handleSerial(); // Feedback g_fb1_duty = calcDuty(g_fb1_high_us, g_fb1_period_us); g_fb2_duty = calcDuty(g_fb2_high_us, g_fb2_period_us); // Сброс если сигнал пропал > 100мс uint32_t now = micros(); if (now - g_fb1_last_us > 100000UL) { g_fb1_duty = 0; g_fb1_period_us = 0; } if (now - g_fb2_last_us > 100000UL) { g_fb2_duty = 0; g_fb2_period_us = 0; } // NTC — v1.3: прогревочное чтение перед реальным, см. changelog вверху // файла (кроссталк АЦП между низкоомным подключённым каналом и // висящими в воздухе соседними). for (int i = 0; i < 4; i++) { analogRead(NTC_PINS[i]); // throwaway g_ntc[i] = analogRead(NTC_PINS[i]); } // Вывод каждые 500мс uint32_t ms = millis(); if (ms - g_last_print >= 500) { g_last_print = ms; Serial.print("PWM1="); Serial.print(g_duty1); Serial.print("% FB1="); Serial.print(g_fb1_duty); Serial.print("% PWM2="); Serial.print(g_duty2); Serial.print("% FB2="); Serial.print(g_fb2_duty); Serial.print("% NTC: "); for (int i = 0; i < 4; i++) { Serial.print(g_ntc[i]); if (i < 3) Serial.print(" "); } Serial.println(); } delay(20); }

ИБП

Тут всё просто - берем Step-Up DC 5-24, модуль PowerBank с алиэкспресса, пригоршню терминалов (да, лучше пригоршню - 24В надо не только для кинкони, но и для датчиков, и для Эко Нома), паяем на макетке. И да, я опять соединил все земли и у батарейки нет защиты от переразряда, ну и пусть, не жалко. Из соображений компактности держатель батарейки разместил над модулями, получилось мило, но наверное не стоило так делать, больше не буду.
К сожалению, в процессе изготовления не фотал, только уже установленный. Слева сверху вниз:
- ввод 5В
- выход голый с батареи
- 6 шт GND и 6 шт +24В
Собираем снова, итерация 2
Красивый чОрный корпус отправляется ждать следующего кинкони со следующим проектом. А в дело вступает валявшийся бокс от сигнализационного ИБП. Туда войдут:
кинкони
импульсный БП 5В
платка на макетке из блока PowerBank на TP4056 и DC Step-Up конвертера на 24В
гнездо под литиевый аккум 18650
кусок дин-рейки под модульное оборудование - вдруг когда-нибудь я захочу туда реле накрутить и рулить чем-нибудь типа насоса.
Arduino Pro Mini на макетке

Рефакторим прошивку
Тут будет лирика, не очень относящаяся собственно к проекту - можно было обойтись и без этого. Суть в том, что я ощутил в себе навязчивое желание рефакторить свою модульную прошивку.
Собственно, проблема была в том, что прошивка переросла себя: несмотря на то, что каждый модуль писался отдельным файлом, всё это сводилось в один большой main.cpp, в котором проводился опрос датчиков, пересчёт в физические величины, отрисовывался веб-интерфейс и MQTT. Работало, но каждое новое устройство или новая вкладка в интерфейсе означала правки в нескольких не связанных друг с другом местах, риск что-то сломать повышался (и даже несколько раз реализовывался).
Поскольку контроллер получается нехило разветвленный и включал в себя 3 новых device (kinkony, ekonom, arduino), я решил что пора. Расчехлил по случаю клод коворк, отдал ему старый проект, описал вкратце идею общей шины данных для модулей, ответил на несколько вопросов и пошел заниматься своими делами.
Клод переписал ядро с нуля, добавив шину данных (Bus) по схеме publish/subscribe. API шины прост и незамысловат:
cpp
Bus::declare("p_heat", 100); // объявить канал, scale=100 (сотые доли) Bus::write("p_heat", 187); // записать значение (1.87 бар) int64_t v = Bus::read("p_heat"); // прочитать текущее Bus::subscribeAll([](const char* id, int64_t value) { // вызывается на КАЖДОЕ изменение любого канала });
Значения хранятся как int64_t с отдельным множителем (scale) — на ESP32 это дешевле и предсказуемее, чем float, а для котельной гигаточности не нужны. Ну и гонять float через MQTT/JSON/веб - дело такое, кто-нибудь что-нибудь округлит не туда.
Дальше всё строится по одному правилу: устройства только пишут в шину, ничего не знают о том, кто их данные читает. Опрос датчика давления, счётчиков воды/газа, термисторов, насоса - каждый просто публикует свои raw.* каналы. Отдельный слой (BoilerRoomApp) читает эти raw-значения, применяет калибровки (переводит миллиамперы в бар, ADC-код термистора в градусы по бета-модели) и публикует уже физические величины — тоже в шину, под другими именами.
А дальше сколько угодно независимых потребителей одних и тех же данных: веб-дашборд опрашивает /api/channels и рисует таблицу, MQTT-модуль подписан на subscribeAll и шлёт каждое изменение в брокер, вкладка диагностики фильтрует всё, что начинается с raw.. Ни один из этих потребителей не знает про существование остальных и не знает, откуда физически взялось значение — с термистора, с RS485-теплосчётчика или из ADC.
Практический эффект: когда потребовалось добавить дельту температур насосного контура (подача минус обратка) — это оказалось одной новой строчкой Bus::declare и десятком строк расчёта, без правок в веб-интерфейсе или MQTT-модуле — оба сами подхватили новый канал, потому что пробегают по шине в полном объеме.
Из подводных камней: шина живёт в статическом массиве фиксированного размера (без malloc — на микроконтроллере это осознанный выбор), когда для диагностики добавил состояния всех входов и выходов кинкони, упёрся в потолок и некоторое время пытался понять, куда делись уже зарегистрированные данные - каналов шины не хватило, и часть данных скрылись в неизвестность. Вылечилось увеличением количества каналов до 128.
Подключаем насос
Приехавший насос серии APE оснащен трехпиновым разъемом управления и контроля. Судя по инструкции, существует фирменный кабель для подключения - красивый как Охтинский мост, с герметизированным концом для насоса и понятной цветовой маркировкой провода. Но дистрибутор забыл его завести.
Благо, колодец под разъем глубокий и прочный, а шаг и размер пинов внутри точно соответсвуют IDC 2.54, поэтому берем из запасников произвольный ардуинохвост с мамами на стандартную гребенку, наращиваем провод, и втыкаем.
В инструкции есть даже схема разъема. Но подписи к схеме набраны 3-4 мм кеглем, а в моем экземпляре они еще и не пропечатались, поэтому тыкался наобум. Правильный порядок, направление от кабеля питания к краю насоса: PWM signal - GND - Feedback.
Характеристика ШИМ не банальна: скважность 85-10% линейно соответсвует скорости 1-100%, 85-94% - минимальная скорость, 95% и выше - останов, 1-10% - максимальная скорость, 0 - игнорируется ШИМ, насос работает в установленном кнопкой на корпусе режиме. Естественно, на уровне дашборда всё это великолепие отмапили в стандартную шкалу 0-100% и чекбокс ручного режима.
Фидбек удивил еще больше: как я понял, он не про скорость, а про нагрузку, скважность линейно означает потребляемую мощность, 1% = 1 Вт мощности. Но это неточно, надо бы достать ваттметр и проверить.
Ну и вишенкой - сигнал фидбека на открытом коллекторе, из-за чего иногда проскакивают значения около 100%, не стал разбираться и городить физический фильтр, на уровне прошивки ESP заблокировал всё, что больше 75.
Рисуем дашборд
Наверное тут картинки только, даже не знаю что написать можно. Как говорится, "вместо тысячи слов":





Пожалуй, добавлю что вкладки RS485 и диагностики включаемые на лету, в общих настройках есть чекбокс, работающий без перезагрузки контроллера
Итог, возможно промежуточный
Всё собрано, нигде не капает, контроллер работает в полном составе, система отопления, если не в порядке, то по крайней мере контролируема и диагностируема на лету, если засрется фильтр или котел или еще что-нибудь - можно будет оперативно поправить.
В планах - интеграция насоса ХВС (не знаю даже, может альтернативой будет частотник), насоса подкачки теплоносителя, системы защиты от протечек, ну и еще на что фантазии хватит.
Смета
Проект делался долго и упорно, часть комплектухи валялась по сусекам, цены на них по памяти и могут быть неактуальны. Некоторые вещи (например ящик) я даже не представляю где и почем продаются, цену ставил по внутреннему ощущению. Арматура учитывается только та, которую пришлось реально докупать, тройники в ПП у меня либо были заложены и заглушены, либо валялись в запасе.
Наименование |
Количество |
Стоимость |
Kinkony A16 |
1 шт |
1300 |
Arduino Pro Mini |
1 шт |
250 |
DC Step-up 5-24V |
1 шт |
170 |
PowerBank module |
1 шт |
55 |
18650 Li-Ion |
1 шт |
200 |
БП 5В 3А |
1 шт |
350 |
Ящик ИБП |
1 шт. |
1000 |
Мелочевка (терминалы, резисторы, держатель батареи) |
набор |
500 |
Эко Ном СТУ20-RS |
1 шт |
3650 |
Тройник 1" под датчик с ниппелем 1" |
1шт |
750 |
Датчик давления PT-506 |
2 шт |
1500 |
Футорка 1/4"-1/2" |
2 шт |
150 |
Термистор NTC 10K |
4 шт |
48 |
Гильза 6мм 1/2" |
4 шт |
840 |
Счетчик воды |
1 шт |
800 |
Геркон для газового счетчика |
1 шт |
30 |
Насос Shimge APE-A 25-6 |
1 шт |
6700 |
Насос Shimge APE 32-8 |
1 шт |
6500 |
Итого: |
24793 |
Alsig
Такое специфичное решение для газа и некоторого закрытого объёма, где он может собраться. Я бы поставил пару независимых систем безопасности и сам блок управления на демпферах поставил, для нейтрализации влияния вибрации.
Без критики, просто доп варианты безопасности.
vbifkol Автор
Кажется я чего-то не понял. Контроллер висит в котельной на бетонной стене. Газа он никак не трогает, его вообще можно за пределы котельной вынести. Куда и зачем демпферы?
Газовая автоматика конечно висит, родная - анализатор газа с сигнализацией и автоматическим клапаном. Кажется у нее даже есть выход на сигнализацию, но беглый гуглеж не показал протокола и я решил её не подключать к контроллеру. О том что газ перекрыт я узнаю по выравниванию обратки и подачи ниже уровня уставки.