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

Support OCPP 2.1 variables #988

Merged

Conversation

maaikez
Copy link
Contributor

@maaikez maaikez commented Feb 17, 2025

Describe your changes

Add support for OCPP 2.1 variables and add check for required variables in device model.

Issue ticket number and link

Checklist before requesting a review

@maaikez maaikez force-pushed the feature/v21/variable-support branch from c891edf to b6d5d8b Compare February 17, 2025 14:02
@Pietfried Pietfried force-pushed the feature/v21/variable-support branch from b6d5d8b to 1212a82 Compare February 17, 2025 17:01
Copy link
Contributor

@Pietfried Pietfried left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One general issue I see with this change is that you can now define device models that are valid according to the new integrity check but could lead to unhandled exceptions at runtime. Lets have a look at an example.

AlignedDataCtrlr.AlignedDataTxEndedInterval is only required if AlignedDataCtrlr.Available is true. So you can define a device model that doenst contain AlignedDataCtrlr.AlignedDataTxEndedInterval. In the code, we just access AlignedDataCtrlr.AlignedDataTxEndedInterval using this->device_model.get_value<int>(ControllerComponentVariables::AlignedDataTxEndedInterval). This leads to an unhandled exception.

I see three options:

  1. Define every variable that is required only if the Available variable of the Controller is present and true as a ComponentVariable and not a RequiredComponentVariable. This avoids the option to use get_value and forces us to use get_optional_value instead.
    This is the safest option, but it leads to quite some changes in code.

  2. Keep defining these variables as RequiredComponentVariable and use get_value but make sure everywhere where it is called that the Available variable is checked.
    Requires fewer changes than 1) but we can still crash at runtime

  3. We could enforce that more controllers are required than in the specification. This is also how the code was written (if the spec says a variable is required we require it, no matter what value Available of the Controller has. Libocpp does support the AlignedDataCtrlr features, so it must also be present. Same is true for SampledDataCtrlr so we can enforce that they are present and available. LocalAuthListCtrlr, SmartChargingCtrlr, TariffCostCtrlr, MonitoringCtrlr and DisplayMessageCtrlr I would consider optional and we could then go with option 2).
    Only few changes in existing code. We still need to protect code blocks where variables are accessed directly using get_value. The introduction of the functional blocks should make this easier though.

Interested in your thoughts @maaikez and @marcemmers .

Comment on lines 2243 to 2269
///
/// \brief Required ComponentVariable.
///
struct RequiredComponentVariable : ComponentVariable {
/// \brief Constructor
RequiredComponentVariable() : required_for({OcppProtocolVersion::v201, OcppProtocolVersion::v21}) {};

///
/// \brief RequiredComponentVariable
/// \param component Component
/// \param variable Variable
/// \param custom_data Custom data (default nullopt)
/// \param required_for Required for which version. Multiple versions can be given.
///
RequiredComponentVariable(const Component component, const std::optional<Variable> variable,
const std::optional<CustomData> custom_data = std::nullopt,
const std::set<OcppProtocolVersion> required_for = {OcppProtocolVersion::v201,
OcppProtocolVersion::v21}) :
ComponentVariable(), required_for(required_for) {
this->component = component;
this->variable = variable;
this->customData = custom_data;
};

/// \brief For which ocpp protocol version(s) this component variable is required.
std::set<OcppProtocolVersion> required_for;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is auto-generated. You either need to define this elsewhere or adjust the jinja template in https://github.com/EVerest/libocpp/blob/main/src/code_generator/common/templates/ocpp_types.hpp.jinja . I would prefer to move the definition into the device_model.hpp and therefore remove it from the jinja template

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm there will be a circular dependency then (DeviceModel <-> CtrlrComponentVariables).
Why not add it in CtrlrComponentVariables?

@@ -456,36 +456,6 @@ int32_t DeviceModelStorageSqlite::clear_custom_variable_monitors() {
}

void DeviceModelStorageSqlite::check_integrity() {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a comment here with the reason why its empty

}
};

TEST_F(DeviceModelTest, test_allow_zero2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: test_allow_zero2 defined before test_allow_zero looks a little bit odd. A name like test_min_limit_and_allow_zero is probably better

@maaikez
Copy link
Contributor Author

maaikez commented Feb 19, 2025

One general issue I see with this change is that you can now define device models that are valid according to the new integrity check but could lead to unhandled exceptions at runtime. Lets have a look at an example.

...

I see three options:

...

2. Keep defining these variables as `RequiredComponentVariable` and use `get_value` but make sure everywhere where it is called that the `Available` variable is checked.
   Requires fewer changes than 1) but we can still crash at runtime

3. We could enforce that more controllers are required than in the specification. This is also how the code was written (if the spec says a variable is required we require it, no matter what value `Available` of the Controller has. Libocpp does support the `AlignedDataCtrlr` features, so it must also be present. Same is true for `SampledDataCtrlr` so we can enforce that they are present and available. `LocalAuthListCtrlr`, `SmartChargingCtrlr`, `TariffCostCtrlr`, `MonitoringCtrlr` and `DisplayMessageCtrlr` I would consider optional and we could then go with option 2).
   Only few changes in existing code. We still need to protect code blocks where variables are accessed directly using `get_value`. The introduction of the functional blocks should make this easier though.

Interested in your thoughts @maaikez and @marcemmers .

I would say 3 (in combination with 2). This is the way libocpp is written so we should just make the components available that we depend on. I also see no use in making them optional (AlignedDataCtrlr and SampledDataCtrlr).

@Pietfried Pietfried self-assigned this Feb 19, 2025
@maaikez maaikez force-pushed the feature/v21/variable-support branch from 61c4a82 to 256556e Compare February 20, 2025 10:03
Pietfried and others added 9 commits February 20, 2025 16:50
…y for which ocpp version a variable is required. This is the base to continue implementing a device model integrity check inside libocpps DeviceModel class

Signed-off-by: Piet Gömpel <pietgoempel@gmail.com>
Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
…e changes. Add documentation

Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
…d the required variables are really always required. Only make smart charging ctrlr if smart charging is available.

Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
…nt is available) and if they are not used while the whole ctrlr is not available..

Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
…variables.

Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
@maaikez maaikez force-pushed the feature/v21/variable-support branch from 085c47d to 6dc5f86 Compare February 20, 2025 17:41
…pt instead of customData.

Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
@maaikez maaikez force-pushed the feature/v21/variable-support branch from 6dc5f86 to 9f6d312 Compare February 20, 2025 17:44
Copy link
Contributor

@Pietfried Pietfried left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
@maaikez maaikez force-pushed the feature/v21/variable-support branch from 8ae041f to ffbcce1 Compare February 24, 2025 10:08
Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl>
@maaikez maaikez merged commit 9c9c481 into feature/ocpp2.1-public-draft-messages Feb 24, 2025
7 of 8 checks passed
@maaikez maaikez deleted the feature/v21/variable-support branch February 24, 2025 11:48
Copy link
Contributor

@Pietfried Pietfried left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed that this has been already merged, Im still submitting the comments so we could add them later

There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and
`SampledDataCtrlr`.
When libocpp is started and initialized, all required Variables will be checked and an DeviceModelError is thrown if
one of the required Variables is not there.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
one of the required Variables is not there.
one of the required Variables is not present.


There are some required Variables, which can be found in the OCPP spec.
Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.
There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and
There are some Components that are always required because they are required by libocpp: `AlignedDataCtrlr` and


## Required variables

There are some required Variables, which can be found in the OCPP spec.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There are some required Variables, which can be found in the OCPP spec.
There are Variables that are defined as **required** in the OCPP specification.

## Required variables

There are some required Variables, which can be found in the OCPP spec.
Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.
Some `Variables` are only required if the `Available` variable of the respective `Component` is present and configured to true. Examples for this are the `ReservationCtrlr` and the `SmartChargingCtrlr`.

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

Successfully merging this pull request may close these issues.

2 participants