Comments (4)
Hello,
interesting question and not completely unexpected.
If you take a look at all the messages in the callbacks, you'll realize that most of the messages and/or attributes are different between v1.6 and v2.0.1, so it wasn't really possible to unify the two versions from a library perspective, hence the two separate packages. It's literally two different protocols, not just a "version bump".
Take GetConfiguration
(v1.6) as an example. It was basically replaced by the GetVariables
message (v2.0.1), which uses an entirely new data model. I honestly don't see how it could be possible to create an abstraction (except for a raw map[string]interface{}
type), that would allow to map two heterogenous types under a common interface/parent class.
Adapters?
My understanding is that any vendor or service provider who wishes to support both protocol versions will have to rewrite their handlers anyways (with lots of copy paste), as more data and custom behavior is involved. I expect DB schemas to also change between versions.
If you want to leverage shared logic, you could either:
- convert the v1.6 messages internally to match the v2 schema
- delegate all business logic to external functions, which take in primitive parameters or custom types -> this would be an adapter on your end basically
Here's a naive approach, just to show you what would be involved for a "simple" message:
// v1.6 handler
func (handler *V16Handler) OnBootNotification(chargePointId string, request *core.BootNotificationRequest) (confirmation *core.BootNotificationConfirmation, err error) {
logDefault(chargePointId, request.GetFeatureName()).Infof("boot confirmed")
// Forward to v2 handler, converting to the data model expected by v2
res, err := v2Handler.OnBootNotification(chargePointId, &provisioning.BootNotificationRequest{
Reason: provisioning.BootReasonUnknown, // This did not exist in 1.6, so you will have to either assume or
ChargingStation: provisioning.ChargingStationType{
SerialNumber: request.ChargePointSerialNumber,
Model: request.ChargePointModel,
VendorName: request.ChargePointVendor,
FirmwareVersion: request.FirmwareVersion,
Modem: &provisioning.ModemType{
Iccid: request.Iccid,
Imsi: request.Imsi,
},
},
})
// Re-convert to v1.6 format
return &core.BootNotificationConfirmation{
CurrentTime: types.NewDateTime(res.CurrentTime.Time),
Interval: res.Interval,
Status: core.RegistrationStatus(res.Status),
}, nil
}
// v2.0.1 handler (different file, but can be in the same package to reuse all your custom functions)
func (c *V2Handler) OnBootNotification(chargingStationID string, request *provisioning.BootNotificationRequest) (response *provisioning.BootNotificationResponse, err error) {
logDefault(chargingStationID, request.GetFeatureName()).Infof("boot confirmed for %v %v, serial: %v, firmare version: %v, reason: %v",
request.ChargingStation.VendorName, request.ChargingStation.Model, request.ChargingStation.SerialNumber, request.ChargingStation.FirmwareVersion, request.Reason)
response = provisioning.NewBootNotificationResponse(types.NewDateTime(time.Now()), defaultHeartbeatInterval, provisioning.RegistrationStatusAccepted)
return
}
Just this example should show you that these conversions can be problematic, since information could be lost in both directions.
It's up to you to decide whether an adapter would be preferable for your setup, instead of a clean separation.
Just a shared interface?
If you just wish to have all the callbacks from v1.6 and v2.0.1 in a single package, this could probably be achieved, although with a different naming scheme (e.g. OnV16BootNotification
along OnV2BootNotification
). This would not solve the issues given by the underlying protocols being different, but it could simplify your implementation a bit. I would have to investigate this.
TLDR
As much as I understand your pain, I don't plan on writing an adapter between the two protocol versions, because it would require making some dangerous assumptions which might do more harm than good in the long run.
If you come up with a brilliant idea to solve this, merge requests are definitely welcome!
Instead, I could investigate if offering the two interfaces combined into a single one would offer any major benefits (see my point above).
from ocpp-go.
Hi @lorenzodonini .
Thank you very much for your really detailed and well structured answer.
It helps us to know that these two versions can be seen as new protocols on a certain level. Even if we can unify them, it will probably cause problems sooner or later. Thus, we are going to try separating the version-specific code parts from our custom logic.
We will let you know when have a brilliant idee to solve this!
from ocpp-go.
Cant we handle this with websocket sub protocol and run them in different ports, or have a subprotocol based switching server in front of service
from ocpp-go.
@ysaakpr you can definitely do that on a networking level, but it won't solve the fact that you need to implement both v1.6 and v2.0.1 callbacks in your code.
Btw the networking layer currently doesn't pass any information about the negotiated subprotocol to the upper layers -> that's why the protocol version needs to be known at startup time.
In other words the current implementation forces you to spin up two processes, one for v1.6 and one for v2.0.1, if you need to handle both concurrently.
from ocpp-go.
Related Issues (20)
- type Transaction struct - StoppedReason - Type -> TriggerReason? HOT 2
- Validator instance seperate in ocpp1.6 and ocpp2.0.1 HOT 1
- Unable to Include LocalAuthorizationList in OCPP1.6 SendLocalList Command HOT 2
- Infinite wait on stopping a disconnected charge point HOT 1
- Need to support panic recovery in the request handlers HOT 4
- Unhandled `FormatViolation` type on `CallError` on ocpp v2 (OCPP 2.0.1 Specification, Table B06.FR.17)
- Firmware Status Notification HOT 2
- Clustering - Horizontal Scaling, Production deployment more than one node HOT 2
- OCPP 2.0 Reset Request Validator Error HOT 2
- OCPP2.0.1 No means for cleanly sending securityerror codes HOT 1
- Unhandled/error validation for `TransactionEventRequest` eventType:`Started` with idToken/IdTokenType (type:`NoAuthorization` and empty `idtoken` value)
- Race condition in chargePoint.Start() HOT 4
- Race in library and tests HOT 1
- Unhandled json errors in GetConfiguration HOT 3
- Parsing of local timestamps not supported - spec violation? HOT 9
- Central-system 1.6 example - "fatal error: concurrent map writes" when connecting multiple chargers rapidly HOT 1
- Code Generation HOT 1
- TriggerMessage.Req validation disallows passing connector 0 HOT 6
- ChangeConfigurationRequest doesn't allow empty values
- Bad Request response for https via curl request HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ocpp-go.