public static string GetReportString(string dateTimeStr, float temperatureVal, ModbusDeviceInfo deviceInfo) { string reportStr = temperatureVal.ToString(); // 室温的设备种类编码是004 string deviceTypeStr = "004"; string deviceSnStr = deviceInfo.ServiceArea.ToString().PadLeft(3, '0') + deviceInfo.SpotNumber.PadLeft(3, '0') + deviceTypeStr + deviceInfo.DeviceAddr.ToString().PadLeft(3, '0'); string insertStr = @"INSERT INTO " + deviceInfo.DbTableName + @"(time_stamp, device_number, value_01" + @") VALUES('" + dateTimeStr + @"'," + deviceSnStr + @", " + reportStr + @")"; return insertStr; }
/// <summary> /// 查询执行 /// </summary> override public void DoInquiry() { if ((null != DeviceList) && (0 != DeviceList.Count)) { AppendUITextBox("\r\n>------------------------------->"); AppendUITextBox(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString()); // 对列表中的各个设备, 逐一进行查询 for (int i = 0; i < DeviceList.Count; i++) { ModbusDeviceInfo di = DeviceList[i]; AppendUITextBox("开始查询 " + di.DeviceName); Thread inquiryThread = new Thread(delegate() { InquiryTask(di); }); inquiryThread.Start(); System.Threading.Thread.Sleep(500); } } }
/// <summary> /// 单个设备查询线程的执行过程 /// </summary> /// <param name="deviceInfo"></param> override protected void InquiryTask(ModbusDeviceInfo deviceInfo) { string dateTimeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); TcpSocketCommunicator inquirer = new TcpSocketCommunicator(); try { // 与设备模块进行连接(Connect) // 设定Receive的接收超时时间为3000毫秒 AppendUITextBox(" 开始连接: "+ deviceInfo.DeviceName); inquirer.Connect(deviceInfo.HostName, deviceInfo.PortNum, 3000); AppendUITextBox(" "+ deviceInfo.DeviceName + "连接成功!"); System.Threading.Thread.Sleep(100); // 发送查询命令内容 // 目标设备地址 // 功能码: 0x03(读) // 寄存器地址: 0x0202 // 读长度: 0x0002 byte[] tmpBytes = { (byte)deviceInfo.DeviceAddr, 0x03, 0x02, 0x02, 0x00, 0x02 }; UInt16 crc16 = CRC16(tmpBytes, 6); byte crcLowByte = (byte)(crc16 & 0x00FF); byte crcHighByte = (byte)((crc16 & 0xFF00) >> 8); // 水表 byte[] sendBytes = { (byte)deviceInfo.DeviceAddr, 0x03, 0x02, 0x02, 0x00, 0x02, crcLowByte, crcHighByte }; // 向设备模块发送读数查询指令 AppendUITextBox(" 查询 "+ deviceInfo.DeviceName + " 指令发送!"); inquirer.Send(sendBytes); // 接收设备模块返回的读数查询结果 ReceiveData ir = inquirer.Receive(); AppendUITextBox(" 接收到 "+ deviceInfo.DeviceName + " 应答数据: " + ir.RcvLen.ToString() + " 字节."); if ((ir.RcvLen >= 1) && (deviceInfo.DeviceAddr != ir.RcvBytes[0])) { AppendUITextBox(" "+ "收到的应答设备地址不一致: " + ir.RcvBytes[0].ToString()); return; } if (ir.RcvLen < 3) { System.Diagnostics.Trace.WriteLine(@"收到数据不正确, 无长度位!"); return; } int data_len = ir.RcvBytes[2]; if (ir.RcvLen < data_len + 3) { System.Diagnostics.Trace.WriteLine(@"收到数据长度不正确!"); return; } string waterVolumeStr = ""; for (int i = 3; i < 3 + data_len; i++) { string valStr = string.Format("{0:X}", ir.RcvBytes[i]).PadLeft(2, '0'); waterVolumeStr += valStr; } int iWaterVolumeVal = Convert.ToInt32(waterVolumeStr, 16); // 首先读数要乘以放大倍率 float waterVolumeVal = iWaterVolumeVal * deviceInfo.Magnification; // 然后除以量纲得到实际小数值 float fValue = waterVolumeVal / deviceInfo.Magnitude; float fWaterVolumeVal = fValue + deviceInfo.Adjustment; // 上报给服务器 string insertStr = GetReportString(dateTimeStr, fWaterVolumeVal, deviceInfo); AppendUITextBox(" "+ deviceInfo.DeviceName + " : 读数值 = " + fValue.ToString() + " + " + deviceInfo.Adjustment.ToString() + " = " + fWaterVolumeVal.ToString()); ReportToDBServer(insertStr, deviceInfo.DeviceName); } catch (Exception ex) { AppendUITextBox(" "+ deviceInfo.DeviceName + ": 查询失败!"); System.Diagnostics.Trace.WriteLine(ex.ToString()); } finally { inquirer.Close(); } }
public static string GetReportString(string dateTimeStr, float waterVolumeVal, ModbusDeviceInfo deviceInfo) { string reportStr = waterVolumeVal.ToString(); // 水表的设备种类编码是002 string deviceTypeStr = "002"; string deviceSnStr = deviceInfo.ServiceArea.ToString().PadLeft(3, '0') + deviceInfo.SpotNumber.PadLeft(3, '0') + deviceTypeStr + deviceInfo.DeviceAddr.ToString().PadLeft(3, '0'); string insertStr = @"INSERT INTO " + deviceInfo.DbTableName + @"(time_stamp, device_number, value_01, group_id" + @") VALUES('" + dateTimeStr + @"'," + deviceSnStr + @", " + reportStr + ", " + deviceInfo.GroupId.ToString() + @")"; return(insertStr); }
/// <summary> /// 单个电表查询线程的执行过程 /// </summary> /// <param name="deviceInfo"></param> protected override void InquiryTask(ModbusDeviceInfo deviceInfo) { TcpSocketCommunicator inquirer = new TcpSocketCommunicator(); try { // 与设备模块进行连接(Connect) // 设定Receive的接收超时时间为3000毫秒 AppendUITextBox(" 开始连接: " + deviceInfo.DeviceName); inquirer.Connect(deviceInfo.HostName, deviceInfo.PortNum, 3000); AppendUITextBox(" " + deviceInfo.DeviceName + "连接成功!"); System.Threading.Thread.Sleep(100); // 向设备模块发送查询指令(Modbus协议) // 第一个字节是通信地址(设备号) // 第二个字节是功能码0x03(读数据) // 后面依次是读的起始地址0x0000和读长度0x004E(=78, 读到"正向(吸收)有功电能") // 最后两个字节是CRC16校验码 byte[] tmpBytes = { (byte)deviceInfo.DeviceAddr, 0x03, 0x00, 0x00, 0x00, 0x4E }; // 计算CRC校验码 UInt16 crc16 = CRC16(tmpBytes, 6); byte crcLowByte = (byte)(crc16 & 0x00FF); byte crcHighByte = (byte)((crc16 & 0xFF00) >> 8); byte[] sendBytes = { (byte)deviceInfo.DeviceAddr, 0x03, 0x00, 0x00, 0x00, 0x4E, crcLowByte, crcHighByte }; // 向设备模块发送Modbus读数查询指令 AppendUITextBox(" 查询 " + deviceInfo.DeviceName + " 指令发送!"); inquirer.Send(sendBytes); // 接收设备模块返回的读数查询结果 ReceiveData rd = inquirer.Receive(); AppendUITextBox(" 接收到 " + deviceInfo.DeviceName + " 应答数据: " + rd.RcvLen.ToString() + " 字节."); // 对应答数据进行检查, 返回的第一个字节应该跟设备地址号一致 if ( (rd.RcvLen >= 1) && (deviceInfo.DeviceAddr != rd.RcvBytes[0]) ) { AppendUITextBox(" " + "收到的应答设备地址不一致: " + rd.RcvBytes[0].ToString()); return; } float fValue; string insertStr = GetReportString(rd, deviceInfo, out fValue); if (null == insertStr) { return; } AppendUITextBox(" " + deviceInfo.DeviceName + " : 读数值 = " + fValue.ToString() + " + " + deviceInfo.Adjustment.ToString() + " = " + (fValue + deviceInfo.Adjustment).ToString()); // 上报给服务器 ReportToDBServer(insertStr, deviceInfo.DeviceName); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.ToString()); AppendUITextBox(" " + deviceInfo.DeviceName + " : 查询失败!"); } finally { inquirer.Close(); } }
public static string GetReportString(ReceiveData inquiryResult, ModbusDeviceInfo deviceInfo, out float fValue) { string reportStr = ""; fValue = 0; List<DataUnitInfo> dataInfoList = ElectricMeterDataSetting.GetElectricMeterDataSetting(); int total_flg = 0; // 数据库表中用以标识该电表是否为"总表"的标志, 如果是总表, 那么不在表示用电量占比的饼图和柱状图中显示其用电量; if (-1 != deviceInfo.DeviceName.IndexOf(@"总表")) { total_flg = 1; } foreach (var dataInfo in dataInfoList) { // -5是因为要去掉前面三个字节(分别是设备码, 操作码03, 和读的长度)和最后两个字节(CRC校验) if (dataInfo.Offset < inquiryResult.RcvLen - 5 - 1) { string dataStr = "0x"; // 越过前面三个字节 int idx = dataInfo.Offset + 3; for (int i = 0; i < dataInfo.Length; i++) { dataStr += string.Format("{0:X}", inquiryResult.RcvBytes[idx]).PadLeft(2, '0'); idx++; } UInt32 val; try { val = Convert.ToUInt32(dataStr, 16); dataInfo.Value = val; reportStr += ", " + val.ToString(); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.ToString()); } } } // 现在只把"正向(吸收)有功电能"即耗电量, 存到数据库表里 string[] arr = reportStr.Split(','); string valueStr = arr[arr.Length - 4].Trim(); int iValue; if (!int.TryParse(valueStr, out iValue)) { return null; } // 读数值要乘以放大倍率 float value = iValue * deviceInfo.Magnification; // 然后还要除以量纲得到浮点型小数值 fValue = value / deviceInfo.Magnitude; // 加上校正值进行校正调整得到最终的用电量 float realVal = fValue + deviceInfo.Adjustment; // 电表的设备种类编码是001 string deviceTypeStr = "001"; // 3位服务区编号 + 3位采集点位置编号 + 3位设备种类编号 + 3位设备地址 = 12位设备编号唯一确定一个具体的设备 string deviceSnStr = deviceInfo.ServiceArea.ToString().PadLeft(3, '0') + deviceInfo.SpotNumber.PadLeft(3, '0') + deviceTypeStr + deviceInfo.DeviceAddr.ToString().PadLeft(3, '0'); string insertStr = @"INSERT INTO " + deviceInfo.DbTableName + @"(time_stamp, device_number, value_01, total_flg, group_id" + @") VALUES('" + inquiryResult.TimeStamp + @"'" + @", '" + deviceSnStr + @"'," + realVal.ToString() + ", " + total_flg.ToString() + ", " + deviceInfo.GroupId.ToString() + @")"; return insertStr; }
protected virtual void InquiryTask(ModbusDeviceInfo deviceInfo) { AppendUITextBox("这里是基类的方法呀呀呀!!!!"); }
private List<ModbusDeviceInfo> CreateWaterTemperatureList() { List<ModbusDeviceInfo> waterTemperatureMeterList = new List<ModbusDeviceInfo>(); foreach (ListViewItem item in listView5.Items) { if (!item.Checked) { continue; } ModbusDeviceInfo deviceInfo = new ModbusDeviceInfo(); string[] paraArr = new string[item.SubItems.Count]; int idx = 0; foreach (ListViewItem.ListViewSubItem subitems in item.SubItems) { paraArr[idx] = subitems.Text.Trim(); idx++; } int value; // 服务区编号 deviceInfo.ServiceArea = Service_area_num; // 设备名称 deviceInfo.DeviceName = paraArr[0]; // DeviceSN deviceInfo.SpotNumber = paraArr[1]; // 目标设备地址 if (int.TryParse(paraArr[2], out value)) { deviceInfo.DeviceAddr = value; } // IP deviceInfo.HostName = paraArr[3]; // 端口号 if (int.TryParse(paraArr[4], out value)) { deviceInfo.PortNum = value; } // 数据库中对应的表名 deviceInfo.DbTableName = Db_table_list[4]; // 水温的量纲默认是10 deviceInfo.Magnitude = 10; waterTemperatureMeterList.Add(deviceInfo); } return waterTemperatureMeterList; }
private List<ModbusDeviceInfo> CreateWaterMeterList() { List<ModbusDeviceInfo> waterMeterList = new List<ModbusDeviceInfo>(); foreach (ListViewItem item in listView4.Items) { if (!item.Checked) { continue; } ModbusDeviceInfo deviceInfo = new ModbusDeviceInfo(); string[] paraArr = new string[item.SubItems.Count]; int idx = 0; foreach (ListViewItem.ListViewSubItem subitems in item.SubItems) { paraArr[idx] = subitems.Text.Trim(); idx++; } int value; float fvalue; // 服务区编号 deviceInfo.ServiceArea = Service_area_num; // 设备名称 deviceInfo.DeviceName = paraArr[0]; // DeviceSN deviceInfo.SpotNumber = paraArr[1]; // 目标设备地址 if (int.TryParse(paraArr[2], out value)) { deviceInfo.DeviceAddr = value; } // IP deviceInfo.HostName = paraArr[3]; // 端口号 if (int.TryParse(paraArr[4], out value)) { deviceInfo.PortNum = value; } // 读数放大倍率 if (float.TryParse(paraArr[5], out fvalue)) { deviceInfo.Magnification = fvalue; } // 分组编号 deviceInfo.GroupId = 0; // 默认值是0 if (int.TryParse(paraArr[6], out value)) { deviceInfo.GroupId = value; } float fAdjustment = 0; if (float.TryParse(paraArr[7], out fAdjustment)) { deviceInfo.Adjustment = fAdjustment; } // 数据库中对应的表名 deviceInfo.DbTableName = Db_table_list[3]; // 水表的量纲默认是10 deviceInfo.Magnitude = 10; waterMeterList.Add(deviceInfo); } return waterMeterList; }
/// <summary> /// 单个设备查询线程的执行过程 /// </summary> /// <param name="deviceInfo"></param> protected override void InquiryTask(ModbusDeviceInfo deviceInfo) { string dateTimeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); TcpSocketCommunicator inquirer = new TcpSocketCommunicator(); try { // 与设备模块进行连接(Connect) // 设定Receive的接收超时时间为3000毫秒 AppendUITextBox(" 开始连接: " + deviceInfo.DeviceName); inquirer.Connect(deviceInfo.HostName, deviceInfo.PortNum, 3000); AppendUITextBox(" " + deviceInfo.DeviceName + "连接成功!"); System.Threading.Thread.Sleep(100); // 发送查询命令内容 // 帧头:0x10 // 总字节数: 0x07 // 目标地址: 4byte16进制数 // IO功能编号: 0x0A PT100温度采集 string deviceAddrStr = deviceInfo.DeviceAddr.ToString().PadLeft(8, '0'); if (8 != deviceAddrStr.Length) { return; } byte b1 = Convert.ToByte(deviceAddrStr.Substring(0, 2), 16); byte b2 = Convert.ToByte(deviceAddrStr.Substring(2, 2), 16); byte b3 = Convert.ToByte(deviceAddrStr.Substring(4, 2), 16); byte b4 = Convert.ToByte(deviceAddrStr.Substring(6, 2), 16); byte[] sendBytes = { 0x10, 0x07, b1, b2, b3, b4, 0x0a }; // 向设备模块发送读数查询指令 AppendUITextBox(" 查询 " + deviceInfo.DeviceName + " 指令发送!"); inquirer.Send(sendBytes); // 接收设备模块返回的读数查询结果 ReceiveData ir = inquirer.Receive(); AppendUITextBox(" 接收到 " + deviceInfo.DeviceName + " 应答数据: " + ir.RcvLen.ToString() + " 字节."); // 室温返回的结果是字符串, 直接是以小数表示, 所以不用除以量纲 string outStr = System.Text.Encoding.ASCII.GetString(ir.RcvBytes).Substring(0, ir.RcvLen); int idx = -1; string temperatureStr = ""; // 加号表示零上温度,减号表示零下温度 if (-1 != (idx = outStr.IndexOf('+'))) { temperatureStr = outStr.Substring(idx).Trim(); } else if (-1 != (idx = outStr.IndexOf('-'))) { temperatureStr = outStr.Substring(idx).Trim(); } else { return; } float temperatureVal = 0; if (!float.TryParse(temperatureStr, out temperatureVal)) { return; } // 加上校正值进行校正调整得到最终的温度值 float fValue = temperatureVal + deviceInfo.Adjustment; AppendUITextBox(" " + deviceInfo.DeviceName + " 返回值: " + temperatureStr + " + (" + deviceInfo.Adjustment.ToString() + ") = " + fValue.ToString()); // 上报给服务器 string insertStr = GetReportString(dateTimeStr, fValue, deviceInfo); AppendUITextBox(" " + deviceInfo.DeviceName + " : 读数值 = " + fValue.ToString()); ReportToDBServer(insertStr, deviceInfo.DeviceName); // 判断温度值是否在正常区间内 int alarmType = 0; if (0 != (alarmType = IsTemperatureOutOfRange(fValue))) { AddTemperatureAlarmRecord(deviceInfo, alarmType, fValue); } } catch (Exception ex) { AppendUITextBox(" " + deviceInfo.DeviceName + ": 查询失败!"); System.Diagnostics.Trace.WriteLine(ex.ToString()); } finally { inquirer.Close(); } }
/// <summary> /// 追加室温异常警报记录 /// </summary> /// <param name="deviceInfo"></param> void AddTemperatureAlarmRecord(ModbusDeviceInfo deviceInfo, int alarmType, float alarmValue) { // date_time string dateTimeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // sarea_id string sareaIdStr = deviceInfo.ServiceArea.ToString().PadLeft(3, '0'); // spot_id string spotIdStr = deviceInfo.SpotNumber.ToString().PadLeft(3, '0'); // device_type 室温固定是"004" string deviceTypeStr = "004"; // device_id string deviceIdStr = deviceInfo.DeviceAddr.ToString().PadLeft(3, '0'); string alarmTypeStr = string.Empty; if (alarmType > 0) { alarmTypeStr = @"高于上限"; } else { alarmTypeStr = @"低于下限"; } // alart_message string alarmMsgStr = Service_area_name + " " + deviceInfo.DeviceName + " 室温异常 : " + alarmTypeStr; // value_01 = alarmValue string insertStr = @"INSERT INTO " + "temperature_alarm_record" + @"(date_time, sarea_id, spot_id, device_type, device_id, alarm_message, value_01" + @") VALUES('" + dateTimeStr + @"','" + sareaIdStr + @"', '" + spotIdStr + @"', '" + deviceTypeStr + @"', '" + deviceIdStr + @"', '" + alarmMsgStr + @"', " + alarmValue.ToString() + @")"; WriteToDB(insertStr); if (!SaveToLocalFile(insertStr)) { AppendUITextBox(" " + deviceInfo.DeviceName + " 室温异常" + " : 保存本地记录文件失败!"); } }
virtual protected void InquiryTask(ModbusDeviceInfo deviceInfo) { AppendUITextBox("这里是基类的方法呀呀呀!!!!"); }