commit 81433310f9edcf283842f5faa19fc98541fc7d1e Author: Fabian Schlenz Date: Tue May 21 05:52:57 2019 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e56cf2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.h diff --git a/config.sample.h b/config.sample.h new file mode 100644 index 0000000..799d9eb --- /dev/null +++ b/config.sample.h @@ -0,0 +1,27 @@ +#define WIFI_SSID "....." +#define WIFI_PASS "....." + +#define LED_WIDTH 16 +#define LED_HEIGHT 16 +#define LED_COUNT 256 +#define LED_TYPE WS2812B +#define DATA_PIN 14 +#define COLOR_ORDER GRB + +#define NTP_SERVER "pool.ntp.org" +#define NTP_INTERVAL 60000 +#define NTP_OFFSET 7200 + +#define MQTT_SERVER "....." +#define MQTT_PORT 1883 +#define MQTT_USER "pitrix" +#define MQTT_PASS "....." +#define MQTT_TOPIC_MODE "pitrix/mode" +#define MQTT_TOPIC_STATUS "pitrix/status" +#define MQTT_TOPIC_LOG "pitrix/log" + +#define OTA_HOSTNAME "pitrix" +#define OTA_STARTUP_DELAY 5 // How many seconds to wait at startup. Set to 0 to disable. + +#define FPS 50 +#define SHOW_TEXT_DELAY 100 diff --git a/effect.h b/effect.h new file mode 100644 index 0000000..fd91989 --- /dev/null +++ b/effect.h @@ -0,0 +1,4 @@ +class Effect { + public: + virtual void loop() {}; +}; diff --git a/effect_bell.h b/effect_bell.h new file mode 100644 index 0000000..bf5bd87 --- /dev/null +++ b/effect_bell.h @@ -0,0 +1,24 @@ +class Bell : public Effect { + private: + + CRGB color_on = CRGB(0xFFFF00); + CRGB color_off= CRGB(0x000000); + boolean invert = false; + + public: + void loop() { + for(int y=0; y<16; y++) { + for(int x=0; x<2; x++) { + for(int z=0; z<8; z++) { + leds[XYsafe(x*8+z, y)] = sprite_bell[y*2+x]>>(7-z) & 1 ^ invert ? color_on : color_off; + } + } + } + + EVERY_N_MILLISECONDS(300) { + invert = !invert; + } + } + + +}; diff --git a/effect_clock.h b/effect_clock.h new file mode 100644 index 0000000..f075515 --- /dev/null +++ b/effect_clock.h @@ -0,0 +1,45 @@ +class Clock : public Effect { + private: + CRGB color_h = CRGB(0xFF0000); + CRGB color_m = CRGB(0x00FF00); + CRGB color_colon = CRGB(0xFFFF00); + + void drawNumber(uint8_t number, int x, int y, CRGB color) { + char buffer[7]; + sprintf(buffer, "%02d", number); + drawText(buffer, x, y, color); + } + + void drawText(char *text, int x, int y, CRGB color) { + for (int i = 0; i < strlen(text); i++) { + drawSprite(font_char(numbers4x7, text[i]), x + i * 4, y, color); + } + } + + unsigned char* font_char(unsigned char* font, char c) { + return &font[(c - 48) * 4]; + } + + void drawSprite(unsigned char* sprite, int xOffset, int yOffset, CRGB color) { + for ( byte y = 0; y < 7; y++) { + for ( byte x = 0; x < 4; x++) { + bool on = (sprite[x] >> y & 1) * 255; + if (on) { + leds[ XYsafe(x + xOffset, y + yOffset) ] = color; + } + } + } + } + public: + Clock() {} + void loop() { + clear(); + drawNumber(ntpClient.getHours(), 0, 0, color_h); + drawNumber(ntpClient.getMinutes(), 8, 0, color_m); + /*if (ntpClient.getSeconds() & 1) { + leds[XYsafe(13, 2)] = color_colon; + leds[XYsafe(13, 5)] = color_colon; + }*/ + drawNumber(ntpClient.getSeconds(), 8, 8, color_colon); + } +}; diff --git a/effect_sinematrix3.h b/effect_sinematrix3.h new file mode 100644 index 0000000..ad697cc --- /dev/null +++ b/effect_sinematrix3.h @@ -0,0 +1,68 @@ +class Sinematrix3 : public Effect { + private: + double pangle = 0; + double angle = 0; + double sx = 0; + double sy = 0; + double tx = 0; + double ty = 0; + double cx = 0; + double cy = 0; + double rcx = 0; + double rcy = 0; + double angle2 = 0; + double sx2 = 0; + double sy2 = 0; + double tx2 = 0; + double ty2 = 0; + double basecol = 0; + double fx = 1.0/(LED_WIDTH/PI); + double fy = 1.0/(LED_HEIGHT/PI); + Matrix rotate; + + public: + Sinematrix3() {} + void loop() { + pangle = addmodpi( pangle, 0.0133 + (angle/256) ); + angle = cos(pangle) * PI; + sx = addmodpi( sx, 0.00673 ); + sy = addmodpi( sy, 0.00437 ); + tx = addmodpi( tx, 0.00239 ); + ty = addmodpi( ty, 0.00293 ); + cx = addmodpi( cx, 0.00197 ); + cy = addmodpi( cy, 0.00227 ); + rcx = (LED_WIDTH/2) + (sin(cx) * LED_WIDTH); + rcy = (LED_HEIGHT/2) + (sin(cy) * LED_HEIGHT); + angle2 = addmodpi( angle2, 0.0029 ); + sx2 = addmodpi( sx2, 0.0041); + sy2 = addmodpi( sy2, 0.0031); + tx2 = addmodpi( tx2, 0.0011 ); + ty2 = addmodpi( ty2, 0.0023 ); + basecol = addmod( basecol, 1.0, 0.007 ); + + rotate = { + .a11 = cos(angle), + .a12 = -sin(angle), + .a21 = sin(angle), + .a22 = cos(angle) + }; + Matrix zoom = { + .a11 = sin(sx)/4.0 + 0.15, + .a12 = 0, //atan(cos(sx2)), + .a21 = 0, //atan(cos(sy2)), + .a22 = cos(sy)/4.0 + 0.15 + }; + Vector translate = { + .x1 = sin(tx) * LED_WIDTH, + .x2 = sin(ty) * LED_HEIGHT + }; + + for( int x = 0; x < LED_WIDTH; x++ ) { + for( int y = 0; y < LED_HEIGHT; y++ ) { + Vector c = add(multiply( multiply(rotate, zoom), { .x1 = x-rcx, .x2 = y-rcy } ), translate); + //Vector c2 = add(multiply( multiply(zoom2, rotate2), { .x1 = x, .x2 = y } ), translate2); + leds[XYsafe(x,y)] = CHSV((basecol+basefield(c.x1, c.x2))*255, 255, 255); //31+(sines(c2.x1-10, c2.x2-10)*224)); + } + } + } +}; diff --git a/effect_static.h b/effect_static.h new file mode 100644 index 0000000..91cf080 --- /dev/null +++ b/effect_static.h @@ -0,0 +1,18 @@ +class Static : public Effect { + private: + CRGB color; + public: + Static(CRGB col) { + color = col; + } + void loop() { + EVERY_N_SECONDS(1) { + for ( int i = 0; i < LED_COUNT; i++) { + leds[i] = color; + } + FastLED.show(); + } + } + + +}; diff --git a/fastled.ino b/fastled.ino new file mode 100644 index 0000000..28ca0ba --- /dev/null +++ b/fastled.ino @@ -0,0 +1,4 @@ +void fastled_setup() { + FastLED.addLeds(leds, LED_COUNT).setCorrection(TypicalLEDStrip); + FastLED.setBrightness(20); +} diff --git a/functions.h b/functions.h new file mode 100644 index 0000000..0e97950 --- /dev/null +++ b/functions.h @@ -0,0 +1,43 @@ +int XYsafe(int x, int y) { + if ( x >= LED_WIDTH) return 0; + if ( y >= LED_HEIGHT) return 0; + if ( x < 0) return 0; + if ( y < 0) return 0; + + // Invert y + y = LED_HEIGHT - 1 - y; + + if (y & 1) x = LED_WIDTH - 1 - x; + + // Invert x + //x = LED_WIDTH - 1 - x; + + return y*LED_WIDTH+x; +} + +void clear() { + for ( byte y = 0; y < LED_HEIGHT; y++) { + for ( byte x = 0; x < LED_WIDTH; x++) { + leds[ XYsafe(x, y)] = CHSV((16*y)+(47*x), 255, 42); + } + } +} + +inline double sines(double x, double y) { + return ((cos(x) * sin(y)) * 0.5) + 0.5; +} + +inline double basefield(double x, double y) { + return (cos(x) * sin(y) * cos(sqrt((x*x) + (y*y)))); +} + +inline double addmod(double x, double mod, double delta) { + x = x + delta; + while( x >= mod ) x -= mod; + while( x < 0.0 ) x += mod; + return x; +} + +inline double addmodpi(double x, double delta) { + return addmod(x, 2*PI, delta); +} diff --git a/mqtt.h b/mqtt.h new file mode 100644 index 0000000..d2c7daa --- /dev/null +++ b/mqtt.h @@ -0,0 +1,43 @@ +PubSubClient mqtt_client(wifi); +long mqtt_last_reconnect_attempt = 0; + +void mqtt_callback(char* topic, byte* payload, unsigned int length) { + payload[length] = '\0'; + + for (int i=0; i 5000) { + mqtt_last_reconnect_attempt = now; + if (mqtt_connect()) { + mqtt_last_reconnect_attempt = 0; + } + } + } else { + mqtt_client.loop(); + } +} diff --git a/ntp.ino b/ntp.ino new file mode 100644 index 0000000..e94649a --- /dev/null +++ b/ntp.ino @@ -0,0 +1,7 @@ +void ntp_setup() { + ntpClient.begin(); +} + +void ntp_loop() { + ntpClient.update(); +} diff --git a/ota.ino b/ota.ino new file mode 100644 index 0000000..bb9c297 --- /dev/null +++ b/ota.ino @@ -0,0 +1,32 @@ +void ota_setup() { + ArduinoOTA.onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + + // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() + Serial.println("OTA * Start updating " + type); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nOTA * End"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("OTA * Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("OTA * Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + ArduinoOTA.setHostname(OTA_HOSTNAME); + ArduinoOTA.begin(); +} + +void ota_loop() { + ArduinoOTA.handle(); +} diff --git a/pitrix.ino b/pitrix.ino new file mode 100644 index 0000000..f6b19cc --- /dev/null +++ b/pitrix.ino @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include "FastLED.h" +#include +#include + +#include "config.h" +CRGB leds[LED_COUNT]; +WiFiClient wifi; +WiFiUDP ntpUDP; +NTPClient ntpClient(ntpUDP, NTP_SERVER, NTP_OFFSET, NTP_INTERVAL); + +#include "effect.h" +#include "tools.h" +#include "functions.h" +#include "text.h" +#include "sprites.h" +#include "effect_sinematrix3.h" +#include "effect_clock.h" +#include "effect_bell.h" +#include "effect_static.h" + +void setup() { + // put your setup code here, to run once: + Serial.begin(74880); + Serial.println("Core * Starting"); + wifi_setup(); + ota_setup(); + fastled_setup(); + ntp_setup(); + mqtt_setup(); + Serial.println("Core * Setup complete"); +} + +Sinematrix3 effect_sinematrix3; +Clock effect_clock; +Bell effect_bell; +Static effect_off(CRGB(0x000000)); +Effect* current_effect = &effect_clock; + +#define NUM_EFFECTS 4 +EffectEntry effects[NUM_EFFECTS] = { + {"bell", &effect_bell}, + {"sinematrix3", &effect_sinematrix3}, + {"clock", &effect_clock}, + {"off", &effect_off} +}; + +#include "mqtt.h" + +uint8_t starting_up = OTA_STARTUP_DELAY; + +void loop() { + // put your main code here, to run repeatedly: + ota_loop(); + + if (starting_up > 0) { + EVERY_N_SECONDS(1) { + starting_up--; + clear(); + for (int i=0; iloop(); + FastLED.show(); + } +} diff --git a/sprites.h b/sprites.h new file mode 100644 index 0000000..166aa6c --- /dev/null +++ b/sprites.h @@ -0,0 +1,18 @@ +static unsigned char sprite_bell[] = { + 0b00000001, 0b10000000, + 0b00000010, 0b01000000, + 0b00001111, 0b11110000, + 0b00010000, 0b00001000, + 0b00100000, 0b00100100, + 0b00100000, 0b00110100, + 0b00100000, 0b00110100, + 0b00100000, 0b00110100, + 0b00100000, 0b00110100, + 0b00100000, 0b00110100, + 0b00100000, 0b00000100, + 0b01000000, 0b11111010, + 0b01000000, 0b00000010, + 0b00111111, 0b11111100, + 0b00000100, 0b00100000, + 0b00000011, 0b11000000 +}; diff --git a/text.h b/text.h new file mode 100644 index 0000000..d3af117 --- /dev/null +++ b/text.h @@ -0,0 +1,144 @@ +static unsigned char Font5x7[] = { + 0x00, 0x00, 0x00, 0x00, 0x00,// (space) + 0x00, 0x00, 0x5F, 0x00, 0x00,// ! + 0x00, 0x07, 0x00, 0x07, 0x00,// " + 0x14, 0x7F, 0x14, 0x7F, 0x14,// # + 0x24, 0x2A, 0x7F, 0x2A, 0x12,// $ + 0x23, 0x13, 0x08, 0x64, 0x62,// % + 0x36, 0x49, 0x55, 0x22, 0x50,// & + 0x00, 0x05, 0x03, 0x00, 0x00,// ' + 0x00, 0x1C, 0x22, 0x41, 0x00,// ( + 0x00, 0x41, 0x22, 0x1C, 0x00,// ) + 0x08, 0x2A, 0x1C, 0x2A, 0x08,// * + 0x08, 0x08, 0x3E, 0x08, 0x08,// + + 0x00, 0x50, 0x30, 0x00, 0x00,// , + 0x08, 0x08, 0x08, 0x08, 0x08,// - + 0x00, 0x60, 0x60, 0x00, 0x00,// . + 0x20, 0x10, 0x08, 0x04, 0x02,// / + 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0 + 0x00, 0x42, 0x7F, 0x40, 0x00,// 1 + 0x42, 0x61, 0x51, 0x49, 0x46,// 2 + 0x21, 0x41, 0x45, 0x4B, 0x31,// 3 + 0x18, 0x14, 0x12, 0x7F, 0x10,// 4 + 0x27, 0x45, 0x45, 0x45, 0x39,// 5 + 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6 + 0x01, 0x71, 0x09, 0x05, 0x03,// 7 + 0x36, 0x49, 0x49, 0x49, 0x36,// 8 + 0x06, 0x49, 0x49, 0x29, 0x1E,// 9 + 0x00, 0x36, 0x36, 0x00, 0x00,// : + 0x00, 0x56, 0x36, 0x00, 0x00,// ; + 0x00, 0x08, 0x14, 0x22, 0x41,// < + 0x14, 0x14, 0x14, 0x14, 0x14,// = + 0x41, 0x22, 0x14, 0x08, 0x00,// > + 0x02, 0x01, 0x51, 0x09, 0x06,// ? + 0x32, 0x49, 0x79, 0x41, 0x3E,// @ + 0x7E, 0x11, 0x11, 0x11, 0x7E,// A + 0x7F, 0x49, 0x49, 0x49, 0x36,// B + 0x3E, 0x41, 0x41, 0x41, 0x22,// C + 0x7F, 0x41, 0x41, 0x22, 0x1C,// D + 0x7F, 0x49, 0x49, 0x49, 0x41,// E + 0x7F, 0x09, 0x09, 0x01, 0x01,// F + 0x3E, 0x41, 0x41, 0x51, 0x32,// G + 0x7F, 0x08, 0x08, 0x08, 0x7F,// H + 0x00, 0x41, 0x7F, 0x41, 0x00,// I + 0x20, 0x40, 0x41, 0x3F, 0x01,// J + 0x7F, 0x08, 0x14, 0x22, 0x41,// K + 0x7F, 0x40, 0x40, 0x40, 0x40,// L + 0x7F, 0x02, 0x04, 0x02, 0x7F,// M + 0x7F, 0x04, 0x08, 0x10, 0x7F,// N + 0x3E, 0x41, 0x41, 0x41, 0x3E,// O + 0x7F, 0x09, 0x09, 0x09, 0x06,// P + 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q + 0x7F, 0x09, 0x19, 0x29, 0x46,// R + 0x46, 0x49, 0x49, 0x49, 0x31,// S + 0x01, 0x01, 0x7F, 0x01, 0x01,// T + 0x3F, 0x40, 0x40, 0x40, 0x3F,// U + 0x1F, 0x20, 0x40, 0x20, 0x1F,// V + 0x7F, 0x20, 0x18, 0x20, 0x7F,// W + 0x63, 0x14, 0x08, 0x14, 0x63,// X + 0x03, 0x04, 0x78, 0x04, 0x03,// Y + 0x61, 0x51, 0x49, 0x45, 0x43,// Z + 0x00, 0x00, 0x7F, 0x41, 0x41,// [ + 0x02, 0x04, 0x08, 0x10, 0x20,// "\" + 0x41, 0x41, 0x7F, 0x00, 0x00,// ] + 0x04, 0x02, 0x01, 0x02, 0x04,// ^ + 0x40, 0x40, 0x40, 0x40, 0x40,// _ + 0x00, 0x01, 0x02, 0x04, 0x00,// ` + 0x20, 0x54, 0x54, 0x54, 0x78,// a + 0x7F, 0x48, 0x44, 0x44, 0x38,// b + 0x38, 0x44, 0x44, 0x44, 0x20,// c + 0x38, 0x44, 0x44, 0x48, 0x7F,// d + 0x38, 0x54, 0x54, 0x54, 0x18,// e + 0x08, 0x7E, 0x09, 0x01, 0x02,// f + 0x08, 0x14, 0x54, 0x54, 0x3C,// g + 0x7F, 0x08, 0x04, 0x04, 0x78,// h + 0x00, 0x44, 0x7D, 0x40, 0x00,// i + 0x20, 0x40, 0x44, 0x3D, 0x00,// j + 0x00, 0x7F, 0x10, 0x28, 0x44,// k + 0x00, 0x41, 0x7F, 0x40, 0x00,// l + 0x7C, 0x04, 0x18, 0x04, 0x78,// m + 0x7C, 0x08, 0x04, 0x04, 0x78,// n + 0x38, 0x44, 0x44, 0x44, 0x38,// o + 0x7C, 0x14, 0x14, 0x14, 0x08,// p + 0x08, 0x14, 0x14, 0x18, 0x7C,// q + 0x7C, 0x08, 0x04, 0x04, 0x08,// r + 0x48, 0x54, 0x54, 0x54, 0x20,// s + 0x04, 0x3F, 0x44, 0x40, 0x20,// t + 0x3C, 0x40, 0x40, 0x20, 0x7C,// u + 0x1C, 0x20, 0x40, 0x20, 0x1C,// v + 0x3C, 0x40, 0x30, 0x40, 0x3C,// w + 0x44, 0x28, 0x10, 0x28, 0x44,// x + 0x0C, 0x50, 0x50, 0x50, 0x3C,// y + 0x44, 0x64, 0x54, 0x4C, 0x44,// z + 0x00, 0x08, 0x36, 0x41, 0x00,// { + 0x00, 0x00, 0x7F, 0x00, 0x00,// | + 0x00, 0x41, 0x36, 0x08, 0x00,// } + 0x08, 0x08, 0x2A, 0x1C, 0x08,// -> + 0x08, 0x1C, 0x2A, 0x08, 0x08 // <- +}; + +static unsigned char numbers4x7[] = { + 0x3E, 0x51, 0x45, 0x3E,// 0 + 0x00, 0x42, 0x7F, 0x40,// 1 + 0x42, 0x61, 0x49, 0x46,// 2 + 0x21, 0x45, 0x4B, 0x31,// 3 + 0x18, 0x14, 0x7F, 0x10,// 4 + 0x27, 0x45, 0x45, 0x39,// 5 + 0x3C, 0x4A, 0x49, 0x30,// 6 + 0x01, 0x71, 0x09, 0x05, // 7 + 0x36, 0x49, 0x49, 0x36,// 8 + 0x06, 0x49, 0x29, 0x1E// 9 +}; + +unsigned char* Char(unsigned char* font, char c) { + return &font[(c - 32) * 5]; +} + +void DrawSprite(unsigned char* sprite, int length, int xOffset, int yOffset, CRGB color) { + // leds[ XYsafe(x, y) ] = CHSV(0, 0, 255); + for ( byte y = 0; y < 7; y++) { + for ( byte x = 0; x < 5; x++) { + bool on = (sprite[x] >> y & 1) * 255; + if (on) { + leds[ XYsafe(x + xOffset, y + yOffset) ] = color; + } + } + } +} + +void DrawText(char *text, int x, int y, CRGB color) { + for (int i = 0; i < strlen(text); i++) { + DrawSprite(Char(Font5x7, text[i]), 5, x + i * 6, y, color); + } +} + +void DrawTextOneFrame(char *text, int xOffset, int yOffset, CRGB color) { + DrawText(text, xOffset, yOffset, color); +} + +void DrawNumberOneFrame(uint32_t number, int xOffset, int yOffset, CRGB color) { + char buffer[7]; + //itoa(number,buffer,10); + sprintf(buffer, "%02d", number); + DrawTextOneFrame(buffer, xOffset, yOffset, color); +} diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..cf9be04 --- /dev/null +++ b/tools.h @@ -0,0 +1,42 @@ +typedef struct Vector { + double x1; + double x2; +} Vector; + +typedef struct Matrix { + double a11; + double a12; + double a21; + double a22; +} Matrix; + +struct Matrix multiply(struct Matrix m1, struct Matrix m2) { + Matrix r = { + .a11 = m1.a11*m2.a11 + m1.a12*m2.a21, + .a12 = m1.a11*m2.a12 + m1.a12*m2.a22, + .a21 = m1.a21*m2.a11 + m1.a22*m2.a21, + .a22 = m1.a21*m2.a12 + m1.a22*m2.a22 + }; + return r; +}; + +struct Vector multiply(struct Matrix m, struct Vector v) { + Vector r = { + .x1 = (m.a11*v.x1) + (m.a12*v.x2), + .x2 = (m.a21*v.x1) + (m.a22*v.x2) + }; + return r; +} + +struct Vector add(struct Vector v1, struct Vector v2) { + Vector r = { + .x1 = v1.x1 + v2.x2, + .x2 = v1.x2 + v2.x2 + }; + return r; +} + +struct EffectEntry { + char* name; + Effect* effect; +}; diff --git a/wifi.ino b/wifi.ino new file mode 100644 index 0000000..91c6b13 --- /dev/null +++ b/wifi.ino @@ -0,0 +1,13 @@ +void wifi_setup() { + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASS); + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi * Connection Failed! Rebooting..."); + delay(5000); + ESP.restart(); + } + Serial.println("WiFi * Ready"); + Serial.print("WiFi * IP address: "); + Serial.println(WiFi.localIP()); +} +