75271436f7
User: "оверлеев которые выводят какую-то инфу из MQTT может быть
бесконечно много. Надо делать настраиваемым через json/yaml конфиг".
Заменили захардкоженный TempMqttOverlay на generic MqttOverlay:
- cpp/mqtt_overlay.hpp/.cpp: класс MqttOverlayItem (один topic + один
text overlay) + MqttOverlayManager (контейнер). Загрузка из JSON.
- cpp/mqtt_overlay_c_api.cpp: extern "C" обёртка для grid_record.c.
- docker/mqtt_overlays.json: default config с temp_outside примером.
- grid_record.c: --mqtt-overlays=PATH (заменил --temp-topic).
- src/CMakeLists.txt: temp_overlay* удалены, mqtt_overlay* добавлены.
JSON schema:
{
"overlays": [
{
"id": "temp_outside",
"topic": "zigbee2mqtt/Температура на улице",
"json_field": "temperature", // пусто = raw payload string
"format": "%+.1f°C", // printf
"anchor": "right-bottom", // right-top, left-bottom, ...
"margin_x": 32, "margin_y": 24,
"pixel_size": 32,
"color": [255, 255, 255], "alpha": 230,
"font_path": "/fonts/DejaVuSans-Bold.ttf"
}
]
}
MqttBrokerCfg делятся между всеми overlays (one connect_async per item
но shared credentials). Добавление новых overlays = редактирование JSON +
restart cfc-grid (hot-reload через ZMQ — Phase 12).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
114 lines
3.7 KiB
C++
114 lines
3.7 KiB
C++
/* MqttOverlay — generic MQTT-driven text overlay (Phase 11b).
|
|
*
|
|
* Каждый overlay = одна MQTT-подписка + один persistent text overlay.
|
|
* Конфиг загружается из JSON-файла (mqtt_overlays.json):
|
|
* {
|
|
* "overlays": [
|
|
* { "id": "temp_outside",
|
|
* "topic": "zigbee2mqtt/Температура на улице",
|
|
* "json_field": "temperature", // если payload JSON; пусто — raw string
|
|
* "format": "%+.1f°C", // printf для extracted значения
|
|
* "anchor": "right-bottom", // right-top, left-bottom, ...
|
|
* "margin_x": 32, "margin_y": 24,
|
|
* "pixel_size": 32,
|
|
* "color": [255, 255, 255], "alpha": 230,
|
|
* "font_path": "/fonts/DejaVuSans-Bold.ttf"
|
|
* }, ...
|
|
* ]
|
|
* }
|
|
*
|
|
* Менеджер (MqttOverlayManager) держит vector<MqttOverlayItem>, поднимает
|
|
* MQTT-клиентов и добавляет overlays в композер. Hot-reload через
|
|
* reload_from_file() — пересоздаёт всех subscribers и overlays.
|
|
*
|
|
* Лицензия: LGPL-2.1+
|
|
*/
|
|
|
|
#ifndef CUFRAMES_COMPOSER_CPP_MQTT_OVERLAY_HPP
|
|
#define CUFRAMES_COMPOSER_CPP_MQTT_OVERLAY_HPP
|
|
|
|
#include "../overlay.h"
|
|
|
|
#include <atomic>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
struct mosquitto;
|
|
struct mosquitto_message;
|
|
|
|
namespace cfc {
|
|
|
|
struct MqttOverlayCfg {
|
|
std::string id;
|
|
std::string topic;
|
|
std::string json_field; /* если payload JSON; пусто = raw string */
|
|
std::string format = "%s"; /* printf-formatted (для double — "%+.1f°C") */
|
|
std::string anchor = "right-bottom"; /* right-top, left-bottom, ... */
|
|
int margin_x = 32, margin_y = 24;
|
|
int pixel_size = 32;
|
|
int r = 255, g = 255, b = 255;
|
|
int alpha = 230;
|
|
std::string font_path = "/fonts/DejaVuSans-Bold.ttf";
|
|
};
|
|
|
|
struct MqttBrokerCfg {
|
|
std::string host = "cctv-mosquitto";
|
|
int port = 1883;
|
|
std::string username;
|
|
std::string password;
|
|
};
|
|
|
|
class MqttOverlayItem {
|
|
public:
|
|
MqttOverlayItem(const MqttOverlayCfg& cfg, const MqttBrokerCfg& broker,
|
|
int frame_w, int frame_h);
|
|
~MqttOverlayItem();
|
|
MqttOverlayItem(const MqttOverlayItem&) = delete;
|
|
MqttOverlayItem& operator=(const MqttOverlayItem&) = delete;
|
|
|
|
bool start();
|
|
cfc_overlay_t* overlay() const { return overlay_; }
|
|
const std::string& id() const { return cfg_.id; }
|
|
|
|
private:
|
|
static void on_connect(struct mosquitto* m, void* user, int rc);
|
|
static void on_message(struct mosquitto* m, void* user,
|
|
const struct mosquitto_message* msg);
|
|
|
|
void handle_payload(const char* payload, std::size_t len);
|
|
void update_text(const std::string& text);
|
|
void reposition_overlay();
|
|
|
|
MqttOverlayCfg cfg_;
|
|
MqttBrokerCfg broker_;
|
|
int frame_w_, frame_h_;
|
|
struct mosquitto* mosq_ = nullptr;
|
|
cfc_overlay_t* overlay_ = nullptr;
|
|
std::atomic<bool> running_{false};
|
|
std::string last_text_;
|
|
};
|
|
|
|
class MqttOverlayManager {
|
|
public:
|
|
explicit MqttOverlayManager(const MqttBrokerCfg& broker) : broker_(broker) {}
|
|
~MqttOverlayManager() = default;
|
|
|
|
/* Загрузить overlays из JSON-файла. Возвращает количество созданных. */
|
|
int load_from_file(const std::string& path, int frame_w, int frame_h);
|
|
|
|
/* Pointers на overlays для регистрации в композере. */
|
|
std::vector<cfc_overlay_t*> overlay_handles() const;
|
|
|
|
void clear();
|
|
int size() const { return static_cast<int>(items_.size()); }
|
|
|
|
private:
|
|
MqttBrokerCfg broker_;
|
|
std::vector<std::unique_ptr<MqttOverlayItem>> items_;
|
|
};
|
|
|
|
} // namespace cfc
|
|
|
|
#endif /* CUFRAMES_COMPOSER_CPP_MQTT_OVERLAY_HPP */
|