5a96a696b1
- 펌웨어(program), C# 대시보드(TestProgram), 시뮬레이터(Simulator), 프로토콜/문서(Protocol, doc) 전체를 단일 저장소로 통합 - program 폴더의 별도 git 저장소를 제거하고 통합 저장소에 흡수 - 빌드 산출물(program/build, bin/obj, *.o/.elf/.bin/.hex 등) .gitignore 처리 - 사내 Synology NAS Git 원격 연결 예정 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
221 lines
9.1 KiB
Markdown
221 lines
9.1 KiB
Markdown
# ErvCollector — ERV 24시간 수집/저장 + 원격 모니터링·제어 서버 (미니PC)
|
|
|
|
3개 현장의 EW11(TCP Client)이 보내는 ERV `0xAA STATUS` 프레임을 수신·파싱하여
|
|
**InfluxDB** 에 적재(장기 보관)하고, **내장 웹 대시보드 + HTTP API** 로 실시간 모니터링과 **원격 제어**를 제공한다.
|
|
|
|
```
|
|
[현장1 ERV]─RS485─[EW11]─WiFi/인터넷─┐ TCP 6001
|
|
[현장2 ERV]─RS485─[EW11]─WiFi/인터넷─┤ TCP 6002 → [미니PC] ErvCollector ┬ InfluxDB(보관) → Grafana(장기분석)
|
|
[현장3 ERV]─RS485─[EW11]─WiFi/인터넷─┘ TCP 6003 └ HTTP 8080 (웹 대시보드 + 제어 API)
|
|
```
|
|
|
|
**원격 제어 원리**: EW11 은 양방향 투명 브리지이므로, 현장 EW11 이 서버로 열어둔 **동일 TCP 소켓**으로
|
|
서버가 `CTRL_*` 프레임을 역방향 전송하면 EW11 → RS-485 → ERV 로 전달된다(추가 회선 불필요).
|
|
→ ERV 펌웨어(UART1)가 `CTRL_*` 수신 처리(PC_ERV_Protocol 2.1)를 구현해야 실제 동작한다.
|
|
|
|
- 프레임 규격: `../PC_ERV_Protocol.md`
|
|
- 현장 구분: **포트 분리**(6001/6002/6003 = site01/02/03), 펌웨어/프로토콜 변경 불필요.
|
|
|
|
---
|
|
|
|
## 1. 저장 정책 (결정 사항)
|
|
|
|
| 항목 | 값 |
|
|
|---|---|
|
|
| 저장 해상도 | **10초 주기 + 이산 상태 변화 시 즉시** |
|
|
| 보관 기간 | **1년** (InfluxDB 버킷 retention) |
|
|
| 스택 | **InfluxDB OSS 2.x + Grafana** |
|
|
|
|
- 연속값(PM2.5/PM10/VOC/CO2 등)은 10초 주기 샘플.
|
|
- 이산값(전원/운전모드/풍량/부가모드/후드/프리셋/에러코드 + 각실 댐퍼·공기질등급·LED)이 바뀌면 **즉시 1건** 추가 기록 → 변화 시점 누락 없음.
|
|
|
|
---
|
|
|
|
## 1.5 원격 모니터링·제어 (HTTP API)
|
|
|
|
서버는 `Http.Prefix`(기본 8080)에서 웹 대시보드와 API 를 제공한다.
|
|
|
|
| 메서드 | 경로 | 설명 |
|
|
|---|---|---|
|
|
| GET | `/` | 내장 웹 대시보드(`wwwroot/index.html`) — 3현장 모니터링 + 제어 |
|
|
| GET | `/api/latest` | 현장별 최신 상태 JSON(온라인 여부 + 글로벌 + 각실) |
|
|
| POST | `/api/control` | 제어. 헤더 `X-Auth-Token`(토큰 설정 시), 본문 JSON |
|
|
|
|
**제어 본문 예시**
|
|
```json
|
|
{ "site":"site01", "action":"power", "value":1 }
|
|
{ "site":"site01", "action":"runmode", "value":2 } // 1환기 2자동 3공청 4바이패스
|
|
{ "site":"site01", "action":"fan", "value":3 } // 0~4 (자동모드 무시)
|
|
{ "site":"site01", "action":"submode", "type":2, "value":1 }// type 1수면 2조리 3회복
|
|
{ "site":"site01", "action":"hood", "value":1 }
|
|
{ "site":"site01", "action":"preset", "value":2 } // 0 ECO 1 NORMAL 2 TURBO
|
|
{ "site":"site01", "action":"hyst", "pm25":30,"pm10":50,"voc":300,"co2":700 }
|
|
{ "site":"site01", "action":"damper", "room":2, "value":1 }// room 1거실 2~4침실
|
|
{ "site":"site01", "action":"led", "room":1, "value":7 }// 0~9
|
|
```
|
|
→ 서버가 해당 현장 EW11 소켓으로 `CTRL_*` 프레임 송신. 응답 `{"ok":true}` (연결 없으면 503).
|
|
|
|
> **보안**: 제어는 민감하므로 `Http.Token` 을 반드시 설정(대시보드 토큰칸/`X-Auth-Token`).
|
|
> 운영 시 HTTP 포트는 사내망/VPN 으로 제한하고 외부 직노출 금지 권장.
|
|
|
|
> **바인딩**: `Http.Prefix` — Linux 미니PC 는 `http://*:8080/`(전체 인터페이스),
|
|
> Windows 비관리자 테스트는 `http://localhost:8080/` 만 가능(`+`/`*` 는 관리자 또는 `netsh http add urlacl` 필요).
|
|
|
|
---
|
|
|
|
## 2. 데이터 스키마 (InfluxDB measurement)
|
|
|
|
**erv_global** (tag: `site`)
|
|
`power, run_mode, auto_state, fan_mode, sub_mode, hood, hyst_preset, hyst_pm25, hyst_pm10, hyst_voc, hyst_co2, error_code` (모두 정수)
|
|
|
|
**erv_room** (tag: `site`, `room`=1~4)
|
|
`damper, pm25, pm10, voc, co2, air_quality, led_dim, load_score, final_volume` (모두 정수)
|
|
|
|
> 코드값 의미(run_mode 1환기/2자동/…, air_quality 1매우나쁨~4좋음 등)는 Grafana **Value mappings** 로 라벨 표시.
|
|
|
|
---
|
|
|
|
## 3. 미니PC 설치 (Ubuntu 기준)
|
|
|
|
### 3.1 .NET 런타임
|
|
```bash
|
|
sudo apt-get update && sudo apt-get install -y dotnet-runtime-10.0 # 또는 dotnet-sdk-10.0
|
|
```
|
|
|
|
### 3.2 InfluxDB OSS 2.x
|
|
```bash
|
|
# 설치 (공식 저장소)
|
|
curl -s https://repos.influxdata.com/influxdata-archive_compat.key | sudo gpg --dearmor -o /usr/share/keyrings/influxdata.gpg
|
|
echo "deb [signed-by=/usr/share/keyrings/influxdata.gpg] https://repos.influxdata.com/debian stable main" | sudo tee /etc/apt/sources.list.d/influxdata.list
|
|
sudo apt-get update && sudo apt-get install -y influxdb2
|
|
sudo systemctl enable --now influxdb
|
|
|
|
# 초기 설정 (org=herv, bucket=erv, 보관 1년=8760h)
|
|
influx setup --org herv --bucket erv --retention 8760h --username admin --password '<PW>' --force
|
|
# 쓰기용 토큰 확인
|
|
influx auth list
|
|
```
|
|
→ 출력된 토큰을 `appsettings.json` 의 `Influx.Token` 에 기입.
|
|
|
|
### 3.3 Collector 빌드/실행
|
|
```bash
|
|
cd ErvCollector
|
|
dotnet publish -c Release -o /opt/erv-collector
|
|
# appsettings.json 의 Influx.Token / Sites 포트 확인 후
|
|
/opt/erv-collector/ErvCollector
|
|
```
|
|
|
|
### 3.4 systemd 등록 (24시간 자동 실행/재시작)
|
|
`/etc/systemd/system/erv-collector.service`
|
|
```ini
|
|
[Unit]
|
|
Description=ERV Collector
|
|
After=network.target influxdb.service
|
|
|
|
[Service]
|
|
WorkingDirectory=/opt/erv-collector
|
|
ExecStart=/opt/erv-collector/ErvCollector
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
```bash
|
|
sudo systemctl daemon-reload && sudo systemctl enable --now erv-collector
|
|
journalctl -u erv-collector -f # 로그 확인
|
|
```
|
|
|
|
### 3.5 Grafana
|
|
```bash
|
|
sudo apt-get install -y grafana && sudo systemctl enable --now grafana-server
|
|
# 브라우저 http://<미니PC>:3000 (admin/admin)
|
|
# Data source: InfluxDB → Query language Flux → URL http://127.0.0.1:8086 → org=herv, token, default bucket=erv
|
|
```
|
|
대시보드: site별 변수(`site`)로 현장 전환, room별 패널로 PM/CO2/VOC 추이 + 운전모드/에러 상태 표시.
|
|
|
|
---
|
|
|
|
## 4. EW11 설정 (현장 3대, IOTService 또는 웹)
|
|
|
|
| 항목 | 값 |
|
|
|---|---|
|
|
| Serial | 115200 / 8 / None / 1 |
|
|
| Protocol | **TCP Client** |
|
|
| Server Addr | 회사 서버 **공인 IP**(또는 DDNS 도메인) |
|
|
| Server Port | 현장1→6001, 현장2→6002, 현장3→6003 |
|
|
| Security | **AES**(16자 키, 서버와 동일) ※ EW11 TLS는 인증서 미검증이라 AES 병행 권장 |
|
|
| Keep Alive / Reconnect | 활성 |
|
|
| Buffer Size | ≥ 256 (STATUS 78B 여유) |
|
|
|
|
> 회사측: 라우터에서 6001~6003 → 미니PC로 **포트포워딩**. 가능하면 inbound 를 3현장 공인 IP로 제한.
|
|
|
|
---
|
|
|
|
## 5. 용량 메모
|
|
|
|
- 10초 주기 × 3현장 ≈ 연 ~950만 레코드(이벤트 추가분 포함). InfluxDB 압축 시 연 수백 MB~2GB 수준 → 미니PC SSD로 충분.
|
|
- 1년 retention 이면 자동으로 오래된 데이터 만료.
|
|
|
|
---
|
|
|
|
## 6.5 WSL2 로 임시 구축 (미니PC 구입 전 검증)
|
|
|
|
WSL2 는 실제 Linux VM 이라 위 **3장 Ubuntu 설치 절차(.NET / InfluxDB / Grafana)가 그대로** 동작한다.
|
|
검증/개발용으로 충분하다. 단 아래 2가지를 챙겨야 한다.
|
|
|
|
### (1) WSL 안에서 서비스 자동 실행 — systemd 활성화
|
|
`/etc/wsl.conf` (WSL 내부)
|
|
```ini
|
|
[boot]
|
|
systemd=true
|
|
```
|
|
→ Windows PowerShell 에서 `wsl --shutdown` 후 재시작하면 `systemctl` 로 influxdb/grafana/erv-collector 를 서비스로 띄울 수 있다.
|
|
|
|
### (2) 외부 EW11 이 WSL 서비스에 접속 — 네트워크 노출
|
|
WSL2 는 기본적으로 NAT 라 **LAN 의 EW11 이 WSL 내부 포트에 직접 못 붙는다**. 둘 중 하나로 해결:
|
|
|
|
**방법 A — Mirrored networking (Windows 11 22H2+, 권장)**
|
|
`%UserProfile%\.wslconfig` (Windows 측)
|
|
```ini
|
|
[wsl2]
|
|
networkingMode=mirrored
|
|
```
|
|
→ `wsl --shutdown` 후 재시작. WSL 이 호스트 IP 를 공유하므로 EW11 은 **Windows PC 의 LAN IP : 6001~6003** 으로 바로 접속.
|
|
|
|
**방법 B — portproxy (Windows 10 등)**
|
|
관리자 PowerShell:
|
|
```powershell
|
|
$wsl = (wsl hostname -I).Trim().Split(" ")[0] # WSL 내부 IP (재부팅 시 변동)
|
|
foreach ($p in 6001,6002,6003) {
|
|
netsh interface portproxy add v4tov4 listenport=$p listenaddress=0.0.0.0 connectport=$p connectaddress=$wsl
|
|
}
|
|
```
|
|
|
|
### (3) Windows 방화벽 인바운드 허용
|
|
```powershell
|
|
New-NetFirewallRule -DisplayName "ERV Collector" -Direction Inbound -Protocol TCP -LocalPort 6001-6003 -Action Allow
|
|
New-NetFirewallRule -DisplayName "Grafana" -Direction Inbound -Protocol TCP -LocalPort 3000 -Action Allow
|
|
```
|
|
|
|
> ⚠️ WSL/PC 는 **검증용**으로 권장. 24시간 양산 운영은 절전/재부팅/업데이트로 끊길 수 있어 전용 미니PC 가 안전하다.
|
|
> 또한 방법 B 의 WSL 내부 IP 는 재부팅마다 바뀌므로 방법 A(mirrored)가 편하다.
|
|
|
|
### (4) 순수 로컬 테스트라면
|
|
EW11 없이 같은 PC 에서 데모 프레임만 흘려볼 거면 네트워크 설정 불필요 — `127.0.0.1:6001` 로 바로 송신해 검증 가능(앞선 스모크 테스트 방식).
|
|
|
|
---
|
|
|
|
## 7. 구성 파일 (`appsettings.json`)
|
|
```json
|
|
{
|
|
"Influx": { "Url": "http://127.0.0.1:8086", "Org": "herv", "Bucket": "erv", "Token": "<TOKEN>" },
|
|
"SampleIntervalSeconds": 10,
|
|
"Sites": [
|
|
{ "Port": 6001, "Name": "site01" },
|
|
{ "Port": 6002, "Name": "site02" },
|
|
{ "Port": 6003, "Name": "site03" }
|
|
]
|
|
}
|
|
```
|