Files
FrameAssistant/src/ha/HaEntity.h
T
matzmanandClaude Opus 5.5 466743eff9 HA entity, sensor and device classes (iteration 2, step 3)
HaEntity describes an entity for device-based discovery, throttles its
state (SEN-14) and reports availability (SEN-15); HaSensor is the
`sensor` type. HaDevice publishes discovery, availability and states
after each connect and after HA's birth message, provides the last
will and removes itself from HA. Unit tests with a fake MQTT client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:12:43 +02:00

75 lines
2.3 KiB
C++

#pragma once
#include <QByteArray>
#include <QElapsedTimer>
#include <QJsonObject>
#include <QObject>
#include <QString>
#include <QTimer>
// One HA entity (docs/DESIGN.md, D23): the base class of every entity type.
// It describes the entity for discovery, holds its current state, throttles
// state changes (SEN-14) and knows whether it has a value (SEN-15: without
// one, HA shows it as unavailable).
//
// It knows nothing about MQTT: HaDevice publishes what it reports.
class HaEntity : public QObject {
Q_OBJECT
public:
struct Description {
// Topic level and suffix of the unique id, e.g. "uptime".
QString id;
// Name shown in HA, e.g. "Uptime".
QString name;
// Optional: HA device class, unit, entity category ("diagnostic", …).
QString deviceClass;
QString unit;
QString category;
// Minimum time between two published states (SEN-14).
int throttleMs = 1000;
};
// `platform`: the HA entity type, e.g. "sensor".
HaEntity(QString platform, Description description,
QObject* parent = nullptr);
const QString& platform() const { return m_platform; }
const Description& description() const { return m_description; }
// The component for device-based discovery; topics are relative to the
// device's base topic "~". `uniqueIdPrefix`: e.g.
// "frameassistant_<device id>".
virtual QJsonObject discoveryComponent(const QString& uniqueIdPrefix) const;
// Topics relative to the device's base topic.
QString stateTopic() const;
QString availabilityTopic() const;
bool hasValue() const { return m_hasValue; }
// The state as published; empty without a value.
QByteArray state() const { return m_hasValue ? m_state : QByteArray(); }
signals:
// A new state to publish, at most once per throttle interval (the newest
// one wins). Emitted before availabilityChanged(true) for a first value.
void stateChanged(const QByteArray& state);
void availabilityChanged(bool available);
protected:
// For the concrete types: set or clear the state.
void updateState(const QByteArray& state);
void clearState();
private:
void emitState();
const QString m_platform;
const Description m_description;
QByteArray m_state;
bool m_hasValue = false;
// The state last emitted, and when.
QByteArray m_emittedState;
QElapsedTimer m_sinceEmit;
QTimer m_throttle;
};