Skip to content
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

Backend requests #39

Merged
merged 3 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- 'platformio.ini'
- '.github/workflows/tests.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.head_ref || github.ref_name }}
cancel-in-progress: true

jobs:
Expand Down
3 changes: 3 additions & 0 deletions conf/conf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ namespace fabomatic
/// @brief Backend reply (sub-topic of the full machine topic)
static constexpr std::string_view response_topic{"/reply"};

/// @brief Backend requests (sub-topic of the full machine topic)
static constexpr std::string_view request_topic{"/request"};

/// @brief Number of tries to get a reply from the backend
static constexpr auto MAX_TRIES{2};

Expand Down
1 change: 1 addition & 0 deletions include/BoardLogic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ namespace fabomatic
[[nodiscard]] auto getMachine() const -> const Machine &;
[[nodiscard]] auto authorize(const card::uid_t uid) -> bool;
[[nodiscard]] auto getHostname() const -> const std::string;
auto processBackendRequests() -> void;

// copy reference
BoardLogic &operator=(const BoardLogic &board) = delete;
Expand Down
5 changes: 5 additions & 0 deletions include/FabBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ namespace fabomatic

std::string topic{""};
std::string response_topic{""};
std::string request_topic{""};
std::string last_query{""};
std::string last_reply{""};
std::string last_request{""};

bool online{false};
bool answer_pending{false};
Expand All @@ -55,6 +57,7 @@ namespace fabomatic
Buffer buffer;

auto messageReceived(String &topic, String &payload) -> void;
auto requestReceived(String &topic, String &payload) -> void;

template <typename QueryT>
[[nodiscard]] auto publish(const QueryT &payload) -> PublishResult;
Expand Down Expand Up @@ -86,6 +89,8 @@ namespace fabomatic
[[nodiscard]] auto transmitBuffer() -> bool;
[[nodiscard]] auto saveBuffer() -> bool;

[[nodiscard]] auto checkBackendRequest() -> std::optional<std::unique_ptr<MQTTInterface::BackendRequest>>;

auto connect() -> bool;
auto connectWiFi() -> bool;
auto loop() -> bool;
Expand Down
29 changes: 19 additions & 10 deletions include/MQTTtypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace fabomatic::MQTTInterface
const card::uid_t uid;

UserQuery() = delete;
constexpr UserQuery(card::uid_t card_uid) : uid(card_uid){};
constexpr UserQuery(card::uid_t card_uid) : uid(card_uid) {};

[[nodiscard]] auto waitForReply() const -> bool override { return true; };
[[nodiscard]] auto payload() const -> const std::string override;
Expand Down Expand Up @@ -63,7 +63,7 @@ namespace fabomatic::MQTTInterface
const card::uid_t uid;

StartUseQuery() = delete;
constexpr StartUseQuery(card::uid_t card_uid) : uid(card_uid){};
constexpr StartUseQuery(card::uid_t card_uid) : uid(card_uid) {};

[[nodiscard]] auto payload() const -> const std::string override;
[[nodiscard]] auto waitForReply() const -> bool override { return true; };
Expand All @@ -83,7 +83,7 @@ namespace fabomatic::MQTTInterface
/// @param card_uid machine user card id
/// @param mid machine id
/// @param duration duration of usage, in seconds
constexpr StopUseQuery(card::uid_t card_uid, std::chrono::seconds duration) : uid(card_uid), duration_s(duration){};
constexpr StopUseQuery(card::uid_t card_uid, std::chrono::seconds duration) : uid(card_uid), duration_s(duration) {};
[[nodiscard]] auto payload() const -> const std::string override;
[[nodiscard]] auto waitForReply() const -> bool override { return true; };
[[nodiscard]] auto buffered() const -> bool override { return true; };
Expand All @@ -102,7 +102,7 @@ namespace fabomatic::MQTTInterface
/// @param card_uid machine user card id
/// @param mid machine id
/// @param duration duration of usage, in seconds
constexpr InUseQuery(card::uid_t card_uid, std::chrono::seconds duration) : uid(card_uid), duration_s(duration){};
constexpr InUseQuery(card::uid_t card_uid, std::chrono::seconds duration) : uid(card_uid), duration_s(duration) {};
[[nodiscard]] auto payload() const -> const std::string override;
[[nodiscard]] auto waitForReply() const -> bool override { return true; };
[[nodiscard]] auto buffered() const -> bool override { return false; };
Expand All @@ -115,7 +115,7 @@ namespace fabomatic::MQTTInterface
const card::uid_t uid;

RegisterMaintenanceQuery() = delete;
constexpr RegisterMaintenanceQuery(card::uid_t card_uid) : uid(card_uid){};
constexpr RegisterMaintenanceQuery(card::uid_t card_uid) : uid(card_uid) {};

[[nodiscard]] auto payload() const -> const std::string override;
[[nodiscard]] auto waitForReply() const -> bool override { return true; };
Expand All @@ -129,7 +129,7 @@ namespace fabomatic::MQTTInterface
const bool request_ok{false}; /* True if the request was processed by the server */

Response() = delete;
constexpr Response(bool result) : request_ok(result){};
constexpr Response(bool result) : request_ok(result) {};
};

/// @brief Result code for user authentication result
Expand All @@ -150,10 +150,10 @@ namespace fabomatic::MQTTInterface
FabUser::UserLevel user_level{FabUser::UserLevel::Unknown}; /* User priviledges */

UserResponse() = delete;
UserResponse(bool rok) : Response(rok){};
UserResponse(bool rok) : Response(rok) {};

UserResponse(bool rok, UserResult res) : Response(rok),
result(static_cast<uint8_t>(res)){};
result(static_cast<uint8_t>(res)) {};

[[nodiscard]] static auto fromJson(JsonDocument &doc) -> std::unique_ptr<UserResponse>;

Expand All @@ -174,7 +174,7 @@ namespace fabomatic::MQTTInterface
uint16_t grace{0}; /* Grace period in minutes */
std::string description{""}; /* Description of the expired maintenance */
MachineResponse() = delete;
MachineResponse(bool rok) : Response(rok){};
MachineResponse(bool rok) : Response(rok) {};

[[nodiscard]] static auto fromJson(JsonDocument &doc) -> std::unique_ptr<MachineResponse>;
};
Expand All @@ -184,10 +184,19 @@ namespace fabomatic::MQTTInterface
{
public:
SimpleResponse() = delete;
constexpr SimpleResponse(bool rok) : Response(rok){};
constexpr SimpleResponse(bool rok) : Response(rok) {};

[[nodiscard]] static auto fromJson(JsonDocument &doc) -> std::unique_ptr<SimpleResponse>;
};

/// @brief Class for server request
class BackendRequest
{
public:
card::uid_t requester;
std::string request_type;
BackendRequest(const card::uid_t &uid, const std::string &request) : requester{uid}, request_type(request) {};
[[nodiscard]] static auto fromJson(const JsonDocument &doc) -> std::optional<std::unique_ptr<BackendRequest>>;
};
} // namespace fabomatic::MQTTInterface
#endif // MQTTTYPES_HPP_
16 changes: 16 additions & 0 deletions include/card.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ namespace fabomatic::card
return ss.str();
}

/**
* @brief Returns an UID from its string representation
* @param str hex string to convert
* @return uid value
*/
[[nodiscard]] inline auto str_uid(const std::string &str) -> card::uid_t
{
uint64_t ll_value;

std::stringstream ss{};
ss << std::hex << str;
ss >> ll_value;

return ll_value;
}

/**
* @brief Converts a UID from an array of bytes to a number
* @param uid array of bytes
Expand Down
4 changes: 3 additions & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ name = fab-o-matic

[env]
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.08.10/platform-espressif32.zip
#platform =https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
framework = arduino
test_framework = unity
check_tool = clangtidy
Expand All @@ -31,8 +32,9 @@ lib_deps = https://github.com/PBrunot/LiquidCrystal.git#use_const
adafruit/Adafruit NeoPixel@^1.12.3
https://github.com/tzapu/[email protected]
ArduinoOTA
build_unflags = -std=gnu++11 -fexceptions
build_unflags = -std=gnu++11 -fexceptions -fno-lto
build_flags = -std=gnu++2b
-flto=auto
-g3
-Os
-I conf
Expand Down
24 changes: 24 additions & 0 deletions src/BoardLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,4 +652,28 @@ namespace fabomatic
std::to_string(conf::default_config::machine_id.id);
}

auto BoardLogic::processBackendRequests() -> void
{
auto &backend = getServer();
backend.loop();
if (auto result = backend.checkBackendRequest(); result.has_value())
{
const auto &req = result->get();
ESP_LOGI(TAG, "Processing backend request : %s", req->request_type.c_str());
FabUser fu{req->requester, "BACKEND", true, FabUser::UserLevel::FabAdmin};

if (req->request_type == "start")
{
logout();
if (!authorize(fu.card_uid))
{
ESP_LOGE(TAG, "Failure to execute start request from backend");
}
}
if (req->request_type == "stop")
{
logout();
}
}
}
} // namespace fabomatic
62 changes: 55 additions & 7 deletions src/FabBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,23 @@ namespace fabomatic
*/
void FabBackend::messageReceived(String &s_topic, String &s_payload)
{
ESP_LOGI(TAG, "MQTT Client: Received on %s -> %s", s_topic.c_str(), s_payload.c_str());
ESP_LOGI(TAG, "MQTT Client: message received on %s -> %s", s_topic.c_str(), s_payload.c_str());

last_reply.assign(s_payload.c_str());
answer_pending = false;
// Needed for equality test below
std::string_view view_topic{s_topic.c_str()};
if (view_topic == this->response_topic)
{
last_reply.assign(s_payload.c_str());
answer_pending = false;
}
else if (view_topic == this->request_topic)
{
last_request.assign(s_payload.c_str());
}
else if (view_topic != this->topic)
{
ESP_LOGW(TAG, "MQTT Client: unrecognized topic %s", s_topic.c_str());
}
}

/**
Expand Down Expand Up @@ -343,9 +356,9 @@ namespace fabomatic
// Setup subscriptions
if (client.connected())
{
std::stringstream tmp_topic;
tmp_topic << topic << conf::mqtt::response_topic;
response_topic.assign(tmp_topic.str());
std::stringstream ss_resp{};
ss_resp << topic << conf::mqtt::response_topic;
response_topic.assign(ss_resp.str());

if (!client.subscribe(response_topic.c_str()))
{
Expand All @@ -356,6 +369,21 @@ namespace fabomatic
ESP_LOGD(TAG, "MQTT Client: subscribed to reply topic %s", response_topic.c_str());
online = true;
}

std::stringstream ss_req{};
ss_req << topic << conf::mqtt::request_topic;
request_topic.assign(ss_req.str());

if (!client.subscribe(request_topic.c_str()))
{
ESP_LOGE(TAG, "MQTT Client: failure to subscribe to requests topic %s", request_topic.c_str());
}
else
{
ESP_LOGD(TAG, "MQTT Client: subscribed to requests topic %s", request_topic.c_str());
online = true;
}

// Announce the board to the server
if (auto query = MQTTInterface::AliveQuery{}; publish(query) == PublishResult::PublishedWithoutAnswer)
{
Expand Down Expand Up @@ -622,7 +650,7 @@ namespace fabomatic
}
}
}
last_reply = "";
last_reply.clear();

ESP_LOGW(TAG, "Retransmittion completed, remaining messages=%d", buffer.count());
return !hasBufferedMsg();
Expand Down Expand Up @@ -655,4 +683,24 @@ namespace fabomatic
buffer.setChanged(false);
ESP_LOGI(TAG, "Loaded buffer with %d messages", buffer.count());
}

auto FabBackend::checkBackendRequest() -> std::optional<std::unique_ptr<MQTTInterface::BackendRequest>>
{
if (!this->last_request.empty())
{
const auto payload = last_request.c_str();
if (DeserializationError error = deserializeJson(doc, payload))
{
ESP_LOGE(TAG, "Failed to parse json: %s (%s)", payload, error.c_str());
last_request.clear();
return std::nullopt;
}

last_request.clear();

return MQTTInterface::BackendRequest::fromJson(doc);
}
return std::nullopt;
}

} // namespace fabomatic
12 changes: 12 additions & 0 deletions src/MQTTtypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,16 @@ namespace fabomatic::MQTTInterface
auto response = std::make_unique<SimpleResponse>(doc["request_ok"].as<bool>());
return response;
}

auto BackendRequest::fromJson(const JsonDocument &doc) -> std::optional<std::unique_ptr<BackendRequest>>
{
if (doc.containsKey("request_type") && doc.containsKey("uid"))
{
const auto request = doc["request_type"].as<std::string>();
const auto struid = doc["uid"].as<std::string>();
return std::make_unique<BackendRequest>(card::str_uid(struid), request);
}
ESP_LOGW(TAG, "Cannot decode backend request from JsonDocument");
return std::nullopt;
}
} // namespace fabomatic::MQTTInterface
8 changes: 4 additions & 4 deletions src/RFIDWrapper.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ namespace fabomatic
{
const auto result = driver->PICC_IsNewCardPresent();

if (conf::debug::ENABLE_LOGS && result)
ESP_LOGD(TAG, "isNewCardPresent=%d", result);

if (disabledUntil && disabledUntil > fabomatic::Tasks::arduinoNow())
if (disabledUntil.has_value() && disabledUntil > fabomatic::Tasks::arduinoNow())
{
ESP_LOGD(TAG, "isNewCardPresent is disabled");
return false;
}

if (conf::debug::ENABLE_LOGS && result)
ESP_LOGD(TAG, "isNewCardPresent=%d", result);

return result;
}

Expand Down
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ namespace fabomatic
void taskCheckRfid()
{
Board::logic.checkRfid();
Board::logic.processBackendRequests();
}

/// @brief blink led
Expand Down
Loading
Loading