Compare commits
12 Commits
31157453cb
...
a55e5e1ec2
Author | SHA1 | Date | |
---|---|---|---|
a55e5e1ec2 | |||
cc3bcb0370 | |||
63bb2b43cf | |||
4b3797f4fc | |||
808112ebb0 | |||
14f8e0fd3d | |||
7651e46ee0 | |||
8fe03313ac | |||
40efeee436 | |||
2715d5aa6a | |||
d966d2ef8e | |||
0d88dc3e0f |
41
README.md
Normal file
41
README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# ESPleaf
|
||||||
|
|
||||||
|
## Layout description
|
||||||
|
|
||||||
|
Layout is defined in `LAYOUT` in `config.h`.
|
||||||
|
|
||||||
|
LEDs within a node are supposed to be installed counter-clockwise. The edge where the cables enter the node is node 0. To its right (counter-clockwise, remember) is corner 0. Then edge 1, corner 1, edge 2, corner 2 before coming back to edge 0.
|
||||||
|
|
||||||
|
Thereby, the next panel can either be installed along edge 1 or edge 2. (But the cable has to go corner 0, corner 1, corner 2 first.)
|
||||||
|
|
||||||
|
First panel is ignored in `LAYOUT`. First entry in `LAYOUT` is the edge through which the cable leaves Node 0 to Node 1 - which can be either Edge 1 or Edge 2.
|
||||||
|
|
||||||
|
On the next panel, the edge the cable is coming through is called Edge 0 again. And so on.
|
||||||
|
|
||||||
|
So, `LAYOUT` countains a list of edges the cable takes to leave to the next node.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
Command can be sent via MQTT to `MQTT_TOPIC_COMMANDS`. Syntax is `key=value` or `key=value&key2=value2...`.
|
||||||
|
|
||||||
|
Valid keys are:
|
||||||
|
* `mode` sets a new mode. Valid modes are:
|
||||||
|
* `corners`
|
||||||
|
* `nodes`
|
||||||
|
* `first_corner`
|
||||||
|
* `first_node`
|
||||||
|
* `flash`
|
||||||
|
* `static`
|
||||||
|
* `off`
|
||||||
|
* `brightness` sets the overall brightness of the lamp. Values are from 0 to 255 inclusive.
|
||||||
|
* `duration` if sets, `mode` and `brightness` are set for this amount of seconds only.
|
||||||
|
* `color` sets the color for `static` and `flash` modes. A predefined color name is expected.
|
||||||
|
* `speedup` sets a speedup for faster animations. Default value 1, possible values are 1 to 255. 0 will lead to an exception.
|
||||||
|
|
||||||
|
## Startup sequence
|
||||||
|
|
||||||
|
During startup:
|
||||||
|
* 1 green corner: FastLED is initialized. Layout is now being analyzed.
|
||||||
|
* 2 green corners: Layout is done. WiFi is being connected.
|
||||||
|
* 3 green corners: WiFi connection established. Connecting to MQTT server.
|
||||||
|
* Everything green (quarter of a second): Initialization done.
|
@ -21,10 +21,15 @@
|
|||||||
#define SPEEDUP 1
|
#define SPEEDUP 1
|
||||||
|
|
||||||
#define MAX_MILLIAMPS 1000
|
#define MAX_MILLIAMPS 1000
|
||||||
|
// Maximum color difference for the random effects.
|
||||||
|
// This changes the hue value +/- this value. Use a maximum value of 127, otherwise strange things might happen.
|
||||||
|
#define COLOR_DIFFERENCE 25
|
||||||
|
|
||||||
#define WIFI_SSID "..."
|
#define WIFI_SSID "..."
|
||||||
#define WIFI_PASS "..."
|
#define WIFI_PASS "..."
|
||||||
|
|
||||||
|
#define OTA_HOSTNAME "..."
|
||||||
|
|
||||||
#define MQTT_CLIENT_ID "espleaf"
|
#define MQTT_CLIENT_ID "espleaf"
|
||||||
#define MQTT_USER "..."
|
#define MQTT_USER "..."
|
||||||
#define MQTT_PASS "..."
|
#define MQTT_PASS "..."
|
||||||
|
@ -3,16 +3,28 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "edge.h"
|
#include "edge.h"
|
||||||
#include "corner.h"
|
#include "corner.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
// Delta-X data. Per direction of a triangle is a triple with Delta-X values for each direction.
|
||||||
|
static const int8_t dx[][3] = {{0, 1, -1}, {1, 0, -1}, {1, -1, 0}, {0, -1, 1}, {-1, 0, 1}, {-1, 1, 0}};
|
||||||
|
static const int8_t dy[][3] = {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}, {1, 0, 0}, {0, -1, 0}, {0, 0, 1}};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int8_t x;
|
||||||
|
int8_t y;
|
||||||
|
} Coords;
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
private:
|
|
||||||
uint16_t _number;
|
|
||||||
public:
|
public:
|
||||||
|
uint16_t _number;
|
||||||
|
Coords coords;
|
||||||
|
uint8_t direction;
|
||||||
Node* neighbours[CORNERS_PER_PART];
|
Node* neighbours[CORNERS_PER_PART];
|
||||||
Edge* edges[CORNERS_PER_PART];
|
Edge* edges[CORNERS_PER_PART];
|
||||||
Corner* _corners[CORNERS_PER_PART];
|
Corner* _corners[CORNERS_PER_PART];
|
||||||
Node(uint16_t number);
|
Node(uint16_t number, Coords c, uint8_t direction);
|
||||||
Node* create_neighbour(uint8_t edge);
|
Node* create_neighbour(uint8_t edge);
|
||||||
|
Coords coords_at_direction(uint8_t edge);
|
||||||
|
|
||||||
void blend_to(CRGB color, uint16_t effect_id=0, uint8_t effect_speed=0);
|
void blend_to(CRGB color, uint16_t effect_id=0, uint8_t effect_speed=0);
|
||||||
void set_color(CRGB color);
|
void set_color(CRGB color);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "edge.h"
|
#include "edge.h"
|
||||||
#include "corner.h"
|
#include "corner.h"
|
||||||
|
|
||||||
|
class Node;
|
||||||
|
|
||||||
extern std::vector<Node*> nodes;
|
extern std::vector<Node*> nodes;
|
||||||
extern std::list<Edge*> edges;
|
extern std::list<Edge*> edges;
|
||||||
@ -23,10 +24,12 @@ enum AnimationMode {
|
|||||||
AM_FLASH,
|
AM_FLASH,
|
||||||
AM_OFF,
|
AM_OFF,
|
||||||
AM_ERROR,
|
AM_ERROR,
|
||||||
AM_NONE
|
AM_NONE,
|
||||||
|
AM_STATIC
|
||||||
};
|
};
|
||||||
|
|
||||||
extern AnimationMode mode;
|
extern AnimationMode mode;
|
||||||
extern AnimationMode temp_mode;
|
extern AnimationMode temp_mode;
|
||||||
extern unsigned long temp_mode_until;
|
extern unsigned long temp_mode_until;
|
||||||
extern int return_to_brightness;
|
extern int return_to_brightness;
|
||||||
|
extern uint8_t speedup;
|
||||||
|
@ -12,10 +12,12 @@
|
|||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = d1_mini
|
board = d1_mini
|
||||||
framework = arduino
|
framework = arduino
|
||||||
upload_port = /dev/cu.wchusbserial*
|
;upload_port = /dev/cu.wchusbserial*
|
||||||
|
upload_protocol = espota
|
||||||
|
upload_port = espleaf-prod.local
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
monitor_port = /dev/cu.wchusbserial*
|
monitor_port = /dev/cu.wchusbserial*
|
||||||
monitor_speed = 74880
|
monitor_speed = 74880
|
||||||
monitor_filters = default, time, send_on_enter, esp8266_exception_decoder
|
monitor_filters = default, time, send_on_enter, esp8266_exception_decoder
|
||||||
lib_deps = fastled/FastLED @ 3.4.0
|
lib_deps = fastled/FastLED @ 3.4.0
|
||||||
PubSubClient
|
PubSubClient @ 2.8
|
@ -44,13 +44,13 @@ bool Corner::reached_level(uint16_t level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Corner::blend_to(CRGB target, uint16_t eid, uint8_t effect_speed) {
|
void Corner::blend_to(CRGB target, uint16_t eid, uint8_t effect_speed) {
|
||||||
LOGln("blendTo called. Corner: %p, target: %d,%d,%d, eid: %d, 'old' effect_id: %d, speed: %d", this, target.r, target.g, target.b, eid, effect_id, effect_speed);
|
//LOGln("blendTo called. Corner: %p, target: %d,%d,%d, eid: %d, 'old' effect_id: %d, speed: %d", this, target.r, target.g, target.b, eid, effect_id, effect_speed);
|
||||||
if (eid==0) {
|
if (eid==0) {
|
||||||
this->effect_id = random16();
|
this->effect_id = random16();
|
||||||
LOGln("Set effect_id to %d", this->effect_id);
|
//LOGln("Set effect_id to %d", this->effect_id);
|
||||||
} else {
|
} else {
|
||||||
if (this->effect_id == eid) {
|
if (this->effect_id == eid) {
|
||||||
LOGln("'Old' effect. Doing nothing.");
|
//LOGln("'Old' effect. Doing nothing.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->effect_id = eid;
|
this->effect_id = eid;
|
||||||
|
128
src/main.cpp
128
src/main.cpp
@ -1,5 +1,6 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
@ -20,6 +21,7 @@ AnimationMode mode = AM_CORNERS;
|
|||||||
AnimationMode temp_mode;
|
AnimationMode temp_mode;
|
||||||
unsigned long temp_mode_until;
|
unsigned long temp_mode_until;
|
||||||
int return_to_brightness = -1;
|
int return_to_brightness = -1;
|
||||||
|
uint8_t speedup = SPEEDUP;
|
||||||
|
|
||||||
unsigned long last_loop = 0;
|
unsigned long last_loop = 0;
|
||||||
|
|
||||||
@ -32,7 +34,7 @@ bool looping;
|
|||||||
void setup_layout() {
|
void setup_layout() {
|
||||||
LOGln("Setting up layout...");
|
LOGln("Setting up layout...");
|
||||||
uint8_t layout[] = LAYOUT;
|
uint8_t layout[] = LAYOUT;
|
||||||
Node* current_node = new Node(0);
|
Node* current_node = new Node(0, {0, 0}, 0);
|
||||||
nodes.push_back(current_node);
|
nodes.push_back(current_node);
|
||||||
|
|
||||||
for(uint16_t i=0; i<NODE_COUNT-1; i++) {
|
for(uint16_t i=0; i<NODE_COUNT-1; i++) {
|
||||||
@ -53,6 +55,45 @@ void setup_layout() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Node* n1 : nodes) {
|
||||||
|
LOGln("Looking for neighbours of node #%d @ %d,%d", n1->_number, n1->coords.x, n1->coords.y);
|
||||||
|
for(int edge=0; edge<CORNERS_PER_PART; edge++) {
|
||||||
|
Coords c = n1->coords_at_direction(edge);
|
||||||
|
LOGln(" Chcking edge %d @ %d,%d...", edge, c.x, c.y);
|
||||||
|
|
||||||
|
Node* found = nullptr;
|
||||||
|
for(Node* n2 : nodes) {
|
||||||
|
if (n2 == n1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (n2->coords.x == c.x && n2->coords.y == c.y) {
|
||||||
|
found = n2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found != nullptr) {
|
||||||
|
LOGln(" Found node #%d", found->_number);
|
||||||
|
uint8_t inverse_dir = (n1->direction + 2*edge + 3) % 6;
|
||||||
|
int8_t e = (inverse_dir - found->direction) % 6;
|
||||||
|
if (e < 0) e+=6;
|
||||||
|
e = e / 2;
|
||||||
|
//LOGln(" inverse_dir: %d, edge: %d", inverse_dir, edge);
|
||||||
|
int8_t e1 = (edge - 1) % CORNERS_PER_PART;
|
||||||
|
if (e1<0) e1+=CORNERS_PER_PART;
|
||||||
|
int8_t e2 = (e - 1) % CORNERS_PER_PART;
|
||||||
|
if (e2<0) e2+=CORNERS_PER_PART;
|
||||||
|
|
||||||
|
LOGln(" Mapping Corner #%d,%d with #%d,%d", n1->_number, edge, found->_number, e2);
|
||||||
|
n1->_corners[edge]->_short_neighbours.push_back(found->_corners[e2]);
|
||||||
|
|
||||||
|
LOGln(" Mapping Corner #%d,%d with #%d,%d", n1->_number, e1, found->_number, e);
|
||||||
|
n1->_corners[e1]->_short_neighbours.push_back(found->_corners[e]);
|
||||||
|
} else {
|
||||||
|
LOGln(" No match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(Corner* corner: corners) {
|
for(Corner* corner: corners) {
|
||||||
LOGln("Corner %p:", corner);
|
LOGln("Corner %p:", corner);
|
||||||
for(auto c: corner->_long_neighbours) {
|
for(auto c: corner->_long_neighbours) {
|
||||||
@ -76,41 +117,61 @@ void setup_fastled() {
|
|||||||
FastLED.addLeds<WS2812B, 5, GRB>(leds, LEDS_PER_CORNER * CORNERS_PER_PART * NODE_COUNT).setCorrection(TypicalLEDStrip);
|
FastLED.addLeds<WS2812B, 5, GRB>(leds, LEDS_PER_CORNER * CORNERS_PER_PART * NODE_COUNT).setCorrection(TypicalLEDStrip);
|
||||||
LOGln("LEDs: %3d", LED_COUNT);
|
LOGln("LEDs: %3d", LED_COUNT);
|
||||||
FastLED.setBrightness(255);
|
FastLED.setBrightness(255);
|
||||||
FastLED.setDither(DISABLE_DITHER);
|
//FastLED.setDither(DISABLE_DITHER);
|
||||||
FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_MILLIAMPS);
|
FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_MILLIAMPS);
|
||||||
set_all_leds(CRGB::Black);
|
set_all_leds(CRGB::Black);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_rng() {
|
void show_all() {
|
||||||
LOGln("Starting WiFi scan for RNG initialization...");
|
for(Node* node : nodes) {
|
||||||
WiFi.mode(WIFI_STA);
|
node->draw();
|
||||||
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);
|
FastLED.show();
|
||||||
random16_set_seed(seed);
|
}
|
||||||
|
|
||||||
|
void show_status(uint8_t status, CRGB color=CRGB::Green) {
|
||||||
|
for (int i=0; i<status; i++) {
|
||||||
|
if (i<corners.size()) {
|
||||||
|
corners[i]->set_color(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=status; i<corners.size(); i++) {
|
||||||
|
corners[i]->set_color(CRGB::Black);
|
||||||
|
}
|
||||||
|
show_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(74880);
|
Serial.begin(74880);
|
||||||
LOGln("ESPleaf starting.");
|
LOGln("ESPleaf starting.");
|
||||||
|
|
||||||
setup_layout();
|
|
||||||
setup_fastled();
|
setup_fastled();
|
||||||
|
show_status(1);
|
||||||
|
|
||||||
|
setup_layout();
|
||||||
|
show_status(2);
|
||||||
|
|
||||||
#ifdef TEST_MODE
|
#ifdef TEST_MODE
|
||||||
LOGln("TEST_MODE is active!");
|
LOGln("TEST_MODE is active!");
|
||||||
#else
|
#else
|
||||||
setup_rng();
|
|
||||||
|
|
||||||
wifi_setup();
|
wifi_setup();
|
||||||
mqtt_setup();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
show_status(3);
|
||||||
|
|
||||||
|
mqtt_setup();
|
||||||
|
ArduinoOTA.setHostname(OTA_HOSTNAME);
|
||||||
|
ArduinoOTA.onProgress([&](unsigned int progress, unsigned int total){
|
||||||
|
uint8_t count = progress * corners.size() / total;
|
||||||
|
show_status(count, CRGB::Blue);
|
||||||
|
});
|
||||||
|
ArduinoOTA.onEnd([](){ show_status(0); });
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
|
||||||
|
show_status(255);
|
||||||
|
delay(250);
|
||||||
|
show_status(0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@ -129,7 +190,9 @@ void loop() {
|
|||||||
#else
|
#else
|
||||||
// Normal mode
|
// Normal mode
|
||||||
mqtt_loop();
|
mqtt_loop();
|
||||||
EVERY_N_MILLISECONDS(20 / SPEEDUP) {
|
ArduinoOTA.handle();
|
||||||
|
|
||||||
|
if (speedup > 0 && (millis() - last_loop > (20 / speedup) || last_loop > millis())) {
|
||||||
looping = false;
|
looping = false;
|
||||||
|
|
||||||
AnimationMode active_mode = mode;
|
AnimationMode active_mode = mode;
|
||||||
@ -154,44 +217,37 @@ void loop() {
|
|||||||
corner->infect(300, 600);
|
corner->infect(300, 600);
|
||||||
}
|
}
|
||||||
looping |= !corner->is_finished();
|
looping |= !corner->is_finished();
|
||||||
corner->draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (random8(128)==0) {
|
if (random8(128)==0) {
|
||||||
if (active_mode == AM_FIRST_CORNER) {
|
uint16_t corner = (active_mode == AM_FIRST_CORNER) ? 0 : random16(corners.size());
|
||||||
corners[0]->blend_to(CHSV(random8(), 255, 255));
|
CHSV color = rgb2hsv_approximate(corners[corner]->color);
|
||||||
} else {
|
corners[corner]->blend_to(CHSV(color.h - COLOR_DIFFERENCE + random8(2*COLOR_DIFFERENCE), 255, 255));
|
||||||
corners[random16(corners.size())]->blend_to(CHSV(random8(), 255, 255));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (active_mode == AM_NODES || active_mode == AM_FIRST_NODE) {
|
} else if (active_mode == AM_NODES || active_mode == AM_FIRST_NODE) {
|
||||||
for(Node* node : nodes) {
|
for(Node* node : nodes) {
|
||||||
node->step();
|
node->step();
|
||||||
node->infect(512);
|
node->infect(512);
|
||||||
node->draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (random8(128)==0) {
|
if (random8(128)==0) {
|
||||||
if (active_mode == AM_FIRST_NODE) {
|
uint16_t corner = (active_mode == AM_FIRST_NODE) ? 0 : random8(nodes.size());
|
||||||
nodes[0]->blend_to(CHSV(random8(), 255, 255));
|
CHSV color = rgb2hsv_approximate(corners[corner]->color);
|
||||||
} else {
|
nodes[corner]->blend_to(CHSV(color.h - COLOR_DIFFERENCE + random8(2*COLOR_DIFFERENCE), 255, 255));
|
||||||
nodes[random8(nodes.size())]->blend_to(CHSV(random8(), 255, 255));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (active_mode == AM_FLASH) {
|
} else if (active_mode == AM_FLASH) {
|
||||||
for (Node* node : nodes) {
|
for (Node* node : nodes) {
|
||||||
node->step();
|
node->step();
|
||||||
node->infect(512);
|
node->infect(512);
|
||||||
node->draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (millis() / 1000 > last_loop / 1000) {
|
if (millis() / 1000 > last_loop / 1000) {
|
||||||
nodes[0]->blend_to(((millis() / 1000) % 2 == 0) ? CRGB::Black : color, 0, 64);
|
nodes[0]->blend_to(((millis() / 1000) % 2 == 0) ? CRGB::Black : color, 0, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (active_mode == AM_OFF) {
|
} else if (active_mode == AM_OFF || active_mode == AM_STATIC) {
|
||||||
for(Node* node : nodes) {
|
for(Node* node : nodes) {
|
||||||
node->set_color(CRGB::Black);
|
node->set_color(active_mode == AM_OFF ? CRGB::Black : color);
|
||||||
}
|
}
|
||||||
} else { // This includes AM_ERROR
|
} else { // This includes AM_ERROR
|
||||||
for(Node* node : nodes) {
|
for(Node* node : nodes) {
|
||||||
@ -204,5 +260,5 @@ void loop() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FastLED.show();
|
show_all();
|
||||||
}
|
}
|
17
src/mqtt.cpp
17
src/mqtt.cpp
@ -24,16 +24,24 @@ void callback(char* topic, byte* pl, unsigned int length) {
|
|||||||
uint16_t duration = 0;
|
uint16_t duration = 0;
|
||||||
AnimationMode new_mode = AM_NONE;
|
AnimationMode new_mode = AM_NONE;
|
||||||
String current_part;
|
String current_part;
|
||||||
|
LOGln("Received command %s", payload.c_str());
|
||||||
while (payload.length() > 0) {
|
while (payload.length() > 0) {
|
||||||
int offset = payload.indexOf("&");
|
int offset = payload.indexOf("&");
|
||||||
if (offset != -1) {
|
if (offset != -1) {
|
||||||
current_part = payload.substring(0, offset);
|
current_part = payload.substring(0, offset);
|
||||||
payload = payload.substring(offset + 1);
|
payload = payload.substring(offset + 1);
|
||||||
|
} else {
|
||||||
|
current_part = payload;
|
||||||
|
payload = "";
|
||||||
}
|
}
|
||||||
offset = current_part.indexOf("=");
|
offset = current_part.indexOf("=");
|
||||||
if (offset==-1) continue;
|
if (offset==-1) {
|
||||||
|
LOGln("Parameter without '=' detected: %s", current_part.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String key = current_part.substring(0, offset);
|
String key = current_part.substring(0, offset);
|
||||||
String value = current_part.substring(offset+1);
|
String value = current_part.substring(offset+1);
|
||||||
|
LOGln(" Processing key %s with value %s", key.c_str(), value.c_str());
|
||||||
|
|
||||||
if (key.equals("mode")) {
|
if (key.equals("mode")) {
|
||||||
if (value.equals("nodes")) { new_mode = AM_NODES; }
|
if (value.equals("nodes")) { new_mode = AM_NODES; }
|
||||||
@ -42,6 +50,7 @@ void callback(char* topic, byte* pl, unsigned int length) {
|
|||||||
else if (value.equals("first_corner")) { new_mode = AM_FIRST_CORNER; }
|
else if (value.equals("first_corner")) { new_mode = AM_FIRST_CORNER; }
|
||||||
else if (value.equals("off")) { new_mode = AM_OFF; }
|
else if (value.equals("off")) { new_mode = AM_OFF; }
|
||||||
else if (value.equals("flash")) { new_mode = AM_FLASH; }
|
else if (value.equals("flash")) { new_mode = AM_FLASH; }
|
||||||
|
else if (value.equals("static")) { new_mode = AM_STATIC; }
|
||||||
else { LOGln("Unknown mode '%s'.", value.c_str()); }
|
else { LOGln("Unknown mode '%s'.", value.c_str()); }
|
||||||
} else if (key.equals("duration")) {
|
} else if (key.equals("duration")) {
|
||||||
duration = value.toInt();
|
duration = value.toInt();
|
||||||
@ -54,11 +63,17 @@ void callback(char* topic, byte* pl, unsigned int length) {
|
|||||||
if (value.equals("red")) { color = CRGB::Red; }
|
if (value.equals("red")) { color = CRGB::Red; }
|
||||||
else if (value.equals("green")) { color = CRGB::Green; }
|
else if (value.equals("green")) { color = CRGB::Green; }
|
||||||
else if (value.equals("blue")) { color = CRGB::Blue; }
|
else if (value.equals("blue")) { color = CRGB::Blue; }
|
||||||
|
else if (value.equals("pink")) { color = CRGB::Pink; }
|
||||||
|
else if (value.equals("yellow")) { color = CRGB::Yellow; }
|
||||||
|
else if (value.equals("orange")) { color = CRGB::Orange; }
|
||||||
else { LOGln("Unknown color name %s.", value.c_str());}
|
else { LOGln("Unknown color name %s.", value.c_str());}
|
||||||
|
} else if (key.equals("speedup")) {
|
||||||
|
speedup = value.toInt();
|
||||||
} else {
|
} else {
|
||||||
LOGln("Unknown key '%s'. (For reference: Value is '%s'.)", key.c_str(), value.c_str());
|
LOGln("Unknown key '%s'. (For reference: Value is '%s'.)", key.c_str(), value.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOGln("Finished processing the command.");
|
||||||
|
|
||||||
if (new_mode != AM_NONE) {
|
if (new_mode != AM_NONE) {
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
|
35
src/node.cpp
35
src/node.cpp
@ -2,8 +2,12 @@
|
|||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
Node::Node(uint16_t number) {
|
Node::Node(uint16_t number, Coords c, uint8_t _dir) {
|
||||||
_number = number;
|
_number = number;
|
||||||
|
coords = c;
|
||||||
|
direction = _dir;
|
||||||
|
|
||||||
|
LOGln("Created Node #%d at coordinates %d,%d with direction %d.", _number, coords.x, coords.y, direction);
|
||||||
for(int i=0; i<CORNERS_PER_PART; i++) {
|
for(int i=0; i<CORNERS_PER_PART; i++) {
|
||||||
edges[i] = new Edge();
|
edges[i] = new Edge();
|
||||||
}
|
}
|
||||||
@ -26,38 +30,25 @@ Node::Node(uint16_t number) {
|
|||||||
last_corner->_long_neighbours.push_back(_corners[0]);
|
last_corner->_long_neighbours.push_back(_corners[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Coords Node::coords_at_direction(uint8_t edge) {
|
||||||
|
return {(int8_t)(coords.x + dx[direction][edge]), (int8_t)(coords.y + dy[direction][edge])};
|
||||||
|
}
|
||||||
|
|
||||||
Node* Node::create_neighbour(uint8_t edge) {
|
Node* Node::create_neighbour(uint8_t edge) {
|
||||||
Node* node = new Node(_number + 1);
|
Coords new_c = coords_at_direction(edge);
|
||||||
|
int8_t new_dir = (edge==1) ? ((direction - 1) % 6) : ((direction + 1) % 6);
|
||||||
|
if (new_dir < 0) new_dir+=6;
|
||||||
|
Node* node = new Node(_number + 1, new_c, new_dir);
|
||||||
node->neighbours[0] = this;
|
node->neighbours[0] = this;
|
||||||
neighbours[edge] = node;
|
neighbours[edge] = node;
|
||||||
|
|
||||||
node->edges[0]->neighbour = this->edges[edge];
|
node->edges[0]->neighbour = this->edges[edge];
|
||||||
this->edges[edge]->neighbour = node->edges[0];
|
this->edges[edge]->neighbour = node->edges[0];
|
||||||
|
|
||||||
node->_corners[0]->_short_neighbours.push_back(_corners[(edge-1) % CORNERS_PER_PART]);
|
|
||||||
node->_corners[CORNERS_PER_PART - 1]->_short_neighbours.push_back(_corners[edge]);
|
|
||||||
_corners[(edge-1) % CORNERS_PER_PART]->_short_neighbours.push_back(node->_corners[0]);
|
|
||||||
_corners[edge]->_short_neighbours.push_back(node->_corners[CORNERS_PER_PART - 1]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
delete node->edges[0];
|
|
||||||
node->edges[0] = this->edges[edge];
|
|
||||||
|
|
||||||
Corner* c = this->corners[(edge-1) % CORNERS_PER_PART];
|
|
||||||
c->merge_leds(node->corners[0]);
|
|
||||||
delete node->corners[0];
|
|
||||||
node->corners[0] = c;
|
|
||||||
|
|
||||||
c = this->corners[edge];
|
|
||||||
c->merge_leds(node->corners[CORNERS_PER_PART-1]);
|
|
||||||
delete node->corners[CORNERS_PER_PART-1];
|
|
||||||
node->corners[CORNERS_PER_PART-1] = c;
|
|
||||||
*/
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::blend_to(CRGB color, uint16_t effect_id, uint8_t effect_speed) {
|
void Node::blend_to(CRGB color, uint16_t effect_id, uint8_t effect_speed) {
|
||||||
LOGln("Node::blend_to called. this:%p", this);
|
|
||||||
if (effect_speed == 0) effect_speed = random8(2)+1;
|
if (effect_speed == 0) effect_speed = random8(2)+1;
|
||||||
if (effect_id == 0) effect_id = random16();
|
if (effect_id == 0) effect_id = random16();
|
||||||
for(Corner* corner : this->_corners) {
|
for(Corner* corner : this->_corners) {
|
||||||
|
@ -10,4 +10,5 @@ void wifi_setup() {
|
|||||||
delay(300);
|
delay(300);
|
||||||
}
|
}
|
||||||
LOGln(" Connected as %s", WiFi.localIP().toString().c_str());
|
LOGln(" Connected as %s", WiFi.localIP().toString().c_str());
|
||||||
|
random16_add_entropy(micros());
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user