1.1.0: begin(username, password, rootTopic) - the library signature now matches every example, the readme and the website (as published since 2024 no sketch could authenticate: the 64-hex password became the MQTT username). Discovery answers go out over MQTT directly, every device, resumed from loop() under heap pressure within the backend's 5 s window, instead of the 5-slot HTTP queue that silently dropped the rest (which the backend's reconcile then deleted from Alexa). JSON aligned with Alexa / alex2node: event.payload present, ActionMapping payload an object, semantics only when a capability has mappings. Pointer-stable device/capability containers (std::deque), the MQTT payload is copied by length before parsing (no write past the buffer), fragmented directive ids are ignored (a Discover is answered on its first fragment), deprecated ArduinoJson 7 calls replaced, credential Serial prints removed, ESP32 include guards (untested; the ESP8266 is the target). Examples: WIFI_PASSWORD, LED_BUILTIN fallback, string+int print fixes. library.json + library.properties restored (1.1.0; AsyncMqttClient, ArduinoJson 7, ESP Async TCP), LICENSE (MIT), a real keywords.txt, .gitattributes text=auto eol=lf (tree normalised to LF). readme: Forgejo URLs, platformio.ini snippet, Library Manager install, begin() order, INTERIOR_BLIND for blinds, 1.1.0 changelog. All five examples compile warning-free for d1_mini (PlatformIO 6.2, espressif8266) on pve-B450.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 04:58:38 +00:00
parent 1313f47856
commit 87caad25be
20 changed files with 3117 additions and 2782 deletions

View file

@ -1,164 +1,166 @@
#include "AlexaDevice.h"
AlexaDevice::AlexaDevice(const String& name, const String& rootTopic, const String& endpointId)
: name(name), endpointId(endpointId), rootTopic(rootTopic) {
// Initialize event arrays to nullptr
for (int i = 0; i < MAX_EVENTS; ++i) {
eventNames[i] = nullptr; // Set all event names to nullptr
eventCallbacks[i] = nullptr; // Set all callbacks to nullptr
}
}
// Setters and Getters
void AlexaDevice::setName(const String& name) {
this->name = name;
}
String AlexaDevice::getName() const {
return name;
}
String AlexaDevice::getEndpointId() const {
return endpointId;
}
DisplayCategory AlexaDevice::getDisplayCategory() const {
return displayCategory;
}
void AlexaDevice::setDisplayCategory(DisplayCategory category) {
displayCategory = category;
}
String AlexaDevice::getDescription() const {
return description;
}
void AlexaDevice::setDescription(const String& description) {
this->description = description;
}
String AlexaDevice::getManufacturerName() const {
return manufacturerName;
}
void AlexaDevice::setManufacturerName(const String& manufacturerName) {
this->manufacturerName = manufacturerName;
}
String AlexaDevice::getManufacturer() const {
return manufacturer;
}
void AlexaDevice::setManufacturer(const String& manufacturer) {
this->manufacturer = manufacturer;
}
String AlexaDevice::getModel() const {
return model;
}
void AlexaDevice::setModel(const String& model) {
this->model = model;
}
String AlexaDevice::getSoftwareVersion() const {
return softwareVersion;
}
AlexaInterface* AlexaDevice::addCapability(AlexaInterfaceType type) {
// Check if a interface with the given type already exists
for (auto& iface : capabilities) {
if (iface.getType() == type) {
return &iface; // Return the existing interface
}
}
// If the interface doesn't exist, create a new one
capabilities.emplace_back(type);
Serial.print("Created new interface with type: ");
Serial.println(capabilities.back().getTypeString());
// Return a pointer to the newly created device
return &capabilities.back();
}
JsonDocument AlexaDevice::getDeviceJSON() const {
JsonDocument json;
// Main device attributes
json["endpointId"] = endpointId;
json["friendlyName"] = name;
json["description"] = description;
json["manufacturerName"] = manufacturerName;
JsonArray displayCategories = json["displayCategories"].to<JsonArray>();
displayCategories.add(DisplayCategoryUtils::toString(displayCategory));
JsonObject additionalAttributes = json["additionalAttributes"].to<JsonObject>();
additionalAttributes["manufacturer"] = manufacturer;
additionalAttributes["model"] = model;
additionalAttributes["serialNumber"] = "ESP2Alex";
additionalAttributes["firmwareVersion"] = "1.0.0";
additionalAttributes["softwareVersion"] = softwareVersion;
additionalAttributes["customIdentifier"] = "ESP2Alex";
JsonArray capabilitiesArray = json["capabilities"].to<JsonArray>();
for (AlexaInterface capability : capabilities) {
capabilitiesArray.add(capability.getJSON().as<JsonObject>());
}
// capabilitiesArray.add(capability.getJSON().as<JsonObject>());
return json;
}
// void AlexaDevice::registerEvent(const String& eventName, std::function<void(const JsonDocument&,const AlexaInterfaceType&)> callback) {
// eventCallbacks[eventName] = callback;
// }
// void AlexaDevice::triggerEvent(const String& eventName, const JsonDocument& directive,const AlexaInterfaceType& type) const {
// auto it = eventCallbacks.find(eventName);
// if (it != eventCallbacks.end()) {
// // Call the registered callback function
// it->second(directive,type);
// } else {
// Serial.print("No event registered for: ");
// Serial.println(eventName);
// }
// }
// Register an event callback function
void AlexaDevice::registerEvent(const char* eventName, void (*callback)(const JsonDocument&, const AlexaInterfaceType&)) {
for (int i = 0; i < MAX_EVENTS; ++i) {
// Find an empty slot for the new event
if (eventNames[i] == nullptr) {
eventNames[i] = eventName; // Store the event name
eventCallbacks[i] = callback; // Store the callback function
break;
}
}
}
// Trigger the event and invoke the corresponding callback
void AlexaDevice::triggerEvent(const char* eventName, const JsonDocument& directive, const AlexaInterfaceType& type) const {
for (int i = 0; i < MAX_EVENTS; ++i) {
if (eventNames[i] != nullptr && strcmp(eventNames[i], eventName) == 0) {
// Found the event name, call the corresponding callback function
eventCallbacks[i](directive, type);
return;
}
}
// If no event was found, print an error message
Serial.print("No event registered for: ");
Serial.println(eventName);
}
#include "AlexaDevice.h"
AlexaDevice::AlexaDevice(const String& name, const String& rootTopic, const String& endpointId)
: name(name), endpointId(endpointId), rootTopic(rootTopic) {
// Initialize event arrays to nullptr
for (int i = 0; i < MAX_EVENTS; ++i) {
eventNames[i] = nullptr; // Set all event names to nullptr
eventCallbacks[i] = nullptr; // Set all callbacks to nullptr
}
}
// Setters and Getters
void AlexaDevice::setName(const String& name) {
this->name = name;
}
String AlexaDevice::getName() const {
return name;
}
String AlexaDevice::getEndpointId() const {
return endpointId;
}
DisplayCategory AlexaDevice::getDisplayCategory() const {
return displayCategory;
}
void AlexaDevice::setDisplayCategory(DisplayCategory category) {
displayCategory = category;
}
String AlexaDevice::getDescription() const {
return description;
}
void AlexaDevice::setDescription(const String& description) {
this->description = description;
}
String AlexaDevice::getManufacturerName() const {
return manufacturerName;
}
void AlexaDevice::setManufacturerName(const String& manufacturerName) {
this->manufacturerName = manufacturerName;
}
String AlexaDevice::getManufacturer() const {
return manufacturer;
}
void AlexaDevice::setManufacturer(const String& manufacturer) {
this->manufacturer = manufacturer;
}
String AlexaDevice::getModel() const {
return model;
}
void AlexaDevice::setModel(const String& model) {
this->model = model;
}
String AlexaDevice::getSoftwareVersion() const {
return softwareVersion;
}
AlexaInterface* AlexaDevice::addCapability(AlexaInterfaceType type) {
// Check if a interface with the given type already exists
for (auto& iface : capabilities) {
if (iface.getType() == type) {
return &iface; // Return the existing interface
}
}
// If the interface doesn't exist, create a new one
capabilities.emplace_back(type);
Serial.print("Created new interface with type: ");
Serial.println(capabilities.back().getTypeString());
// Return a pointer to the newly created device
return &capabilities.back();
}
JsonDocument AlexaDevice::getDeviceJSON() const {
JsonDocument json;
// Main device attributes
json["endpointId"] = endpointId;
json["friendlyName"] = name;
json["description"] = description;
json["manufacturerName"] = manufacturerName;
JsonArray displayCategories = json["displayCategories"].to<JsonArray>();
displayCategories.add(DisplayCategoryUtils::toString(displayCategory));
JsonObject additionalAttributes = json["additionalAttributes"].to<JsonObject>();
additionalAttributes["manufacturer"] = manufacturer;
additionalAttributes["model"] = model;
additionalAttributes["serialNumber"] = "ESP2Alex";
additionalAttributes["firmwareVersion"] = "1.1.0";
additionalAttributes["softwareVersion"] = softwareVersion;
additionalAttributes["customIdentifier"] = "ESP2Alex";
JsonArray capabilitiesArray = json["capabilities"].to<JsonArray>();
for (const AlexaInterface& capability : capabilities) {
capabilitiesArray.add(capability.getJSON().as<JsonObject>());
}
// capabilitiesArray.add(capability.getJSON().as<JsonObject>());
return json;
}
// void AlexaDevice::registerEvent(const String& eventName, std::function<void(const JsonDocument&,const AlexaInterfaceType&)> callback) {
// eventCallbacks[eventName] = callback;
// }
// void AlexaDevice::triggerEvent(const String& eventName, const JsonDocument& directive,const AlexaInterfaceType& type) const {
// auto it = eventCallbacks.find(eventName);
// if (it != eventCallbacks.end()) {
// // Call the registered callback function
// it->second(directive,type);
// } else {
// Serial.print("No event registered for: ");
// Serial.println(eventName);
// }
// }
// Register an event callback function
void AlexaDevice::registerEvent(const char* eventName, void (*callback)(const JsonDocument&, const AlexaInterfaceType&)) {
for (int i = 0; i < MAX_EVENTS; ++i) {
// Find an empty slot for the new event
if (eventNames[i] == nullptr) {
eventNames[i] = eventName; // Store the event name
eventCallbacks[i] = callback; // Store the callback function
break;
}
}
}
// Trigger the event and invoke the corresponding callback
void AlexaDevice::triggerEvent(const char* eventName, const JsonDocument& directive, const AlexaInterfaceType& type, bool warnIfMissing) const {
for (int i = 0; i < MAX_EVENTS; ++i) {
if (eventNames[i] != nullptr && strcmp(eventNames[i], eventName) == 0) {
// Found the event name, call the corresponding callback function
eventCallbacks[i](directive, type);
return;
}
}
// If no event was found, print an error message
if (warnIfMissing) {
Serial.print("No event registered for: ");
Serial.println(eventName);
}
}