diff --git a/.gitignore b/.gitignore
index 4fbc9ac..30a5810 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
bin/*
*.bin
.pio
+*.swp
diff --git a/lib/Figments/Input.h b/lib/Figments/Input.h
index deec40d..0036ef3 100644
--- a/lib/Figments/Input.h
+++ b/lib/Figments/Input.h
@@ -163,7 +163,7 @@ class OnlineTaskMixin : public virtual Loopable {
}
}
- virtual void handleEventOnline(const InputEvent &evt) = 0;
+ virtual void handleEventOnline(const InputEvent &evt) {}
void loop() override {
if (m_online) {
@@ -171,7 +171,7 @@ class OnlineTaskMixin : public virtual Loopable {
}
}
- virtual void loopOnline() = 0;
+ virtual void loopOnline() {}
private:
bool m_online = false;
diff --git a/lib/Figments/Ringbuf.h b/lib/Figments/Ringbuf.h
index 5807ca5..023be93 100644
--- a/lib/Figments/Ringbuf.h
+++ b/lib/Figments/Ringbuf.h
@@ -31,6 +31,16 @@ struct Ringbuf {
}
m_items[cur] = src;
}
+
+ size_t write(T(&dest)[Size]) {
+ int i = 0;
+ size_t ret = 0;
+ while(take(dest[i])) {
+ i++;
+ ret += sizeof(T);
+ }
+ return ret;
+ }
private:
int m_head = 0;
int m_tail = 0;
diff --git a/platformio.ini b/platformio.ini
index 1fc65a7..0ce140f 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -8,17 +8,37 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
+[common_env_data]
+src_filter = "+<*> -<.git/> -<.svn/> -"
+
[env:featheresp32]
platform = espressif32
board = featheresp32
framework = arduino
+build_flags =
+ -D PLATFORM_ARDUINO
+ -D BOARD_ESP32
lib_deps =
fastled/FastLED@^3.4.0
thijse/ArduinoLog@^1.0.3
knolleary/PubSubClient@^2.8.0
bblanchon/ArduinoJson@^6.17.3
- ricaun/ArduinoUniqueID@^1.1.0
sstaub/NTP@^1.4.0
-src_filter = "+<*> -<.git/> -<.svn/> - +"
-; upload_protocol = espota
-; upload_port = 10.0.0.171
+ arduino-libraries/NTPClient@^3.1.0
+src_filter = "${common_env_data.src_filter} +"
+
+[env:huzzah]
+platform = espressif8266
+board = huzzah
+framework = arduino
+build_flags =
+ -D PLATFORM_ARDUINO
+ -D BOARD_ESP8266
+lib_deps =
+ fastled/FastLED@^3.4.0
+ thijse/ArduinoLog@^1.0.3
+ knolleary/PubSubClient@^2.8.0
+ bblanchon/ArduinoJson@^6.17.3
+ sstaub/NTP@^1.4.0
+ arduino-libraries/NTPClient@^3.1.0
+src_filter = "${common_env_data.src_filter} +"
diff --git a/src/Config.cpp b/src/Config.cpp
index f924afd..4e4a24e 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -1,15 +1,14 @@
#include "./Config.h"
#include "./Static.h"
#include
+#include
constexpr uint16_t HardwareConfig::MAX_LED_NUM;
HardwareConfig
HardwareConfig::load() {
HardwareConfig ret;
-#ifdef PLATFORM_PHOTON
EEPROM.get(0, ret);
-#endif
return ret;
}
@@ -17,9 +16,7 @@ void
HardwareConfig::save() {
HardwareConfig dataCopy{*this};
dataCopy.checksum = getCRC();
-#ifdef PLATFORM_PHOTON
EEPROM.put(0, dataCopy);
-#endif
}
LinearCoordinateMapping
@@ -103,6 +100,8 @@ ConfigService::handleEvent(const InputEvent &evt)
//Log.info("Saving configuration");
m_config.save();
break;
+ default:
+ break;
}
}
diff --git a/src/Config.h b/src/Config.h
index 1f4b021..a0eda84 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -2,7 +2,8 @@
#include
//#define PLATFORM_PHOTON
-#define PLATFORM_ARDUINO
+//#define PLATFORM_ARDUINO
+#define RENDERBUG_VERSION 2
struct HardwareConfig {
uint8_t version = 2;
@@ -29,7 +30,11 @@ struct HardwareConfig {
LinearCoordinateMapping toCoordMap() const;
static constexpr uint16_t MAX_LED_NUM = 255;
+#ifdef PLATFORM_PHOTON
+ static constexpr bool HAS_MPU_6050 = true;
+#else
static constexpr bool HAS_MPU_6050 = false;
+#endif
private:
uint8_t getCRC() const;
diff --git a/src/LogService.cpp b/src/LogService.cpp
new file mode 100644
index 0000000..3d76568
--- /dev/null
+++ b/src/LogService.cpp
@@ -0,0 +1,100 @@
+#include "LogService.h"
+#include "Static.h"
+#include
+
+void
+LogService::handleEvent(const InputEvent& evt) {
+ if (evt.intent != InputEvent::None) {
+ const char* sourceName;
+ switch(evt.intent) {
+ case InputEvent::PowerToggle:
+ sourceName = "power-toggle";
+ break;
+ case InputEvent::SetPower:
+ sourceName = "set-power";
+ break;
+ case InputEvent::PreviousPattern:
+ sourceName = "previous-pattern";
+ break;
+ case InputEvent::NextPattern:
+ sourceName = "next-pattern";
+ break;
+ case InputEvent::SetPattern:
+ sourceName = "set-pattern";
+ break;
+ case InputEvent::SetColor:
+ sourceName = "set-color";
+ break;
+ case InputEvent::Acceleration:
+ sourceName = "acceleration";
+ break;
+ case InputEvent::UserInput:
+ sourceName = "user";
+ break;
+ case InputEvent::SetBrightness:
+ sourceName = "set-brightness";
+ break;
+ case InputEvent::FirmwareUpdate:
+ sourceName = "firmware-update";
+ break;
+ case InputEvent::NetworkStatus:
+ sourceName = "network-status";
+ break;
+ case InputEvent::NetworkActivity:
+ sourceName = "network-activity";
+ break;
+ case InputEvent::StartThing:
+ sourceName = "start-thing";
+ break;
+ case InputEvent::StopThing:
+ sourceName = "stop-thing";
+ break;
+ case InputEvent::SetDisplayOffset:
+ sourceName = "set-display-offset";
+ break;
+ case InputEvent::SetDisplayLength:
+ sourceName = "set-display-length";
+ break;
+ case InputEvent::SaveConfigurationRequest:
+ sourceName = "save-configuration";
+ break;
+ default:
+ sourceName = 0;
+ break;
+ }
+ char valueBuf[255];
+ switch(evt.type) {
+ case InputEvent::Null:
+ snprintf(valueBuf, sizeof(valueBuf), "null");break;
+ case InputEvent::Integer:
+ snprintf(valueBuf, sizeof(valueBuf), "%d %02x", evt.asInt(), evt.asInt());break;
+ case InputEvent::String:
+ snprintf(valueBuf, sizeof(valueBuf), "\"%s\"", evt.asString());break;
+ case InputEvent::Color:
+ snprintf(valueBuf, sizeof(valueBuf), "[%d, %d, %d]", evt.asRGB().r, evt.asRGB().g, evt.asRGB().b);break;
+ }
+ char buf[255 * 2];
+ if (sourceName == 0) {
+ snprintf(buf, sizeof(buf), "{\"intent\": %d, \"value\": %s}", evt.intent, valueBuf);
+ } else {
+ snprintf(buf, sizeof(buf), "{\"intent\": \"%s\", \"value\": %s}", sourceName, valueBuf);
+ }
+ if (evt.intent != m_lastEvent.intent) {
+ if (m_duplicateEvents > 0) {
+ Log.notice("Suppressed reporting %u duplicate events.", m_duplicateEvents);
+ }
+ Log.verbose("Event: %s", buf);
+ m_duplicateEvents = 0;
+ m_lastEvent = evt;
+ //Particle.publish("renderbug/event", buf, PRIVATE);
+ } else {
+ m_duplicateEvents++;
+ }
+ /*if (m_online) {
+ } else {
+ Log.info("[offline] Event: %s", buf);
+ }*/
+ }
+}
+
+STATIC_ALLOC(LogService);
diff --git a/src/LogService.h b/src/LogService.h
new file mode 100644
index 0000000..32f3e49
--- /dev/null
+++ b/src/LogService.h
@@ -0,0 +1,12 @@
+#include
+
+class LogService : public Task {
+ public:
+ LogService() : Task("Logging") {}
+ void handleEvent(const InputEvent& event) override;
+ void loop() override {}
+
+ private:
+ uint16_t m_duplicateEvents = 0;
+ InputEvent m_lastEvent;
+};
diff --git a/src/Platform.cpp b/src/Platform.cpp
new file mode 100644
index 0000000..3cc5ee8
--- /dev/null
+++ b/src/Platform.cpp
@@ -0,0 +1,139 @@
+#include "Platform.h"
+#include
+#include "Static.h"
+
+#ifdef BOARD_ESP32
+#include
+#elif defined(BOARD_ESP8266)
+#include
+#include
+#include
+#include
+
+WiFiUDP wifiUdp;
+NTPClient timeClient(wifiUdp, "pool.ntp.org", 3600 * -7);
+#endif
+
+#ifdef PLATFORM_PHOTON
+STARTUP(BootOptions::initPins());
+#else
+#include "platform/arduino/MQTTTelemetry.h"
+void printNewline(Print* logOutput) {
+ logOutput->print("\r\n");
+}
+#endif
+
+int Platform::s_timezone = 0;
+
+const char*
+Platform::name()
+{
+#ifdef PLATFORM_PHOTON
+ return "Photon";
+#else
+ return "Unknown!";
+#endif
+}
+
+const char*
+Platform::version()
+{
+#ifdef PLATFORM_PHOTON
+ return System.version().c_str();
+#else
+ return "Unknown!";
+#endif
+}
+
+void
+Platform::preSetup()
+{
+ Serial.begin(115200);
+#ifdef PLATFORM_PHOTON
+ System.enableFeature(FEATURE_RETAINED_MEMORY);
+ if (bootopts.isFlash) {
+ System.dfu();
+ }
+ if (bootopts.isSerial) {
+ bootopts.waitForRelease();
+ while(!Serial.isConnected()) {
+ Particle.process();
+ }
+ Log.notice("\xf0\x9f\x94\x8c Serial connected");
+ }
+#else
+ Log.begin(LOG_LEVEL_VERBOSE, Static::instance()->logPrinter());
+ Log.setSuffix(printNewline);
+#endif
+}
+
+void
+Platform::setup()
+{
+#ifdef PLATFORM_PHOTON
+ Time.zone(Static::instance()->getTimezone());
+#elif defined(BOARD_ESP32)
+ constexpr int dst = 1;
+ configTime(s_timezone* 3600, 3600 * dst, "pool.ntp.org");
+#elif defined(BOARD_ESP8266)
+ timeClient.begin();
+#endif
+}
+
+void
+Platform::bootSplash()
+{
+#ifdef PLATFORM_PHOTON
+ Log.notice(u8" Boot pin configuration:");
+ Log.notice(u8" 2: Setup - %d", bootopts.isSetup);
+ Log.notice(u8" 3: Serial - %d", bootopts.isSerial);
+ Log.notice(u8" 4: Flash - %d", bootopts.isFlash);
+#endif
+}
+
+void
+Platform::loop()
+{
+#ifdef BOARD_ESP8266
+ timeClient.update();
+#endif
+}
+
+bool
+Platform::getLocalTime(struct tm* timedata)
+{
+#ifdef PLATFORM_PHOTON
+ if (Time.isValid()) {
+ timedata->tm_hour = Time.hour();
+ timedata->tm_min = Time.minute();
+ return true;
+ }
+ return false;
+#elif defined(BOARD_ESP32)
+ return getLocalTime(timedata);
+#else
+ timeClient.update();
+ timedata->tm_hour = timeClient.getHours();
+ timedata->tm_min = timeClient.getMinutes();
+ return true;
+#endif
+}
+
+const char*
+Platform::deviceID()
+{
+ uint64_t chipid;
+#ifdef BOARD_ESP32
+ chipid = ESP.getEfuseMac();
+#elif defined(BOARD_ESP8266)
+ chipid = ESP.getChipId();
+#endif
+ snprintf(s_deviceID, sizeof(s_deviceID), "%08X", (uint32_t)chipid);
+ return s_deviceID;
+}
+
+BootOptions
+Platform::bootopts;
+
+char
+Platform::s_deviceID[15];
diff --git a/src/Platform.h b/src/Platform.h
new file mode 100644
index 0000000..b8aba95
--- /dev/null
+++ b/src/Platform.h
@@ -0,0 +1,31 @@
+#pragma once
+#include
+#include "BootOptions.h"
+
+class Platform {
+ static int s_timezone;
+ static char s_deviceID[15];
+ public:
+ static BootOptions bootopts;
+ static void setTimezone(int tz) { s_timezone = tz; }
+ static int getTimezone() { return s_timezone; }
+
+ static void addLEDs(CRGB* leds, unsigned int ledCount) {
+#ifdef PLATFORM_PHOTON
+ FastLED.addLeds(leds, ledCount);
+#elif defined(BOARD_ESP32)
+ FastLED.addLeds(leds, ledCount);
+#else
+ FastLED.addLeds(leds, ledCount);
+#endif
+ }
+
+ static const char* name();
+ static const char* version();
+ static void preSetup();
+ static void bootSplash();
+ static void setup();
+ static void loop();
+ static bool getLocalTime(struct tm* timedata);
+ static const char* deviceID();
+};
diff --git a/src/WiFiTask.cpp b/src/WiFiTask.cpp
index 9c93661..01751d0 100644
--- a/src/WiFiTask.cpp
+++ b/src/WiFiTask.cpp
@@ -1,10 +1,16 @@
#include
#include
+
+#ifdef BOARD_ESP8266
+#include
+#endif
+#ifdef BOARD_ESP32
#include
+#endif
#include "Static.h"
#include "WiFiTask.h"
-WiFiTask::WiFiTask() : InputSource("WiFi") {}
+WiFiTask::WiFiTask() : InputSource("WiFi"), m_lastStatus(WL_IDLE_STATUS) {}
void
WiFiTask::onStart()
diff --git a/src/WiFiTask.h b/src/WiFiTask.h
index fc95d4e..d19262f 100644
--- a/src/WiFiTask.h
+++ b/src/WiFiTask.h
@@ -1,5 +1,4 @@
#include
-#include
#include "Static.h"
class WiFiTask : public InputSource {
@@ -8,5 +7,5 @@ class WiFiTask : public InputSource {
void onStart() override;
InputEvent read() override;
private:
- uint8_t m_lastStatus = WL_IDLE_STATUS;
+ uint8_t m_lastStatus;
};
diff --git a/src/animations/Power.cpp b/src/animations/Power.cpp
index 1451f0f..e0e09ad 100644
--- a/src/animations/Power.cpp
+++ b/src/animations/Power.cpp
@@ -16,6 +16,8 @@ public:
break;
case InputEvent::SetBrightness:
m_brightness = evt.asInt();
+ default:
+ return;
}
}
diff --git a/src/firmware b/src/firmware
new file mode 120000
index 0000000..cc2dd92
--- /dev/null
+++ b/src/firmware
@@ -0,0 +1 @@
+firmware
\ No newline at end of file
diff --git a/src/inputs/Buttons.cpp b/src/inputs/Buttons.cpp
index a8b4ed5..5692f71 100644
--- a/src/inputs/Buttons.cpp
+++ b/src/inputs/Buttons.cpp
@@ -1,11 +1,13 @@
#include "./Buttons.h"
+#include "../Static.h"
void
Buttons::onStart()
{
for(int i = 0; i < 3; i++) {
//Log.info("Bound pin %d to button %d", 2 + i, i);
- m_buttons[i].attach(2 + i, INPUT_PULLDOWN);
+ //m_buttons[i].attach(2 + i, INPUT_PULLDOWN);
+ m_buttons[i].attach(2 + i, INPUT_PULLUP);
m_buttons[i].interval(15);
}
}
@@ -35,3 +37,5 @@ Buttons::read()
}
return InputEvent{};
}
+
+STATIC_ALLOC(Buttons);
diff --git a/src/inputs/MPU6050.cpp b/src/inputs/MPU6050.cpp
index e69de29..488dd2c 100644
--- a/src/inputs/MPU6050.cpp
+++ b/src/inputs/MPU6050.cpp
@@ -0,0 +1,65 @@
+#include "MPU6050.h"
+#include
+#include "../Config.h"
+#include "../Static.h"
+
+MPU5060::MPU5060() : InputSource("MPU5060") {}
+
+void
+MPU5060::onStart()
+{
+ Wire.begin();
+
+ // Turn on the sensor
+ Wire.beginTransmission(I2C_ADDRESS);
+ Wire.write(PWR_MGMT_1);
+ Wire.write(0);
+ Wire.endTransmission(true);
+
+ // Configure the filter
+ Wire.beginTransmission(I2C_ADDRESS);
+ Wire.write(CONFIG_REG);
+ Wire.write(3);
+ Wire.endTransmission(true);
+
+ // Configure the accel range
+ Wire.beginTransmission(I2C_ADDRESS);
+ Wire.write(ACCEL_CONFIG_REG);
+ // 4G
+ Wire.write(2 << 3);
+ Wire.endTransmission(true);
+}
+
+void
+MPU5060::onStop()
+{
+ Wire.beginTransmission(I2C_ADDRESS);
+ // Turn off the sensor
+ Wire.write(PWR_MGMT_1);
+ Wire.write(1);
+ Wire.endTransmission(true);
+ //Wire.end();
+}
+
+InputEvent
+MPU5060::read()
+{
+ EVERY_N_MILLISECONDS(5) {
+ Wire.beginTransmission(I2C_ADDRESS);
+ Wire.write(ACCEL_XOUT_HIGH);
+ Wire.endTransmission(false);
+ Wire.requestFrom(I2C_ADDRESS, 6);
+ const int16_t accelX = Wire.read() << 8 | Wire.read();
+ const int16_t accelY = Wire.read() << 8 | Wire.read();
+ const int16_t accelZ = Wire.read() << 8 | Wire.read();
+ const uint16_t accelSum = abs(accelX) + abs(accelY) + abs(accelZ);
+ const uint16_t delta = abs(m_value.value() - accelSum);
+ m_value.add(accelSum);
+ if (delta > 32) {
+ return InputEvent{InputEvent::Acceleration, delta};
+ }
+ }
+ return InputEvent{};
+}
+
+STATIC_ALLOC(MPU5060);
diff --git a/src/inputs/MPU6050.h b/src/inputs/MPU6050.h
index 107c5c3..7f8fbd3 100644
--- a/src/inputs/MPU6050.h
+++ b/src/inputs/MPU6050.h
@@ -1,4 +1,4 @@
-#include
+#include
class MPU5060: public InputSource {
const int ACCEL_XOUT_HIGH = 0x3B;
@@ -15,57 +15,11 @@ class MPU5060: public InputSource {
const int ACCEL_CONFIG_REG = 0x1C;
public:
- MPU5060() : InputSource("MPU5060", HardwareConfig::HAS_MPU_6050 ? Task::Running : Task::Stopped) {}
- void onStart() override {
- Wire.begin();
+ MPU5060();
- // Turn on the sensor
- Wire.beginTransmission(I2C_ADDRESS);
- Wire.write(PWR_MGMT_1);
- Wire.write(0);
- Wire.endTransmission(true);
-
- // Configure the filter
- Wire.beginTransmission(I2C_ADDRESS);
- Wire.write(CONFIG_REG);
- Wire.write(3);
- Wire.endTransmission(true);
-
- // Configure the accel range
- Wire.beginTransmission(I2C_ADDRESS);
- Wire.write(ACCEL_CONFIG_REG);
- // 4G
- Wire.write(2 << 3);
- Wire.endTransmission(true);
- }
-
- void onStop() override {
- Wire.beginTransmission(I2C_ADDRESS);
- // Turn off the sensor
- Wire.write(PWR_MGMT_1);
- Wire.write(1);
- Wire.endTransmission(true);
- //Wire.end();
- }
-
- InputEvent read() override {
- EVERY_N_MILLISECONDS(5) {
- Wire.beginTransmission(I2C_ADDRESS);
- Wire.write(ACCEL_XOUT_HIGH);
- Wire.endTransmission(false);
- Wire.requestFrom(I2C_ADDRESS, 6);
- const int16_t accelX = Wire.read() << 8 | Wire.read();
- const int16_t accelY = Wire.read() << 8 | Wire.read();
- const int16_t accelZ = Wire.read() << 8 | Wire.read();
- const uint16_t accelSum = abs(accelX) + abs(accelY) + abs(accelZ);
- const uint16_t delta = abs(m_value.value() - accelSum);
- m_value.add(accelSum);
- if (delta > 32) {
- return InputEvent{InputEvent::Acceleration, delta};
- }
- }
- return InputEvent{};
- }
+ void onStart() override;
+ void onStop() override;
+ InputEvent read() override;
template
struct Averager {
diff --git a/src/main.cpp b/src/main.cpp
index 1052e94..640fba2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,3 @@
-#define RENDERBUG_VERSION 1
-
#include "Arduino.h"
#include
@@ -10,13 +8,14 @@
#include
#endif
-#include "BootOptions.h"
+#include "Platform.h"
#include "Static.h"
#include "Config.h"
#include "colors.h"
#include "Sequencer.h"
+#include "LogService.h"
#include "animations/Power.cpp"
#include "animations/SolidAnimation.cpp"
@@ -62,16 +61,6 @@ Display neckDisplay(leds, HardwareConfig::MAX_LED_NUM, &neckMap);
// Setup power management
Power power;
-// Clip the display at whatever is configured while still showing over-paints
-FigmentFunc displayClip([](Display* dpy) {
- auto coords = Static::instance()->coordMap();
- for(int i = 0; i < HardwareConfig::MAX_LED_NUM; i++) {
- if (i < coords->startPixel || i > coords->pixelCount + coords->startPixel) {
- dpy->pixelAt(i) %= 40;
- }
- }
-});
-
FigmentFunc configDisplay([](Display* dpy) {
uint8_t brightness = brighten8_video(beatsin8(60));
auto coords = Static::instance()->coordMap();
@@ -112,23 +101,39 @@ InputBlip inputBlip;
class ArduinoOTAUpdater : public BufferedInputSource {
public:
ArduinoOTAUpdater() : BufferedInputSource("ArduinoOTA") {
- ArduinoOTA.onStart(&ArduinoOTAUpdater::s_onStart).onProgress(&ArduinoOTAUpdater::s_onProgress);
+ ArduinoOTA.onStart(&ArduinoOTAUpdater::s_onStart);
+ ArduinoOTA.onProgress(&ArduinoOTAUpdater::s_onProgress);
}
void loop() override {
- ArduinoOTA.handle();
+ if (m_online) {
+ ArduinoOTA.handle();
+ }
BufferedInputSource::loop();
}
+
+ void handleEvent(const InputEvent& evt) {
+ if (evt.intent == InputEvent::NetworkStatus) {
+ Log.notice("Booting OTA");
+ m_online = true;
+ ArduinoOTA.begin();
+ }
+ }
private:
+ bool m_online = false;
static void s_onStart() {
+ Log.notice("OTA Start!");
Static::instance()->setEvent(InputEvent::FirmwareUpdate);
}
static void s_onProgress(unsigned int progress, unsigned int total) {
+ Log.notice("OTA Progress! %d / %d", progress, total);
Static::instance()->setEvent(InputEvent{InputEvent::FirmwareUpdate, progress});
}
};
+STATIC_ALLOC(ArduinoOTAUpdater);
+
InputFunc randomPulse([]() {
static unsigned int pulse = 0;
EVERY_N_MILLISECONDS(25) {
@@ -158,6 +163,8 @@ InputMapper keyMap([](const InputEvent& evt) {
case Buttons::Cross:
return InputEvent::UserInput;
break;
+ default:
+ break;
}
}
return InputEvent::None;
@@ -189,7 +196,6 @@ Renderer renderer{
&solid,
&flashlight,
Static::instance(),
- &displayClip,
&inputBlip,
&power,
}
@@ -249,6 +255,8 @@ public:
//Log.info("Save...");
setEvent(InputEvent::SaveConfigurationRequest);
break;
+ default:
+ break;
}
}
}
@@ -265,6 +273,8 @@ private:
case InputEvent::SetDisplayOffset:
current = Static::instance()->coordMap()->startPixel;
break;
+ default:
+ break;
}
setEvent(InputEvent{m_currentIntent, current - 1});
}
@@ -278,6 +288,8 @@ private:
case InputEvent::SetDisplayOffset:
current = Static::instance()->coordMap()->startPixel;
break;
+ default:
+ break;
}
setEvent(InputEvent{m_currentIntent, current + 1});
}
@@ -288,22 +300,12 @@ private:
return InputEvent::SetDisplayOffset;
case InputEvent::SetDisplayOffset:
return InputEvent::SetDisplayLength;
+ default:
+ return InputEvent::None;
}
}
};
-enum Phase {
- Null,
- AstronomicalDay,
- NauticalDay,
- CivilDay,
- CivilNight,
- NauticalNight,
- AstronomicalNight,
- Evening,
- Bedtime,
-};
-
struct ScheduleEntry {
uint8_t hour;
uint8_t brightness;
@@ -358,28 +360,32 @@ uint8_t brightnessForTime(uint8_t hour, uint8_t minute) {
return lerp8by8(start.brightness, end.brightness, frac);
}
-WiFiUDP wifiUdp;
-NTP ntp(wifiUdp);
+class CircadianRhythm : public InputSource {
+ private:
+ bool needsUpdate = true;
+ public:
+ CircadianRhythm() : InputSource("CircadianRhythm") {}
-InputFunc circadianRhythm([]() {
- static bool needsUpdate = true;
+ InputEvent read() {
EVERY_N_SECONDS(60) {
needsUpdate = true;
}
-#ifdef PLATFORM_PHOTON
- if (Time.isValid() && needsUpdate) {
- needsUpdate = false;
- return InputEvent{InputEvent::SetBrightness, brightnessForTime(Time.hour(), Time.minute())};
+ if (needsUpdate) {
+ uint8_t hour = 0;
+ uint8_t minute = 0;
+ needsUpdate = false;
+ struct tm timeinfo;
+ Platform::getLocalTime(&timeinfo);
+ hour = timeinfo.tm_hour;
+ minute = timeinfo.tm_min;
+ Log.notice("Current time: %d:%d", hour, minute);
+ return InputEvent{InputEvent::SetBrightness, brightnessForTime(hour, minute)};
+ }
+ return InputEvent{};
}
-#else
- ntp.update();
- if (needsUpdate) {
- needsUpdate = false;
- return InputEvent{InputEvent::SetBrightness, brightnessForTime(ntp.hours(), ntp.minutes())};
- }
-#endif
- return InputEvent{};
-}, "CircadianRhythm", Task::Running);
+};
+
+STATIC_ALLOC(CircadianRhythm);
// A special mainloop app for configuring hardware settings that reboots the
// device when the user is finished.
@@ -393,11 +399,14 @@ MainLoop configApp{{
#endif
// Read hardware inputs
- new Buttons(),
+ Static::instance(),
// Map input buttons to configuration commands
new ConfigInputTask(),
+ // System logging
+ Static::instance(),
+
// Fill the entire display with a color, to see size
&configDisplay,
// Render some basic input feedback
@@ -409,10 +418,11 @@ MainLoop configApp{{
// Turn on,
MainLoop renderbugApp{{
- // Load/update graphics configuration from EEPROM and Particle
+ // Load/update graphics configuration from EEPROM
Static::instance(),
// Platform inputs
+ // TODO: Merge cloud and esp wifi tasks into a common networking base
#ifdef PLATFORM_PHOTON
// Particle cloud status
Static::instance(),
@@ -424,9 +434,12 @@ MainLoop renderbugApp{{
Static::instance(),
#endif
+ // System logging
+ Static::instance(),
+
// Hardware drivers
- //new MPU5060(),
- //new Buttons(),
+ Static::instance(),
+ Static::instance(),
// Map buttons to events
&keyMap,
@@ -435,7 +448,7 @@ MainLoop renderbugApp{{
&sequencer,
// Daily rhythm activities
- &circadianRhythm,
+ Static::instance(),
// Periodic motion input
&randomPulse,
@@ -454,7 +467,6 @@ MainLoop renderbugApp{{
// Update UI layer
&power,
- &displayClip,
Static::instance(),
&inputBlip,
@@ -462,6 +474,9 @@ MainLoop renderbugApp{{
&renderer,
// Platform telemetry
+ // TODO: Combine some of these services into a unified telemetry API with
+ // platform-specific backends?
+ // Or at least, just the MQTT and watchdog ones.
#ifdef PLATFORM_PHOTON
// Update photon telemetry
Static::instance(),
@@ -480,63 +495,33 @@ MainLoop renderbugApp{{
#else
// MQTT
Static::instance(),
+
+ // OTA Updates
+ Static::instance(),
#endif
}};
MainLoop &runner = renderbugApp;
-#ifdef PLATFORM_PHOTON
-STARTUP(BootOptions::initPins());
-retained BootOptions bootopts;
-#else
-BootOptions bootopts;
-
-void printNewline(Print* logOutput) {
- logOutput->print("\r\n");
-}
-#endif
-
// Tune in,
void setup() {
- Serial.begin(115200);
-#ifdef PLATFORM_PHOTON
- System.enableFeature(FEATURE_RETAINED_MEMORY);
- if (bootopts.isFlash) {
- System.dfu();
- }
- if (bootopts.isSerial) {
- bootopts.waitForRelease();
- while(!Serial.isConnected()) {
- Particle.process();
- }
- //Log.info("\xf0\x9f\x94\x8c Serial connected");
- }
-#else
- Log.begin(LOG_LEVEL_VERBOSE, &Serial, true);
- Log.setSuffix(printNewline);
- Log.notice("Test log?");
-#endif
+ Platform::preSetup();
+ Static::instance()->setSequencer(&sequencer);
Log.notice(u8"🐛 Booting Renderbug!");
Log.notice(u8"🐞 I am built for %d LEDs running on %dmA", HardwareConfig::MAX_LED_NUM, PSU_MILLIAMPS);
-#ifdef PLATFORM_PHOTON
- Log.notice(u8"📡 Particle version %s", System.version().c_str());
-#endif
- Log.notice(u8" Boot pin configuration:");
- Log.notice(u8" 2: Setup - %d", bootopts.isSetup);
- Log.notice(u8" 3: Serial - %d", bootopts.isSerial);
- Log.notice(u8" 4: Flash - %d", bootopts.isFlash);
+ Log.notice(u8"📡 Platform %s version %s", Platform::name(), Platform::version());
+ Platform::bootSplash();
- //Log.info(u8" Setting timezone to UTC-7");
- //Time.zone(-7);
+ Log.notice(u8"Setting timezone to -7 (PST)");
+ Platform::setTimezone(-7);
+
+ Log.notice(u8" Setting up platform...");
+ Platform::setup();
Log.notice(u8"💡 Starting FastLED...");
-#ifdef PLATFORM_PHOTON
- FastLED.addLeds(leds, HardwareConfig::MAX_LED_NUM);
-#else
- FastLED.addLeds(leds, HardwareConfig::MAX_LED_NUM);
-#endif
+ Platform::addLEDs(leds, HardwareConfig::MAX_LED_NUM);
- if (bootopts.isSetup) {
+ if (Platform::bootopts.isSetup) {
Log.notice(u8"🌌 Starting Figment in configuration mode...");
runner = configApp;
} else {
@@ -548,8 +533,6 @@ void setup() {
//Log.info(u8"💽 %lu bytes of free RAM", System.freeMemory());
Log.notice(u8"🚀 Setup complete! Ready to rock and roll.");
Serial.flush();
- ntp.begin();
- ArduinoOTA.begin();
}
// Drop out.
diff --git a/src/platform/arduino/MQTTTelemetry.cpp b/src/platform/arduino/MQTTTelemetry.cpp
new file mode 100644
index 0000000..c390e81
--- /dev/null
+++ b/src/platform/arduino/MQTTTelemetry.cpp
@@ -0,0 +1,230 @@
+#include "MQTTTelemetry.h"
+
+#ifdef BOARD_ESP8266
+#include
+#elif defined(BOARD_ESP32)
+#include
+#endif
+
+#include
+
+#include "../../Static.h"
+#include "../../Config.h"
+#include "../../Platform.h"
+
+WiFiClient wifiClient;
+
+MQTTTelemetry::MQTTTelemetry() : BufferedInputSource("MQTT"),
+ m_mqtt(PubSubClient(wifiClient)),
+ m_logPrinter(this)
+{}
+
+void
+MQTTTelemetry::handleEventOnline(const InputEvent& evt)
+{
+ if (!m_mqtt.connected()) {
+ Log.notice("Connecting to MQTT...");
+ const IPAddress server(10, 0, 0, 2);
+ const char* deviceID = Platform::deviceID();
+ Log.verbose("Device ID %s", deviceID);
+ m_mqtt.setServer(server, 1883);
+ m_mqtt.setBufferSize(512);
+ m_mqtt.setCallback(&MQTTTelemetry::s_callback);
+ if (m_mqtt.connect(deviceID)) {
+ Log.notice("Connected to MQTT");
+ m_needHeartbeat = true;
+
+ const String deviceName = String("Renderbug ESP8266") + (char*)deviceID;
+ const String rootTopic = String("homeassistant/light/renderbug/") + (char*)deviceID;
+ const String configTopic = rootTopic + "/config";
+ Log.verbose("root topic %s", rootTopic.c_str());
+ Log.verbose("config topic %s", configTopic.c_str());
+ const String statTopic = rootTopic + "/state";
+ const String cmdTopic = rootTopic + "/set";
+ const String attrTopic = rootTopic + "/attributes";
+ const String logTopic = rootTopic + "/log";
+ const String heartbeatTopic = rootTopic + "/heartbeat";
+ strcpy(m_statTopic, statTopic.c_str());
+ strcpy(m_attrTopic, attrTopic.c_str());
+ strcpy(m_cmdTopic, cmdTopic.c_str());
+ strcpy(m_logTopic, logTopic.c_str());
+ strcpy(m_heartbeatTopic, heartbeatTopic.c_str());
+
+ StaticJsonDocument<1024> configJson;
+ configJson["~"] = rootTopic;
+ configJson["name"] = deviceName;
+ configJson["ret"] = true;
+ configJson["unique_id"] = (char*) deviceID;
+ configJson["cmd_t"] = "~/set";
+ configJson["stat_t"] = "~/state";
+ configJson["json_attr_t"] = "~/attributes";
+ configJson["schema"] = "json";
+ configJson["brightness"] = true;
+ configJson["rgb"] = true;
+
+ int i = 0;
+ for(const Sequencer::Scene& scene : m_sequencer->scenes()) {
+ configJson["fx_list"][i++] = scene.name;
+ }
+
+ configJson["dev"]["name"] = "Renderbug";
+#ifdef PLATFORM_PHOTON
+ configJson["dev"]["mdl"] = "Photon";
+#elif defined(BOARD_ESP32)
+ configJson["dev"]["mdl"] = "ESP32";
+#elif defined(BOARD_ESP8266)
+ configJson["dev"]["mdl"] = "ESP8266";
+#else
+ configJson["dev"]["mdl"] = "Unknown";
+#endif
+ configJson["dev"]["sw"] = RENDERBUG_VERSION;
+ configJson["dev"]["mf"] = "Phong Robotics";
+ configJson["dev"]["ids"][0] = (char*)deviceID;
+ char buf[1024];
+ serializeJson(configJson, buf, sizeof(buf));
+ Log.verbose("Publish %s %s", configTopic.c_str(), buf);
+ m_mqtt.publish(configTopic.c_str(), buf);
+ m_mqtt.subscribe(m_cmdTopic);
+ } else {
+ Log.warning("Could not connect to MQTT");
+ }
+ } else {
+ if (evt.intent == InputEvent::SetPower) {
+ StaticJsonDocument<256> doc;
+ char buf[256];
+ doc["state"] = evt.asInt() ? "ON" : "OFF";
+ serializeJson(doc, buf, sizeof(buf));
+ m_mqtt.publish(m_statTopic, buf);
+ } else if (evt.intent == InputEvent::SetBrightness) {
+ StaticJsonDocument<256> doc;
+ char buf[256];
+ doc["brightness"] = evt.asInt();
+ doc["state"] = "ON";
+ serializeJson(doc, buf, sizeof(buf));
+ m_mqtt.publish(m_statTopic, buf);
+ } else if (evt.intent == InputEvent::SetColor) {
+ StaticJsonDocument<256> doc;
+ char buf[256];
+ CRGB color = evt.asRGB();
+ doc["color"]["r"] = color.r;
+ doc["color"]["g"] = color.g;
+ doc["color"]["b"] = color.b;
+ doc["state"] = "ON";
+ serializeJson(doc, buf, sizeof(buf));
+ m_mqtt.publish(m_statTopic, buf);
+ } else if (evt.intent == InputEvent::SetPattern) {
+ StaticJsonDocument<256> doc;
+ char buf[256];
+ doc["effect"] = evt.asString();
+ doc["state"] = "ON";
+ serializeJson(doc, buf, sizeof(buf));
+ m_mqtt.publish(m_statTopic, buf);
+ } else if (evt.intent == InputEvent::FirmwareUpdate) {
+ m_mqtt.publish("renderbug/debug/firmware", "firmware update!");
+ }
+ }
+}
+
+void
+MQTTTelemetry::loop()
+{
+ BufferedInputSource::loop();
+ OnlineTaskMixin::loop();
+}
+
+void
+MQTTTelemetry::loopOnline()
+{
+ m_mqtt.loop();
+ EVERY_N_SECONDS(10) {
+ m_needHeartbeat = true;
+ }
+ if (m_needHeartbeat) {
+ char buf[512];
+ StaticJsonDocument<512> response;
+ response["fps"] = FastLED.getFPS();
+ response["RSSI"] = WiFi.RSSI();
+ response["localip"] = WiFi.localIP().toString();
+ response["free_ram"] = ESP.getFreeHeap();
+ response["os_version"] = ESP.getSdkVersion();
+ response["sketch_version"] = ESP.getSketchMD5();
+ serializeJson(response, buf, sizeof(buf));
+ m_mqtt.publish(m_attrTopic, buf);
+ m_mqtt.publish(m_heartbeatTopic, buf);
+ Log.notice("Heartbeat: %s", buf);
+
+ response.clear();
+ auto sched = MainLoop::instance()->scheduler;
+ for(auto task : sched.tasks) {
+ response[task->name] = task->state == Task::Running;
+ }
+ serializeJson(response, buf, sizeof(buf));
+ m_mqtt.publish(m_heartbeatTopic, buf);
+ m_needHeartbeat = false;
+ }
+}
+
+void
+MQTTTelemetry::callback(char* topic, byte* payload, unsigned int length)
+{
+ DynamicJsonDocument doc(1024);
+ deserializeJson(doc, payload, length);
+
+ if (doc.containsKey("state")) {
+ if (doc["state"] == "ON") {
+ setEvent(InputEvent{InputEvent::SetPower, true});
+ } else if (doc["state"] == "OFF") {
+ setEvent(InputEvent{InputEvent::SetPower, false});
+ }
+ }
+
+ if (doc.containsKey("start")) {
+ strcpy(m_patternBuf, doc["start"].as());
+ setEvent(InputEvent{InputEvent::StartThing, m_patternBuf});
+ }
+
+ if (doc.containsKey("stop")) {
+ if (doc["stop"] == name) {
+ Log.notice("You can't kill an idea, or stop the MQTT Task via MQTT.");
+ } else {
+ strcpy(m_patternBuf, doc["stop"].as());
+ setEvent(InputEvent{InputEvent::StopThing, m_patternBuf});
+ }
+ }
+
+ if (doc.containsKey("pixelCount")) {
+ setEvent(InputEvent{InputEvent::SetDisplayLength, (int)doc["pixelCount"]});
+ }
+
+ if (doc.containsKey("startPixel")) {
+ setEvent(InputEvent{InputEvent::SetDisplayOffset, (int)doc["startPixel"]});
+ }
+
+ if (doc.containsKey("save")) {
+ setEvent(InputEvent{InputEvent::SaveConfigurationRequest});
+ }
+
+ if (doc.containsKey("effect")) {
+ strcpy(m_patternBuf, doc["effect"].as());
+ setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf});
+ }
+
+ if (doc.containsKey("color")) {
+ uint8_t r = doc["color"]["r"];
+ uint8_t g = doc["color"]["g"];
+ uint8_t b = doc["color"]["b"];
+ setEvent(InputEvent{InputEvent::SetColor, CRGB(r, g, b)});
+ }
+
+ if (doc.containsKey("brightness")) {
+ setEvent(InputEvent{InputEvent::SetBrightness, (int)doc["brightness"]});
+ }
+}
+
+void
+MQTTTelemetry::s_callback(char* topic, byte* payload, unsigned int length)
+{
+ Static::instance()->callback(topic, payload, length);
+}
+
+STATIC_ALLOC(MQTTTelemetry);
diff --git a/src/platform/arduino/MQTTTelemetry.h b/src/platform/arduino/MQTTTelemetry.h
index a676a36..3bc5f8b 100644
--- a/src/platform/arduino/MQTTTelemetry.h
+++ b/src/platform/arduino/MQTTTelemetry.h
@@ -1,163 +1,58 @@
-#include
+#include
+#include
+
#include
#include
-#include
-#include
-WiFiClient wifi;
-PubSubClient m_mqtt(wifi);
+#include "../../Sequencer.h"
class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
public:
- MQTTTelemetry() : BufferedInputSource("MQTT") {}
+ MQTTTelemetry();
+ void setSequencer(Sequencer* seq) { m_sequencer = seq; }
- void handleEventOnline(const InputEvent& evt) override {
- if (!m_mqtt.connected()) {
- Log.notice("Connecting to MQTT...");
- const IPAddress server(10, 0, 0, 2);
- uint64_t chipid = ESP.getEfuseMac();
- char deviceID[15];
- snprintf(deviceID, 15, "%08X", (uint32_t)chipid);
- Log.verbose("Device ID %s", deviceID);
- m_mqtt.setServer(server, 1883);
- m_mqtt.setBufferSize(512);
- m_mqtt.setCallback(&MQTTTelemetry::s_callback);
- if (m_mqtt.connect(deviceID)) {
- Log.notice("Connected to MQTT");
-
- const String deviceName = String("Renderbug ESP32 ") + (char*)deviceID;
- const String rootTopic = String("homeassistant/light/renderbug/") + (char*)deviceID;
- const String configTopic = rootTopic + "/config";
- Log.verbose("root topic %s", rootTopic.c_str());
- Log.verbose("config topic %s", configTopic.c_str());
- const String statTopic = rootTopic + "/state";
- const String cmdTopic = rootTopic + "/set";
- const String attrTopic = rootTopic + "/attributes";
- strcpy(m_statTopic, statTopic.c_str());
- strcpy(m_attrTopic, attrTopic.c_str());
- strcpy(m_cmdTopic, cmdTopic.c_str());
-
- StaticJsonDocument<1024> configJson;
- configJson["~"] = rootTopic;
- configJson["name"] = deviceName;
- configJson["ret"] = true;
- configJson["unique_id"] = (char*) deviceID;
- configJson["cmd_t"] = "~/set";
- configJson["stat_t"] = "~/state";
- configJson["json_attr_t"] = "~/attributes";
- configJson["schema"] = "json";
- configJson["brightness"] = true;
- configJson["rgb"] = true;
-
- configJson["dev"]["name"] = "Renderbug";
-#ifdef PLATFORM_PHOTON
- configJson["dev"]["mdl"] = "Photon";
-#else
- configJson["dev"]["mdl"] = "ESP32";
-#endif
- configJson["dev"]["sw"] = RENDERBUG_VERSION;
- configJson["dev"]["mf"] = "Phong Robotics";
- configJson["dev"]["ids"][0] = (char*)deviceID;
- char buf[1024];
- serializeJson(configJson, buf, sizeof(buf));
- Log.verbose("Publish %s %s", configTopic.c_str(), buf);
- m_mqtt.publish(configTopic.c_str(), buf);
- m_mqtt.subscribe(m_cmdTopic);
- } else {
- Log.warning("Could not connect to MQTT");
+ class LogPrinter : public Print {
+ private:
+ MQTTTelemetry* telemetry;
+ Ringbuf buf;
+ public:
+ LogPrinter(MQTTTelemetry* telemetry) : telemetry(telemetry) {};
+ size_t write(uint8_t byte) {
+ char outBuf[512];
+ if (byte == '\n') {
+ size_t bufSize = buf.write(outBuf);
+ outBuf[std::min(sizeof(outBuf), bufSize)] = 0;
+ telemetry->m_mqtt.publish(telemetry->m_logTopic, outBuf);
+ } else {
+ buf.insert(byte);
+ }
+ return sizeof(byte);
}
- } else {
- if (evt.intent == InputEvent::SetPower) {
- StaticJsonDocument<256> doc;
- char buf[256];
- doc["state"] = evt.asInt() ? "ON" : "OFF";
- serializeJson(doc, buf, sizeof(buf));
- m_mqtt.publish(m_statTopic, buf);
- } else if (evt.intent == InputEvent::SetBrightness) {
- StaticJsonDocument<256> doc;
- char buf[256];
- doc["brightness"] = evt.asInt();
- serializeJson(doc, buf, sizeof(buf));
- m_mqtt.publish(m_statTopic, buf);
- } else if (evt.intent == InputEvent::SetColor) {
- StaticJsonDocument<256> doc;
- char buf[256];
- CRGB color = evt.asRGB();
- doc["color"]["r"] = color.r;
- doc["color"]["g"] = color.g;
- doc["color"]["b"] = color.b;
- serializeJson(doc, buf, sizeof(buf));
- m_mqtt.publish(m_statTopic, buf);
- } else if (evt.intent == InputEvent::SetPattern) {
- StaticJsonDocument<256> doc;
- char buf[256];
- doc["effect"] = evt.asString();
- serializeJson(doc, buf, sizeof(buf));
- m_mqtt.publish(m_statTopic, buf);
- }
- }
+ };
+
+ Print* logPrinter() {
+ return &m_logPrinter;
}
- void loop() override {
- BufferedInputSource::loop();
- OnlineTaskMixin::loop();
- }
+ void handleEventOnline(const InputEvent& evt) override;
+ void loop() override;
- void loopOnline() override {
- m_mqtt.loop();
- EVERY_N_SECONDS(10) {
- char buf[254];
- StaticJsonDocument<200> response;
- response["fps"] = FastLED.getFPS();
- response["RSSI"] = WiFi.RSSI();
- response["localip"] = WiFi.localIP().toString();
- response["free_ram"] = ESP.getFreeHeap();
- response["os_version"] = ESP.getSdkVersion();
- response["sketch_version"] = ESP.getSketchMD5();
- serializeJson(response, buf, sizeof(buf));
- m_mqtt.publish(m_attrTopic, buf);
- }
- }
+ void loopOnline() override;
private:
char m_statTopic[100];
char m_attrTopic[100];
char m_cmdTopic[100];
+ char m_logTopic[100];
+ char m_heartbeatTopic[100];
- void callback(char* topic, byte* payload, unsigned int length) {
- DynamicJsonDocument doc(1024);
- deserializeJson(doc, payload, length);
-
- if (doc.containsKey("state")) {
- if (doc["state"] == "ON") {
- setEvent(InputEvent{InputEvent::SetPower, true});
- } else if (doc["state"] == "OFF") {
- setEvent(InputEvent{InputEvent::SetPower, false});
- }
- }
-
- if (doc.containsKey("effect")) {
- strcpy(m_patternBuf, doc["effect"].as());
- setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf});
- }
-
- if (doc.containsKey("color")) {
- uint8_t r = doc["color"]["r"];
- uint8_t g = doc["color"]["g"];
- uint8_t b = doc["color"]["b"];
- setEvent(InputEvent{InputEvent::SetColor, CRGB(r, g, b)});
- }
-
- if (doc.containsKey("brightness")) {
- setEvent(InputEvent{InputEvent::SetBrightness, (int)doc["brightness"]});
- }
- }
-
- static void s_callback(char* topic, byte* payload, unsigned int length) {
- Static::instance()->callback(topic, payload, length);
- }
+ void callback(char* topic, byte* payload, unsigned int length);
+ static void s_callback(char* topic, byte* payload, unsigned int length);
char m_patternBuf[48];
-};
+ bool m_needHeartbeat = false;
-STATIC_ALLOC(MQTTTelemetry);
+ Sequencer *m_sequencer = 0;
+ PubSubClient m_mqtt;
+ LogPrinter m_logPrinter;
+};
diff --git a/src/platform/particle/PhotonTelemetry.cpp b/src/platform/particle/PhotonTelemetry.cpp
index 2315cbe..2ef2d89 100644
--- a/src/platform/particle/PhotonTelemetry.cpp
+++ b/src/platform/particle/PhotonTelemetry.cpp
@@ -57,108 +57,12 @@ PhotonTelemetry::loop()
void
PhotonTelemetry::handleEvent(const InputEvent &evt)
{
- Serial.flush();
- if (evt.intent == InputEvent::NetworkStatus) {
- onConnected();
- }
- if (evt.intent != InputEvent::None) {
- const char* sourceName;
- switch(evt.intent) {
- case InputEvent::PowerToggle:
- sourceName = "power-toggle";
- break;
- case InputEvent::SetPower:
- sourceName = "set-power";
- break;
- case InputEvent::PreviousPattern:
- sourceName = "previous-pattern";
- break;
- case InputEvent::NextPattern:
- sourceName = "next-pattern";
- break;
- case InputEvent::SetPattern:
- sourceName = "set-pattern";
- break;
- case InputEvent::SetColor:
- sourceName = "set-color";
- break;
- case InputEvent::Acceleration:
- sourceName = "acceleration";
- break;
- case InputEvent::UserInput:
- sourceName = "user";
- break;
- case InputEvent::SetBrightness:
- sourceName = "set-brightness";
- break;
- case InputEvent::FirmwareUpdate:
- sourceName = "firmware-update";
- break;
- case InputEvent::NetworkStatus:
- sourceName = "network-status";
- break;
- case InputEvent::NetworkActivity:
- sourceName = "network-activity";
- break;
- case InputEvent::StartThing:
- sourceName = "start-thing";
- break;
- case InputEvent::StopThing:
- sourceName = "stop-thing";
- break;
- case InputEvent::SetDisplayOffset:
- sourceName = "set-display-offset";
- break;
- case InputEvent::SetDisplayLength:
- sourceName = "set-display-length";
- break;
- case InputEvent::SaveConfigurationRequest:
- sourceName = "save-configuration";
- break;
- default:
- sourceName = 0;
- break;
- }
- char valueBuf[255];
- switch(evt.type) {
- case InputEvent::Null:
- snprintf(valueBuf, sizeof(valueBuf), "null");break;
- case InputEvent::Integer:
- snprintf(valueBuf, sizeof(valueBuf), "%d %02x", evt.asInt(), evt.asInt());break;
- case InputEvent::String:
- snprintf(valueBuf, sizeof(valueBuf), "\"%s\"", evt.asString());break;
- case InputEvent::Color:
- snprintf(valueBuf, sizeof(valueBuf), "[%d, %d, %d]", evt.asRGB().r, evt.asRGB().g, evt.asRGB().b);break;
- }
- char buf[255 * 2];
- if (sourceName == 0) {
- snprintf(buf, sizeof(buf), "{\"intent\": %d, \"value\": %s}", evt.intent, valueBuf);
- } else {
- snprintf(buf, sizeof(buf), "{\"intent\": \"%s\", \"value\": %s}", sourceName, valueBuf);
- }
- if (m_online) {
- if (evt.intent != m_lastEvent.intent) {
- if (m_duplicateEvents > 0) {
- Log.info("Suppressed reporting %ld duplicate events.", m_duplicateEvents);
- }
- Log.info("Event: %s", buf);
- m_duplicateEvents = 0;
- m_lastEvent = evt;
- Particle.publish("renderbug/event", buf, PRIVATE);
- } else {
- m_duplicateEvents++;
- }
- } else {
- Log.info("[offline] Event: %s", buf);
- }
-
- if (evt.intent == InputEvent::SetColor) {
- NSFastLED::CRGB rgb {evt.asRGB()};
- uint32_t color = (rgb.r << 16) + (rgb.g << 8) + (rgb.b << 0);
- m_ledStatus.setColor(color);
- m_ledStatus.setActive(true);
- m_rgbPulseFrame = 1000;
- }
+ if (evt.intent == InputEvent::SetColor) {
+ NSFastLED::CRGB rgb {evt.asRGB()};
+ uint32_t color = (rgb.r << 16) + (rgb.g << 8) + (rgb.b << 0);
+ m_ledStatus.setColor(color);
+ m_ledStatus.setActive(true);
+ m_rgbPulseFrame = 1000;
}
}