Skip to content

Commit 9041b9f

Browse files
initialed85lorenzodonini
authored andcommitted
Fix validation for GetCompositeSchedule, run gofmt, run go vet and fix a few implicitly copied locks
1 parent 9b48003 commit 9041b9f

20 files changed

+99
-56
lines changed

README.md

+56-15
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ There are currently no plans of supporting OCPP-S.
1818

1919
Planned milestones and features:
2020

21-
- [x] OCPP 1.6
22-
- [x] OCPP 2.0.1 (examples working, but will need more real-world testing)
23-
- [ ] Dedicated package for configuration management
21+
- [x] OCPP 1.6
22+
- [x] OCPP 2.0.1 (examples working, but will need more real-world testing)
23+
- [ ] Dedicated package for configuration management
2424

2525
## OCPP 1.6 Usage
2626

@@ -31,6 +31,7 @@ go get github.com/lorenzodonini/ocpp-go
3131
```
3232

3333
You will also need to fetch some dependencies:
34+
3435
```sh
3536
cd <path-to-ocpp-go>
3637
export GO111MODULE=on
@@ -42,6 +43,7 @@ Your application may either act as a [Central System](#central-system) (server)
4243
### Central System
4344

4445
If you want to integrate the library into your custom Central System, you must implement the callbacks defined in the profile interfaces, e.g.:
46+
4547
```go
4648
import (
4749
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
@@ -65,7 +67,7 @@ func (handler *CentralSystemHandler) OnBootNotification(chargePointId string, re
6567
return core.NewBootNotificationConfirmation(types.NewDateTime(time.Now()), defaultHeartbeatInterval, core.RegistrationStatusAccepted), nil
6668
}
6769

68-
// further callbacks...
70+
// further callbacks...
6971
```
7072

7173
Every time a request from the charge point comes in, the respective callback function is called.
@@ -77,6 +79,7 @@ You need to implement at least all other callbacks defined in the `core.CentralS
7779
Depending on which OCPP profiles you want to support in your application, you will need to implement additional callbacks as well.
7880

7981
To start a central system instance, simply run the following:
82+
8083
```go
8184
centralSystem := ocpp16.NewCentralSystem(nil, nil)
8285

@@ -102,6 +105,7 @@ log.Println("stopped central system")
102105
#### Sending requests
103106

104107
To send requests to the charge point, you may either use the simplified API:
108+
105109
```go
106110
err := centralSystem.ChangeAvailability("1234", myCallback, 1, core.AvailabilityTypeInoperative)
107111
if err != nil {
@@ -110,6 +114,7 @@ if err != nil {
110114
```
111115

112116
or create a message manually:
117+
113118
```go
114119
request := core.NewChangeAvailabilityRequest(1, core.AvailabilityTypeInoperative)
115120
err := centralSystem.SendRequestAsync("clientId", request, callbackFunction)
@@ -118,8 +123,9 @@ if err != nil {
118123
}
119124
```
120125

121-
In both cases, the request is sent asynchronously and the function returns right away.
126+
In both cases, the request is sent asynchronously and the function returns right away.
122127
You need to write the callback function to check for errors and handle the confirmation on your own:
128+
123129
```go
124130
myCallback := func(confirmation *core.ChangeAvailabilityConfirmation, e error) {
125131
if e != nil {
@@ -137,19 +143,22 @@ Since the initial `centralSystem.Start` call blocks forever, you may want to wra
137143

138144
You can take a look at the [full example](./example/1.6/cs/central_system_sim.go).
139145
To run it, simply execute:
146+
140147
```bash
141148
go run ./example/1.6/cs/*.go
142149
```
143150

144151
#### Docker
145152

146153
A containerized version of the central system example is available:
154+
147155
```bash
148156
docker pull ldonini/ocpp1.6-central-system:latest
149157
docker run -it -p 8887:8887 --rm --name central-system ldonini/ocpp1.6-central-system:latest
150158
```
151159

152160
You can also run it directly using docker-compose:
161+
153162
```sh
154163
docker-compose -f example/1.6/docker-compose.yml up central-system
155164
```
@@ -158,16 +167,18 @@ docker-compose -f example/1.6/docker-compose.yml up central-system
158167

159168
If you wish to test the central system using TLS, make sure you put your self-signed certificates inside the `example/1.6/certs` folder.
160169

161-
Feel free to use the utility script `cd example/1.6 && ./create-test-certificates.sh` for generating test certificates.
170+
Feel free to use the utility script `cd example/1.6 && ./create-test-certificates.sh` for generating test certificates.
162171

163172
Then run the following:
173+
164174
```
165175
docker-compose -f example/1.6/docker-compose.tls.yml up central-system
166176
```
167177

168178
### Charge Point
169179

170180
If you want to integrate the library into your custom Charge Point, you must implement the callbacks defined in the profile interfaces, e.g.:
181+
171182
```go
172183
import (
173184
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
@@ -199,6 +210,7 @@ You need to implement at least all other callbacks defined in the `core.ChargePo
199210
Depending on which OCPP profiles you want to support in your application, you will need to implement additional callbacks as well.
200211

201212
To start a charge point instance, simply run the following:
213+
202214
```go
203215
chargePointId := "cp0001"
204216
csUrl = "ws://localhost:8887"
@@ -213,7 +225,7 @@ err := chargePoint.Start(csUrl)
213225
if err != nil {
214226
log.Println(err)
215227
} else {
216-
log.Printf("connected to central system at %v", csUrl)
228+
log.Printf("connected to central system at %v", csUrl)
217229
mainRoutine() // ... your program logic goes here
218230
}
219231

@@ -225,6 +237,7 @@ log.Printf("disconnected from central system")
225237
#### Sending requests
226238

227239
To send requests to the central station, you have two options. You may either use the simplified synchronous blocking API (recommended):
240+
228241
```go
229242
bootConf, err := chargePoint.BootNotification("model1", "vendor1")
230243
if err != nil {
@@ -236,11 +249,13 @@ if err != nil {
236249
```
237250

238251
or create a message manually:
252+
239253
```go
240254
request := core.NewBootNotificationRequest("model1", "vendor1")
241255
```
242256

243257
You can then decide to send the message using a synchronous blocking call:
258+
244259
```go
245260
// Synchronous call
246261
confirmation, err := chargePoint.SendRequest(request)
@@ -250,7 +265,9 @@ if err != nil {
250265
bootConf := confirmation.(*core.BootNotificationConfirmation)
251266
// ... do something with the confirmation
252267
```
268+
253269
or an asynchronous call:
270+
254271
```go
255272
// Asynchronous call
256273
err := chargePoint.SendRequestAsync(request, callbackFunction)
@@ -260,6 +277,7 @@ if err != nil {
260277
```
261278

262279
In the latter case, you need to write the callback function and check for errors on your own:
280+
263281
```go
264282
callback := func(confirmation ocpp.Response, e error) {
265283
bootConf := confirmation.(*core.BootNotificationConfirmation)
@@ -275,8 +293,10 @@ callback := func(confirmation ocpp.Response, e error) {
275293
When creating a message manually, you always need to perform type assertion yourself, as the `SendRequest` and `SendRequestAsync` APIs use generic `Request` and `Confirmation` interfaces.
276294

277295
#### Example
296+
278297
You can take a look at the [full example](./example/1.6/cp/charge_point_sim.go).
279298
To run it, simply execute:
299+
280300
```bash
281301
CLIENT_ID=chargePointSim CENTRAL_SYSTEM_URL=ws://<host>:8887 go run example/1.6/cp/*.go
282302
```
@@ -286,6 +306,7 @@ You need to specify the URL of a running central station server via environment
286306
#### Docker
287307

288308
A containerized version of the charge point example is available:
309+
289310
```bash
290311
docker pull ldonini/ocpp1.6-charge-point:latest
291312
docker run -e CLIENT_ID=chargePointSim -e CENTRAL_SYSTEM_URL=ws://<host>:8887 -it --rm --name charge-point ldonini/ocpp1.6-charge-point:latest
@@ -294,6 +315,7 @@ docker run -e CLIENT_ID=chargePointSim -e CENTRAL_SYSTEM_URL=ws://<host>:8887 -i
294315
You need to specify the host, on which the central system is running, in order for the charge point to connect to it.
295316

296317
You can also run it directly using docker-compose:
318+
297319
```sh
298320
docker-compose -f example/1.6/docker-compose.yml up charge-point
299321
```
@@ -302,9 +324,10 @@ docker-compose -f example/1.6/docker-compose.yml up charge-point
302324

303325
If you wish to test the charge point using TLS, make sure you put your self-signed certificates inside the `example/1.6/certs` folder.
304326

305-
Feel free to use the utility script `cd example/1.6 && ./create-test-certificates.sh` for generating test certificates.
327+
Feel free to use the utility script `cd example/1.6 && ./create-test-certificates.sh` for generating test certificates.
306328

307329
Then run the following:
330+
308331
```
309332
docker-compose -f example/1.6/docker-compose.tls.yml up charge-point
310333
```
@@ -319,18 +342,20 @@ All incoming and outgoing messages are validated by default, using the [validato
319342
Constraints are defined on every request/response struct, as per OCPP specs.
320343

321344
Validation may be disabled at a package level if needed:
345+
322346
```go
323347
ocppj.SetMessageValidation(false)
324-
```
348+
```
325349

326350
Use at your own risk, as this will disable validation for all messages!
327351

328-
> I will be evaluating the possibility to selectively disable validation for a specific message,
352+
> I will be evaluating the possibility to selectively disable validation for a specific message,
329353
> e.g. by passing message options.
330354
331355
### Verbose logging
332356

333357
The `ws` and `ocppj` packages offer the possibility to enable verbose logs, via your logger of choice, e.g.:
358+
334359
```go
335360
// Setup your own logger
336361
log = logrus.New()
@@ -340,17 +365,19 @@ log.SetLevel(logrus.DebugLevel) // Debug level needed to see all logs
340365
ws.SetLogger(log.WithField("logger", "websocket"))
341366
ocppj.SetLogger(log.WithField("logger", "ocppj"))
342367
```
368+
343369
The logger you pass needs to conform to the `logging.Logger` interface.
344370
Commonly used logging libraries, such as zap or logrus, adhere to this interface out-of-the-box.
345371

346372
If you are using a logger, that isn't conform, you can simply write an adapter between the `Logger` interface and your own logging system.
347373

348374
### Websocket ping-pong
349375

350-
The websocket package currently supports client-initiated pings only.
376+
The websocket package currently supports client-initiated pings only.
351377

352378
If your setup requires the server to be the initiator of a ping-pong (e.g. for web-based charge points),
353379
you may disable ping-pong entirely and just rely on the heartbeat mechanism:
380+
354381
```go
355382
cfg := ws.NewServerTimeoutConfig()
356383
cfg.PingWait = 0 // this instructs the server to wait forever
@@ -366,7 +393,7 @@ Experimental support for version 2.0.1 is now supported!
366393
> Version 2.0 was skipped entirely, since it is considered obsolete.
367394
368395
Requests and responses in OCPP 2.0.1 are handled the same way they were in v1.6.
369-
The notable change is that there are now significantly more supported messages and profiles (feature sets),
396+
The notable change is that there are now significantly more supported messages and profiles (feature sets),
370397
which also require their own handlers to be implemented.
371398

372399
The library API to the lower websocket and ocpp-j layers remains unchanged.
@@ -383,6 +410,7 @@ More in-depth documentation for v2.0.1 will follow.
383410
### CSMS
384411

385412
To start a CSMS instance, run the following:
413+
386414
```go
387415
import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1"
388416

@@ -420,6 +448,7 @@ log.Println("stopped CSMS")
420448
#### Sending requests
421449

422450
Similarly to v1.6, you may send requests using the simplified API, e.g.
451+
423452
```go
424453
err := csms.GetLocalListVersion(chargingStationID, myCallback)
425454
if err != nil {
@@ -432,11 +461,12 @@ Or you may build requests manually and send them using the asynchronous API.
432461
#### Docker image
433462

434463
There is a Dockerfile and a docker image available upstream.
435-
Feel free
464+
Feel free
436465

437466
### Charging Station
438467

439468
To start a charging station instance, simply run the following:
469+
440470
```go
441471
chargingStationID := "cs0001"
442472
csmsUrl = "ws://localhost:8887"
@@ -464,7 +494,7 @@ err := chargingStation.Start(csmsUrl)
464494
if err != nil {
465495
log.Println(err)
466496
} else {
467-
log.Printf("connected to CSMS at %v", csmsUrl)
497+
log.Printf("connected to CSMS at %v", csmsUrl)
468498
mainRoutine() // ... your program logic goes here
469499
}
470500

@@ -476,6 +506,7 @@ log.Println("disconnected from CSMS")
476506
#### Sending requests
477507

478508
Similarly to v1.6 you may send requests using the simplified API (recommended), e.g.
509+
479510
```go
480511
bootResp, err := chargingStation.BootNotification(provisioning.BootReasonPowerUp, "model1", "vendor1")
481512
if err != nil {
@@ -485,4 +516,14 @@ if err != nil {
485516
}
486517
```
487518

488-
Or you may build requests manually and send them using either the synchronous or asynchronous API.
519+
Or you may build requests manually and send them using either the synchronous or asynchronous API.
520+
521+
#### Contributing
522+
523+
If you're contributing a code change, you'll want to be sure the tests are passing first; here are the steps to check that:
524+
525+
- Install [toxiproxy](https://github.com/Shopify/toxiproxy) for your platform
526+
- Shell 1 - `cd example/1.6 && ./create-test-certificates.sh ; cd ../..`
527+
- Shell 1 - `cd example/2.0.1 && ./create-test-certificates.sh ; cd ../..`
528+
- Shell 1 - `toxiproxy-server -port 8474 -host localhost`
529+
- Shell 2 - `go fmt ./... && go vet ./... && go test -v -count=1 -failfast ./...`

ocpp1.6/core/stop_transaction.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func NewStopTransactionConfirmation() *StopTransactionConfirmation {
107107
return &StopTransactionConfirmation{}
108108
}
109109

110-
//TODO: advanced validation
110+
// TODO: advanced validation
111111
func init() {
112112
_ = types.Validate.RegisterValidation("reason", isValidReason)
113113
}

ocpp1.6/smartcharging/get_composite_schedule.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type GetCompositeScheduleRequest struct {
4040
// In case the request was invalid, or couldn't be processed, an error will be sent instead.
4141
type GetCompositeScheduleConfirmation struct {
4242
Status GetCompositeScheduleStatus `json:"status" validate:"required,compositeScheduleStatus"`
43-
ConnectorId *int `json:"connectorId,omitempty" validate:"omitempty,gt=0"`
43+
ConnectorId *int `json:"connectorId,omitempty" validate:"omitempty,gte=0"`
4444
ScheduleStart *types.DateTime `json:"scheduleStart,omitempty"`
4545
ChargingSchedule *types.ChargingSchedule `json:"chargingSchedule,omitempty" validate:"omitempty"`
4646
}

ocpp1.6_test/cancel_reservation_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func (suite *OcppV16TestSuite) TestCancelReservationE2EMocked() {
4242
cancelReservationConfirmation := reservation.NewCancelReservationConfirmation(status)
4343
channel := NewMockWebSocket(wsId)
4444

45-
reservationListener := MockChargePointReservationListener{}
45+
reservationListener := &MockChargePointReservationListener{}
4646
reservationListener.On("OnCancelReservation", mock.Anything).Return(cancelReservationConfirmation, nil).Run(func(args mock.Arguments) {
4747
request, ok := args.Get(0).(*reservation.CancelReservationRequest)
4848
require.NotNil(t, request)
@@ -51,7 +51,7 @@ func (suite *OcppV16TestSuite) TestCancelReservationE2EMocked() {
5151
})
5252
setupDefaultCentralSystemHandlers(suite, nil, expectedCentralSystemOptions{clientId: wsId, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true})
5353
setupDefaultChargePointHandlers(suite, nil, expectedChargePointOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true})
54-
suite.chargePoint.SetReservationHandler(&reservationListener)
54+
suite.chargePoint.SetReservationHandler(reservationListener)
5555
// Run Test
5656
suite.centralSystem.Start(8887, "somePath")
5757
err := suite.chargePoint.Start(wsUrl)

ocpp1.6_test/clear_charging_profile_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func (suite *OcppV16TestSuite) TestClearChargingProfileE2EMocked() {
5353
ClearChargingProfileConfirmation := smartcharging.NewClearChargingProfileConfirmation(status)
5454
channel := NewMockWebSocket(wsId)
5555

56-
smartChargingListener := MockChargePointSmartChargingListener{}
56+
smartChargingListener := &MockChargePointSmartChargingListener{}
5757
smartChargingListener.On("OnClearChargingProfile", mock.Anything).Return(ClearChargingProfileConfirmation, nil).Run(func(args mock.Arguments) {
5858
request, ok := args.Get(0).(*smartcharging.ClearChargingProfileRequest)
5959
require.True(t, ok)
@@ -65,7 +65,7 @@ func (suite *OcppV16TestSuite) TestClearChargingProfileE2EMocked() {
6565
})
6666
setupDefaultCentralSystemHandlers(suite, nil, expectedCentralSystemOptions{clientId: wsId, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true})
6767
setupDefaultChargePointHandlers(suite, nil, expectedChargePointOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true})
68-
suite.chargePoint.SetSmartChargingHandler(&smartChargingListener)
68+
suite.chargePoint.SetSmartChargingHandler(smartChargingListener)
6969
// Run Test
7070
suite.centralSystem.Start(8887, "somePath")
7171
err := suite.chargePoint.Start(wsUrl)

0 commit comments

Comments
 (0)