Skip to content

Commit ac5beae

Browse files
committed
add .NET example
1 parent 6df0802 commit ac5beae

13 files changed

+3169
-0
lines changed

examples/dotnet/.gitignore

Lines changed: 428 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
12+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
13+
<PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1" />
14+
<PackageReference Include="System.ServiceModel.Primitives" Version="4.10.2" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
Copyright 2021 Microsoft Corporation
3+
*/
4+
5+
using System.Text;
6+
using System.Reflection;
7+
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Converters;
9+
using Newtonsoft.Json.Linq;
10+
using RabbitMQ.Client;
11+
using OCPPCentralSystem.Models;
12+
using OCPPCentralSystem.Schemas.OCPP16;
13+
using System;
14+
15+
namespace OCPPCentralSystem.Controllers
16+
{
17+
public class CSMSMiddlewareOCPP16 : I_OCPP_CentralSystemService_16
18+
{
19+
private int _transactionNumber = 0;
20+
private readonly IModel _channel;
21+
private readonly string _exchangeName;
22+
private readonly JsonSerializer _serializer;
23+
24+
public CSMSMiddlewareOCPP16(IModel channel, string exchangeName)
25+
{
26+
_channel = channel;
27+
_exchangeName = exchangeName;
28+
29+
var settings = new JsonSerializerSettings();
30+
settings.Converters.Add(new StringEnumConverter());
31+
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
32+
_serializer = JsonSerializer.Create(settings);
33+
}
34+
35+
public void ProcessRequest(RequestPayload request, string routingKey)
36+
{
37+
try
38+
{
39+
object responsePayload = null;
40+
41+
// Use reflection to find the method on the service interface
42+
var method = typeof(I_OCPP_CentralSystemService_16).GetMethod(request.Action);
43+
44+
if (method != null)
45+
{
46+
var parameters = method.GetParameters();
47+
if (parameters.Length == 1)
48+
{
49+
var paramType = parameters[0].ParameterType;
50+
var requestObj = request.Payload.ToObject(paramType, _serializer);
51+
52+
// Inject chargeBoxIdentity if the property exists
53+
var chargeBoxIdentityField = paramType.GetField("chargeBoxIdentity");
54+
if (chargeBoxIdentityField != null)
55+
{
56+
chargeBoxIdentityField.SetValue(requestObj, routingKey);
57+
}
58+
59+
responsePayload = method.Invoke(this, new object[] { requestObj });
60+
}
61+
else
62+
{
63+
Console.WriteLine($"Method ${request.Action} has unexpected number of parameters.");
64+
}
65+
}
66+
else
67+
{
68+
Console.WriteLine($"Unknown action: ${request.Action}");
69+
}
70+
71+
if (responsePayload != null)
72+
{
73+
var response = new ResponsePayload(request.UniqueId, responsePayload);
74+
response.Payload = JObject.FromObject(responsePayload, _serializer);
75+
response.WrappedPayload = new JArray { response.MessageTypeId, response.UniqueId, response.Payload };
76+
77+
SendResponse(response, routingKey);
78+
}
79+
}
80+
catch (Exception ex)
81+
{
82+
Console.WriteLine($"Error processing message: ${ex}");
83+
}
84+
}
85+
86+
private void SendResponse(ResponsePayload response, string id)
87+
{
88+
var message = response.WrappedPayload.ToString(Formatting.None);
89+
Console.WriteLine($"${id}: send ${message}");
90+
var body = Encoding.UTF8.GetBytes(message);
91+
92+
var properties = _channel.CreateBasicProperties();
93+
properties.ContentType = "application/json";
94+
properties.Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
95+
properties.CorrelationId = response.UniqueId;
96+
97+
_channel.BasicPublish(exchange: _exchangeName,
98+
routingKey: id,
99+
basicProperties: properties,
100+
body: body);
101+
}
102+
103+
public AuthorizeResponse Authorize(AuthorizeRequest request)
104+
{
105+
Console.WriteLine("Authorization requested on chargepoint " + request.chargeBoxIdentity + " and badge ID " + request.idTag);
106+
107+
IdTagInfo info = new IdTagInfo
108+
{
109+
expiryDateSpecified = false,
110+
status = AuthorizationStatus.Accepted
111+
};
112+
113+
return new AuthorizeResponse(info);
114+
}
115+
116+
public BootNotificationResponse BootNotification(BootNotificationRequest request)
117+
{
118+
Console.WriteLine("Chargepoint with identity: " + request.chargeBoxIdentity + " booted!");
119+
return new BootNotificationResponse(RegistrationStatus.Accepted, DateTime.UtcNow, 60);
120+
}
121+
122+
public HeartbeatResponse Heartbeat(HeartbeatRequest request)
123+
{
124+
Console.WriteLine("Heartbeat received from: " + request.chargeBoxIdentity);
125+
return new HeartbeatResponse(DateTime.UtcNow);
126+
}
127+
128+
public MeterValuesResponse MeterValues(MeterValuesRequest request)
129+
{
130+
Console.WriteLine("Meter values for connector ID " + request.connectorId + " on chargepoint " + request.chargeBoxIdentity + ":");
131+
foreach (MeterValue meterValue in request.meterValue)
132+
{
133+
foreach (SampledValue sampledValue in meterValue.sampledValue)
134+
{
135+
Console.WriteLine("Value: " + sampledValue.value + " " + sampledValue.unit.ToString());
136+
}
137+
}
138+
return new MeterValuesResponse();
139+
}
140+
141+
public StartTransactionResponse StartTransaction(StartTransactionRequest request)
142+
{
143+
Console.WriteLine("Start transaction " + _transactionNumber.ToString() + " from " + request.timestamp + " on chargepoint " + request.chargeBoxIdentity + " on connector " + request.connectorId + " with badge ID " + request.idTag + " and meter reading at start " + request.meterStart);
144+
_transactionNumber++;
145+
146+
IdTagInfo info = new IdTagInfo
147+
{
148+
expiryDateSpecified = false,
149+
status = AuthorizationStatus.Accepted
150+
};
151+
152+
return new StartTransactionResponse(_transactionNumber, info);
153+
}
154+
155+
public StopTransactionResponse StopTransaction(StopTransactionRequest request)
156+
{
157+
Console.WriteLine("Stop transaction " + request.transactionId.ToString() + " from " + request.timestamp + " on chargepoint " + request.chargeBoxIdentity + " with badge ID " + request.idTag + " and meter reading at stop " + request.meterStop);
158+
159+
IdTagInfo info = new IdTagInfo
160+
{
161+
expiryDateSpecified = false,
162+
status = AuthorizationStatus.Accepted
163+
};
164+
165+
return new StopTransactionResponse(info);
166+
}
167+
168+
public StatusNotificationResponse StatusNotification(StatusNotificationRequest request)
169+
{
170+
Console.WriteLine("Chargepoint " + request.chargeBoxIdentity + " and connector " + request.connectorId + " status#: " + request.status.ToString());
171+
return new StatusNotificationResponse();
172+
}
173+
174+
public DataTransferResponse DataTransfer(DataTransferRequest request)
175+
{
176+
return new DataTransferResponse(DataTransferStatus.Rejected, string.Empty);
177+
}
178+
179+
public DiagnosticsStatusNotificationResponse DiagnosticsStatusNotification(DiagnosticsStatusNotificationRequest request)
180+
{
181+
return new DiagnosticsStatusNotificationResponse();
182+
}
183+
184+
public FirmwareStatusNotificationResponse FirmwareStatusNotification(FirmwareStatusNotificationRequest request)
185+
{
186+
return new FirmwareStatusNotificationResponse();
187+
}
188+
}
189+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
Copyright 2020 Cognizant
3+
Copyright 2021 Microsoft Corporation
4+
*/
5+
6+
using Newtonsoft.Json.Linq;
7+
8+
namespace OCPPCentralSystem.Models
9+
{
10+
public class BasePayload
11+
{
12+
public int MessageTypeId { get; set; }
13+
14+
public string UniqueId { get; set; }
15+
16+
public JObject Payload { get; set; }
17+
18+
public JArray WrappedPayload { get; set; }
19+
}
20+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2020 Cognizant
3+
Copyright 2021 Microsoft Corporation
4+
*/
5+
6+
using Newtonsoft.Json.Linq;
7+
8+
namespace OCPPCentralSystem.Models
9+
{
10+
public class ErrorPayload : BasePayload
11+
{
12+
public string ErrorCode { get; set; }
13+
14+
public string ErrorDescription { get; set; }
15+
16+
public new JArray WrappedPayload => new JArray() { MessageTypeId, UniqueId, ErrorCode, ErrorDescription, Payload };
17+
18+
public ErrorPayload(string uniqueId)
19+
{
20+
MessageTypeId = 4;
21+
UniqueId = uniqueId;
22+
}
23+
24+
public ErrorPayload(string uniqueId,string errorCode)
25+
{
26+
MessageTypeId = 4;
27+
UniqueId = uniqueId;
28+
ErrorCode = errorCode;
29+
ErrorDescription = "";
30+
Payload = JObject.FromObject("");
31+
}
32+
33+
public ErrorPayload(JArray payload)
34+
{
35+
MessageTypeId = int.Parse(payload[0].ToString());
36+
UniqueId = payload[1].ToString();
37+
ErrorCode = payload[2].ToString();
38+
ErrorDescription = payload[3].ToString();
39+
Payload = (JObject)payload[4];
40+
}
41+
}
42+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright 2020 Cognizant
3+
Copyright 2021 Microsoft Corporation
4+
*/
5+
6+
using System.Collections.Generic;
7+
using Newtonsoft.Json.Schema;
8+
9+
namespace OCPPCentralSystem.Models
10+
{
11+
public class JsonValidationResponse
12+
{
13+
public bool Valid { get; set; }
14+
15+
public List<ValidationError> Errors { get; set; }
16+
17+
public string CustomErrors { get; set; }
18+
}
19+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2020 Cognizant
3+
Copyright 2021 Microsoft Corporation
4+
*/
5+
6+
using Newtonsoft.Json;
7+
8+
namespace OCPPCentralSystem.Models
9+
{
10+
public class LogPayload
11+
{
12+
public bool IsRequest { get; set; }
13+
public string Command { get; set; }
14+
public int StationChargerId { get; set; }
15+
public string Input { get; set; }
16+
17+
public LogPayload(RequestPayload requestPayload,string chargepointName)
18+
{
19+
IsRequest=true;
20+
Command=requestPayload.Action;
21+
StationChargerId=int.Parse(chargepointName);
22+
Input= JsonConvert.SerializeObject(requestPayload.Payload);
23+
}
24+
25+
public LogPayload(string command,ErrorPayload errorPayload,string chargepointName)
26+
{
27+
IsRequest=false;
28+
Command=command;
29+
StationChargerId=int.Parse(chargepointName);
30+
Input= JsonConvert.SerializeObject(errorPayload.Payload);
31+
}
32+
33+
public LogPayload(string command,ResponsePayload responsePayload,string stationChargerId)
34+
{
35+
IsRequest=false;
36+
Command=command;
37+
StationChargerId=int.Parse(stationChargerId);
38+
Input=JsonConvert.SerializeObject(responsePayload.Payload);
39+
}
40+
}
41+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2020 Cognizant
3+
Copyright 2021 Microsoft Corporation
4+
*/
5+
6+
using Newtonsoft.Json.Linq;
7+
8+
namespace OCPPCentralSystem.Models
9+
{
10+
public class RequestPayload : BasePayload
11+
{
12+
public string Action { get; set; } = string.Empty;
13+
14+
public RequestPayload(JArray payload)
15+
{
16+
MessageTypeId = (int)(payload[0]);
17+
UniqueId = payload[1].ToString();
18+
Action = payload[2].ToString();
19+
Payload = (JObject)payload[3];
20+
}
21+
22+
public RequestPayload(object payload)
23+
{
24+
JObject request = JObject.FromObject(payload);
25+
MessageTypeId = (int)request.GetValue("MessageTypeId");
26+
UniqueId = request.GetValue("UniqueId").ToString();
27+
Action = request.GetValue("Action").ToString();
28+
Payload = (JObject)request.GetValue("Payload");
29+
}
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Copyright 2020 Cognizant
3+
Copyright 2021 Microsoft Corporation
4+
*/
5+
6+
using Newtonsoft.Json.Linq;
7+
8+
namespace OCPPCentralSystem.Models
9+
{
10+
public class ResponsePayload : BasePayload
11+
{
12+
public ResponsePayload(string uniqueId, object payload)
13+
{
14+
MessageTypeId = 3;
15+
UniqueId = uniqueId;
16+
Payload = JObject.FromObject(payload);
17+
WrappedPayload = new JArray { MessageTypeId, UniqueId, Payload };
18+
}
19+
20+
public ResponsePayload(JArray payload)
21+
{
22+
MessageTypeId = int.Parse(payload[0].ToString());
23+
UniqueId = payload[1].ToString();
24+
Payload = (JObject)payload[2];
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)