MicroOcpp icon indicating copy to clipboard operation
MicroOcpp copied to clipboard

"data" field in DataTransfer only allow text data. - Example about sendRequest() and setRequestHandler() is wrong.

Open JungHeum-Park opened this issue 11 months ago • 0 comments

Hi @matth-x . I found "data" field in Datatransfer only allow string. In OCPP 1.6 Specification - Edition 2 p.64, defines "data" 's field type as text. Also. There is test case about datatransfer in OCTT.(TC_062) In this test case, if I send JSON Object in data field, the test fails with this info. (The testcase was aborted because The message did not pass JSON schema validation. Reason: #/data: expected type: String, found: JSONObject)

So we need to serialize data to string in "data" field.

In MicroOcpp.h

/*
 * Create and send an operation without using the built-in Operation class. This function bypasses
 * the business logic which comes with this library. E.g. you can send unknown operations, extend
 * OCPP or replace parts of the business logic with custom behavior.
 * 
 * Use case 1, extend the library by sending additional operations. E.g. DataTransfer:
 * 
 * sendRequest("DataTransfer", [] () -> std::unique_ptr<MicroOcpp::JsonDoc> {
 *     //will be called to create the request once this operation is being sent out
 *     size_t capacity = JSON_OBJECT_SIZE(3) +
 *                       JSON_OBJECT_SIZE(2); //for calculating the required capacity, see https://arduinojson.org/v6/assistant/
 *     auto res = std::unique_ptr<MicroOcpp::JsonDoc>(new MicroOcpp::JsonDoc(capacity)); 
 *     JsonObject request = *res;
 *     request["vendorId"] = "My company Ltd.";
 *     request["messageId"] = "TargetValues";
 *     request["data"]["battery_capacity"] = 89;
 *     request["data"]["battery_soc"] = 34;
 *     return res;
 * }, [] (JsonObject response) -> void {
 *     //will be called with the confirmation response of the server
 *     if (!strcmp(response["status"], "Accepted")) {
 *         //DataTransfer has been accepted
 *         int max_energy = response["data"]["max_energy"];
 *     }
 * });
 * 
 * Use case 2, bypass the business logic of this library for custom behavior. E.g. StartTransaction:
 * 
 * sendRequest("StartTransaction", [] () -> std::unique_ptr<MicroOcpp::JsonDoc> {
 *     //will be called to create the request once this operation is being sent out
 *     size_t capacity = JSON_OBJECT_SIZE(4); //for calculating the required capacity, see https://arduinojson.org/v6/assistant/
 *     auto res = std::unique_ptr<MicroOcpp::JsonDoc>(new MicroOcpp::JsonDoc(capacity)); 
 *     JsonObject request = res->to<JsonObject>();
 *     request["connectorId"] = 1;
 *     request["idTag"] = "A9C3CE1D7B71EA";
 *     request["meterStart"] = 1234;
 *     request["timestamp"] = "2023-06-01T11:07:43Z"; //e.g. some historic transaction
 *     return res;
 * }, [] (JsonObject response) -> void {
 *     //will be called with the confirmation response of the server
 *     const char *status = response["idTagInfo"]["status"];
 *     int transactionId = response["transactionId"];
 * });
 * 
 * In Use case 2, the library won't send any further StatusNotification or StopTransaction on
 * its own.
 */
void sendRequest(const char *operationType,
            std::function<std::unique_ptr<MicroOcpp::JsonDoc> ()> fn_createReq,
            std::function<void (JsonObject)> fn_processConf);

/*
 * Set a custom handler for an incoming operation type. This will update the core Operation registry
 * of the library, potentially replacing the built-in Operation handler and bypassing the
 * business logic of this library.
 * 
 * Note that when replacing an operation handler, the attached listeners will be reset.
 * 
 * Example usage:
 * 
 * setRequestHandler("DataTransfer", [] (JsonObject request) -> void {
 *     //will be called with the request message from the server
 *     const char *vendorId = request["vendorId"];
 *     const char *messageId = request["messageId"];
 *     int battery_capacity = request["data"]["battery_capacity"];
 *     int battery_soc = request["data"]["battery_soc"];
 * }, [] () -> std::unique_ptr<MicroOcpp::JsonDoc> {
 *     //will be called  to create the response once this operation is being sent out
 *     size_t capacity = JSON_OBJECT_SIZE(2) +
 *                       JSON_OBJECT_SIZE(1); //for calculating the required capacity, see https://arduinojson.org/v6/assistant/
 *     auto res = std::unique_ptr<MicroOcpp::JsonDoc>(new MicroOcpp::JsonDoc(capacity)); 
 *     JsonObject response = res->to<JsonObject>();
 *     response["status"] = "Accepted";
 *     response["data"]["max_energy"] = 59;
 *     return res;
 * });
 */
void setRequestHandler(const char *operationType,
            std::function<void (JsonObject)> fn_processReq,
            std::function<std::unique_ptr<MicroOcpp::JsonDoc> ()> fn_createConf);

This example send "data" field as json object

JungHeum-Park avatar Jan 13 '25 10:01 JungHeum-Park