本文作者:烟火之旅

机房/库房环境采集:以太网温湿度变送器SNMP与TCP混合组网调试

烟火之旅 2026-09-26 2147

多协议传感设备调试:以太网温湿度变送器 SNMP、TCP 通讯实战

wKgZPGqzZT6Ac5xqACv8kCkabNM748.jpg

0

物联网 #Modbus #TCP/IP #UDP #SNMP #POE供电 #以太网温湿度传感器 #网口温湿度变送器 #工业现场 #环境监测 #Wireshark #Python

前面把 asyncio 高并发采集、多协议固件开发、EMC 电磁兼容、PoE 功率分配、双供电切换、Wireshark 排障、车间落地、现场测试全流程全部讲透了。这一篇聚焦一个非常实际的问题——

当你拿到一台多协议以太网温湿度变送器,SNMP 和 TCP(Modbus TCP)两种协议都要用,调试时该怎么下手。

0

先说一个现场真实场景:

甲方要求:温湿度数据走 Modbus TCP 进动环平台做实时采集和联动,同时要求 SNMP 接入 IT 运维的 Zabbix 做设备存活监控和端口状态查看。 设备到了,你配好 IP,Modbus Poll 一跑,数据正常。然后打开 Zabbix,SNMP 模板挂上去,发现——

读不到温度

。 你以为是 SNMP 社区名不对,改了 public、private、自定义,都不行。 你以为是 OID 不对,用 snmpwalk 手动跑,发现设备返回

Timeout: No Response from 192.168.100.50

。 你以为是防火墙拦了 UDP 161,关了防火墙还是不行。 最后发现:这台设备的 SNMP Agent

默认关闭

,需要在 Web 管理界面手动启用。而你之前根本不知道这台设备有 Web 管理界面——说明书 200 页,这一行藏在第 147 页的"高级功能"里。

一、先搞清楚:你的设备到底支持什么

1. 三种常见多协议模式

模式 说明 典型设备
双栈并行 SNMP Agent + Modbus TCP Server 同时运行,互不干扰 大多数中高端工业传感器
协议切换 同一端口号可通过配置切换为 SNMP 或 Modbus TCP(不同时运行) 部分低端设备
网关模式 设备本身是一个 SNMP Agent,但温湿度数据通过内部轮询 Modbus 从站获取 带多协议转换的工业网关

调试前必做

:登录设备 Web 界面(或串口配置工具),确认 SNMP 和 Modbus TCP 是否

同时启用

。很多设备默认只开 Modbus TCP,SNMP 需要手动开启。

2. 快速确认清单

□ 设备是否有 Web 管理界面?(浏览器访问 IP)
□ SNMP 功能是否默认开启?(查看 Web 界面或说明书)
□ SNMP 版本支持:v1 / v2c / v3?(多数设备只支持 v2c)
□ 社区名(Community):默认 public?还是自定义?
□ SNMP 端口:默认 161?是否可修改?
□ Modbus TCP 端口:默认 502?是否可修改?
□ 两种协议是否共享同一 IP 和端口?还是独立端口?
□ 设备是否有 MIB 文件?(.mib 或 .txt 格式)

复制

二、SNMP 调试实战

wKgZO2qzZUOALoyuAB-t1EJX_uw455.jpg

0

1. 从零开始的 SNMP 调试流程

第 1 步:确认 SNMP Agent 已启用
  → 浏览器登录设备 Web 界面
  → 找到 SNMP 配置页面
  → 确认 "Enable SNMP" 已勾选
  → 记录社区名、SNMP 版本、端口号

第 2 步:从命令行测试基础连通性
  → snmpwalk -v 2c -c public IP 1.3.6.1.2.1.1.1
  → 如果返回系统描述信息,说明 SNMP 基本正常

第 3 步:找到温湿度 OID
  → 用 snmpwalk 遍历整个 MIB 树
  → 或查阅设备 MIB 文件,找到温度/湿度对应的 OID

第 4 步:验证数据正确性
  → 对比 SNMP 读取值与 Modbus TCP 读取值
  → 确认缩放因子、数据类型一致

复制

2. 常用 SNMP 命令行工具

# 安装(Ubuntu/Debian)
apt install snmp snmp-mibs-downloader

# 基础查询
snmpget -v 2c -c public 192.168.100.50 1.3.6.1.2.1.1.1.0
# 返回:系统描述(设备型号、固件版本等)

# 遍历子树
snmpwalk -v 2c -c public 192.168.100.50 1.3.6.1.4.1

# 指定 MIB 文件
snmptranslate -Td -m ./device.mib TEMP-SENSOR-MIB::temperature

# 批量查询
for oid in 1.3.6.1.4.1.50001.1.1.1 1.3.6.1.4.1.50001.1.1.2; do
    snmpget -v 2c -c public 192.168.100.50 $oid
done

# 持续监控(每 5 秒查询一次)
while true; do
    snmpget -v 2c -c public 192.168.100.50 1.3.6.1.4.1.50001.1.1.1.0
    sleep 5
done

复制

3. Python SNMP 读取

from pysnmp.hlapi import *

def snmp_get(ip, community, oid):
    """SNMP GET 单个 OID"""
    iterator = getCmd(
        SnmpEngine(),
        CommunityData(community),
        UdpTransportTarget((ip, 161), timeout=2.0, retries=2),
        ContextData(),
        ObjectType(ObjectIdentity(oid))
    )
    
    errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
    
    if errorIndication:
        print(f"SNMP 错误: {errorIndication}")
        return None
    elif errorStatus:
        print(f"SNMP 状态错误: {errorStatus.prettyPrint()}")
        return None
    else:
        for varBind in varBinds:
            return varBind[1].prettyPrint()

# 示例:读取温度和湿度
ip = "192.168.100.50"
community = "public"

# 假设 OID(需根据实际 MIB 替换)
temp_oid = "1.3.6.1.4.1.50001.1.1.1.0"
humid_oid = "1.3.6.1.4.1.50001.1.1.2.0"

temp = snmp_get(ip, community, temp_oid)
humid = snmp_get(ip, community, humid_oid)

print(f"温度: {temp} ℃")
print(f"湿度: {humid} %RH")

复制

4. SNMP 常见问题排查

问题 现象 排查方法 解决
SNMP 未启用 snmpwalk 超时 登录 Web 界面检查 启用 SNMP Agent
社区名错误 No Such Name 或超时 尝试 public、private 确认设备配置的社区名
OID 不存在 No Such Instance snmpwalk 遍历整棵树 查阅 MIB 文件确认正确 OID
数据类型不匹配 读到的数值异常大 检查数据类型(INTEGER/Float) 按 MIB 定义解析
缩放因子不对 温度显示 224 而不是 22.4 检查 MIB 中的 DISPLAY-HINT 应用缩放因子 ×0.1
UDP 被防火墙拦截 超时 检查 iptables / 交换机 ACL 放行 UDP 161
设备 SNMP 栈崩溃 偶尔响应,偶尔超时 重启设备后恢复 升级固件或限制查询频率

三、TCP(Modbus TCP)调试实战

1. Modbus TCP 调试流程

第 1 步:确认 TCP 502 端口可达
  → nc -zv IP 502
  → 或 telnet IP 502

第 2 步:用 Modbus Poll 读取寄存器
  → 连接 → TCP/IP → 输入 IP、端口 502
  → 设置从站 ID、功能码 03、起始地址、数量
  → 观察数据

第 3 步:验证数据格式
  → 确认寄存器类型(INT16/UINT16/INT32/Float)
  → 确认字节序(ABCD/CDAB/BADC/DCBA)
  → 确认缩放因子(×0.1 / ×0.01 / 无)

第 4 步:Python 脚本批量验证
  → 用 pymodbus 读取,自动对比预期值

复制

2. Python Modbus TCP 读取

import asyncio
from pymodbus.client import AsyncModbusTcpClient

async def read_sensor(ip, port=502, slave_id=1):
    client = AsyncModbusTcpClient(ip, port=port, timeout=2.0)
    await client.connect()
    
    if not client.connected:
        print(f" {ip} 连接失败")
        return
    
    # 读取保持寄存器 0-3(温度、湿度、PM2.5、压差)
    resp = await client.read_holding_registers(0, count=4, slave=slave_id)
    
    if resp.isError():
        print(f" {ip} 读取失败: {resp}")
    else:
        temp = resp.registers[0] * 0.1
        humid = resp.registers[1] * 0.1
        pm25 = resp.registers[2]
        pressure = resp.registers[3]
        print(f" {ip}:")
        print(f"   温度: {temp} ℃")
        print(f"   湿度: {humid} %RH")
        print(f"   PM2.5: {pm25} μg/m³")
        print(f"   压差: {pressure} Pa")
    
    await client.close()

# 批量读取
async def batch_read(ips):
    for ip in ips:
        await read_sensor(ip)

ips = ["192.168.100.50", "192.168.100.51", "192.168.100.52"]
asyncio.run(batch_read(ips))

复制

3. Modbus TCP 常见问题排查

问题 现象 排查方法 解决
端口不可达 连接超时 nc -zv IP 502 检查设备是否启用 Modbus TCP
从站 ID 错误 返回非法功能码 尝试 ID 1、255、设备标签值 确认设备从站地址
地址偏移不对 读到 0 或乱码 尝试 0-based 和 1-based 确认组态软件地址模式
字节序不对 数值异常 读 UINT16 和 INT16 对比 调整字节顺序
缩放因子不对 数值偏大 10 倍 对比标准温湿度计 设置 ÷10 或 ×0.1
连接数满 偶尔连不上 检查已建立连接数 限制并发或重启设备
TCP Keepalive 未开 半开连接 Wireshark 抓包 开启 Keepalive

四、SNMP 与 Modbus TCP 数据对比验证

1. 为什么需要对比

场景 原因
甲方同时要求两种协议 动环用 Modbus,IT 运维用 SNMP
数据一致性验证 确认两种协议读到的数据一致
故障定位 如果 Modbus 读不到但 SNMP 能读到,说明 Modbus 配置有问题
验收测试 两种协议都要验证,确保功能完整

2. 对比脚本

import asyncio
from pymodbus.client import AsyncModbusTcpClient
from pysnmp.hlapi import *

async def compare_protocols(ip, snmp_community, modbus_port=502, slave_id=1):
    """对比 SNMP 和 Modbus TCP 读到的数据"""
    print(f"n{'='*50}")
    print(f"设备: {ip}")
    print(f"{'='*50}")
    
    # Modbus TCP 读取
    mb_client = AsyncModbusTcpClient(ip, port=modbus_port, timeout=2.0)
    await mb_client.connect()
    
    if mb_client.connected:
        mb_resp = await mb_client.read_holding_registers(0, count=2, slave=slave_id)
        if not mb_resp.isError():
            mb_temp = mb_resp.registers[0] * 0.1
            mb_humid = mb_resp.registers[1] * 0.1
            print(f"Modbus TCP: 温度={mb_temp}℃, 湿度={mb_humid}%RH")
        else:
            print("Modbus TCP: 读取失败")
            mb_temp, mb_humid = None, None
    else:
        print("Modbus TCP: 连接失败")
        mb_temp, mb_humid = None, None
    
    await mb_client.close()
    
    # SNMP 读取(同步方式,简化示例)
    # 实际使用时需要安装 pysnmp 并配置正确的 OID
    print("SNMP: 需要配置正确的 OID(参考设备 MIB 文件)")
    print("  请手动执行: snmpwalk -v 2c -c public IP 1.3.6.1.4.1")
    
    # 如果两种协议都成功,对比数据
    if mb_temp is not None:
        print(f"n数据对比提示:")
        print(f"  Modbus 温度: {mb_temp}℃")
        print(f"  SNMP 温度: 请手动对比")
        print(f"  偏差应 < 0.5℃(传感器自身精度)")

# 运行对比
ips = ["192.168.100.50"]
for ip in ips:
    asyncio.run(compare_protocols(ip, "public"))

复制

五、Zabbix 集成实战

1. Zabbix SNMP 模板配置

步骤 1:创建主机
  → 配置 → 主机 → 创建主机
  → 主机名称: Sensor-A01
  → 群组: Temperature Sensors
  → 接口: SNMP, IP 地址, 端口 161

步骤 2:配置 SNMP 社区
  → 宏 → 创建宏
  → 宏: {$SNMP_COMMUNITY}
  → 值: public

步骤 3:创建监控项
  → 监控项 → 创建监控项
  → 名称: 温度
  → 类型: SNMPv2 代理
  → 键值: sensor.temp
  → SNMP OID: 1.3.6.1.4.1.50001.1.1.1.0
  → 信息类型: 数字(浮点数)
  → 单位: ℃
  → 更新间隔: 30s

步骤 4:创建触发器
  → 触发器 → 创建触发器
  → 名称: 温度过高
  → 表达式: last(/Sensor-A01/sensor.temp) > 30
  → 严重性: 警告

步骤 5:创建图形
  → 图形 → 创建图形
  → 名称: 温湿度趋势
  → 添加监控项: 温度、湿度

复制

2. Zabbix Modbus TCP 配置

方法 1:使用 Zabbix 内置的 Modbus 监控项(Zabbix 5.0+)
  → 监控项类型: Modbus
  → 端点: tcp://192.168.100.50:502
  → 从站 ID: 1
  → 寄存器类型: Holding register
  → 寄存器地址: 0
  → 数据类型: INT16
  → 转换: ×0.1

方法 2:使用外部脚本(Zabbix agent + Python)
  → 编写 Python 脚本读取 Modbus TCP
  → Zabbix agent 调用脚本
  → 返回 JSON 格式数据

复制

六、Wireshark 同时抓 SNMP 和 Modbus TCP

1. 抓包过滤器

# 同时抓 SNMP(UDP 161)和 Modbus TCP(TCP 502)
tcp port 502 or udp port 161

复制

2. 显示过滤器

# SNMP 请求和响应
snmp

# Modbus TCP 请求和响应
modbus

# 同时看两种协议
tcp.port == 502 || udp.port == 161

# 按设备 IP 过滤
ip.addr == 192.168.100.50 && (tcp.port == 502 || udp.port == 161)

复制

3. 分析要点

协议 关注点
SNMP GET/GETNEXT 请求是否完整、响应是否超时、是否有 SNMPv3 认证失败
Modbus TCP MBAP 头 Transaction ID 是否递增、功能码是否正确、寄存器数据是否合理
时间线 两种协议的请求是否互相影响(TCP 重传是否阻塞 UDP)

七、常见返工点

问题 后果 正确做法
不确认 SNMP 是否启用 调试半天发现功能没开 先登录 Web 界面确认
不查 MIB 文件 用错 OID 向厂家索要 MIB 文件
社区名用默认 public 安全审计不通过 改为自定义社区名
SNMP 和 Modbus 数据不一致 验收时被质疑 对比验证,确认缩放因子一致
Zabbix 模板用错数据类型 图形显示异常 确认 SNMP 返回的数据类型
不测试并发 现场同时跑两种协议出问题 同时发起 SNMP GET 和 Modbus 读取
不保存 MIB 文件 后期维护找不到 OID 归档 MIB 文件到项目文档

八、一句话总结

SNMP 和 Modbus TCP 在同一台设备上并存,调试的核心不是"会不会用工具",而是

先搞清楚设备到底支持什么、默认开了什么、MIB 里定义了什么

。 SNMP 调试记住四步:确认启用 → 命令行测试 → 找对 OID → 验证数据。 Modbus TCP 调试记住四步:端口可达 → 寄存器能读 → 字节序正确 → 缩放因子匹配。 两种协议都调通之后,一定要做数据对比——一个物理量,两种协议读出来应该一致。不一致就说明哪里配错了,别等到验收时再发现。

审核编辑 黄宇