Files
cariflex/tools/EVerest-main/lib/everest/ocpp/src/charge_point.cpp
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

322 lines
13 KiB
C++

// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#include <chrono>
#include <condition_variable>
#include <csignal>
#include <date/date.h>
#include <date/tz.h>
#include <fstream>
#include <iostream>
#include <mutex>
#include <sys/prctl.h>
#include <thread>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/program_options.hpp>
#include <everest/logging.hpp>
#include <ocpp/v16/charge_point.hpp>
#include <ocpp/v16/database_handler.hpp>
#include <ocpp/common/cistring.hpp>
#include <ocpp/common/string.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
namespace po = boost::program_options;
ocpp::v16::ChargePoint* charge_point;
bool running = false;
std::mutex m;
int main(int argc, char* argv[]) {
po::options_description desc("OCPP charge point");
desc.add_options()("help,h", "produce help message");
desc.add_options()("maindir", po::value<std::string>(), "set main dir in which the schemas folder resides");
desc.add_options()("conf", po::value<std::string>(), "charge point config relative to maindir");
desc.add_options()("logconf", po::value<std::string>(), "The path to a custom logging.ini");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help") != 0) {
std::cout << desc << "\n";
return 1;
}
std::string maindir = ".";
if (vm.count("maindir") != 0) {
maindir = vm["maindir"].as<std::string>();
}
const auto database_path = "/tmp/ocpp";
const auto share_path = fs::path(maindir) / "share" / "everest" / "modules" / "OCPP";
// initialize logging as early as possible
auto logging_config = share_path / "logging.ini";
if (vm.count("logconf") != 0) {
logging_config = fs::path(vm["logconf"].as<std::string>());
}
Everest::Logging::init(logging_config.string(), "charge_point");
std::string conf = "config.json";
if (vm.count("conf") != 0) {
conf = vm["conf"].as<std::string>();
}
fs::path config_path = share_path / conf;
if (!fs::exists(config_path)) {
EVLOG_error << "Could not find config at: " << config_path;
return 1;
}
std::ifstream ifs(config_path.c_str());
std::string config_file((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
auto json_config = json::parse(config_file);
json_config["Internal"]["LogMessagesFormat"][0] = "console_detailed";
auto user_config_path = fs::path("/tmp") / "user_config.json";
if (fs::exists(user_config_path)) {
std::ifstream ifs(user_config_path.c_str());
std::string user_config_file((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
auto user_config = json::parse(user_config_file);
json_config.merge_patch(user_config);
} else {
std::ofstream fs(user_config_path.c_str());
auto user_config = json::object();
fs << user_config << std::endl;
fs.close();
}
const fs::path sql_init_path = share_path / "core_migrations";
// create the cso_path
const fs::path cso_path = "/tmp/client/cso";
if (!fs::exists(cso_path)) {
fs::create_directories(cso_path);
}
const fs::path csms_path = "/tmp/client/csms";
if (!fs::exists(csms_path)) {
fs::create_directories(csms_path);
}
const fs::path ca_v2g_path = "/tmp/certs/ca/v2g/";
if (!fs::exists(ca_v2g_path)) {
fs::create_directories(ca_v2g_path);
}
const fs::path ca_mo_path = "/tmp/certs/ca/mo/";
if (!fs::exists(ca_mo_path)) {
fs::create_directories(ca_mo_path);
}
if (!fs::is_regular_file("/tmp/certs/ca/v2g/V2G_CA_BUNDLE.pem")) {
fsstd::ofstream("/tmp/certs/ca/v2g/V2G_CA_BUNDLE.pem");
}
if (!fs::is_regular_file("/tmp/certs/ca/mo/MO_CA_BUNDLE.pem")) {
fsstd::ofstream("/tmp/certs/ca/mo//MO_CA_BUNDLE.pem");
}
ocpp::SecurityConfiguration secConfig;
secConfig.csms_ca_bundle = fs::path("/tmp/certs/ca/v2g/V2G_CA_BUNDLE.pem");
secConfig.mf_ca_bundle = fs::path("/tmp/certs/ca/v2g/V2G_CA_BUNDLE.pem");
secConfig.v2g_ca_bundle = fs::path("/tmp/certs/ca/v2g/V2G_CA_BUNDLE.pem");
secConfig.mo_ca_bundle = fs::path("/tmp/certs/ca/mo/MO_CA_BUNDLE.pem");
secConfig.csms_leaf_cert_directory = fs::path("/tmp/client/csms/");
secConfig.csms_leaf_key_directory = fs::path("/tmp/client/csms/");
secConfig.secc_leaf_cert_directory = fs::path("/tmp/client/cso/");
secConfig.secc_leaf_key_directory = fs::path("/tmp/client/cso/");
charge_point = new ocpp::v16::ChargePoint(json_config.dump(), share_path, user_config_path, database_path,
sql_init_path, fs::path("/tmp"), nullptr, secConfig);
/************************************** START REGISTERING CALLBACKS **************************************/
charge_point->register_enable_evse_callback([](std::int32_t connector) {
std::cout << "Callback: "
<< "Enabling chargepoint at connector#" << connector;
return true;
});
charge_point->register_disable_evse_callback([](std::int32_t connector) {
std::cout << "Callback: "
<< "Disabling chargepoint at connector#" << connector;
return true;
});
charge_point->register_pause_charging_callback([](std::int32_t connector) {
std::cout << "Callback: "
<< "Pausing charging at connector#" << connector;
return true;
});
charge_point->register_resume_charging_callback([](std::int32_t connector) {
std::cout << "Callback: "
<< "Resuming charging at connector#" << connector;
return true;
});
charge_point->register_provide_token_callback(
[](const std::string& id_token, const std::vector<std::int32_t>& referenced_connectors, bool prevalidated) {
std::cout << "Callback: "
<< "Received token " << id_token << " for further validation" << std::endl;
});
charge_point->register_stop_transaction_callback([](std::int32_t connector, ocpp::v16::Reason reason) {
std::cout << "Callback: "
<< "Stopping transaction with at connector#" << connector
<< " with reason: " << ocpp::v16::conversions::reason_to_string(reason);
return true;
});
charge_point->register_reserve_now_callback([](std::int32_t reservation_id, std::int32_t connector,
ocpp::DateTime expiryDate, ocpp::CiString<20> idTag,
std::optional<ocpp::CiString<20>> parent_id) {
std::cout << "Callback: "
<< "Reserving connector# " << connector << " for id token: " << idTag.get() << " until "
<< expiryDate;
return ocpp::v16::ReservationStatus::Accepted;
});
charge_point->register_cancel_reservation_callback([](std::int32_t reservation_id) {
std::cout << "Callback: "
<< "Cancelling reservation with id: " << reservation_id;
return true;
});
charge_point->register_unlock_connector_callback([](std::int32_t connector) {
std::cout << "Callback: "
<< "Unlock connector#" << connector;
return ocpp::v16::UnlockStatus::Unlocked;
});
charge_point->register_upload_diagnostics_callback([](const ocpp::v16::GetDiagnosticsRequest& request) {
std::cout << "Callback: "
<< "Uploading Diagnostics file" << std::endl;
ocpp::v16::GetLogResponse r;
r.status = ocpp::v16::LogStatusEnumType::Accepted;
return r;
});
charge_point->register_update_firmware_callback([](const ocpp::v16::UpdateFirmwareRequest msg) {
std::cout << "Callback: "
<< "Updating Firmware" << std::endl;
});
charge_point->register_signed_update_firmware_callback([](ocpp::v16::SignedUpdateFirmwareRequest msg) {
std::cout << "Callback: "
<< "Updating Signed Firmware" << std::endl;
return ocpp::v16::UpdateFirmwareStatusEnumType::Accepted;
});
charge_point->register_upload_logs_callback([](ocpp::v16::GetLogRequest req) {
std::cout << "Callback: "
<< "Uploading Logs" << std::endl;
ocpp::v16::GetLogResponse r;
r.status = ocpp::v16::LogStatusEnumType::Accepted;
return r;
});
charge_point->register_set_connection_timeout_callback([](std::int32_t connection_timeout) {
std::cout << "Callback: "
<< "Setting connection timeout" << std::endl;
});
charge_point->register_reset_callback([](const ocpp::v16::ResetType& reset_type) {
std::cout << "Callback: "
<< "Exectuting: " << ocpp::v16::conversions::reset_type_to_string(reset_type) << " reset"
<< std::endl;
return true;
});
charge_point->register_set_system_time_callback([](const std::string& system_time) {
std::cout << "Callback: "
<< "Setting system time to " << system_time;
});
charge_point->register_signal_set_charging_profiles_callback([]() {
std::cout << "Callback: "
<< "Setting charging profiles" << std::endl;
});
charge_point->register_transaction_updated_callback([](const std::int32_t connector, const std::string& session_id,
const std::int32_t transaction_id,
const ocpp::v16::IdTagInfo& id_tag_info) {
std::cout << "Callback: Transaction updated at connector# " << connector
<< " and transaction id: " << transaction_id << std::endl;
});
/************************************** STOP REGISTERING CALLBACKS **************************************/
charge_point->start();
{
std::lock_guard<std::mutex> lk(m);
running = true;
}
std::thread t1([&] {
std::int32_t value = 0;
bool transaction_running = false;
while (!std::cin.fail() && running) {
std::string command;
std::cin >> command;
std::cout << std::endl;
std::string uuid;
if (command == "auth") {
auto result = charge_point->authorize_id_token(ocpp::CiString<20>(std::string("DEADBEEF")));
} else if (command == "start_transaction") {
if (!transaction_running) {
uuid = boost::lexical_cast<std::string>(boost::uuids::random_generator()());
charge_point->on_session_started(1, uuid, ocpp::SessionStartedReason::EVConnected, std::nullopt);
const auto result = charge_point->authorize_id_token(ocpp::CiString<20>(std::string("DEADBEEF")));
if (result.id_tag_info.status == ocpp::v16::AuthorizationStatus::Accepted) {
charge_point->on_transaction_started(1, uuid, "DEADBEEF", 0, std::nullopt, ocpp::DateTime(),
std::nullopt);
charge_point->on_resume_charging(1);
transaction_running = true;
}
}
} else if (command == "stop_transaction") {
if (transaction_running) {
charge_point->on_transaction_stopped(1, uuid, ocpp::v16::Reason::Local, ocpp::DateTime(), 2500,
std::nullopt, std::nullopt);
charge_point->on_session_stopped(1, uuid);
transaction_running = false;
} else {
std::cout << "No transaction is currently running. Use command \"start_transaction\" first"
<< std::endl;
}
} else if (command == "end") {
running = false;
} else if (command == "help") {
std::cout << "You can run the following commands:\n"
<< "\t- start_transaction : Starts a transaction with token \"DEADBEEF\"\n"
<< "\t- stop_transaction : Stops a transaction if currently running\n"
<< "\t- auth : Authorizes the token \"DEADBEEF\"\n"
<< "\t- end : Stop execution of the program\n"
<< std::endl;
} else {
std::cout << "Received unknown command" << std::endl;
}
}
});
t1.join();
std::cout << "Goodbye" << std::endl;
return 0;
}