#include // homie lib from: https://github.com/marvinroger/homie-esp8266/ #include #ifdef __AVR__ #include #endif #define PIN 2 //data pin for ws2812 #define NUMPIXELS 64 #define FPS 15 uint8_t effect=0; #define EFFECT_NONE 0 #define EFFECT_SMOOTH 1 uint8_t movingPoint_x=3; uint8_t movingPoint_y=3; uint8_t wheelPos=0; uint8_t wheelPosSlow=0; //for slower wheelPos increment than 1 int wheelSpeed=16; //16=+1/frame int smoothing=80; //0 to 100. 100=no change (ultrasmooth), 0=no smoothing. int strength=50; //how much pixels to apply color to #define EFFECT_SPIRAL 2 #define EFFECT_RANDOMFADE 3 int fadespeedmax=5; //1 to 255 int iconCountStart=0; //for percentage calculation int iconCountdown=0; //0=off uint8_t iconchar=0; //last displayed char int32_t iconcolor=0; //last icon color /* the values in this array are a 8x8 bitmap font for ascii characters */ static uint64_t font[128] = { /************************************************************************ * font.c * Copyright (C) Lisa Milne 2014 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see ************************************************************************/ 0x7E7E7E7E7E7E0000, /* NUL */ 0x7E7E7E7E7E7E0000, /* SOH */ 0x7E7E7E7E7E7E0000, /* STX */ 0x7E7E7E7E7E7E0000, /* ETX */ 0x7E7E7E7E7E7E0000, /* EOT */ 0x7E7E7E7E7E7E0000, /* ENQ */ 0x7E7E7E7E7E7E0000, /* ACK */ 0x7E7E7E7E7E7E0000, /* BEL */ 0x7E7E7E7E7E7E0000, /* BS */ 0x0, /* TAB */ 0x7E7E7E7E7E7E0000, /* LF */ 0x7E7E7E7E7E7E0000, /* VT */ 0x7E7E7E7E7E7E0000, /* FF */ 0x7E7E7E7E7E7E0000, /* CR */ 0x7E7E7E7E7E7E0000, /* SO */ 0x7E7E7E7E7E7E0000, /* SI */ 0x7E7E7E7E7E7E0000, /* DLE */ 0x7E7E7E7E7E7E0000, /* DC1 */ 0x7E7E7E7E7E7E0000, /* DC2 */ 0x7E7E7E7E7E7E0000, /* DC3 */ 0x7E7E7E7E7E7E0000, /* DC4 */ 0x7E7E7E7E7E7E0000, /* NAK */ 0x7E7E7E7E7E7E0000, /* SYN */ 0x7E7E7E7E7E7E0000, /* ETB */ 0x7E7E7E7E7E7E0000, /* CAN */ 0x7E7E7E7E7E7E0000, /* EM */ 0x7E7E7E7E7E7E0000, /* SUB */ 0x7E7E7E7E7E7E0000, /* ESC */ 0x7E7E7E7E7E7E0000, /* FS */ 0x7E7E7E7E7E7E0000, /* GS */ 0x7E7E7E7E7E7E0000, /* RS */ 0x7E7E7E7E7E7E0000, /* US */ 0x0, /* (space) */ 0x808080800080000, /* ! */ 0x2828000000000000, /* " */ 0x287C287C280000, /* # */ 0x81E281C0A3C0800, /* $ */ 0x6094681629060000, /* % */ 0x1C20201926190000, /* & */ 0x808000000000000, /* ' */ 0x810202010080000, /* ( */ 0x1008040408100000, /* ) */ 0x2A1C3E1C2A000000, /* * */ 0x8083E08080000, /* + */ 0x81000, /* , */ 0x3C00000000, /* - */ 0x80000, /* . */ 0x204081020400000, /* / */ 0x1824424224180000, /* 0 */ 0x8180808081C0000, /* 1 */ 0x3C420418207E0000, /* 2 */ 0x3C420418423C0000, /* 3 */ 0x81828487C080000, /* 4 */ 0x7E407C02423C0000, /* 5 */ 0x3C407C42423C0000, /* 6 */ 0x7E04081020400000, /* 7 */ 0x3C423C42423C0000, /* 8 */ 0x3C42423E023C0000, /* 9 */ 0x80000080000, /* : */ 0x80000081000, /* ; */ 0x6186018060000, /* < */ 0x7E007E000000, /* = */ 0x60180618600000, /* > */ 0x3844041800100000, /* ? */ 0x3C449C945C201C, /* @ */ 0x1818243C42420000, /* A */ 0x7844784444780000, /* B */ 0x3844808044380000, /* C */ 0x7844444444780000, /* D */ 0x7C407840407C0000, /* E */ 0x7C40784040400000, /* F */ 0x3844809C44380000, /* G */ 0x42427E4242420000, /* H */ 0x3E080808083E0000, /* I */ 0x1C04040444380000, /* J */ 0x4448507048440000, /* K */ 0x40404040407E0000, /* L */ 0x4163554941410000, /* M */ 0x4262524A46420000, /* N */ 0x1C222222221C0000, /* O */ 0x7844784040400000, /* P */ 0x1C222222221C0200, /* Q */ 0x7844785048440000, /* R */ 0x1C22100C221C0000, /* S */ 0x7F08080808080000, /* T */ 0x42424242423C0000, /* U */ 0x8142422424180000, /* V */ 0x4141495563410000, /* W */ 0x4224181824420000, /* X */ 0x4122140808080000, /* Y */ 0x7E040810207E0000, /* Z */ 0x3820202020380000, /* [ */ 0x4020100804020000, /* */ 0x3808080808380000, /* ] */ 0x1028000000000000, /* ^ */ 0x7E0000, /* _ */ 0x1008000000000000, /* ` */ 0x3C023E463A0000, /* a */ 0x40407C42625C0000, /* b */ 0x1C20201C0000, /* c */ 0x2023E42463A0000, /* d */ 0x3C427E403C0000, /* e */ 0x18103810100000, /* f */ 0x344C44340438, /* g */ 0x2020382424240000, /* h */ 0x800080808080000, /* i */ 0x800180808080870, /* j */ 0x20202428302C0000, /* k */ 0x1010101010180000, /* l */ 0x665A42420000, /* m */ 0x2E3222220000, /* n */ 0x3C42423C0000, /* o */ 0x5C62427C4040, /* p */ 0x3A46423E0202, /* q */ 0x2C3220200000, /* r */ 0x1C201804380000, /* s */ 0x103C1010180000, /* t */ 0x2222261A0000, /* u */ 0x424224180000, /* v */ 0x81815A660000, /* w */ 0x422418660000, /* x */ 0x422214081060, /* y */ 0x3C08103C0000, /* z */ 0x1C103030101C0000, /* { */ 0x808080808080800, /* | */ 0x38080C0C08380000, /* } */ 0x324C000000, /* ~ */ 0x7E7E7E7E7E7E0000 /* DEL */ }; Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); HomieNode homieNode("pixel", "commands"); uint8_t pixelR[NUMPIXELS]; uint8_t pixelG[NUMPIXELS]; uint8_t pixelB[NUMPIXELS]; //write to buffer, flip with showBuffer() uint8_t pixelR_buffer[NUMPIXELS]; uint8_t pixelG_buffer[NUMPIXELS]; uint8_t pixelB_buffer[NUMPIXELS]; long lastMillis=0; long fpsdelay=1000/FPS; int xyToPos(int x, int y){ //convert x y pixel position to matrix position if (y%2==0){ return (y*8+x); }else{ return (y*8+(7-x)); } } int numToPos(int num){ //convert pixel number to actual 8x8 matrix position int x=num%8; int y=num/8; return xyToPos(x,y); } uint32_t wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } if(WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } void led_fill(uint32_t c) { for (int i=0; i < strip.numPixels(); i++) { strip.setPixelColor(i, c); } strip.show(); } void led_random() { for (int i=0; i < strip.numPixels(); i++) { strip.setPixelColor(i, wheel(random(0,255))); } strip.show(); } void showBuffer() { for (int i=0; i < strip.numPixels(); i++) { pixelR[i]=pixelR_buffer[i]; pixelG[i]=pixelG_buffer[i]; pixelB[i]=pixelB_buffer[i]; strip.setPixelColor(i, pixelR[i], pixelG[i], pixelB[i]); } strip.show(); } uint8_t getAverage(uint8_t array[NUMPIXELS], uint8_t i, int x, int y) { uint16_t sum=0; uint8_t count=0; if (i>=8){ //up sum+=array[i-8]; count++; } if (i<(64-8)){ //down sum+=array[i+8]; count++; } if (i>=1){ //left sum+=array[i-1]; count++; } if (i<(64-1)){ //right sum+=array[i+1]; count++; } /* if (i>=(8+1)){ //up left sum+=array[i-8-1]; count++; } if (i<(64-8-1)){ //down left sum+=array[i+8-1]; count++; } if (i>=(8-1)){ //up right sum+=array[i-8+1]; count++; } if (i<(64-8+1)){ //down right sum+=array[i+8+1]; count++; }*/ return sum/count; } void led_smooth() { for (int i=0; i < strip.numPixels(); i++) { //uint8_t avgbrightness=pixelR_buffer[i]/3+pixelG_buffer[i]/3+pixelB_buffer[i]/3; pixelR_buffer[i]=(smoothing/100.0)*pixelR[i] + (1.0-(smoothing/100.0))*getAverage(pixelR,i, 0,0); pixelG_buffer[i]=(smoothing/100.0)*pixelG[i] + (1.0-(smoothing/100.0))*getAverage(pixelG,i, 0,0); pixelB_buffer[i]=(smoothing/100.0)*pixelB[i] + (1.0-(smoothing/100.0))*getAverage(pixelB,i, 0,0); } showBuffer(); } void led_movingPoint() { uint32_t c=wheel(wheelPos); wheelPosSlow+=wheelSpeed; wheelPos=(wheelPos+ (wheelPosSlow/10) )%255; wheelPosSlow=wheelPosSlow%16; uint8_t r = (uint8_t)(c >> 16); uint8_t g = (uint8_t)(c >> 8); uint8_t b = (uint8_t)c; movingPoint_x=movingPoint_x+8+random(-random(0,1+1),random(0,1+1)+1); movingPoint_y=movingPoint_y+8+random(-random(0,1+1),random(0,1+1)+1); if (movingPoint_x<8){ movingPoint_x=8-movingPoint_x; }else if (movingPoint_x>=16){ movingPoint_x=22-movingPoint_x; }else{ movingPoint_x-=8; } if (movingPoint_y<8){ movingPoint_y=8-movingPoint_y; }else if (movingPoint_y>=16){ movingPoint_y=22-movingPoint_y; }else{ movingPoint_y-=8; } uint8_t startx=movingPoint_x; uint8_t starty=movingPoint_y; for (int i=0;i=16){ movingPoint_x=22-movingPoint_x; }else{ movingPoint_x-=8; } if (movingPoint_y<8){ movingPoint_y=8-movingPoint_y; }else if (movingPoint_y>=16){ movingPoint_y=22-movingPoint_y; }else{ movingPoint_y-=8; } if (pixelR[xyToPos(movingPoint_x,movingPoint_y)]r){ pixelR[xyToPos(movingPoint_x,movingPoint_y)]--; } if (pixelG[xyToPos(movingPoint_x,movingPoint_y)]g){ pixelG[xyToPos(movingPoint_x,movingPoint_y)]--; } if (pixelB[xyToPos(movingPoint_x,movingPoint_y)]b){ pixelB[xyToPos(movingPoint_x,movingPoint_y)]--; } } //pixelR[xyToPos(movingPoint_x,movingPoint_y)]=0.5*pixelR[xyToPos(movingPoint_x,movingPoint_y)]+0.5*r; //pixelG[xyToPos(movingPoint_x,movingPoint_y)]=0.5*pixelG[xyToPos(movingPoint_x,movingPoint_y)]+0.5*g; //pixelB[xyToPos(movingPoint_x,movingPoint_y)]=0.5*pixelB[xyToPos(movingPoint_x,movingPoint_y)]+0.5*b; movingPoint_x=startx; movingPoint_y=starty; } void bufferClear() { for (int i=0; i < strip.numPixels(); i++) { pixelR_buffer[i]=0; pixelG_buffer[i]=0; pixelB_buffer[i]=0; } } void led_spiral() { wheelPos++; for (int i=0; i < strip.numPixels(); i++) { //strip.setPixelColor(i,wheel((wheelPos+i*5)%255)); } strip.show(); } void led_randomfade() { for (int i=0; i < strip.numPixels(); i++) { pixelR_buffer[i]+=random(0,random(0,fadespeedmax+1)+1); //use buffer red channel for color wheel strip.setPixelColor(i,wheel(pixelR_buffer[i])); } strip.show(); } void led_icon(uint8_t fontchar, uint32_t iconcolor) { for (int i=0; i < strip.numPixels(); i++) { uint64_t mask=1LL<<(uint64_t)i; if ( (font[fontchar]&mask) == 0){ strip.setPixelColor(numToPos(i),strip.Color(0, 0, 0)); //bit is 0 at pos i }else{ float _brightness=1.0- ( (iconCountStart-iconCountdown)*1.0/iconCountStart ); uint8_t _r=(uint8_t)(iconcolor >> 16); uint8_t _g=(uint8_t)(iconcolor >> 8); uint8_t _b=(uint8_t)iconcolor; strip.setPixelColor(numToPos(i),strip.Color(_r*_brightness,_g*_brightness,_b*_brightness)); //bit is 1 at pos i } } strip.show(); } void set_randomBuffer() { for (int i=0; i < strip.numPixels(); i++) { uint32_t c=wheel(random(0,256)); pixelR_buffer[i]=(uint8_t)(c >> 16); pixelG_buffer[i]=(uint8_t)(c >> 8); pixelB_buffer[i]=(uint8_t)c; } } uint32_t parseColor(String value){ if (value.charAt(0)=='#'){ //solid fill String color=value.substring(1); int number = (int) strtol( &color[0], NULL, 16); // Split them up into r, g, b values int r = number >> 16; int g = number >> 8 & 0xFF; int b = number & 0xFF; Homie.getLogger() << "r=" << r << " g=" << g << " b=" << b << endl; //Serial.print("r=");Serial.print(r); //Serial.print(" g=");Serial.print(g); //Serial.print(" b=");Serial.println(b); return strip.Color(r, g, b); } return 0; } bool effectHandler(const HomieRange& range, const String& value) { Homie.getLogger() << "-> " << value << endl; int sep = value.indexOf("|"); String command=value.substring(0,sep); String parameters=value.substring(sep+1); Homie.getLogger() << "command=" << command << " parameters=" << parameters << endl; if (command.equals("fill")){ effect=EFFECT_NONE; led_fill(parseColor(parameters)); }else if (command.equals("off")){ effect=EFFECT_NONE; led_fill(strip.Color(0, 0, 0)); }else if (command.equals("random")){ effect=EFFECT_NONE; led_random(); }else if (command.equals("set")){ //example: set|37#ff003a effect=EFFECT_NONE; int x=parameters.substring(0,1).toInt(); int y=parameters.substring(1,2).toInt(); String cstr=parameters.substring(2,9); strip.setPixelColor(xyToPos(x,y), parseColor(cstr)); strip.show(); }else if (command.equals("smooth")){ //example: smooth|[wheelspeed]|[smoothing]|[strength] wheelspeed=1-255, smoothing=0-100, strength=1-255 int sepparam = parameters.indexOf("|"); int p1=parameters.substring(0,sepparam).toInt(); String parameters_part2=parameters.substring(sepparam+1); sepparam = parameters_part2.indexOf("|"); int p2=parameters_part2.substring(0,sepparam).toInt(); int p3=parameters_part2.substring(sepparam+1).toInt(); wheelSpeed=16; //default, speed=+1 /frame if (p1>0){ wheelSpeed=p1; } smoothing=80; if (p2>0){ smoothing=p2; } strength=50; if (p3>0){ strength=p3; } Homie.getLogger() << "-- p1=" << p1 << " p2=" << p2 << " p3=" << p3 << endl; effect=EFFECT_SMOOTH; bufferClear(); showBuffer(); strip.show(); }else if (command.equals("spiral")){ effect=EFFECT_SPIRAL; bufferClear(); showBuffer(); strip.show(); }else if (command.equals("clearbuffer")){ bufferClear(); showBuffer(); strip.show(); }else if (command.equals("randomfade")){ //example: randomfade|5 int sepparam = parameters.indexOf("|"); int p1=parameters.substring(0,sepparam).toInt(); fadespeedmax=5; if (p1>0){ fadespeedmax=p1; } effect=EFFECT_RANDOMFADE; set_randomBuffer(); //initialize random }else if (command.equals("randombuffer")){ set_randomBuffer(); //set random showBuffer(); } return true; } bool pixelsHandler(const HomieRange& range, const String& value) { String remaining=value; int i=0; effect=EFFECT_NONE; do{ String current=remaining.substring(0,7); Homie.getLogger() << i << ":" << current << endl; uint32_t currentcolor=parseColor(current); strip.setPixelColor(i, currentcolor); i++; remaining=remaining.substring(7); }while(remaining.length()>2 && (i0){ //icon effect active iconCountdown--; led_icon(iconchar,iconcolor); }else{ switch(effect){ case EFFECT_SMOOTH: led_movingPoint(); led_smooth(); break; case EFFECT_SPIRAL: led_spiral(); break; case EFFECT_RANDOMFADE: led_randomfade(); break; } } lastMillis=currentMillis; } }