Skip to content

Commit 6ecb834

Browse files
committed
feat: initial support for 2.1 (wip)
1 parent 706b7aa commit 6ecb834

File tree

3 files changed

+130
-76
lines changed

3 files changed

+130
-76
lines changed

ocpp/ocpp.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,5 @@ const (
120120
_ Dialect = iota
121121
V16
122122
V2
123+
V21
123124
)

ocppj/ocppj.go

Lines changed: 60 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
package ocppj
33

44
import (
5-
"bytes"
65
"encoding/json"
76
"fmt"
8-
"math/rand"
9-
"reflect"
10-
117
"github.com/lorenzodonini/ocpp-go/logging"
8+
"math/rand"
129

1310
"gopkg.in/go-playground/validator.v9"
1411

@@ -65,9 +62,11 @@ func SetMessageValidation(enabled bool) {
6562
type MessageType int
6663

6764
const (
68-
CALL MessageType = 2
69-
CALL_RESULT MessageType = 3
70-
CALL_ERROR MessageType = 4
65+
CALL MessageType = 2
66+
CALL_RESULT MessageType = 3
67+
CALL_ERROR MessageType = 4
68+
CALL_RESULT_ERROR MessageType = 5
69+
SEND MessageType = 6
7170
)
7271

7372
// An OCPP-J message.
@@ -183,12 +182,41 @@ func (callError *CallError) MarshalJSON() ([]byte, error) {
183182
return ocppMessageToJson(fields)
184183
}
185184

185+
// -------------------- Call --------------------
186+
187+
// An OCPP-J SEND message, containing an OCPP Request.
188+
type Send struct {
189+
Message `validate:"-"`
190+
MessageTypeId MessageType `json:"messageTypeId" validate:"required,eq=2"`
191+
UniqueId string `json:"uniqueId" validate:"required,max=36"`
192+
Action string `json:"action" validate:"required,max=36"`
193+
Payload ocpp.Request `json:"payload" validate:"required"`
194+
}
195+
196+
func (call *Send) GetMessageTypeId() MessageType {
197+
return call.MessageTypeId
198+
}
199+
200+
func (call *Send) GetUniqueId() string {
201+
return call.UniqueId
202+
}
203+
204+
func (call *Send) MarshalJSON() ([]byte, error) {
205+
fields := make([]interface{}, 4)
206+
fields[0] = int(call.MessageTypeId)
207+
fields[1] = call.UniqueId
208+
fields[2] = call.Action
209+
fields[3] = call.Payload
210+
return jsonMarshal(fields)
211+
}
212+
186213
const (
187214
NotImplemented ocpp.ErrorCode = "NotImplemented" // Requested Action is not known by receiver.
188215
NotSupported ocpp.ErrorCode = "NotSupported" // Requested Action is recognized but not supported by the receiver.
189216
InternalError ocpp.ErrorCode = "InternalError" // An internal error occurred and the receiver was not able to process the requested Action successfully.
190217
MessageTypeNotSupported ocpp.ErrorCode = "MessageTypeNotSupported" // A message with a Message Type Number received that is not supported by this implementation.
191218
ProtocolError ocpp.ErrorCode = "ProtocolError" // Payload for Action is incomplete.
219+
RpcFrameworkError ocpp.ErrorCode = "RpcFrameworkError" // Content of the call is not a valid RPC Request, for example: MessageId could not be read.
192220
SecurityError ocpp.ErrorCode = "SecurityError" // During the processing of Action a security issue occurred preventing receiver from completing the Action successfully.
193221
PropertyConstraintViolation ocpp.ErrorCode = "PropertyConstraintViolation" // Payload is syntactically correct but at least one field contains an invalid value.
194222
OccurrenceConstraintViolationV2 ocpp.ErrorCode = "OccurrenceConstraintViolation" // Payload for Action is syntactically correct but at least one of the fields violates occurrence constraints.
@@ -207,7 +235,7 @@ func FormatErrorType(d dialector) ocpp.ErrorCode {
207235
switch d.Dialect() {
208236
case ocpp.V16:
209237
return FormatViolationV16
210-
case ocpp.V2:
238+
case ocpp.V2, ocpp.V21:
211239
return FormatViolationV2
212240
default:
213241
panic(fmt.Sprintf("invalid dialect: %v", d))
@@ -218,7 +246,7 @@ func OccurrenceConstraintErrorType(d dialector) ocpp.ErrorCode {
218246
switch d.Dialect() {
219247
case ocpp.V16:
220248
return OccurrenceConstraintViolationV16
221-
case ocpp.V2:
249+
case ocpp.V2, ocpp.V21:
222250
return OccurrenceConstraintViolationV2
223251
default:
224252
panic(fmt.Sprintf("invalid dialect: %v", d))
@@ -228,32 +256,17 @@ func OccurrenceConstraintErrorType(d dialector) ocpp.ErrorCode {
228256
func IsErrorCodeValid(fl validator.FieldLevel) bool {
229257
code := ocpp.ErrorCode(fl.Field().String())
230258
switch code {
231-
case NotImplemented, NotSupported, InternalError, MessageTypeNotSupported, ProtocolError, SecurityError, FormatViolationV16, FormatViolationV2, PropertyConstraintViolation, OccurrenceConstraintViolationV16, OccurrenceConstraintViolationV2, TypeConstraintViolation, GenericError:
259+
case NotImplemented, NotSupported, InternalError, MessageTypeNotSupported,
260+
ProtocolError, SecurityError, FormatViolationV16, FormatViolationV2,
261+
PropertyConstraintViolation, OccurrenceConstraintViolationV16, OccurrenceConstraintViolationV2,
262+
TypeConstraintViolation, GenericError:
232263
return true
233264
}
234265
return false
235266
}
236267

237268
// -------------------- Logic --------------------
238269

239-
// Unmarshals an OCPP-J json object from a byte array.
240-
// Returns the array of elements contained in the message.
241-
func ParseRawJsonMessage(dataJson []byte) ([]interface{}, error) {
242-
var arr []interface{}
243-
err := json.Unmarshal(dataJson, &arr)
244-
if err != nil {
245-
return nil, err
246-
}
247-
return arr, nil
248-
}
249-
250-
// Unmarshals an OCPP-J json object from a JSON string.
251-
// Returns the array of elements contained in the message.
252-
func ParseJsonMessage(dataJson string) ([]interface{}, error) {
253-
rawJson := []byte(dataJson)
254-
return ParseRawJsonMessage(rawJson)
255-
}
256-
257270
func ocppMessageToJson(message interface{}) ([]byte, error) {
258271
jsonData, err := jsonMarshal(message)
259272
if err != nil {
@@ -317,15 +330,6 @@ func errorFromValidation(d dialector, validationErrors validator.ValidationError
317330
return ocpp.NewError(GenericError, fmt.Sprintf("%v", validationErrors.Error()), messageId)
318331
}
319332

320-
// Marshals data by manipulating EscapeHTML property of encoder
321-
func jsonMarshal(t interface{}) ([]byte, error) {
322-
buffer := &bytes.Buffer{}
323-
encoder := json.NewEncoder(buffer)
324-
encoder.SetEscapeHTML(EscapeHTML)
325-
err := encoder.Encode(t)
326-
return bytes.TrimRight(buffer.Bytes(), "\n"), err
327-
}
328-
329333
// -------------------- Endpoint --------------------
330334

331335
// An OCPP-J endpoint is one of the two entities taking part in the communication.
@@ -372,40 +376,6 @@ func (endpoint *Endpoint) GetProfileForFeature(featureName string) (*ocpp.Profil
372376
return nil, false
373377
}
374378

375-
func parseRawJsonRequest(raw interface{}, requestType reflect.Type) (ocpp.Request, error) {
376-
if raw == nil {
377-
raw = &struct{}{}
378-
}
379-
bytes, err := json.Marshal(raw)
380-
if err != nil {
381-
return nil, err
382-
}
383-
request := reflect.New(requestType).Interface()
384-
err = json.Unmarshal(bytes, &request)
385-
if err != nil {
386-
return nil, err
387-
}
388-
result := request.(ocpp.Request)
389-
return result, nil
390-
}
391-
392-
func parseRawJsonConfirmation(raw interface{}, confirmationType reflect.Type) (ocpp.Response, error) {
393-
if raw == nil {
394-
raw = &struct{}{}
395-
}
396-
bytes, err := json.Marshal(raw)
397-
if err != nil {
398-
return nil, err
399-
}
400-
confirmation := reflect.New(confirmationType).Interface()
401-
err = json.Unmarshal(bytes, &confirmation)
402-
if err != nil {
403-
return nil, err
404-
}
405-
result := confirmation.(ocpp.Response)
406-
return result, nil
407-
}
408-
409379
// Parses an OCPP-J message. The function expects an array of elements, as contained in the JSON message.
410380
//
411381
// Pending requests are automatically cleared, in case the received message is a CallResponse or CallError.
@@ -414,20 +384,25 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
414384
if len(arr) < 3 {
415385
return nil, ocpp.NewError(FormatErrorType(endpoint), "Invalid message. Expected array length >= 3", "")
416386
}
387+
417388
rawTypeId, ok := arr[0].(float64)
418389
if !ok {
419390
return nil, ocpp.NewError(FormatErrorType(endpoint), fmt.Sprintf("Invalid element %v at 0, expected message type (int)", arr[0]), "")
420391
}
392+
421393
typeId := MessageType(rawTypeId)
422394
uniqueId, ok := arr[1].(string)
423395
if !ok {
424396
return nil, ocpp.NewError(FormatErrorType(endpoint), fmt.Sprintf("Invalid element %v at 1, expected unique ID (string)", arr[1]), uniqueId)
425397
}
398+
426399
if uniqueId == "" {
427400
return nil, ocpp.NewError(FormatErrorType(endpoint), "Invalid unique ID, cannot be empty", uniqueId)
428401
}
429-
// Parse message
430-
if typeId == CALL {
402+
403+
// Parse message base on type
404+
switch typeId {
405+
case CALL:
431406
if len(arr) != 4 {
432407
return nil, ocpp.NewError(FormatErrorType(endpoint), "Invalid Call message. Expected array length 4", uniqueId)
433408
}
@@ -455,7 +430,7 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
455430
return nil, errorFromValidation(endpoint, err.(validator.ValidationErrors), uniqueId, action)
456431
}
457432
return &call, nil
458-
} else if typeId == CALL_RESULT {
433+
case CALL_RESULT:
459434
request, ok := pendingRequestState.GetPendingRequest(uniqueId)
460435
if !ok {
461436
log.Infof("No previous request %v sent. Discarding response message", uniqueId)
@@ -476,7 +451,7 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
476451
return nil, errorFromValidation(endpoint, err.(validator.ValidationErrors), uniqueId, request.GetFeatureName())
477452
}
478453
return &callResult, nil
479-
} else if typeId == CALL_ERROR {
454+
case CALL_ERROR, CALL_RESULT_ERROR:
480455
_, ok := pendingRequestState.GetPendingRequest(uniqueId)
481456
if !ok {
482457
log.Infof("No previous request %v sent. Discarding error message", uniqueId)
@@ -510,7 +485,16 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
510485
return nil, errorFromValidation(endpoint, err.(validator.ValidationErrors), uniqueId, "")
511486
}
512487
return &callError, nil
513-
} else {
488+
489+
case SEND:
490+
// SEND can be only sent in OCPP 2.1
491+
if endpoint.Dialect() != ocpp.V21 {
492+
return nil, ocpp.NewError(MessageTypeNotSupported, "SEND message is not supported in this OCPP version", uniqueId)
493+
}
494+
495+
// Send does not expect a confirmation, so it is not added to the pending requests.
496+
return nil, nil
497+
default:
514498
return nil, ocpp.NewError(MessageTypeNotSupported, fmt.Sprintf("Invalid message type ID %v", typeId), uniqueId)
515499
}
516500
}

ocppj/parse.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package ocppj
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"github.com/lorenzodonini/ocpp-go/ocpp"
7+
"reflect"
8+
)
9+
10+
func parseRawJsonRequest(raw interface{}, requestType reflect.Type) (ocpp.Request, error) {
11+
if raw == nil {
12+
raw = &struct{}{}
13+
}
14+
bytes, err := json.Marshal(raw)
15+
if err != nil {
16+
return nil, err
17+
}
18+
request := reflect.New(requestType).Interface()
19+
err = json.Unmarshal(bytes, &request)
20+
if err != nil {
21+
return nil, err
22+
}
23+
result := request.(ocpp.Request)
24+
return result, nil
25+
}
26+
27+
func parseRawJsonConfirmation(raw interface{}, confirmationType reflect.Type) (ocpp.Response, error) {
28+
if raw == nil {
29+
raw = &struct{}{}
30+
}
31+
bytes, err := json.Marshal(raw)
32+
if err != nil {
33+
return nil, err
34+
}
35+
confirmation := reflect.New(confirmationType).Interface()
36+
err = json.Unmarshal(bytes, &confirmation)
37+
if err != nil {
38+
return nil, err
39+
}
40+
result := confirmation.(ocpp.Response)
41+
return result, nil
42+
}
43+
44+
// Marshals data by manipulating EscapeHTML property of encoder
45+
func jsonMarshal(t interface{}) ([]byte, error) {
46+
buffer := &bytes.Buffer{}
47+
encoder := json.NewEncoder(buffer)
48+
encoder.SetEscapeHTML(EscapeHTML)
49+
err := encoder.Encode(t)
50+
return bytes.TrimRight(buffer.Bytes(), "\n"), err
51+
}
52+
53+
// Unmarshals an OCPP-J json object from a byte array.
54+
// Returns the array of elements contained in the message.
55+
func ParseRawJsonMessage(dataJson []byte) ([]interface{}, error) {
56+
var arr []interface{}
57+
err := json.Unmarshal(dataJson, &arr)
58+
if err != nil {
59+
return nil, err
60+
}
61+
return arr, nil
62+
}
63+
64+
// Unmarshals an OCPP-J json object from a JSON string.
65+
// Returns the array of elements contained in the message.
66+
func ParseJsonMessage(dataJson string) ([]interface{}, error) {
67+
rawJson := []byte(dataJson)
68+
return ParseRawJsonMessage(rawJson)
69+
}

0 commit comments

Comments
 (0)