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>
75 lines
2.3 KiB
C++
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;
|
|
};
|