using System; using System.Collections.Generic; using System.Linq; using System.Net.NetworkInformation; using System.Net; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using Newtonsoft.Json; using JinYuan.Models; using System.Buffers; using Newtonsoft.Json.Linq; using System.Collections; using Org.BouncyCastle.Ocsp; namespace JinYuan.Helper { public class EnergyMeterHelper { public const int BufferSize = 1024;//6kb private int _timeout = 2000; private Ping _ping = null; private IPEndPoint _endPoint = null; private Socket EnergyMeterSocket = null; private PingReply _pingReply = null; private string _lastError = ""; public enum ModBusExceptionCode //错误代码 { IllegalFunction = 01, IllegalDataAddress, IllegalDataValue, SlaveDeviceFailure, Acknowledge, SlaveDeviceBusy, GatewayPathUnavailable, GatewayTargetDeviceFailed2Respond, } /// /// 构造函数 /// public EnergyMeterHelper() { // used to ping the PLC // this._ping = new Ping(); // EndPoint parametres // this._endPoint = new IPEndPoint(0, 0); } /// /// set ip and port /// public void SetTCPParams(IPAddress ip, int port) { this._endPoint.Address = ip; this._endPoint.Port = port; } /// /// returns the connection status /// public bool Connected { get { try { return (EnergyMeterSocket == null) ? false : EnergyMeterSocket.Connected; } catch (Exception ex) { //PrintfLog.LogError(ex.Message); return false; } } } /// /// close the socket /// /// public void Close() { lock (this) { if (EnergyMeterSocket == null) return; if (Connected) { EnergyMeterSocket.Disconnect(false); EnergyMeterSocket.Close(); } EnergyMeterSocket.Dispose(); EnergyMeterSocket = null; } } public bool Connect() { if (this.Connected == true) { return true; } try { if (this.TCPConnect()) { return true; } else { return false; } } catch (Exception ex) { Close(); return false; } } private bool TCPConnect() { try { if (EnergyMeterSocket != null) { EnergyMeterSocket.Dispose(); } EnergyMeterSocket = new Socket(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); EnergyMeterSocket.SendTimeout = _timeout; EnergyMeterSocket.ReceiveTimeout = _timeout; EnergyMeterSocket.Connect(this._endPoint); return this.Connected; } catch (System.Exception ex) { TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 智能电表:网口连接失败"); return false; } } public bool Ping() { try { if (this._endPoint.Address == null) return false; this._pingReply = this._ping.Send(this._endPoint.Address, this._timeout); return (this._pingReply.Status == IPStatus.Success) ? true : false; } catch (Exception) { //PrintfLog.LogError("ECFFU ping exception"); return false; } } public bool SendAndGetRes(byte[] bytes, ref List listM)//, ref JetReturnResult jet { var arrayPool = ArrayPool.Shared; byte[] buffer = arrayPool.Rent(BufferSize);//new byte[1024]; byte[] RecvData = new byte[88 * 4 + 9];//0x58 int size = 88 * 4 + 9;//0x58 if (!Ping()) { return false; } try { // 发送 Send(bytes, bytes.Length); // 接收 Receive(ref RecvData, size); // 解析 if ((RecvData[0] == Convert.ToByte(01 >> 8) && RecvData[1] == Convert.ToByte(01)))//pTask.id { if (RecvData[7] == 0x04)//读线圈寄存器功能码 { //数据赋值 Array.Copy(RecvData, 0, buffer, 0, RecvData.Length); TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取原始数据:{string.Join(" ", RecvData)}"); decimal PhaseVoltageA = Convert.ToDecimal(HextoFloat(buffer[9], buffer[10], buffer[11], buffer[12])); decimal PhaseVoltageB = Convert.ToDecimal(HextoFloat(buffer[13], buffer[14], buffer[15], buffer[16])); decimal PhaseVoltageC = Convert.ToDecimal(HextoFloat(buffer[17], buffer[18], buffer[19], buffer[20])); decimal PhaseCurrentA = Convert.ToDecimal(HextoFloat(buffer[21], buffer[22], buffer[23], buffer[24])); decimal PhaseCurrentB = Convert.ToDecimal(HextoFloat(buffer[25], buffer[26], buffer[27], buffer[28])); decimal PhaseCurrentC = Convert.ToDecimal(HextoFloat(buffer[29], buffer[30], buffer[31], buffer[32])); decimal PhasePowerA = Convert.ToDecimal(HextoFloat(buffer[33], buffer[34], buffer[35], buffer[36])); decimal PhasePowerB = Convert.ToDecimal(HextoFloat(buffer[37], buffer[38], buffer[39], buffer[40])); decimal PhasePowerC = Convert.ToDecimal(HextoFloat(buffer[41], buffer[42], buffer[43], buffer[44])); decimal ActivePower = Convert.ToDecimal(HextoFloat(buffer[121], buffer[122], buffer[123], buffer[124])); decimal PowerFactor = Convert.ToDecimal(HextoFloat(buffer[133], buffer[134], buffer[135], buffer[136])); decimal pt = 1; decimal ct = 150 / 5; decimal AccumulatedElectricity = Convert.ToDecimal(HextoFloat(buffer[181], buffer[182], buffer[183], buffer[184])); ElectricEnergy m = new ElectricEnergy(); m.PhaseVoltageA = PhaseVoltageA; m.PhaseVoltageB = PhaseVoltageB; m.PhaseVoltageC = PhaseVoltageC; m.PhaseCurrentA = PhaseCurrentA * ct; m.PhaseCurrentB = PhaseCurrentB * ct; m.PhaseCurrentC = PhaseCurrentC * ct; m.PhasePowerA = PhaseVoltageA * PhaseCurrentA * ct; m.PhasePowerB = PhaseVoltageB * PhaseCurrentB * ct; m.PhasePowerC = PhaseVoltageC * PhaseCurrentC * ct; m.ActivePower = ActivePower * ct; m.PowerFactor = PowerFactor * ct; m.pt = pt;//Convert.ToDecimal(HextoFloat(buffer[0], buffer[0], buffer[0], buffer[0])); m.ct = ct;//Convert.ToDecimal(HextoFloat(buffer[0], buffer[0], buffer[0], buffer[0])); m.AccumulatedElectricity = AccumulatedElectricity; listM.Add(m); } else { switch (RecvData[8]) { case (byte)ModBusExceptionCode.IllegalDataAddress: _lastError = string.Format("SendAndGetRes():ReadInputRegister [IllegalDataAddress]"); break; case (byte)ModBusExceptionCode.IllegalDataValue: _lastError = string.Format("SendAndGetRes():ReadInputRegister [IllegalDataValue]"); break; case (byte)ModBusExceptionCode.IllegalFunction: _lastError = string.Format("SendAndGetRes():ReadInputRegister [IllegalFunction]"); break; default: _lastError = string.Format("SendAndGetRes():ReadInputRegister [FunctionException]"); break; } TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取数据异常,原因:{_lastError}"); } } } catch (Exception ex) { TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取原始数据:{string.Join(" ", RecvData)}"); TxtHelper.WriteTxt($@"D:\APILog\Logs\智能电表信息\{DateTime.Now.ToString("yyyy-MM-dd")}.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + $"电能表读取数据异常,原因:{ex}"); Close(); return false; } finally { arrayPool.Return(buffer); } return true; } /// /// send a command to energy meter device /// /// /// /// private int Send(Byte[] command, int cmdLen) { if (!Connected) { throw new Exception("EnergyMeter Socket is not connected."); } // sends the command // int bytesSent = EnergyMeterSocket.Send(command, cmdLen, SocketFlags.None); // it checks the number of bytes sent // if (bytesSent != cmdLen) { string msg = string.Format("EnergyMeter Sending error. (Expected bytes: {0} Sent: {1})", cmdLen, bytesSent); throw new Exception(msg); } return bytesSent; } /// /// receives a response from the plc /// /// /// /// private int Receive(ref Byte[] response, int respLen) { if (!this.Connected) { throw new Exception("EnergyMeter Socket is not connected."); } // receives the response, this is a synchronous method and can hang the process int bytesRecv = EnergyMeterSocket.Receive(response, respLen, SocketFlags.None); // check the number of bytes received // // if (bytesRecv != respLen) // { // string msg = string.Format("Receiving error. (Expected: {0} Received: {1})" // , respLen, bytesRecv); // throw new Exception(msg); // } return bytesRecv; } /// /// HexToFloat /// /// 高字高字节 /// 高字低字节 /// 低字高字节 /// 低字低字节 /// float public static float HextoFloat(byte H1, byte H2, byte D1, byte D2) { try { //byte-->short int s1, s2; s1 = Convert.ToInt32(H1 * 256) + Convert.ToInt32(H2); s2 = Convert.ToInt32(D1 * 256) + Convert.ToInt32(D2); //将输入数值short转化为无符号unsigned short int us1 = s1, us2 = s2; if (s1 < 0) us1 += 65536; if (s2 < 0) us2 += 65536; //sign: 符号位, exponent: 阶码, mantissa:尾数 int sign, exponent; float mantissa; //计算符号位 sign = us1 / 32768; //去掉符号位 int emCode = us1 % 32768; //计算阶码 exponent = emCode / 128; //计算尾数 mantissa = (float)(emCode % 128 * 65536 + us2) / 8388608; //代入公式 fValue = (-1) ^ S x 2 ^ (E - 127) x (1 + M) return (float)Math.Pow(-1, sign) * (float)Math.Pow(2, exponent - 127) * (1 + mantissa); } catch (Exception ex) { return 0; } } } }