-
Notifications
You must be signed in to change notification settings - Fork 54
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
Fix: OCPP 2.0.1 CS, EVSE, and Connector availability tracking #292
Conversation
7e790a9
to
8d7b0c4
Compare
Confirmed that OCTT Availability test cases pass with this and EVerest/everest-core#459 |
When running OCTT test change availability charging station - inoperative to operative we get unexpected state changes from available to unavailable and back again multiple times. Can you please check on your end if this might be caused by these changes? |
Testing the code we see that the callbacks In the following logging I added where the callbacks are called. 2023-Dec-11 13:59:55.410560 BBOC (BackOfficeCommu:225) [comm ] [in ][2, "1112611f-ce33-42a7-9270-502bc90f3049", "ChangeAvailability", {"operationalStatus":"Operative"}]
2023-Dec-11 13:59:55.410685 BBOC (BackOfficeCommu:222) [comm ] [out][3,"1112611f-ce33-42a7-9270-502bc90f3049",{"status":"Accepted"}]
2023-Dec-11 13:59:55.410765 BBOC (AvailabilityHan:292) [info ] status: Operative persist: false **<-- (change_effective_availability_callback)**
2023-Dec-11 13:59:55.437280 BBOC (TransactionHand:299) [info ] Connector #1: : Change: 160 ---> 1
2023-Dec-11 13:59:55.437376 BBOC (AvailabilityHan:403) [info ] connectorStatus: Available
OperationalStatusEnum: Operative
2023-Dec-11 13:59:55.437572 BBOC (AvailabilityHan:292) [info ] status: Operative persist: true **<-- (persist_availability_setting_callback)**
2023-Dec-11 13:59:55.437645 BBOC (BackOfficeCommu:222) [comm ] [out][2,"ad3dcfa5-0695-488e-a71b-8006db2ca3c6","StatusNotification",{"connectorId":1,"connectorStatus":"Available","evseId":1,"timestamp":"2023-12-11T13:59:55.437Z"}]
2023-Dec-11 13:59:55.442844 BBOC (AvailabilityHan:292) [info ] status: Operative persist: false **<-- (change_effective_availability_callback)** |
libocpp will call the The |
94337ef
to
6f315ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically I think this works fine; however, I am afraid it is still too complex (might be hard to maintain in the future)
A "simpler" thing I would suggest is to make the public interfaces more explicit (instead of having a lot of optional values, split the public interface into dedicated methods that clearly express the effect in the name (set_evse_operational_status, set_connector_operational_status; drop this "is_boot" parameter but instead create a update method to recompute the effective status)
But an actual thought I have: To me it seems a lot of the code complexity stems from keeping the statuses in sync. So as first step I would suggest to extract this responsibility of computing the effective status (since it needs to have a "global" view on the cs, evses, connectors ) into a dedicated class that can compute the effective status for each level. And then indeed I would rather just compute the effective state each time it is requested (since that is cheap) instead of having is stored redundantly.
But let's talk about this rather in a call ;)
lib/ocpp/v201/database_handler.cpp
Outdated
insert_stmt.bind_int("@evse_id", evse_id.value_or(0)); | ||
insert_stmt.bind_int("@connector_id", connector_id.value_or(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I understand correctly that for connector_id = 0 you refer to the evse, and for both 0 the whole CS?
And evse_id = 0 is invalid for any connector_id != 0 , right?
If so, I would suggest to split up the public interface of this handler into three dedicated methods for each use case ( insert_cs_availability
(no ids as inputs), insert_evse_availability
(evse id as input), insert_connector_availability
(evse and connector ids as inputs) which then can privately call exactly this implementation (would be clearer to me and avoid possible misusage)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored!
lib/ocpp/v201/database_handler.cpp
Outdated
OperationalStatusEnum DatabaseHandler::get_availability(const std::optional<int32_t> evse_id, | ||
std::optional<int32_t> connector_id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as for insert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commited by accident
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
lib/ocpp/v201/charge_point.cpp
Outdated
void ChargePoint::set_operative_status(std::optional<int32_t> evse_id, std::optional<int32_t> connector_id, | ||
OperationalStatusEnum new_status, bool persist, bool is_boot) { | ||
OperationalStatusEnum old_op_status = this->operative_status; | ||
if (!evse_id.has_value()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand this works correctly, but I would assume in the future this can get confusing again for someone not that deep into how this works ("why don't I care about the connector_id?")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored - there are now separate methods for setting CS, EVSE, and connector statuses.
fe11475
to
d1e02ac
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put a bunch of comments into the code; not fully conclusive, but I would suggest best way to deal with it is just have a pairing session (in the end I think this is all really just about readability and maintainability of the code, which is also a matter of style & taste of course)
8c74f78
to
ff9ca60
Compare
if (!transaction_active) { | ||
// execute change availability if possible | ||
this->callbacks.change_availability_callback(msg, true); | ||
// No transactions - execute the change now | ||
this->execute_change_availability_request(msg, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This differs from the original behaviour - in this current state, libocpp will NOT call the callback if the effective state of the components did not change.
for (auto const& [evse_id, evse] : this->evses) { | ||
if (!evse->has_active_transaction()) { | ||
this->set_evse_connectors_unavailable(evse, false); | ||
// FIXME: This will linger after the update too! We probably need another mechanism... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably a bug. Need to write an issue/ticket about this.
@hikinggrass : I reviewed this together with @valentin-dimov ; besides the two comments by @valentin-dimov (those we can discuss; probably those are out of scope for this PR), for me this looks good - but I think you (or someone as involved as you) should approve/re-check first |
Just tested the branch. There seems to be bug where if you change the chargingStation to inoperative and then back of operative, to connector is not updated to operative. You have to send a operative for the connector specifically to fix it afterwards. See our logging where I added the callback as logging 2024-Jan-09 15:46:37.896884 BBOC (BackOfficeCommu:219) [comm ] [in ][3,"4528285b-466a-4e01-bcbb-57c0c3e59aa7",{}]
2024-Jan-09 15:47:31.443887 BBOC (BackOfficeCommu:219) [comm ] [in ][2,"1d81f457-3454-4fcc-a6c9-88a848001b52","ChangeAvailability",{"operationalStatus":"Inoperative"}]
2024-Jan-09 15:47:31.444615 BBOC (BackOfficeCommu:216) [comm ] [out][3,"1d81f457-3454-4fcc-a6c9-88a848001b52",{"status":"Accepted"}]
2024-Jan-09 15:47:31.462177 BBOC (BackOfficeCommu:164) [info ] connector_effective_operative_status_changed_callback: evse_id: 1 connector_id: 1 new_status: Inoperative
2024-Jan-09 15:47:31.464886 BBOC (BackOfficeCommu:216) [comm ] [out][2,"998d38b3-8595-4955-840d-f8cbc46f6d9b","StatusNotification",{"connectorId":1,"connectorStatus":"Unavailable","evseId":1,"timestamp":"2024-01-09T15:47:31.464Z"}]
2024-Jan-09 15:47:31.502163 BBOC (BackOfficeCommu:219) [comm ] [in ][3,"998d38b3-8595-4955-840d-f8cbc46f6d9b",{}]
2024-Jan-09 15:47:31.510147 BBOC (TransactionHand:299) [info ] Connector #1: : Change: 1 ---> 160
2024-Jan-09 15:47:37.812339 BBOC (device_model.cp:112) [warning ] [libocpp] unknown component in ISO15118Ctrlr.V2GCertificateInstallationEnabled
2024-Jan-09 15:47:37.812580 BBOC (device_model.cp:112) [warning ] [libocpp] unknown component in ISO15118Ctrlr.PnCEnabled
2024-Jan-09 15:47:37.812644 BBOC (device_model.cp:120) [warning ] [libocpp] unknown variable in InternalCtrlr.V2GCertificateExpireCheckIntervalSeconds
2024-Jan-09 15:47:47.007601 BBOC (BackOfficeCommu:219) [comm ] [in ][2,"f0859086-7e87-48dd-a662-7923e6c0453c","ChangeAvailability",{"operationalStatus":"Operative"}]
2024-Jan-09 15:47:47.007769 BBOC (BackOfficeCommu:216) [comm ] [out][3,"f0859086-7e87-48dd-a662-7923e6c0453c",{"status":"Accepted"}]
2024-Jan-09 15:47:54.758691 BBOC (BackOfficeCommu:219) [comm ] [in ][2,"689c5392-9336-41ba-bb26-b55470e629fd","ChangeAvailability",{"operationalStatus":"Operative","evse":{"id":1,"connectorId":1}}]
2024-Jan-09 15:47:54.758992 BBOC (BackOfficeCommu:216) [comm ] [out][3,"689c5392-9336-41ba-bb26-b55470e629fd",{"status":"Accepted"}]
2024-Jan-09 15:47:54.775972 BBOC (BackOfficeCommu:164) [info ] connector_effective_operative_status_changed_callback: evse_id: 1 connector_id: 1 new_status: Operative
2024-Jan-09 15:47:54.778600 BBOC (BackOfficeCommu:216) [comm ] [out][2,"55b4aab5-c698-48fc-b35f-824b34975b50","StatusNotification",{"connectorId":1,"connectorStatus":"Available","evseId":1,"timestamp":"2024-01-09T15:47:54.778Z"}]
2024-Jan-09 15:47:54.815825 BBOC (BackOfficeCommu:219) [comm ] [in ][3,"55b4aab5-c698-48fc-b35f-824b34975b50",{}]
2024-Jan-09 15:47:54.826826 BBOC (TransactionHand:299) [info ] Connector #1: : Change: 160 ---> 1
|
/// Note: It is expected that ComponentStateManager::trigger_all_effective_availability_changed_callbacks is called | ||
/// on boot, and ComponentStateManager::send_status_notification_all_connectors is called when first connected to | ||
/// the CSMS. \param evse_connector_structure Maps each EVSE ID to the number of connectors the EVSE has \param | ||
/// db_handler A shared reference to the persistent database \param send_connector_status_notification_callback The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting of these \param entries is quite hard to read
5ebf6a7
to
94edef1
Compare
* Introduced component_state_managager which stores and monitors operational/effective states of the CS, EVSEs, and connectors * Introduced three callbacks cs_effective_operative_status_changed_callback, evse_effective_operative_status_changed_callback, connector_effective_operative_status_changed_callback that are called in case of operative state changes for each component * extended ocpp201 database_handler to store operational states persistently * libocpp user is required to call on_unavailable and on_enabled for connectors as a result of operative_status_changed_callback(s). Signed-off-by: pietfried <[email protected]> Signed-off-by: Valentin DImov <[email protected]>
3cbb6f5
to
5fface8
Compare
…_status in send_status_notification_single_connector_internal * applied same change in initialize_reported_state_cache * removed unused function connector_status_to_operational_status * fixed CMakeLists.txt in test dir * removed obsolete test cases Signed-off-by: pietfried <[email protected]>
5fface8
to
468bedb
Compare
Companion PR from everest-core: EVerest/everest-core#459