Files
trmnl_server_cpp/TRMNL.cpp
2026-06-30 17:00:16 +03:00

289 lines
4.9 KiB
C++

#include "TRMNL.h"
#include "helpers.h"
#include <set>
#include <time.h>
using std::list;
using std::map;
using std::optional;
using std::set;
using std::string;
using nlohmann::json;
TRMNL::TRMNL(const string& id,
const string& api_key,
const string& friendly_id,
int refresh_rate,
bool is_refresh_aligned)
: m_id(id),
m_api_key(api_key),
m_friendly_id(friendly_id),
m_refresh_rate(refresh_rate),
m_is_refresh_aligned(is_refresh_aligned),
m_update_handler()
{}
TRMNL::TRMNL(const nlohmann::json& j)
: m_id(""),
m_api_key(""),
m_friendly_id(""),
m_refresh_rate(DEFAULT_REFRESH_RATE),
m_update_handler()
{
json_extract(j, "ID", m_id);
json_extract(j, "api_key", m_api_key);
json_extract(j, "friendly_id", m_friendly_id);
json_extract(j, "refresh_rate", m_refresh_rate);
}
const string& TRMNL::id() const
{
return m_id;
}
const string& TRMNL::api_key() const
{
return m_api_key;
}
const string& TRMNL::friendly_id() const
{
return m_friendly_id;
}
int TRMNL::refresh_rate() const
{
return m_refresh_rate;
}
bool TRMNL::is_refresh_aligned() const
{
return m_is_refresh_aligned;
}
int TRMNL::get_next_refresh(int min_time, int offset) const
{
if (!m_is_refresh_aligned)
{
return m_refresh_rate;
}
if (min_time > m_refresh_rate)
{
min_time = m_refresh_rate;
}
int result = 0;
time_t curr = time(nullptr);
struct tm* now = localtime(&curr);
int tmp_refresh = m_refresh_rate;
set<int> allowed_minutes = {0, 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30};
set<int> allowed_hours = {1, 2, 3, 4, 6, 8, 12, 24};
// Check whether refresh rate is minutes aligned
if (0 == m_refresh_rate % 60)
{
tmp_refresh /= 60;
now->tm_sec = 0;
// Check whether refresh rate is hours aligned
if (0 == tmp_refresh % 60)
{
tmp_refresh /= 60;
now->tm_min = 0;
// Hours within the day
if (0 != allowed_hours.count(tmp_refresh))
{
now->tm_hour -= now->tm_hour % tmp_refresh;
}
now->tm_hour += tmp_refresh;
}
else
{
// Minutes within the hour
if (0 != allowed_minutes.count(tmp_refresh))
{
now->tm_min -= now->tm_min % tmp_refresh;
}
now->tm_min += tmp_refresh;
}
}
time_t next = mktime(now);
result = next - curr + offset;
while (result < min_time)
{
result += m_refresh_rate;
}
return result;
}
void TRMNL::id(const std::string& id)
{
m_id = id;
if (m_update_handler)
{
m_update_handler(*this);
}
}
void TRMNL::api_key(const std::string& api_key)
{
m_api_key = api_key;
if (m_update_handler)
{
m_update_handler(*this);
}
}
void TRMNL::friendly_id(const std::string& friendly_id)
{
m_friendly_id = friendly_id;
if (m_update_handler)
{
m_update_handler(*this);
}
}
void TRMNL::refresh_rate(int refresh_rate)
{
m_refresh_rate = refresh_rate;
if (m_update_handler)
{
m_update_handler(*this);
}
}
void TRMNL::is_refresh_aligned(bool to_align)
{
m_is_refresh_aligned = to_align;
if (m_update_handler)
{
m_update_handler(*this);
}
}
void TRMNL::set_update_handler(std::function<void (const TRMNL& trmnl)> handler)
{
m_update_handler = handler;
}
string TRMNL::friendly_from_id(string id)
{
size_t pos = id.find(':');
while (pos != string::npos)
{
id.erase(pos, 1);
pos = id.find(':');
}
if (id.size() <= 6)
{
return id;
}
else
{
return id.substr(id.size() - 6);
}
}
void to_json(json& j, const TRMNL& trmnl)
{
j = json{
{"ID", trmnl.m_id},
{"api_key", trmnl.m_api_key},
{"friendly_id", trmnl.m_friendly_id},
{"refresh_rate", trmnl.m_refresh_rate},
};
}
void TRMNLContainer::TRMNL_update_handler(const TRMNL& trmnl)
{
auto it = m_by_id.find(trmnl.m_id);
if (it == m_by_id.end())
{
return;
}
// An update is needed only if friendly ID changes
if (0 == m_by_friendly.count(trmnl.m_friendly_id))
{
m_by_friendly[trmnl.m_friendly_id] = it->second;
}
}
TRMNLContainer& TRMNLContainer::operator=(const TRMNLContainer& other)
{
m_devices = other.m_devices;
m_by_id = other.m_by_id;
m_by_friendly = other.m_by_friendly;
for (TRMNL& device : m_devices)
{
device.set_update_handler([this](const TRMNL& trmnl){ TRMNL_update_handler(trmnl); });
}
return *this;
}
void TRMNLContainer::add_device(TRMNL trmnl)
{
if (trmnl.m_id.empty())
{
return;
}
auto it = m_devices.insert(m_devices.end(), trmnl);
m_by_id[trmnl.m_id] = it;
if (!trmnl.m_friendly_id.empty())
{
m_by_friendly[trmnl.m_friendly_id] = it;
}
it->set_update_handler([this](const TRMNL& trmnl){ TRMNL_update_handler(trmnl); });
}
TRMNL* TRMNLContainer::get_device_by_id(const string& id)
{
TRMNL* result = nullptr;
if (0 != m_by_id.count(id))
{
result = &(*m_by_id[id]);
}
return result;
}
TRMNL* TRMNLContainer::get_device_by_friendly(const string& friendly)
{
TRMNL* result = nullptr;
if (0 != m_by_friendly.count(friendly))
{
result = &(*m_by_friendly[friendly]);
}
return result;
}
void TRMNLContainer::clear()
{
m_by_friendly.clear();
m_by_id.clear();
m_devices.clear();
}
void to_json(json& j, const TRMNLContainer& cont)
{
j = cont.m_devices;
}