AlexaInterfaces.h/.cpp hold one row per interface in program memory (28: namespace, version, property names, flags, type), each row and string an object of its own, so the linker keeps only the rows a sketch names. addCapability(AlexaInterfaceType) is an always-inline switch that folds to one row; a type without a row is refused with an error. The Event handler gets its type from the capabilities of the device. Versions follow the interface pages (EndpointHealth 3.1, ThermostatController 3.2), HumiditySensor is new, the two withdrawn interfaces and AlexaInterfaceUtils are gone. Display category names are in flash. The discovery objects of the five examples are unchanged: 14 new host tests compare them with what the previous commit announced. basicLight on a D1 mini: static RAM 34,508 -> 30,788, flash 338,533 -> 330,509; it links two rows, EndpointHealth and PowerController. Host tests: 47 -> 61. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
108 lines
4.1 KiB
C++
108 lines
4.1 KiB
C++
#ifndef ALEXA_STATUS_MESSAGE_H
|
|
#define ALEXA_STATUS_MESSAGE_H
|
|
|
|
#include <Arduino.h>
|
|
#include <ArduinoJson.h>
|
|
#include "AlexaInterfaces.h"
|
|
#include "AlexaTransport.h"
|
|
|
|
enum class EndpointHealth
|
|
{
|
|
OK,
|
|
UNREACHABLE
|
|
};
|
|
|
|
enum class PowerController
|
|
{
|
|
ON,
|
|
OFF
|
|
};
|
|
enum class TemperatureSensorScale
|
|
{
|
|
CELSIUS,
|
|
FAHRENHEIT
|
|
};
|
|
|
|
class AlexaStatusMessage
|
|
{
|
|
public:
|
|
// Built by AlexaDevice::buildStatusMessage(), which passes the bridge as the transport: it publishes the report
|
|
// and supplies the time of every property. A message without a transport cannot be sent.
|
|
AlexaStatusMessage(const String &correlationToken, const String &rootTopic, const String &endpointId, const bool isResponse, AlexaTransport *transport = nullptr);
|
|
|
|
AlexaStatusMessage &AddHealthProp(EndpointHealth endpointHealth, unsigned int uncertaintyInMs = 0)
|
|
{
|
|
JsonDocument healthValue;
|
|
healthValue["value"] = (endpointHealth == EndpointHealth::OK) ? "OK" : "UNREACHABLE";
|
|
return AddProperty(AlexaInterfaces::EndpointHealth, healthValue.as<JsonObject>(), uncertaintyInMs);
|
|
}
|
|
|
|
AlexaStatusMessage &AddPowerControllerProp(PowerController powerController, unsigned int uncertaintyInMs = 0)
|
|
{
|
|
String value = (powerController == PowerController::ON) ? "ON" : "OFF";
|
|
return AddProperty(AlexaInterfaces::PowerController, value, uncertaintyInMs);
|
|
}
|
|
|
|
AlexaStatusMessage &AddTemperatureSensorProp(TemperatureSensorScale tempSensor,float value, unsigned int uncertaintyInMs = 0)
|
|
{
|
|
JsonDocument tempValue;
|
|
tempValue["scale"] = "CELSIUS";
|
|
tempValue["value"] = value;
|
|
if((tempSensor == TemperatureSensorScale::FAHRENHEIT)){
|
|
tempValue["value"] = (value - 32) * 5.0 / 9.0;
|
|
}
|
|
return AddProperty(AlexaInterfaces::TemperatureSensor, tempValue.as<JsonObject>(), uncertaintyInMs);
|
|
}
|
|
|
|
AlexaStatusMessage &AddBrightnessControllerProp(unsigned int brightness, unsigned int uncertaintyInMs = 0)
|
|
{
|
|
return AddProperty(AlexaInterfaces::BrightnessController, brightness, uncertaintyInMs);
|
|
}
|
|
AlexaStatusMessage &AddColorTemperatureControllerProp(unsigned int colorTemperature, unsigned int uncertaintyInMs = 0)
|
|
{
|
|
return AddProperty(AlexaInterfaces::ColorTemperatureController, colorTemperature, uncertaintyInMs);
|
|
}
|
|
AlexaStatusMessage &AddToggleControllerProp(PowerController powerController,String instanceName, unsigned int uncertaintyInMs = 0)
|
|
{
|
|
String value = (powerController == PowerController::ON) ? "ON" : "OFF";
|
|
return AddProperty(AlexaInterfaces::ToggleController, value, uncertaintyInMs,instanceName);
|
|
}
|
|
|
|
// Adds a property the sketch built itself. Its timeOfSample is set to the current time when the object has
|
|
// none or still carries the 1.x placeholder "{REPLACE_WITH_DATETIME}".
|
|
AlexaStatusMessage &AddContextProp(const JsonObject &property);
|
|
|
|
// Publishes the report on <root>/<endpointId>/alexaResponce now. Returns false when nothing was sent: no
|
|
// session with the broker, the MQTT client or the heap cannot take the report, or it is over
|
|
// ALEX2ESP_MAX_MESSAGE bytes. The reason is on Serial; a report is never sent truncated.
|
|
bool send();
|
|
|
|
private:
|
|
String rootTopic;
|
|
String endpointId;
|
|
AlexaTransport *transport;
|
|
JsonDocument doc;
|
|
JsonArray contextProperties;
|
|
|
|
String generateMessageId();
|
|
void setTimeOfSample(JsonObject property);
|
|
|
|
// Adds the first property of the row: every interface with a helper above reports one
|
|
template <typename T>
|
|
AlexaStatusMessage &AddProperty(const AlexaInterfaceDesc &row, const T &value, unsigned int uncertaintyInMs = 0,const String &instanceName="")
|
|
{
|
|
JsonObject prop = contextProperties.add<JsonObject>();
|
|
prop["namespace"] = FPSTR(row.ns);
|
|
prop["name"] = FPSTR(row.property(0));
|
|
|
|
if (!instanceName.isEmpty()) {
|
|
prop["instance"] = instanceName;
|
|
}
|
|
prop["value"] = value;
|
|
|
|
setTimeOfSample(prop);
|
|
prop["uncertaintyInMilliseconds"] = uncertaintyInMs;
|
|
return *this;
|
|
}
|
|
};
|
|
#endif
|