[2026-05-17] sort: move songs/poems/toasts to separate files per item, clean songs.md
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
---
|
||||
title: 'Node-RED: вентиляция по CO₂'
|
||||
tags:
|
||||
- family
|
||||
- home
|
||||
- automation
|
||||
- nodered
|
||||
- ventilation
|
||||
updated: '2026-05-17'
|
||||
---
|
||||
|
||||
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 / 30–60 s.
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
- [[family/how-to/home-automation]] — общая автоматизация дома
|
||||
Reference in New Issue
Block a user