Files
bobbycar-boardcomputer-firm…/main/cloud.cpp
T

288 lines
7.0 KiB
C++
Raw Normal View History

2021-11-02 11:39:36 +01:00
#include "cloud.h"
// system includes
#include <optional>
2021-11-02 11:39:36 +01:00
// esp-idf includes
#include <esp_log.h>
2021-12-29 05:42:08 +01:00
// 3rdparty lib includes
#include <espwifistack.h>
#include <esphttpdutils.h>
#include <fmt/core.h>
#include <tickchrono.h>
2022-01-29 21:10:48 +01:00
#include <wrappers/websocket_client.h>
2021-12-29 05:42:08 +01:00
// local includes
#include "globals.h"
#include "utils.h"
#include "newsettings.h"
2021-11-02 11:39:36 +01:00
using namespace std::chrono_literals;
namespace {
constexpr const char * const TAG = "BOBBYCLOUD";
} // namespace
#ifdef FEATURE_CLOUD
espcpputils::websocket_client cloudClient;
bool cloudStarted{};
espchrono::millis_clock::time_point lastCreateTry;
espchrono::millis_clock::time_point lastStartTry;
std::string cloudBuffer;
std::optional<espchrono::millis_clock::time_point> lastCloudCollect;
std::optional<espchrono::millis_clock::time_point> lastCloudSend;
2021-11-02 11:39:36 +01:00
void initCloud()
{
if (configs.cloudSettings.cloudEnabled.value &&
2021-12-29 05:42:08 +01:00
!configs.cloudUrl.value.empty())
2021-11-02 11:39:36 +01:00
{
createCloud();
if (!cloudClient)
return;
if (wifi_stack::get_sta_status() != wifi_stack::WiFiStaStatus::CONNECTED)
return;
startCloud();
}
}
void updateCloud()
{
const auto now = espchrono::millis_clock::now();
if (!lastCloudCollect || now - *lastCloudCollect >= std::chrono::milliseconds{configs.boardcomputerHardware.timersSettings.cloudCollectRate.value})
{
cloudCollect();
lastCloudCollect = now;
}
if (!lastCloudSend || now - *lastCloudSend >= 1000ms/configs.boardcomputerHardware.timersSettings.cloudSendRate.value)
{
cloudSend();
lastCloudSend = now;
}
}
2021-11-02 11:39:36 +01:00
void cloudCollect()
{
if (!cloudClient)
{
cloudBuffer.clear();
return;
}
if (!cloudStarted)
{
cloudBuffer.clear();
return;
}
if (!cloudClient.is_connected())
{
cloudBuffer.clear();
return;
}
if (cloudBuffer.empty())
cloudBuffer = '[';
else
cloudBuffer += ',';
cloudBuffer += fmt::format("[{},{},{}",
2022-01-29 21:10:48 +01:00
std::chrono::floor<std::chrono::milliseconds>(espchrono::millis_clock::now().time_since_epoch()).count(),
std::chrono::floor<std::chrono::milliseconds>(espchrono::utc_clock::now().time_since_epoch()).count(),
2021-11-02 11:39:36 +01:00
heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
if (wifi_stack::get_sta_status() == wifi_stack::WiFiStaStatus::CONNECTED)
{
if (const auto &result = wifi_stack::get_sta_ap_info(); result)
cloudBuffer += fmt::format(",{}", result->rssi);
else
cloudBuffer += ",null";
}
else
cloudBuffer += ",null";
if (raw_gas)
cloudBuffer += fmt::format(",{}", *raw_gas);
else
cloudBuffer += ",null";
if (raw_brems)
cloudBuffer += fmt::format(",{}", *raw_brems);
else
cloudBuffer += ",null";
if (gas)
cloudBuffer += fmt::format(",{:.1f}", *gas);
else
cloudBuffer += ",null";
if (brems)
cloudBuffer += fmt::format(",{:.1f}", *brems);
else
cloudBuffer += ",null";
constexpr const auto addController = [](const Controller &controller){
if (!controller.feedbackValid)
{
cloudBuffer += ",null";
return;
}
cloudBuffer += fmt::format(",[{:.02f},{:.02f}",
controller.getCalibratedVoltage(),
fixBoardTemp(controller.feedback.boardTemp));
constexpr const auto addMotor = [](const bobbycar::protocol::serial::MotorState &command,
const bobbycar::protocol::serial::MotorFeedback &feedback,
bool invert){
cloudBuffer += fmt::format(",[{},{:.2f},{:.2f},{}]",
command.pwm * (invert?-1:1),
convertToKmh(feedback.speed) * (invert?-1:1),
fixCurrent(feedback.dcLink),
feedback.error);
};
addMotor(controller.command.left, controller.feedback.left, controller.invertLeft);
addMotor(controller.command.right, controller.feedback.right, controller.invertRight);
cloudBuffer += ']';
};
addController(controllers.front);
addController(controllers.back);
2021-11-21 01:36:44 +01:00
//cloudBuffer += fmt::format("", );
2021-11-02 11:39:36 +01:00
cloudBuffer += "]";
}
void cloudSend()
{
if (configs.cloudSettings.cloudEnabled.value &&
2021-12-29 05:42:08 +01:00
!configs.cloudUrl.value.empty())
2021-11-02 11:39:36 +01:00
{
if (!cloudClient)
{
if (espchrono::ago(lastCreateTry) < 10s)
return;
createCloud();
}
if (!cloudClient)
return;
if (!cloudStarted)
{
if (espchrono::ago(lastStartTry) < 10s)
return;
if (wifi_stack::get_sta_status() != wifi_stack::WiFiStaStatus::CONNECTED)
return;
startCloud();
}
if (!cloudStarted)
return;
if (!cloudClient.is_connected())
return;
if (cloudBuffer.empty())
return;
cloudBuffer += ']';
2022-01-02 21:12:57 +01:00
const auto timeout = std::chrono::ceil<espcpputils::ticks>(espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value}).count();
2021-11-02 11:39:36 +01:00
const auto written = cloudClient.send_text(cloudBuffer, timeout);
if (written < 0)
{
ESP_LOGE("BOBBY", "cloudClient.send_text() failed with %i", written);
}
else if (written != cloudBuffer.size())
{
ESP_LOGE("BOBBY", "websocket sent size mismatch, sent=%i, expected=%i", written, cloudBuffer.size());
}
cloudBuffer.clear();
}
else if (cloudClient)
{
destroyCloud();
}
}
void createCloud()
{
ESP_LOGI("BOBBY", "called");
if (cloudClient)
{
ESP_LOGE(TAG, "cloud client already created");
return;
}
lastCreateTry = espchrono::millis_clock::now();
const esp_websocket_client_config_t config = {
2021-12-29 05:42:08 +01:00
.uri = configs.cloudUrl.value.c_str(),
2021-11-02 11:39:36 +01:00
};
cloudClient = espcpputils::websocket_client{&config};
if (!cloudClient)
{
ESP_LOGE(TAG, "websocket could not be constructed");
return;
}
ESP_LOGI("BOBBY", "cloud client created");
}
void startCloud()
{
ESP_LOGI("BOBBY", "called");
if (!cloudClient)
{
ESP_LOGE(TAG, "cloud client not created");
return;
}
if (cloudStarted)
{
ESP_LOGE(TAG, "cloud client already started");
return;
}
lastStartTry = espchrono::millis_clock::now();
const auto result = cloudClient.start();
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), "BOBBY", "cloudClient.start() returned: %s", esp_err_to_name(result));
if (result == ESP_OK)
cloudStarted = true;
}
void destroyCloud()
{
ESP_LOGI("BOBBY", "called");
if (!cloudClient)
{
ESP_LOGE(TAG, "cloud client not created");
return;
}
cloudClient = {};
cloudStarted = false;
}
#endif