前言
最近有一个项目中需要使用SNMP协议的get命令读取远程智慧站房的站房温度、湿度等实时数据,并且可以通过set命令对空调进行开和关的控制。
网络走的是VPN,知道远程主机的IP地址和community口令,以及对应每个设备的OID,就比较容易获取对应设备的实时数据,以及对空调进行开关控制了。
SNMP协议
概述: SNMP 支持 V1 、V2、V3协议,get,getnext 和 set 三种操作,由于设备所接的监控设备 丌同,扩展的模块多少和类型丌同,对应的监测量丌是固定的,所以设备没有固定的 MIB 库,监测量不 OID 对应的原则如内容所示。可以采用 getnext 遍历整个设备 MIB。对于监 测量的描述信息,采用 OCTET STRING,编码方式为 gb2312,对于开关量(输入和输 出),采用 INTEGER 类型,只有 0 和 1 两个值,对于模拟量(输入和输出),采用 OCTET STRING 表示,默认保留小数点后 4 位小数,对于枚举量,采用 INTEGER 表示,门禁等 信息 OCTET STRING 表示,表示方式遵循设备相应协议。
实时数据和监测点描述信息对应的 OID 结构描述如下图:
监测类型对应关系如下图所示:
空调的相关控制命令:
首先可以使用net-snmp等工具获取相关的oid信息,我使用的是Snmputilg.exe这个工具获取对应的站房温度、站房湿度、空调红外传感器1、空调红外传感器2的描述oid以及对应的值。对于空调控制来说,需要现场运维人员进行相应的学习:比如说自动模式、关灯指令,具体描述见上面的SNMP文档协议。
nodejs使用net-snmp库实现远程读取温湿度等环境实时数据,控制空调
关于nodejs中snmp库的选择,目前www.npmjs.com/search?q=sn…中比较流行的有如下两个nodejs库:
- net-snmp This module implements versions 1, 2c and 3 of the Simple Network Management Protocol (SNMP).
- snmp-node This is a native SNMP library for Node.js. The purpose is to provide enough functionality to perform large scale monitoring of network equipment. Current features towards this end are:
- Full implementation of SNMPv2c, including 64 bit data types.
- Support for Get, GetNext and Set requests, with optimizations such as GetAll and GetSubtree.
- No unusual external dependencies, no non-JavaScript code.
- Very high performance, unlimited parallellism. (There are always limits. However, there are no arbitrary such imposed by this code and you at least won't run out of file descriptors.)
- De facto standards compliance. Generated packets are compared against Net-SNMP and should be identical in all relevant aspects.
- Well tested. Test coverage should be at or close to 100% for all important code paths.
我使用的是
net-snmp这个Nodejs库。
使用nodejs和net-snmp的js代码如下:
var snmp = require ("net-snmp");
var moment = require('moment');
const nodemon = require("nodemon");
var session = snmp.createSession ("15.129.13.267", "public");
// 15.129.13.267 靖屏大道站 学习了“开”和“关”两个指令
// 温湿度模块1 模拟量输入(AI1) 站房温度 27.40 无告警 连接正常
// 温湿度模块1 模拟量输入(AI2) 站房湿度 46.40 无告警 连接正常
// 站房温度
// 监测点配置(类型:模拟量输入AI,地址:1,索引:1)
// 1.3.6.1.4.1.50688.2.4.1.1.0
// 站房湿度
// 监测点配置(类型:模拟量输入AI,地址:1,索引:2)
// 1.3.6.1.4.1.50688.2.4.1.2.0
// 命令=GET: OID=1.3.6.1.4.1.50688.2.4.1.2.0; 值=5110
var items = [
{name: '站房温度', oid: '1.3.6.1.4.1.50688.2.4.1.1.0'},
{name: '站房湿度', oid: '1.3.6.1.4.1.50688.2.4.1.2.0'},
{name: '空调控制指令1', oid: '1.3.6.1.4.1.50688.2.9.256.1.0'},
{name: '空调控制指令2', oid: '1.3.6.1.4.1.50688.2.9.256.2.0'}
];
// snmpset 控制空调
// 控制空调之前,需要现场学习对应的指令,目前空调控制器有两个红外探头,有两个通道
// 开空调
// 自动模式 00 自动模式、风速-自动、上下扫风、左右扫风
function openAirCondition() {
this.set('1.3.6.1.4.1.50688.2.9.256.1.0', 0);
}
// 关空调
// 关机 63 可以再任何模式下学习
function closeAirCondition() {
this.set('1.3.6.1.4.1.50688.2.9.256.1.0', 63);
}
function set(strOid, iVal) {
var varbinds = [
{
oid: strOid,
type: netsnmp.ObjectType.Integer,
value: iVal
}
];
this.sessionObj.set (varbinds, function (error, varbinds) {
if (error) {
console.error (error.toString ());
} else {
// for version 1 we can assume all OIDs were successful
console.log (varbinds.oid + "|" + varbinds.value);
// for version 2c we must check each OID for an error condition
if (netsnmp.isVarbindError (varbinds))
console.error (netsnmp.varbindError (varbinds));
else
console.log (varbinds.oid + "|" + varbinds.value);
}
});
}
// 获取数据
function getData() {
var oids = [];
items.forEach((val, index) => {
oids.push(val.oid);
});
session.get (oids, function (error, varbinds) {
if (error) {
console.error (error);
} else {
for (var i = 0; i < varbinds.length; i++)
if (snmp.isVarbindError (varbinds[i]))
console.error (snmp.varbindError (varbinds[i]))
else
console.log (varbinds[i].oid + " = " + varbinds[i].value);
}
//session.close ();
});
}
session.trap (snmp.TrapType.LinkDown, function (error) {
if (error)
console.error (error);
});
// 每隔2秒钟获取一次当前站房的温湿度、空调红外传感器1和空调红外传感器2的值
setInterval(()=>{
let nowTime = moment().format('YYYY-MM-DD HH:mm:ss');
console.log('当前时间为:', nowTime);
getData();
}, 2000);
运行结果如下图所示: