If the code hasn't been touched in this long, its probably release-worthy.
This commit is contained in:
@@ -26,7 +26,7 @@ BluetoothSerialTelemetry::read()
|
||||
// Overwrite the '*' character, to leave us with a complete command
|
||||
commandBuf[cmdSize-1] = 0;
|
||||
|
||||
//Log.notice("Bluetooth read %s", commandBuf);
|
||||
Log.verbose("Bluetooth read %s", commandBuf);
|
||||
|
||||
if (commandBuf[0] == 'R') {
|
||||
m_color = CRGB(std::atoi(&commandBuf[1]), m_color.g, m_color.b);
|
||||
@@ -49,6 +49,12 @@ BluetoothSerialTelemetry::read()
|
||||
return InputEvent{InputEvent::SetPower, 0};
|
||||
} else if (commandBuf[0] == 'p') {
|
||||
return InputEvent{InputEvent::SetPattern, &commandBuf[1]};
|
||||
} else if (commandBuf[0] == 'b') {
|
||||
return InputEvent::BeatDetect;
|
||||
} else if (commandBuf[0] == 'c') {
|
||||
return InputEvent{InputEvent::SetDisplayLength, std::atoi(&commandBuf[1])};
|
||||
} else if (commandBuf[0] == 'Y') {
|
||||
return InputEvent::SaveConfigurationRequest;
|
||||
} else if (commandBuf[0] == 'A') {
|
||||
char* axisVal = strtok(&commandBuf[1], ",");
|
||||
const uint8_t accelX = std::atof(axisVal) * 10;
|
||||
@@ -75,12 +81,13 @@ BluetoothSerialTelemetry::read()
|
||||
void
|
||||
BluetoothSerialTelemetry::onStart()
|
||||
{
|
||||
Log.notice("Starting up Bluetooth...");
|
||||
Log.trace("Starting up Bluetooth...");
|
||||
if (m_serial.begin(Platform::deviceName())) {
|
||||
Log.notice("Bluetooth started!");
|
||||
Log.notice("Bluetooth started! Device name is %s", Platform::deviceName());
|
||||
} else {
|
||||
Log.warning("Bluetooth could not be started!");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_ALLOC(BluetoothSerialTelemetry);
|
||||
STATIC_TASK(BluetoothSerialTelemetry);
|
||||
|
@@ -117,39 +117,37 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
|
||||
Log.notice("Connected to MQTT");
|
||||
m_needHeartbeat = true;
|
||||
|
||||
StaticJsonDocument<1024> configJson;
|
||||
|
||||
Lightswitch.toJson(configJson);
|
||||
m_json.clear();
|
||||
Lightswitch.toJson(m_json);
|
||||
|
||||
int i = 0;
|
||||
for(const Sequencer::Scene& scene : m_sequencer->scenes()) {
|
||||
configJson["fx_list"][i++] = scene.name;
|
||||
m_json["fx_list"][i++] = scene.name;
|
||||
}
|
||||
configJson["brightness"] = true;
|
||||
configJson["rgb"] = true;
|
||||
m_json["brightness"] = true;
|
||||
m_json["rgb"] = true;
|
||||
|
||||
char buf[1024];
|
||||
serializeJson(configJson, buf, sizeof(buf));
|
||||
publishDoc(Lightswitch.configTopic().c_str(), true);
|
||||
|
||||
Log.verbose("Publish %s %s", Lightswitch.configTopic().c_str(), buf);
|
||||
m_mqtt.publish(Lightswitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
||||
//Log.verbose("Publish %s %s", Lightswitch.configTopic().c_str(), buf);
|
||||
//m_mqtt.publish(Lightswitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
||||
m_mqtt.subscribe(Lightswitch.commandTopic().c_str());
|
||||
|
||||
configJson.clear();
|
||||
flashlightSwitch.toJson(configJson, false);
|
||||
configJson["cmd_t"] = "~/set";
|
||||
configJson["ret"] = true;
|
||||
serializeJson(configJson, buf, sizeof(buf));
|
||||
m_mqtt.publish(flashlightSwitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
||||
m_json.clear();
|
||||
flashlightSwitch.toJson(m_json, false);
|
||||
m_json["cmd_t"] = "~/set";
|
||||
m_json["ret"] = true;
|
||||
publishDoc(flashlightSwitch.configTopic().c_str(), true);
|
||||
//m_mqtt.publish(flashlightSwitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
||||
m_mqtt.subscribe(flashlightSwitch.commandTopic().c_str());
|
||||
|
||||
configJson.clear();
|
||||
FPSSensor.toJson(configJson, false);
|
||||
configJson["unit_of_meas"] = "Frames/s";
|
||||
serializeJson(configJson, buf, sizeof(buf));
|
||||
m_json.clear();
|
||||
FPSSensor.toJson(m_json, false);
|
||||
m_json["unit_of_meas"] = "Frames/s";
|
||||
publishDoc(FPSSensor.configTopic().c_str(), true);
|
||||
|
||||
Log.verbose("Publish %s %s", FPSSensor.configTopic().c_str(), buf);
|
||||
m_mqtt.publish(FPSSensor.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
||||
//Log.verbose("Publish %s %s", FPSSensor.configTopic().c_str(), buf);
|
||||
//m_mqtt.publish(FPSSensor.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
||||
m_mqtt.subscribe(FPSSensor.commandTopic().c_str());
|
||||
|
||||
#ifdef BOARD_ESP8266
|
||||
@@ -172,39 +170,28 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
|
||||
String flashlightStatTopic = flashlightSwitch.statTopic();
|
||||
m_mqtt.publish(flashlightStatTopic.c_str(), "ON");
|
||||
} else if (evt.intent == InputEvent::SetPower) {
|
||||
StaticJsonDocument<256> doc;
|
||||
char buf[256];
|
||||
m_json.clear();
|
||||
m_isOn = evt.asInt() ? true : false;
|
||||
doc["state"] = m_isOn ? "ON" : "OFF";
|
||||
serializeJson(doc, buf, sizeof(buf));
|
||||
m_mqtt.publish(statTopic.c_str(), buf);
|
||||
m_json["state"] = m_isOn ? "ON" : "OFF";
|
||||
publishDoc(statTopic.c_str());
|
||||
} else if (evt.intent == InputEvent::SetBrightness) {
|
||||
StaticJsonDocument<256> doc;
|
||||
char buf[256];
|
||||
doc["brightness"] = evt.asInt();
|
||||
doc["state"] = m_isOn ? "ON" : "OFF";
|
||||
serializeJson(doc, buf, sizeof(buf));
|
||||
m_mqtt.publish(statTopic.c_str(), buf);
|
||||
m_json.clear();
|
||||
m_json["brightness"] = evt.asInt();
|
||||
m_json["state"] = m_isOn ? "ON" : "OFF";
|
||||
publishDoc(statTopic.c_str());
|
||||
} 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"] = m_isOn ? "ON" : "OFF";
|
||||
serializeJson(doc, buf, sizeof(buf));
|
||||
m_mqtt.publish(statTopic.c_str(), buf);
|
||||
m_json.clear();
|
||||
m_json["color"]["r"] = color.r;
|
||||
m_json["color"]["g"] = color.g;
|
||||
m_json["color"]["b"] = color.b;
|
||||
m_json["state"] = m_isOn ? "ON" : "OFF";
|
||||
publishDoc(statTopic.c_str());
|
||||
} else if (evt.intent == InputEvent::SetPattern) {
|
||||
StaticJsonDocument<256> doc;
|
||||
char buf[256];
|
||||
doc["effect"] = evt.asString();
|
||||
doc["state"] = m_isOn ? "ON" : "OFF";
|
||||
serializeJson(doc, buf, sizeof(buf));
|
||||
m_mqtt.publish(statTopic.c_str(), buf);
|
||||
} else if (evt.intent == InputEvent::FirmwareUpdate) {
|
||||
String updateTopic = m_debugTopic + "/firmware";
|
||||
m_mqtt.publish(updateTopic.c_str(), "firmware update!");
|
||||
m_json.clear();
|
||||
m_json["effect"] = evt.asString();
|
||||
m_json["state"] = m_isOn ? "ON" : "OFF";
|
||||
publishDoc(statTopic.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,22 +228,20 @@ MQTTTelemetry::loopOnline()
|
||||
m_needHeartbeat = true;
|
||||
}
|
||||
if (m_needHeartbeat) {
|
||||
char buf[512];
|
||||
StaticJsonDocument<512> response;
|
||||
response["device_id"] = Platform::deviceID();
|
||||
response["sketch_version"] = ESP.getSketchMD5();
|
||||
response["os_version"] = ESP.getSdkVersion();
|
||||
response["localip"] = WiFi.localIP().toString();
|
||||
response["pixelCount"] = Static<ConfigService>::instance()->coordMap()->pixelCount;
|
||||
response["startPixel"] = Static<ConfigService>::instance()->coordMap()->startPixel;
|
||||
response["RSSI"] = WiFi.RSSI();
|
||||
response["free_ram"] = ESP.getFreeHeap();
|
||||
response["fps"] = FastLED.getFPS();
|
||||
serializeJson(response, buf, sizeof(buf));
|
||||
m_json.clear();
|
||||
m_json["device_id"] = Platform::deviceID();
|
||||
m_json["sketch_version"] = ESP.getSketchMD5();
|
||||
m_json["os_version"] = ESP.getSdkVersion();
|
||||
m_json["localip"] = WiFi.localIP().toString();
|
||||
m_json["pixelCount"] = Static<ConfigService>::instance()->coordMap()->physicalPixelCount();
|
||||
//m_json["startPixel"] = Static<ConfigService>::instance()->coordMap()->startPixel;
|
||||
m_json["RSSI"] = WiFi.RSSI();
|
||||
m_json["free_ram"] = ESP.getFreeHeap();
|
||||
m_json["fps"] = FastLED.getFPS();
|
||||
String availTopic = m_rootTopic + "/available";
|
||||
m_mqtt.publish(Lightswitch.heartbeatTopic().c_str(), buf);
|
||||
publishDoc(Lightswitch.heartbeatTopic().c_str());
|
||||
m_mqtt.publish(Device.availabilityTopic.c_str(), "online");
|
||||
//Log.notice("Heartbeat: %s", buf);
|
||||
//Log.trace("Heartbeat: %s", buf);
|
||||
|
||||
String fpsCounter = String(FastLED.getFPS());
|
||||
m_mqtt.publish(FPSSensor.statTopic().c_str(), fpsCounter.c_str());
|
||||
@@ -280,89 +265,106 @@ MQTTTelemetry::callback(char* topic, const char* payload)
|
||||
setEvent(InputEvent{InputEvent::SetPattern, "Idle"});
|
||||
}
|
||||
} else if (Lightswitch.isCommandTopic(topic)) {
|
||||
StaticJsonDocument<512> doc;
|
||||
deserializeJson(doc, payload);
|
||||
deserializeJson(m_json, payload);
|
||||
|
||||
if (doc.containsKey("state")) {
|
||||
if (doc["state"] == "ON") {
|
||||
if (m_json.containsKey("state")) {
|
||||
if (m_json["state"] == "ON") {
|
||||
Log.notice("Turning on power");
|
||||
setEvent(InputEvent{InputEvent::SetPower, true});
|
||||
} else if (doc["state"] == "OFF") {
|
||||
} else if (m_json["state"] == "OFF") {
|
||||
Log.notice("Turning off power");
|
||||
setEvent(InputEvent{InputEvent::SetPattern, "Idle"});
|
||||
setEvent(InputEvent{InputEvent::SetPower, false});
|
||||
}
|
||||
}
|
||||
|
||||
if (doc.containsKey("start")) {
|
||||
strcpy(m_patternBuf, doc["start"].as<const char*>());
|
||||
if (m_json.containsKey("start")) {
|
||||
strcpy(m_patternBuf, m_json["start"].as<const char*>());
|
||||
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.");
|
||||
if (m_json.containsKey("stop")) {
|
||||
if (m_json["stop"] == name) {
|
||||
Log.warning("You can't kill an idea, or stop the MQTT Task via MQTT.");
|
||||
} else {
|
||||
strcpy(m_patternBuf, doc["stop"].as<const char*>());
|
||||
strcpy(m_patternBuf, m_json["stop"].as<const char*>());
|
||||
setEvent(InputEvent{InputEvent::StopThing, m_patternBuf});
|
||||
}
|
||||
}
|
||||
|
||||
if (doc.containsKey("pixelCount")) {
|
||||
setEvent(InputEvent{InputEvent::SetDisplayLength, (int)doc["pixelCount"]});
|
||||
if (m_json.containsKey("pixelCount")) {
|
||||
Log.notice("Pixel count changed");
|
||||
setEvent(InputEvent{InputEvent::SetDisplayLength, m_json["pixelCount"].as<int>()});
|
||||
}
|
||||
|
||||
if (doc.containsKey("startPixel")) {
|
||||
setEvent(InputEvent{InputEvent::SetDisplayOffset, (int)doc["startPixel"]});
|
||||
if (m_json.containsKey("startPixel")) {
|
||||
Log.notice("Start pixel changed");
|
||||
setEvent(InputEvent{InputEvent::SetDisplayOffset, m_json["startPixel"].as<int>()});
|
||||
}
|
||||
|
||||
if (doc.containsKey("save")) {
|
||||
if (m_json.containsKey("save")) {
|
||||
setEvent(InputEvent{InputEvent::SaveConfigurationRequest});
|
||||
}
|
||||
|
||||
if (doc.containsKey("restart")) {
|
||||
#ifdef BOARD_ESP8266
|
||||
ESP.wdtDisable();
|
||||
ESP.restart();
|
||||
#endif
|
||||
if (m_json.containsKey("restart")) {
|
||||
Platform::restart();
|
||||
}
|
||||
|
||||
if (doc.containsKey("reconnect")) {
|
||||
if (m_json.containsKey("reconnect")) {
|
||||
m_mqtt.disconnect();
|
||||
}
|
||||
|
||||
if (doc.containsKey("ping")) {
|
||||
if (m_json.containsKey("ping")) {
|
||||
m_needHeartbeat = true;
|
||||
Log.notice("Queuing up heartbeat");
|
||||
}
|
||||
|
||||
if (doc.containsKey("effect")) {
|
||||
strcpy(m_patternBuf, doc["effect"].as<const char*>());
|
||||
if (m_json.containsKey("effect")) {
|
||||
strcpy(m_patternBuf, m_json["effect"].as<const char*>());
|
||||
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"];
|
||||
if (m_json.containsKey("color")) {
|
||||
uint8_t r = m_json["color"]["r"];
|
||||
uint8_t g = m_json["color"]["g"];
|
||||
uint8_t b = m_json["color"]["b"];
|
||||
setEvent(InputEvent{InputEvent::SetColor, CRGB(r, g, b)});
|
||||
}
|
||||
|
||||
if (doc.containsKey("brightness")) {
|
||||
setEvent(InputEvent{InputEvent::SetBrightness, (int)doc["brightness"]});
|
||||
if (m_json.containsKey("brightness")) {
|
||||
setEvent(InputEvent{InputEvent::SetBrightness, m_json["brightness"].as<int>()});
|
||||
}
|
||||
|
||||
Log.notice("Event done.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MQTTTelemetry::s_callback(char* topic, byte* payload, unsigned int length)
|
||||
{
|
||||
char topicBuf[128];
|
||||
char payloadBuf[512];
|
||||
strcpy(topicBuf, topic);
|
||||
memcpy(payloadBuf, payload, length);
|
||||
payloadBuf[std::min(sizeof(payloadBuf) - 1, length)] = 0;
|
||||
Static<MQTTTelemetry>::instance()->callback(topicBuf, payloadBuf);
|
||||
strcpy(s_topicBuf, topic);
|
||||
memcpy(s_payloadBuf, payload, length);
|
||||
s_payloadBuf[std::min(sizeof(s_payloadBuf) - 1, length)] = 0;
|
||||
Static<MQTTTelemetry>::instance()->callback(s_topicBuf, s_payloadBuf);
|
||||
}
|
||||
|
||||
char MQTTTelemetry::s_topicBuf[128] = {0};
|
||||
char MQTTTelemetry::s_payloadBuf[512] = {0};
|
||||
|
||||
void
|
||||
MQTTTelemetry::publishDoc(const char* topic, bool retain)
|
||||
{
|
||||
m_mqtt.beginPublish(topic, measureJson(m_json), retain);
|
||||
serializeJson(m_json, m_mqtt);
|
||||
m_mqtt.endPublish();
|
||||
}
|
||||
|
||||
void
|
||||
MQTTTelemetry::publishDoc(const char* topic)
|
||||
{
|
||||
publishDoc(topic, false);
|
||||
}
|
||||
|
||||
|
||||
STATIC_ALLOC(MQTTTelemetry);
|
||||
STATIC_TASK(MQTTTelemetry);
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
|
||||
public:
|
||||
@@ -25,13 +26,16 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
|
||||
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;
|
||||
Serial.println(outBuf);
|
||||
char c;
|
||||
String logTopic = telemetry->m_debugTopic + "/log";
|
||||
telemetry->m_mqtt.publish(logTopic.c_str(), outBuf);
|
||||
telemetry->m_mqtt.beginPublish(logTopic.c_str(), buf.size(), false);
|
||||
while (buf.take(c)) {
|
||||
Serial.write(c);
|
||||
telemetry->m_mqtt.write(c);
|
||||
}
|
||||
Serial.println();
|
||||
telemetry->m_mqtt.endPublish();
|
||||
} else {
|
||||
buf.insert(byte);
|
||||
}
|
||||
@@ -61,9 +65,15 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
|
||||
char m_patternBuf[48];
|
||||
bool m_needHeartbeat = false;
|
||||
bool m_isOn = true;
|
||||
static char s_topicBuf[128];
|
||||
static char s_payloadBuf[512];
|
||||
|
||||
void publishDoc(const char* topic);
|
||||
void publishDoc(const char* topic, bool retain);
|
||||
|
||||
Sequencer *m_sequencer = 0;
|
||||
WiFiClient m_wifi;
|
||||
PubSubClient m_mqtt;
|
||||
LogPrinter m_logPrinter;
|
||||
StaticJsonDocument<1024> m_json;
|
||||
};
|
||||
|
34
src/platform/arduino/OTA.cpp
Normal file
34
src/platform/arduino/OTA.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "OTA.h"
|
||||
#include "../../Static.h"
|
||||
|
||||
ArduinoOTAUpdater::ArduinoOTAUpdater() : BufferedInputSource("ArduinoOTA") {
|
||||
ArduinoOTA.onStart(&ArduinoOTAUpdater::s_onStart);
|
||||
ArduinoOTA.onProgress(&ArduinoOTAUpdater::s_onProgress);
|
||||
}
|
||||
|
||||
void ArduinoOTAUpdater::loop() {
|
||||
if (m_online) {
|
||||
ArduinoOTA.handle();
|
||||
}
|
||||
BufferedInputSource::loop();
|
||||
}
|
||||
|
||||
void ArduinoOTAUpdater::handleEvent(const InputEvent& evt) {
|
||||
if (evt.intent == InputEvent::NetworkStatus && evt.asInt()) {
|
||||
Log.notice("Booting OTA");
|
||||
m_online = true;
|
||||
ArduinoOTA.begin();
|
||||
}
|
||||
}
|
||||
void ArduinoOTAUpdater::s_onStart() {
|
||||
Log.notice("OTA Start!");
|
||||
Static<ArduinoOTAUpdater>::instance()->setEvent(InputEvent::FirmwareUpdate);
|
||||
}
|
||||
|
||||
void ArduinoOTAUpdater::s_onProgress(unsigned int progress, unsigned int total) {
|
||||
Log.notice("OTA Progress! %d / %d", progress, total);
|
||||
Static<ArduinoOTAUpdater>::instance()->setEvent(InputEvent{InputEvent::FirmwareUpdate, progress});
|
||||
}
|
||||
|
||||
STATIC_ALLOC(ArduinoOTAUpdater);
|
||||
STATIC_TASK(ArduinoOTAUpdater);
|
14
src/platform/arduino/OTA.h
Normal file
14
src/platform/arduino/OTA.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <ArduinoOTA.h>
|
||||
#include <Figments.h>
|
||||
|
||||
class ArduinoOTAUpdater : public BufferedInputSource {
|
||||
public:
|
||||
ArduinoOTAUpdater();
|
||||
void loop() override;
|
||||
void handleEvent(const InputEvent& evt) override;
|
||||
|
||||
private:
|
||||
bool m_online = false;
|
||||
static void s_onStart();
|
||||
static void s_onProgress(unsigned int progress, unsigned int total);
|
||||
};
|
232
src/platform/arduino/U8Display.cpp
Normal file
232
src/platform/arduino/U8Display.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
#include <Figments.h>
|
||||
#include <U8g2lib.h>
|
||||
#include "../../Static.h"
|
||||
#include <ArduinoLog.h>
|
||||
#include "../../LogService.h"
|
||||
|
||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, 16, 15, 4);
|
||||
|
||||
class U8Display : public Task {
|
||||
public:
|
||||
U8Display() : Task("U8Display") {}
|
||||
|
||||
enum ScreenState {
|
||||
BootSplash,
|
||||
Running,
|
||||
Message,
|
||||
Idle = Running
|
||||
};
|
||||
|
||||
void onStart() {
|
||||
xTaskCreatePinnedToCore(
|
||||
&U8Display::redrawTask,
|
||||
name,
|
||||
2000,
|
||||
this,
|
||||
1,
|
||||
&m_renderTask, 0
|
||||
);
|
||||
}
|
||||
|
||||
void handleEvent(const InputEvent& evt) {
|
||||
m_lastEvent = evt;
|
||||
if (m_state == Idle) {
|
||||
switch(evt.intent) {
|
||||
case InputEvent::NetworkStatus:
|
||||
m_nextState = Message;
|
||||
m_message = evt.asBool() ? "Online!" : "Offline :[";
|
||||
break;
|
||||
case InputEvent::SetPattern:
|
||||
m_nextState = Message;
|
||||
m_message = "Pattern: " + String(evt.asString());
|
||||
break;
|
||||
case InputEvent::SetPower:
|
||||
m_nextState = Message;
|
||||
m_message = evt.asBool() ? "Power On" : "Power Off";
|
||||
break;
|
||||
case InputEvent::SaveConfigurationRequest:
|
||||
m_nextState = Message;
|
||||
m_message = "Settings Saved!";
|
||||
break;
|
||||
case InputEvent::FirmwareUpdate:
|
||||
m_nextState = Message;
|
||||
m_message = "Firmware update";
|
||||
break;
|
||||
case InputEvent::PreviousPattern:
|
||||
m_nextState = Message;
|
||||
m_message = "Previous Pattern";
|
||||
break;
|
||||
case InputEvent::NextPattern:
|
||||
m_nextState = Message;
|
||||
m_message = "Next Pattern";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawSplash() {
|
||||
//u8g2.setFont(u8g2_font_VCR_OSD_mr);
|
||||
u8g2.setFont(u8g2_font_HelvetiPixelOutline_tr);
|
||||
u8g2.setDrawColor(1);
|
||||
uint8_t splashWidth = u8g2.getStrWidth("Renderbug!");
|
||||
u8g2.drawStr(64 - splashWidth / 2, 32 - 15, "Renderbug!");
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
u8g2.setCursor(15, 64 - 7);
|
||||
u8g2.print("Version ");
|
||||
u8g2.print(RENDERBUG_VERSION);
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
uint8_t sparkleX = (64 - splashWidth/2) + scale8(7-i, beatsin8(40)) * (splashWidth/7) + 5;
|
||||
uint8_t sparkleY = scale8(3+i, beatsin8(40)) * 3 + 7;
|
||||
u8g2.setDrawColor(2);
|
||||
if (beatsin8(60*4) + i * 3 >= 170) {
|
||||
u8g2.drawLine(sparkleX - 3, sparkleY - 3, sparkleX + 3, sparkleY + 3);
|
||||
u8g2.drawLine(sparkleX + 3, sparkleY - 3, sparkleX - 3, sparkleY + 3);
|
||||
} else if (beatsin8(60*4) + i * 2 >= 82) {
|
||||
u8g2.drawLine(sparkleX - 4, sparkleY - 4, sparkleX + 2, sparkleY + 2);
|
||||
u8g2.drawLine(sparkleX - 2, sparkleY - 2, sparkleX + 4, sparkleY + 4);
|
||||
u8g2.drawLine(sparkleX + 4, sparkleY - 4, sparkleX - 2, sparkleY + 2);
|
||||
u8g2.drawLine(sparkleX + 2, sparkleY - 2, sparkleX - 4, sparkleY + 4);
|
||||
} else {
|
||||
u8g2.drawLine(sparkleX - 2, sparkleY, sparkleX + 2, sparkleY);
|
||||
u8g2.drawLine(sparkleX, sparkleY - 2, sparkleX, sparkleY + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawMessage() {
|
||||
//u8g2.setFont(u8g2_font_VCR_OSD_mr);
|
||||
u8g2.setFont(u8g2_font_HelvetiPixelOutline_tr);
|
||||
uint8_t splashWidth = u8g2.getStrWidth(m_message.c_str());
|
||||
if (splashWidth >= 128) {
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
splashWidth = u8g2.getStrWidth(m_message.c_str());
|
||||
}
|
||||
u8g2.drawStr(64 - splashWidth / 2, 32 - 15, m_message.c_str());
|
||||
}
|
||||
|
||||
void drawTime() {
|
||||
u8g2.setFont(u8g2_font_7x13O_tn);
|
||||
u8g2.setCursor(0, 64);
|
||||
struct tm timeinfo;
|
||||
Platform::getLocalTime(&timeinfo);
|
||||
uint8_t hour = timeinfo.tm_hour;
|
||||
uint8_t minute = timeinfo.tm_min;
|
||||
u8g2.print(hour);
|
||||
u8g2.print(":");
|
||||
u8g2.print(minute);
|
||||
}
|
||||
|
||||
void drawState(ScreenState state) {
|
||||
switch(state) {
|
||||
case BootSplash:
|
||||
drawSplash();
|
||||
break;
|
||||
case Message:
|
||||
drawMessage();
|
||||
break;
|
||||
case Running:
|
||||
uint8_t y = 11;
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
u8g2.setCursor(0, y);
|
||||
u8g2.print("FPS: ");
|
||||
u8g2.setFont(u8g2_font_7x13O_tn);
|
||||
u8g2.print(FastLED.getFPS());
|
||||
y += 12;
|
||||
u8g2.setCursor(0, y);
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
u8g2.print("Last event: ");
|
||||
y += 7;
|
||||
u8g2.setCursor(10, y);
|
||||
u8g2.setFont(u8g2_font_4x6_tr);
|
||||
const char* intentName = LogService::intentName(m_lastEvent.intent);
|
||||
if (intentName) {
|
||||
u8g2.print(intentName);
|
||||
} else {
|
||||
u8g2.print("<");
|
||||
u8g2.print(m_lastEvent.intent);
|
||||
u8g2.print(">");
|
||||
}
|
||||
y += 12;
|
||||
u8g2.setCursor(15, y);
|
||||
u8g2.setFont(u8g2_font_7x13O_tf);
|
||||
u8g2.print(LogService::eventValue(m_lastEvent));
|
||||
drawTime();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_MILLISECONDS(8) {
|
||||
xTaskNotifyGive(m_renderTask);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ScreenState m_state = BootSplash;
|
||||
ScreenState m_nextState = BootSplash;
|
||||
uint8_t m_transitionFrame = 0;
|
||||
uint8_t m_screenStartTime = 0;
|
||||
InputEvent m_lastEvent;
|
||||
String m_message;
|
||||
|
||||
TaskHandle_t m_renderTask;
|
||||
void redraw() {
|
||||
if (m_state != m_nextState) {
|
||||
EVERY_N_MILLISECONDS(8) {
|
||||
constexpr uint8_t speed = 11;
|
||||
if (m_transitionFrame <= 255 - speed) {
|
||||
m_transitionFrame += speed;
|
||||
} else {
|
||||
m_transitionFrame = 255;
|
||||
}
|
||||
uint8_t offset = ease8InOutApprox(m_transitionFrame);
|
||||
u8g2.clearBuffer();
|
||||
if (m_transitionFrame <= 128) {
|
||||
uint8_t width = scale8(128, offset * 2);
|
||||
u8g2.setDrawColor(1);
|
||||
drawState(m_state);
|
||||
u8g2.drawBox(0, 0, width, 64);
|
||||
u8g2.setDrawColor(2);
|
||||
u8g2.drawBox(width, 0, 8, 64);
|
||||
} else {
|
||||
uint8_t width = scale8(128, offset/2)*2;
|
||||
u8g2.setDrawColor(1);
|
||||
drawState(m_nextState);
|
||||
u8g2.setDrawColor(2);
|
||||
u8g2.drawBox(std::max(0, width - 8), 0, 8, 64);
|
||||
u8g2.setDrawColor(1);
|
||||
u8g2.drawBox(width, 0, 128, 64);
|
||||
}
|
||||
u8g2.sendBuffer();
|
||||
|
||||
if (m_transitionFrame == 255) {
|
||||
m_state = m_nextState;
|
||||
m_screenStartTime = millis();
|
||||
m_transitionFrame = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u8g2.clearBuffer();
|
||||
drawState(m_state);
|
||||
u8g2.sendBuffer();
|
||||
uint16_t screenTime = millis() - m_screenStartTime;
|
||||
if (screenTime >= 7000 && m_state != Idle) {
|
||||
m_nextState = Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void redrawTask(void* data) {
|
||||
u8g2.begin();
|
||||
U8Display* self = static_cast<U8Display*>(data);
|
||||
self->m_screenStartTime = millis();
|
||||
while (true) {
|
||||
self->redraw();
|
||||
ulTaskNotifyTake(0, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
STATIC_ALLOC(U8Display);
|
||||
STATIC_TASK(U8Display);
|
42
src/platform/arduino/WiFiTask.cpp
Normal file
42
src/platform/arduino/WiFiTask.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <Input.h>
|
||||
#include <ArduinoLog.h>
|
||||
|
||||
#ifdef BOARD_ESP8266
|
||||
#include <ESP8266WiFi.h>
|
||||
#endif
|
||||
#ifdef BOARD_ESP32
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#include "Static.h"
|
||||
#include "WiFiTask.h"
|
||||
|
||||
WiFiTask::WiFiTask() : InputSource("WiFi"), m_lastStatus(WL_IDLE_STATUS) {}
|
||||
|
||||
void
|
||||
WiFiTask::onStart()
|
||||
{
|
||||
Log.notice("Starting wifi...");
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin("The Frequency", "thepasswordkenneth");
|
||||
}
|
||||
|
||||
InputEvent
|
||||
WiFiTask::read()
|
||||
{
|
||||
uint8_t curStatus = WiFi.status();
|
||||
if (m_lastStatus != curStatus) {
|
||||
m_lastStatus = curStatus;
|
||||
Log.verbose("WiFi Status: %d", curStatus);
|
||||
if (curStatus == WL_CONNECTED) {
|
||||
Log.notice("Connected! IP address is %s", WiFi.localIP().toString().c_str());
|
||||
return InputEvent{InputEvent::NetworkStatus, true};
|
||||
} else if (curStatus == WL_CONNECTION_LOST || curStatus == WL_DISCONNECTED) {
|
||||
Log.notice("Lost wifi connection!");
|
||||
return InputEvent{InputEvent::NetworkStatus, false};
|
||||
}
|
||||
}
|
||||
return InputEvent{};
|
||||
}
|
||||
|
||||
STATIC_ALLOC(WiFiTask);
|
||||
STATIC_TASK(WiFiTask);
|
11
src/platform/arduino/WiFiTask.h
Normal file
11
src/platform/arduino/WiFiTask.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <Input.h>
|
||||
#include "Static.h"
|
||||
|
||||
class WiFiTask : public InputSource {
|
||||
public:
|
||||
WiFiTask();
|
||||
void onStart() override;
|
||||
InputEvent read() override;
|
||||
private:
|
||||
uint8_t m_lastStatus;
|
||||
};
|
@@ -33,3 +33,4 @@ class MDNSService : public Task {
|
||||
};
|
||||
|
||||
STATIC_ALLOC(MDNSService);
|
||||
STATIC_TASK(MDNSService);
|
||||
|
@@ -202,4 +202,4 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
|
||||
};
|
||||
|
||||
STATIC_ALLOC(MQTTTelemetry);
|
||||
|
||||
STATIC_TASK(MQTTTelemetry);
|
||||
|
@@ -67,3 +67,4 @@ PhotonTelemetry::handleEvent(const InputEvent &evt)
|
||||
}
|
||||
|
||||
STATIC_ALLOC(PhotonTelemetry);
|
||||
STATIC_TASK(PhotonTelemetry);
|
||||
|
@@ -28,3 +28,4 @@ class Watchdog : public Task {
|
||||
};
|
||||
|
||||
STATIC_ALLOC(Watchdog);
|
||||
STATIC_TASK(Watchdog);
|
||||
|
@@ -154,4 +154,5 @@ class WebTelemetry : public Task {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
STATIC_ALLOC(WebTelemetry);
|
||||
STATIC_TASK(WebTelemetry);
|
||||
|
@@ -26,3 +26,4 @@ CloudStatus::initNetwork(system_event_t event, int param) {
|
||||
}
|
||||
|
||||
STATIC_ALLOC(CloudStatus);
|
||||
STATIC_TASK(CloudStatus);
|
||||
|
@@ -182,6 +182,5 @@ PhotonInput::setStartPixel(String command)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC_ALLOC(PhotonInput);
|
||||
STATIC_TASK(PhotonInput);
|
||||
|
Reference in New Issue
Block a user