Browse Source

garland: mqtt support

mcspr-patch-1
DmitryBlinov 3 years ago
committed by Maxim Prokhorov
parent
commit
518d56b442
2 changed files with 105 additions and 11 deletions
  1. +95
    -8
      code/espurna/garland.cpp
  2. +10
    -3
      code/espurna/garland/scene.h

+ 95
- 8
code/espurna/garland.cpp View File

@ -10,6 +10,15 @@ The most time consuming operation is actually showing leds by Adafruit Neopixel.
More long strip can take more time to show. More long strip can take more time to show.
Currently animation calculation, brightness calculation/transition and showing makes in one loop cycle. Currently animation calculation, brightness calculation/transition and showing makes in one loop cycle.
Debug output shows timings. Overal timing should be not more that 3000 ms. Debug output shows timings. Overal timing should be not more that 3000 ms.
MQTT control:
"command:["immediate", "queue", "sequence", "reset"]
"enable":["true", "false"]
"brightness":[0-255]
"speed":[30-60]
"animation":["PixieDust", "Sparkr", "Run", "Stars", "Spread", "R"andCyc", "Fly", "Comets", "Assemble", "Dolphins", "Salut"]
"palette":["RGB", "Rainbow", "Stripe", "Party", "Heat", Fire", "Blue", "Sun", "Lime", "Pastel"]
"duration":5000
*/ */
#include "garland.h" #include "garland.h"
@ -23,6 +32,7 @@ Debug output shows timings. Overal timing should be not more that 3000 ms.
#include "garland/color.h" #include "garland/color.h"
#include "garland/palette.h" #include "garland/palette.h"
#include "garland/scene.h" #include "garland/scene.h"
#include "mqtt.h"
#include "ws.h" #include "ws.h"
const char* NAME_GARLAND_ENABLED = "garlandEnabled"; const char* NAME_GARLAND_ENABLED = "garlandEnabled";
@ -34,6 +44,19 @@ const char* NAME_GARLAND_SET_BRIGHTNESS = "garland_set_brightness";
const char* NAME_GARLAND_SET_SPEED = "garland_set_speed"; const char* NAME_GARLAND_SET_SPEED = "garland_set_speed";
const char* NAME_GARLAND_SET_DEFAULT = "garland_set_default"; const char* NAME_GARLAND_SET_DEFAULT = "garland_set_default";
const char* MQTT_TOPIC_GARLAND = "garland";
const char* MQTT_TOPIC_COMMAND = "command";
const char* MQTT_TOPIC_ENABLE = "enable";
const char* MQTT_TOPIC_BRIGHTNESS = "brightness";
const char* MQTT_TOPIC_ANIM_PEED = "speed";
const char* MQTT_TOPIC_ANIMATION = "animation";
const char* MQTT_TOPIC_PALETTE = "palette";
const char* MQTT_TOPIC_DURATION = "duration";
const char* GARLAND_COMMAND_IMMEDIATE = "immediate";
const char* GARLAND_COMMAND_RESET = "reset"; // reset queue
const char* GARLAND_COMMAND_QUEUE = "queue"; // enqueue command payload
#define EFFECT_UPDATE_INTERVAL_MIN 7000 // 5 sec #define EFFECT_UPDATE_INTERVAL_MIN 7000 // 5 sec
#define EFFECT_UPDATE_INTERVAL_MAX 12000 // 10 sec #define EFFECT_UPDATE_INTERVAL_MAX 12000 // 10 sec
@ -91,6 +114,8 @@ Anim* anims[] = {new AnimStart(), new AnimPixieDust(), new AnimSparkr(), new Ani
constexpr size_t animsSize() { return sizeof(anims)/sizeof(anims[0]); } constexpr size_t animsSize() { return sizeof(anims)/sizeof(anims[0]); }
String immediate_command;
std::queue<String> commands;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void garlandDisable() { void garlandDisable() {
pixels.clear(); pixels.clear();
@ -99,6 +124,13 @@ void garlandDisable() {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void garlandEnabled(bool enabled) { void garlandEnabled(bool enabled) {
_garland_enabled = enabled; _garland_enabled = enabled;
setSetting(NAME_GARLAND_ENABLED, _garland_enabled);
if (!_garland_enabled) {
schedule_function([]() {
pixels.clear();
pixels.show();
});
}
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -147,14 +179,7 @@ bool _garlandWebSocketOnKeyCheck(const char* key, JsonVariant& value) {
void _garlandWebSocketOnAction(uint32_t client_id, const char* action, JsonObject& data) { void _garlandWebSocketOnAction(uint32_t client_id, const char* action, JsonObject& data) {
if (strcmp(action, NAME_GARLAND_SWITCH) == 0) { if (strcmp(action, NAME_GARLAND_SWITCH) == 0) {
if (data.containsKey("status") && data.is<int>("status")) { if (data.containsKey("status") && data.is<int>("status")) {
_garland_enabled = (1 == data["status"].as<int>());
setSetting(NAME_GARLAND_ENABLED, _garland_enabled);
if (!_garland_enabled) {
schedule_function([](){
pixels.clear();
pixels.show();
});
}
garlandEnabled(1 == data["status"].as<int>());
} }
} }
@ -189,10 +214,33 @@ void _garlandWebSocketOnAction(uint32_t client_id, const char* action, JsonObjec
} }
#endif #endif
//------------------------------------------------------------------------------
void executeCommand(const String& command) {
DEBUG_MSG_P(PSTR("[GARLAND] Executing command \"%s\"\n"), command.c_str());
// Parse JSON input
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(command);
if (!root.success()) {
DEBUG_MSG_P(PSTR("[GARLAND] Error parsing command\n"));
return;
}
if (root.containsKey(MQTT_TOPIC_ENABLE)) {
auto enable = root[MQTT_TOPIC_ENABLE].as<String>();
garlandEnabled(enable != "false");
DEBUG_MSG_P(PSTR("[GARLAND] Enabled: \"%s\"\n"), enable.c_str());
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Loop // Loop
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void garlandLoop(void) { void garlandLoop(void) {
if (!immediate_command.isEmpty()) {
executeCommand(immediate_command);
immediate_command.clear();
}
if (!garlandEnabled()) if (!garlandEnabled())
return; return;
@ -226,10 +274,49 @@ void garlandLoop(void) {
} }
} }
//------------------------------------------------------------------------------
void garlandMqttCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) {
mqttSubscribe(MQTT_TOPIC_GARLAND);
}
if (type == MQTT_MESSAGE_EVENT) {
// Match topic
String t = mqttMagnitude((char*)topic);
if (t.equals(MQTT_TOPIC_GARLAND)) {
// Parse JSON input
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(payload);
if (!root.success()) {
DEBUG_MSG_P(PSTR("[GARLAND] Error parsing mqtt data\n"));
return;
}
String command = GARLAND_COMMAND_IMMEDIATE;
if (root.containsKey(MQTT_TOPIC_COMMAND)) {
command = root[MQTT_TOPIC_COMMAND].as<String>();
DEBUG_MSG_P(PSTR("[GARLAND] Command: \"%s\"\n"), command.c_str());
}
if (command == GARLAND_COMMAND_IMMEDIATE) {
immediate_command = payload;
} else if (command == GARLAND_COMMAND_RESET) {
std::queue<String> empty;
std::swap( commands, empty );
immediate_command = "";
} else if (command == GARLAND_COMMAND_QUEUE) {
commands.push(payload);
}
}
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void garlandSetup() { void garlandSetup() {
_garlandConfigure(); _garlandConfigure();
mqttRegister(garlandMqttCallback);
// Websockets // Websockets
#if WEB_SUPPORT #if WEB_SUPPORT
wsRegister() wsRegister()


+ 10
- 3
code/espurna/garland/scene.h View File

@ -70,10 +70,17 @@ private:
byte brightness = 0; byte brightness = 0;
// Reverse to speed. If more convenient to calculate in this way.
// 1 < cycleFactor < 4
byte speed = 50;
// cycleFactor is actually number of cycles to calculate and draw one animation step
// if cycleFactor is 2 or more, than calculation and drawing made in different cycles
// cycleFactor is float. For example cycleFactor=2.5 gives one step 2 than next 3 cycles per anim step
// Recommended values: 1 < cycleFactor < 4
float cycleFactor = 2.0; float cycleFactor = 2.0;
// speed is reverse to cycleFactor. For forward direction control of animation speed.
// Recommended values: 30 < speed < 60.
// Correspondence:
// speed=60, cycleFactor=1
// speed=30, cycleFactor=4
byte speed = 50;
float cycleTail = 0; float cycleTail = 0;
int cyclesRemain = 0; int cyclesRemain = 0;


Loading…
Cancel
Save