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>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
#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;
|
||||
};
|
||||
Reference in New Issue
Block a user