208 lines
4.7 KiB
C++
208 lines
4.7 KiB
C++
#include <Arduino.h>
|
|
#include <ESP8266WiFi.h>
|
|
#include "my_fastled.h"
|
|
#include "config.h"
|
|
#include "tools.h"
|
|
#include "node.h"
|
|
#include "edge.h"
|
|
#include "corner.h"
|
|
#include "prototypes.h"
|
|
#include "mqtt.h"
|
|
|
|
std::vector<Node*> nodes;
|
|
std::list<Edge*> edges;
|
|
std::vector<Corner*> corners;
|
|
|
|
CRGB leds[LED_COUNT];
|
|
CRGB color = CRGB::Pink;
|
|
|
|
AnimationMode mode = AM_CORNERS;
|
|
AnimationMode temp_mode;
|
|
unsigned long temp_mode_until;
|
|
int return_to_brightness = -1;
|
|
|
|
unsigned long last_loop = 0;
|
|
|
|
#ifdef TEST_MODE
|
|
uint8_t base_hue = 0;
|
|
#endif
|
|
|
|
bool looping;
|
|
|
|
void setup_layout() {
|
|
LOGln("Setting up layout...");
|
|
uint8_t layout[] = LAYOUT;
|
|
Node* current_node = new Node(0);
|
|
nodes.push_back(current_node);
|
|
|
|
for(uint16_t i=0; i<NODE_COUNT-1; i++) {
|
|
current_node = current_node->create_neighbour(layout[i]);
|
|
nodes.push_back(current_node);
|
|
}
|
|
|
|
for(Node* node: nodes) {
|
|
for(Edge* edge: node->edges) {
|
|
auto e = std::find(edges.begin(), edges.end(), edge);
|
|
if (e == edges.end()) {
|
|
edges.push_back(edge);
|
|
}
|
|
}
|
|
LOGln("Node %p:", node);
|
|
for(Node* n : node->neighbours) {
|
|
LOGln(" %p", n);
|
|
}
|
|
}
|
|
|
|
for(Corner* corner: corners) {
|
|
LOGln("Corner %p:", corner);
|
|
for(auto c: corner->_long_neighbours) {
|
|
LOGln(" Long: %p", c);
|
|
}
|
|
for(auto c: corner->_short_neighbours) {
|
|
LOGln(" Short: %p", c);
|
|
}
|
|
}
|
|
|
|
LOGln("Counts:");
|
|
LOGln("Nodes: %3d", nodes.size());
|
|
LOGln("Edges: %3d", edges.size());
|
|
LOGln("Corners: %3d", corners.size());
|
|
}
|
|
|
|
void setup_fastled() {
|
|
LOGln("Setting up FastLED...");
|
|
// GPIO5 = D1
|
|
// GPIO2 = D4
|
|
FastLED.addLeds<WS2812B, 5, GRB>(leds, LEDS_PER_CORNER * CORNERS_PER_PART * NODE_COUNT).setCorrection(TypicalLEDStrip);
|
|
LOGln("LEDs: %3d", LED_COUNT);
|
|
FastLED.setBrightness(255);
|
|
FastLED.setDither(DISABLE_DITHER);
|
|
FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_MILLIAMPS);
|
|
set_all_leds(CRGB::Black);
|
|
}
|
|
|
|
void setup_rng() {
|
|
LOGln("Starting WiFi scan for RNG initialization...");
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.disconnect();
|
|
uint16_t seed = 0;
|
|
int n = WiFi.scanNetworks();
|
|
LOGln("%d WiFi networks found", n);
|
|
for(int i=0; i<n; i++) {
|
|
LOGln(" %s, %d dB", WiFi.SSID(i).c_str(), WiFi.RSSI(i));
|
|
seed = (seed << 2) | (WiFi.RSSI(i) & 0x03);
|
|
}
|
|
LOGln("WiFi scan done. Generated seed is 0x%04x", seed);
|
|
random16_set_seed(seed);
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(74880);
|
|
LOGln("ESPleaf starting.");
|
|
|
|
setup_layout();
|
|
setup_fastled();
|
|
#ifdef TEST_MODE
|
|
LOGln("TEST_MODE is active!");
|
|
#else
|
|
setup_rng();
|
|
|
|
wifi_setup();
|
|
mqtt_setup();
|
|
#endif
|
|
|
|
}
|
|
|
|
void loop() {
|
|
#ifdef TEST_MODE
|
|
EVERY_N_MILLISECONDS(20) {
|
|
int i=0;
|
|
for(Node* node : nodes) {
|
|
CHSV color(base_hue + 150*i, 255, 255);
|
|
for(int j=0; j<CORNERS_PER_PART*LEDS_PER_CORNER; j++) {
|
|
leds[i*CORNERS_PER_PART*LEDS_PER_CORNER+j] = color;
|
|
}
|
|
i++;
|
|
}
|
|
base_hue += 1;
|
|
}
|
|
#else
|
|
// Normal mode
|
|
mqtt_loop();
|
|
EVERY_N_MILLISECONDS(20 / SPEEDUP) {
|
|
looping = false;
|
|
|
|
AnimationMode active_mode = mode;
|
|
if (temp_mode_until > 0) {
|
|
if (temp_mode_until>millis()) {
|
|
active_mode = temp_mode;
|
|
} else {
|
|
temp_mode_until = 0;
|
|
if (return_to_brightness != -1) {
|
|
FastLED.setBrightness(return_to_brightness);
|
|
return_to_brightness = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (active_mode == AM_CORNERS || active_mode == AM_FIRST_CORNER) {
|
|
for(Corner* corner: corners) {
|
|
corner->step();
|
|
if (active_mode == AM_FIRST_CORNER) {
|
|
corner->infect(512, 512);
|
|
} else {
|
|
corner->infect(300, 600);
|
|
}
|
|
looping |= !corner->is_finished();
|
|
corner->draw();
|
|
}
|
|
|
|
if (random8(128)==0) {
|
|
if (active_mode == AM_FIRST_CORNER) {
|
|
corners[0]->blend_to(CHSV(random8(), 255, 255));
|
|
} else {
|
|
corners[random16(corners.size())]->blend_to(CHSV(random8(), 255, 255));
|
|
}
|
|
}
|
|
} else if (active_mode == AM_NODES || active_mode == AM_FIRST_NODE) {
|
|
for(Node* node : nodes) {
|
|
node->step();
|
|
node->infect(512);
|
|
node->draw();
|
|
}
|
|
|
|
if (random8(128)==0) {
|
|
if (active_mode == AM_FIRST_NODE) {
|
|
nodes[0]->blend_to(CHSV(random8(), 255, 255));
|
|
} else {
|
|
nodes[random8(nodes.size())]->blend_to(CHSV(random8(), 255, 255));
|
|
}
|
|
}
|
|
} else if (active_mode == AM_FLASH) {
|
|
for (Node* node : nodes) {
|
|
node->step();
|
|
node->infect(512);
|
|
node->draw();
|
|
}
|
|
|
|
if (millis() / 1000 > last_loop / 1000) {
|
|
nodes[0]->blend_to(((millis() / 1000) % 2 == 0) ? CRGB::Black : color, 0, 64);
|
|
}
|
|
|
|
} else if (active_mode == AM_OFF) {
|
|
for(Node* node : nodes) {
|
|
node->set_color(CRGB::Black);
|
|
}
|
|
} else { // This includes AM_ERROR
|
|
for(Node* node : nodes) {
|
|
node->set_color(CRGB::Black);
|
|
}
|
|
nodes[0]->set_color(CRGB::Red);
|
|
}
|
|
|
|
last_loop = millis();
|
|
}
|
|
#endif
|
|
|
|
FastLED.show();
|
|
} |