DeviceHandler.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. using Edge.Core.Parser;
  2. using Edge.Core.Processor;
  3. using Edge.Core.Processor.Communicator;
  4. using Edge.Core.Processor.Dispatcher.Attributes;
  5. using Edge.Core.UniversalApi;
  6. using Microsoft.Extensions.DependencyInjection;
  7. using Microsoft.Extensions.Logging;
  8. using Microsoft.Extensions.Logging.Abstractions;
  9. using SuZhouSuAnXin_BatteryEMS.MessageEntity;
  10. using System;
  11. using System.Linq;
  12. using System.Threading.Tasks;
  13. namespace SuZhouSuAnXin_BatteryEMS
  14. {
  15. [MetaPartsRequired(typeof(HalfDuplexActivePollingDeviceProcessor<,>))]
  16. [MetaPartsRequired(typeof(TcpClientCommunicator<>))]
  17. [MetaPartsDescriptor(
  18. "速安行电池EMS",
  19. "用于驱动 苏州速安行新能源科技有限公司 电池EMS系统,EMS侧默认端口为502,日志名称:DynamicPrivate_SuZhouSuAnXin_BatteryEMS",
  20. new[] { "lang-zh-cn:电池储能lang-en-us:BatterySystem" })]
  21. public class DeviceHandler : TestableActivePollingDeviceHandler<byte[], MessageEntity.MessageBase>, IDisposable
  22. {
  23. private IContext<byte[], MessageEntity.MessageBase> context;
  24. private ILogger logger = NullLogger.Instance;
  25. private IServiceProvider services;
  26. private DeviceConfigV1 deviceConfig;
  27. public class DeviceConfigV1
  28. {
  29. public string DeviceName { get; set; }
  30. public byte SlaveAddress { get; set; }
  31. public string Description { get; set; }
  32. }
  33. [ParamsJsonSchemas("ctorParamsJsonSchema")]
  34. public DeviceHandler(DeviceConfigV1 deviceConfig, IServiceProvider services)
  35. {
  36. this.deviceConfig = deviceConfig;
  37. this.services = services;
  38. var loggerFactory = services.GetRequiredService<ILoggerFactory>();
  39. this.logger = loggerFactory.CreateLogger("DynamicPrivate_SuZhouSuAnXin_BatteryEMS");
  40. }
  41. public override void Init(IContext<byte[], MessageEntity.MessageBase> context)
  42. {
  43. base.Init(context);
  44. this.context = context;
  45. var timeWindowWithActivePollingOutgoing =
  46. this.context.Outgoing as TimeWindowWithActivePollingOutgoing<byte[], MessageEntity.MessageBase>;
  47. int previousPolledDeviceIndex = 0;
  48. timeWindowWithActivePollingOutgoing.PollingMsgProducer = () =>
  49. {
  50. try
  51. {
  52. if (DateTime.Now.Ticks % 2 == 0)
  53. {
  54. //0x0016 2 总电压 电池系统当前直流测电压(外侧电压)
  55. //0x0017 2 总电流 电池系统当前直流充放电电流
  56. //0x0018 2 SOC 电池系统当前 SOC 数据
  57. //0x0019 2 SOH 电池系统当前 SOH 数据
  58. //0x001A 2 DOD 放电深度
  59. return new OutgoingQueryMessage(0x16, 5);
  60. }
  61. else
  62. {
  63. //寄存器地址 字节数 含义 备注
  64. //0x0230 2 系统时钟:年 数据范围:2000 - 2099
  65. //0x0231 2 系统时钟:月 数据范围:1 - 12
  66. //0x0232 2 系统时钟:日 数据范围:1 - 31
  67. //0x0233 2 系统时钟:时 数据范围:0 - 23
  68. //0x0234 2 系统时钟:分 数据范围:0 - 59
  69. //0x0235 2 系统时钟:秒 数据范围:0 - 59
  70. return new OutgoingQueryMessage(0x0230, 5);
  71. }
  72. }
  73. catch (Exception exxx)
  74. {
  75. logger.LogError($"Exceptioned (previousPolledHandlerIndex: {previousPolledDeviceIndex}): {exxx}");
  76. return null;
  77. }
  78. };
  79. }
  80. public override async Task Process(IContext<byte[], MessageEntity.MessageBase> context)
  81. {
  82. await base.Process(context);
  83. return;
  84. }
  85. public void Dispose()
  86. {
  87. }
  88. [UniversalApi]
  89. public async Task<object> SendOutgoingQueryMessageAsync(int startingRegAddress, byte noOfRegAddress)
  90. {
  91. var response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(startingRegAddress, noOfRegAddress),
  92. (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage;
  93. if (response == null)
  94. throw new TimeoutException("long time no see incoming response");
  95. return response.ToLogString();
  96. }
  97. [UniversalApi]
  98. public async Task<object> ReadGenericInfoAsync()
  99. {
  100. //数据类型 比例因子 范围 偏移量 实际量程 字节数 备注
  101. //总电压 0.1V 0 - 10000 0 0 - 1000V 2(UINT16)
  102. //总电流 0.1A 0 - 6000 - 3000 - 300 - 300A 2(INT16) 实际充电为负数,放电为正数
  103. //SOC 0.1 % 0 - 1000 0 0 - 100 % 2(UINT16)
  104. //SOH 0.1 % 0 - 1000 0 0 - 100 % 2(UINT16)
  105. //DOD 0.1 % 0 - 1000 0 0 - 100 % 2(UINT16) 最近一次放电深度
  106. //单体电压 0.001V 0 - 5000 0 0 - 5V 2(UINT16)
  107. //温度 1℃ 0 - 210 - 80 - 80 - 130℃ 1
  108. //湿度 1 % 0 - 100 0 0 - 100 % 1
  109. //总充电电量 1kWH 0 4(UINT32)
  110. //总放电电量 1kWH 0 4(UINT32)
  111. //寄存器地址 字节数 含义 备注
  112. //0x0016 2 总电压 电池系统当前直流测电压(外侧电压)
  113. //0x0017 2 总电流 电池系统当前直流充放电电流
  114. //0x0018 2 SOC 电池系统当前 SOC 数据
  115. //0x0019 2 SOH 电池系统当前 SOH 数据
  116. //0x001A 2 DOD 放电深度
  117. //0x001B 2 循环次数 电池系统累计循环次数
  118. //0x001C 2 总电压—内侧 电池系统当前直流累加电压数据
  119. //0x001D 2 单体最高电压值 电池系统当前单体最高电压
  120. //0x001E 2 单体最低电压值 电池系统当前单体最低电压
  121. //0x001F 2 单体平均电压 电池系统当前单体平均电压
  122. var response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(0x0016, 10),
  123. (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage;
  124. if (response == null)
  125. throw new TimeoutException("long time no see incoming response for reg address starts from 0x0016 of 10 count");
  126. //0.1V
  127. var 总电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Take(2).Reverse().ToArray()))) / 10;
  128. //0.1A
  129. var 总电流 = ((decimal)(BitConverter.ToInt16(response.InnerRawData.Skip(2).Take(2).Reverse().ToArray()))) / 10;
  130. //0.1%
  131. var SOC = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(4).Take(2).Reverse().ToArray()))) / 10;
  132. //0.1%
  133. var SOH = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(6).Take(2).Reverse().ToArray()))) / 10;
  134. //0.1%
  135. var DOD = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(8).Take(2).Reverse().ToArray()))) / 10;
  136. var 电池系统累计循环次数 = BitConverter.ToUInt16(response.InnerRawData.Skip(10).Take(2).Reverse().ToArray());
  137. //0.1V
  138. var 电池系统当前直流累加电压数据 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(12).Take(2).Reverse().ToArray()))) / 10;
  139. //0.1V
  140. var 电池系统当前单体最高电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(14).Take(2).Reverse().ToArray()))) / 10;
  141. //0.1V
  142. var 电池系统当前单体最低电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(16).Take(2).Reverse().ToArray()))) / 10;
  143. //0.1V
  144. var 电池系统当前单体平均电压 = ((decimal)(BitConverter.ToUInt16(response.InnerRawData.Skip(18).Take(2).Reverse().ToArray()))) / 10;
  145. //寄存器地址 字节数 含义 备注
  146. //0x0200 2 系统充放电状态 0:正常 1:禁充 2:禁放 3:待机
  147. //0x0201 2 充放电计划1使能 0:禁用 1:使能
  148. //0x0202 2 充放电计划1模式 0:待机 1:充电 2:放电
  149. //0x0203 2 充放电计划1起始时间 高字节小时数 0 - 23 低字节分钟数 0 - 59
  150. //0x0204 2 充放电计划1终止时间 高字节小时数 0 - 23 低字节分钟数 0 - 59
  151. //0x0205 2 充放电计划1有功功率 Kw
  152. //0x0206 2 充放电计划2使能 0:禁用 1:使能
  153. //0x0207 2 充放电计划2模式 0:待机 1:充电 2:放电
  154. //0x0208 2 充放电计划2起始时间 高字节小时数 0 - 23 低字节分钟数 0 - 59
  155. //0x0209 2 充放电计划2终止时间 高字节小时数 0 - 23 低字节分钟数 0 - 59
  156. //0x020A 2 充放电计划2有功功率 Kw
  157. response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(0x0200, 11),
  158. (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage;
  159. if (response == null)
  160. throw new TimeoutException("long time no see incoming response for reg address starts from 0x0200 of 11 count");
  161. var 系统充放电状态 = "???undefined???";
  162. var __系统充放电状态value = BitConverter.ToInt16(response.InnerRawData.Take(2).Reverse().ToArray());
  163. if (__系统充放电状态value == 0)
  164. 系统充放电状态 = "正常";
  165. else if (__系统充放电状态value == 1)
  166. 系统充放电状态 = "禁充";
  167. else if (__系统充放电状态value == 2)
  168. 系统充放电状态 = "禁放";
  169. else if (__系统充放电状态value == 3)
  170. 系统充放电状态 = "待机";
  171. var 充放电计划1使能 = BitConverter.ToInt16(response.InnerRawData.Skip(2).Take(2).Reverse().ToArray()) == 0 ? "禁用" : "使能";
  172. var __充放电计划1模式value = BitConverter.ToInt16(response.InnerRawData.Skip(4).Take(2).Reverse().ToArray());
  173. var 充放电计划1模式 = __充放电计划1模式value == 0 ? "待机" : (__充放电计划1模式value == 1 ? "充电" : "放电");
  174. var 充放电计划1起始时间_分钟数 = response.InnerRawData.Skip(6).First();
  175. var 充放电计划1起始时间_小时数 = response.InnerRawData.Skip(7).First();
  176. var 充放电计划1终止时间_分钟数 = response.InnerRawData.Skip(8).First();
  177. var 充放电计划1终止时间_小时数 = response.InnerRawData.Skip(9).First();
  178. var 充放电计划1有功功率 = ((decimal)(BitConverter.ToInt16(response.InnerRawData.Skip(10).Take(2).Reverse().ToArray()))) / 10;
  179. var 充放电计划2使能 = BitConverter.ToInt16(response.InnerRawData.Skip(12).Take(2).Reverse().ToArray()) == 0 ? "禁用" : "使能";
  180. var __充放电计划2模式value = BitConverter.ToInt16(response.InnerRawData.Skip(14).Take(2).Reverse().ToArray());
  181. var 充放电计划2模式 = __充放电计划1模式value == 0 ? "待机" : (__充放电计划1模式value == 1 ? "充电" : "放电");
  182. var 充放电计划2起始时间_分钟数 = response.InnerRawData.Skip(16).First();
  183. var 充放电计划2起始时间_小时数 = response.InnerRawData.Skip(17).First();
  184. var 充放电计划2终止时间_分钟数 = response.InnerRawData.Skip(18).First();
  185. var 充放电计划2终止时间_小时数 = response.InnerRawData.Skip(19).First();
  186. var 充放电计划2有功功率 = ((decimal)(BitConverter.ToInt16(response.InnerRawData.Skip(20).Take(2).Reverse().ToArray()))) / 10;
  187. //寄存器地址 字节数 含义 备注
  188. //0x0230 2 系统时钟:年 数据范围:2000 - 2099
  189. //0x0231 2 系统时钟:月 数据范围:1 - 12
  190. //0x0232 2 系统时钟:日 数据范围:1 - 31
  191. //0x0233 2 系统时钟:时 数据范围:0 - 23
  192. //0x0234 2 系统时钟:分 数据范围:0 - 59
  193. //0x0235 2 系统时钟:秒 数据范围:0 - 5
  194. response = await this.context.Outgoing.WriteAsync(new OutgoingQueryMessage(0x0230, 6),
  195. (_, testResponse) => testResponse is IncomingMessage, 6000) as IncomingMessage;
  196. if (response == null)
  197. throw new TimeoutException("long time no see incoming response for reg address starts from 0x0230 of 6 count");
  198. var 系统时钟_年 = BitConverter.ToUInt16(response.InnerRawData.Take(2).Reverse().ToArray());
  199. var 系统时钟_月 = BitConverter.ToUInt16(response.InnerRawData.Skip(2).Take(2).Reverse().ToArray());
  200. var 系统时钟_日 = BitConverter.ToUInt16(response.InnerRawData.Skip(4).Take(2).Reverse().ToArray());
  201. var 系统时钟_时 = BitConverter.ToUInt16(response.InnerRawData.Skip(6).Take(2).Reverse().ToArray());
  202. var 系统时钟_分 = BitConverter.ToUInt16(response.InnerRawData.Skip(8).Take(2).Reverse().ToArray());
  203. var 系统时钟_秒 = BitConverter.ToUInt16(response.InnerRawData.Skip(10).Take(2).Reverse().ToArray());
  204. return new
  205. {
  206. 总电压,
  207. 总电流,
  208. SOC,
  209. SOH,
  210. DOD,
  211. 电池系统累计循环次数,
  212. 电池系统当前直流累加电压数据,
  213. 电池系统当前单体最高电压,
  214. 电池系统当前单体最低电压,
  215. 电池系统当前单体平均电压,
  216. 系统充放电状态,
  217. 充放电计划1使能,
  218. 充放电计划1模式,
  219. 充放电计划1起始时间_分钟数,
  220. 充放电计划1起始时间_小时数,
  221. 充放电计划1终止时间_分钟数,
  222. 充放电计划1终止时间_小时数,
  223. 充放电计划1有功功率,
  224. 充放电计划2使能,
  225. 充放电计划2模式,
  226. 充放电计划2起始时间_分钟数,
  227. 充放电计划2起始时间_小时数,
  228. 充放电计划2终止时间_分钟数,
  229. 充放电计划2终止时间_小时数,
  230. 充放电计划2有功功率,
  231. 系统时钟_年,
  232. 系统时钟_月,
  233. 系统时钟_日,
  234. 系统时钟_时,
  235. 系统时钟_分,
  236. 系统时钟_秒
  237. };
  238. }
  239. }
  240. }