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

171 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 'Node-RED: вентиляция по CO₂'
tags:
- family
- home
- automation
- nodered
- ventilation
updated: '2026-09-14'
related:
- '[[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)
```js
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.
```js
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):
```js
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)**:
```js
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
```js
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
```js
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)
```js
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.
## Связанные заметки
- [[family/how-to/home-automation]] — общая автоматизация дома
- [[family/plans/t610-home-automation]] — миграция на t610, §5-кватер-Г (перенос flows) и §5-кватер-З (фикс датчика столовой)
- [[Modbus/RTU_Framing_Source_Analysis]] — канон сборки RTU-кадров (почему `dining` молчал и как починили)
## Статус данных для автоматики (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 — ПЕРЕНЕСЕНО
> **Этот раздел переехал в [[family/how-to/ha-automations]] §3.** Документ `nodered-ventilation` — только про вентиляцию по CO₂.
> Кратко: порог освещённости ночного света душевой был **8 lx** и лежал ровно в центре дребезга датчика (**7 ↔ 12**, рабочий диапазон 0…15 lx) → свет мигал. **Правка 2026-09-15 по решению Alex: `below: 6` / `above: 6`**, применена через REST API, подтверждена чтением обратно. Полный разбор, замеры, питфоллы API и остаточный риск — в [[family/how-to/ha-automations]].
**Сущности:** дублируются в [[family/how-to/ha-automations]] §2. Здесь не повторяем.
**Автоматизации:** `1771997851260` (вкл) / `1771997918348` (выкл) — разбор в [[family/how-to/ha-automations]] §3.
**❌ Причина мигания и ✅ правка:** см. блок выше. Замеры и обоснование — в [[family/how-to/ha-automations]] §3.
**🔴 ПИТФОЛЛ (нужен для любой правки автоматизаций):** REST `GET/POST /api/config/automation/config/<id>` использует **`triggers`/`conditions`** (мн. ч.; в файле — `trigger`/`condition`). Правка по единственному числу **молча уходит в пустые пути**: POST → `200 {"result":"ok"}`, значения НЕ меняются. **Всегда читать обратно.** Подробнее — [[family/how-to/ha-automations]] §5.
**Артефакты:** скрипт `~/tmp-t610/fix_shower_light_threshold.sh`; бэкап `~/tmp-t610/automations/automations.yaml.bak-20260915-105455`.
---