首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >大容量档案库房多节点温湿度传感器组网方案与网络拓扑选型实践

大容量档案库房多节点温湿度传感器组网方案与网络拓扑选型实践

原创
作者头像
盛世宏博小可
修改于 2026-09-28 13:46:20
修改于 2026-09-28 13:46:20
900
举报

# 大容量档案库房多节点温湿度传感器组网方案与网络拓扑选型实践

大容量档案库房跟普通机房、实验室完全不是一个量级。普通机房几百平米、几十个监测点;大容量档案库房动辄几千到上万平米,密集架一排排像迷宫,监测点轻松破千。更要命的是档案库房对温湿度的均匀性要求极高——库房内任意两点温差不能超过 ±2℃,湿度偏差不超过 ±5%RH,否则纸张老化速度会指数级上升。

这种规模下,组网方案选错了,不是"效果不好"的问题,而是"根本跑不起来"。

先说一个真实案例:

> 某省级档案馆新馆,建筑面积 12000㎡,分 4 个独立库房区,每个库房约 3000㎡。

> 设计标准:每 100㎡部署 4 台温湿度传感器(GB/T 27703-2011 要求),总计约 480 台。

> 加上走廊、过渡间、缓冲间,全馆共 512 台以太网温湿度传感器。

> 初始方案:全部接入一台核心 PoE 交换机,星形拓扑,/24 子网统一分配。

> 问题接踵而至:

> - 512 台设备集中到一台 48 口交换机,需要 11 台接入交换机堆叠,广播域巨大

> - ARP 表溢出(默认 2048 条,512 台传感器 + 其他设备轻松撑满)

> - 某库房施工期间网线短路,导致整台接入交换机 PoE 保护,该库房全部传感器离线

> - 网络风暴:一台传感器固件异常疯狂发广播包,整个 /24 子网瘫痪

> - 核心交换机 CPU 长期 60%+,网络延迟抖动严重

> 优化方案:改为分层分区树形拓扑 + VLAN 隔离

> - 全馆划分为 16 个区域,每区 32 台传感器,独立 /27 子网

> - 每区一台 8 口工业 PoE 交换机(接入层),上联到库房汇聚交换机

> - 4 个库房各一台 24 口汇聚交换机(L2+),再上联到核心

> - 每个区域 VLAN 隔离,广播域控制在 32 台以内

> - 汇聚层做 DHCP Snooping + 风暴控制

> 结果:单区域故障不影响其他区域,广播流量降低 97%,核心交换机 CPU 降到 8%,网络延迟 P99 < 5ms。

---

## 一、大容量档案库房的特点与挑战

### 1. 档案库房 vs 普通机房

| 维度 | 普通机房 | 大容量档案库房 |

|---|---|---|

| 面积 | 100-500㎡ | 3000-15000㎡ |

| 监测点数 | 20-200 个 | 500-2000 个 |

| 密集架布局 | 无密集架,机柜间距大 | 密集架排列密集,通道窄 |

| 温湿度均匀性 | ±3℃/±10%RH | ±2℃/±5%RH(国标要求) |

| 网络环境 | 标准桥架、机柜理线 | 金属密集架干扰、长距离布线 |

| 供电条件 | UPS 保障 | 部分区域无 UPS,市电直供 |

| 运维频率 | 7×24 有人值守 | 工作时间有人,夜间无人 |

| 安全等级 | 等保二级/三级 | 等保三级+档案专网隔离 |

### 2. 核心挑战

```

┌─────────────────────────────────────────────────────────────────────────┐

│ 大容量档案库房组网挑战 │

├─────────────────────────────────────────────────────────────────────────┤

│ │

│ 1. 规模挑战:节点数量大 │

│ ├── 500-2000 个监测节点 │

│ ├── 单一广播域无法承载(ARP 泛洪、广播风暴) │

│ ├── 单一子网 IP 地址规划困难 │

│ └── 集中式采集服务器性能瓶颈 │

│ │

│ 2. 物理环境挑战:金属密集架干扰 │

│ ├── 密集架为金属结构,对无线信号屏蔽严重 │

│ ├── 网线沿密集架敷设,易被挤压、磨损 │

│ ├── 密集架移动时可能拉扯网线 │

│ └── 库房内叉车/推车可能碰撞弱电桥架 │

│ │

│ 3. 电气环境挑战:供电不稳定 │

│ ├── 档案库房照明、除湿机、空调大功率设备频繁启停 │

│ ├── 电网波动大,PoE 交换机易受干扰 │

│ ├── 部分老旧库房无等电位连接,雷击感应电压高 │

│ └── 市电中断后无 UPS 续航(传感器依赖 PoE 交换机自带供电) │

│ │

│ 4. 管理挑战:分区管理需求 │

│ ├── 不同库房存放不同年代/级别档案,环境要求不同 │

│ ├── 权限隔离:A 库房管理员不能看 B 库房数据 │

│ ├── 告警分级:核心库房告警级别高于普通库房 │

│ └── 维护隔离:某区域检修不能影响其他区域 │

│ │

│ 5. 合规挑战:国标/行标要求 │

│ ├── GB/T 27703-2011《信息与文献 档案馆库房温湿度管理》 │

│ ├── DA/T 56-2014《档案库房温湿度监控规范》 │

│ ├── 数据保存期限 ≥ 30 年(等保合规) │

│ └── 审计追溯:任何温湿度越限必须可回溯 │

│ │

└─────────────────────────────────────────────────────────────────────────┘

```

---

## 二、网络拓扑选型

### 1. 三种拓扑方案对比

```

方案 A:扁平星形拓扑(不推荐)

═══════════════════════════════════════════════════════════════════════

[核心交换机]

│

├── [接入交换机 1] ─── 48 台传感器(库房 A 区 1)

├── [接入交换机 2] ─── 48 台传感器(库房 A 区 2)

├── ...

└── [接入交换机 11] ── 32 台传感器(库房 D 区 16)

优点:架构简单、部署快、成本低

缺点:

- 单一广播域,512 台设备 ARP 泛洪严重

- 任何一台接入交换机故障影响一个区域

- 核心交换机压力巨大

- 无故障隔离,一个端口异常可能影响全局

适用:<100 台传感器的小型库房

方案 B:分层树形拓扑(推荐)

═══════════════════════════════════════════════════════════════════════

[核心交换机(机房)]

│

├── [汇聚交换机 A](库房 A 配线间)

│ │

│ ├── [接入交换机 A-1] ─── 32 台传感器(A 区 1-4 排)

│ ├── [接入交换机 A-2] ─── 32 台传感器(A 区 5-8 排)

│ └── [接入交换机 A-3] ─── 32 台传感器(A 区 9-12 排)

│

├── [汇聚交换机 B](库房 B 配线间)

│ ├── [接入交换机 B-1] ─── 32 台

│ └── ...

├── [汇聚交换机 C](库房 C 配线间)

└── [汇聚交换机 D](库房 D 配线间)

优点:

- 分层清晰,每区独立广播域(32 台/VLAN)

- 故障隔离:接入层故障不影响汇聚层,汇聚层故障不影响其他库房

- 核心交换机压力小(只需处理 4 条上联链路)

- 扩展性好:新增库房只需加汇聚交换机

- 便于分区管理和权限隔离

缺点:设备数量多,成本较高

适用:200-2000 台传感器的大中型库房

方案 C:环形冗余拓扑(高可用场景)

═══════════════════════════════════════════════════════════════════════

[核心交换机]

│

├── [汇聚 A] ──── [汇聚 B] ──── [汇聚 C] ──── [汇聚 D]

│ │ │ │ │

│ └──────────────┴──────────────┴──────────────┘

│ (ERPS 环网,自愈 <50ms)

│

└── 每个汇聚下接接入交换机(同方案 B)

优点:链路冗余,单点光纤断裂不影响通信

缺点:配置复杂,需要支持 ERPS/RSTP 的交换机

适用:国家级档案馆、对可用性要求极高的场景

```

### 2. 推荐拓扑:分层树形 + VLAN 隔离

```

┌─────────────────────────────────────────────────────────────────────────────┐

│ 档案库房网络拓扑总览 │

│ │

│ ╔═══════════════════════════════════════════════════════════════════════╗ │

│ ║ 核心层(Core) ║ │

│ ║ ┌─────────────────────────────────────────────────────────────────┐ ║ │

│ ║ │ 核心交换机(L3,双电源冗余) │ ║ │

│ ║ │ VLAN 接口: │ ║ │

│ ║ │ VLAN 100: 10.20.30.1/24 管理网 │ ║ │

│ ║ │ VLAN 200: 172.16.0.1/20 传感器总网(细分见下) │ ║ │

│ ║ │ VLAN 300: 10.20.40.1/24 采集服务器网 │ ║ │

│ ║ │ VLAN 400: 10.20.50.1/24 存储/数据库网 │ ║ │

│ ║ │ 路由:静态路由 + OSPF(如果有多台核心) │ ║ │

│ ║ │ ACL:传感器子网之间禁止互访,仅允许访问采集服务器 │ ║ │

│ ║ └─────────────────────────────────────────────────────────────────┘ ║ │

│ ╚═══════════════════════════════════════════════════════════════════════╝ │

│ │ │

│ ┌──────────────┬──────────┼──────────┬──────────────┐ │

│ ▼ ▼ ▼ ▼ ▼ │

│ ╔═════════════╗ ╔═════════════╗ ╔═════════════╗ ╔═════════════╗ │

│ ║ 汇聚层 A ║ ║ 汇聚层 B ║ ║ 汇聚层 C ║ ║ 汇聚层 D ║ │

│ ║ (库房 A) ║ ║ (库房 B) ║ ║ (库房 C) ║ ║ (库房 D) ║ │

│ ║ 24口 L2+ ║ ║ 24口 L2+ ║ ║ 24口 L2+ ║ ║ 24口 L2+ ║ │

│ ║ PoE+ ║ ║ PoE+ ║ ║ PoE+ ║ ║ PoE+ ║ │

│ ║ VLAN 10-13 ║ ║ VLAN 14-17 ║ ║ VLAN 18-21 ║ ║ VLAN 22-25 ║ │

│ ╚══════╤══════╝ ╚══════╤══════╝ ╚══════╤══════╝ ╚══════╤══════╝ │

│ │ │ │ │ │

│ ┌────┼────┐ ┌────┼────┐ ┌────┼────┐ ┌────┼────┐ │

│ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │

│ ┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐ │

│ │接入││接入││接入││接入││接入││接入││接入││接入││接入││接入││接入│ │

│ │8口 ││8口 ││8口 ││8口 ││8口 ││8口 ││8口 ││8口 ││8口 ││8口 ││8口 │ │

│ │PoE ││PoE ││PoE ││PoE ││PoE ││PoE ││PoE ││PoE ││PoE ││PoE ││PoE │ │

│ └─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘└─┬──┘ │

│ │ │ │ │ │ │ │ │ │ │ │ │

│ [32台传感器] [32台] [32台] [32台] [32台] [32台] [32台] [32台] │

│ 每区 32 台,共 16 个区域,总计 512 台传感器 │

└─────────────────────────────────────────────────────────────────────────────┘

```

---

## 三、IP 地址与 VLAN 规划

### 1. VLAN 规划

```

VLAN 规划(按区域划分):

核心管理:

VLAN 100 → 管理网(交换机管理、IPMI、采集服务器) 10.20.30.0/24

VLAN 300 → 采集服务器网 10.20.40.0/24

VLAN 400 → 存储/数据库网 10.20.50.0/24

传感器网(按库房+区域划分):

库房 A(汇聚 A):

VLAN 10 → A 区 1-4 排 172.16.10.0/27 (32 台)

VLAN 11 → A 区 5-8 排 172.16.11.0/27 (32 台)

VLAN 12 → A 区 9-12 排 172.16.12.0/27 (32 台)

VLAN 13 → A 区 13-16 排 172.16.13.0/27 (32 台)

库房 B(汇聚 B):

VLAN 14 → B 区 1-4 排 172.16.14.0/27 (32 台)

VLAN 15 → B 区 5-8 排 172.16.15.0/27 (32 台)

VLAN 16 → B 区 9-12 排 172.16.16.0/27 (32 台)

VLAN 17 → B 区 13-16 排 172.16.17.0/27 (32 台)

库房 C(汇聚 C):

VLAN 18-21 → 同上结构 172.16.18.0/27 ~ 172.16.21.0/27

库房 D(汇聚 D):

VLAN 22-25 → 同上结构 172.16.22.0/27 ~ 172.16.25.0/27

总计:16 个 VLAN,每个 /27 子网容纳 30 台可用地址(32 - 网络地址 - 网关)

实际每台传感器固定 IP,DHCP 保留地址分配

```

### 2. IP 地址分配

```

IP 分配规则(以 A 区 1-4 排为例,VLAN 10,172.16.10.0/27):

172.16.10.0 → 网络地址

172.16.10.1 → 网关(接入交换机 VLAN 接口)

172.16.10.2-31 → 传感器地址(30 个可用)

传感器 IP 编码规则:

172.16.{VLAN ID}.{排号}{架号}

例:A 区第 3 排第 6 列密集架 → 172.16.10.306

解析:VLAN 10 = A 区 1-4 排,排号 3,架号 06

管理 IP(交换机):

汇聚 A:10.20.30.10

接入 A-1:10.20.30.11

接入 A-2:10.20.30.12

接入 A-3:10.20.30.13

接入 A-4:10.20.30.14

```

---

## 四、交换机选型与配置

### 1. 交换机选型

| 层级 | 型号推荐 | 关键参数 | 数量 |

|---|---|---|---|

| 核心 | 华为 S5735-S24P4X(或同档) | 24×PoE+ 4×SFP+,L3 路由,双电源 | 1-2(冗余) |

| 汇聚 | 华为 S5735-S24P4X 或 TP-Link TL-SG2428P | 24×PoE+,L2+,支持 VLAN/STP | 4 |

| 接入 | 华为 S1730S-S8P4S(或同档工业级) | 8×PoE 4×SFP,DIN 导轨,宽温 -40~75℃ | 16 |

```

选型要点:

1. PoE 预算:每台接入交换机 8 口满载(8×15W = 120W),选 150W 以上 PoE 预算

2. 温度范围:档案库房温度可能低至 14℃,交换机需支持 0℃ 启动(工业级 -40℃ 更好)

3. 端口密度:接入层 8 口刚好覆盖 32 台(4 台交换机 × 8 口 = 32)

4. 上联端口:接入交换机需要 SFP 上联到汇聚(光纤,抗干扰)

5. 管理功能:支持 SNMP v3、LLDP、端口镜像(排障用)

```

### 2. 接入交换机配置示例(华为)

```

system-view

sysname Access-A1

# 创建 VLAN

vlan batch 10

# 配置上联端口(SFP 光纤)

interface GigabitEthernet0/0/9

port link-type trunk

port trunk allow-pass vlan 10

description Uplink-to-Aggregation-A

# 配置下联端口(连接传感器)

interface range GigabitEthernet0/0/1 to GigabitEthernet0/0/8

port link-type access

port default vlan 10

poe enable

poe priority high

storm-control broadcast min-packets 50 max-packets 100 interval 60

loopback-detect enable

description Sensor-Port

# 配置管理 IP

interface Vlanif1

ip address 10.20.30.11 255.255.255.0

# 默认路由

ip route-static 0.0.0.0 0.0.0.0 10.20.30.1

# SNMP 配置

snmp-agent

snmp-agent sys-info version v3

snmp-agent group v3 monitor-group privacy read-view all

snmp-agent usm-user v3 monitor monitor-group

snmp-agent trap enable

snmp-agent target-host trap address udp-domain 10.20.40.100 params securityname monitor v3 privacy

# 端口安全(防止私接)

interface range GigabitEthernet0/0/1 to GigabitEthernet0/0/8

port-security enable

port-security max-mac-num 2

port-security protect-action restrict

# 保存

save

```

### 3. 汇聚交换机配置示例

```

system-view

sysname Aggregate-A

# 创建 VLAN

vlan batch 10 11 12 13 100

# 下联接入交换机(trunk)

interface range GigabitEthernet0/0/1 to GigabitEthernet0/0/4

port link-type trunk

port trunk allow-pass vlan 10 11 12 13

description Downlink-to-Access

# 上联核心(trunk)

interface GigabitEthernet0/0/25

port link-type trunk

port trunk allow-pass vlan 10 11 12 13 100

description Uplink-to-Core

# VLAN 接口(网关)

interface Vlanif10

ip address 172.16.10.1 255.255.255.224

interface Vlanif11

ip address 172.16.11.1 255.255.255.224

interface Vlanif12

ip address 172.16.12.1 255.255.255.224

interface Vlanif13

ip address 172.16.13.1 255.255.255.224

# DHCP(为传感器分配固定 IP)

dhcp enable

ip pool sensor-a1

gateway-list 172.16.10.1

network 172.16.10.0 mask 255.255.255.224

static-bind ip-address 172.16.10.2 mac-address xxxx-xxxx-xxx1

static-bind ip-address 172.16.10.3 mac-address xxxx-xxxx-xxx2

# ... 为每台传感器绑定 MAC-IP

# 管理 IP

interface Vlanif100

ip address 10.20.30.10 255.255.255.0

# STP(防止环路)

stp mode rstp

stp priority 4096

# 风暴控制

storm-control broadcast level 10

storm-control multicast level 20

save

```

---

## 五、传感器部署策略

### 1. 密集架区域部署

```

密集架排列示意(单区 4 排 × 8 列 = 32 个监测点):

通道 1 通道 2 通道 3 通道 4 通道 5

┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐

│ │←D→│ │←D→│ │←D→│ │←D→│ │←D→│ │

│ 1│ │ 2│ │ 3│ │ 4│ │ 5│ │ 6│ │ 7│ │ 8│

│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │

└──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘

↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑

传感器 传感器 传感器 传感器 传感器 传感器 传感器 传感器

(每通道两端各 1 台 = 每排 2 台 × 4 排 = 8 台)

(4 列密集架 × 每列 6 层 = 24 台,安装在不同高度层)

总计:8 + 24 = 32 台/区

```

### 2. 安装要点

```

安装规范:

1. 高度:距离地面 1.5m(人体呼吸带)和 3.0m(密集架顶部),上下两层各一台

2. 避开:远离空调出风口(≥2m)、除湿机排水口、阳光直射

3. 朝向:传感器探头朝向通道,不朝向密集架金属面

4. 固定:使用不锈钢支架,不破坏密集架结构

5. 布线:

- 网线穿金属软管,沿密集架顶部桥架敷设

- 密集架移动区域预留 20% 余量(防止拉扯)

- 接头处使用防水 RJ45 接头(库房湿度可能 >80%)

6. 标识:每台传感器贴二维码标签(IP、位置、安装日期)

```

---

## 六、采集服务器部署

### 1. 分区采集架构

```

┌─────────────────────────────────────────────────────────────────────────┐

│ 采集服务器部署架构 │

│ │

│ ┌─────────────────────────────────────────────────────────────────────┐│

│ │ 中心采集服务器(10.20.40.100) ││

│ │ ┌───────────────────────────────────────────────────────────────┐ ││

│ │ │ MQTT Broker(EMQX) │ ││

│ │ │ 接收所有区域前置机的数据 │ ││

│ │ └───────────────────────────────────────────────────────────────┘ ││

│ │ ┌───────────────────────────────────────────────────────────────┐ ││

│ │ │ InfluxDB(时序数据库) │ ││

│ │ │ 存储所有传感器历史数据,保留策略:热数据 90 天,冷数据 30 年 │ ││

│ │ └───────────────────────────────────────────────────────────────┘ ││

│ │ ┌───────────────────────────────────────────────────────────────┐ ││

│ │ │ 告警引擎 │ ││

│ │ │ 实时分析数据,触发越限告警、离线告警、PoE 异常告警 │ ││

│ │ └───────────────────────────────────────────────────────────────┘ ││

│ │ ┌───────────────────────────────────────────────────────────────┐ ││

│ │ │ Web 可视化(Grafana + 定制前端) │ ││

│ │ │ 三维库房热力图、趋势分析、合规报表 │ ││

│ │ └───────────────────────────────────────────────────────────────┘ ││

│ └─────────────────────────────────────────────────────────────────────┘│

│ ▲ │

│ │ MQTT/HTTP │

│ ┌───────────────────────┼───────────────────────┐ │

│ ▼ ▼ ▼ │

│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │

│ │ 前置机 A │ │ 前置机 B │ │ 前置机 C │ ... │

│ │ 库房 A │ │ 库房 B │ │ 库房 C │ │

│ │ 本地采集 │ │ 本地采集 │ │ 本地采集 │ │

│ │ 128 台 │ │ 128 台 │ │ 128 台 │ │

│ └──────────┘ └──────────┘ └──────────┘ │

└─────────────────────────────────────────────────────────────────────────┘

```

### 2. 前置采集机代码(分区采集)

```python

import asyncio

import struct

import time

import json

from typing import Dict, List, Optional

from dataclasses import dataclass

from datetime import datetime

import logging

import paho.mqtt.client as mqtt

from influxdb_client import InfluxDBClient, Point

from influxdb_client.client.write_api import SYNCHRONOUS

logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')

logger = logging.getLogger(__name__)

@dataclass

class SensorNode:

"""传感器节点"""

ip: str

name: str

location: str # 库房-排-列-层

vlan_id: int

cabinet_row: int

cabinet_col: int

shelf_level: int

class ZoneCollector:

"""区域采集器(负责一个库房的所有传感器)"""

def __init__(self, zone_id: str, sensors: List[SensorNode],

mqtt_config: Dict, influx_config: Dict,

poll_interval: int = 15):

self.zone_id = zone_id

self.sensors = sensors

self.mqtt_config = mqtt_config

self.influx_config = influx_config

self.poll_interval = poll_interval

self.running = False

self.readings = {}

self.stats = {

'total': 0, 'success': 0, 'fail': 0,

'last_poll': 0, 'avg_latency_ms': 0

}

# InfluxDB 客户端

self.influx_client = InfluxDBClient(

url=influx_config['url'],

token=influx_config['token'],

org=influx_config['org']

)

self.write_api = self.influx_client.write_api(write_options=SYNCHRONOUS)

# MQTT 客户端(用于发布告警)

self.mqtt_client = mqtt.Client(client_id=f"zone_{zone_id}")

self.mqtt_client.on_connect = self._on_mqtt_connect

def _on_mqtt_connect(self, client, userdata, flags, rc):

if rc == 0:

logger.info(f"[{self.zone_id}] MQTT connected")

async def start(self):

self.running = True

# 连接 MQTT

self.mqtt_client.connect(

self.mqtt_config['host'],

self.mqtt_config.get('port', 1883),

keepalive=60

)

self.mqtt_client.loop_start()

# 启动采集循环

asyncio.create_task(self._collect_loop())

# 启动上报循环

asyncio.create_task(self._report_loop())

logger.info(f"[{self.zone_id}] Zone collector started, {len(self.sensors)} sensors")

async def _collect_loop(self):

"""采集循环"""

while self.running:

start = time.time()

# 按 VLAN 分组,每组并发采集

vlan_groups = {}

for s in self.sensors:

vlan_groups.setdefault(s.vlan_id, []).append(s)

for vlan_id, group in vlan_groups.items():

# 每组最多 8 个并发(对应一台接入交换机)

for i in range(0, len(group), 8):

batch = group[i:i+8]

tasks = [self._read_sensor(s) for s in batch]

await asyncio.gather(*tasks, return_exceptions=True)

self.stats['last_poll'] = time.time()

elapsed_ms = (time.time() - start) * 1000

self.stats['avg_latency_ms'] = elapsed_ms / max(1, len(self.sensors))

# 等待下一个周期

sleep_time = max(0, self.poll_interval - elapsed_ms / 1000)

if sleep_time > 0:

await asyncio.sleep(sleep_time)

async def _read_sensor(self, sensor: SensorNode) -> Optional[Dict]:

"""读取单台传感器"""

try:

self.stats['total'] += 1

t0 = time.time()

reader, writer = await asyncio.wait_for(

asyncio.open_connection(sensor.ip, 502),

timeout=3.0

)

# Modbus TCP 读保持寄存器 0-1

tid = int(t0 * 1000) % 65535

req = struct.pack('>HHHHBHH', tid, 0, 6, 1, 0x03, 0, 2)

writer.write(req)

await writer.drain()

resp = await asyncio.wait_for(reader.read(256), timeout=2.0)

writer.close()

await writer.wait_closed()

if len(resp) < 11:

raise ValueError("Response too short")

_, _, _, _, _, bc = struct.unpack('>HHHBBB', resp[:9])

if bc != 4:

raise ValueError(f"Bad byte count: {bc}")

temp_raw, hum_raw = struct.unpack('>hh', resp[9:13])

temp = temp_raw * 0.1

hum = hum_raw * 0.1

if not (14 <= temp <= 35 and 30 <= hum <= 80):

raise ValueError(f"Out of archive range: T={temp} H={hum}")

reading = {

'ip': sensor.ip,

'name': sensor.name,

'location': sensor.location,

'temperature': temp,

'humidity': hum,

'vlan_id': sensor.vlan_id,

'latency_ms': (time.time() - t0) * 1000,

'timestamp': t0

}

self.readings[sensor.ip] = reading

self.stats['success'] += 1

# 写入 InfluxDB

self._write_influx(reading)

# 检查告警

self._check_alarm(reading)

return reading

except Exception as e:

self.stats['fail'] += 1

logger.warning(f"[{self.zone_id}] {sensor.ip} read failed: {e}")

return None

def _write_influx(self, reading: Dict):

"""写入时序数据库"""

try:

point = Point("archive_temp_hum") \

.tag("zone", self.zone_id) \

.tag("location", reading['location']) \

.tag("vlan", str(reading['vlan_id'])) \

.field("temperature", reading['temperature']) \

.field("humidity", reading['humidity']) \

.field("latency_ms", reading['latency_ms']) \

.time(datetime.fromtimestamp(reading['timestamp']))

self.write_api.write(

bucket=self.influx_config['bucket'],

org=self.influx_config['org'],

record=point

)

except Exception as e:

logger.error(f"[{self.zone_id}] InfluxDB write error: {e}")

def _check_alarm(self, reading: Dict):

"""检查告警条件"""

temp = reading['temperature']

hum = reading['humidity']

alarms = []

# 国标要求:温度 14-24℃,湿度 45-60%(纸质档案)

if temp > 24:

alarms.append(('TEMPERATURE_HIGH', f"温度偏高: {temp}℃", 'WARNING'))

elif temp < 14:

alarms.append(('TEMPERATURE_LOW', f"温度偏低: {temp}℃", 'WARNING'))

if hum > 60:

alarms.append(('HUMIDITY_HIGH', f"湿度偏高: {hum}%RH", 'WARNING'))

elif hum < 45:

alarms.append(('HUMIDITY_LOW', f"湿度偏低: {hum}%RH", 'WARNING'))

# 紧急告警(超出允许范围更多)

if temp > 28 or temp < 10:

alarms.append(('TEMPERATURE_CRITICAL', f"温度紧急: {temp}℃", 'CRITICAL'))

if hum > 70 or hum < 35:

alarms.append(('HUMIDITY_CRITICAL', f"湿度紧急: {hum}%RH", 'CRITICAL'))

for alarm_type, message, severity in alarms:

payload = json.dumps({

'zone': self.zone_id,

'location': reading['location'],

'type': alarm_type,

'message': message,

'severity': severity,

'value': {'temperature': temp, 'humidity': hum},

'timestamp': reading['timestamp']

})

topic = f"archive/alarm/{self.zone_id}"

self.mqtt_client.publish(topic, payload, qos=1)

async def _report_loop(self):

"""定期上报统计信息"""

while self.running:

await asyncio.sleep(60)

success_rate = self.stats['success'] / max(1, self.stats['total']) * 100

logger.info(

f"[{self.zone_id}] Stats: "

f"Total={self.stats['total']} "

f"Success={success_rate:.1f}% "

f"AvgLatency={self.stats['avg_latency_ms']:.0f}ms"

)

def stop(self):

self.running = False

self.mqtt_client.loop_stop()

self.influx_client.close()

# 主程序

async def main():

mqtt_config = {'host': '10.20.40.100', 'port': 1883}

influx_config = {

'url': 'http://10.20.40.100:8086',

'token': 'archive-token-xxx',

'org': 'archive',

'bucket': 'archive_env'

}

# 模拟 512 台传感器配置

sensors = []

for zone in range(4): # 4 个库房

for area in range(4): # 每库房 4 个区

vlan = 10 + zone * 4 + area

for i in range(32): # 每区 32 台

sensors.append(SensorNode(

ip=f"172.16.{vlan}.{i+2}",

name=f"Sensor-Z{zone}-A{area}-{i+1}",

location=f"库房{zone+1}-区{area+1}-排{i//8+1}-列{(i%8)+1}",

vlan_id=vlan,

cabinet_row=i // 8 + 1,

cabinet_col=(i % 8) + 1,

shelf_level=1 if i < 16 else 3

))

# 按库房分组启动采集器

zones = {}

for s in sensors:

zone_id = f"zone_{s.location.split('-')[0]}"

zones.setdefault(zone_id, []).append(s)

collectors = []

for zone_id, zone_sensors in zones.items():

c = ZoneCollector(zone_id, zone_sensors, mqtt_config, influx_config)

await c.start()

collectors.append(c)

try:

while True:

await asyncio.sleep(1)

except KeyboardInterrupt:

for c in collectors:

c.stop()

if __name__ == "__main__":

asyncio.run(main())

```

---

## 七、常见问题与排查

| 问题 | 原因 | 解决方案 |

|---|---|---|

| 传感器频繁离线 | 密集架移动拉扯网线 | 使用拖链电缆,预留余量 |

| 数据跳变 | 密集架金属面反射干扰 | 传感器远离金属面 ≥30cm |

| PoE 供电不稳定 | 库房湿度高导致端口腐蚀 | 使用工业级防水接头 |

| 网络延迟大 | 跨 VLAN 路由瓶颈 | 确保汇聚层 L3 路由性能 |

| 广播风暴 | 某传感器异常发包 | 启用端口广播风暴控制 |

| IP 冲突 | 手动配置错误 | DHCP 静态绑定 + IP 扫描 |

| 数据丢失 | 采集服务器单点故障 | 部署主备采集服务器 |

| 历史数据查询慢 | 数据量太大 | InfluxDB 降采样 + 冷热分离 |

---

## 八、验收标准

| 项目 | 标准 | 测试方法 |

|---|---|---|

| 网络连通性 | 所有传感器 ping 通 | 批量 ping 测试 |

| 采集覆盖率 | 100% 在线 | 统计在线设备 |

| 数据到达率 | ≥99.9%(24h) | 对比传感器本地与中心数据 |

| 采集延迟 | P99 < 15s | 记录采集时间戳 |

| 网络分区 | 各 VLAN 隔离 | 跨 VLAN ping 测试应不通 |

| 故障隔离 | 单区故障不影响其他区 | 断开某接入交换机上联 |

| PoE 稳定性 | 48h 无异常断电 | 持续监测 PoE 端口状态 |

| 告警响应 | <30s | 模拟越限 |

| 数据完整性 | 30 年可查 | 验证 InfluxDB 数据保留策略 |

---

## 九、一句话总结

> 大容量档案库房多节点组网的核心原则:"分而治之,层层隔离"。

> 不要试图用一个大二层网络承载上千台传感器——那一定会出问题。

> 按物理区域划 VLAN、按层级选设备、按分区部署采集器,

> 让每个广播域控制在 30 台以内,让每个故障域不超过一个库房。

> 网络拓扑选对了,后面的数据质量、告警准确性、运维效率才有保障。

---

关键词:大容量档案库房、多节点温湿度传感器、组网方案、网络拓扑选型、分层树形拓扑、VLAN隔离、PoE供电、密集架部署、分区采集、InfluxDB、ModbusTCP、故障隔离、广播域控制、GB/T27703、档案库房环境监控

标签:#大容量档案库房 #多节点组网 #温湿度传感器 #网络拓扑 #VLAN隔离 #PoE供电 #分层树形拓扑 #密集架 #分区采集 #InfluxDB #ModbusTCP #故障隔离 #档案环境监控 #GB/T27703

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档