#ifndef ALEXA_STATUS_MESSAGE_H #define ALEXA_STATUS_MESSAGE_H #include #include #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(), 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(), 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 //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 AlexaStatusMessage &AddProperty(const AlexaInterfaceDesc &row, const T &value, unsigned int uncertaintyInMs = 0,const String &instanceName="") { JsonObject prop = contextProperties.add(); 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