OCPP20MessageHandler.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using EVCB_OCPP.Packet.Messages;
  2. using EVCB_OCPP.Packet.Messages.Basic;
  3. using EVCB_OCPP.WSServer.Service.WsService;
  4. using EVCB_OCPP20.Packet.Features;
  5. using Microsoft.Extensions.Logging;
  6. using Newtonsoft.Json;
  7. using Newtonsoft.Json.Linq;
  8. using OCPPServer.Protocol;
  9. using System;
  10. using I20Confirmation = EVCB_OCPP20.Packet.Messages.IConfirmation;
  11. using I20Request = EVCB_OCPP20.Packet.Messages.IRequest;
  12. namespace EVCB_OCPP.WSServer.Message
  13. {
  14. /// <summary>
  15. /// 實現 OCPP20 基本傳送規範,
  16. /// 1.訊息 基本格式,將訊息包裝成 Call 、CallResult、CallError 三種格式
  17. /// 2.OCPP 定義的傳送規則:交易相關的訊息必須依照時序性傳送,一個傳完才能接著送下一個(忽略規則 由Center System定義)
  18. /// </summary>
  19. internal class OCPP20MessageHandler
  20. {
  21. static protected ILogger logger;
  22. #region 傳送 or 解析訊息需要欄位
  23. private const int INDEX_MESSAGEID = 0;
  24. private const int INDEX_UNIQUEID = 1;
  25. internal const int TYPENUMBER_CALL = 2;
  26. private const int INDEX_CALL_ACTION = 2;
  27. private const int INDEX_CALL_PAYLOAD = 3;
  28. internal const int TYPENUMBER_CALLRESULT = 3;
  29. private const int INDEX_CALLRESULT_PAYLOAD = 2;
  30. internal const int TYPENUMBER_CALLERROR = 4;
  31. private const int INDEX_CALLERROR_ERRORCODE = 2;
  32. private const int INDEX_CALLERROR_DESCRIPTION = 3;
  33. private const int INDEX_CALLERROR_PAYLOAD = 4;
  34. private const string CALL_FORMAT = "[2,\"{0}\",\"{1}\",{2}]";
  35. private const string CALLRESULT_FORMAT = "[3,\"{0}\",{1}]";
  36. private const string CALLERROR_FORMAT = "[4,\"{0}\",\"{1}\",\"{2}\",{3}]";
  37. private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
  38. private const string DATE_FORMAT_WITH_MS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
  39. #endregion
  40. /// <summary>
  41. /// 將收到的封包做基本的拆解分成 Call 、CallResult、CallError
  42. /// </summary>
  43. /// <param name="client"></param>
  44. /// <param name="data"></param>
  45. /// <returns></returns>
  46. internal MessageResult AnalysisReceiveData(WsClientData client, string data)
  47. {
  48. MessageResult result = new MessageResult();
  49. try
  50. {
  51. var msg = Parse(data);
  52. if (msg != null)
  53. {
  54. result.UUID = msg.Id;
  55. switch (msg.TypeId)
  56. {
  57. case TYPENUMBER_CALL:
  58. {
  59. //只有CallMessage 才有在RawData有Action
  60. BasicMessageResult baseResult = UnPackPayloadbyCall(msg.Action, msg.Payload.ToString());
  61. Actions action = Actions.None;
  62. Enum.TryParse<Actions>(msg.Action, out action);
  63. result.Action = msg.Action;
  64. if (baseResult.Request20 != null)
  65. {
  66. if (baseResult.Request20.Validate())
  67. {
  68. result.Id = TYPENUMBER_CALL;
  69. result.Message = baseResult.Request20;
  70. }
  71. else
  72. {
  73. string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
  74. OCPPErrorDescription.OccurenceConstraintViolation);
  75. result.Id = TYPENUMBER_CALL;
  76. result.Message = baseResult.Request20;
  77. result.Success = false;
  78. result.CallErrorMsg = replyMsg;
  79. result.Exception = new Exception("Validation Failed");
  80. }
  81. }
  82. else
  83. {
  84. string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation, OCPPErrorDescription.OccurenceConstraintViolation);
  85. result.Id = TYPENUMBER_CALL;
  86. result.Message = baseResult.Request20;
  87. result.Success = false;
  88. result.CallErrorMsg = replyMsg;
  89. result.Exception = baseResult.Exception;
  90. }
  91. }
  92. break;
  93. case TYPENUMBER_CALLRESULT:
  94. {
  95. BasicMessageResult baseResult = UnPackPayloadbyCallResult(client.queue20, msg.Id, msg.Payload.ToString());
  96. if (baseResult.Confirmation20 != null)
  97. {
  98. if (baseResult.Confirmation20.Validate())
  99. {
  100. result.Id = TYPENUMBER_CALLRESULT;
  101. result.Message = baseResult.Confirmation20;
  102. result.Action = baseResult.Confirmation20.GetRequest().Action;
  103. //return data
  104. }
  105. else
  106. {
  107. string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
  108. OCPPErrorDescription.OccurenceConstraintViolation);
  109. result.Id = TYPENUMBER_CALLRESULT;
  110. result.Message = baseResult.Confirmation20;
  111. result.Success = false;
  112. result.CallErrorMsg = replyMsg;
  113. result.Exception = new Exception("Validate Failed");
  114. }
  115. }
  116. else
  117. {
  118. string replyMsg = BasicMessageHandler.GenerateCallError(msg.Id, OCPPErrorCodes.OccurenceConstraintViolation.ToString(),
  119. OCPPErrorDescription.OccurenceConstraintViolation);
  120. result.Id = TYPENUMBER_CALLRESULT;
  121. result.Message = baseResult.Confirmation20;
  122. result.Success = false;
  123. result.CallErrorMsg = replyMsg;
  124. result.Exception = baseResult.Exception;
  125. }
  126. }
  127. break;
  128. case TYPENUMBER_CALLERROR:
  129. {
  130. result.Id = TYPENUMBER_CALLERROR;
  131. // var sentRequest = UnPackPayloadbyCallError(client.queue, msg.Id);
  132. //if (sentRequest != null)
  133. //{
  134. // I20Request request = sentRequest as I20Request;
  135. // result.Action = request.Action;
  136. // result.Message = sentRequest;
  137. // result.ReceivedErrorCode = string.Format("ErrorMsg {0}:{1}", ((CallErrorMessage)msg).ErrorCode, ((CallErrorMessage)msg).ErrorDescription);
  138. //}
  139. }
  140. break;
  141. default:
  142. break;
  143. }
  144. // if (msg != null) Console.WriteLine(string.Format("Receieved Message : {0}", msg.ToString()));
  145. }
  146. }
  147. catch (Exception ex)
  148. {
  149. if (string.IsNullOrEmpty(result.UUID))
  150. {
  151. result.UUID = data.Substring(4, 39);
  152. result.UUID = result.UUID.Split(new string[] { "\"," }, StringSplitOptions.None)[0];
  153. }
  154. result.Success = false;
  155. result.Exception = ex;
  156. }
  157. return result;
  158. }
  159. #region 解析收到的訊息
  160. /// <summary>
  161. /// Parse data to OCPP Basic Message
  162. /// </summary>
  163. /// <param name="message"></param>
  164. /// <returns></returns>
  165. private BaseMessage Parse(string message)
  166. {
  167. try
  168. {
  169. if (message.StartsWith("[4,\""))
  170. {
  171. message = message.Replace('{', '"');
  172. message = message.Replace('}', '"');
  173. }
  174. var array = JsonConvert.DeserializeObject<JArray>(message);
  175. BaseMessage msg = null;
  176. switch ((int)array[INDEX_MESSAGEID])
  177. {
  178. case TYPENUMBER_CALL:
  179. {
  180. CallMessage call = new CallMessage();
  181. call.Action = array[INDEX_CALL_ACTION].ToString();
  182. call.Payload = array[INDEX_CALL_PAYLOAD].ToString().Replace("\r\n", "");
  183. msg = call;
  184. }
  185. break;
  186. case TYPENUMBER_CALLRESULT:
  187. {
  188. CallResultMessage callResult = new CallResultMessage();
  189. callResult.Payload = array[INDEX_CALLRESULT_PAYLOAD].ToString().Replace("\r\n", "");
  190. msg = callResult;
  191. }
  192. break;
  193. case TYPENUMBER_CALLERROR:
  194. {
  195. CallErrorMessage callError = new CallErrorMessage();
  196. callError.ErrorCode = array[INDEX_CALLERROR_ERRORCODE].ToString();
  197. callError.ErrorDescription = array[INDEX_CALLERROR_DESCRIPTION].ToString();
  198. callError.ErrorDetails = array[INDEX_CALLERROR_PAYLOAD].ToString().Replace("\r\n", "");
  199. msg = callError;
  200. }
  201. break;
  202. default:
  203. throw new Exception("Message Type notSupported");
  204. }
  205. msg.Id = array[INDEX_UNIQUEID].ToString();
  206. return msg;
  207. }
  208. catch (Exception ex)
  209. {
  210. throw new Exception(string.Format("Parse Error=> {0} Problem: {0}", message, ex.Message));
  211. }
  212. }
  213. private BasicMessageResult UnPackPayloadbyCall(string action, string payload)
  214. {
  215. BasicMessageResult result = new BasicMessageResult();
  216. try
  217. {
  218. result.Request20 = (I20Request)(JsonConvert.DeserializeObject(payload, Type.GetType("EVCB_OCPP20.Packet.Messages." + action + "Request,EVCB_OCPP20.Packet")));
  219. }
  220. catch (Exception ex)
  221. {
  222. result.Exception = ex;
  223. logger.LogError(string.Format("[{0}]UnPackPayloadbyCall Ex: {1}", action, ex.Message), "UnPack");
  224. }
  225. return result;
  226. }
  227. private BasicMessageResult UnPackPayloadbyCallResult(EVCB_OCPP20.Packet.Messages.Basic.Queue requestQueue, string uniqueId, string payload)
  228. {
  229. BasicMessageResult result = new BasicMessageResult();
  230. try
  231. {
  232. I20Request request = requestQueue.RestoreRequest(uniqueId);
  233. I20Confirmation confrim = JsonConvert.DeserializeObject(payload, Type.GetType("EVCB_OCPP20.Packet.Messages." + request.Action + "Response,EVCB_OCPP20.Packet")) as I20Confirmation;
  234. confrim.SetRequest(request);
  235. result.Confirmation20 = confrim;
  236. }
  237. catch (Exception ex)
  238. {
  239. result.Exception = ex;
  240. logger.LogError(string.Format("UnPackPayloadbyCallResult Data:[{0},{1}] Ex: {2}", uniqueId, payload, ex.ToString()), "UnPack");
  241. }
  242. return result;
  243. }
  244. #endregion
  245. }
  246. }