Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: OCPP 1.6j security extension #266

Merged
21 changes: 20 additions & 1 deletion example/1.6/cp/charge_point_sim.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strconv"
"time"

"github.com/lorenzodonini/ocpp-go/ocpp1.6/logging"
"github.com/sirupsen/logrus"

ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
Expand Down Expand Up @@ -80,6 +81,17 @@ func exampleRoutine(chargePoint ocpp16.ChargePoint, stateHandler *ChargePointHan
logDefault(bootConf.GetFeatureName()).Infof("status: %v, interval: %v, current time: %v", bootConf.Status, bootConf.Interval, bootConf.CurrentTime.String())
// Notify connector status
updateStatus(stateHandler, 0, core.ChargePointStatusAvailable)
// Security event
_, err = chargePoint.SecurityEventNotification("Event", types.Now())
checkError(err)
// Send log notification
_, err = chargePoint.LogStatusNotification(logging.UploadLogStatusUploading, 1)
checkError(err)
// Request cert signing
certificate, err := chargePoint.SignCertificate("adsad")
checkError(err)
logDefault(certificate.GetFeatureName()).Infof("status: %v", certificate.Status)

// Wait for some time ...
time.Sleep(5 * time.Second)
// Simulate charging for connector 1
Expand Down Expand Up @@ -166,6 +178,13 @@ func main() {
chargePoint.SetReservationHandler(handler)
chargePoint.SetRemoteTriggerHandler(handler)
chargePoint.SetSmartChargingHandler(handler)
// OCPP 1.6j Security extension
chargePoint.SetCertificateHandler(handler)
chargePoint.SetLogHandler(handler)
chargePoint.SetSecureFirmwareHandler(handler)
chargePoint.SetExtendedTriggerMessageHandler(handler)
chargePoint.SetSecurityHandler(handler)

ocppj.SetLogger(log.WithField("logger", "ocppj"))
ws.SetLogger(log.WithField("logger", "websocket"))
// Connects to central system
Expand All @@ -185,7 +204,7 @@ func init() {
log = logrus.New()
log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
// Set this to DebugLevel if you want to retrieve verbose logs from the ocppj and websocket layers
log.SetLevel(logrus.InfoLevel)
log.SetLevel(logrus.ErrorLevel)
}

// Utility functions
Expand Down
56 changes: 48 additions & 8 deletions example/1.6/cp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import (
"time"

ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/certificates"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/extendedtriggermessage"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/firmware"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/localauth"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/logging"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/reservation"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/securefirmware"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/security"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
)
Expand Down Expand Up @@ -142,7 +147,7 @@ func (handler *ChargePointHandler) OnRemoteStopTransaction(request *core.RemoteS
}

func (handler *ChargePointHandler) OnReset(request *core.ResetRequest) (confirmation *core.ResetConfirmation, err error) {
//TODO: stop all ongoing transactions
// TODO: stop all ongoing transactions
logDefault(request.GetFeatureName()).Warn("no reset logic implemented yet")
return core.NewResetConfirmation(core.ResetStatusAccepted), nil
}
Expand Down Expand Up @@ -183,7 +188,7 @@ func (handler *ChargePointHandler) OnSendLocalList(request *localauth.SendLocalL
// ------------- Firmware management profile callbacks -------------

func (handler *ChargePointHandler) OnGetDiagnostics(request *firmware.GetDiagnosticsRequest) (confirmation *firmware.GetDiagnosticsConfirmation, err error) {
//TODO: perform diagnostics upload out-of-band
// TODO: perform diagnostics upload out-of-band
logDefault(request.GetFeatureName()).Warn("no diagnostics upload logic implemented yet")
return firmware.NewGetDiagnosticsConfirmation(), nil
}
Expand All @@ -209,7 +214,7 @@ func (handler *ChargePointHandler) OnTriggerMessage(request *remotetrigger.Trigg
status := remotetrigger.TriggerMessageStatusRejected
switch request.RequestedMessage {
case core.BootNotificationFeatureName:
//TODO: schedule boot notification message
// TODO: schedule boot notification message
break
case firmware.DiagnosticsStatusNotificationFeatureName:
// Schedule diagnostics status notification request
Expand All @@ -220,7 +225,7 @@ func (handler *ChargePointHandler) OnTriggerMessage(request *remotetrigger.Trigg
}()
status = remotetrigger.TriggerMessageStatusAccepted
case firmware.FirmwareStatusNotificationFeatureName:
//TODO: schedule firmware status notification message
// TODO: schedule firmware status notification message
break
case core.HeartbeatFeatureName:
// Schedule heartbeat request
Expand All @@ -231,7 +236,7 @@ func (handler *ChargePointHandler) OnTriggerMessage(request *remotetrigger.Trigg
}()
status = remotetrigger.TriggerMessageStatusAccepted
case core.MeterValuesFeatureName:
//TODO: schedule meter values message
// TODO: schedule meter values message
break
case core.StatusNotificationFeatureName:
connectorID := *request.ConnectorId
Expand Down Expand Up @@ -291,23 +296,58 @@ func (handler *ChargePointHandler) OnCancelReservation(request *reservation.Canc
// ------------- Smart charging profile callbacks -------------

func (handler *ChargePointHandler) OnSetChargingProfile(request *smartcharging.SetChargingProfileRequest) (confirmation *smartcharging.SetChargingProfileConfirmation, err error) {
//TODO: handle logic
// TODO: handle logic
logDefault(request.GetFeatureName()).Warn("no set charging profile logic implemented yet")
return smartcharging.NewSetChargingProfileConfirmation(smartcharging.ChargingProfileStatusNotSupported), nil
}

func (handler *ChargePointHandler) OnClearChargingProfile(request *smartcharging.ClearChargingProfileRequest) (confirmation *smartcharging.ClearChargingProfileConfirmation, err error) {
//TODO: handle logic
// TODO: handle logic
logDefault(request.GetFeatureName()).Warn("no clear charging profile logic implemented yet")
return smartcharging.NewClearChargingProfileConfirmation(smartcharging.ClearChargingProfileStatusUnknown), nil
}

func (handler *ChargePointHandler) OnGetCompositeSchedule(request *smartcharging.GetCompositeScheduleRequest) (confirmation *smartcharging.GetCompositeScheduleConfirmation, err error) {
//TODO: handle logic
// TODO: handle logic
logDefault(request.GetFeatureName()).Warn("no get composite schedule logic implemented yet")
return smartcharging.NewGetCompositeScheduleConfirmation(smartcharging.GetCompositeScheduleStatusRejected), nil
}

func (handler *ChargePointHandler) OnDeleteCertificate(request *certificates.DeleteCertificateRequest) (response *certificates.DeleteCertificateResponse, err error) {
logDefault(request.GetFeatureName()).Infof("certificate %v deleted", request.CertificateHashData)
return certificates.NewDeleteCertificateResponse(certificates.DeleteCertificateStatusAccepted), nil
}

func (handler *ChargePointHandler) OnGetInstalledCertificateIds(request *certificates.GetInstalledCertificateIdsRequest) (response *certificates.GetInstalledCertificateIdsResponse, err error) {
logDefault(request.GetFeatureName()).Infof("returning installed certificate ids")
return certificates.NewGetInstalledCertificateIdsResponse(certificates.GetInstalledCertificateStatusAccepted), nil
}

func (handler *ChargePointHandler) OnInstallCertificate(request *certificates.InstallCertificateRequest) (response *certificates.InstallCertificateResponse, err error) {
logDefault(request.GetFeatureName()).Infof("certificate installed")
return certificates.NewInstallCertificateResponse(certificates.CertificateStatusAccepted), nil
}

func (handler *ChargePointHandler) OnGetLog(request *logging.GetLogRequest) (response *logging.GetLogResponse, err error) {
logDefault(request.GetFeatureName()).Infof("returning log")
return logging.NewGetLogResponse(logging.LogStatusAccepted), nil
}

func (handler *ChargePointHandler) OnSignedUpdateFirmware(request *securefirmware.SignedUpdateFirmwareRequest) (response *securefirmware.SignedUpdateFirmwareResponse, err error) {
logDefault(request.GetFeatureName()).Infof("signed update firmware request received")
return securefirmware.NewSignedUpdateFirmwareResponse(securefirmware.UpdateFirmwareStatusAccepted), nil
}

func (handler *ChargePointHandler) OnExtendedTriggerMessage(request *extendedtriggermessage.ExtendedTriggerMessageRequest) (response *extendedtriggermessage.ExtendedTriggerMessageResponse, err error) {
logDefault(request.GetFeatureName()).Infof("extended trigger message received")
return extendedtriggermessage.NewExtendedTriggerMessageResponse(extendedtriggermessage.ExtendedTriggerMessageStatusAccepted), nil
}

func (handler *ChargePointHandler) OnCertificateSigned(request *security.CertificateSignedRequest) (response *security.CertificateSignedResponse, err error) {
logDefault(request.GetFeatureName()).Infof("certificate signed")
return security.NewCertificateSignedResponse(security.CertificateSignedStatusAccepted), nil
}

func checkError(err error) {
if err != nil {
log.Fatal(err)
Expand Down
8 changes: 7 additions & 1 deletion example/1.6/cs/central_system_sim.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ func main() {
centralSystem.SetReservationHandler(handler)
centralSystem.SetRemoteTriggerHandler(handler)
centralSystem.SetSmartChargingHandler(handler)

// Add callbacks for OCPP 1.6 security profiles
centralSystem.SetSecurityHandler(handler)
centralSystem.SetSecureFirmwareHandler(handler)
centralSystem.SetLogHandler(handler)

// Add handlers for dis/connection of charge points
centralSystem.SetNewChargePointHandler(func(chargePoint ocpp16.ChargePointConnection) {
handler.chargePoints[chargePoint.ID()] = &ChargePointState{connectors: map[int]*ConnectorInfo{}, transactions: map[int]*TransactionInfo{}}
Expand All @@ -237,5 +243,5 @@ func init() {
log = logrus.New()
log.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
// Set this to DebugLevel if you want to retrieve verbose logs from the ocppj and websocket layers
log.SetLevel(logrus.InfoLevel)
log.SetLevel(logrus.ErrorLevel)
}
27 changes: 25 additions & 2 deletions example/1.6/cs/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"fmt"
"time"

"github.com/lorenzodonini/ocpp-go/ocpp1.6/logging"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/securefirmware"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/security"
"github.com/sirupsen/logrus"

"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
Expand Down Expand Up @@ -130,7 +133,7 @@ func (handler *CentralSystemHandler) OnStartTransaction(chargePointId string, re
nextTransactionId += 1
connector.currentTransaction = transaction.id
info.transactions[transaction.id] = transaction
//TODO: check billable clients
// TODO: check billable clients
logDefault(chargePointId, request.GetFeatureName()).Infof("started transaction %v for connector %v", transaction.id, transaction.connectorId)
return core.NewStartTransactionConfirmation(types.NewIdTagInfo(types.AuthorizationStatusAccepted), transaction.id), nil
}
Expand All @@ -146,7 +149,7 @@ func (handler *CentralSystemHandler) OnStopTransaction(chargePointId string, req
connector.currentTransaction = -1
transaction.endTime = request.Timestamp
transaction.endMeter = request.MeterStop
//TODO: bill charging period to client
// TODO: bill charging period to client
}
logDefault(chargePointId, request.GetFeatureName()).Infof("stopped transaction %v - %v", request.TransactionId, request.Reason)
for _, mv := range request.TransactionData {
Expand Down Expand Up @@ -179,6 +182,26 @@ func (handler *CentralSystemHandler) OnFirmwareStatusNotification(chargePointId

// No callbacks for Local Auth management, Reservation, Remote trigger or Smart Charging profile on central system

func (handler *CentralSystemHandler) OnSecurityEventNotification(chargingStationID string, request *security.SecurityEventNotificationRequest) (response *security.SecurityEventNotificationResponse, err error) {
logDefault(chargingStationID, request.GetFeatureName()).Infof("security event notification received")
return security.NewSecurityEventNotificationResponse(), nil
}

func (handler *CentralSystemHandler) OnSignCertificate(chargingStationID string, request *security.SignCertificateRequest) (response *security.SignCertificateResponse, err error) {
logDefault(chargingStationID, request.GetFeatureName()).Infof("certificate signing request received")
return security.NewSignCertificateResponse(types.GenericStatusAccepted), nil
}

func (handler *CentralSystemHandler) OnSignedFirmwareStatusNotification(chargingStationID string, request *securefirmware.SignedFirmwareStatusNotificationRequest) (response *securefirmware.SignedFirmwareStatusNotificationResponse, err error) {
logDefault(chargingStationID, request.GetFeatureName()).Infof("signed firmware status notification received")
return securefirmware.NewFirmwareStatusNotificationResponse(), nil
}

func (handler *CentralSystemHandler) OnLogStatusNotification(chargingStationID string, request *logging.LogStatusNotificationRequest) (response *logging.LogStatusNotificationResponse, err error) {
logDefault(chargingStationID, request.GetFeatureName()).Infof("log status notification received")
return logging.NewLogStatusNotificationResponse(), nil
}

// Utility functions

func logDefault(chargePointId string, feature string) *logrus.Entry {
Expand Down
3 changes: 3 additions & 0 deletions example/1.6/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ services:
- sim
tty: true
charge-point:
depends_on:
central-system:
condition: service_started
build:
context: ../..
dockerfile: cp/Dockerfile
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ go 1.16
require (
github.com/Shopify/toxiproxy v2.1.4+incompatible
github.com/go-playground/locales v0.12.1 // indirect
github.com/go-playground/universal-translator v0.16.0 // indirect
github.com/go-playground/universal-translator v0.16.0
github.com/gorilla/mux v1.7.3
github.com/gorilla/websocket v1.4.1
github.com/kr/pretty v0.1.0 // indirect
github.com/leodido/go-urn v1.1.0 // indirect
github.com/relvacode/iso8601 v1.3.0 // indirect
github.com/relvacode/iso8601 v1.3.0
github.com/sirupsen/logrus v1.4.2
github.com/stretchr/testify v1.8.0
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect
Expand Down
Loading
Loading