在物联网管理平台的实际现场应用过程中,遇到过大大小小几十个改进的需求点,这些需求点都是实际用户提出来的,一方面为了方便用户使用提高用户体验,一方面为了提升整体的整个系统的完整性,甚至有些需求说的不好听一点就是造假,比如硬件设备精度不够,会短暂的在某些值附近飘动,但是客户端采集到数据后,如果该值刚好在报警值附近飘动,不能说是报警,因为也有可能是干扰引起的飘动,这种严格意义上说又不算是报警,只有持续超过了报警值,才算是真正的报警,所以需要设计一个报警延时参数,超过了延时时间还处于报警则认为是报警。
存储周期很好理解,就是多久存储一次这个设备的记录值,有些设备很重要,可以将这个存储周期设置的小一点,比如5s就存储一个值,有些不大重要的,可以设置一个很大的值,这样可以因地制宜,省下不少的存储空间。报警类型也是一个很好的参数规则,对于我们常见的规则就是大于上限值属于高报,低于下限值属于低报,比如温度就属于这个情况。而有些气体是高于最小值属于低报,高于最大值属于高报,相当于一定要低于最低值才是正常的,有毒气体一般都属于这个类型。有些特定环境又是要求气体的浓度超过最大值才正常比如氧气,要求超过最大值才是正常,最大值和最小值中间是低报,小于最小值是高报,因为氧气太少了属于最紧急的事件。
字段说明




void DeviceServer::doReceiveValue(const QString &portName, quint8 addr, const QList<quint16> &values)
{
//找到设备名称
QString deviceName = DbQuery::getDeviceName(portName, addr);
//找到当前索引位置的设备地址对应探测器的最小寄存器地址
//如果读取的起始寄存器地址是5则回来的数据位第一个是寄存器地址5的数据,后面连续
quint16 nodeMinAddr = DbQuery::getNodeMinAddr(portName, addr);
//根据不同的探测器对应的小数点,换算值
QList<float> datas;
foreach (quint16 value, values) {
datas << value;
}
for (int i = 0; i < DbData::NodeInfo_Count; ++i) {
if (DbData::NodeInfo_DeviceName.at(i) == deviceName) {
//有时候可能出现总共添加了8个探测器但是真实读到4个探测器的情况
int startIndex = DbData::NodeInfo_NodeAddr.at(i) - nodeMinAddr - 1;
if (startIndex >= datas.count()) {
continue;
}
QString positionID = DbData::NodeInfo_PositionID.at(i);
float nodeMax = DbData::NodeInfo_NodeMax.at(i);
float nodeMin = DbData::NodeInfo_NodeMin.at(i);
float nodeRange = DbData::NodeInfo_NodeRange.at(i);
int dotCount = DbData::NodeInfo_DotCount.at(i);
//目前收到的值需要经过几层过滤计算才是真实的值
//第一层是小数点(默认0),比如收到的值是1000,如果小数点设定的1则真实的是100
//第二层是量程(默认0),比如收到998,如果设定的量程0.25则运算后 998/4000*0.25=0.062375
//第三层是最大值(默认1000),假设设定的最大值1000,如果收到的值>1000则取1000,因为某些设备损坏或者误报采集到的是一个很大的不准确的值
//第四层是清零值(默认0),假设设定的是50,则低于50都认为是0,因为某些设备损坏或者误报采集到的是一个很小的不准确的值
//根据设定的小数点来重新计算真实的值
float nodeValue = (float)values.at(startIndex);
if (dotCount > 0) {
nodeValue = nodeValue / qPow(10, dotCount);
}
//4218按照新的规则计算值 实际数=模拟量/4000*量程 模拟量就是采集的值
if (nodeRange > 0) {
nodeValue = (float)values.at(startIndex) / 4000 * nodeRange;
}
//如果收到的值大于最大值则取最大值作为当前的值
nodeValue = nodeValue > nodeMax ? nodeMax : nodeValue;
//如果设置了消零阀值,在未达到消零阀值时显示都是零,只有超过消零阀值才是显示真实值
if (nodeRange == 0) {
nodeValue = nodeValue < nodeMin ? 0 : nodeValue;
}
//精度过滤,避免精度过大显示太长
nodeValue = QString::number(nodeValue, 'f', AppConfig::Precision).toFloat();
//找到当前探测器处理探测器报警
//如果当前值小于最小值而且当前不处于下限报警则触发报警
//如果当前值大于最大值而且当前不处于上限报警则触发报警
//0-低报 1-低报恢复 2-高报 3-高报恢复
quint8 nodeStatus = 100;
//根据设定的不同的报警类型处理,假定上限值100,下限值25
//HH表示超过25是低报,超过100是高报
//HL表示低于25是低报,超过100是高报
//LL表示低于25是高报,低于100是低报
QString alarmType = DbData::NodeInfo_AlarmType.at(i);
if (alarmType == "HH") {
doAlarmHH(nodeStatus, positionID, nodeValue, i);
} else if (alarmType == "HL") {
doAlarmHL(nodeStatus, positionID, nodeValue, i);
} else if (alarmType == "LL") {
doAlarmLL(nodeStatus, positionID, nodeValue, i);
}
//处理报警
//qDebug() << TIMEMS << positionID << nodeStatus << nodeValue;
doAlarm(nodeStatus, positionID, nodeValue, i);
//没有变动的数据则无需处理,不然界面上一下子这么多数据刷新可能导致高CPU,一样的数据也没有必要
if (DbData::NodeInfo_NodeValue.at(i) != nodeValue) {
QString nodeSign = DbData::NodeInfo_NodeSign.at(i);
DeviceHelper::deviceValue(positionID, nodeValue, nodeSign);
DbData::NodeInfo_NodeValue[i] = nodeValue;
}
//云端数据同步
if (AppConfig::UseNetDb) {
QString sql = QString("update NodeData set NodeValue='%1',SaveTime='%2' where PositionID='%3'").arg(nodeValue).arg(DATETIME).arg(positionID);
DbData::DbNet->append(sql);
}
datas[startIndex] = nodeValue;
}
}
emit receiveValue(portName, addr, datas);
}