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
This commit is contained in:
@@ -0,0 +1,425 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <everest/conversions/ocpp/ocpp_conversions.hpp>
|
||||
|
||||
#include <everest/logging.hpp>
|
||||
|
||||
#include "generated/types/display_message.hpp"
|
||||
|
||||
namespace ocpp_conversions {
|
||||
types::display_message::MessagePriorityEnum
|
||||
to_everest_display_message_priority(const ocpp::v2::MessagePriorityEnum& priority) {
|
||||
switch (priority) {
|
||||
case ocpp::v2::MessagePriorityEnum::AlwaysFront:
|
||||
return types::display_message::MessagePriorityEnum::AlwaysFront;
|
||||
case ocpp::v2::MessagePriorityEnum::InFront:
|
||||
return types::display_message::MessagePriorityEnum::InFront;
|
||||
case ocpp::v2::MessagePriorityEnum::NormalCycle:
|
||||
return types::display_message::MessagePriorityEnum::NormalCycle;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert ocpp::v2::MessagePriorityEnum to types::display_message::MessagePriorityEnum");
|
||||
}
|
||||
|
||||
ocpp::v2::MessagePriorityEnum
|
||||
to_ocpp_201_message_priority(const types::display_message::MessagePriorityEnum& priority) {
|
||||
switch (priority) {
|
||||
case types::display_message::MessagePriorityEnum::AlwaysFront:
|
||||
return ocpp::v2::MessagePriorityEnum::AlwaysFront;
|
||||
case types::display_message::MessagePriorityEnum::InFront:
|
||||
return ocpp::v2::MessagePriorityEnum::InFront;
|
||||
case types::display_message::MessagePriorityEnum::NormalCycle:
|
||||
return ocpp::v2::MessagePriorityEnum::NormalCycle;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert types::display_message::MessagePriorityEnum to ocpp::v2::MessagePriorityEnum");
|
||||
}
|
||||
|
||||
types::display_message::MessageStateEnum to_everest_display_message_state(const ocpp::v2::MessageStateEnum& state) {
|
||||
switch (state) {
|
||||
case ocpp::v2::MessageStateEnum::Charging:
|
||||
return types::display_message::MessageStateEnum::Charging;
|
||||
case ocpp::v2::MessageStateEnum::Faulted:
|
||||
return types::display_message::MessageStateEnum::Faulted;
|
||||
case ocpp::v2::MessageStateEnum::Idle:
|
||||
return types::display_message::MessageStateEnum::Idle;
|
||||
case ocpp::v2::MessageStateEnum::Unavailable:
|
||||
return types::display_message::MessageStateEnum::Unavailable;
|
||||
case ocpp::v2::MessageStateEnum::Suspended:
|
||||
return types::display_message::MessageStateEnum::Suspending;
|
||||
case ocpp::v2::MessageStateEnum::Discharging:
|
||||
return types::display_message::MessageStateEnum::Discharging;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::v2::MessageStateEnum to types::display_message::MessageStateEnum");
|
||||
}
|
||||
|
||||
ocpp::v2::MessageStateEnum to_ocpp_201_display_message_state(const types::display_message::MessageStateEnum& state) {
|
||||
switch (state) {
|
||||
case types::display_message::MessageStateEnum::Charging:
|
||||
return ocpp::v2::MessageStateEnum::Charging;
|
||||
case types::display_message::MessageStateEnum::Faulted:
|
||||
return ocpp::v2::MessageStateEnum::Faulted;
|
||||
case types::display_message::MessageStateEnum::Idle:
|
||||
return ocpp::v2::MessageStateEnum::Idle;
|
||||
case types::display_message::MessageStateEnum::Unavailable:
|
||||
return ocpp::v2::MessageStateEnum::Unavailable;
|
||||
case types::display_message::MessageStateEnum::Suspending:
|
||||
return ocpp::v2::MessageStateEnum::Suspended;
|
||||
case types::display_message::MessageStateEnum::Discharging:
|
||||
return ocpp::v2::MessageStateEnum::Discharging;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::display_message::MessageStateEnum to ocpp::v2::MessageStateEnum");
|
||||
}
|
||||
|
||||
types::text_message::MessageFormat
|
||||
to_everest_display_message_format(const ocpp::v2::MessageFormatEnum& message_format) {
|
||||
switch (message_format) {
|
||||
case ocpp::v2::MessageFormatEnum::ASCII:
|
||||
return types::text_message::MessageFormat::ASCII;
|
||||
case ocpp::v2::MessageFormatEnum::HTML:
|
||||
return types::text_message::MessageFormat::HTML;
|
||||
case ocpp::v2::MessageFormatEnum::URI:
|
||||
return types::text_message::MessageFormat::URI;
|
||||
case ocpp::v2::MessageFormatEnum::UTF8:
|
||||
return types::text_message::MessageFormat::UTF8;
|
||||
case ocpp::v2::MessageFormatEnum::QRCODE:
|
||||
return types::text_message::MessageFormat::QRCODE;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::v2::MessageFormat to types::display_message::MessageFormatEnum");
|
||||
}
|
||||
|
||||
ocpp::v2::MessageFormatEnum to_ocpp_201_message_format_enum(const types::text_message::MessageFormat& format) {
|
||||
switch (format) {
|
||||
case types::text_message::MessageFormat::ASCII:
|
||||
return ocpp::v2::MessageFormatEnum::ASCII;
|
||||
case types::text_message::MessageFormat::HTML:
|
||||
return ocpp::v2::MessageFormatEnum::HTML;
|
||||
case types::text_message::MessageFormat::URI:
|
||||
return ocpp::v2::MessageFormatEnum::URI;
|
||||
case types::text_message::MessageFormat::UTF8:
|
||||
return ocpp::v2::MessageFormatEnum::UTF8;
|
||||
case types::text_message::MessageFormat::QRCODE:
|
||||
return ocpp::v2::MessageFormatEnum::QRCODE;
|
||||
}
|
||||
|
||||
throw std::out_of_range("Could not convert types::display_message::MessageFormat to ocpp::v2::MessageFormatEnum");
|
||||
}
|
||||
|
||||
ocpp::IdentifierType to_ocpp_identifiertype_enum(const types::display_message::IdentifierType identifier_type) {
|
||||
switch (identifier_type) {
|
||||
case types::display_message::IdentifierType::IdToken:
|
||||
return ocpp::IdentifierType::IdToken;
|
||||
case types::display_message::IdentifierType::SessionId:
|
||||
return ocpp::IdentifierType::SessionId;
|
||||
case types::display_message::IdentifierType::TransactionId:
|
||||
return ocpp::IdentifierType::TransactionId;
|
||||
}
|
||||
|
||||
throw std::out_of_range("types::display_message::Identifier_type to ocpp::IdentierType");
|
||||
}
|
||||
|
||||
types::display_message::IdentifierType to_everest_identifier_type_enum(const ocpp::IdentifierType identifier_type) {
|
||||
switch (identifier_type) {
|
||||
case ocpp::IdentifierType::SessionId:
|
||||
return types::display_message::IdentifierType::SessionId;
|
||||
case ocpp::IdentifierType::IdToken:
|
||||
return types::display_message::IdentifierType::IdToken;
|
||||
case ocpp::IdentifierType::TransactionId:
|
||||
return types::display_message::IdentifierType::TransactionId;
|
||||
}
|
||||
throw std::out_of_range("ocpp::IdentierType to types::display_message::Identifier_type");
|
||||
}
|
||||
|
||||
types::text_message::MessageContent
|
||||
to_everest_display_message_content(const ocpp::DisplayMessageContent& message_content) {
|
||||
types::text_message::MessageContent message;
|
||||
message.content = message_content.message;
|
||||
if (message_content.message_format.has_value()) {
|
||||
message.format = to_everest_display_message_format(message_content.message_format.value());
|
||||
}
|
||||
message.language = message_content.language;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
types::display_message::DisplayMessage to_everest_display_message(const ocpp::DisplayMessage& display_message) {
|
||||
types::display_message::DisplayMessage m;
|
||||
m.id = display_message.id;
|
||||
m.message.content = display_message.message.message;
|
||||
if (display_message.message.message_format.has_value()) {
|
||||
m.message.format = to_everest_display_message_format(display_message.message.message_format.value());
|
||||
}
|
||||
m.message.language = display_message.message.language;
|
||||
|
||||
if (display_message.priority.has_value()) {
|
||||
m.priority = ocpp_conversions::to_everest_display_message_priority(display_message.priority.value());
|
||||
}
|
||||
|
||||
m.qr_code = display_message.qr_code;
|
||||
m.identifier_id = display_message.identifier_id;
|
||||
if (display_message.identifier_type.has_value()) {
|
||||
m.identifier_type = to_everest_identifier_type_enum(display_message.identifier_type.value());
|
||||
}
|
||||
|
||||
if (display_message.state.has_value()) {
|
||||
m.state = to_everest_display_message_state(display_message.state.value());
|
||||
}
|
||||
|
||||
if (display_message.timestamp_from.has_value()) {
|
||||
m.timestamp_from = display_message.timestamp_from.value().to_rfc3339();
|
||||
}
|
||||
|
||||
if (display_message.timestamp_to.has_value()) {
|
||||
m.timestamp_to = display_message.timestamp_to.value().to_rfc3339();
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
ocpp::DisplayMessage to_ocpp_display_message(const types::display_message::DisplayMessage& display_message) {
|
||||
ocpp::DisplayMessage m;
|
||||
m.id = display_message.id;
|
||||
m.message.message = display_message.message.content;
|
||||
m.message.language = display_message.message.language;
|
||||
if (display_message.message.format.has_value()) {
|
||||
m.message.message_format = to_ocpp_201_message_format_enum(display_message.message.format.value());
|
||||
}
|
||||
|
||||
if (display_message.priority.has_value()) {
|
||||
m.priority = ocpp_conversions::to_ocpp_201_message_priority(display_message.priority.value());
|
||||
}
|
||||
|
||||
m.qr_code = display_message.qr_code;
|
||||
m.identifier_id = display_message.identifier_id;
|
||||
if (display_message.identifier_type.has_value()) {
|
||||
m.identifier_type = to_ocpp_identifiertype_enum(display_message.identifier_type.value());
|
||||
}
|
||||
|
||||
if (display_message.state.has_value()) {
|
||||
m.state = to_ocpp_201_display_message_state(display_message.state.value());
|
||||
}
|
||||
|
||||
try {
|
||||
if (display_message.timestamp_from.has_value()) {
|
||||
m.timestamp_from = ocpp::DateTime(display_message.timestamp_from.value());
|
||||
}
|
||||
if (display_message.timestamp_to.has_value()) {
|
||||
m.timestamp_to = ocpp::DateTime(display_message.timestamp_to.value());
|
||||
}
|
||||
} catch (const ocpp::TimePointParseException& e) {
|
||||
EVLOG_warning << "Could not parse timestamp when converting DisplayMessage: " << e.what();
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
types::session_cost::TariffMessage to_everest_tariff_message(const ocpp::TariffMessage& tariff_message) {
|
||||
types::session_cost::TariffMessage m;
|
||||
m.ocpp_transaction_id = tariff_message.ocpp_transaction_id;
|
||||
m.identifier_id = tariff_message.identifier_id;
|
||||
if (tariff_message.identifier_type.has_value()) {
|
||||
m.identifier_type = to_everest_identifier_type_enum(tariff_message.identifier_type.value());
|
||||
}
|
||||
|
||||
for (const auto& message : tariff_message.message) {
|
||||
types::text_message::MessageContent content = to_everest_display_message_content(message);
|
||||
m.messages.push_back(content);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
types::session_cost::DefaultPrice to_everest_default_price(const std::vector<ocpp::DisplayMessageContent>& messages) {
|
||||
types::session_cost::DefaultPrice default_price;
|
||||
for (const auto& message : messages) {
|
||||
default_price.messages.push_back(to_everest_display_message_content(message));
|
||||
}
|
||||
return default_price;
|
||||
}
|
||||
|
||||
types::session_cost::SessionStatus to_everest_running_cost_state(const ocpp::RunningCostState& state) {
|
||||
switch (state) {
|
||||
case ocpp::RunningCostState::Charging:
|
||||
return types::session_cost::SessionStatus::Running;
|
||||
case ocpp::RunningCostState::Idle:
|
||||
return types::session_cost::SessionStatus::Idle;
|
||||
case ocpp::RunningCostState::Finished:
|
||||
return types::session_cost::SessionStatus::Finished;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::RunningCostState to types::session_cost::SessionStatus");
|
||||
}
|
||||
|
||||
types::session_cost::SessionCostChunk create_session_cost_chunk(const double& price, const uint32_t& number_of_decimals,
|
||||
const std::optional<ocpp::DateTime>& timestamp,
|
||||
const std::optional<uint32_t>& meter_value) {
|
||||
types::session_cost::SessionCostChunk chunk;
|
||||
chunk.cost = types::money::MoneyAmount();
|
||||
chunk.cost->value = static_cast<int>(price * (pow(10, number_of_decimals)));
|
||||
if (timestamp.has_value()) {
|
||||
chunk.timestamp_to = timestamp.value().to_rfc3339();
|
||||
}
|
||||
chunk.metervalue_to = meter_value;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
types::money::Price create_price(const double& price, const uint32_t& number_of_decimals,
|
||||
std::optional<types::money::CurrencyCode> currency_code) {
|
||||
types::money::Price p;
|
||||
types::money::Currency currency;
|
||||
currency.code = currency_code;
|
||||
currency.decimals = number_of_decimals;
|
||||
p.currency = currency;
|
||||
p.value.value = static_cast<int>(price * (pow(10, number_of_decimals)));
|
||||
return p;
|
||||
}
|
||||
|
||||
types::session_cost::ChargingPriceComponent
|
||||
create_charging_price_component(const double& price, const uint32_t& number_of_decimals,
|
||||
const types::session_cost::CostCategory category,
|
||||
std::optional<types::money::CurrencyCode> currency_code) {
|
||||
types::session_cost::ChargingPriceComponent c;
|
||||
c.category = category;
|
||||
c.price = create_price(price, number_of_decimals, currency_code);
|
||||
return c;
|
||||
}
|
||||
|
||||
types::session_cost::SessionCost create_session_cost(const ocpp::RunningCost& running_cost,
|
||||
const uint32_t number_of_decimals,
|
||||
std::optional<types::money::CurrencyCode> currency_code) {
|
||||
types::session_cost::SessionCost cost;
|
||||
cost.session_id = running_cost.transaction_id;
|
||||
cost.currency.code = currency_code;
|
||||
cost.currency.decimals = static_cast<int32_t>(number_of_decimals);
|
||||
cost.status = to_everest_running_cost_state(running_cost.state);
|
||||
cost.qr_code = running_cost.qr_code_text;
|
||||
if (running_cost.cost_messages.has_value()) {
|
||||
cost.message = std::vector<types::text_message::MessageContent>();
|
||||
for (const ocpp::DisplayMessageContent& message : running_cost.cost_messages.value()) {
|
||||
const auto m = to_everest_display_message_content(message);
|
||||
cost.message->push_back(m);
|
||||
}
|
||||
}
|
||||
|
||||
types::session_cost::SessionCostChunk chunk = create_session_cost_chunk(
|
||||
running_cost.cost, number_of_decimals, running_cost.timestamp, running_cost.meter_value);
|
||||
cost.cost_chunks = std::vector<types::session_cost::SessionCostChunk>();
|
||||
cost.cost_chunks->push_back(chunk);
|
||||
|
||||
if (running_cost.charging_price.has_value()) {
|
||||
cost.charging_price = std::vector<types::session_cost::ChargingPriceComponent>();
|
||||
const ocpp::RunningCostChargingPrice& price = running_cost.charging_price.value();
|
||||
if (price.hour_price.has_value()) {
|
||||
types::session_cost::ChargingPriceComponent hour_price = create_charging_price_component(
|
||||
price.hour_price.value(), number_of_decimals, types::session_cost::CostCategory::Time, currency_code);
|
||||
cost.charging_price->push_back(hour_price);
|
||||
}
|
||||
if (price.kWh_price.has_value()) {
|
||||
types::session_cost::ChargingPriceComponent energy_price = create_charging_price_component(
|
||||
price.kWh_price.value(), number_of_decimals, types::session_cost::CostCategory::Energy, currency_code);
|
||||
cost.charging_price->push_back(energy_price);
|
||||
}
|
||||
if (price.flat_fee.has_value()) {
|
||||
types::session_cost::ChargingPriceComponent flat_fee_price = create_charging_price_component(
|
||||
price.flat_fee.value(), number_of_decimals, types::session_cost::CostCategory::FlatFee, currency_code);
|
||||
cost.charging_price->push_back(flat_fee_price);
|
||||
}
|
||||
}
|
||||
|
||||
if (running_cost.idle_price.has_value()) {
|
||||
types::session_cost::IdlePrice idle_price;
|
||||
const ocpp::RunningCostIdlePrice& ocpp_idle_price = running_cost.idle_price.value();
|
||||
if (ocpp_idle_price.idle_hour_price.has_value()) {
|
||||
idle_price.hour_price =
|
||||
create_price(ocpp_idle_price.idle_hour_price.value(), number_of_decimals, currency_code);
|
||||
}
|
||||
|
||||
if (ocpp_idle_price.idle_grace_minutes.has_value()) {
|
||||
idle_price.grace_minutes = ocpp_idle_price.idle_grace_minutes.value();
|
||||
}
|
||||
|
||||
cost.idle_price = idle_price;
|
||||
}
|
||||
|
||||
if (running_cost.next_period_at_time.has_value() || running_cost.next_period_charging_price.has_value() ||
|
||||
running_cost.next_period_idle_price.has_value()) {
|
||||
types::session_cost::NextPeriodPrice next_period;
|
||||
if (running_cost.next_period_at_time.has_value()) {
|
||||
next_period.timestamp_from = running_cost.next_period_at_time.value().to_rfc3339();
|
||||
}
|
||||
if (running_cost.next_period_idle_price.has_value()) {
|
||||
types::session_cost::IdlePrice next_period_idle_price;
|
||||
const ocpp::RunningCostIdlePrice& ocpp_next_period_idle_price = running_cost.next_period_idle_price.value();
|
||||
if (ocpp_next_period_idle_price.idle_hour_price.has_value()) {
|
||||
next_period_idle_price.hour_price = create_price(ocpp_next_period_idle_price.idle_hour_price.value(),
|
||||
number_of_decimals, currency_code);
|
||||
}
|
||||
|
||||
if (ocpp_next_period_idle_price.idle_grace_minutes.has_value()) {
|
||||
next_period_idle_price.grace_minutes = ocpp_next_period_idle_price.idle_grace_minutes.value();
|
||||
}
|
||||
|
||||
next_period.idle_price = next_period_idle_price;
|
||||
}
|
||||
if (running_cost.next_period_charging_price.has_value()) {
|
||||
const ocpp::RunningCostChargingPrice& next_period_charging_price =
|
||||
running_cost.next_period_charging_price.value();
|
||||
|
||||
next_period.charging_price = std::vector<types::session_cost::ChargingPriceComponent>();
|
||||
|
||||
if (next_period_charging_price.hour_price.has_value()) {
|
||||
types::session_cost::ChargingPriceComponent hour_price =
|
||||
create_charging_price_component(next_period_charging_price.hour_price.value(), number_of_decimals,
|
||||
types::session_cost::CostCategory::Time, currency_code);
|
||||
next_period.charging_price.push_back(hour_price);
|
||||
}
|
||||
|
||||
if (next_period_charging_price.kWh_price.has_value()) {
|
||||
types::session_cost::ChargingPriceComponent energy_price =
|
||||
create_charging_price_component(next_period_charging_price.kWh_price.value(), number_of_decimals,
|
||||
types::session_cost::CostCategory::Energy, currency_code);
|
||||
next_period.charging_price.push_back(energy_price);
|
||||
}
|
||||
|
||||
if (next_period_charging_price.flat_fee.has_value()) {
|
||||
types::session_cost::ChargingPriceComponent flat_fee_price =
|
||||
create_charging_price_component(next_period_charging_price.flat_fee.value(), number_of_decimals,
|
||||
types::session_cost::CostCategory::FlatFee, currency_code);
|
||||
next_period.charging_price.push_back(flat_fee_price);
|
||||
}
|
||||
}
|
||||
|
||||
cost.next_period = next_period;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
ocpp::DateTime to_ocpp_datetime_or_now(const std::string& datetime_string) {
|
||||
std::optional<ocpp::DateTime> timestamp;
|
||||
try {
|
||||
return ocpp::DateTime(datetime_string);
|
||||
} catch (const ocpp::TimePointParseException& e) {
|
||||
EVLOG_warning << "Could not parse datetime string: " << e.what() << ". Using current DateTime instead";
|
||||
}
|
||||
return ocpp::DateTime();
|
||||
}
|
||||
|
||||
ocpp::ReservationCheckStatus
|
||||
to_ocpp_reservation_check_status(const types::reservation::ReservationCheckStatus& status) {
|
||||
switch (status) {
|
||||
case types::reservation::ReservationCheckStatus::NotReserved:
|
||||
return ocpp::ReservationCheckStatus::NotReserved;
|
||||
case types::reservation::ReservationCheckStatus::ReservedForToken:
|
||||
return ocpp::ReservationCheckStatus::ReservedForToken;
|
||||
case types::reservation::ReservationCheckStatus::ReservedForOtherToken:
|
||||
return ocpp::ReservationCheckStatus::ReservedForOtherToken;
|
||||
case types::reservation::ReservationCheckStatus::ReservedForOtherTokenAndHasParentToken:
|
||||
return ocpp::ReservationCheckStatus::ReservedForOtherTokenAndHasParentToken;
|
||||
}
|
||||
|
||||
EVLOG_warning << "Could not convert reservation check status. Returning default 'NotReserved.";
|
||||
return ocpp::ReservationCheckStatus::NotReserved;
|
||||
}
|
||||
|
||||
} // namespace ocpp_conversions
|
||||
Reference in New Issue
Block a user