Files
obsidian-vault/family/how-to/nodered-ventilation.md
T

8.6 KiB
Raw Blame History

title, tags, updated, related
title tags updated related
Node-RED: вентиляция по CO₂
family
home
automation
nodered
ventilation
2026-09-14
family/plans/t610-home-automation
family/how-to/home-automation

🔄 ГДЕ ЖИВЁТ (обновлено 2026-09-14)

Flows перенесены на HP t610 (HA OS) — перенос выполнен 2026-09-14, см. family/plans/t610-home-automation §5-кватер-Г.

  • Файл: /addon_configs/a0d7b954_nodered/flows.json в аддоне a0d7b954_nodered (68 узлов, было 124 б пустых).
  • 🔴 Ключевая правка при переезде: узел server"addon": false"addon": true. На TrueNAS Node-RED был отдельным docker-контейнером и ходил в HA по адресу + long-lived token (токена в переносимых файлах нет вообще — не искать). На t610 он HA-аддон → в аддон-режиме Supervisor даёт доступ к HA без токена. Лог после правки: [server:Home Assistant] Connected to http://supervisor/core, ошибок 0.
  • Модуль: опция аддона npm_packages: ["node-red-contrib-home-assistant-websocket@0.80.3"].
  • Доступ: наружу НЕ выпущен (host_network: true глушит порт-маппинг; снимается только галочкой в UI) → через ingress HA: http://192.168.2.176/api/hassio_ingress/4vUcCxEpYJMbQ64z-kWPCvFadq8ayl4lzvzJPDUaZzE/. Домен nodered.mallexxx.duckdns.org не используется (отдаёт 401 от nginx HA).
  • Старый Node-RED на TrueNAS (/mnt/RED_2TB/docker/nodered/, порт 1880) пока жив как источник/откат.
  • ⚠️ Известное следствие: узел fan.fan_at2_1/2 (slave 10) в HA на t610 — unavailable (блок закомментирован в configuration.yaml), поэтому управление вентиляторами AT2 не работает. Также проверить наличие cover.intake_damper_* (в конфиге HA заслонки описаны как switch.*). Alex: задача по slave 10 не ставилась.

Node-RED flow для управления вентиляцией по данным CO₂ датчиков.

Структура

[room demand msgs]
      ↓
(1) Demand Aggregator
      ↓
(2) Intake Allocation
      ↓
(3) Discretization per damper
      ↓
(4) Intake Damper Outputs
      ↓
(5) Exhaust Arbitration
      ↓
(6) Exhaust Dampers
      ↓
(7) Exhaust Fans
      ↓
(8) Kitchen Hood

1. Demand Aggregator (stateful)

let demands = flow.get("room_demands") || {};
demands[msg.room] = msg.raw_demand;
flow.set("room_demands", demands);
msg.demands = demands;
return msg;

2. Intake Allocation

Комнаты с intake дамперами: bedroom, kids, living. Приоритеты: living = 1.2, остальные = 1.0.

const ROOMS = ["bedroom", "kids", "living"];
const PRIORITY = { bedroom: 1.0, kids: 1.0, living: 1.2 };
let weighted = {}, sum = 0;
for (let r of ROOMS) {
  let d = msg.demands[r] || 0;
  weighted[r] = d * (PRIORITY[r] || 1);
  sum += weighted[r];
}
if (sum === 0) return null;
let allocation = {};
for (let r of ROOMS) { allocation[r] = 100 * weighted[r] / sum; }
msg.intake_pct = allocation;
return msg;

3. Discretization

Bedroom/Kids (0 / 33 / 66 / 100):

function snap(x) {
  if (x < 10) return 0;
  if (x < 33) return 33;
  if (x < 66) return 66;
  return 100;
}
msg.payload = snap(msg.payload);
return msg;

Living (dual-damper):

let p = msg.payload;
let A = 0, B = 0;
if (p < 10) { A=0; B=0; }
else if (p < 30) { A=66; B=0; }
else if (p < 55) { A=66; B=66; }
else if (p < 80) { A=100; B=66; }
else { A=100; B=100; }
msg.damperA = A; msg.damperB = B;
return msg;

5. Exhaust Arbitration

let d = msg.demands;
msg.exhaust = {
  at2_1: Math.max(d.toilet || 0, d.shower || 0, d.kitchen || 0),
  at2_2: Math.max(d.bathroom || 0, d.office || 0)
};
return msg;

7. Fan Speed

function speed(d) {
  if (d < 5) return 30;
  if (d < 20) return 50;
  if (d < 40) return 70;
  return 100;
}
msg.payload = speed(msg.payload);
return msg;

8. Kitchen Hood (3-speed)

let d = msg.demands.kitchen || 0;
if (d < 10) msg.payload = 0;
else if (d < 30) msg.payload = 1;
else if (d < 60) msg.payload = 2;
else msg.payload = 3;
return msg;

Gate: current_state (manual override → block automation).

Все дамперы: rate-limit 1 msg / 3060 s.

Связанные заметки

Статус данных для автоматики (2026-09-14)

Все три комнаты (bedroom, kids, dining) публикуют данные в MQTT. Датчик столовой (slave 1) был сломан багом сборки кадров в modbus-bridge — починен 2026-09-14 (см. family/plans/t610-home-automation §5-кватер-З). До фикса автоматика вентиляции по CO₂ работала без данных столовой. ⚠️ fan.fan_at2_1/2 (slave 10) — unavailable (блок закомментирован в configuration.yaml) → исполнительный контур вентиляторов AT2 не работает. Задача по slave 10 Alex'ом не ставилась.

🔦 Ночной свет душевой 2 — пороги (правка 2026-09-15)

Сущности: датчик освещённости sensor.shower_2_presence_sensor_illuminance (радар присутствия Tuya ZY-M100-S_2 / TS0601, ieee 0xa4c138c4a94a6a31, устройство shower_2_presence_sensor); присутствие binary_sensor.shower_2_presence_sensor_presence; лампа switch.night_light_shower_2 (TS0001, ieee 0x84fd27fffed9e137) + хелпер light.night_light_shower_2 (switch_as_x, т.е. две сущности на одно реле).

Автоматизации (в HA по id): «Вкл. ночной свет душевая» 1771997851260, «Выкл. ночной свет душевая» 1771997918348.

Причина мигания: порог стоял 8 lx, а реальный рабочий диапазон датчика в душевой — 0…15 lx. Замеры 2026-09-14/15 показали метание 7 ↔ 12 (и 0↔5, 8↔13 в другие дни) — ровно вокруг 8. Отсюда дёрганье.

Поставлено (Alex: «ставь 6»): below: 6 (вкл) / above: 6 (выкл).

⚠️ Риск, о котором предупреждал: при 2 lx (текущее состояние, покой) выключение ждёт above: 6 и может не наступить → свет остаётся гореть. Гистерезис не сделан осознанно — по прямому указанию Alex. Если свет будет залипать — варианты: гистерезис вкл below 4 / выкл above 10, либо гасить ночной свет по факту включения основной лампы.

Питфолл (важно для будущих правок): REST GET/POST /api/config/automation/config/<id> отдаёт и принимает поля во множественном числе — triggers / conditions (в файле automations.yaml это trigger/condition). Правка по trigger/condition через API молча уходит в пустые пути, POST возвращает 200 {"result":"ok"}, но значения НЕ меняются. Всегда читать конфиг обратно и сверять значения.

Рабочий скрипт: ~/tmp-t610/fix_shower_light_threshold.sh (читает конфиг → правит только .below/.above == 8 → POST → читает обратно). Бэкап файла: ~/tmp-t610/automations/automations.yaml.bak-20260915-105455.