-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add simple EvAPI and extend EvManager with simplistic SoC calculation #891
base: main
Are you sure you want to change the base?
Changes from 15 commits
b7a727d
5fcc16b
feeb598
921a7f7
ed02b39
3a919b2
fad56c4
038a90e
59bc9b9
5e9a275
eb4f634
81a79d8
d7a67ae
fcf43bf
5060f53
ba781f8
2ec49b9
8bc6ab4
536e8fb
17c9998
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
description: >- | ||
This interface defines the ev manager. An ev manager represents the | ||
charging logic of the ev side | ||
cmds: {} | ||
vars: | ||
bsp_event: | ||
description: >- | ||
Events from CP/Relais | ||
type: object | ||
$ref: /board_support_common#/BspEvent | ||
ev_info: | ||
description: More details about the EV if available | ||
type: object | ||
$ref: /evse_manager#/EVInfo | ||
errors: | ||
- reference: /errors/evse_manager |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1 | ||
|
||
target_sources(${MODULE_NAME} | ||
PRIVATE | ||
"main/emptyImpl.cpp" | ||
) | ||
|
||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 | ||
# insert other things like install cmds etc here | ||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright Pionix GmbH and Contributors to EVerest | ||
#include "EvAPI.hpp" | ||
#include <utils/date.hpp> | ||
|
||
namespace module { | ||
|
||
static const auto NOTIFICATION_PERIOD = std::chrono::seconds(1); | ||
|
||
EvSessionInfo::EvSessionInfo() : state("Unknown") { | ||
} | ||
|
||
void EvSessionInfo::reset() { | ||
std::lock_guard<std::mutex> lock(this->session_info_mutex); | ||
this->state = "Unknown"; | ||
} | ||
|
||
void EvSessionInfo::update_state(const std::string& event) { | ||
std::lock_guard<std::mutex> lock(this->session_info_mutex); | ||
this->state = event; | ||
} | ||
|
||
EvSessionInfo::operator std::string() { | ||
std::lock_guard<std::mutex> lock(this->session_info_mutex); | ||
|
||
auto now = date::utc_clock::now(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be made |
||
|
||
json session_info = json::object({ | ||
{"state", this->state}, | ||
{"datetime", Everest::Date::to_rfc3339(now)}, | ||
}); | ||
|
||
return session_info.dump(); | ||
} | ||
|
||
void EvAPI::init() { | ||
invoke_init(*p_main); | ||
|
||
std::vector<std::string> ev_connectors; | ||
std::string var_ev_connectors = this->api_base + "ev_connectors"; | ||
|
||
for (auto& ev : this->r_ev_manager) { | ||
auto& session_info = this->info.emplace_back(std::make_unique<EvSessionInfo>()); | ||
std::string ev_base = this->api_base + ev->module_id; | ||
ev_connectors.push_back(ev->module_id); | ||
|
||
// API variables | ||
std::string var_base = ev_base + "/var/"; | ||
|
||
std::string var_ev_info = var_base + "ev_info"; | ||
ev->subscribe_ev_info([this, &ev, var_ev_info](types::evse_manager::EVInfo ev_info) { | ||
json ev_info_json = ev_info; | ||
this->mqtt.publish(var_ev_info, ev_info_json.dump()); | ||
}); | ||
|
||
std::string var_session_info = var_base + "session_info"; | ||
ev->subscribe_bsp_event([this, var_session_info, &session_info](const auto& bsp_event) { | ||
session_info->update_state(types::board_support_common::event_to_string(bsp_event.event)); | ||
this->mqtt.publish(var_session_info, *session_info); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it could improve readability if those blocks are refactored to static functions like |
||
|
||
std::string var_datetime = var_base + "datetime"; | ||
this->api_threads.push_back(std::thread([this, var_datetime, var_session_info, &session_info]() { | ||
auto next_tick = std::chrono::steady_clock::now(); | ||
while (this->running) { | ||
std::string datetime_str = Everest::Date::to_rfc3339(date::utc_clock::now()); | ||
this->mqtt.publish(var_datetime, datetime_str); | ||
this->mqtt.publish(var_session_info, *session_info); | ||
|
||
next_tick += NOTIFICATION_PERIOD; | ||
std::this_thread::sleep_until(next_tick); | ||
} | ||
})); | ||
|
||
// API commands | ||
std::string cmd_base = ev_base + "/cmd/"; | ||
} | ||
|
||
this->api_threads.push_back(std::thread([this, var_ev_connectors, ev_connectors]() { | ||
auto next_tick = std::chrono::steady_clock::now(); | ||
while (this->running) { | ||
json ev_connectors_array = ev_connectors; | ||
this->mqtt.publish(var_ev_connectors, ev_connectors_array.dump()); | ||
|
||
next_tick += NOTIFICATION_PERIOD; | ||
std::this_thread::sleep_until(next_tick); | ||
} | ||
})); | ||
} | ||
|
||
void EvAPI::ready() { | ||
invoke_ready(*p_main); | ||
|
||
std::string var_active_errors = this->api_base + "errors/var/active_errors"; | ||
this->api_threads.push_back(std::thread([this, var_active_errors]() { | ||
auto next_tick = std::chrono::steady_clock::now(); | ||
while (this->running) { | ||
std::string datetime_str = Everest::Date::to_rfc3339(date::utc_clock::now()); | ||
|
||
if (not r_error_history.empty()) { | ||
// request active errors | ||
types::error_history::FilterArguments filter; | ||
filter.state_filter = types::error_history::State::Active; | ||
auto active_errors = r_error_history.at(0)->call_get_errors(filter); | ||
json errors_json = json(active_errors); | ||
|
||
// publish | ||
this->mqtt.publish(var_active_errors, errors_json.dump()); | ||
} | ||
next_tick += NOTIFICATION_PERIOD; | ||
std::this_thread::sleep_until(next_tick); | ||
} | ||
})); | ||
} | ||
|
||
} // namespace module |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright Pionix GmbH and Contributors to EVerest | ||
#ifndef EVAPI_HPP | ||
#define EVAPI_HPP | ||
|
||
// | ||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT | ||
// template version 2 | ||
// | ||
|
||
#include "ld-ev.hpp" | ||
|
||
// headers for provided interface implementations | ||
#include <generated/interfaces/empty/Implementation.hpp> | ||
|
||
// headers for required interface implementations | ||
#include <generated/interfaces/error_history/Interface.hpp> | ||
#include <generated/interfaces/ev_manager/Interface.hpp> | ||
|
||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 | ||
// insert your custom include headers here | ||
#include <condition_variable> | ||
#include <list> | ||
#include <memory> | ||
#include <mutex> | ||
#include <sstream> | ||
|
||
#include <date/date.h> | ||
#include <date/tz.h> | ||
|
||
namespace module { | ||
|
||
class LimitDecimalPlaces; | ||
|
||
class EvSessionInfo { | ||
public: | ||
EvSessionInfo(); | ||
|
||
void reset(); | ||
void update_state(const std::string& event); | ||
|
||
/// \brief Converts this struct into a serialized json object | ||
operator std::string(); | ||
|
||
private: | ||
std::mutex session_info_mutex; | ||
std::string state = "Unknown"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think an enum could be preferable here. It would make it clearer what the possible values can be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think, |
||
}; | ||
} // namespace module | ||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 | ||
|
||
namespace module { | ||
|
||
struct Conf {}; | ||
|
||
class EvAPI : public Everest::ModuleBase { | ||
public: | ||
EvAPI() = delete; | ||
EvAPI(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider, std::unique_ptr<emptyImplBase> p_main, | ||
std::vector<std::unique_ptr<ev_managerIntf>> r_ev_manager, | ||
std::vector<std::unique_ptr<error_historyIntf>> r_error_history, Conf& config) : | ||
ModuleBase(info), | ||
mqtt(mqtt_provider), | ||
p_main(std::move(p_main)), | ||
r_ev_manager(std::move(r_ev_manager)), | ||
r_error_history(std::move(r_error_history)), | ||
config(config){}; | ||
|
||
Everest::MqttProvider& mqtt; | ||
const std::unique_ptr<emptyImplBase> p_main; | ||
const std::vector<std::unique_ptr<ev_managerIntf>> r_ev_manager; | ||
const std::vector<std::unique_ptr<error_historyIntf>> r_error_history; | ||
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::vector<std::thread> api_threads; | ||
bool running = true; | ||
|
||
std::list<std::unique_ptr<EvSessionInfo>> info; | ||
|
||
const std::string api_base = "everest_api/"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps make this a |
||
// 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 // EVAPI_HPP |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# EvAPI module documentation | ||
Check notice on line 1 in modules/EvAPI/README.md Codacy Production / Codacy Static Code Analysismodules/EvAPI/README.md#L1
|
||
This module is responsible for providing a simple MQTT based API to EVerest internals exposing EvManager related functionality | ||
Check notice on line 2 in modules/EvAPI/README.md Codacy Production / Codacy Static Code Analysismodules/EvAPI/README.md#L2
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright Pionix GmbH and Contributors to EVerest | ||
|
||
#include "emptyImpl.hpp" | ||
|
||
namespace module { | ||
namespace main { | ||
|
||
void emptyImpl::init() { | ||
} | ||
|
||
void emptyImpl::ready() { | ||
} | ||
|
||
} // namespace main | ||
} // namespace module |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright Pionix GmbH and Contributors to EVerest | ||
#ifndef MAIN_EMPTY_IMPL_HPP | ||
#define MAIN_EMPTY_IMPL_HPP | ||
|
||
// | ||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT | ||
// template version 3 | ||
// | ||
|
||
#include <generated/interfaces/empty/Implementation.hpp> | ||
|
||
#include "../EvAPI.hpp" | ||
|
||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 | ||
// insert your custom include headers here | ||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 | ||
|
||
namespace module { | ||
namespace main { | ||
|
||
struct Conf {}; | ||
|
||
class emptyImpl : public emptyImplBase { | ||
public: | ||
emptyImpl() = delete; | ||
emptyImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<EvAPI>& mod, Conf& config) : | ||
emptyImplBase(ev, "main"), mod(mod), config(config){}; | ||
|
||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1 | ||
// insert your public definitions here | ||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1 | ||
|
||
protected: | ||
// no commands defined for this interface | ||
|
||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1 | ||
// insert your protected definitions here | ||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1 | ||
|
||
private: | ||
const Everest::PtrContainer<EvAPI>& 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 main | ||
} // namespace module | ||
|
||
#endif // MAIN_EMPTY_IMPL_HPP |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
description: >- | ||
The EVerest Ev API module, exposing some internal functionality on an external | ||
MQTT connection. | ||
config: {} | ||
provides: | ||
main: | ||
description: EVerest API | ||
interface: empty | ||
requires: | ||
ev_manager: | ||
interface: ev_manager | ||
min_connections: 1 | ||
max_connections: 128 | ||
error_history: | ||
interface: error_history | ||
min_connections: 0 | ||
max_connections: 1 | ||
enable_external_mqtt: true | ||
metadata: | ||
license: https://opensource.org/licenses/Apache-2.0 | ||
authors: | ||
- Kai-Uwe Hermann |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename
event
here? I think it might be a little bit confusing to call this variable event when it actually represents the state