Initial commit.

This commit is contained in:
Fabian Schlenz 2019-05-21 05:52:57 +02:00
commit 81433310f9
17 changed files with 611 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
config.h

27
config.sample.h Normal file
View File

@ -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

4
effect.h Normal file
View File

@ -0,0 +1,4 @@
class Effect {
public:
virtual void loop() {};
};

24
effect_bell.h Normal file
View File

@ -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;
}
}
};

45
effect_clock.h Normal file
View File

@ -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);
}
};

68
effect_sinematrix3.h Normal file
View File

@ -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));
}
}
}
};

18
effect_static.h Normal file
View File

@ -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();
}
}
};

4
fastled.ino Normal file
View File

@ -0,0 +1,4 @@
void fastled_setup() {
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, LED_COUNT).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(20);
}

43
functions.h Normal file
View File

@ -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);
}

43
mqtt.h Normal file
View File

@ -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<NUM_EFFECTS; i++) {
EffectEntry e = effects[i];
if (strcmp(e.name, (char*)payload)==0) {
current_effect = e.effect;
clear();
return;
}
}
}
boolean mqtt_connect() {
if (mqtt_client.connect("pitrix", MQTT_USER, MQTT_PASS)) {
mqtt_client.subscribe(MQTT_TOPIC_MODE);
mqtt_client.publish(MQTT_TOPIC_STATUS, "ONLINE");
}
return mqtt_client.connected();
}
void mqtt_setup() {
mqtt_client.setServer(MQTT_SERVER, MQTT_PORT);
mqtt_client.setCallback(mqtt_callback);
mqtt_last_reconnect_attempt = 0;
}
void mqtt_loop() {
if (!mqtt_client.connected()) {
long now = millis();
if (now - mqtt_last_reconnect_attempt > 5000) {
mqtt_last_reconnect_attempt = now;
if (mqtt_connect()) {
mqtt_last_reconnect_attempt = 0;
}
}
} else {
mqtt_client.loop();
}
}

7
ntp.ino Normal file
View File

@ -0,0 +1,7 @@
void ntp_setup() {
ntpClient.begin();
}
void ntp_loop() {
ntpClient.update();
}

32
ota.ino Normal file
View File

@ -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();
}

78
pitrix.ino Normal file
View File

@ -0,0 +1,78 @@
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "FastLED.h"
#include <NTPClient.h>
#include <PubSubClient.h>
#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; i<starting_up; i++) {
leds[XYsafe(i, 0)] = CRGB(0xff0000);
}
FastLED.show();
}
return;
}
ntp_loop();
mqtt_loop();
EVERY_N_MILLISECONDS(1000 / FPS) {
current_effect->loop();
FastLED.show();
}
}

18
sprites.h Normal file
View File

@ -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
};

144
text.h Normal file
View File

@ -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);
}

42
tools.h Normal file
View File

@ -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;
};

13
wifi.ino Normal file
View File

@ -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());
}