diff --git a/Port/dotnet/V2G/V2GMessageProcessor.cs b/Port/dotnet/V2G/V2GMessageProcessor.cs index ac6b225..d4f71d1 100644 --- a/Port/dotnet/V2G/V2GMessageProcessor.cs +++ b/Port/dotnet/V2G/V2GMessageProcessor.cs @@ -170,6 +170,55 @@ namespace V2GDecoderNet analysis.AppendLine(); analysis.Append(ParseChargeParameterDiscoveryResAnalysis(chargeParameterDiscoveryRes, ns3, ns4)); } + + // Phase 3: Extended Features - Message detection + var paymentServiceSelectionReq = body.Element(ns3 + "PaymentServiceSelectionReq"); + if (paymentServiceSelectionReq != null) + { + analysis.AppendLine("Message Type: PaymentServiceSelectionReq"); + analysis.AppendLine(); + analysis.Append(ParsePaymentServiceSelectionReqAnalysis(paymentServiceSelectionReq, ns3, ns4)); + } + + var paymentServiceSelectionRes = body.Element(ns3 + "PaymentServiceSelectionRes"); + if (paymentServiceSelectionRes != null) + { + analysis.AppendLine("Message Type: PaymentServiceSelectionRes"); + analysis.AppendLine(); + analysis.Append(ParsePaymentServiceSelectionResAnalysis(paymentServiceSelectionRes, ns3, ns4)); + } + + var chargingStatusReq = body.Element(ns3 + "ChargingStatusReq"); + if (chargingStatusReq != null) + { + analysis.AppendLine("Message Type: ChargingStatusReq"); + analysis.AppendLine(); + analysis.Append(ParseChargingStatusReqAnalysis(chargingStatusReq, ns3, ns4)); + } + + var chargingStatusRes = body.Element(ns3 + "ChargingStatusRes"); + if (chargingStatusRes != null) + { + analysis.AppendLine("Message Type: ChargingStatusRes"); + analysis.AppendLine(); + analysis.Append(ParseChargingStatusResAnalysis(chargingStatusRes, ns3, ns4)); + } + + var sessionStopReq = body.Element(ns3 + "SessionStopReq"); + if (sessionStopReq != null) + { + analysis.AppendLine("Message Type: SessionStopReq"); + analysis.AppendLine(); + analysis.Append(ParseSessionStopReqAnalysis(sessionStopReq, ns3, ns4)); + } + + var sessionStopRes = body.Element(ns3 + "SessionStopRes"); + if (sessionStopRes != null) + { + analysis.AppendLine("Message Type: SessionStopRes"); + analysis.AppendLine(); + analysis.Append(ParseSessionStopResAnalysis(sessionStopRes, ns3, ns4)); + } // Add other message types as needed } @@ -1309,6 +1358,212 @@ namespace V2GDecoderNet return analysis.ToString(); } + private static string ParsePaymentServiceSelectionReqAnalysis(XElement paymentServiceSelectionReq, XNamespace ns3, XNamespace ns4) + { + var analysis = new StringBuilder(); + analysis.AppendLine("πŸ’³ Payment Service Selection Request Analysis:"); + analysis.AppendLine(" Purpose: Select payment method for charging session"); + analysis.AppendLine(); + + var selectedPaymentOption = paymentServiceSelectionReq.Element(ns3 + "SelectedPaymentOption"); + if (selectedPaymentOption != null) + { + analysis.AppendLine($" πŸ†” Selected Payment Option: {selectedPaymentOption.Value}"); + string paymentType = selectedPaymentOption.Value switch + { + "Contract" => "πŸ”— Contract-based payment", + "ExternalPayment" => "πŸ’° External payment method", + _ => $"❓ Unknown ({selectedPaymentOption.Value})" + }; + analysis.AppendLine($" Type: {paymentType}"); + } + + var selectedServiceList = paymentServiceSelectionReq.Element(ns3 + "SelectedServiceList"); + if (selectedServiceList != null) + { + analysis.AppendLine(" πŸ“‹ Selected Service List:"); + var selectedServices = selectedServiceList.Elements(ns3 + "SelectedService"); + int serviceCount = 0; + foreach (var service in selectedServices) + { + serviceCount++; + var serviceId = service.Element(ns3 + "ServiceID"); + var parameterSetId = service.Element(ns3 + "ParameterSetID"); + + analysis.AppendLine($" {serviceCount}. Service ID: {serviceId?.Value}"); + if (parameterSetId != null) + analysis.AppendLine($" Parameter Set ID: {parameterSetId.Value}"); + } + + if (serviceCount == 0) + analysis.AppendLine(" No services selected"); + } + + analysis.AppendLine(" βœ… Payment service selection requested"); + return analysis.ToString(); + } + + private static string ParsePaymentServiceSelectionResAnalysis(XElement paymentServiceSelectionRes, XNamespace ns3, XNamespace ns4) + { + var analysis = new StringBuilder(); + analysis.AppendLine("πŸ’³ Payment Service Selection Response Analysis:"); + analysis.AppendLine(" Purpose: Confirm payment method selection"); + analysis.AppendLine(); + + var responseCode = paymentServiceSelectionRes.Element(ns3 + "ResponseCode"); + if (responseCode != null) + { + analysis.AppendLine($" πŸ“Š Response Code: {responseCode.Value}"); + string status = responseCode.Value switch + { + "OK" => "βœ… Payment selection accepted", + "OK_NewSessionEstablished" => "βœ… New session established", + "FAILED" => "❌ Payment selection failed", + _ => $"⚠️ Unknown ({responseCode.Value})" + }; + analysis.AppendLine($" Status: {status}"); + } + + analysis.AppendLine(" πŸ”„ Payment method selection completed"); + return analysis.ToString(); + } + + private static string ParseChargingStatusReqAnalysis(XElement chargingStatusReq, XNamespace ns3, XNamespace ns4) + { + var analysis = new StringBuilder(); + analysis.AppendLine("πŸ”‹ Charging Status Request Analysis:"); + analysis.AppendLine(" Purpose: Request AC charging status information"); + analysis.AppendLine(); + + analysis.AppendLine(" πŸ” Requesting current charging status from EVSE"); + analysis.AppendLine(" πŸ“Š Status inquiry for AC charging session"); + return analysis.ToString(); + } + + private static string ParseChargingStatusResAnalysis(XElement chargingStatusRes, XNamespace ns3, XNamespace ns4) + { + var analysis = new StringBuilder(); + analysis.AppendLine("πŸ”‹ Charging Status Response Analysis:"); + analysis.AppendLine(" Purpose: Provide AC charging status information"); + analysis.AppendLine(); + + var responseCode = chargingStatusRes.Element(ns3 + "ResponseCode"); + if (responseCode != null) + { + analysis.AppendLine($" πŸ“Š Response Code: {responseCode.Value}"); + string status = responseCode.Value switch + { + "OK" => "βœ… Success", + "OK_NewSessionEstablished" => "βœ… New session established", + "FAILED" => "❌ Failed", + _ => $"⚠️ Unknown ({responseCode.Value})" + }; + analysis.AppendLine($" Status: {status}"); + } + + var evseId = chargingStatusRes.Element(ns3 + "EVSEID"); + if (evseId != null) + { + analysis.AppendLine($" 🏭 EVSE ID: {evseId.Value}"); + } + + var saScheduleTupleId = chargingStatusRes.Element(ns3 + "SAScheduleTupleID"); + if (saScheduleTupleId != null) + { + analysis.AppendLine($" πŸ”Œ SA Schedule Tuple ID: {saScheduleTupleId.Value}"); + } + + var evseMaxCurrent = chargingStatusRes.Element(ns3 + "EVSEMaxCurrent"); + if (evseMaxCurrent != null) + { + var value = evseMaxCurrent.Element(ns4 + "Value"); + var unit = evseMaxCurrent.Element(ns4 + "Unit"); + var multiplier = evseMaxCurrent.Element(ns4 + "Multiplier"); + if (value != null) + analysis.AppendLine($" ⚑ EVSE Max Current: {value.Value} {GetUnitString(unit?.Value)} (10^{multiplier?.Value ?? "0"})"); + } + + var meterInfo = chargingStatusRes.Element(ns3 + "MeterInfo"); + if (meterInfo != null) + { + analysis.AppendLine(" πŸ“Š Meter Information:"); + + var meterId = meterInfo.Element(ns3 + "MeterID"); + if (meterId != null) + analysis.AppendLine($" πŸ†” Meter ID: {meterId.Value}"); + + var meterReading = meterInfo.Element(ns3 + "MeterReading"); + if (meterReading != null) + analysis.AppendLine($" πŸ“ Meter Reading: {meterReading.Value} Wh"); + + var sigMeterReading = meterInfo.Element(ns3 + "SigMeterReading"); + if (sigMeterReading != null) + analysis.AppendLine($" πŸ” Signed Meter Reading: [Length: {sigMeterReading.Value.Length}]"); + + var meterStatus = meterInfo.Element(ns3 + "MeterStatus"); + if (meterStatus != null) + analysis.AppendLine($" πŸ“Š Meter Status: {meterStatus.Value}"); + } + + var receiptRequired = chargingStatusRes.Element(ns3 + "ReceiptRequired"); + if (receiptRequired != null) + { + analysis.AppendLine($" 🧾 Receipt Required: {receiptRequired.Value}"); + } + + analysis.AppendLine(" βœ… AC charging status provided"); + return analysis.ToString(); + } + + private static string ParseSessionStopReqAnalysis(XElement sessionStopReq, XNamespace ns3, XNamespace ns4) + { + var analysis = new StringBuilder(); + analysis.AppendLine("πŸ›‘ Session Stop Request Analysis:"); + analysis.AppendLine(" Purpose: Request charging session termination"); + analysis.AppendLine(); + + var chargingSession = sessionStopReq.Element(ns3 + "ChargingSession"); + if (chargingSession != null) + { + analysis.AppendLine($" πŸ”„ Charging Session: {chargingSession.Value}"); + string sessionType = chargingSession.Value switch + { + "Terminate" => "βœ… Terminate - Session ending completely", + "Pause" => "⏸️ Pause - Session paused temporarily", + _ => $"⚠️ Unknown ({chargingSession.Value})" + }; + analysis.AppendLine($" Type: {sessionType}"); + } + + analysis.AppendLine(" πŸ›‘ Requesting session termination"); + return analysis.ToString(); + } + + private static string ParseSessionStopResAnalysis(XElement sessionStopRes, XNamespace ns3, XNamespace ns4) + { + var analysis = new StringBuilder(); + analysis.AppendLine("πŸ›‘ Session Stop Response Analysis:"); + analysis.AppendLine(" Purpose: Confirm charging session termination"); + analysis.AppendLine(); + + var responseCode = sessionStopRes.Element(ns3 + "ResponseCode"); + if (responseCode != null) + { + analysis.AppendLine($" πŸ“Š Response Code: {responseCode.Value}"); + string status = responseCode.Value switch + { + "OK" => "βœ… Session terminated successfully", + "OK_NewSessionEstablished" => "βœ… New session established", + "FAILED" => "❌ Session termination failed", + _ => $"⚠️ Unknown ({responseCode.Value})" + }; + analysis.AppendLine($" Status: {status}"); + } + + analysis.AppendLine(" πŸ”š Charging session terminated"); + return analysis.ToString(); + } + private static string GetUnitString(string? unitValue) { return unitValue switch