Giter Site home page Giter Site logo

Comments (4)

lorenzodonini avatar lorenzodonini commented on June 5, 2024 2

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.

tretmar avatar tretmar commented on June 5, 2024

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.

ysaakpr avatar ysaakpr commented on June 5, 2024

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.

lorenzodonini avatar lorenzodonini commented on June 5, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.