using Edge.Core.Parser; using Edge.Core.Processor; using Edge.Core.Processor.Communicator; using Edge.Core.Processor.Dispatcher.Attributes; using Edge.Core.UniversalApi; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using SuZhouSuAnXin_BatteryEMS.MessageEntity; using System; using System.Linq; using System.Threading.Tasks; namespace SuZhouSuAnXin_BatteryEMS { [MetaPartsRequired(typeof(HalfDuplexActivePollingDeviceProcessor<,>))] [MetaPartsRequired(typeof(TcpClientCommunicator<>))] [MetaPartsDescriptor( "速安行电池EMS", "用于驱动 苏州速安行新能源科技有限公司 电池EMS系统,EMS侧默认端口为502,日志名称:DynamicPrivate_SuZhouSuAnXin_BatteryEMS", new[] { "lang-zh-cn:电池储能lang-en-us:BatterySystem" })] public class DeviceHandler : TestableActivePollingDeviceHandler, IDisposable { private IContext context; private ILogger logger = NullLogger.Instance; private IServiceProvider services; private DeviceConfigV1 deviceConfig; public class DeviceConfigV1 { public string DeviceName { get; set; } public byte SlaveAddress { get; set; } public string Description { get; set; } } [ParamsJsonSchemas("ctorParamsJsonSchema")] public DeviceHandler(DeviceConfigV1 deviceConfig, IServiceProvider services) { this.deviceConfig = deviceConfig; this.services = services; var loggerFactory = services.GetRequiredService(); this.logger = loggerFactory.CreateLogger("DynamicPrivate_SuZhouSuAnXin_BatteryEMS"); } public override void Init(IContext context) { base.Init(context); this.context = context; var timeWindowWithActivePollingOutgoing = this.context.Outgoing as TimeWindowWithActivePollingOutgoing; int previousPolledDeviceIndex = 0; timeWindowWithActivePollingOutgoing.PollingMsgProducer = () => { try { if (DateTime.Now.Ticks % 2 == 0) { //0x0016 2 总电压 电池系统当前直流测电压(外侧电压) //0x0017 2 总电流 电池系统当前直流充放电电流 //0x0018 2 SOC 电池系统当前 SOC 数据 //0x0019 2 SOH 电池系统当前 SOH 数据 //0x001A 2 DOD 放电深度 return new OutgoingQueryMessage(0x16, 5); } else { //寄存器地址 字节数 含义 备注 //0x0230 2 系统时钟:年 数据范围:2000 - 2099 //0x0231 2 系统时钟:月 数据范围:1 - 12 //0x0232 2 系统时钟:日 数据范围:1 - 31 //0x0233 2 系统时钟:时 数据范围:0 - 23 //0x0234 2 系统时钟:分 数据范围:0 - 59 //0x0235 2 系统时钟:秒 数据范围:0 - 59 return new OutgoingQueryMessage(0x0230, 5); } } catch (Exception exxx) { logger.LogError($"Exceptioned (previousPolledHandlerIndex: {previousPolledDeviceIndex}): {exxx}"); return null; } }; } public override async Task Process(IContext context) { await base.Process(context); return; } public void Dispose() { } [UniversalApi] public async Task SendOutgoingQueryMessageAsync(int startingRegAddress, byte noOfRegAddress) { var response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(startingRegAddress, noOfRegAddress), (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage; if (response == null) throw new TimeoutException("long time no see incoming response"); return response.ToLogString(); } [UniversalApi] public async Task ReadGenericInfoAsync() { //数据类型 比例因子 范围 偏移量 实际量程 字节数 备注 //总电压 0.1V 0 - 10000 0 0 - 1000V 2(UINT16) //总电流 0.1A 0 - 6000 - 3000 - 300 - 300A 2(INT16) 实际充电为负数,放电为正数 //SOC 0.1 % 0 - 1000 0 0 - 100 % 2(UINT16) //SOH 0.1 % 0 - 1000 0 0 - 100 % 2(UINT16) //DOD 0.1 % 0 - 1000 0 0 - 100 % 2(UINT16) 最近一次放电深度 //单体电压 0.001V 0 - 5000 0 0 - 5V 2(UINT16) //温度 1℃ 0 - 210 - 80 - 80 - 130℃ 1 //湿度 1 % 0 - 100 0 0 - 100 % 1 //总充电电量 1kWH 0 4(UINT32) //总放电电量 1kWH 0 4(UINT32) //寄存器地址 字节数 含义 备注 //0x0016 2 总电压 电池系统当前直流测电压(外侧电压) //0x0017 2 总电流 电池系统当前直流充放电电流 //0x0018 2 SOC 电池系统当前 SOC 数据 //0x0019 2 SOH 电池系统当前 SOH 数据 //0x001A 2 DOD 放电深度 //0x001B 2 循环次数 电池系统累计循环次数 //0x001C 2 总电压—内侧 电池系统当前直流累加电压数据 //0x001D 2 单体最高电压值 电池系统当前单体最高电压 //0x001E 2 单体最低电压值 电池系统当前单体最低电压 //0x001F 2 单体平均电压 电池系统当前单体平均电压 var response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(0x0016, 10), (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage; if (response == null) throw new TimeoutException("long time no see incoming response for reg address starts from 0x0016 of 10 count"); //0.1V var 总电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Take(2).Reverse().ToArray()))) / 10; //0.1A var 总电流 = ((decimal)(BitConverter.ToInt16(response.InnerRawData.Skip(2).Take(2).Reverse().ToArray()))) / 10; //0.1% var SOC = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(4).Take(2).Reverse().ToArray()))) / 10; //0.1% var SOH = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(6).Take(2).Reverse().ToArray()))) / 10; //0.1% var DOD = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(8).Take(2).Reverse().ToArray()))) / 10; var 电池系统累计循环次数 = BitConverter.ToUInt16(response.InnerRawData.Skip(10).Take(2).Reverse().ToArray()); //0.1V var 电池系统当前直流累加电压数据 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(12).Take(2).Reverse().ToArray()))) / 10; //0.1V var 电池系统当前单体最高电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(14).Take(2).Reverse().ToArray()))) / 10; //0.1V var 电池系统当前单体最低电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(16).Take(2).Reverse().ToArray()))) / 10; //0.1V var 电池系统当前单体平均电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(18).Take(2).Reverse().ToArray()))) / 10; //寄存器地址 字节数 含义 备注 //0x0200 2 系统充放电状态 0:正常 1:禁充 2:禁放 3:待机 //0x0201 2 充放电计划1使能 0:禁用 1:使能 //0x0202 2 充放电计划1模式 0:待机 1:充电 2:放电 //0x0203 2 充放电计划1起始时间 高字节小时数 0 - 23 低字节分钟数 0 - 59 //0x0204 2 充放电计划1终止时间 高字节小时数 0 - 23 低字节分钟数 0 - 59 //0x0205 2 充放电计划1有功功率 Kw //0x0206 2 充放电计划2使能 0:禁用 1:使能 //0x0207 2 充放电计划2模式 0:待机 1:充电 2:放电 //0x0208 2 充放电计划2起始时间 高字节小时数 0 - 23 低字节分钟数 0 - 59 //0x0209 2 充放电计划2终止时间 高字节小时数 0 - 23 低字节分钟数 0 - 59 //0x020A 2 充放电计划2有功功率 Kw response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(0x0200, 11), (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage; if (response == null) throw new TimeoutException("long time no see incoming response for reg address starts from 0x0200 of 11 count"); var 系统充放电状态 = "???undefined???"; var __系统充放电状态value = BitConverter.ToInt16(response.InnerRawData.Take(2).Reverse().ToArray()); if (__系统充放电状态value == 0) 系统充放电状态 = "正常"; else if (__系统充放电状态value == 1) 系统充放电状态 = "禁充"; else if (__系统充放电状态value == 2) 系统充放电状态 = "禁放"; else if (__系统充放电状态value == 3) 系统充放电状态 = "待机"; var 充放电计划1使能 = BitConverter.ToInt16(response.InnerRawData.Skip(2).Take(2).Reverse().ToArray()) == 0 ? "禁用" : "使能"; var __充放电计划1模式value = BitConverter.ToInt16(response.InnerRawData.Skip(4).Take(2).Reverse().ToArray()); var 充放电计划1模式 = __充放电计划1模式value == 0 ? "待机" : (__充放电计划1模式value == 1 ? "充电" : "放电"); var 充放电计划1起始时间_分钟数 = response.InnerRawData.Skip(6).First(); var 充放电计划1起始时间_小时数 = response.InnerRawData.Skip(7).First(); var 充放电计划1终止时间_分钟数 = response.InnerRawData.Skip(8).First(); var 充放电计划1终止时间_小时数 = response.InnerRawData.Skip(9).First(); var 充放电计划1有功功率 = ((decimal)(BitConverter.ToInt16(response.InnerRawData.Skip(10).Take(2).Reverse().ToArray()))) / 10; var 充放电计划2使能 = BitConverter.ToInt16(response.InnerRawData.Skip(12).Take(2).Reverse().ToArray()) == 0 ? "禁用" : "使能"; var __充放电计划2模式value = BitConverter.ToInt16(response.InnerRawData.Skip(14).Take(2).Reverse().ToArray()); var 充放电计划2模式 = __充放电计划1模式value == 0 ? "待机" : (__充放电计划1模式value == 1 ? "充电" : "放电"); var 充放电计划2起始时间_分钟数 = response.InnerRawData.Skip(16).First(); var 充放电计划2起始时间_小时数 = response.InnerRawData.Skip(17).First(); var 充放电计划2终止时间_分钟数 = response.InnerRawData.Skip(18).First(); var 充放电计划2终止时间_小时数 = response.InnerRawData.Skip(19).First(); var 充放电计划2有功功率 = ((decimal)(BitConverter.ToInt16(response.InnerRawData.Skip(20).Take(2).Reverse().ToArray()))) / 10; //寄存器地址 字节数 含义 备注 //0x0230 2 系统时钟:年 数据范围:2000 - 2099 //0x0231 2 系统时钟:月 数据范围:1 - 12 //0x0232 2 系统时钟:日 数据范围:1 - 31 //0x0233 2 系统时钟:时 数据范围:0 - 23 //0x0234 2 系统时钟:分 数据范围:0 - 59 //0x0235 2 系统时钟:秒 数据范围:0 - 5 response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(0x0230, 6), (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage; if (response == null) throw new TimeoutException("long time no see incoming response for reg address starts from 0x0230 of 6 count"); var 系统时钟_年 = BitConverter.ToUInt16(response.InnerRawData.Take(2).Reverse().ToArray()); var 系统时钟_月 = BitConverter.ToUInt16(response.InnerRawData.Skip(2).Take(2).Reverse().ToArray()); var 系统时钟_日 = BitConverter.ToUInt16(response.InnerRawData.Skip(4).Take(2).Reverse().ToArray()); var 系统时钟_时 = BitConverter.ToUInt16(response.InnerRawData.Skip(6).Take(2).Reverse().ToArray()); var 系统时钟_分 = BitConverter.ToUInt16(response.InnerRawData.Skip(8).Take(2).Reverse().ToArray()); var 系统时钟_秒 = BitConverter.ToUInt16(response.InnerRawData.Skip(10).Take(2).Reverse().ToArray()); return new { 总电压, 总电流, SOC, SOH, DOD, 电池系统累计循环次数, 电池系统当前直流累加电压数据, 电池系统当前单体最高电压, 电池系统当前单体最低电压, 电池系统当前单体平均电压, 系统充放电状态, 充放电计划1使能, 充放电计划1模式, 充放电计划1起始时间_分钟数, 充放电计划1起始时间_小时数, 充放电计划1终止时间_分钟数, 充放电计划1终止时间_小时数, 充放电计划1有功功率, 充放电计划2使能, 充放电计划2模式, 充放电计划2起始时间_分钟数, 充放电计划2起始时间_小时数, 充放电计划2终止时间_分钟数, 充放电计划2终止时间_小时数, 充放电计划2有功功率, 系统时钟_年, 系统时钟_月, 系统时钟_日, 系统时钟_时, 系统时钟_分, 系统时钟_秒 }; } } }