Compare commits

...

9 Commits

24 changed files with 147 additions and 46 deletions

3
data/config.json Normal file
View File

@ -0,0 +1,3 @@
{
"version": 3
}

View File

@ -0,0 +1,18 @@
{
"version": 1,
"strides": [
{"x": 0, "y": 6, "pixels": 6},
{"x": 1, "y": 6, "pixels": 6},
{"x": 2, "y": 6, "pixels": 6},
{"x": 3, "y": 4, "pixels": 9},
{"x": 4, "y": 4, "pixels": 14},
{"x": 5, "y": 0, "pixels": 17},
{"x": 6, "y": 2, "pixels": 12},
{"x": 7, "y": 0, "pixels": 18},
{"x": 8, "y": 4, "pixels": 14},
{"x": 9, "y": 5, "pixels": 9},
{"x": 10, "y": 4, "pixels": 7},
{"x": 11, "y": 5, "pixels": 6},
{"x": 12, "y": 5, "pixels": 6}
]
}

6
data/maps/default.json Normal file
View File

@ -0,0 +1,6 @@
{
"version": 1,
"strides": [
{"x": 0, "y": 0, "pixels": 255}
]
}

View File

@ -0,0 +1,16 @@
{
"version": 1,
"tasks": [
"Renderer",
"SerialInput",
"BPM",
"Bluetooth"
],
"scenes": {
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
"Acid": ["Chimes", "Pulse", "MPU5060", "IdleColors", "Rainbow"],
"Flashlight": ["Flashlight"]
},
"surfaceMap": "cyberplague"
}

View File

@ -0,0 +1,15 @@
{
"version": 1,
"tasks": [
"Renderer",
"MQTT",
"WiFi",
"ArduinoOTA",
"UpdateStatusAnimation"
],
"scenes": {
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
"Flashlight": ["Flashlight"]
}
"surfaceMap": "default"
}

View File

@ -0,0 +1,17 @@
{
"version": 1,
"tasks": [
"Bluetooth",
"Renderer",
"WiFi",
"MQTT",
"ArduinoOTA",
"UpdateStatusAnimation"
],
"scenes": {
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
"Acid": ["Chimes", "Pulse", "MPU5060", "IdleColors", "Rainbow"],
"Flashlight": ["Flashlight"]
}
"surfaceMap": "default"
}

View File

@ -22,16 +22,14 @@ struct Task : public virtual Loopable {
}; };
Task() {} Task() {}
explicit Task(State initialState) : Task(0, initialState) {} explicit Task(const char* name) : name(name) {}
explicit Task(const char* name) : Task(name, Running) {}
Task(const char* name, State initialState) : name(name), state(initialState) {}
void start() { state = Running; onStart(); } void start() { state = Running; onStart(); }
void stop() { onStop(); state = Stopped; } void stop() { onStop(); state = Stopped; }
virtual bool isFigment() const { return false; } virtual bool isFigment() const { return false; }
const char* name = ""; const char* name = "";
State state = Running; State state = Stopped;
}; };
struct TaskFunc: public Task { struct TaskFunc: public Task {
@ -42,9 +40,7 @@ struct TaskFunc: public Task {
struct Figment: public Task { struct Figment: public Task {
Figment() : Task() {} Figment() : Task() {}
explicit Figment(State initialState) : Task(initialState) {}
explicit Figment(const char* name) : Task(name) {} explicit Figment(const char* name) : Task(name) {}
Figment(const char* name, State initialState) : Task(name, initialState) {}
virtual void render(Display* dpy) const = 0; virtual void render(Display* dpy) const = 0;
bool isFigment() const override { return true; } bool isFigment() const override { return true; }
}; };

View File

@ -114,8 +114,6 @@ class InputSource: public Task {
public: public:
InputSource() : Task() {init();} InputSource() : Task() {init();}
explicit InputSource(const char* name) : Task(name) {init();} explicit InputSource(const char* name) : Task(name) {init();}
explicit InputSource(Task::State initialState) : Task(initialState) {init();}
InputSource(const char* name, Task::State initialState) : Task(name, initialState) {init();}
void loop() override; void loop() override;
void onStart() override; void onStart() override;
virtual InputEvent read() = 0; virtual InputEvent read() = 0;
@ -134,7 +132,6 @@ class InputFunc : public InputSource {
public: public:
InputFunc(std::function<InputEvent(void)> f) : InputSource(), m_func(f) {} InputFunc(std::function<InputEvent(void)> f) : InputSource(), m_func(f) {}
InputFunc(std::function<InputEvent(void)> f, const char* name) : InputSource(name), m_func(f) {} InputFunc(std::function<InputEvent(void)> f, const char* name) : InputSource(name), m_func(f) {}
InputFunc(std::function<InputEvent(void)> f, const char* name, Task::State initialState) : InputSource(name, initialState), m_func(f) {}
InputEvent read() override { InputEvent read() override {
return m_func(); return m_func();

View File

@ -30,7 +30,7 @@ private:
// Particle. This allows for multiple devices with wildly different displays to // Particle. This allows for multiple devices with wildly different displays to
// run the same code // run the same code
struct ConfigService: public Task { struct ConfigService: public Task {
ConfigService() : Task("Configuration") {} ConfigService() : Task("Configuration") {state = Task::Running;}
void onStart(); void onStart();
void loop() override; void loop() override;
void handleEvent(const InputEvent &evt) override; void handleEvent(const InputEvent &evt) override;

View File

@ -2,7 +2,7 @@
class LogService : public Task { class LogService : public Task {
public: public:
LogService() : Task("Logging") {} LogService() : Task("Logging") {state = Task::Running;}
void handleEvent(const InputEvent& event) override; void handleEvent(const InputEvent& event) override;
void loop() override {} void loop() override {}

View File

@ -96,6 +96,7 @@ Platform::preSetup()
#else #else
#ifdef CONFIG_MQTT #ifdef CONFIG_MQTT
Log.begin(LOG_LEVEL_TRACE, Static<MQTTTelemetry>::instance()->logPrinter()); Log.begin(LOG_LEVEL_TRACE, Static<MQTTTelemetry>::instance()->logPrinter());
Static<MQTTTelemetry>::instance()->setSequencer(Static<Sequencer>::instance());
#else #else
Log.begin(LOG_LEVEL_TRACE, &Serial); Log.begin(LOG_LEVEL_TRACE, &Serial);
#endif #endif

View File

@ -7,7 +7,7 @@ class Platform : public Task {
static int s_timezone; static int s_timezone;
static char s_deviceID[15]; static char s_deviceID[15];
public: public:
Platform() : Task("Platform") {} Platform() : Task("Platform") {state = Task::Running;}
static BootOptions bootopts; static BootOptions bootopts;
static void setTimezone(int tz) { s_timezone = tz; } static void setTimezone(int tz) { s_timezone = tz; }
static int getTimezone() { return s_timezone; } static int getTimezone() { return s_timezone; }

View File

@ -6,6 +6,7 @@ Sequencer::Sequencer() :
Task("SceneSequencer"), Task("SceneSequencer"),
m_idx(0) m_idx(0)
{ {
state = Task::Running;
} }
void void

View File

@ -1,7 +1,7 @@
#include "Chimes.h" #include "Chimes.h"
#include "../Static.h" #include "../Static.h"
ChimesAnimation::ChimesAnimation() : Figment("Chimes", Task::Stopped) { ChimesAnimation::ChimesAnimation() : Figment("Chimes") {
} }
void ChimesAnimation::randomize() { void ChimesAnimation::randomize() {

View File

@ -1,7 +1,7 @@
#include "Drain.h" #include "Drain.h"
#include "../Static.h" #include "../Static.h"
DrainAnimation::DrainAnimation() : Figment("Drain", Task::Stopped) {} DrainAnimation::DrainAnimation() : Figment("Drain") {}
void DrainAnimation::loop() { void DrainAnimation::loop() {
EVERY_N_MILLISECONDS(8) { EVERY_N_MILLISECONDS(8) {

View File

@ -1,7 +1,7 @@
#include "Flashlight.h" #include "Flashlight.h"
#include "../Static.h" #include "../Static.h"
Flashlight::Flashlight() : Figment("Flashlight", Task::Stopped) { Flashlight::Flashlight() : Figment("Flashlight") {
m_blobs.forEach([](Blob &blob) { m_blobs.forEach([](Blob &blob) {
blob.setHue(random(255)); blob.setHue(random(255));
blob.setSaturation(10); blob.setSaturation(10);

View File

@ -4,7 +4,7 @@
template<uint8_t MaxBrightness = 255, uint32_t MaxMilliAmps = 500, uint32_t Voltage = 5> template<uint8_t MaxBrightness = 255, uint32_t MaxMilliAmps = 500, uint32_t Voltage = 5>
class Power: public Figment { class Power: public Figment {
public: public:
Power() : Figment("Power") {} Power() : Figment("Power") {state = Task::Running;}
void handleEvent(const InputEvent& evt) override { void handleEvent(const InputEvent& evt) override {
switch (evt.intent) { switch (evt.intent) {

View File

@ -1,7 +1,7 @@
#include "SolidAnimation.h" #include "SolidAnimation.h"
#include "../Static.h" #include "../Static.h"
SolidAnimation::SolidAnimation() : Figment("Solid", Task::Stopped) { SolidAnimation::SolidAnimation() : Figment("Solid") {
} }
void SolidAnimation::randomize() { void SolidAnimation::randomize() {

View File

@ -4,8 +4,8 @@
template<int Period> template<int Period>
class ColorSequenceInput: public InputSource { class ColorSequenceInput: public InputSource {
public: public:
ColorSequenceInput(const std::vector<CRGB> &colors, const char* name, Task::State initialState) ColorSequenceInput(const std::vector<CRGB> &colors, const char* name)
: InputSource(name, initialState), m_colors(colors) {} : InputSource(name), m_colors(colors) {}
InputEvent read() override { InputEvent read() override {
EVERY_N_SECONDS(Period) { EVERY_N_SECONDS(Period) {

34
src/inputs/Serial.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "Serial.h"
InputEvent
Serial::read()
{
while (Serial.available() > 0) {
char nextChar = Serial.read();
if (nextChar == '\n') {
doCommand();
m_buf = "";
} else {
m_buf += nextChar;
}
}
}
void
Serial::doCommand() {
if (command == "tasks") {
Serial.println("Tasks:");
auto sched = MainLoop::instance()->scheduler;
for(auto task : sched.tasks) {
bool isFigment = task->isFigment();
if (isFigment) {
Serial.println("F " + task->name);
} else {
Serial.println("T " + task->name);
}
}
}
}
STATIC_ALLOC(SerialInput);
STATIC_TASK(SerialInput);

View File

@ -1,12 +1,17 @@
#pragma once
#include "Particle.h" #include "Particle.h"
#include "../Figments/Figments.h" #include "../Figments/Figments.h"
class SerialInput: public InputSource { class SerialInput: public InputSource {
public: public:
void onAttach() override { void onStart() override {
//Serial.begin(); //Serial.begin();
} }
InputEvent read() { InputEvent read();
}
private:
String m_buf;
void doCommand();
} }

View File

@ -3,10 +3,7 @@
#include <FastLED.h> #include <FastLED.h>
#include <Figments.h> #include <Figments.h>
#ifndef PLATFORM_PHOTON
#include <ArduinoLog.h> #include <ArduinoLog.h>
#endif // !PLATFORM_PHOTON
#include "Platform.h" #include "Platform.h"
#include "Static.h" #include "Static.h"
@ -23,13 +20,6 @@
#include "inputs/ColorCycle.h" #include "inputs/ColorCycle.h"
#include "inputs/Buttons.h" #include "inputs/Buttons.h"
#ifdef PLATFORM_PHOTON
#include "platform/particle/inputs/Photon.h"
#include "platform/particle/inputs/CloudStatus.h"
#endif // PLATFORM_PHOTON
//SerialLogHandler logHandler;
#define MAX_BRIGHTNESS 255 #define MAX_BRIGHTNESS 255
//#define PSU_MILLIAMPS 4800 //#define PSU_MILLIAMPS 4800
//#define PSU_MILLIAMPS 500 //#define PSU_MILLIAMPS 500
@ -75,7 +65,7 @@ InputFunc randomPulse([]() {
} }
} }
return InputEvent{}; return InputEvent{};
}, "Pulse", Task::Stopped); }, "Pulse");
REGISTER_TASK(randomPulse); REGISTER_TASK(randomPulse);
@ -167,7 +157,7 @@ ColorSequenceInput<9> idleCycle{{
CRGB(128, 0, 128), // Purple CRGB(128, 0, 128), // Purple
CRGB(255, 255, 255), // White CRGB(255, 255, 255), // White
CRGB(0, 255, 255), // Cyan CRGB(0, 255, 255), // Cyan
}, "IdleColors", Task::Stopped}; }, "IdleColors"};
REGISTER_TASK(idleCycle); REGISTER_TASK(idleCycle);
@ -177,7 +167,7 @@ ColorSequenceInput<7> rainbowCycle{{
CRGB(0, 255, 0), // Green CRGB(0, 255, 0), // Green
CRGB(0, 0, 255), // Blue CRGB(0, 0, 255), // Blue
CRGB(128, 0, 128), // Purple CRGB(128, 0, 128), // Purple
}, "Rainbow", Task::Stopped}; }, "Rainbow"};
REGISTER_TASK(rainbowCycle); REGISTER_TASK(rainbowCycle);
@ -428,17 +418,15 @@ MainLoop* runner = &safeModeApp;
void setup() { void setup() {
// Turn on, // Turn on,
Platform::preSetup(); Platform::preSetup();
#ifdef CONFIG_MQTT
Static<MQTTTelemetry>::instance()->setSequencer(&sequencer);
#endif // CONFIG_MQTT
Log.notice(u8"🐛 Booting Renderbug!"); Log.notice(u8"🐛 Booting Renderbug!");
Log.notice(u8"🐞 I am built for %d LEDs running on %dmA", HardwareConfig::MAX_LED_NUM, PSU_MILLIAMPS); Log.notice(u8"🐞 I am built for %d LEDs running on %dmA", HardwareConfig::MAX_LED_NUM, PSU_MILLIAMPS);
Log.notice(u8"📡 Platform %s version %s", Platform::name(), Platform::version()); Log.notice(u8"📡 Platform %s version %s", Platform::name(), Platform::version());
Log.notice(u8"Setting timezone to -7 (PST)"); Log.notice(u8"Setting timezone to +2 (CEST)");
Platform::setTimezone(-7); Platform::setTimezone(+2);
Log.notice(u8"Setting up platform..."); Log.notice(u8"Setting up platform...");
Platform::setup(); Platform::setup();
Platform::bootSplash(); Platform::bootSplash();
@ -453,6 +441,7 @@ void setup() {
FastLED.show(); FastLED.show();
} else if (Platform::bootopts.isSetup) { } else if (Platform::bootopts.isSetup) {
Log.notice(u8"🔧 Starting Figment in configuration mode..."); Log.notice(u8"🔧 Starting Figment in configuration mode...");
FastLED.showColor(CRGB(0, 5, 0));
//runner = &configApp; //runner = &configApp;
} else { } else {
Log.notice(u8"🌌 Starting Figment..."); Log.notice(u8"🌌 Starting Figment...");

View File

@ -6,6 +6,8 @@
#include "../../Config.h" #include "../../Config.h"
#include "../../Platform.h" #include "../../Platform.h"
StaticJsonDocument<1024> m_json;
struct MQTTDevice { struct MQTTDevice {
const String id; const String id;
const String name; const String name;
@ -234,14 +236,13 @@ MQTTTelemetry::loopOnline()
m_json["os_version"] = ESP.getSdkVersion(); m_json["os_version"] = ESP.getSdkVersion();
m_json["localip"] = WiFi.localIP().toString(); m_json["localip"] = WiFi.localIP().toString();
m_json["pixelCount"] = Static<ConfigService>::instance()->coordMap()->physicalPixelCount(); m_json["pixelCount"] = Static<ConfigService>::instance()->coordMap()->physicalPixelCount();
//m_json["startPixel"] = Static<ConfigService>::instance()->coordMap()->startPixel; m_json["loadedProfile"] = Static<ConfigService>::instance()->loadedProfile();
m_json["RSSI"] = WiFi.RSSI(); m_json["RSSI"] = WiFi.RSSI();
m_json["free_ram"] = ESP.getFreeHeap(); m_json["free_ram"] = ESP.getFreeHeap();
m_json["fps"] = FastLED.getFPS(); m_json["fps"] = FastLED.getFPS();
String availTopic = m_rootTopic + "/available"; String availTopic = m_rootTopic + "/available";
publishDoc(Lightswitch.heartbeatTopic().c_str()); publishDoc(Lightswitch.heartbeatTopic().c_str());
m_mqtt.publish(Device.availabilityTopic.c_str(), "online"); m_mqtt.publish(Device.availabilityTopic.c_str(), "online");
//Log.trace("Heartbeat: %s", buf);
String fpsCounter = String(FastLED.getFPS()); String fpsCounter = String(FastLED.getFPS());
m_mqtt.publish(FPSSensor.statTopic().c_str(), fpsCounter.c_str()); m_mqtt.publish(FPSSensor.statTopic().c_str(), fpsCounter.c_str());
@ -302,6 +303,11 @@ MQTTTelemetry::callback(char* topic, const char* payload)
setEvent(InputEvent{InputEvent::SetDisplayOffset, m_json["startPixel"].as<int>()}); setEvent(InputEvent{InputEvent::SetDisplayOffset, m_json["startPixel"].as<int>()});
} }
if (m_json.containsKey("loadConfig")) {
Log.notice("Loading new config");
setEvent(InputEvent{InputEvent::LoadConfigurationByName, m_json["loadConfig"].as<const char*>()});
}
if (m_json.containsKey("save")) { if (m_json.containsKey("save")) {
setEvent(InputEvent{InputEvent::SaveConfigurationRequest}); setEvent(InputEvent{InputEvent::SaveConfigurationRequest});
} }

View File

@ -12,8 +12,6 @@
#include <WiFi.h> #include <WiFi.h>
#endif #endif
#include <ArduinoJson.h>
class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin { class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
public: public:
MQTTTelemetry(); MQTTTelemetry();
@ -75,5 +73,4 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
WiFiClient m_wifi; WiFiClient m_wifi;
PubSubClient m_mqtt; PubSubClient m_mqtt;
LogPrinter m_logPrinter; LogPrinter m_logPrinter;
StaticJsonDocument<1024> m_json;
}; };