diff --git a/modules/OCPPConfiguration/OCPPConfiguration.cpp b/modules/OCPPConfiguration/OCPPConfiguration.cpp index 6fc7730a20..ef5ed2ba7e 100644 --- a/modules/OCPPConfiguration/OCPPConfiguration.cpp +++ b/modules/OCPPConfiguration/OCPPConfiguration.cpp @@ -13,9 +13,6 @@ void OCPPConfiguration::init() { void OCPPConfiguration::ready() { invoke_ready(*p_main); - auto wait_attached = false; - while (wait_attached) { - }; const auto mapping_file_path = std::filesystem::path{config.mapping_file_path}; event_handler = std::make_unique(mapping_file_path); diff --git a/modules/OCPPConfiguration/config-mapping.yaml b/modules/OCPPConfiguration/config-mapping.yaml index 96f86082cc..bb16c59347 100644 --- a/modules/OCPPConfiguration/config-mapping.yaml +++ b/modules/OCPPConfiguration/config-mapping.yaml @@ -1,337 +1,312 @@ -AllowOfflineTxForUnknownId: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: allow_offline_tx_for_unknown_id - config_key: allow_offline_tx_for_unknown_id_config - - mapping: - component: - name: ocpp - instance: 2 - evse: - id: 2 - connector_id: 2 - variable: - instance: 2 - maps_to: - module_id: allow_offline_tx_for_unknown_id - config_key: allow_offline_tx_for_unknown_id_config -AuthorizationCacheEnabled: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: authorization_cache_enabled - config_key: authorization_cache_enabled_config -AuthorizeRemoteTxRequests: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: authorize_remote_tx_requests - config_key: authorize_remote_tx_requests_config -BlinkRepeat: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: blink_repeat - config_key: blink_repeat_config -ClockAlignedDataInterval: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: clock_aligned_data_interval - config_key: clock_aligned_data_interval_config -ConnectionTimeOut: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: connection_time_out - config_key: connection_time_out_config -ConnectorPhaseRotation: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: connector_phase_rotation - config_key: connector_phase_rotation_config -HeartbeatInterval: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: heartbeat_interval - config_key: heartbeat_interval_config -LightIntensity: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: light_intensity - config_key: light_intensity_config -LocalAuthorizeOffline: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: local_authorize_offline - config_key: local_authorize_offline_config -LocalPreAuthorize: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: local_pre_authorize - config_key: local_pre_authorize_config -MaxEnergyOnInvalidId: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: max_energy_on_invalid_id - config_key: max_energy_on_invalid_id_config -MeterValuesAlignedData: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: meter_values_aligned_data - config_key: meter_values_aligned_data_config -MeterValuesSampledData: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: meter_values_sampled_data - config_key: meter_values_sampled_data_config -MeterValueSampleInterval: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: meter_value_sample_interval - config_key: meter_value_sample_interval_config -MinimumStatusDuration: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: minimum_status_duration - config_key: minimum_status_duration_config -ResetRetries: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: reset_retries - config_key: reset_retries_config -StopTransactionOnEVSideDisconnect: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: stop_transaction_on_ev_side_disconnect - config_key: stop_transaction_on_ev_side_disconnect_config -StopTransactionOnInvalidId: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: stop_transaction_on_invalid_id - config_key: stop_transaction_on_invalid_id_config -StopTxnAlignedData: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: stop_txn_aligned_data - config_key: stop_txn_aligned_data_config -StopTxnSampledData: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: stop_txn_sampled_data - config_key: stop_txn_sampled_data_config -TransactionMessageAttempts: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: transaction_message_attempts - config_key: transaction_message_attempts_config -TransactionMessageRetryInterval: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: transaction_message_retry_interval - config_key: transaction_message_retry_interval_config -UnlockConnectorOnEVSideDisconnect: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: unlock_connector_on_ev_side_disconnect - config_key: unlock_connector_on_ev_side_disconnect_config -WebsocketPingInterval: - - mapping: - component: - name: ocpp - instance: 1 - evse: - id: 1 - connector: 1 - variable: - instance: 1 - maps_to: - module_id: websocket_ping_interval - config_key: websocket_ping_interval_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: AllowOfflineTxForUnknownId + instance: 1 + maps_to: + module_id: allow_offline_tx_for_unknown_id + config_key: allow_offline_tx_for_unknown_id_config +- component: + name: ocpp + instance: 2 + evse: + id: 2 + connector_id: 2 + variable: + name: AllowOfflineTxForUnknownId + instance: 2 + maps_to: + module_id: allow_offline_tx_for_unknown_id + config_key: allow_offline_tx_for_unknown_id_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: AuthorizationCacheEnabled + instance: 1 + maps_to: + module_id: authorization_cache_enabled + config_key: authorization_cache_enabled_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: AuthorizeRemoteTxRequests + instance: 1 + maps_to: + module_id: authorize_remote_tx_requests + config_key: authorize_remote_tx_requests_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: BlinkRepeat + instance: 1 + maps_to: + module_id: blink_repeat + config_key: blink_repeat_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: ClockAlignedDataInterval + instance: 1 + maps_to: + module_id: clock_aligned_data_interval + config_key: clock_aligned_data_interval_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: ConnectionTimeOut + instance: 1 + maps_to: + module_id: connection_time_out + config_key: connection_time_out_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: ConnectorPhaseRotation + instance: 1 + maps_to: + module_id: connector_phase_rotation + config_key: connector_phase_rotation_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: HeartbeatInterval + instance: 1 + maps_to: + module_id: heartbeat_interval + config_key: heartbeat_interval_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: LightIntensity + instance: 1 + maps_to: + module_id: light_intensity + config_key: light_intensity_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: LocalAuthorizeOffline + instance: 1 + maps_to: + module_id: local_authorize_offline + config_key: local_authorize_offline_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: LocalPreAuthorize + instance: 1 + maps_to: + module_id: local_pre_authorize + config_key: local_pre_authorize_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: MaxEnergyOnInvalidId + instance: 1 + maps_to: + module_id: max_energy_on_invalid_id + config_key: max_energy_on_invalid_id_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: MeterValuesAlignedData + instance: 1 + maps_to: + module_id: meter_values_aligned_data + config_key: meter_values_aligned_data_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: MeterValuesSampledData + instance: 1 + maps_to: + module_id: meter_values_sampled_data + config_key: meter_values_sampled_data_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: MeterValueSampleInterval + instance: 1 + maps_to: + module_id: meter_value_sample_interval + config_key: meter_value_sample_interval_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: MinimumStatusDuration + instance: 1 + maps_to: + module_id: minimum_status_duration + config_key: minimum_status_duration_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: ResetRetries + instance: 1 + maps_to: + module_id: reset_retries + config_key: reset_retries_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: StopTransactionOnEVSideDisconnect + instance: 1 + maps_to: + module_id: stop_transaction_on_ev_side_disconnect + config_key: stop_transaction_on_ev_side_disconnect_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: StopTransactionOnInvalidId + instance: 1 + maps_to: + module_id: stop_transaction_on_invalid_id + config_key: stop_transaction_on_invalid_id_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: StopTxnAlignedData + instance: 1 + maps_to: + module_id: stop_txn_aligned_data + config_key: stop_txn_aligned_data_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: StopTxnSampledData + instance: 1 + maps_to: + module_id: stop_txn_sampled_data + config_key: stop_txn_sampled_data_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: TransactionMessageAttempts + instance: 1 + maps_to: + module_id: transaction_message_attempts + config_key: transaction_message_attempts_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: TransactionMessageRetryInterval + instance: 1 + maps_to: + module_id: transaction_message_retry_interval + config_key: transaction_message_retry_interval_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: UnlockConnectorOnEVSideDisconnect + instance: 1 + maps_to: + module_id: unlock_connector_on_ev_side_disconnect + config_key: unlock_connector_on_ev_side_disconnect_config +- component: + name: ocpp + instance: 1 + evse: + id: 1 + connector: 1 + variable: + name: WebsocketPingInterval + instance: 1 + maps_to: + module_id: websocket_ping_interval + config_key: websocket_ping_interval_config diff --git a/modules/OCPPConfiguration/main/mapping_reader.cpp b/modules/OCPPConfiguration/main/mapping_reader.cpp index 4c692c5667..dcb2636115 100644 --- a/modules/OCPPConfiguration/main/mapping_reader.cpp +++ b/modules/OCPPConfiguration/main/mapping_reader.cpp @@ -4,49 +4,47 @@ #include "mapping_reader.hpp" #include "everest/logging.hpp" #include "util.hpp" -#include #include namespace module { OcppToEverestConfigMapping MappingReader::read_mapping(const std::filesystem::path& file_path) { const auto hacked_file_path = std::filesystem::path{"modules"} / "OCPPConfiguration" / file_path; // TODO: this is very hacky - const auto tree = Util::load_existing_user_config(hacked_file_path); + const auto tree = Util::load_existing_user_config(hacked_file_path); const auto root = tree.rootref(); + return parse_mapping(root); +} +OcppToEverestConfigMapping MappingReader::parse_mapping(const c4::yml::NodeRef& root) { auto mapping = OcppToEverestConfigMapping{}; - for (const auto& variables_sequence_node : root.children()) { - const auto key = variables_sequence_node.key(); - const auto variable_name = std::string{key.str, key.len}; - - for (const auto& mappings_sequence_node : variables_sequence_node.children()) { - - for (auto const& mapping_node : mappings_sequence_node.children()) { - auto component_variable = parse_component_variable_node(variable_name, mapping_node); - - auto module_mapping = parse_mapping_node(mapping_node["maps_to"]); - - mapping.insert({std::move(component_variable), std::move(module_mapping)}); - } - } + for (const auto& mapping_node : root) { + auto mapped_node = parse_mapping_node(mapping_node); + mapping.insert(std::move(mapped_node)); } - return mapping; } +std::pair +MappingReader::parse_mapping_node(const c4::yml::NodeRef& mapping_node) { + auto component_variable = parse_component_variable_node(mapping_node); + auto module_mapping = parse_maps_to_node(mapping_node["maps_to"]); + return {std::move(component_variable), std::move(module_mapping)}; +} -ComponentVariable MappingReader::parse_component_variable_node(std::string variable_name, const c4::yml::NodeRef& node) { +ComponentVariable MappingReader::parse_component_variable_node(const c4::yml::NodeRef& node) { + // component is optional auto component = node.has_child("component") ? parse_component_node(node["component"]) : Component{}; - auto variable = node.has_child("variable") ? parse_variable_node(variable_name, node["variable"]) - : Variable{.name = variable_name}; + + // variable is required + auto variable = parse_variable_node(node["variable"]); return {std::move(component), std::move(variable)}; } Component MappingReader::parse_component_node(const c4::yml::NodeRef& node) { auto evse = node.has_child("evse") ? parse_evse_node(node["evse"]) : std::nullopt; - auto instance_optinal_val = node.has_child("instance") ? std::optional{node["instance"].val()} : std::nullopt; + const auto instance_optinal_val = node.has_child("instance") ? std::optional{node["instance"].val()} : std::nullopt; auto instance = instance_optinal_val.has_value() ? std::optional{std::string{instance_optinal_val.value().str, instance_optinal_val.value().len}} : std::nullopt; @@ -55,8 +53,22 @@ Component MappingReader::parse_component_node(const c4::yml::NodeRef& node) { return {std::move(component_name), std::move(instance), std::move(evse)}; } -Variable MappingReader::parse_variable_node(std::string variable_name, const c4::yml::NodeRef node) { - auto instance_optional_val = node.has_child("instance") ? std::optional{node["instance"].val()} : std::nullopt; +Variable MappingReader::parse_variable_node(const c4::yml::NodeRef node) { + const auto node_has_name = node.has_child("name"); + if (!node_has_name) { + throw std::runtime_error("Variable node must have a name"); + } + + const auto name_has_val = node["name"].has_val(); + if (!name_has_val) { + throw std::runtime_error("Variable name must have a value"); + } + + const auto variable_name_val = node["name"].val(); + auto variable_name = std::string{variable_name_val.str, variable_name_val.len}; + + const auto instance_optional_val = + node.has_child("instance") ? std::optional{node["instance"].val()} : std::nullopt; auto instance = instance_optional_val.has_value() ? std::optional{std::string{instance_optional_val.value().str, instance_optional_val.value().len}} @@ -68,10 +80,10 @@ std::optional MappingReader::parse_evse_node(const c4::yml::N if (!node.has_child("id")) { throw std::runtime_error("EVSE node must have an id"); } - auto id_val = node["id"].val(); + const auto id_val = node["id"].val(); auto id = std::stoi(std::string{id_val.str, id_val.len}); - auto connector_id_optional_val = node.has_child("id") ? std::optional{node["id"].val()} : std::nullopt; + const auto connector_id_optional_val = node.has_child("id") ? std::optional{node["id"].val()} : std::nullopt; auto connector_id = connector_id_optional_val.has_value() ? std::optional{std::stoi(std::string{connector_id_optional_val.value().str, connector_id_optional_val.value().len})} @@ -80,7 +92,7 @@ std::optional MappingReader::parse_evse_node(const c4::yml::N return types::ocpp::EVSE{std::move(id), std::move(connector_id)}; } -EverestConfigMapping MappingReader::parse_mapping_node(const ryml::NodeRef& node) { +EverestConfigMapping MappingReader::parse_maps_to_node(const ryml::NodeRef& node) { const auto parse_node = [](const auto& node) { const auto val = node.val(); diff --git a/modules/OCPPConfiguration/main/mapping_reader.hpp b/modules/OCPPConfiguration/main/mapping_reader.hpp index 922045883d..963a2036e3 100644 --- a/modules/OCPPConfiguration/main/mapping_reader.hpp +++ b/modules/OCPPConfiguration/main/mapping_reader.hpp @@ -25,11 +25,13 @@ class MappingReader { static OcppToEverestConfigMapping read_mapping(const std::filesystem::path& file_path); private: - static EverestConfigMapping parse_mapping_node(const ryml::NodeRef& node); + static std::pair parse_mapping_node(const c4::yml::NodeRef& mapping_node); + static EverestConfigMapping parse_maps_to_node(const ryml::NodeRef& node); static types::ocpp::Component parse_component_node(const c4::yml::NodeRef& node); static std::optional parse_evse_node(const c4::yml::NodeRef node); - static types::ocpp::Variable parse_variable_node(std::string variable_name, const c4::yml::NodeRef node); - static ComponentVariable parse_component_variable_node(std::string variable_name, const c4::yml::NodeRef& node); + static Variable parse_variable_node(const c4::yml::NodeRef node); + static ComponentVariable parse_component_variable_node(const c4::yml::NodeRef& node); + static OcppToEverestConfigMapping parse_mapping(const c4::yml::NodeRef& root); }; } // namespace module \ No newline at end of file