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

Issue with DataTransfer on both ocpp 1.6 and 2.0.1 #257

Open
KatyushaScarlet opened this issue Mar 11, 2024 · 2 comments
Open

Issue with DataTransfer on both ocpp 1.6 and 2.0.1 #257

KatyushaScarlet opened this issue Mar 11, 2024 · 2 comments

Comments

@KatyushaScarlet
Copy link

Hi, I'm trying to develop a program to convert OCPP 1.6 requests to OCPP 2.0.1 requests and I'm running into a strange problem:
Filling the data field in DataTransferRequest with bytes[] obtained from json or string conversion is converted to base64 on the receiving end.
This problem occurs in my attempts to use either 1.6 or 2.0.1 examples.

For example, on the charge point my code like this:

    type DataSample struct {
        SampleString string `json: "sample_string"`
        SampleValue float64 `json: "sample_value"`
    }

......

	data := DataSample{SampleString: "dummyData", SampleValue: 42}
	jsonData, _ := json.Marshal(data)
	dataConf, err := chargePoint.DataTransfer("vendor1", func(request *core.DataTransferRequest) {
		request.MessageId = "message1"
		request.Data = jsonData
	})

However, in the DataTransferRequest on the receiving end, I will get an object of type {interface{} | string} with this value:

`eyJzYW1wbGVfc3RyaW5nIjoiZHVtbXlEYXRhIiwic2FtcGxlX3ZhbHVlIjo0Mn0=`

It is a string using base64 encoding with the original value:

{"sample_string": "dummyData", "sample_value":42}

If this is normal?
but when I look at the 2.0.1 example, I see that the csms code is like this:

func (c *CSMSHandler) OnDataTransfer(chargingStationID string, request *data.DataTransferRequest) (response *data.DataTransferResponse, err error) {
	var dataSample DataSample
	err = json.Unmarshal(request.Data.([]byte), &dataSample)
	if err ! = nil {
		logDefault(chargingStationID, request.GetFeatureName()).
			Errorf("invalid data received: %v", request.Data)
		return nil, err
	}
	logDefault(chargingStationID, request.GetFeatureName()).
		Infof("data received: %v, %v", dataSample.SampleString, dataSample.SampleValue)
	return data.NewDataTransferResponse(data.DataTransferStatusAccepted), nil
}

When I tested this on example, I found that both 1.6 and 2.0.1 exmaple get a base64 string for request.Data and cause a fatal exception on csms (due to json.Unmarshal decoding failure).
I've also looked at the test package, but in 2.0.1 I only see suite.chargingStation.DataTransfer(vendorId) , and I don't find a place to set request.Data.

Since I don't have access to a physical charging post at the moment, I don't know which type of data is the correct one to pass in a real usage scenario.
I'm not sure if I'm missing some setting somewhere, or if there's something wrong with my code.

Thanks!

@KatyushaScarlet
Copy link
Author

Now, I'm using this code on csms , referencing the OCPP 1.6 test package, so that it can successfully receive DataTransfer requests from charge point.

type DataSample struct {
	SampleString string  `json:"sample_string"`
	SampleValue  float64 `json:"sample_value"`
}

func parseDataSample(req *data.DataTransferRequest) (DataSample, error) {
	jsonString, _ := json.Marshal(req.Data)
	var result DataSample
	err := json.Unmarshal(jsonString, &result)
	return result, err
}

func (c *CSMSHandler) OnDataTransfer(chargingStationID string, request *data.DataTransferRequest) (response *data.DataTransferResponse, err error) {
	dataSample, err := parseDataSample(request)
	if err != nil {
		logDefault(chargingStationID, request.GetFeatureName()).
			Errorf("invalid data received: %v", request.Data)
		return nil, err
	}
	logDefault(chargingStationID, request.GetFeatureName()).
		Infof("data received: %v, %v", dataSample.SampleString, dataSample.SampleValue)
	return data.NewDataTransferResponse(data.DataTransferStatusAccepted), nil
}

But I'm still not sure if it will work on the real scenario.

@lorenzodonini
Copy link
Owner

Hey @KatyushaScarlet , you don't need to marshal anything beforehand. If pre-marshaled, the data field will effectively be a byte array, which will be transformed to base64 when marshaled, which is probably not what you want.

Just pass the following:

data := DataSample{SampleString: "dummyData", SampleValue: 42}
dataConf, err := chargePoint.DataTransfer("vendor1", func(request *core.DataTransferRequest) {
	request.MessageId = "message1"
	request.Data = &data
})

The go struct will be automatically marshaled to JSON.

On the receiving end, since the parser has no idea what type to expect when initially unmarshaling the message, the data is unmarshaled into an interface type (typically a map[string]interface{}).
To parse it into a specific type, you'll need to resort to the workaround you correctly pointed out in the parseDataSample function. This will work in a real-world scenario just fine, assuming you know what data type is being received.

Nevertheless, I'll add a utility function to the data transfer feature to help with unmarshaling the payload into arbitrary types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants