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,155 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#include "BUDCExternalDerate.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/component_base.hpp"
|
||||
#include "ftxui/component/component_options.hpp"
|
||||
#include "ftxui/component/event.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/elements.hpp"
|
||||
#include "ftxui/screen/color.hpp"
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
namespace module {
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
void BUDCExternalDerate::init() {
|
||||
}
|
||||
|
||||
void BUDCExternalDerate::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
auto msg_component = Container::Vertical({Renderer([] { return text(""); })});
|
||||
|
||||
std::map<std::string, std::map<std::string, Component>> messages;
|
||||
|
||||
r_derate->subscribe_all_errors(
|
||||
[&](Everest::error::Error const& error) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
auto error_elem = Renderer([=] { return text(" - " + error.type); });
|
||||
auto sub_elem = Renderer([=] { return text(" " + error.sub_type); });
|
||||
auto msg_elem = Renderer([=] { return text(" " + error.message); });
|
||||
|
||||
auto component = Container::Vertical({
|
||||
error_elem,
|
||||
sub_elem,
|
||||
msg_elem,
|
||||
});
|
||||
|
||||
messages[error.type][error.sub_type] = component;
|
||||
msg_component->Add(component);
|
||||
screen.Post(Event::Custom);
|
||||
},
|
||||
[&](Everest::error::Error const& error) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
if (messages.count(error.type)) {
|
||||
auto& sub = messages.at(error.type);
|
||||
if (sub.count(error.sub_type)) {
|
||||
auto& elem = sub.at(error.sub_type);
|
||||
elem->Detach();
|
||||
sub.erase(error.sub_type);
|
||||
}
|
||||
if (not sub.size()) {
|
||||
messages.erase(error.type);
|
||||
}
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
auto msg_component_holder = Container::Horizontal({msg_component});
|
||||
|
||||
auto msg_component_renderer = Renderer(msg_component_holder, [&] {
|
||||
auto win = window(text("Active Errors"), msg_component_holder->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto var_component =
|
||||
Container::Vertical({Renderer([&] { return text("plug_temperature_C: " + std::to_string(plug_temp_C)); })});
|
||||
auto var_component_holder = Container::Horizontal({var_component});
|
||||
auto var_component_renderer = Renderer(var_component_holder, [&] {
|
||||
auto win = window(text("Vars"), var_component_holder->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
r_derate->subscribe_plug_temperature_C([&](double temp) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
plug_temp_C = temp;
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
InputOption o;
|
||||
o.multiline = false;
|
||||
o.cursor_position = 0;
|
||||
|
||||
auto max_export_current_A_input = Input(&max_export_current_A, "100.0", o);
|
||||
auto max_import_current_A_input = Input(&max_import_current_A, "200.0", o);
|
||||
auto max_export_power_W_input = Input(&max_export_power_W, "300.0", o);
|
||||
auto max_import_power_W_input = Input(&max_import_power_W, "400.0", o);
|
||||
|
||||
Component ovm_start = Button(
|
||||
"Set",
|
||||
[&] {
|
||||
types::dc_external_derate::ExternalDerating val;
|
||||
val.max_export_current_A = std::stof(max_export_current_A);
|
||||
val.max_import_current_A = std::stof(max_import_current_A);
|
||||
val.max_export_power_W = std::stof(max_export_power_W);
|
||||
val.max_import_power_W = std::stof(max_import_power_W);
|
||||
r_derate->call_set_external_derating(val);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White)) |
|
||||
flex_grow;
|
||||
|
||||
auto action_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
max_export_current_A_input,
|
||||
max_import_current_A_input,
|
||||
max_export_power_W_input,
|
||||
max_import_power_W_input,
|
||||
ovm_start,
|
||||
}),
|
||||
});
|
||||
|
||||
auto action_component_renderer = Renderer(action_component, [&] {
|
||||
return vbox({hbox(ovm_start->Render()),
|
||||
|
||||
vbox(hbox(text(" Max Export Current (A): "), max_export_current_A_input->Render()),
|
||||
hbox(text(" Max Import Current (A): "), max_import_current_A_input->Render()),
|
||||
hbox(text(" Max Export Power (W): "), max_export_power_W_input->Render()),
|
||||
hbox(text(" Max Import Power (W): "), max_import_power_W_input->Render()))});
|
||||
});
|
||||
|
||||
auto action_renderer = Renderer(action_component, [&] {
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("DC External Derate Commands"), action_component_renderer->Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Horizontal({action_renderer, var_component_renderer, msg_component_renderer});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
return vbox({
|
||||
text("DC External Derate Bringup") | bold | hcenter,
|
||||
hbox({main_container->Render()}),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUDCEXTERNAL_DERATE_HPP
|
||||
#define BUDCEXTERNAL_DERATE_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/dc_external_derate/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUDCExternalDerate : public Everest::ModuleBase {
|
||||
public:
|
||||
BUDCExternalDerate() = delete;
|
||||
BUDCExternalDerate(const ModuleInfo& info, std::unique_ptr<dc_external_derateIntf> r_derate, Conf& config) :
|
||||
ModuleBase(info), r_derate(std::move(r_derate)), config(config){};
|
||||
|
||||
const std::unique_ptr<dc_external_derateIntf> r_derate;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::string max_export_current_A{"20.0"};
|
||||
std::string max_import_current_A{"0.0"};
|
||||
std::string max_export_power_W{"20000.0"};
|
||||
std::string max_import_power_W{"0.0"};
|
||||
|
||||
double plug_temp_C{0.};
|
||||
std::mutex data_mutex;
|
||||
//
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUDCEXTERNAL_DERATE_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for the dc_external_derate interface
|
||||
requires:
|
||||
derate:
|
||||
interface: dc_external_derate
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Jan Christoph Habig
|
||||
@@ -0,0 +1,546 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "BUDisplayMessage.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
#include <generated/types/text_message.hpp>
|
||||
|
||||
using namespace ftxui;
|
||||
namespace {
|
||||
|
||||
constexpr std::array<types::display_message::MessagePriorityEnum, 3> MessagePriorityEnumValues = {
|
||||
types::display_message::MessagePriorityEnum::AlwaysFront, types::display_message::MessagePriorityEnum::InFront,
|
||||
types::display_message::MessagePriorityEnum::NormalCycle};
|
||||
|
||||
constexpr std::array<types::display_message::MessageStateEnum, 4> MessageStateEnumValues = {
|
||||
types::display_message::MessageStateEnum::Charging, types::display_message::MessageStateEnum::Faulted,
|
||||
types::display_message::MessageStateEnum::Idle, types::display_message::MessageStateEnum::Unavailable};
|
||||
|
||||
constexpr std::array<types::text_message::MessageFormat, 4> MessageFormatValues = {
|
||||
types::text_message::MessageFormat::ASCII, types::text_message::MessageFormat::HTML,
|
||||
types::text_message::MessageFormat::URI, types::text_message::MessageFormat::UTF8};
|
||||
|
||||
constexpr std::array<types::display_message::IdentifierType, 3> Identifier_typeValues = {
|
||||
types::display_message::IdentifierType::IdToken, types::display_message::IdentifierType::SessionId,
|
||||
types::display_message::IdentifierType::TransactionId};
|
||||
|
||||
// Enum-String to be used for Dropdown GUI elements
|
||||
std::vector<std::string> MessagePriorityEnumStrings;
|
||||
std::vector<std::string> MessageStateEnumStrings;
|
||||
std::vector<std::string> MessageFormatStrings;
|
||||
std::vector<std::string> IdentifierTypeStrings;
|
||||
|
||||
struct MessageContentParameters {
|
||||
std::string content;
|
||||
std::string language;
|
||||
|
||||
std::string msg_id;
|
||||
std::string timestamp_from;
|
||||
std::string timestamp_to;
|
||||
std::string identifier_id;
|
||||
std::string qr_code;
|
||||
|
||||
int priority;
|
||||
int state;
|
||||
int format;
|
||||
int id_type;
|
||||
};
|
||||
|
||||
types::display_message::DisplayMessage inputs2dspmsg_types(const MessageContentParameters& params) {
|
||||
int set_msg_id = 0;
|
||||
if (not params.msg_id.empty()) {
|
||||
set_msg_id = std::stoi(params.msg_id);
|
||||
}
|
||||
|
||||
types::text_message::MessageContent msg_content{
|
||||
params.content,
|
||||
params.format == MessageFormatValues.size()
|
||||
? std::nullopt
|
||||
: std::optional<types::text_message::MessageFormat>(MessageFormatValues[params.format]),
|
||||
params.language.empty() ? std::nullopt : std::optional<std::string>{params.language}};
|
||||
types::display_message::DisplayMessage msg{
|
||||
msg_content,
|
||||
params.msg_id.empty() ? std::nullopt : std::optional<int>(set_msg_id),
|
||||
params.priority == MessagePriorityEnumValues.size()
|
||||
? std::nullopt
|
||||
: std::optional<types::display_message::MessagePriorityEnum>(MessagePriorityEnumValues[params.priority]),
|
||||
params.state == MessageStateEnumValues.size()
|
||||
? std::nullopt
|
||||
: std::optional<types::display_message::MessageStateEnum>(MessageStateEnumValues[params.state]),
|
||||
params.timestamp_from.empty() ? std::nullopt : std::optional<std::string>(params.timestamp_from),
|
||||
params.timestamp_to.empty() ? std::nullopt : std::optional<std::string>(params.timestamp_to),
|
||||
params.identifier_id.empty() ? std::nullopt : std::optional<std::string>(params.identifier_id),
|
||||
params.id_type == Identifier_typeValues.size()
|
||||
? std::nullopt
|
||||
: std::optional<types::display_message::IdentifierType>(Identifier_typeValues[params.id_type]),
|
||||
params.qr_code.empty() ? std::nullopt : std::optional<std::string>(params.qr_code)};
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
auto input_parameters_to_display_messages(
|
||||
const std::vector<std::unique_ptr<MessageContentParameters>>& set_msg_parameter_vector) {
|
||||
std::vector<types::display_message::DisplayMessage> display_messages;
|
||||
for (auto& msg_params : set_msg_parameter_vector) {
|
||||
if (msg_params->content.empty()) {
|
||||
continue;
|
||||
}
|
||||
display_messages.push_back(inputs2dspmsg_types(*msg_params));
|
||||
}
|
||||
return display_messages;
|
||||
}
|
||||
|
||||
auto comma_separated_ids_to_vector(const std::string& get_msg_id_str) {
|
||||
std::optional<std::vector<int32_t>> get_msg_ids = std::vector<int32_t>{};
|
||||
|
||||
int get_msg_id;
|
||||
std::stringstream msg_ids_ss(get_msg_id_str);
|
||||
|
||||
while (msg_ids_ss.good()) {
|
||||
std::string singleNumber_str;
|
||||
getline(msg_ids_ss, singleNumber_str, ',');
|
||||
try {
|
||||
int singleNumber = std::stoi(singleNumber_str);
|
||||
get_msg_ids->push_back(singleNumber);
|
||||
} catch (...) {
|
||||
// just ignore it
|
||||
}
|
||||
}
|
||||
if (get_msg_ids->size() == 0) {
|
||||
get_msg_ids = std::nullopt;
|
||||
}
|
||||
return get_msg_ids;
|
||||
}
|
||||
|
||||
auto msg_priority_int_to_optional_enum(int get_msg_priority_selected) {
|
||||
return (get_msg_priority_selected < MessagePriorityEnumValues.size())
|
||||
? std::optional<
|
||||
types::display_message::MessagePriorityEnum>{MessagePriorityEnumValues[get_msg_priority_selected]}
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
auto msg_state_int_to_optional_enum(int get_msg_state_selected) {
|
||||
return (get_msg_state_selected < MessageStateEnumValues.size())
|
||||
? std::optional<types::display_message::MessageStateEnum>{MessageStateEnumValues[get_msg_state_selected]}
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
void log_cmd_response(std::vector<std::string>* log, const std::string& log_prefix, const std::string& status,
|
||||
const std::optional<std::string>& status_info) {
|
||||
log->insert(log->begin(), log_prefix + ": " + status + ": '" + status_info.value_or("") + "'");
|
||||
}
|
||||
|
||||
void log_message(std::vector<std::string>* log, types::display_message::DisplayMessage msg) {
|
||||
std::string message_str = msg.message.content;
|
||||
std::string format_str = (msg.message.format ? message_format_to_string(msg.message.format.value()) : "<no fmt>");
|
||||
std::string lang_str = msg.message.language.value_or("<no lang>");
|
||||
std::string id_str = (msg.id ? std::to_string(msg.id.value()) : "<no id>");
|
||||
std::string prio_str = (msg.priority ? message_priority_enum_to_string(msg.priority.value()) : "<no prio>");
|
||||
std::string state_str = (msg.state ? message_state_enum_to_string(msg.state.value()) : "<no stat>");
|
||||
std::string tstmp_fr_str = msg.timestamp_from.value_or("<no t_from>");
|
||||
std::string tstmp_to_str = msg.timestamp_to.value_or("<no t_to>");
|
||||
std::string id_id_str = msg.identifier_id.value_or("<no id_id>");
|
||||
std::string id_type_str =
|
||||
(msg.identifier_type ? identifier_type_to_string(msg.identifier_type.value()) : "<no id_typ>");
|
||||
std::string qr_str = msg.qr_code.value_or("<no qr>");
|
||||
|
||||
std::vector<std::string> strings_to_join = {message_str, format_str, lang_str, id_str, prio_str, state_str,
|
||||
tstmp_fr_str, tstmp_to_str, id_id_str, id_type_str, qr_str};
|
||||
std::string joined_string = std::accumulate(
|
||||
std::begin(strings_to_join), std::end(strings_to_join), std::string{},
|
||||
[](std::string& first, std::string& second) { return first.empty() ? second : first + ", " + second; });
|
||||
|
||||
log->insert(log->begin(), joined_string);
|
||||
}
|
||||
|
||||
class MessageInputMask : public ComponentBase {
|
||||
public:
|
||||
MessageInputMask(const std::string& heading, MessageContentParameters* parameters) :
|
||||
m_heading(heading), m_parameters(parameters) {
|
||||
|
||||
m_msg_prio_dd = Dropdown(&MessagePriorityEnumStrings, &(m_parameters->priority));
|
||||
m_msg_stat_dd = Dropdown(&MessageStateEnumStrings, &(m_parameters->state));
|
||||
m_msg_form_dd = Dropdown(&MessageFormatStrings, &(m_parameters->format));
|
||||
m_id_type_dd = Dropdown(&IdentifierTypeStrings, &(m_parameters->id_type));
|
||||
|
||||
InputOption id_input_o;
|
||||
id_input_o.multiline = false;
|
||||
id_input_o.cursor_position = 0;
|
||||
id_input_o.on_change = [&]() {
|
||||
if (m_parameters->identifier_id.size() > 36) {
|
||||
m_parameters->identifier_id.resize(36);
|
||||
}
|
||||
};
|
||||
|
||||
InputOption msg_id_input_o;
|
||||
msg_id_input_o.multiline = false;
|
||||
msg_id_input_o.cursor_position = 0;
|
||||
msg_id_input_o.on_change = [&]() {
|
||||
m_parameters->msg_id.erase(std::remove_if(m_parameters->msg_id.begin(), m_parameters->msg_id.end(),
|
||||
[](char c) { return !std::isdigit(c); }),
|
||||
m_parameters->msg_id.end());
|
||||
};
|
||||
|
||||
InputOption input_o;
|
||||
input_o.multiline = false;
|
||||
|
||||
m_msg_input = Input(&(m_parameters->content), "<required>", input_o);
|
||||
m_msg_id_input = Input(&(m_parameters->msg_id), "<none>", msg_id_input_o);
|
||||
m_qr_input = Input(&(m_parameters->qr_code), "<none>", input_o);
|
||||
m_lang_input = Input(&(m_parameters->language), "<none>", input_o);
|
||||
m_t_from_input = Input(&(m_parameters->timestamp_from), "<none>", input_o);
|
||||
m_t_to_input = Input(&(m_parameters->timestamp_to), "<none>", input_o);
|
||||
m_id_input = Input(&(m_parameters->identifier_id), "<none>", id_input_o);
|
||||
|
||||
m_msg_details_component = Container::Vertical({
|
||||
m_msg_prio_dd,
|
||||
m_msg_stat_dd,
|
||||
m_id_type_dd,
|
||||
m_msg_form_dd,
|
||||
m_msg_id_input,
|
||||
m_lang_input,
|
||||
m_id_input,
|
||||
m_t_from_input,
|
||||
m_t_to_input,
|
||||
m_qr_input,
|
||||
});
|
||||
|
||||
auto set_parameters_renderer = Renderer(m_msg_details_component, [&] {
|
||||
return vbox({
|
||||
hbox(hbox(text(" [Priority] : ") | vcenter, m_msg_prio_dd->Render()), filler(),
|
||||
hbox(text(" [State] : ") | vcenter, m_msg_stat_dd->Render()), filler()),
|
||||
hbox(hbox(text(" [Identifier Type] : ") | vcenter, m_id_type_dd->Render()), filler(),
|
||||
hbox(text(" [Format] : ") | vcenter, m_msg_form_dd->Render()), filler()),
|
||||
hbox(text(" [Message Id] : "), m_msg_id_input->Render()),
|
||||
hbox(text(" [Language] : "), m_lang_input->Render()),
|
||||
hbox(text(" [Identifier] : "), m_id_input->Render()),
|
||||
hbox(text(" [Date-Time From]: "), m_t_from_input->Render()),
|
||||
hbox(text(" [Date-Time To] : "), m_t_to_input->Render()),
|
||||
hbox(text(" [QR-Code] : "), m_qr_input->Render()),
|
||||
});
|
||||
});
|
||||
|
||||
m_details_collapsible = Collapsible("Message Details", set_parameters_renderer);
|
||||
|
||||
auto set_msg_component = Container::Vertical({
|
||||
m_msg_input,
|
||||
m_details_collapsible,
|
||||
});
|
||||
|
||||
// Add it to the container so it can receive focus.
|
||||
Add(set_msg_component);
|
||||
}
|
||||
|
||||
// Override the Render method to display label and input together.
|
||||
Element OnRender() override {
|
||||
return vbox({
|
||||
text(m_heading) | inverted,
|
||||
hbox(text(" Message : ") | bold, m_msg_input->Render()),
|
||||
m_details_collapsible->Render(),
|
||||
text(""),
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_heading;
|
||||
MessageContentParameters* m_parameters;
|
||||
|
||||
Component m_msg_prio_dd;
|
||||
Component m_msg_form_dd;
|
||||
Component m_id_type_dd;
|
||||
Component m_msg_stat_dd;
|
||||
|
||||
Component m_msg_input;
|
||||
Component m_msg_id_input;
|
||||
Component m_qr_input;
|
||||
Component m_lang_input;
|
||||
Component m_t_from_input;
|
||||
Component m_t_to_input;
|
||||
Component m_id_input;
|
||||
|
||||
Component m_msg_details_component;
|
||||
|
||||
Component m_details_collapsible;
|
||||
};
|
||||
|
||||
Component MessageInputMaskComponent(const std::string& heading, MessageContentParameters* parameters) {
|
||||
return Make<MessageInputMask>(heading, parameters);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace module {
|
||||
|
||||
void BUDisplayMessage::init() {
|
||||
}
|
||||
|
||||
void BUDisplayMessage::ready() {
|
||||
// Prepare Enum-String to be used for Dropdown GUI elements
|
||||
for (auto msgPriority : MessagePriorityEnumValues) {
|
||||
MessagePriorityEnumStrings.push_back(message_priority_enum_to_string(msgPriority));
|
||||
}
|
||||
MessagePriorityEnumStrings.push_back("<none>");
|
||||
|
||||
for (auto msgState : MessageStateEnumValues) {
|
||||
MessageStateEnumStrings.push_back(message_state_enum_to_string(msgState));
|
||||
}
|
||||
MessageStateEnumStrings.push_back("<none>");
|
||||
|
||||
for (auto msgFormat : MessageFormatValues) {
|
||||
MessageFormatStrings.push_back(message_format_to_string(msgFormat));
|
||||
}
|
||||
MessageFormatStrings.push_back("<none>");
|
||||
|
||||
for (auto idType : Identifier_typeValues) {
|
||||
IdentifierTypeStrings.push_back(identifier_type_to_string(idType));
|
||||
}
|
||||
IdentifierTypeStrings.push_back("<none>");
|
||||
|
||||
/***************************************************************************************+
|
||||
* Start of FTXUI-GUI
|
||||
****************************************************************************************/
|
||||
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
int log_pane_index = 0;
|
||||
std::vector<std::string> log;
|
||||
auto log_pane_raw_component = Menu(&log, &log_pane_index);
|
||||
auto log_pane_component = log_pane_raw_component | vscroll_indicator;
|
||||
|
||||
auto log_pane_renderer =
|
||||
Renderer(log_pane_component, [&] { return window(text(" Command Log "), log_pane_component->Render()); });
|
||||
|
||||
/***************************************************************************************+
|
||||
* Set Display Messages
|
||||
****************************************************************************************/
|
||||
|
||||
/* ********************** INPUTS ******************************************** */
|
||||
std::vector<std::unique_ptr<MessageContentParameters>> set_msg_parameter_vector{};
|
||||
|
||||
int message_input_mask_count;
|
||||
|
||||
std::vector<Component> set_msg_input_masks{};
|
||||
|
||||
auto msg_inputs_component = Container::Vertical({});
|
||||
|
||||
auto add_msg_input_widget = [&] {
|
||||
set_msg_parameter_vector.push_back(std::make_unique<MessageContentParameters>());
|
||||
|
||||
// Initialize dropdown choices to be <none> for all dropdowns
|
||||
set_msg_parameter_vector.back()->priority = MessagePriorityEnumStrings.size() - 1;
|
||||
set_msg_parameter_vector.back()->state = MessageStateEnumStrings.size() - 1;
|
||||
set_msg_parameter_vector.back()->format = MessageFormatStrings.size() - 1;
|
||||
set_msg_parameter_vector.back()->id_type = IdentifierTypeStrings.size() - 1;
|
||||
|
||||
message_input_mask_count += 1;
|
||||
set_msg_input_masks.push_back(MessageInputMaskComponent("Message " + std::to_string(message_input_mask_count),
|
||||
set_msg_parameter_vector.back().get()));
|
||||
msg_inputs_component->Add(set_msg_input_masks.back());
|
||||
|
||||
// Tell FTXUI to redraw
|
||||
screen.PostEvent(Event::Custom);
|
||||
};
|
||||
|
||||
auto reset_msg_input_widgets = [&] {
|
||||
msg_inputs_component->DetachAllChildren();
|
||||
set_msg_input_masks.clear();
|
||||
set_msg_parameter_vector.clear();
|
||||
message_input_mask_count = 0;
|
||||
add_msg_input_widget();
|
||||
};
|
||||
|
||||
add_msg_input_widget();
|
||||
|
||||
/* ********************** BUTTONS ******************************************* */
|
||||
auto add_msg_button = Button(
|
||||
"Add Message!", [&] { add_msg_input_widget(); }, ButtonOption::Border());
|
||||
|
||||
auto set_button = Button(
|
||||
"Set!",
|
||||
[&] {
|
||||
auto display_messages = input_parameters_to_display_messages(set_msg_parameter_vector);
|
||||
|
||||
if (display_messages.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [status, status_info] = r_dm->call_set_display_message(display_messages);
|
||||
|
||||
std::string log_prefix{"Set " + std::to_string(display_messages.size()) + " message(s)"};
|
||||
log_cmd_response(&log, log_prefix, display_message_status_enum_to_string(status), status_info);
|
||||
|
||||
reset_msg_input_widgets();
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
/* ********************** COMPOSITION ******************************************** */
|
||||
|
||||
auto set_parameters_renderer = Renderer(msg_inputs_component, [&] {
|
||||
Elements elements;
|
||||
|
||||
for (auto& input_mask : set_msg_input_masks) {
|
||||
elements.push_back(input_mask->Render());
|
||||
}
|
||||
|
||||
return vbox(std::move(elements));
|
||||
});
|
||||
auto set_component = Container::Vertical({set_parameters_renderer, add_msg_button, set_button});
|
||||
|
||||
/***************************************************************************************+
|
||||
* Get Display Messages
|
||||
****************************************************************************************/
|
||||
|
||||
/* ********************** INPUTS ******************************************** */
|
||||
std::string get_msg_id_str;
|
||||
|
||||
InputOption get_msg_id_input_o;
|
||||
get_msg_id_input_o.multiline = false;
|
||||
get_msg_id_input_o.cursor_position = 0;
|
||||
get_msg_id_input_o.on_change = [&]() {
|
||||
get_msg_id_str.erase(std::remove_if(get_msg_id_str.begin(), get_msg_id_str.end(),
|
||||
[](char c) { return !std::isdigit(c) and c != ','; }),
|
||||
get_msg_id_str.end());
|
||||
};
|
||||
auto get_msg_id_input = Input(&get_msg_id_str, "<comma-separated list of IDs or none>", get_msg_id_input_o);
|
||||
|
||||
/* ********************** DROPDOWNS ******************************************** */
|
||||
int get_msg_priority_selected = MessagePriorityEnumStrings.size() - 1;
|
||||
int get_msg_state_selected = MessageStateEnumStrings.size() - 1;
|
||||
|
||||
auto get_msg_priority_dropdown = Dropdown(&MessagePriorityEnumStrings, &get_msg_priority_selected);
|
||||
auto get_msg_state_dropdown = Dropdown(&MessageStateEnumStrings, &get_msg_state_selected);
|
||||
|
||||
/* ********************** BUTTON ******************************************** */
|
||||
auto get_button = Button(
|
||||
"Get!",
|
||||
[&] {
|
||||
auto get_msg_ids = comma_separated_ids_to_vector(get_msg_id_str);
|
||||
auto msgPriorityChoice = msg_priority_int_to_optional_enum(get_msg_priority_selected);
|
||||
auto msgStateChoice = msg_state_int_to_optional_enum(get_msg_state_selected);
|
||||
|
||||
auto [status_info, messages] =
|
||||
r_dm->call_get_display_messages({get_msg_ids, msgPriorityChoice, msgStateChoice});
|
||||
|
||||
std::string log_prefix{"Got " + (messages ? std::to_string(messages->size()) : "no") + " message(s)"};
|
||||
log_cmd_response(&log, log_prefix, "", status_info);
|
||||
for (auto msg : messages.value_or(std::vector<types::display_message::DisplayMessage>())) {
|
||||
log_message(&log, msg);
|
||||
}
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
/* ********************** COMPOSITION ******************************************** */
|
||||
|
||||
auto get_dropdowns_component = Container::Horizontal({get_msg_priority_dropdown, get_msg_state_dropdown});
|
||||
|
||||
auto get_parameters_component = Container::Vertical({
|
||||
get_dropdowns_component,
|
||||
get_msg_id_input,
|
||||
});
|
||||
|
||||
auto get_parameters_renderer = Renderer(get_parameters_component, [&] {
|
||||
return vbox({
|
||||
text(" Command Parameters ") | inverted,
|
||||
hbox(hbox(text(" [Priority] : ") | vcenter, get_msg_priority_dropdown->Render()), filler(),
|
||||
hbox(text(" [State] : ") | vcenter, get_msg_state_dropdown->Render()), filler()),
|
||||
hbox(text(" [Message Id] : "), get_msg_id_input->Render()),
|
||||
text(" "),
|
||||
});
|
||||
});
|
||||
auto get_component = Container::Vertical({get_parameters_renderer, get_button});
|
||||
|
||||
/***************************************************************************************+
|
||||
* Clear Display Messages
|
||||
****************************************************************************************/
|
||||
|
||||
/* ********************** INPUTS ******************************************** */
|
||||
std::string clear_msg_id_str;
|
||||
InputOption o;
|
||||
o.multiline = false;
|
||||
o.cursor_position = 0;
|
||||
o.on_change = [&]() {
|
||||
clear_msg_id_str.erase(
|
||||
std::remove_if(clear_msg_id_str.begin(), clear_msg_id_str.end(), [](char c) { return !std::isdigit(c); }),
|
||||
clear_msg_id_str.end());
|
||||
};
|
||||
auto clear_id_input = Input(&clear_msg_id_str, "<single id (int) required>", o);
|
||||
|
||||
/* ********************** BUTTON ******************************************** */
|
||||
auto clear_button = Button(
|
||||
"Clear!",
|
||||
[&] {
|
||||
int clear_msg_id;
|
||||
try {
|
||||
clear_msg_id = std::stoi(clear_msg_id_str);
|
||||
clear_msg_id_str = std::to_string(clear_msg_id);
|
||||
} catch (...) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [status, status_info] = r_dm->call_clear_display_message({clear_msg_id});
|
||||
|
||||
std::string log_prefix{"Cleared Messages with ID " + std::to_string(clear_msg_id)};
|
||||
log_cmd_response(&log, log_prefix, clear_message_response_enum_to_string(status), status_info);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
/* ********************** COMPOSITION ******************************************** */
|
||||
auto clear_parameters_renderer = Renderer(clear_id_input, [&] {
|
||||
return vbox({
|
||||
text(" Command Parameters ") | inverted,
|
||||
hbox(text(" Message Id : ") | bold, clear_id_input->Render()),
|
||||
text(" "),
|
||||
});
|
||||
});
|
||||
|
||||
auto clear_component = Container::Vertical({clear_parameters_renderer, clear_button});
|
||||
|
||||
/***************************************************************************************+
|
||||
* Composition of full display
|
||||
****************************************************************************************/
|
||||
|
||||
std::vector<std::string> tab_values{
|
||||
"Set Message",
|
||||
"Get Message",
|
||||
"Clear Message",
|
||||
};
|
||||
|
||||
int tab_selected = 0;
|
||||
auto tab_toggle_component = Toggle(&tab_values, &tab_selected);
|
||||
|
||||
auto tab_toggle_renderer =
|
||||
Renderer(tab_toggle_component, [&] { return window(text(" Commands "), tab_toggle_component->Render()); });
|
||||
|
||||
auto tab_container_component = Container::Tab(
|
||||
{
|
||||
set_component,
|
||||
get_component,
|
||||
clear_component,
|
||||
},
|
||||
&tab_selected);
|
||||
|
||||
auto main_container = Container::Vertical({
|
||||
tab_toggle_renderer,
|
||||
tab_container_component,
|
||||
log_pane_renderer,
|
||||
});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox({
|
||||
text("Display Message") | bold | hcenter,
|
||||
main_container->Render(),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUDISPLAY_MESSAGE_HPP
|
||||
#define BUDISPLAY_MESSAGE_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/display_message/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUDisplayMessage : public Everest::ModuleBase {
|
||||
public:
|
||||
BUDisplayMessage() = delete;
|
||||
BUDisplayMessage(const ModuleInfo& info, std::unique_ptr<display_messageIntf> r_dm, Conf& config) :
|
||||
ModuleBase(info), r_dm(std::move(r_dm)), config(config){};
|
||||
|
||||
const std::unique_ptr<display_messageIntf> r_dm;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUDISPLAY_MESSAGE_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for Display Message interface
|
||||
requires:
|
||||
dm:
|
||||
interface: display_message
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Christoph Burandt
|
||||
@@ -0,0 +1,511 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "BUEvseBoardSupport.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
#include "generated/types/evse_manager.hpp"
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
namespace module {
|
||||
|
||||
static std::vector<std::vector<std::string>> to_string(types::evse_board_support::HardwareCapabilities c) {
|
||||
std::vector<std::vector<std::string>> hw_caps;
|
||||
hw_caps.push_back(
|
||||
{"Max/Min Current", fmt::format("Imp: {}A/{}A Exp: {}A/{}A", c.max_current_A_import, c.min_current_A_import,
|
||||
c.max_current_A_export, c.min_current_A_export)});
|
||||
hw_caps.push_back({"Max/Min Phase Count",
|
||||
fmt::format("Imp: {}ph/{}ph Exp: {}ph/{}ph", c.max_phase_count_import, c.min_phase_count_import,
|
||||
c.max_phase_count_export, c.min_phase_count_export)});
|
||||
hw_caps.push_back({"Connector Type", types::evse_board_support::connector_type_to_string(c.connector_type)});
|
||||
hw_caps.push_back({"CP State E Support", c.supports_cp_state_E ? "Yes" : "No"});
|
||||
if (c.max_plug_temperature_C.has_value()) {
|
||||
hw_caps.push_back({"Max plug temperature", fmt::format("{}C", c.max_plug_temperature_C.value())});
|
||||
}
|
||||
|
||||
return hw_caps;
|
||||
}
|
||||
|
||||
void BUEvseBoardSupport::init() {
|
||||
}
|
||||
|
||||
void BUEvseBoardSupport::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_bsp->subscribe_event([this, &screen](const types::board_support_common::BspEvent e) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
switch (e.event) {
|
||||
case types::board_support_common::Event::A:
|
||||
cp_state = "A";
|
||||
break;
|
||||
case types::board_support_common::Event::B:
|
||||
cp_state = "B";
|
||||
break;
|
||||
case types::board_support_common::Event::C:
|
||||
cp_state = "C";
|
||||
break;
|
||||
case types::board_support_common::Event::D:
|
||||
cp_state = "D";
|
||||
break;
|
||||
case types::board_support_common::Event::E:
|
||||
cp_state = "E";
|
||||
break;
|
||||
case types::board_support_common::Event::F:
|
||||
cp_state = "F";
|
||||
break;
|
||||
case types::board_support_common::Event::PowerOn:
|
||||
relais_feedback = fmt::format("PowerOn (after {} ms)",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - last_allow_power_on_time_point)
|
||||
.count());
|
||||
break;
|
||||
case types::board_support_common::Event::PowerOff:
|
||||
relais_feedback = fmt::format("PowerOff (after {} ms)",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - last_allow_power_on_time_point)
|
||||
.count());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_bsp->subscribe_capabilities([this, &screen](const types::evse_board_support::HardwareCapabilities c) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
hw_caps = to_string(c);
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_bsp->subscribe_telemetry([this, &screen](const types::evse_board_support::Telemetry t) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
telemetry = fmt::format("EVSE {}C Fan {}rpm Supply {}V/{}V, Relais {}", t.evse_temperature_C, t.fan_rpm,
|
||||
t.supply_voltage_12V, t.supply_voltage_minus_12V, t.relais_on);
|
||||
|
||||
if (t.plug_temperature_C.has_value()) {
|
||||
telemetry = telemetry += fmt::format(" Plug {}C ", t.plug_temperature_C.value());
|
||||
}
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_bsp->subscribe_ac_pp_ampacity([this, &screen](const types::board_support_common::ProximityPilot pp) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
proximity_pilot = types::board_support_common::ampacity_to_string(pp.ampacity);
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_bsp->subscribe_request_stop_transaction([this, &screen](const types::evse_manager::StopTransactionRequest t) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
stop_transaction = stop_transaction_reason_to_string(t.reason);
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
// telemetry, pp (needs to be requested as well)
|
||||
|
||||
auto error_handler = [this, &screen](const Everest::error::Error& error) {
|
||||
{
|
||||
std::scoped_lock lock(this->data_mutex);
|
||||
this->last_error_raised = fmt::format("Fault raised: {}, {}", error.type, error.sub_type);
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
};
|
||||
|
||||
auto error_cleared_handler = [this, &screen](const Everest::error::Error& error) {
|
||||
{
|
||||
std::scoped_lock lock(this->data_mutex);
|
||||
this->last_error_cleared = fmt::format("Fault cleared: {}, {}", error.type, error.sub_type);
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
};
|
||||
|
||||
r_bsp->subscribe_all_errors(error_handler, error_cleared_handler);
|
||||
|
||||
if (!r_ac_rcd.empty()) {
|
||||
r_ac_rcd.at(0)->subscribe_all_errors(error_handler, error_cleared_handler);
|
||||
}
|
||||
|
||||
if (!r_lock_motor.empty()) {
|
||||
r_lock_motor.at(0)->subscribe_all_errors(error_handler, error_cleared_handler);
|
||||
}
|
||||
|
||||
std::string last_command = "None";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Relais allow power on
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Component relais_on_button = Button(
|
||||
"Allow power on",
|
||||
[&] {
|
||||
last_command = "Allow power on";
|
||||
last_allow_power_on_time_point = std::chrono::steady_clock::now();
|
||||
r_bsp->call_allow_power_on({true, types::evse_board_support::Reason::FullPowerCharging});
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component relais_off_button = Button(
|
||||
"Force power off",
|
||||
[&] {
|
||||
last_command = "Force power off";
|
||||
last_allow_power_on_time_point = std::chrono::steady_clock::now();
|
||||
r_bsp->call_allow_power_on({false, types::evse_board_support::Reason::PowerOff});
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto relais_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
relais_on_button,
|
||||
relais_off_button,
|
||||
}),
|
||||
});
|
||||
|
||||
auto relais_renderer = Renderer(relais_component, [&] {
|
||||
auto relais_win = window(text("Relais"), relais_component->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
relais_win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PWM control
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
std::string pwm_duty_cycle_str{"5.0"};
|
||||
|
||||
Component cp_state_X1_button = Button(
|
||||
"CP State X1 (PWM Off)",
|
||||
[&] {
|
||||
last_command = "CP State X1 (PWM Off)";
|
||||
r_bsp->call_cp_state_X1();
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component pwm_on_button = Button(
|
||||
"PWM On",
|
||||
[&] {
|
||||
if (pwm_duty_cycle_str.empty())
|
||||
pwm_duty_cycle_str = "5.0";
|
||||
last_command = "PWM On (" + pwm_duty_cycle_str + ")";
|
||||
r_bsp->call_pwm_on(std::stof(pwm_duty_cycle_str.c_str()));
|
||||
},
|
||||
ButtonOption::Animated(Color::Green, Color::White, Color::GreenLight, Color::White));
|
||||
|
||||
Component cp_state_E_button = Button(
|
||||
"CP State E",
|
||||
[&] {
|
||||
last_command = "CP State E";
|
||||
r_bsp->call_cp_state_E();
|
||||
},
|
||||
ButtonOption::Animated(Color::Magenta, Color::White, Color::MagentaLight, Color::White));
|
||||
|
||||
Component cp_state_F_button = Button(
|
||||
"CP State F",
|
||||
[&] {
|
||||
last_command = "CP State F";
|
||||
r_bsp->call_cp_state_F();
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
InputOption o;
|
||||
o.multiline = false;
|
||||
o.cursor_position = 0;
|
||||
o.on_enter = [&]() {
|
||||
last_command = "Update PWM DC to " + pwm_duty_cycle_str;
|
||||
r_bsp->call_pwm_on(std::stof(pwm_duty_cycle_str.c_str()));
|
||||
};
|
||||
auto pwm_dc = Input(&pwm_duty_cycle_str, "5.0", o);
|
||||
auto pwm_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
cp_state_E_button,
|
||||
cp_state_F_button,
|
||||
cp_state_X1_button,
|
||||
pwm_on_button,
|
||||
pwm_dc,
|
||||
}),
|
||||
});
|
||||
|
||||
auto pwm_renderer = Renderer(pwm_component, [&] {
|
||||
auto pwm_win = window(text("PWM"), pwm_component->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
pwm_win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Enable/Disable
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Component enable_on_button = Button(
|
||||
"Enable",
|
||||
[&] {
|
||||
last_command = "Enable";
|
||||
r_bsp->call_enable(true);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component enable_off_button = Button(
|
||||
"Disable",
|
||||
[&] {
|
||||
last_command = "Disable";
|
||||
r_bsp->call_enable(false);
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto enable_component = Container::Vertical({
|
||||
enable_on_button,
|
||||
enable_off_button,
|
||||
});
|
||||
|
||||
auto enable_renderer =
|
||||
Renderer(enable_component, [&] { return window(text("Enable"), enable_component->Render()); });
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AC switch phases while charging
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Component three_phase_button = Button(
|
||||
"ThreePhases",
|
||||
[&] {
|
||||
last_command = "Switch ThreePhases";
|
||||
r_bsp->call_ac_switch_three_phases_while_charging(true);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component single_phase_button = Button(
|
||||
"SinglePhase",
|
||||
[&] {
|
||||
last_command = "Switch SinglePhase";
|
||||
r_bsp->call_ac_switch_three_phases_while_charging(false);
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto phase_switch_component = Container::Vertical({
|
||||
three_phase_button,
|
||||
single_phase_button,
|
||||
});
|
||||
|
||||
auto phase_switch_renderer = Renderer(
|
||||
phase_switch_component, [&] { return window(text("AC Phase Switch"), phase_switch_component->Render()); });
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AC Overcurrent Limit command
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
std::string ac_oc_limit_str = "16.0"; // Default current limit (A)
|
||||
|
||||
Component ac_oc_limit_button = Button(
|
||||
"Set Limit",
|
||||
[&] {
|
||||
if (ac_oc_limit_str.empty())
|
||||
ac_oc_limit_str = "16.0";
|
||||
last_command = "Set AC Overcurrent Limit (" + ac_oc_limit_str + " A)";
|
||||
r_bsp->call_ac_set_overcurrent_limit_A(std::stof(ac_oc_limit_str.c_str()));
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
InputOption ac_oc_input_opt;
|
||||
ac_oc_input_opt.multiline = false;
|
||||
ac_oc_input_opt.cursor_position = 0;
|
||||
ac_oc_input_opt.on_enter = [&]() {
|
||||
if (ac_oc_limit_str.empty())
|
||||
ac_oc_limit_str = "16.0";
|
||||
last_command = "Set AC Overcurrent Limit (" + ac_oc_limit_str + " A)";
|
||||
r_bsp->call_ac_set_overcurrent_limit_A(std::stof(ac_oc_limit_str.c_str()));
|
||||
};
|
||||
auto ac_oc_input = Input(&ac_oc_limit_str, "16.0", ac_oc_input_opt);
|
||||
|
||||
auto ac_oc_component = Container::Vertical({
|
||||
ac_oc_limit_button,
|
||||
ac_oc_input,
|
||||
});
|
||||
|
||||
auto ac_oc_renderer =
|
||||
Renderer(ac_oc_component, [&] { return window(text("AC Overcurrent Limit"), ac_oc_component->Render()); });
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vars
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto vars_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
table_content = {{"CP State", cp_state},
|
||||
{"Relais", relais_feedback},
|
||||
{"Telemetry", telemetry},
|
||||
{"Proximity Pilot", proximity_pilot}};
|
||||
}
|
||||
auto vars = Table(table_content);
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(
|
||||
text("Information"),
|
||||
vbox({text("Last command: " + last_command), text("Last error raised: " + last_error_raised),
|
||||
text("Last error cleared: " + last_error_cleared), vars.Render()})),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Request stop transaction
|
||||
// ---------------------------------------------------------------------------
|
||||
auto vars_stop_transaction_renderer = Renderer([&] {
|
||||
Element reason = text("Request stop transaction: " + stop_transaction);
|
||||
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Buttons"), reason),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Capabilities
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
types::evse_board_support::HardwareCapabilities dummy_caps;
|
||||
dummy_caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable;
|
||||
hw_caps = to_string(dummy_caps);
|
||||
|
||||
auto caps_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> caps_table_content;
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
caps_table_content = hw_caps;
|
||||
}
|
||||
auto caps = Table(caps_table_content);
|
||||
|
||||
caps.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < caps_table_content.size(); i++) {
|
||||
caps.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Capabilities"), caps.Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AC RCD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto no_rcd_text = Renderer([] { return text("No AC RCD module connected in config."); });
|
||||
auto rcd_component = Container::Vertical({
|
||||
no_rcd_text,
|
||||
});
|
||||
|
||||
if (!r_ac_rcd.empty()) {
|
||||
|
||||
std::string rcd_current_display = "N/A";
|
||||
std::string rcd_reset_result = "";
|
||||
|
||||
Component rcd_self_test_button = Button(
|
||||
"Self Test",
|
||||
[&] {
|
||||
last_command = "AC RCD Self Test";
|
||||
r_ac_rcd.at(0)->call_self_test();
|
||||
},
|
||||
ButtonOption::Animated(Color::Green, Color::White, Color::GreenLight, Color::White));
|
||||
|
||||
Component rcd_reset_button = Button(
|
||||
"Reset",
|
||||
[&] {
|
||||
last_command = "AC RCD Reset";
|
||||
bool reset_result = r_ac_rcd.at(0)->call_reset();
|
||||
rcd_reset_result = fmt::format("Reset result: {}", reset_result ? "Success" : "Failed");
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
rcd_component = Container::Vertical({
|
||||
rcd_self_test_button,
|
||||
rcd_reset_button,
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Connector Lock
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto no_lock_text = Renderer([] { return text("No Connector Lock module connected in config."); });
|
||||
auto lock_component = Container::Vertical({
|
||||
no_lock_text,
|
||||
});
|
||||
|
||||
if (!r_lock_motor.empty()) {
|
||||
|
||||
Component lock_button = Button(
|
||||
"Connector Lock",
|
||||
[&] {
|
||||
last_command = "Connector Lock";
|
||||
r_lock_motor.at(0)->call_lock();
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component unlock_button = Button(
|
||||
"Connector Unlock",
|
||||
[&] {
|
||||
last_command = "Connector Unlock";
|
||||
r_lock_motor.at(0)->call_unlock();
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
lock_component = Container::Vertical({
|
||||
lock_button,
|
||||
unlock_button,
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main layout
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto command_row =
|
||||
Container::Horizontal({pwm_renderer, relais_renderer, enable_renderer, phase_switch_renderer, ac_oc_renderer});
|
||||
|
||||
auto info_row = Container::Horizontal({
|
||||
vars_renderer,
|
||||
caps_renderer,
|
||||
vars_stop_transaction_renderer,
|
||||
});
|
||||
|
||||
// Add RCD and Lock components to the interactive container tree
|
||||
auto main_container = Container::Vertical({info_row, command_row, rcd_component, lock_component});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox(text("EVSE Board Support") | bold | hcenter, separator(), info_row->Render(), command_row->Render(),
|
||||
separator(),
|
||||
hbox(window(text("AC RCD"), vbox(text("RCD Current: " + rcd_current_display + " mA"), separator(),
|
||||
rcd_component->Render(), text(rcd_reset_result))) |
|
||||
flex,
|
||||
separator(), window(text("Connector Lock"), lock_component->Render()) | flex));
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUEVSE_BOARD_SUPPORT_HPP
|
||||
#define BUEVSE_BOARD_SUPPORT_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/ac_rcd/Interface.hpp>
|
||||
#include <generated/interfaces/connector_lock/Interface.hpp>
|
||||
#include <generated/interfaces/evse_board_support/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUEvseBoardSupport : public Everest::ModuleBase {
|
||||
public:
|
||||
BUEvseBoardSupport() = delete;
|
||||
BUEvseBoardSupport(const ModuleInfo& info, std::unique_ptr<evse_board_supportIntf> r_bsp,
|
||||
std::vector<std::unique_ptr<connector_lockIntf>> r_lock_motor,
|
||||
std::vector<std::unique_ptr<ac_rcdIntf>> r_ac_rcd, Conf& config) :
|
||||
ModuleBase(info),
|
||||
r_bsp(std::move(r_bsp)),
|
||||
r_lock_motor(std::move(r_lock_motor)),
|
||||
r_ac_rcd(std::move(r_ac_rcd)),
|
||||
config(config){};
|
||||
|
||||
const std::unique_ptr<evse_board_supportIntf> r_bsp;
|
||||
const std::vector<std::unique_ptr<connector_lockIntf>> r_lock_motor;
|
||||
const std::vector<std::unique_ptr<ac_rcdIntf>> r_ac_rcd;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::mutex data_mutex;
|
||||
std::string cp_state;
|
||||
std::string relais_feedback;
|
||||
std::string telemetry;
|
||||
std::string proximity_pilot;
|
||||
std::string stop_transaction;
|
||||
std::vector<std::vector<std::string>> hw_caps;
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_allow_power_on_time_point;
|
||||
std::string last_error_raised;
|
||||
std::string last_error_cleared;
|
||||
|
||||
std::string rcd_current_display;
|
||||
std::string rcd_reset_result;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUEVSE_BOARD_SUPPORT_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,16 @@
|
||||
description: Interactive bring up helper for EVSE Board support interface
|
||||
requires:
|
||||
bsp:
|
||||
interface: evse_board_support
|
||||
lock_motor:
|
||||
interface: connector_lock
|
||||
min_connections: 0
|
||||
max_connections: 1
|
||||
ac_rcd:
|
||||
interface: ac_rcd
|
||||
min_connections: 0
|
||||
max_connections: 1
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
@@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "BUIsolationMonitor.hpp"
|
||||
#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, ResizableSplitLeft, Tab
|
||||
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
|
||||
#include "ftxui/component/component_options.hpp" // for MenuOption, InputOption
|
||||
#include "ftxui/component/event.hpp" // for Event, Event::Custom
|
||||
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for text, color, operator|, bgcolor, filler, Element, vbox, size, hbox, separator, flex, window, graph, EQUAL, paragraph, WIDTH, hcenter, Elements, bold, vscroll_indicator, HEIGHT, flexbox, hflow, border, frame, flex_grow, gauge, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight, dim, spinner, LESS_THAN, center, yframe, GREATER_THAN
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig
|
||||
#include "ftxui/dom/table.hpp" // for Table
|
||||
#include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::Black, Color::Blue, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default, Color::Palette256, ftxui
|
||||
#include "ftxui/screen/color_info.hpp" // for ColorInfo
|
||||
#include "ftxui/screen/terminal.hpp" // for Size, Dimensions
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
namespace module {
|
||||
|
||||
static std::vector<std::vector<std::string>> to_table(types::isolation_monitor::IsolationMeasurement m) {
|
||||
std::vector<std::vector<std::string>> measurement;
|
||||
measurement.push_back({"Resistance F", fmt::format("{} Ohm", m.resistance_F_Ohm)});
|
||||
|
||||
if (m.voltage_V.has_value()) {
|
||||
measurement.push_back({"DC Voltage", fmt::format("{} V", m.voltage_V.value())});
|
||||
}
|
||||
|
||||
if (m.voltage_to_earth_l1e_V.has_value()) {
|
||||
measurement.push_back({"DC Voltage to Earth L1E", fmt::format("{} V", m.voltage_to_earth_l1e_V.value())});
|
||||
}
|
||||
|
||||
if (m.voltage_to_earth_l2e_V.has_value()) {
|
||||
measurement.push_back({"DC Voltage to Earth L2E", fmt::format("{} V", m.voltage_to_earth_l2e_V.value())});
|
||||
}
|
||||
|
||||
measurement.push_back({"Timestamp: ", Everest::Date::to_rfc3339(date::utc_clock::now())});
|
||||
|
||||
return measurement;
|
||||
}
|
||||
|
||||
void BUIsolationMonitor::init() {
|
||||
types::isolation_monitor::IsolationMeasurement m;
|
||||
m.resistance_F_Ohm = 0;
|
||||
last_measurement = to_table(m);
|
||||
}
|
||||
|
||||
void BUIsolationMonitor::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_imd->subscribe_isolation_measurement([this, &screen](const types::isolation_monitor::IsolationMeasurement m) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
last_measurement = to_table(m);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Start IMD Measurements
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Component start_button = Button(
|
||||
"Start Measurements", [&] { r_imd->call_start(); },
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component stop_button = Button(
|
||||
"Stop Measurements", [&] { r_imd->call_stop(); },
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component selftest_button = Button(
|
||||
"Run Self-Test", [&] { r_imd->call_start_self_test(500); },
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
auto ctrl_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
start_button,
|
||||
stop_button,
|
||||
selftest_button,
|
||||
}),
|
||||
});
|
||||
|
||||
auto ctrl_renderer = Renderer(ctrl_component, [&] {
|
||||
auto ctrl_win = window(text("Control"), ctrl_component->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
ctrl_win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vars
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto vars_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
table_content = last_measurement;
|
||||
// table_content = {{"CP State", "cp_state"}, {"Relais", "relais_feedback"}, {"Telemetry", "telemetry"}};
|
||||
}
|
||||
auto vars = Table(table_content);
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Information"), vars.Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Horizontal({
|
||||
ctrl_renderer,
|
||||
vars_renderer,
|
||||
});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox({
|
||||
text("Isolation Monitor") | bold | hcenter,
|
||||
main_container->Render(),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUISOLATION_MONITOR_HPP
|
||||
#define BUISOLATION_MONITOR_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/isolation_monitor/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUIsolationMonitor : public Everest::ModuleBase {
|
||||
public:
|
||||
BUIsolationMonitor() = delete;
|
||||
BUIsolationMonitor(const ModuleInfo& info, std::unique_ptr<isolation_monitorIntf> r_imd, Conf& config) :
|
||||
ModuleBase(info), r_imd(std::move(r_imd)), config(config){};
|
||||
|
||||
const std::unique_ptr<isolation_monitorIntf> r_imd;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::mutex data_mutex;
|
||||
std::vector<std::vector<std::string>> last_measurement;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUISOLATION_MONITOR_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for Isolation Monitor interface
|
||||
requires:
|
||||
imd:
|
||||
interface: isolation_monitor
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "BUOcppConsumer.hpp"
|
||||
|
||||
// for the moment use std::cout
|
||||
// #include <ftxui/component/component.hpp>
|
||||
// #include <ftxui/component/screen_interactive.hpp>
|
||||
// #include <ftxui/dom/table.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace module {
|
||||
|
||||
void BUOcppConsumer::init() {
|
||||
invoke_init(*p_ocpp);
|
||||
invoke_init(*p_ocpp_data_transfer);
|
||||
}
|
||||
|
||||
void BUOcppConsumer::ready() {
|
||||
invoke_ready(*p_ocpp);
|
||||
invoke_ready(*p_ocpp_data_transfer);
|
||||
std::cout << "Ready...\n";
|
||||
}
|
||||
|
||||
void BUOcppConsumer::event(const types::ocpp::GetVariableResult& ev) {
|
||||
std::cout << "GetVariable: " << ev.component_variable.variable.name << '=' << ev.value.value_or("<none>") << " ("
|
||||
<< ev.status << ")\n";
|
||||
}
|
||||
|
||||
void BUOcppConsumer::event(const std::string& value, const types::ocpp::SetVariableResult& ev) {
|
||||
std::cout << "SetVariable: " << ev.component_variable.variable.name << '=' << value << " (" << ev.status << ")\n";
|
||||
}
|
||||
|
||||
void BUOcppConsumer::event_monitor_variable(const std::string& name) {
|
||||
std::cout << "MonitorVariable: " << name << '\n';
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUOCPP_CONSUMER_HPP
|
||||
#define BUOCPP_CONSUMER_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/ocpp/Implementation.hpp>
|
||||
#include <generated/interfaces/ocpp_data_transfer/Implementation.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUOcppConsumer : public Everest::ModuleBase {
|
||||
public:
|
||||
BUOcppConsumer() = delete;
|
||||
BUOcppConsumer(const ModuleInfo& info, std::unique_ptr<ocppImplBase> p_ocpp,
|
||||
std::unique_ptr<ocpp_data_transferImplBase> p_ocpp_data_transfer, Conf& config) :
|
||||
ModuleBase(info),
|
||||
p_ocpp(std::move(p_ocpp)),
|
||||
p_ocpp_data_transfer(std::move(p_ocpp_data_transfer)),
|
||||
config(config){};
|
||||
|
||||
const std::unique_ptr<ocppImplBase> p_ocpp;
|
||||
const std::unique_ptr<ocpp_data_transferImplBase> p_ocpp_data_transfer;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
void event(const types::ocpp::GetVariableResult& ev);
|
||||
void event(const std::string& value, const types::ocpp::SetVariableResult& ev);
|
||||
void event_monitor_variable(const std::string& name);
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUOCPP_CONSUMER_HPP
|
||||
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
# target_link_libraries(${MODULE_NAME}
|
||||
# PRIVATE ftxui::screen
|
||||
# PRIVATE ftxui::dom
|
||||
# PRIVATE ftxui::component
|
||||
# )
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"ocpp/ocppImpl.cpp"
|
||||
"ocpp_data_transfer/ocpp_data_transferImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,12 @@
|
||||
description: Interactive bring up helper for OCPP consumer interface
|
||||
provides:
|
||||
ocpp:
|
||||
description: OCPP inteface
|
||||
interface: ocpp
|
||||
ocpp_data_transfer:
|
||||
description: OCPP data transfer towards the CSMS
|
||||
interface: ocpp_data_transfer
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- James Chapman
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "ocppImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace ocpp {
|
||||
|
||||
void ocppImpl::init() {
|
||||
// TODO(james-ctc): populate variable_store with some initial values
|
||||
}
|
||||
|
||||
void ocppImpl::ready() {
|
||||
}
|
||||
|
||||
bool ocppImpl::handle_stop() {
|
||||
// your code for cmd stop goes here
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ocppImpl::handle_restart() {
|
||||
// your code for cmd restart goes here
|
||||
return true;
|
||||
}
|
||||
|
||||
void ocppImpl::handle_security_event(types::ocpp::SecurityEvent& event) {
|
||||
// your code for cmd security_event goes here
|
||||
}
|
||||
|
||||
std::vector<types::ocpp::GetVariableResult>
|
||||
ocppImpl::handle_get_variables(std::vector<types::ocpp::GetVariableRequest>& requests) {
|
||||
// your code for cmd get_variables goes here
|
||||
std::vector<types::ocpp::GetVariableResult> resultList;
|
||||
for (const auto& i : requests) {
|
||||
types::ocpp::GetVariableResult result{types::ocpp::GetVariableStatusEnumType::Rejected, i.component_variable};
|
||||
const std::string& name = i.component_variable.variable.name;
|
||||
if (const auto it = variable_store.find(name); it != variable_store.end()) {
|
||||
result.value = it->second;
|
||||
result.status = types::ocpp::GetVariableStatusEnumType::Accepted;
|
||||
}
|
||||
mod->event(result);
|
||||
resultList.push_back(result);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
std::vector<types::ocpp::SetVariableResult>
|
||||
ocppImpl::handle_set_variables(std::vector<types::ocpp::SetVariableRequest>& requests, std::string& source) {
|
||||
// your code for cmd set_variables goes here
|
||||
std::vector<types::ocpp::SetVariableResult> resultList;
|
||||
for (const auto& i : requests) {
|
||||
types::ocpp::SetVariableResult result{types::ocpp::SetVariableStatusEnumType::Rejected, i.component_variable};
|
||||
const std::string& name = i.component_variable.variable.name;
|
||||
if (!name.empty()) {
|
||||
variable_store[name] = i.value;
|
||||
result.status = types::ocpp::SetVariableStatusEnumType::Accepted;
|
||||
if (const auto it = std::find(variable_monitor.begin(), variable_monitor.end(), name);
|
||||
it != variable_monitor.end()) {
|
||||
types::ocpp::EventData data{i.component_variable,
|
||||
-1,
|
||||
Everest::Date::to_rfc3339(date::utc_clock::now()),
|
||||
types::ocpp::EventTriggerEnum::Delta,
|
||||
i.value,
|
||||
types::ocpp::EventNotificationType::PreconfiguredMonitor};
|
||||
mod->p_ocpp->publish_event_data(data);
|
||||
}
|
||||
}
|
||||
mod->event(i.value, result);
|
||||
resultList.push_back(result);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
types::ocpp::ChangeAvailabilityResponse
|
||||
ocppImpl::handle_change_availability(types::ocpp::ChangeAvailabilityRequest& request) {
|
||||
// your code for cmd change_availability goes here
|
||||
return {};
|
||||
}
|
||||
|
||||
void ocppImpl::handle_monitor_variables(std::vector<types::ocpp::ComponentVariable>& component_variables) {
|
||||
// your code for cmd monitor_variables goes here
|
||||
for (const auto& i : component_variables) {
|
||||
const std::string& name = i.variable.name;
|
||||
if (!name.empty()) {
|
||||
variable_monitor.push_back(name);
|
||||
mod->event_monitor_variable(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ocpp
|
||||
} // namespace module
|
||||
@@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef OCPP_OCPP_IMPL_HPP
|
||||
#define OCPP_OCPP_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ocpp/Implementation.hpp>
|
||||
|
||||
#include "../BUOcppConsumer.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
#include <map>
|
||||
#include <vector>
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace ocpp {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ocppImpl : public ocppImplBase {
|
||||
public:
|
||||
ocppImpl() = delete;
|
||||
ocppImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<BUOcppConsumer>& mod, Conf& config) :
|
||||
ocppImplBase(ev, "ocpp"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
using Store = std::map<std::string, std::string>;
|
||||
using Monitor = std::vector<std::string>;
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual bool handle_stop() override;
|
||||
virtual bool handle_restart() override;
|
||||
virtual void handle_security_event(types::ocpp::SecurityEvent& event) override;
|
||||
virtual std::vector<types::ocpp::GetVariableResult>
|
||||
handle_get_variables(std::vector<types::ocpp::GetVariableRequest>& requests) override;
|
||||
virtual std::vector<types::ocpp::SetVariableResult>
|
||||
handle_set_variables(std::vector<types::ocpp::SetVariableRequest>& requests, std::string& source) override;
|
||||
virtual types::ocpp::ChangeAvailabilityResponse
|
||||
handle_change_availability(types::ocpp::ChangeAvailabilityRequest& request) override;
|
||||
virtual void handle_monitor_variables(std::vector<types::ocpp::ComponentVariable>& component_variables) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
Store variable_store;
|
||||
Monitor variable_monitor;
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<BUOcppConsumer>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace ocpp
|
||||
} // namespace module
|
||||
|
||||
#endif // OCPP_OCPP_IMPL_HPP
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "ocpp_data_transferImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace ocpp_data_transfer {
|
||||
|
||||
void ocpp_data_transferImpl::init() {
|
||||
}
|
||||
|
||||
void ocpp_data_transferImpl::ready() {
|
||||
}
|
||||
|
||||
types::ocpp::DataTransferResponse
|
||||
ocpp_data_transferImpl::handle_data_transfer(types::ocpp::DataTransferRequest& request) {
|
||||
// your code for cmd data_transfer goes here
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace ocpp_data_transfer
|
||||
} // namespace module
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef OCPP_DATA_TRANSFER_OCPP_DATA_TRANSFER_IMPL_HPP
|
||||
#define OCPP_DATA_TRANSFER_OCPP_DATA_TRANSFER_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ocpp_data_transfer/Implementation.hpp>
|
||||
|
||||
#include "../BUOcppConsumer.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace ocpp_data_transfer {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ocpp_data_transferImpl : public ocpp_data_transferImplBase {
|
||||
public:
|
||||
ocpp_data_transferImpl() = delete;
|
||||
ocpp_data_transferImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<BUOcppConsumer>& mod, Conf& config) :
|
||||
ocpp_data_transferImplBase(ev, "ocpp_data_transfer"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual types::ocpp::DataTransferResponse handle_data_transfer(types::ocpp::DataTransferRequest& request) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<BUOcppConsumer>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace ocpp_data_transfer
|
||||
} // namespace module
|
||||
|
||||
#endif // OCPP_DATA_TRANSFER_OCPP_DATA_TRANSFER_IMPL_HPP
|
||||
@@ -0,0 +1,167 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "BUOverVoltageMonitor.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace module {
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
void BUOverVoltageMonitor::init() {
|
||||
}
|
||||
|
||||
void BUOverVoltageMonitor::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
auto msg_component = Container::Vertical({Renderer([] { return text(""); })});
|
||||
|
||||
std::map<std::string, std::map<std::string, Component>> messages;
|
||||
|
||||
r_ovm->subscribe_all_errors(
|
||||
[&](Everest::error::Error const& error) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
std::regex filter("over_voltage_monitor/");
|
||||
auto error_type = std::regex_replace(error.type, filter, "");
|
||||
auto error_elem = Renderer([=] { return text(" - " + error_type); });
|
||||
auto sub_elem = Renderer([=] { return text(" " + error.sub_type); });
|
||||
auto msg_elem = Renderer([=] { return text(" " + error.message); });
|
||||
|
||||
auto component = Container::Vertical({
|
||||
error_elem,
|
||||
sub_elem,
|
||||
msg_elem,
|
||||
});
|
||||
|
||||
messages[error.type][error.sub_type] = component;
|
||||
msg_component->Add(component);
|
||||
screen.Post(Event::Custom);
|
||||
},
|
||||
[&](Everest::error::Error const& error) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
if (messages.count(error.type)) {
|
||||
auto& sub = messages.at(error.type);
|
||||
if (sub.count(error.sub_type)) {
|
||||
auto& elem = sub.at(error.sub_type);
|
||||
elem->Detach();
|
||||
sub.erase(error.sub_type);
|
||||
}
|
||||
if (not sub.size()) {
|
||||
messages.erase(error.type);
|
||||
}
|
||||
}
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_ovm->subscribe_voltage_measurement_V([this, &screen](float v) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
voltage_measurement_V = fmt::format("{}V", v);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
auto vars_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
table_content = {{"Voltage measurement", voltage_measurement_V}};
|
||||
auto vars = Table(table_content);
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Information"), vbox({vars.Render()})),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto msg_component_holder = Container::Horizontal({msg_component});
|
||||
|
||||
auto msg_component_renderer = Renderer(msg_component_holder, [&] {
|
||||
auto win = window(text("Active Errors"), msg_component_holder->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
InputOption o;
|
||||
o.multiline = false;
|
||||
o.cursor_position = 0;
|
||||
|
||||
auto error_limit_input = Input(&error_limit, "800.0", o);
|
||||
auto emergency_limit_input = Input(&emergency_limit, "1000.0", o);
|
||||
|
||||
Component ovm_set_limit = Button(
|
||||
"Set Error/Emergency Limits",
|
||||
[&] {
|
||||
auto error_val = std::stof(error_limit);
|
||||
auto emergency_val = std::stof(emergency_limit);
|
||||
r_ovm->call_set_limits(emergency_val, error_val);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White)) |
|
||||
flex_grow;
|
||||
|
||||
Component ovm_start = Button(
|
||||
"Start", [&] { r_ovm->call_start(); },
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White)) |
|
||||
flex_grow;
|
||||
|
||||
Component ovm_stop = Button(
|
||||
"Stop", [&] { r_ovm->call_stop(); },
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White)) |
|
||||
flex_grow;
|
||||
|
||||
Component ovm_reset = Button(
|
||||
"Reset", [&] { r_ovm->call_reset_over_voltage_error(); },
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White)) |
|
||||
flex_grow;
|
||||
|
||||
auto action_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
ovm_set_limit,
|
||||
error_limit_input,
|
||||
emergency_limit_input,
|
||||
ovm_start,
|
||||
ovm_stop,
|
||||
ovm_reset,
|
||||
}),
|
||||
});
|
||||
|
||||
auto action_component_renderer = Renderer(action_component, [&] {
|
||||
return vbox({hbox(text(" Over voltage error limit (V): "), error_limit_input->Render()),
|
||||
hbox(text(" Over voltage emergency limit (V): "), emergency_limit_input->Render()),
|
||||
hbox(ovm_set_limit->Render()), hbox(ovm_start->Render()), hbox(ovm_stop->Render()),
|
||||
hbox(ovm_reset->Render())});
|
||||
});
|
||||
|
||||
auto action_renderer = Renderer(action_component, [&] {
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Over Voltage Monitor Commands"), action_component_renderer->Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Horizontal({action_renderer, msg_component_renderer, vars_renderer});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
return vbox({
|
||||
text("Over Voltage Monitor Bringup") | bold | hcenter,
|
||||
hbox({main_container->Render()}),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUOVER_VOLTAGE_MONITOR_HPP
|
||||
#define BUOVER_VOLTAGE_MONITOR_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/over_voltage_monitor/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUOverVoltageMonitor : public Everest::ModuleBase {
|
||||
public:
|
||||
BUOverVoltageMonitor() = delete;
|
||||
BUOverVoltageMonitor(const ModuleInfo& info, std::unique_ptr<over_voltage_monitorIntf> r_ovm, Conf& config) :
|
||||
ModuleBase(info), r_ovm(std::move(r_ovm)), config(config){};
|
||||
|
||||
const std::unique_ptr<over_voltage_monitorIntf> r_ovm;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::string error_limit{"800.0"};
|
||||
std::string emergency_limit{"1000.0"};
|
||||
std::mutex data_mutex;
|
||||
std::string voltage_measurement_V{"0.0V"};
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUOVER_VOLTAGE_MONITOR_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for over_voltage_monitor interface
|
||||
requires:
|
||||
ovm:
|
||||
interface: over_voltage_monitor
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Jan Christoph Habig
|
||||
@@ -0,0 +1,254 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "BUPowerSupplyDC.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
namespace module {
|
||||
|
||||
static std::vector<std::vector<std::string>> to_string(types::power_supply_DC::Capabilities c) {
|
||||
std::vector<std::vector<std::string>> hw_caps;
|
||||
hw_caps.push_back({"Bi-Directional", (c.bidirectional ? "yes" : "no")});
|
||||
hw_caps.push_back({"Export", fmt::format("{}V/{}V {}A/{}A {}W Efficiency {}", c.max_export_voltage_V,
|
||||
c.min_export_voltage_V, c.max_export_current_A, c.min_export_current_A,
|
||||
c.max_export_power_W, c.conversion_efficiency_export.value_or(1.0))});
|
||||
if (c.bidirectional) {
|
||||
hw_caps.push_back(
|
||||
{"Import", fmt::format("{}V/{}V {}A/{}A {}W Efficiency {}", c.max_import_voltage_V.value_or(0),
|
||||
c.min_import_voltage_V.value_or(0), c.max_import_current_A.value_or(0),
|
||||
c.min_import_current_A.value_or(0), c.max_import_power_W.value_or(0),
|
||||
c.conversion_efficiency_import.value_or(1.0))});
|
||||
}
|
||||
hw_caps.push_back({"Current", fmt::format("Ripple {}A Regulation {}A", c.peak_current_ripple_A,
|
||||
c.current_regulation_tolerance_A)});
|
||||
|
||||
return hw_caps;
|
||||
}
|
||||
|
||||
void BUPowerSupplyDC::init() {
|
||||
}
|
||||
|
||||
void BUPowerSupplyDC::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_psu->subscribe_voltage_current([this, &screen](const types::power_supply_DC::VoltageCurrent v) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
actual_voltage = fmt::format("{}V", v.voltage_V);
|
||||
actual_current = fmt::format("{}A", v.current_A);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_psu->subscribe_mode([this, &screen](const types::power_supply_DC::Mode mode) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
actual_mode = mode_to_string(mode);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_psu->subscribe_capabilities([this, &screen](const types::power_supply_DC::Capabilities caps) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
raw_caps = caps;
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
std::string last_command = "None";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Select mode
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Component psu_off = Button(
|
||||
"Power Off",
|
||||
[&] {
|
||||
last_command = "Switch Off";
|
||||
r_psu->call_setMode(types::power_supply_DC::Mode::Off, types::power_supply_DC::ChargingPhase::Other);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component psu_export_cablecheck = Button(
|
||||
"Export (cablecheck EV)",
|
||||
[&] {
|
||||
last_command = "Export (precharge EV)";
|
||||
r_psu->call_setMode(types::power_supply_DC::Mode::Export,
|
||||
types::power_supply_DC::ChargingPhase::CableCheck);
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component psu_export_precharge = Button(
|
||||
"Export (precharge EV)",
|
||||
[&] {
|
||||
last_command = "Export (precharge EV)";
|
||||
r_psu->call_setMode(types::power_supply_DC::Mode::Export, types::power_supply_DC::ChargingPhase::PreCharge);
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component psu_export = Button(
|
||||
"Export (charge EV)",
|
||||
[&] {
|
||||
last_command = "Export (charge EV)";
|
||||
r_psu->call_setMode(types::power_supply_DC::Mode::Export, types::power_supply_DC::ChargingPhase::Charging);
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component psu_import = Button(
|
||||
"Import (discharge EV)",
|
||||
[&] {
|
||||
last_command = "Import (discharge EV)";
|
||||
r_psu->call_setMode(types::power_supply_DC::Mode::Import, types::power_supply_DC::ChargingPhase::Other);
|
||||
},
|
||||
ButtonOption::Animated(Color::Red, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto mode_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
psu_off,
|
||||
psu_export_cablecheck,
|
||||
psu_export_precharge,
|
||||
psu_export,
|
||||
psu_import,
|
||||
}),
|
||||
});
|
||||
|
||||
auto mode_renderer = Renderer(mode_component, [&] {
|
||||
auto mode_win = window(text("Relais"), mode_component->Render());
|
||||
return vbox({
|
||||
hbox({
|
||||
mode_win,
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PWM control
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
std::string setpoint_export_voltage{"10.0"};
|
||||
std::string setpoint_export_current{"1.0"};
|
||||
std::string setpoint_import_voltage{"10.0"};
|
||||
std::string setpoint_import_current{"1.0"};
|
||||
|
||||
Component set_export_voltage_current = Button(
|
||||
"Set Export voltage/current limit",
|
||||
[&] {
|
||||
float v = std::stof(setpoint_export_voltage);
|
||||
float c = std::stof(setpoint_export_current);
|
||||
last_command = fmt::format("Set Export voltage/current limit ({}V / {}A)", v, c);
|
||||
r_psu->call_setExportVoltageCurrent(v, c);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
Component set_import_voltage_current = Button(
|
||||
"Set Import voltage/current limit",
|
||||
[&] {
|
||||
float v = std::stof(setpoint_import_voltage);
|
||||
float c = std::stof(setpoint_import_current);
|
||||
last_command = fmt::format("Set Import voltage/current limit ({}V / {}A)", v, c);
|
||||
r_psu->call_setImportVoltageCurrent(v, c);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::BlueLight, Color::White));
|
||||
|
||||
InputOption o;
|
||||
o.multiline = false;
|
||||
o.cursor_position = 0;
|
||||
|
||||
auto export_voltage_input = Input(&setpoint_export_voltage, "10.0", o);
|
||||
auto export_current_input = Input(&setpoint_export_current, "1.0", o);
|
||||
auto import_voltage_input = Input(&setpoint_import_voltage, "10.0", o);
|
||||
auto import_current_input = Input(&setpoint_import_current, "1.0", o);
|
||||
|
||||
auto voltage_current_component = Container::Horizontal({
|
||||
Container::Vertical({
|
||||
set_export_voltage_current,
|
||||
set_import_voltage_current,
|
||||
export_voltage_input,
|
||||
export_current_input,
|
||||
import_voltage_input,
|
||||
import_current_input,
|
||||
}),
|
||||
});
|
||||
|
||||
auto voltage_current_component_renderer = Renderer(voltage_current_component, [&] {
|
||||
return vbox({hbox(set_export_voltage_current->Render()),
|
||||
hbox(text(" Export voltage (V): "), export_voltage_input->Render()),
|
||||
hbox(text(" Export current (A): "), export_current_input->Render()),
|
||||
hbox(set_import_voltage_current->Render()),
|
||||
hbox(text(" Import voltage (V): "), import_voltage_input->Render()),
|
||||
hbox(text(" Import current (A): "), import_current_input->Render())});
|
||||
});
|
||||
|
||||
auto voltage_current_renderer = Renderer(voltage_current_component, [&] {
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Voltage/Current Setting"), voltage_current_component_renderer->Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vars
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto vars_renderer = Renderer([&] {
|
||||
Element last_command_element = text("Last command: " + last_command);
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
table_content = {
|
||||
{"Actual voltage", actual_voltage}, {"Actual current", actual_current}, {"Actual mode", actual_mode}};
|
||||
}
|
||||
auto vars = Table(table_content);
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Information"), vbox({text("Last command: " + last_command), vars.Render()})),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Capabilities
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto caps_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> caps_table_content;
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
caps_table_content = to_string(raw_caps);
|
||||
}
|
||||
auto caps = Table(caps_table_content);
|
||||
|
||||
caps.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < caps_table_content.size(); i++) {
|
||||
caps.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Capabilities"), caps.Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Horizontal(
|
||||
{voltage_current_renderer, mode_renderer, Container::Vertical({caps_renderer, vars_renderer})});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox({
|
||||
text("Power Supply DC Bringup") | bold | hcenter,
|
||||
main_container->Render(),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUPOWER_SUPPLY_DC_HPP
|
||||
#define BUPOWER_SUPPLY_DC_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/power_supply_DC/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUPowerSupplyDC : public Everest::ModuleBase {
|
||||
public:
|
||||
BUPowerSupplyDC() = delete;
|
||||
BUPowerSupplyDC(const ModuleInfo& info, std::unique_ptr<power_supply_DCIntf> r_psu, Conf& config) :
|
||||
ModuleBase(info), r_psu(std::move(r_psu)), config(config){};
|
||||
|
||||
const std::unique_ptr<power_supply_DCIntf> r_psu;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::mutex data_mutex;
|
||||
types::power_supply_DC::Capabilities raw_caps;
|
||||
std::string actual_voltage;
|
||||
std::string actual_current;
|
||||
std::string actual_mode;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUPOWER_SUPPLY_DC_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for power supply DC interface
|
||||
requires:
|
||||
psu:
|
||||
interface: power_supply_DC
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
326
tools/EVerest-main/modules/BringUp/BUPowermeter/BUPowermeter.cpp
Normal file
326
tools/EVerest-main/modules/BringUp/BUPowermeter/BUPowermeter.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "BUPowermeter.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
#include <ranges>
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
namespace module {
|
||||
|
||||
void optional_add(std::vector<std::vector<std::string>>& table, std::string text, std::string s_value) {
|
||||
table.push_back({text, s_value});
|
||||
}
|
||||
|
||||
void optional_add(std::vector<std::vector<std::string>>& table, std::string text, std::optional<float> o_value) {
|
||||
if (o_value.has_value()) {
|
||||
table.push_back({text, std::to_string(o_value.value())});
|
||||
}
|
||||
}
|
||||
|
||||
void optional_add(std::vector<std::vector<std::string>>& table, std::string text, std::optional<std::string> o_value) {
|
||||
if (o_value.has_value()) {
|
||||
table.push_back({text, o_value.value()});
|
||||
}
|
||||
}
|
||||
|
||||
void BUPowermeter::init() {
|
||||
}
|
||||
|
||||
// Helper function to wrap long text into multiple lines
|
||||
std::vector<std::string> WrapText(const std::string& text, size_t max_width) {
|
||||
std::vector<std::string> lines;
|
||||
size_t start = 0;
|
||||
|
||||
if (max_width < text.size()) {
|
||||
while (start < text.size()) {
|
||||
size_t end = std::min(start + max_width, text.size());
|
||||
size_t last_space = text.rfind(' ', end);
|
||||
|
||||
// If there's no space, split at max_width
|
||||
if (last_space == std::string::npos || last_space < start) {
|
||||
lines.push_back(text.substr(start, max_width));
|
||||
start += max_width;
|
||||
} else {
|
||||
lines.push_back(text.substr(start, last_space - start));
|
||||
start = last_space + 1; // Skip the space
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lines.push_back(text);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
// Helper function to transform text strings into FTXUI Elements
|
||||
std::vector<Element> WrapTextToElements(const std::vector<std::string>& strings) {
|
||||
std::vector<Element> elements;
|
||||
elements.reserve(strings.size()); // Preallocate memory
|
||||
|
||||
// Use std::transform to convert strings to FTXUI elements
|
||||
std::transform(strings.begin(), strings.end(), std::back_inserter(elements),
|
||||
[](const std::string& line) { return text(line); } // Convert each string to FTXUI text
|
||||
);
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
// Helper function to format and render the table content
|
||||
std::vector<std::vector<Element>> FormatTableContent(const std::vector<std::vector<std::string>>& raw_table_content,
|
||||
size_t max_width) {
|
||||
std::vector<std::vector<Element>> table_elements;
|
||||
|
||||
for (const auto& row : raw_table_content) {
|
||||
std::vector<Element> formatted_row;
|
||||
|
||||
for (const auto& cell : row) {
|
||||
// Wrap long strings into multiple lines
|
||||
std::vector<std::string> wrapped_lines = WrapText(cell, max_width);
|
||||
|
||||
// Convert wrapped lines into FTXUI text elements
|
||||
auto cell_element = vbox(WrapTextToElements(wrapped_lines));
|
||||
|
||||
formatted_row.push_back(cell_element);
|
||||
}
|
||||
|
||||
table_elements.push_back(std::move(formatted_row));
|
||||
}
|
||||
|
||||
return table_elements;
|
||||
}
|
||||
|
||||
void BUPowermeter::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_powermeter->subscribe_public_key_ocmf([this, &screen](std::string pk) {
|
||||
public_key = pk;
|
||||
last_event_received = event_received;
|
||||
event_received = std::chrono::steady_clock::now();
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_powermeter->subscribe_powermeter([this, &screen](types::powermeter::Powermeter pm) {
|
||||
powermeter = pm;
|
||||
last_event_received = event_received;
|
||||
event_received = std::chrono::steady_clock::now();
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Commands that can be sent over Powermeter interface
|
||||
// ---------------------------------------------------------------------------
|
||||
Component start_transaction_button = Button(
|
||||
"Start transaction",
|
||||
[&] {
|
||||
types::powermeter::OCMFUserIdentificationStatus
|
||||
identification_status; ///< OCMF Identification Status (IS): General status for user assignment
|
||||
std::vector<types::powermeter::OCMFIdentificationFlags>
|
||||
identification_flags; ///< OCMF Identification Flags (IF): Detailed statements about the user
|
||||
///< assignment, represented by one or more identifiers
|
||||
types::powermeter::OCMFIdentificationType
|
||||
identification_type; ///< OCMF Identification Type (IT): Type of identification data
|
||||
std::optional<types::powermeter::OCMFIdentificationLevel>
|
||||
identification_level; ///< OCMF Identification Level (IL): Encoded overall status of the user assignment
|
||||
std::optional<std::string>
|
||||
identification_data; ///< OCMF Identification Data (ID): The actual identification data e.g. a hex-coded
|
||||
///< UID according to ISO 14443.
|
||||
std::optional<std::string> tariff_text; ///< Tariff text
|
||||
|
||||
last_command = "Start transaction";
|
||||
last_command_duration = "";
|
||||
screen.Post(Event::Custom);
|
||||
types::powermeter::TransactionReq tr;
|
||||
tr.evse_id = config.evse_id;
|
||||
tr.transaction_id = config.transaction_id;
|
||||
tr.identification_status = types::powermeter::OCMFUserIdentificationStatus::ASSIGNED;
|
||||
tr.identification_type = types::powermeter::OCMFIdentificationType::ISO14443;
|
||||
tr.identification_data = config.identification_data;
|
||||
tr.tariff_text = config.tariff_text;
|
||||
|
||||
auto now_b = std::chrono::steady_clock::now();
|
||||
tr_start = r_powermeter->call_start_transaction(tr);
|
||||
auto now_e = std::chrono::steady_clock::now();
|
||||
last_command_duration =
|
||||
fmt::format("{} ms", std::chrono::duration_cast<std::chrono::milliseconds>(now_e - now_b).count());
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component stop_transaction_button = Button(
|
||||
"Stop transaction",
|
||||
[&] {
|
||||
last_command = "Stop transaction";
|
||||
std::string transaction_id = config.transaction_id;
|
||||
auto now_b = std::chrono::steady_clock::now();
|
||||
tr_stop = r_powermeter->call_stop_transaction(transaction_id);
|
||||
auto now_e = std::chrono::steady_clock::now();
|
||||
last_command_duration =
|
||||
fmt::format("{} ms", std::chrono::duration_cast<std::chrono::milliseconds>(now_e - now_b).count());
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component stop_transaction0_button = Button(
|
||||
"Stop transaction empty",
|
||||
[&] {
|
||||
last_command = "Stop transaction";
|
||||
std::string transaction_id = "";
|
||||
auto now_b = std::chrono::steady_clock::now();
|
||||
tr_stop = r_powermeter->call_stop_transaction(transaction_id);
|
||||
auto now_e = std::chrono::steady_clock::now();
|
||||
last_command_duration =
|
||||
fmt::format("{} ms", std::chrono::duration_cast<std::chrono::milliseconds>(now_e - now_b).count());
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component stop_transaction1_button = Button(
|
||||
"Stop transaction dummy",
|
||||
[&] {
|
||||
last_command = "Stop transaction";
|
||||
std::string transaction_id = "DUMMY";
|
||||
auto now_b = std::chrono::steady_clock::now();
|
||||
tr_stop = r_powermeter->call_stop_transaction(transaction_id);
|
||||
auto now_e = std::chrono::steady_clock::now();
|
||||
last_command_duration =
|
||||
fmt::format("{} ms", std::chrono::duration_cast<std::chrono::milliseconds>(now_e - now_b).count());
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto cmds_component = Container::Horizontal({
|
||||
start_transaction_button,
|
||||
stop_transaction_button,
|
||||
stop_transaction0_button,
|
||||
stop_transaction1_button,
|
||||
});
|
||||
|
||||
auto cmds_renderer = Renderer(cmds_component, [&] {
|
||||
auto cmds_win = window(text("Commands"), cmds_component->Render());
|
||||
return vbox({
|
||||
hbox({cmds_win}) | center,
|
||||
separator(),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vars
|
||||
// ---------------------------------------------------------------------------
|
||||
auto vars_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
auto last_event_duration = fmt::format(
|
||||
"{} ms",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(event_received - last_event_received).count());
|
||||
types::units::Energy ed = {};
|
||||
types::units::Power pd = {};
|
||||
types::units::Voltage vd = {};
|
||||
types::units_signed::SignedMeterValue svd = {};
|
||||
types::units::Current cd = {};
|
||||
types::units::Frequency fd = {};
|
||||
|
||||
optional_add(table_content, "Transaction start response: status",
|
||||
types::powermeter::transaction_request_status_to_string(tr_start.status));
|
||||
optional_add(table_content, "Transaction start response: error", tr_start.error);
|
||||
optional_add(table_content, "Transaction start response: transaction_min_stop_time",
|
||||
tr_start.transaction_min_stop_time);
|
||||
optional_add(table_content, "Transaction start response: transaction_max_stop_time",
|
||||
tr_start.transaction_max_stop_time);
|
||||
optional_add(table_content, "Transaction stop response: status",
|
||||
types::powermeter::transaction_request_status_to_string(tr_stop.status));
|
||||
optional_add(table_content, "Transaction stop response: error", tr_stop.error);
|
||||
optional_add(table_content, "Transaction stop response: signed_meter_value",
|
||||
tr_stop.signed_meter_value.value_or(svd).signed_meter_data);
|
||||
if (powermeter.signed_meter_value.has_value()) {
|
||||
optional_add(table_content, "Powermeter: signed meter value",
|
||||
powermeter.signed_meter_value.value().signed_meter_data);
|
||||
optional_add(table_content, "Powermeter: signing method",
|
||||
powermeter.signed_meter_value.value().signing_method);
|
||||
optional_add(table_content, "Powermeter: encoding method",
|
||||
powermeter.signed_meter_value.value().encoding_method);
|
||||
optional_add(table_content, "Powermeter: public key", powermeter.signed_meter_value.value().public_key);
|
||||
}
|
||||
optional_add(table_content, "Powermeter: time stamp", powermeter.timestamp);
|
||||
if (powermeter.temperatures.has_value()) {
|
||||
int i = 1;
|
||||
for (const auto& sensor : *powermeter.temperatures) {
|
||||
std::string label = "Temperature sensor" + std::to_string(i++);
|
||||
optional_add(table_content, label, sensor.temperature);
|
||||
}
|
||||
}
|
||||
|
||||
optional_add(table_content, "Powermeter: imported energy in Wh (from grid), total",
|
||||
std::to_string(powermeter.energy_Wh_import.total));
|
||||
optional_add(table_content, "Powermeter: imported energy in Wh (from grid): L1",
|
||||
powermeter.energy_Wh_import.L1);
|
||||
optional_add(table_content, "Powermeter: imported energy in Wh (from grid): L2",
|
||||
powermeter.energy_Wh_import.L2);
|
||||
optional_add(table_content, "Powermeter: imported energy in Wh (from grid): L3",
|
||||
powermeter.energy_Wh_import.L3);
|
||||
|
||||
optional_add(table_content, "Powermeter: exported energy in Wh (to grid), total",
|
||||
std::to_string(powermeter.energy_Wh_export.value_or(ed).total));
|
||||
optional_add(table_content, "Powermeter: exported energy in Wh (to grid): L1",
|
||||
powermeter.energy_Wh_export.value_or(ed).L1);
|
||||
optional_add(table_content, "Powermeter: exported energy in Wh (to grid): L2",
|
||||
powermeter.energy_Wh_export.value_or(ed).L2);
|
||||
optional_add(table_content, "Powermeter: exported energy in Wh (to grid): L3",
|
||||
powermeter.energy_Wh_export.value_or(ed).L3);
|
||||
|
||||
optional_add(table_content, "Powermeter: user defined meter ID", powermeter.meter_id);
|
||||
optional_add(table_content, "Powermeter: 3 phase rotation error (ccw)", powermeter.phase_seq_error);
|
||||
|
||||
optional_add(table_content, "Powermeter: voltage in V, DC", powermeter.voltage_V.value_or(vd).DC);
|
||||
optional_add(table_content, "Powermeter: voltage in V: L1", powermeter.voltage_V.value_or(vd).L1);
|
||||
optional_add(table_content, "Powermeter: voltage in V: L2", powermeter.voltage_V.value_or(vd).L2);
|
||||
optional_add(table_content, "Powermeter: voltage in V: L3", powermeter.voltage_V.value_or(vd).L3);
|
||||
optional_add(table_content, "Powermeter: current in A, DC", powermeter.current_A.value_or(cd).DC);
|
||||
optional_add(table_content, "Powermeter: current in A: L1", powermeter.current_A.value_or(cd).L1);
|
||||
optional_add(table_content, "Powermeter: current in A: L2", powermeter.current_A.value_or(cd).L2);
|
||||
optional_add(table_content, "Powermeter: current in A: L3", powermeter.current_A.value_or(cd).L3);
|
||||
optional_add(table_content, "Powermeter: frequency in Hz: L1", powermeter.frequency_Hz.value_or(fd).L1);
|
||||
optional_add(table_content, "Powermeter: frequency in Hz: L2", powermeter.frequency_Hz.value_or(fd).L2);
|
||||
optional_add(table_content, "Powermeter: frequency in Hz: L3", powermeter.frequency_Hz.value_or(fd).L3);
|
||||
int i = 1;
|
||||
for (const auto& sensor : *powermeter.temperatures) {
|
||||
std::string label = "Temperature sensor" + std::to_string(i++);
|
||||
optional_add(table_content, label, sensor.temperature);
|
||||
}
|
||||
optional_add(table_content, "Public key", public_key);
|
||||
|
||||
size_t max_width = 120;
|
||||
auto formatted_content = FormatTableContent(table_content, max_width);
|
||||
auto vars = Table(std::move(formatted_content));
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Information"),
|
||||
vbox({text("Last command: " + last_command),
|
||||
text("Last command duration: " + last_command_duration),
|
||||
text("Time between events: " + last_event_duration), vars.Render()})),
|
||||
}) | center,
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Vertical({
|
||||
cmds_renderer,
|
||||
vars_renderer,
|
||||
});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox({
|
||||
text("Powermeter Component") | bold | hcenter,
|
||||
main_container->Render(),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUPOWERMETER_HPP
|
||||
#define BUPOWERMETER_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/powermeter/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string evse_id;
|
||||
std::string transaction_id;
|
||||
std::string identification_data;
|
||||
std::string tariff_text;
|
||||
};
|
||||
|
||||
class BUPowermeter : public Everest::ModuleBase {
|
||||
public:
|
||||
BUPowermeter() = delete;
|
||||
BUPowermeter(const ModuleInfo& info, std::unique_ptr<powermeterIntf> r_powermeter, Conf& config) :
|
||||
ModuleBase(info), r_powermeter(std::move(r_powermeter)), config(config){};
|
||||
|
||||
const std::unique_ptr<powermeterIntf> r_powermeter;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::string last_command;
|
||||
std::string last_command_duration;
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_event_received;
|
||||
std::chrono::time_point<std::chrono::steady_clock> event_received;
|
||||
std::string public_key;
|
||||
types::powermeter::Powermeter powermeter;
|
||||
types::powermeter::TransactionStartResponse tr_start;
|
||||
types::powermeter::TransactionStopResponse tr_stop;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUPOWERMETER_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,25 @@
|
||||
description: Interactive bring up helper for Powermeter interface
|
||||
config:
|
||||
evse_id:
|
||||
description: "Id of this EVSE"
|
||||
type: string
|
||||
default: "EVSE_ID"
|
||||
transaction_id:
|
||||
description: "OCPP transaction UUID"
|
||||
type: string
|
||||
default: "12345678-1234-5678-1234-567812345678"
|
||||
identification_data:
|
||||
description: "User identification means, e.g. RFID card ID"
|
||||
type: string
|
||||
default: "A1B2C3D4E5F6"
|
||||
tariff_text:
|
||||
description: "Tariff Text"
|
||||
type: string
|
||||
default: "custom"
|
||||
requires:
|
||||
powermeter:
|
||||
interface: powermeter
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Florin Mihut
|
||||
145
tools/EVerest-main/modules/BringUp/BUSlac/BUSlac.cpp
Normal file
145
tools/EVerest-main/modules/BringUp/BUSlac/BUSlac.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "BUSlac.hpp"
|
||||
|
||||
#include "ftxui/dom/table.hpp"
|
||||
#include <ftxui/component/component.hpp>
|
||||
#include <ftxui/component/screen_interactive.hpp>
|
||||
#include <ftxui/dom/elements.hpp>
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
namespace module {
|
||||
|
||||
void BUSlac::init() {
|
||||
}
|
||||
|
||||
void BUSlac::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_slac->subscribe_state([this, &screen](const types::slac::State new_state) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
state = types::slac::state_to_string(new_state);
|
||||
}
|
||||
screen.PostEvent(Event::Custom);
|
||||
});
|
||||
|
||||
r_slac->subscribe_dlink_ready([this, &screen](const bool& is_ready) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
dlink = is_ready ? "true" : "false";
|
||||
}
|
||||
screen.PostEvent(Event::Custom);
|
||||
});
|
||||
|
||||
r_slac->subscribe_request_error_routine([this, &screen]() {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
last_request_error_routine_timestamp = std::to_string(
|
||||
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
|
||||
.count());
|
||||
}
|
||||
screen.PostEvent(Event::Custom);
|
||||
});
|
||||
|
||||
r_slac->subscribe_ev_mac_address([this, &screen](const std::string& mac) {
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
ev_mac_address = mac;
|
||||
}
|
||||
screen.PostEvent(Event::Custom);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Left column (Var Display)
|
||||
// -------------------------------------------------------------------
|
||||
auto data_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
table_content = {
|
||||
{"State", state},
|
||||
{"DLink Ready", dlink},
|
||||
{"Last Request Error Routine", last_request_error_routine_timestamp},
|
||||
{"EV MAC Address", ev_mac_address},
|
||||
};
|
||||
}
|
||||
|
||||
auto table = Table(table_content);
|
||||
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < (int)table_content.size(); ++i)
|
||||
table.SelectRow(i).Border(LIGHT);
|
||||
|
||||
return vbox({
|
||||
window(text("Module Data"), vbox({
|
||||
table.Render(),
|
||||
})) |
|
||||
size(WIDTH, EQUAL, 40),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Right column (Command Buttons)
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
auto button_start_slac = Button("Start SLAC", [&] { r_slac->call_reset(true); });
|
||||
auto button_stop_slac = Button("Stop SLAC", [&] { r_slac->call_reset(false); });
|
||||
auto button_enter_bcd = Button("Enter BCD", [&] { r_slac->call_enter_bcd(); });
|
||||
auto button_leave_bcd = Button("Leave BCD", [&] { r_slac->call_leave_bcd(); });
|
||||
auto button_dlink_terminate = Button("DLink Terminate", [&] { r_slac->call_dlink_terminate(); });
|
||||
auto button_dlink_error = Button("DLink Error", [&] { r_slac->call_dlink_error(); });
|
||||
auto button_dlink_pause = Button("DLink Pause", [&] { r_slac->call_dlink_pause(); });
|
||||
|
||||
// Compose the command panel layout
|
||||
auto command_container = Container::Vertical({
|
||||
Container::Horizontal({button_start_slac, button_stop_slac}),
|
||||
button_enter_bcd,
|
||||
button_leave_bcd,
|
||||
button_dlink_terminate,
|
||||
button_dlink_error,
|
||||
button_dlink_pause,
|
||||
});
|
||||
|
||||
auto command_renderer = Renderer(command_container, [&] {
|
||||
return vbox({
|
||||
text("Commands") | bold | center,
|
||||
separator(),
|
||||
button_start_slac->Render(),
|
||||
button_stop_slac->Render(),
|
||||
button_enter_bcd->Render(),
|
||||
button_leave_bcd->Render(),
|
||||
button_dlink_terminate->Render(),
|
||||
button_dlink_error->Render(),
|
||||
button_dlink_pause->Render(),
|
||||
}) |
|
||||
border | size(WIDTH, EQUAL, 40);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Combine columns
|
||||
// -------------------------------------------------------------------
|
||||
auto layout = Container::Horizontal({
|
||||
data_renderer,
|
||||
command_renderer,
|
||||
});
|
||||
|
||||
auto main_renderer = Renderer(layout, [&] {
|
||||
return vbox({
|
||||
text("SLAC BringUp") | bold | center,
|
||||
separator(),
|
||||
hbox({
|
||||
data_renderer->Render(),
|
||||
command_renderer->Render(),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
63
tools/EVerest-main/modules/BringUp/BUSlac/BUSlac.hpp
Normal file
63
tools/EVerest-main/modules/BringUp/BUSlac/BUSlac.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUSLAC_HPP
|
||||
#define BUSLAC_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/slac/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUSlac : public Everest::ModuleBase {
|
||||
public:
|
||||
BUSlac() = delete;
|
||||
BUSlac(const ModuleInfo& info, std::unique_ptr<slacIntf> r_slac, Conf& config) :
|
||||
ModuleBase(info), r_slac(std::move(r_slac)), config(config){};
|
||||
|
||||
const std::unique_ptr<slacIntf> r_slac;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::mutex data_mutex;
|
||||
std::string state;
|
||||
std::string dlink;
|
||||
std::string last_request_error_routine_timestamp;
|
||||
std::string ev_mac_address;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUSLAC_HPP
|
||||
21
tools/EVerest-main/modules/BringUp/BUSlac/CMakeLists.txt
Normal file
21
tools/EVerest-main/modules/BringUp/BUSlac/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
8
tools/EVerest-main/modules/BringUp/BUSlac/manifest.yaml
Normal file
8
tools/EVerest-main/modules/BringUp/BUSlac/manifest.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for SLAC interface
|
||||
requires:
|
||||
slac:
|
||||
interface: slac
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Piet Gömpel
|
||||
202
tools/EVerest-main/modules/BringUp/BUSystem/BUSystem.cpp
Normal file
202
tools/EVerest-main/modules/BringUp/BUSystem/BUSystem.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "BUSystem.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
namespace module {
|
||||
|
||||
void BUSystem::init() {
|
||||
}
|
||||
|
||||
void BUSystem::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_system->subscribe_firmware_update_status([this, &screen](const types::system::FirmwareUpdateStatus fus) {
|
||||
firmware_update_status = types::system::firmware_update_status_enum_to_string(fus.firmware_update_status);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
r_system->subscribe_log_status([this, &screen](const types::system::LogStatus ls) {
|
||||
log_status = types::system::log_status_enum_to_string(ls.log_status);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Commands that can be sent over System interface
|
||||
// ---------------------------------------------------------------------------
|
||||
Component allow_firmware_installation_button = Button(
|
||||
"Allow update",
|
||||
[&] {
|
||||
last_command = "Allow update";
|
||||
r_system->call_allow_firmware_installation();
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component get_reset_allowed_button = Button(
|
||||
"Is reset allowed",
|
||||
[&] {
|
||||
last_command = "Is reset allowed";
|
||||
auto allowed = r_system->call_is_reset_allowed(types::system::ResetType::Soft);
|
||||
is_reset_allowed = (allowed) ? "true" : "false";
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component reset_button = Button(
|
||||
"Reset",
|
||||
[&] {
|
||||
last_command = "Reset";
|
||||
types::system::ResetType type = types::system::ResetType::Soft;
|
||||
bool scheduled = false;
|
||||
r_system->call_reset(type, scheduled);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
Component get_boot_reason_button = Button(
|
||||
"Get boot reason",
|
||||
[&] {
|
||||
last_command = "Get boot reason";
|
||||
auto reason = r_system->call_get_boot_reason();
|
||||
boot_reason = types::system::boot_reason_to_string(reason);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto cmds_component = Container::Horizontal({
|
||||
allow_firmware_installation_button,
|
||||
get_reset_allowed_button,
|
||||
reset_button,
|
||||
get_boot_reason_button,
|
||||
});
|
||||
|
||||
auto cmds_renderer = Renderer(cmds_component, [&] {
|
||||
auto cmds_win = window(text("Commands"), cmds_component->Render());
|
||||
return vbox({
|
||||
hbox({cmds_win}) | center,
|
||||
separator(),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto log_location = Input(&log_upload_location, "Upload location");
|
||||
Component log_button = Button(
|
||||
"Upload logs",
|
||||
[&] {
|
||||
last_command = "Upload logs";
|
||||
types::system::UploadLogsRequest ulr;
|
||||
ulr.location = log_upload_location;
|
||||
ulr.retries = 1;
|
||||
ulr.retry_interval_s = 1;
|
||||
auto result = r_system->call_upload_logs(ulr);
|
||||
upload_logs_status =
|
||||
fmt::format("Upload status:{}", upload_logs_status_to_string(result.upload_logs_status));
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
|
||||
auto log_container = Container::Horizontal({
|
||||
log_location,
|
||||
log_button,
|
||||
});
|
||||
|
||||
auto input_log_renderer = Renderer(log_container, [&] {
|
||||
return vbox({
|
||||
hbox(text(" Upload logs URL : "), log_location->Render(), log_button->Render()),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto input_time = Input(&new_system_time, "New system time in RFC3339 format");
|
||||
Component time_button = Button(
|
||||
"Set system time",
|
||||
[&] {
|
||||
auto result = r_system->call_set_system_time(new_system_time);
|
||||
last_command = (result) ? "Set system time - successful" : "Set system time - unsuccessful";
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
auto input_time_container = Container::Horizontal({
|
||||
input_time,
|
||||
time_button,
|
||||
});
|
||||
|
||||
auto input_time_renderer = Renderer(input_time_container, [&] {
|
||||
return vbox({
|
||||
hbox(text(" New system time : "), input_time->Render(), time_button->Render()),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto input_address = Input(&firmware_update_url, "URL where to take the update from");
|
||||
Component update_button = Button(
|
||||
"Update firmware",
|
||||
[&] {
|
||||
last_command = "Update";
|
||||
types::system::FirmwareUpdateRequest fur;
|
||||
fur.request_id = 1;
|
||||
fur.location = firmware_update_url;
|
||||
auto result = r_system->call_update_firmware(fur);
|
||||
update_firmware_response = update_firmware_response_to_string(result);
|
||||
},
|
||||
ButtonOption::Animated(Color::Blue, Color::White, Color::RedLight, Color::White));
|
||||
auto input_container = Container::Horizontal({
|
||||
input_address,
|
||||
update_button,
|
||||
});
|
||||
|
||||
auto input_renderer = Renderer(input_container, [&] {
|
||||
return vbox({
|
||||
hbox(text(" URL of the update : "), input_address->Render(), update_button->Render()),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vars
|
||||
// ---------------------------------------------------------------------------
|
||||
auto vars_renderer = Renderer([&] {
|
||||
Element last_command_element = text("Last command: " + last_command);
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
{
|
||||
// std::scoped_lock lock(data_mutex);
|
||||
table_content = {{"Firmware update status", firmware_update_status},
|
||||
{"Firmware update response", update_firmware_response},
|
||||
{"Get boot reason", boot_reason},
|
||||
{"Upload log status", upload_logs_status},
|
||||
{"Log status", log_status},
|
||||
{"Is reset allowed", is_reset_allowed}};
|
||||
}
|
||||
auto vars = Table(table_content);
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Information"), vbox({text("Last command: " + last_command), vars.Render()})),
|
||||
}) | center,
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Vertical({
|
||||
input_renderer,
|
||||
input_time_renderer,
|
||||
input_log_renderer,
|
||||
cmds_renderer,
|
||||
vars_renderer,
|
||||
});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox({
|
||||
text("System Component") | bold | hcenter,
|
||||
main_container->Render(),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
68
tools/EVerest-main/modules/BringUp/BUSystem/BUSystem.hpp
Normal file
68
tools/EVerest-main/modules/BringUp/BUSystem/BUSystem.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUSYSTEM_HPP
|
||||
#define BUSYSTEM_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/system/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUSystem : public Everest::ModuleBase {
|
||||
public:
|
||||
BUSystem() = delete;
|
||||
BUSystem(const ModuleInfo& info, std::unique_ptr<systemIntf> r_system, Conf& config) :
|
||||
ModuleBase(info), r_system(std::move(r_system)), config(config){};
|
||||
|
||||
const std::unique_ptr<systemIntf> r_system;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::string last_command;
|
||||
std::string firmware_update_status;
|
||||
std::string log_status;
|
||||
std::string is_reset_allowed;
|
||||
std::string boot_reason;
|
||||
std::string firmware_update_url;
|
||||
std::string new_system_time;
|
||||
std::string log_upload_location;
|
||||
std::string upload_logs_status;
|
||||
std::string update_firmware_response;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUSYSTEM_HPP
|
||||
21
tools/EVerest-main/modules/BringUp/BUSystem/CMakeLists.txt
Normal file
21
tools/EVerest-main/modules/BringUp/BUSystem/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for System component
|
||||
requires:
|
||||
system:
|
||||
interface: system
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Florin Mihut
|
||||
@@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "BUTokenProvider.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/table.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
static std::vector<std::vector<std::string>> to_table(types::authorization::ProvidedIdToken t) {
|
||||
std::vector<std::vector<std::string>> token;
|
||||
token.push_back({"Protocol", fmt::format("{}:", id_token_type_to_string(t.id_token.type))});
|
||||
token.push_back({"UID", fmt::format("{}", t.id_token.value)});
|
||||
|
||||
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
std::tm* p_tm = std::localtime(&now);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(p_tm, "%Y-%m-%d %H:%M:%S");
|
||||
|
||||
token.push_back({"Timestamp", oss.str()});
|
||||
return token;
|
||||
}
|
||||
|
||||
void BUTokenProvider::init() {
|
||||
types::authorization::ProvidedIdToken t;
|
||||
t.id_token.type = types::authorization::IdTokenType::NoAuthorization;
|
||||
t.id_token.value = std::string("0");
|
||||
last_token = to_table(t);
|
||||
}
|
||||
|
||||
void BUTokenProvider::ready() {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
r_token_provider->subscribe_provided_token([this, &screen](const types::authorization::ProvidedIdToken t) {
|
||||
std::scoped_lock lock(data_mutex);
|
||||
last_token = to_table(t);
|
||||
screen.Post(Event::Custom);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vars
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
auto vars_renderer = Renderer([&] {
|
||||
std::vector<std::vector<std::string>> table_content;
|
||||
{
|
||||
std::scoped_lock lock(data_mutex);
|
||||
table_content = last_token;
|
||||
}
|
||||
auto vars = Table(table_content);
|
||||
|
||||
vars.SelectColumn(0).Border(LIGHT);
|
||||
for (int i = 0; i < table_content.size(); i++) {
|
||||
vars.SelectRow(i).Border(LIGHT);
|
||||
}
|
||||
return vbox({
|
||||
hbox({
|
||||
window(text("Information"), vars.Render()),
|
||||
}),
|
||||
}) |
|
||||
flex_grow;
|
||||
});
|
||||
|
||||
auto main_container = Container::Horizontal({
|
||||
vars_renderer,
|
||||
});
|
||||
|
||||
auto main_renderer = Renderer(main_container, [&] {
|
||||
return vbox({
|
||||
text("NFC Token Provider") | bold | hcenter,
|
||||
main_container->Render(),
|
||||
});
|
||||
});
|
||||
|
||||
screen.Loop(main_renderer);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BUTOKEN_PROVIDER_HPP
|
||||
#define BUTOKEN_PROVIDER_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/auth_token_provider/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class BUTokenProvider : public Everest::ModuleBase {
|
||||
public:
|
||||
BUTokenProvider() = delete;
|
||||
BUTokenProvider(const ModuleInfo& info, std::unique_ptr<auth_token_providerIntf> r_token_provider, Conf& config) :
|
||||
ModuleBase(info), r_token_provider(std::move(r_token_provider)), config(config){};
|
||||
|
||||
const std::unique_ptr<auth_token_providerIntf> r_token_provider;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::mutex data_mutex;
|
||||
std::vector<std::vector<std::string>> last_token;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BUTOKEN_PROVIDER_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE ftxui::screen
|
||||
PRIVATE ftxui::dom
|
||||
PRIVATE ftxui::component
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Interactive bring up helper for Token Provider interface
|
||||
requires:
|
||||
token_provider:
|
||||
interface: auth_token_provider
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Christoph Burandt
|
||||
15
tools/EVerest-main/modules/BringUp/CMakeLists.txt
Normal file
15
tools/EVerest-main/modules/BringUp/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
if (NOT ftxui_FOUND AND NOT DEFINED ftxui_SOURCE_DIR)
|
||||
message(WARNING "Not building BringUp modules because dependency ftxui is not available")
|
||||
else()
|
||||
ev_add_module(BUDCExternalDerate)
|
||||
ev_add_module(BUDisplayMessage)
|
||||
ev_add_module(BUEvseBoardSupport)
|
||||
ev_add_module(BUIsolationMonitor)
|
||||
ev_add_module(BUOcppConsumer)
|
||||
ev_add_module(BUOverVoltageMonitor)
|
||||
ev_add_module(BUPowerSupplyDC)
|
||||
ev_add_module(BUPowermeter)
|
||||
ev_add_module(BUSlac)
|
||||
ev_add_module(BUSystem)
|
||||
ev_add_module(BUTokenProvider)
|
||||
endif()
|
||||
Reference in New Issue
Block a user