88fa73f922
User: "у него есть полупрозрачная подложка? у него правильный z-order?"
Z-order был ок (overlays draw'аются после layout.render). Но без bg
текст плохо читался на пёстром кадре — и до прихода MQTT overlay был
visible=0 (не виден вообще).
Изменения:
- overlay.h: cfc_overlay_text_config_t расширена bg_alpha / bg_y/u/v / bg_pad.
bg_alpha=0 — фон отключён (default).
- overlay.c draw_text: если bg_alpha>0, перед blit'ом текста рисуем fill
rect (atlas_w+2*pad) × (atlas_h+2*pad) с заданным цветом и alpha.
- overlay.c update_text: пробрасывает bg-поля при апдейте.
- mqtt_overlay: MqttOverlayCfg + JSON loader научились читать bg_alpha,
bg_y/u/v, bg_pad, placeholder. Default bg = чёрный 160 alpha, pad 10.
- MqttOverlayItem::start: overlay сразу visible=1 с placeholder (default "—"),
reposition_overlay вызывается до получения MQTT — placeholder
позиционируется в anchor сразу.
User'у теперь видна тёмная подложка с текстом в правом-нижнем углу даже
если sensor молчит.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
124 lines
4.3 KiB
C++
124 lines
4.3 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";
|
|
|
|
/* Полупрозрачная подложка. bg_alpha=0 → отключено. */
|
|
int bg_alpha = 160;
|
|
int bg_y = 16, bg_u = 128, bg_v = 128; /* по умолчанию чёрный */
|
|
int bg_pad = 10;
|
|
|
|
/* Что показывать пока нет MQTT-данных. Пусто → overlay невидим до
|
|
* первого сообщения. По умолчанию "—" чтобы было видно что overlay
|
|
* жив, но данные ещё не пришли. */
|
|
std::string placeholder = "—";
|
|
};
|
|
|
|
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 */
|