public string HandleBootNotification(OCPPMessage msgIn, OCPPMessage msgOut) { string errorCode = null; string bootReason = null; try { Logger.LogTrace("Processing boot notification..."); BootNotificationRequest bootNotificationRequest = JsonConvert.DeserializeObject <BootNotificationRequest>(msgIn.JsonPayload); Logger.LogTrace("BootNotification => Message deserialized"); bootReason = bootNotificationRequest?.Reason.ToString(); Logger.LogInformation("BootNotification => Reason={0}", bootReason); BootNotificationResponse bootNotificationResponse = new BootNotificationResponse(); bootNotificationResponse.CurrentTime = DateTimeOffset.UtcNow; bootNotificationResponse.Interval = 300; // 300 seconds bootNotificationResponse.StatusInfo = new StatusInfoType(); bootNotificationResponse.StatusInfo.ReasonCode = string.Empty; bootNotificationResponse.StatusInfo.AdditionalInfo = string.Empty; bootNotificationResponse.CustomData = new CustomDataType(); bootNotificationResponse.CustomData.VendorId = VendorId; if (ChargePointStatus != null) { // Known charge station => accept bootNotificationResponse.Status = RegistrationStatusEnumType.Accepted; } else { // Unknown charge station => reject bootNotificationResponse.Status = RegistrationStatusEnumType.Rejected; } msgOut.JsonPayload = JsonConvert.SerializeObject(bootNotificationResponse); Logger.LogTrace("BootNotification => Response serialized"); } catch (Exception exp) { Logger.LogError(exp, "BootNotification => Exception: {0}", exp.Message); errorCode = ErrorCodes.FormationViolation; } WriteMessageLog(ChargePointStatus.Id, null, msgIn.Action, bootReason, errorCode); return(errorCode); }
public string HandleBootNotification(OCPPMessage msgIn, OCPPMessage msgOut) { string errorCode = null; try { Logger.LogTrace("Processing boot notification..."); BootNotificationRequest bootNotificationRequest = JsonConvert.DeserializeObject <BootNotificationRequest>(msgIn.JsonPayload); Logger.LogTrace("BootNotification => Message deserialized"); BootNotificationResponse bootNotificationResponse = new BootNotificationResponse(); bootNotificationResponse.CurrentTime = DateTimeOffset.UtcNow; bootNotificationResponse.Interval = 300; // 300 seconds if (ChargePointStatus != null) { // Known charge station => accept bootNotificationResponse.Status = BootNotificationResponseStatus.Accepted; } else { // Unknown charge station => reject bootNotificationResponse.Status = BootNotificationResponseStatus.Rejected; } msgOut.JsonPayload = JsonConvert.SerializeObject(bootNotificationResponse); Logger.LogTrace("BootNotification => Response serialized"); } catch (Exception exp) { Logger.LogError(exp, "BootNotification => Exception: {0}", exp.Message); errorCode = ErrorCodes.FormationViolation; } WriteMessageLog(ChargePointStatus.Id, null, msgIn.Action, null, errorCode); return(errorCode); }
/// <summary> /// Process all text messages of this web socket API. /// </summary> /// <param name="RequestTimestamp">The timestamp of the request.</param> /// <param name="Connection">The web socket connection.</param> /// <param name="EventTrackingId">The event tracking identification.</param> /// <param name="CancellationToken">The cancellation token.</param> /// <param name="TextMessage">The received text message.</param> protected async Task <WebSocketTextMessageRespose> ProcessTextMessages(DateTime RequestTimestamp, WebSocketConnection Connection, EventTracking_Id EventTrackingId, CancellationToken CancellationToken, String TextMessage) { JArray JSON = null; WSErrorMessage ErrorMessage = null; try { JSON = JArray.Parse(TextMessage?.Trim()); #region MessageType 2: CALL (Client-to-Server) // [ // 2, // MessageType: CALL (Client-to-Server) // "19223201", // RequestId // "BootNotification", // Action // { // "chargePointVendor": "VendorX", // "chargePointModel": "SingleSocketCharger" // } // ] if (JSON.Count == 4 && JSON[0].Type == JTokenType.Integer && JSON[0].Value <Byte>() == 2 && JSON[1].Type == JTokenType.String && JSON[2].Type == JTokenType.String && JSON[3].Type == JTokenType.Object) { #region Initial checks var RequestId = JSON[1].Value <String>()?.Trim(); var Action = JSON[2].Value <String>()?.Trim(); var RequestData = JSON[3].Value <JObject>(); if (RequestId.IsNullOrEmpty()) { ErrorMessage = new WSErrorMessage( RequestId, WSErrorCodes.ProtocolError, "The given 'request identification' must not be null or empty!", new JObject( new JProperty("request", TextMessage) )); } else if (Action.IsNullOrEmpty()) { ErrorMessage = new WSErrorMessage( RequestId, WSErrorCodes.ProtocolError, "The given 'action' must not be null or empty!", new JObject( new JProperty("request", TextMessage) )); } #endregion else { JObject OCPPResponseJSON = null; switch (Action) { #region BootNotification case "BootNotification": { #region Send OnBootNotificationWSRequest event try { //OnBootNotificationSOAPRequest?.Invoke(DateTime.UtcNow, // SOAPServer.HTTPServer, // Request); } catch (Exception e) { e.Log(nameof(CentralSystemSOAPServer) + "." + nameof(OnBootNotificationSOAPRequest)); } #endregion BootNotificationResponse response = null; try { if (BootNotificationRequest.TryParse(RequestData, out BootNotificationRequest bootNotificationRequest)) { #region Send OnBootNotificationRequest event try { OnBootNotificationRequest?.Invoke(bootNotificationRequest.RequestTimestamp, this, EventTrackingId, ChargeBox_Id.Parse("123"), //OCPPHeader.ChargeBoxIdentity, bootNotificationRequest.ChargePointVendor, bootNotificationRequest.ChargePointModel, bootNotificationRequest.ChargePointSerialNumber, bootNotificationRequest.ChargeBoxSerialNumber, bootNotificationRequest.FirmwareVersion, bootNotificationRequest.Iccid, bootNotificationRequest.IMSI, bootNotificationRequest.MeterType, bootNotificationRequest.MeterSerialNumber); } catch (Exception e) { e.Log(nameof(CentralSystemSOAPServer) + "." + nameof(OnBootNotificationRequest)); } #endregion #region Call async subscribers if (response == null) { var results = OnBootNotification?. GetInvocationList()?. SafeSelect(subscriber => (subscriber as BootNotificationDelegate) (DateTime.UtcNow, this, CancellationToken, EventTrackingId, ChargeBox_Id.Parse("123"), //OCPPHeader.ChargeBoxIdentity, bootNotificationRequest)). ToArray(); if (results?.Length > 0) { await Task.WhenAll(results); response = results.FirstOrDefault()?.Result; } if (results == null || response == null) { response = BootNotificationResponse.Failed(bootNotificationRequest); } } #endregion #region Send OnBootNotificationResponse event try { OnBootNotificationResponse?.Invoke(response.ResponseTimestamp, this, EventTrackingId, ChargeBox_Id.Parse("123"), //OCPPHeader.ChargeBoxIdentity, bootNotificationRequest.ChargePointVendor, bootNotificationRequest.ChargePointModel, bootNotificationRequest.ChargePointSerialNumber, bootNotificationRequest.ChargeBoxSerialNumber, bootNotificationRequest.FirmwareVersion, bootNotificationRequest.Iccid, bootNotificationRequest.IMSI, bootNotificationRequest.MeterType, bootNotificationRequest.MeterSerialNumber, response.Result, response.Status, response.CurrentTime, response.Interval, response.Runtime); } catch (Exception e) { e.Log(nameof(CentralSystemSOAPServer) + "." + nameof(OnBootNotificationResponse)); } #endregion OCPPResponseJSON = response.ToJSON(); } else { ErrorMessage = new WSErrorMessage(RequestId, WSErrorCodes.FormationViolation, "The given 'BootNotification' request could not be parsed!", new JObject( new JProperty("request", TextMessage) )); } } catch (Exception e) { ErrorMessage = new WSErrorMessage(RequestId, WSErrorCodes.FormationViolation, "Processing the given 'BootNotification' request led to an exception!", new JObject( new JProperty("request", TextMessage), new JProperty("exception", e.Message), new JProperty("stacktrace", e.StackTrace) )); } #region Send OnBootNotificationWSResponse event try { //OnBootNotificationSOAPResponse?.Invoke(HTTPResponse.Timestamp, // SOAPServer.HTTPServer, // Request, // HTTPResponse); } catch (Exception e) { e.Log(nameof(CentralSystemSOAPServer) + "." + nameof(OnBootNotificationSOAPResponse)); } #endregion } break; #endregion } if (OCPPResponseJSON != null) { return(new WebSocketTextMessageRespose(RequestTimestamp, TextMessage, DateTime.UtcNow, new WSResponseMessage(WSMessageTypes.CALLRESULT, RequestId, OCPPResponseJSON).ToJSON().ToString())); } } } #endregion #region MessageType 3: CALLRESULT (Server-to-Client) // [ // 3, // MessageType: CALLRESULT (Server-to-Client) // "19223201", // RequestId copied from request // { // "status": "Accepted", // "currentTime": "2013-02-01T20:53:32.486Z", // "heartbeatInterval": 300 // } // ] else if (JSON.Count == 3 && JSON[0].Type == JTokenType.Integer && JSON[0].Value <Byte>() == 3 && JSON[1].Type == JTokenType.String && JSON[2].Type == JTokenType.Object) { } #endregion #region MessageType 4: CALLERROR (Server-to-Client) // [ // 4, // MessageType: CALLERROR (Server-to-Client) // "19223201", // RequestId from request // "<errorCode>", // "<errorDescription>", // { // <errorDetails> // } // ] // Error Code Description // ----------------------------------------------------------------------------------------------- // NotImplemented Requested Action is not known by receiver // NotSupported Requested Action is recognized but not supported by the receiver // InternalError An internal error occurred and the receiver was not able to process the requested Action successfully // ProtocolError Payload for Action is incomplete // SecurityError During the processing of Action a security issue occurred preventing receiver from completing the Action successfully // FormationViolation Payload for Action is syntactically incorrect or not conform the PDU structure for Action // PropertyConstraintViolation Payload is syntactically correct but at least one field contains an invalid value // OccurenceConstraintViolation Payload for Action is syntactically correct but at least one of the fields violates occurence constraints // TypeConstraintViolation Payload for Action is syntactically correct but at least one of the fields violates data type constraints (e.g. “somestring”: 12) // GenericError Any other error not covered by the previous ones else if (JSON.Count == 5 && JSON[0].Type == JTokenType.Integer && JSON[0].Value <Byte>() == 4 && JSON[1].Type == JTokenType.String && JSON[2].Type == JTokenType.String && JSON[3].Type == JTokenType.String && JSON[4].Type == JTokenType.Object) { } #endregion else { ErrorMessage = new WSErrorMessage(JSON.Count >= 2 ? JSON[1].Value <String>()?.Trim() : "unknown", WSErrorCodes.FormationViolation, "The given OCPP request message is invalid!", new JObject( new JProperty("request", TextMessage) )); } } catch (Exception e) { ErrorMessage = new WSErrorMessage(JSON != null && JSON.Count >= 2 ? JSON?[1].Value <String>()?.Trim() : "Unknown request identification", WSErrorCodes.FormationViolation, "Processing the given OCPP request message led to an exception!", new JObject( new JProperty("request", TextMessage), new JProperty("exception", e.Message), new JProperty("stacktrace", e.StackTrace) )); } return(new WebSocketTextMessageRespose(RequestTimestamp, TextMessage, DateTime.UtcNow, ErrorMessage.ToJSON().ToString())); }