standov Опубліковано: 1 січня Поділитись Опубліковано: 1 січня Не оч понятно, в вас ніяк не відрізняється зима/літо? Бо бачу ви орієнтуєтесь на температуру вихлопу? Він жеж дуже залежить від сезону Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: 1 січня Автор Поділитись Опубліковано: 1 січня (змінено) 2 години тому, standov сказав: Не оч понятно, в вас ніяк не відрізняється зима/літо? Бо бачу ви орієнтуєтесь на температуру вихлопу? Він жеж дуже залежить від сезону * Варто напевно виправити, але це температура не вихлопу на вулицю, а температура повітря з будинку (Extract Air), тобто на вході в ТО. На момент написання цього коду визначення сезону ще не було. Хоча там і не дуже складний код, можна було дописати, але вирішив упустити цю перевірку. Частково по датчику повітря витяжки з будинку можна "визначити" сезон зима/літо, бо при вуличній приблизно нижче 15С при довгому простої температури в ПВУ падають, в порівнянні коли ПВУ працює. Відповідно чим нижча температура на вулиці, тим більше остиває ПВУ. Для прикладу, на вулиці 18С і вище - остивання в ПВУ мінімальне або навіть відсутнє, при 15-18С - остивання 1-2 градуси, при 10-15С - 2-4 градуси, при 0-10С - 4-7 градусів, і тд. Тобто якщо в момент запуску по датчику з будинку буде 15С, при типових 20-22С, то остивання на 5-7С може свідчити що на вулиці точно не літо. Поки що час прогрівання і діапазони умов просто фіксовані, щоб перевірити чи код працює і щоб не вдаватися в якісь складніші розрахунки. В цілому і того вистачить, трохи прогріти, якщо ТО холодний. Тривалість і діапазони треба підкоригувати. Змінено 1 січня користувачем TaurosRMK Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: 1 січня Автор Поділитись Опубліковано: 1 січня Поки що не розібрався чи то так має бути, чи потрібно якось зберігати значення деяких сенсорів. Для прикладу деякі бінарні сенсори які приймають значення True при виконанні деяких умов, а умови можуть мати затримки щоб не спрацьовувати часто. Якщо такий сенсор має затримку 10 хв, а від нього залежить ще якись код, який має свою затримку 5 хв, то при кожному оновленні прошивки все скидається в початковий стан і відповідно треба чекати знову, поки спливуть всі затримки і виконаютсья умови. Наприклад, сезон Зима/Літо, якщо Т вулична нижче 15С протягом 15 хв, то сезон Зима. Система працює протягом дня, визначила що сезон Зима, але прийшлося оновити прошивку і після оновлення знову очікування 15 хв щоб визначився сезон. Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: 5 січня Автор Поділитись Опубліковано: 5 січня Ще один кусок автоматизації - запуск витяжного вентилятора на максимальну швидкість для зливу конденсату з теплообмінника. Перший бінарний сенсор визначає чи працює система не менше 30 хв (поки для прикладу), наступний перевіряє всі умови для запуску автоматизації - приточний вентилятор запущений / заслонка відкрита, аналогічно і витяжний, сезон Зима, на вулиці нижче +10С (для прикладу) і статус системи "В роботі". Потім через інтервал кожні 3 години буде відпрацьовувати автоматизація - вимкнення балансування вентиляторів, витяжний на 100% на 90 сек (для прикладу), повернення витяжного на попередньо швидкість, вмикання балансування. # Запуск витяжного вентилятора на 100% для зливу конденсату binary_sensor: - platform: template name: "System Running 30min" id: system_is_running_30min lambda: |- return id(system_is_running).state; filters: - delayed_on: 30min # 30min - delayed_off: 0s - platform: template name: "Condensation Drain" id: condensation_drain lambda: |- if (id(system_is_running_30min).state && id(do_1).state && id(do_2).state && id(outdoor_temp).state < 10.0 && id(mvhr_status) == "running" && id(season_winter).state) { return true; } else { return false; } interval: - interval: 3h # 3h then: - if: condition: binary_sensor.is_on: condensation_drain then: - switch.turn_off: balancing_on - lambda: |- id(previous_exhaust_speed) = id(exhaust_fan).speed; // Зберегти попередню швидкість auto call = id(exhaust_fan).turn_on(); call.set_speed(100); // Увімкнути на 100% call.perform(); ESP_LOGI("MHRV", "Exhaust Fan set to 100%"); - delay: 90s - lambda: |- auto call = id(exhaust_fan).turn_on(); call.set_speed(id(previous_exhaust_speed)); // Повернути на попередню швидкість call.perform(); ESP_LOGI("MHRV", "Exhaust Fan returned to previous speed: %f", id(previous_exhaust_speed)); - delay: 1min - switch.turn_on: balancing_on Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: 16 січня Автор Поділитись Опубліковано: 16 січня (змінено) В темі про вентиляцію показував як за допомогою сенсорів SDP810, які маряють перепад тиску, зробив сенсори щоб розраховувати об'єм повітря і в подальшому балансувати систему. Про самі DIY сенсори описано в темі про вентиляцію, тут залишу код для ESPHome. Сенсори поки що підключені до окремих ESP32, які заведені в НА, тому в основний контролер ESP32 підтягуємо значення сенсорів. Прихований текст sensor: - platform: homeassistant entity_id: sensor.sdp810_supply_sdp810_supply name: "sdp supply" id: sdp810_supply internal: true - platform: homeassistant entity_id: sensor.sdp810_exhaust_sdp810_exhaust name: "sdp exhaust" id: sdp810_exhaust internal: true Далі на прикладі одного сенсору. Потрібно розрахувати падіння тиску в трубках якими під'єднані сенсори і вирахувати це значення з показань сенсора (так ніби трубок там немає). В документах до сенсору є формула, яка виглядає трохи страшно, але ШІ допоміг то все швидко записати 😁 Прихований текст Спочатку по сенсорах температури і вологості розраховуєтсья густина повітря. Прихований текст # Густина приточного повітря, кг/м³ - platform: template name: "Supply Air Density" id: supply_air_density lambda: |- // Температура повітря (°C) float temp_celsius = id(sht30_sup_temp).state; // Відносна вологість (%) float humidity = id(sht30_sup_hum).state; // Газова константа сухого повітря (Дж/(кг*К)) float R_dry_air = 287.05; // Газова константа водяної пари (Дж/(кг*К)) float R_water_vapor = 461.495; // Насичений парціальний тиск водяної пари (Па) float p_sat = 611.2 * exp((17.62 * temp_celsius) / (243.12 + temp_celsius)); // Парціальний тиск водяної пари (Па) float p_vapor = humidity / 100.0 * p_sat; // Атмосферний тиск в Па float atm_pressure = 102800; // Парціальний тиск сухого повітря (Па) float p_dry = atm_pressure - p_vapor; // Температура повітря в Кельвінах float T_kelvin = temp_celsius + 273.15; // Розрахунок густини повітря (кг/м³) float air_density = (p_dry / (R_dry_air * T_kelvin)) + (p_vapor / (R_water_vapor * T_kelvin)); return air_density; state_class: "measurement" unit_of_measurement: "kg/m³" accuracy_decimals: 4 update_interval: 60s Розрахунок падіння тиску в трубках і компенсація показів сенсору на ці значення. Прихований текст # Падіння тиску в трубках, Па (приток) - platform: template name: "Supply Tube Pressure Drop" id: supply_tube_pressure_drop lambda: |- float dp_sensor = id(sdp810_supply).state; float temperature = id(sht30_sup_temp).state; float rho_air = id(supply_air_density).state; float L = 1; // довжина трубок в метрах float D = 0.004; // внутрішній діаметр трубки в метрах float q_c = 6.17 * pow(10, -7); float dp_c = 62; // Формула розрахунку в'язкості повітря (η_air) float air_viscosity = (18.205 + 0.0484 * (temperature - 20)) * pow(10, -6); // Формула розрахунку ε float epsilon = (-64 / 3.14159) * (L / pow(D, 4)) * (air_viscosity / rho_air) * (q_c / dp_sensor) * (std::sqrt(1 + (8 * dp_sensor / dp_c)) - 1); return dp_sensor * ((1 / (1 + epsilon)) - 1); unit_of_measurement: "Pa" accuracy_decimals: 2 update_interval: 5s # Перепад тиску з коригуванням на падіння тиску в трубках (приток) - platform: template name: "Supply Differential Pressure" id: supply_dp lambda: |- float dp_sensor = id(sdp810_supply).state; float dp_tube = id(supply_tube_pressure_drop).state; return dp_sensor - dp_tube; unit_of_measurement: "Pa" accuracy_decimals: 2 update_interval: 5s По формулі розраховується середня швидкість через перепад тиску який віддає сенсор і густину повітря. Де CF - коефіцієнт, який потрібно лабораторно визначати, або ж робити заміри швидкості іншим пристроєм (наприклад анемометр) і вирахувати з формули цей коефіцієнт. Поки що прийнято за 1. Оновлено код з врахуванням калібрування по коефіцієнту. Прихований текст # Швидкість приточного повітря, м/с - platform: template name: "Supply Air Velocity" id: supply_air_velocity lambda: |- // Перепад тиску (Па) float delta_p = id(supply_dp).state; // Густина повітря (кг/м³) float air_density = id(supply_air_density).state; // Швидкість повітря (м/с) float velocity = std::sqrt((2 * delta_p) / air_density); return velocity; filters: - calibrate_polynomial: degree: 2 datapoints: # Map 0.0 (from sensor) to 0.0 (true value) - 1.0 -> 0.7 - 1.98 -> 1.44 - 3.83 -> 3.17 - 5.89 -> 5.22 - 7.93 -> 6.98 device_class: "speed" state_class: "measurement" icon: mdi:gauge unit_of_measurement: "m/s" accuracy_decimals: 2 update_interval: 5s На основі швидкості розраховується об'єм повітря в повітроводі. Прихований текст # Об'ємний потік приточного повітря, м³/год - platform: template name: "Supply Air Volume Flow" id: supply_air_volume_flow lambda: |- // Швидкість повітря (м/с) float velocity = id(supply_air_velocity).state; // Площа перерізу каналу (м²) float area = 3.14159 * pow((0.15 / 2), 2); // Об'ємний потік повітря (м³/с) float volume_flow_rate = area * velocity; // Об'єм повітря за годину (м³/год) float volume_m3_h = volume_flow_rate * 3600; // 3600 секунд return volume_m3_h; device_class: "volume_flow_rate" state_class: "measurement" icon: mdi:gauge unit_of_measurement: "m³/h" update_interval: 30s accuracy_decimals: 0 Змінено 17 січня користувачем TaurosRMK 1 Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: 20 січня Автор Поділитись Опубліковано: 20 січня Балансування вентиляторів. При виборі пресету зі списку швидкість вентиляторів встановлюється на обрану. Так вийшло що в мене опір притоку і витяжки майже однаковий, тому вентилятори видають майже однакову продуктивність при плюс-мінус однакових обертах. Тому встановлюю швидкість на обидва вентилятори рівну, а дальше при потребі відбувається коригування швидкостей вентиляторів щоб вирівняти потоки. Якщо вручну змінити швидкість якогось вентилятора, то контролер буде її вирівнювати, поки потоки не будуть приблизно рівними. Наче працює нормально. select: - platform: template id: air_flow_select name: "Air Flow Select" options: - "Min (90 m³/h)" - "Low (120 m³/h)" - "Medium (160 m³/h)" - "Default (210 m³/h)" - "High (300 m³/h)" - "Max (400 m³/h)" initial_option: "Medium (160 m³/h)" restore_value: true optimistic: true on_value: - lambda: |- float new_fan_speed = 0.0; if (id(air_flow_select).state == "Min (90 m³/h)") { id(target_air_flow) = 90.0; new_fan_speed = 35.0; } else if (id(air_flow_select).state == "Low (120 m³/h)") { id(target_air_flow) = 120.0; new_fan_speed = 42.0; } else if (id(air_flow_select).state == "Medium (160 m³/h)") { id(target_air_flow) = 160.0; new_fan_speed = 50.0; } else if (id(air_flow_select).state == "Default (210 m³/h)") { id(target_air_flow) = 210.0; new_fan_speed = 61.0; } else if (id(air_flow_select).state == "High (300 m³/h)") { id(target_air_flow) = 300.0; new_fan_speed = 75.0; } else if (id(air_flow_select).state == "Max (400 m³/h)") { id(target_air_flow) = 400.0; new_fan_speed = 94.0; } auto call_supply = id(supply_fan).turn_on(); call_supply.set_speed(new_fan_speed); call_supply.perform(); auto call_exhaust = id(exhaust_fan).turn_on(); call_exhaust.set_speed(new_fan_speed); call_exhaust.perform(); switch: - platform: template id: fan_balancing name: "Fan Balancing" icon: mdi:tune optimistic: true interval: - interval: 2min then: - lambda: |- if (id(fan_balancing).state) { float supply_speed = id(supply_fan).speed; float exhaust_speed = id(exhaust_fan).speed; float supply_flow = id(supply_air_volume_flow).state; float exhaust_flow = id(exhaust_air_volume_flow).state; auto call_supply = id(supply_fan).turn_on(); auto call_exhaust = id(exhaust_fan).turn_on(); float difference = supply_flow - exhaust_flow; float tolerance = 5; float speed_change = (abs(difference) > 20) ? 5 : 1; if (abs(difference) > tolerance) { float new_supply_speed = supply_speed + (difference > 0 ? -speed_change : speed_change); new_supply_speed = constrain(new_supply_speed, 0, 100); call_supply.set_speed(new_supply_speed); call_supply.perform(); float new_exhaust_speed = exhaust_speed + (difference > 0 ? speed_change : -speed_change); new_exhaust_speed = constrain(new_exhaust_speed, 0, 100); call_exhaust.set_speed(new_exhaust_speed); call_exhaust.perform(); } } Подумав що можна трохи допрацювати код. Якщо потоки рівні (+ похибка), то можна не робити балансування, а запускати тільки коли потоки відрізняються. Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: В п'ятницю в 18:27 Автор Поділитись Опубліковано: В п'ятницю в 18:27 Підкажіть як правильно записати умови для такої автоматимзації. Тобто саме умови, логіку. Суть задачі - балансування швидкості вентиляторів (приток/витяжка). Вхідні дані: два датчики потоку (м3/год) і два вентилятори. Має працювати якось так. З випадаючого списку вибирається пресет потрібного об'єму повітря (120, 160, 210 м3/год та ін). Ручним методом було знайдено швидкості вентиляторів які плюс-мінус відповідають цим пресетам, тому зразу при виборі пресету швидкісь вентиляторів встановлюється на відповідні значення. А дальше вступає в роботу балансування, яке має робити наступне: Перевіряти по датчиках чи потоки відповідають вибраному пресету (±похибка 10 м3/год). Якщо потоки вентиляторів менше/більше пресету (±похибка), то швидкість збільшується/зменшується на 1. При цьому також має перевірятися умова приток > витяжка. Тобто з цими умовами потоки мають бути в "балансі" близькими до пресету і щоб не виходили за межі похибки, а також щоб приток завжди був більше витяжки. Можливо для цього треба похибку трохи збільшити, бо самі датчики можуть давати похибку в 10-15 м3/год при незмінних обертах вентиляторів. Але це вже інше питання. Допомагав в цьому звісно AI друг Copilot і вийшов такий код, але щось він працює трохи не коректно. Спроби переробити були безуспішні, AI починає фігню пропонувати, пишу одне, пропонує зовсім інше. В цілому наче працює добре, але є моменти, коли напевно умови перевіряються одночасно и одна іншій заважає, тобто буває що приточний потік виходить за межі похибки, але при цьому він стає більшим за витяжний потік. Тобто одна умова виконалася. А потім швидкість зменшується, потік входить в допустимі межі і тут знову спрацьовує умова що притік < витяжки, і знову починається коригування туда-сюда. interval: - interval: 2min then: - lambda: |- if (id(fan_balancing).state) { float supply_flow = id(supply_air_volume_flow).state; float exhaust_flow = id(exhaust_air_volume_flow).state; float target_flow = id(target_air_flow); auto call_supply = id(supply_fan).turn_on(); auto call_exhaust = id(exhaust_fan).turn_on(); float flow_difference = abs(supply_flow - target_flow); float tolerance = 10; float speed_step = (abs(flow_difference) > 20) ? 5 : 1; // Коригуємо приточний вентилятор float new_supply_speed = id(supply_fan).speed; if (abs(supply_flow - target_flow) > tolerance) { new_supply_speed += (supply_flow < target_flow) ? speed_step : -speed_step; } // Коригуємо витяжний вентилятор float new_exhaust_speed = id(exhaust_fan).speed; if (abs(exhaust_flow - target_flow) > tolerance) { new_exhaust_speed += (exhaust_flow < target_flow) ? speed_step : -speed_step; } // Переконуємось, що потік приточного повітря більший за витяжний if (supply_flow <= exhaust_flow) { if (exhaust_flow >= target_flow) { new_exhaust_speed -= 1; new_supply_speed += 1; } else { new_supply_speed += 1; } } new_supply_speed = constrain(new_supply_speed, 0, 100); call_supply.set_speed(new_supply_speed); call_supply.perform(); new_exhaust_speed = constrain(new_exhaust_speed, 0, 100); call_exhaust.set_speed(new_exhaust_speed); call_exhaust.perform(); } Посилання на коментар Поділитися на інших сайтах More sharing options...
volomoto Опубліковано: В понеділок в 09:01 Поділитись Опубліковано: В понеділок в 09:01 25.04.2025 в 21:27, TaurosRMK сказав: Підкажіть як правильно записати умови для такої автоматимзації. Тобто саме умови, логіку. Один з вентиляторів треба зафіксувати по пресету, а іншим вентилятором вже коригувати. Коригування треба робити з допомогою PID контроллера. На вхід контроллера подаєте різницю між потоками з додаванням константи для виконання умови приток > витяжка, і контроллер має звести її до нуля. Посилання на коментар Поділитися на інших сайтах More sharing options...
TaurosRMK Опубліковано: В понеділок в 12:11 Автор Поділитись Опубліковано: В понеділок в 12:11 2 години тому, volomoto сказав: Один з вентиляторів треба зафіксувати по пресету, а іншим вентилятором вже коригувати. Коригування треба робити з допомогою PID контроллера. На вхід контроллера подаєте різницю між потоками з додаванням константи для виконання умови приток > витяжка, і контроллер має звести її до нуля. Я й не думав тут про ПІД, бо напевно він не зможе вийти на уставку і тримати її. Все тому що показання датчиків потоку плавають, навіть без зміни швидкості вентилятора. Знизу графік обертів вентилятора, вони трималися на 1895-1905 об/хв, отой стрибок напевно якраз спрацював код який вище показано, швидкість збільшилася на 1 одиницю. Але по датчиках потоку (зверху) коливання були від 205 до 215 м3/год, і під час збільшення швидкості - до 225 м3/год. Інтервал оновлень датчиків потоку 60с. Тобто в один момент може бути так, что приток > витяжка, а вже через 60 сек потоки можуть бути рівні, або наоборот приток < витяжка. Тому не знаю як буде себе поводити ПІД, напевно буде сходити з розуму. Хоча якщо збільшити різницю приток-витяжка десь до 30 м3/год, то напевно має бути краще. Посилання на коментар Поділитися на інших сайтах More sharing options...
volomoto Опубліковано: В понеділок в 12:41 Поділитись Опубліковано: В понеділок в 12:41 21 хвилину тому, TaurosRMK сказав: Я й не думав тут про ПІД, бо напевно він не зможе вийти на уставку і тримати її. Якраз він і був створений для того, щоб вийти на уставку і тримати її, але якщо виконується умова, що максимальна частота зміни похибки є в два рази меншою, ніж смуга пропускання ПІД контроллера. ПІД – це фільтр нижніх частот, тому вихідний сигнал не може змінюватись швидше, ніж дані із сенсорів. У вас частота оновлення даних 60 с, а фізично швидкості потоків змінюються набагато швидше, тому в межах тих двох хвилин швидкості вентиляторів будуть плавати туди-сюди і у вас нема ніякого контролю над тим. Зробіть оновлення кожних 5 секунд, налаштуйте правильно коефіцієнти і тоді все буде правильно працювати. 1 Посилання на коментар Поділитися на інших сайтах More sharing options...
Рекомендовані повідомлення
Створіть акаунт або увійдіть у нього для коментування
Ви маєте бути користувачем, щоб залишити коментар
Створити акаунт
Зареєструйтеся для отримання акаунта. Це просто!
Зареєструвати акаунтУвійти
Вже зареєстровані? Увійдіть тут.
Увійти зараз