From c0816c80ae29e4432bcd6bb0d3551a15b25c970a Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sun, 18 Nov 2018 00:31:45 +0100 Subject: [PATCH] Infrared support added --- wled00/NpbWrapper.h | 9 ++- wled00/ir_codes.h | 89 +++++++++++++++++++++++++++ wled00/wled00.ino | 16 +++-- wled00/wled01_eeprom.ino | 33 +++++++--- wled00/wled05_init.ino | 10 ++-- wled00/wled08_led.ino | 3 +- wled00/wled09_button.ino | 18 +++--- wled00/wled14_colors.ino | 8 +++ wled00/wled19_ir.ino | 126 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 282 insertions(+), 30 deletions(-) create mode 100644 wled00/ir_codes.h create mode 100644 wled00/wled19_ir.ino diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h index 221fade5..1bbe6d66 100644 --- a/wled00/NpbWrapper.h +++ b/wled00/NpbWrapper.h @@ -2,10 +2,15 @@ #ifndef NpbWrapper_h #define NpbWrapper_h -#define WORKAROUND_ESP32_BITBANG +//#define WORKAROUND_ESP32_BITBANG //see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support -#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 is recommended for ESP8266 +//PIN CONFIGURATION +#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 is recommended for ESP8266 +#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended) +#define IR_PIN 4 //infrared pin. +#define AUXPIN 15 //unused auxiliary output pin + //uncomment this if red and green are swapped //#define SWAPRG diff --git a/wled00/ir_codes.h b/wled00/ir_codes.h new file mode 100644 index 00000000..0f07c226 --- /dev/null +++ b/wled00/ir_codes.h @@ -0,0 +1,89 @@ +//Infrared codes from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/ +#define IR24_BRIGHTER 0xF700FF +#define IR24_DARKER 0xF7807F +#define IR24_OFF 0xF740BF +#define IR24_ON 0xF7C03F +#define IR24_RED 0xF720DF +#define IR24_REDDISH 0xF710EF +#define IR24_ORANGE 0xF730CF +#define IR24_YELLOWISH 0xF708F7 +#define IR24_YELLOW 0xF728D7 +#define IR24_GREEN 0xF7A05F +#define IR24_GREENISH 0xF7906F +#define IR24_TURQUOISE 0xF7B04F +#define IR24_CYAN 0xF78877 +#define IR24_AQUA 0xF7A857 +#define IR24_BLUE 0xF7609F +#define IR24_DEEPBLUE 0xF750AF +#define IR24_PURPLE 0xF7708F +#define IR24_MAGENTA 0xF748B7 +#define IR24_PINK 0xF76897 +#define IR24_WHITE 0xF7E01F +#define IR24_FLASH 0xF7D02F +#define IR24_STROBE 0xF7F00F +#define IR24_FADE 0xF7C837 +#define IR24_SMOOTH 0xF7E817 + +/* 44-key defs, to be done later +#define IR44_BPlus 0xFF3AC5 // +#define IR44_BMinus 0xFFBA45 // +#define IR44_ON 0xFF827D // +#define IR44_OFF 0xFF02FD // +#define IR44_R 0xFF1AE5 // +#define IR44_G 0xFF9A65 // +#define IR44_B 0xFFA25D // +#define IR44_W 0xFF22DD // +#define IR44_B1 0xFF2AD5 // +#define IR44_B2 0xFFAA55 // +#define IR44_B3 0xFF926D // +#define IR44_B4 0xFF12ED // +#define IR44_B5 0xFF0AF5 // +#define IR44_B6 0xFF8A75 // +#define IR44_B7 0xFFB24D // +#define IR44_B8 0xFF32CD // +#define IR44_B9 0xFF38C7 // +#define IR44_B10 0xFFB847 // +#define IR44_B11 0xFF7887 // +#define IR44_B12 0xFFF807 // +#define IR44_B13 0xFF18E7 // +#define IR44_B14 0xFF9867 // +#define IR44_B15 0xFF58A7 // +#define IR44_B16 0xFFD827 // +#define IR44_UPR 0xFF28D7 // +#define IR44_UPG 0xFFA857 // +#define IR44_UPB 0xFF6897 // +#define IR44_QUICK 0xFFE817 // +#define IR44_DOWNR 0xFF08F7 // +#define IR44_DOWNG 0xFF8877 // +#define IR44_DOWNB 0xFF48B7 // +#define IR44_SLOW 0xFFC837 // +#define IR44_DIY1 0xFF30CF // +#define IR44_DIY2 0xFFB04F // +#define IR44_DIY3 0xFF708F // +#define IR44_AUTO 0xFFF00F // +#define IR44_DIY4 0xFF10EF // +#define IR44_DIY5 0xFF906F // +#define IR44_DIY6 0xFF50AF // +#define IR44_FLASH 0xFFD02F // +#define IR44_JUMP3 0xFF20DF // +#define IR44_JUMP7 0xFFA05F // +#define IR44_FADE3 0xFF609F // +#define IR44_FADE7 0xFFE01F // +*/ + +#define COLOR_RED 0xFF0000 +#define COLOR_REDDISH 0xFF7800 +#define COLOR_ORANGE 0xFFA000 +#define COLOR_YELLOWISH 0xFFC800 +#define COLOR_YELLOW 0xFFFF00 +#define COLOR_GREEN 0x00FF00 +#define COLOR_GREENISH 0x00FF78 +#define COLOR_TURQUOISE 0x00FFA0 +#define COLOR_CYAN 0x00FFDC +#define COLOR_AQUA 0x00C8FF +#define COLOR_BLUE 0x00A0FF +#define COLOR_DEEPBLUE 0x0000FF +#define COLOR_PURPLE 0xAA00FF +#define COLOR_MAGENTA 0xFF00DC +#define COLOR_PINK 0xFF00A0 +#define COLOR_WHITE 0xFFFFDC diff --git a/wled00/wled00.ino b/wled00/wled00.ino index ec6608a2..e00b12d5 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -24,7 +24,7 @@ //#define WLED_DISABLE_MOBILE_UI //to toggle usb serial debug (un)comment following line(s) -//#define DEBUG +//#define WLED_DEBUG //library inclusions #include @@ -33,11 +33,15 @@ #include #include "src/dependencies/webserver/WebServer.h" #include + #include #else #include #include #include #include + #include + #include + #include #endif #include @@ -60,10 +64,11 @@ #include "html_settings.h" #include "html_other.h" #include "WS2812FX.h" +#include "ir_codes.h" //version code in format yymmddb (b = daily build) -#define VERSION 1811162 +#define VERSION 1811172 char versionString[] = "0.8.2-dev"; @@ -77,9 +82,8 @@ char otaPass[33] = "wledota"; //Hardware CONFIG (only changeble HERE, not at runtime) -//LED strip pin changeable in NpbWrapper.h. Only change for ESP32 -byte buttonPin = 0; //needs pull-up -byte auxPin = 15; //debug feature, use e.g. for external relay with API call AX= +//LED strip pin, button pin and IR pin changeable in NpbWrapper.h! + byte auxDefaultState = 0; //0: input 1: high 2: low byte auxTriggeredState = 0; //0: input 1: high 2: low char ntpServerName[] = "0.wled.pool.ntp.org"; //NTP server to use @@ -145,6 +149,7 @@ bool useHSBDefault = useHSB; //Sync CONFIG bool buttonEnabled = true; +bool irEnabled = true; //Infrared receiver uint16_t udpPort = 21324; //WLED notifier default port uint16_t udpRgbPort = 19446; //Hyperion port @@ -492,6 +497,7 @@ void loop() { yield(); handleButton(); + handleIR(); handleNetworkTime(); if (!onlyAP) { diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 197c9fd5..06dee8cf 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -246,7 +246,7 @@ void saveSettingsToEEPROM() writeStringToEEPROM(2333, mqttDeviceTopic, 32); writeStringToEEPROM(2366, mqttGroupTopic, 32); - EEPROM.commit(); + commit(); } /* @@ -502,12 +502,16 @@ void loadSettingsFromEEPROM(bool first) //0: preset purpose byte 0:invalid 1:valid preset 1.0 //1:a 2:r 3:g 4:b 5:w 6:er 7:eg 8:eb 9:ew 10:fx 11:sx | custom chase 12:numP 13:numS 14:(0:fs 1:both 2:fe) 15:step 16:ix 17: fp 18-19:Zeros -void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX) +bool applyPreset(byte index, bool loadBri = true, bool loadCol = true, bool loadFX = true) { - if (index == 255 || index == 0) loadSettingsFromEEPROM(false);//load boot defaults - if (index > 25 || index < 1) return; + if (index == 255 || index == 0) + { + loadSettingsFromEEPROM(false);//load boot defaults + return true; + } + if (index > 25 || index < 1) return false; uint16_t i = 380 + index*20; - if (EEPROM.read(i) == 0) return; + if (EEPROM.read(i) == 0) return false; if (loadBri) bri = EEPROM.read(i+1); if (loadCol) { @@ -532,6 +536,7 @@ void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX) strip.setIntensity(effectIntensity); strip.setPalette(effectPalette); } + return true; } void savePreset(byte index) @@ -554,7 +559,7 @@ void savePreset(byte index) EEPROM.write(i+16, effectIntensity); EEPROM.write(i+17, effectPalette); - EEPROM.commit(); + commit(); } String loadMacro(byte index) @@ -597,5 +602,19 @@ void saveMacro(byte index, String mc, bool sing=true) //only commit on single sa { EEPROM.write(i, mc.charAt(i-s)); } - if (sing) EEPROM.commit(); + if (sing) commit(); +} + +void commit() +{ + #ifdef ARDUINO_ARCH_ESP32 + delay(1); + portDISABLE_INTERRUPTS(); + #endif + + EEPROM.commit(); + + #ifdef ARDUINO_ARCH_ESP32 + portENABLE_INTERRUPTS(); + #endif } diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 12c38ce1..e93bc358 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -120,6 +120,7 @@ void wledInit() if (initLedsLast) initStrip(); userBegin(); + if (macroBoot>0) applyMacro(macroBoot); Serial.println("Ada"); } @@ -132,16 +133,13 @@ void initStrip() strip.setColor(0); strip.setBrightness(255); - pinMode(buttonPin, INPUT_PULLUP); - pinMode(4,OUTPUT); //this is only needed in special cases - digitalWrite(4,LOW); + pinMode(BTNPIN, INPUT_PULLUP); if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true); colorUpdated(0); //disable button if it is "pressed" unintentionally - if(digitalRead(buttonPin) == LOW) buttonEnabled = false; - + if(digitalRead(BTNPIN) == LOW) buttonEnabled = false; } void initAP(){ @@ -259,7 +257,7 @@ void getBuildInfo() oappend("debug: false\r\n"); #endif oappend("button-pin: gpio"); - oappendi(buttonPin); + oappendi(BTNPIN); oappend("\r\nstrip-pin: gpio"); oappendi(LEDPIN); oappend("\r\nbrand: wled\r\n"); diff --git a/wled00/wled08_led.ino b/wled00/wled08_led.ino index 48e27984..de1d3a1f 100644 --- a/wled00/wled08_led.ino +++ b/wled00/wled08_led.ino @@ -73,7 +73,8 @@ void colorUpdated(int callMode) //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (NN)6: fx changed 7: hue 8: preset cycle 9: blynk if (!colorChanged()) { - if (callMode == 6) notify(6); + if (callMode == 2) notify(2); + else if (callMode == 6) notify(6); return; //no change } if (callMode != 5 && nightlightActive && nightlightFade) diff --git a/wled00/wled09_button.ino b/wled00/wled09_button.ino index e28653b7..0c6e3a27 100644 --- a/wled00/wled09_button.ino +++ b/wled00/wled09_button.ino @@ -6,15 +6,15 @@ void handleButton() { if (buttonEnabled) { - if (digitalRead(buttonPin) == LOW && !buttonPressedBefore) + if (digitalRead(BTNPIN) == LOW && !buttonPressedBefore) { buttonPressedTime = millis(); buttonPressedBefore = true; } - else if (digitalRead(buttonPin) == HIGH && buttonPressedBefore) + else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore) { delay(15); //debounce - if (digitalRead(buttonPin) == HIGH) + if (digitalRead(BTNPIN) == HIGH) { if (millis() - buttonPressedTime > 7000) {initAP();} else if (millis() - buttonPressedTime > 700) @@ -51,9 +51,9 @@ void handleButton() auxActiveBefore = true; switch (auxTriggeredState) { - case 0: pinMode(auxPin, INPUT); break; - case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break; - case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break; + case 0: pinMode(AUXPIN, INPUT); break; + case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; + case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; } auxStartTime = millis(); } @@ -63,9 +63,9 @@ void handleButton() auxActiveBefore = false; switch (auxDefaultState) { - case 0: pinMode(auxPin, INPUT); break; - case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break; - case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break; + case 0: pinMode(AUXPIN, INPUT); break; + case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; + case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; } } } diff --git a/wled00/wled14_colors.ino b/wled00/wled14_colors.ino index 5140cf7e..5dbf378b 100644 --- a/wled00/wled14_colors.ino +++ b/wled00/wled14_colors.ino @@ -2,6 +2,14 @@ * Color conversion methods */ +void colorFromUint32(uint32_t in) +{ + white = in >> 24 & 0xFF; + col[0] = in >> 16 & 0xFF; + col[1] = in >> 8 & 0xFF; + col[2] = in & 0xFF; +} + void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb { float h = ((float)hue)/65535.0; diff --git a/wled00/wled19_ir.ino b/wled00/wled19_ir.ino new file mode 100644 index 00000000..a1e2f727 --- /dev/null +++ b/wled00/wled19_ir.ino @@ -0,0 +1,126 @@ +/* + * Infrared sensor support for generic 24 key RGB remote + */ + +IRrecv* irrecv; +//change pin in NpbWrapper.h + +decode_results results; + +unsigned long irCheckedTime = 0; +uint32_t lastValidCode = 0; +uint16_t irTimesRepeated = 0; + + +//relatively change brightness, minumum A=5 +void relativeChange(byte* property, int8_t amount, byte lowerBoundary =0) +{ + int16_t new_val = (int16_t) *property + amount; + if (new_val > 0xFF) new_val = 0xFF; + else if (new_val < lowerBoundary) new_val = lowerBoundary; + *property = new_val; +} + +void decodeIr(uint32_t code) +{ + if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down + { + irTimesRepeated++; + if (lastValidCode == IR24_BRIGHTER) + { + relativeChange(&bri, 10); return; + } + else if (lastValidCode == IR24_DARKER) + { + relativeChange(&bri, -10, 5); return; + } + else if (lastValidCode == IR24_ON && irTimesRepeated > 7) + { + nightlightActive = true; + nightlightStartTime = millis(); + } + return; + } + lastValidCode = 0; irTimesRepeated = 0; + + if (code > 0xFFFFFF) return; //invalid code + else if (code > 0xFF0000) decodeIR44(code); //is in 44-key remote range + else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range + //code <= 0xF70000 also invalid +} + +void decodeIR24(uint32_t code) +{ + switch (code) { + case IR24_BRIGHTER : relativeChange(&bri, 10); break; + case IR24_DARKER : relativeChange(&bri, -10, 5); break; + case IR24_OFF : briLast = bri; bri = 0; break; + case IR24_ON : bri = briLast; break; + case IR24_RED : colorFromUint32(COLOR_RED); break; + case IR24_REDDISH : colorFromUint32(COLOR_REDDISH); break; + case IR24_ORANGE : colorFromUint32(COLOR_ORANGE); break; + case IR24_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break; + case IR24_YELLOW : colorFromUint32(COLOR_YELLOW); break; + case IR24_GREEN : colorFromUint32(COLOR_GREEN); break; + case IR24_GREENISH : colorFromUint32(COLOR_GREENISH); break; + case IR24_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break; + case IR24_CYAN : colorFromUint32(COLOR_CYAN); break; + case IR24_AQUA : colorFromUint32(COLOR_AQUA); break; + case IR24_BLUE : colorFromUint32(COLOR_BLUE); break; + case IR24_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break; + case IR24_PURPLE : colorFromUint32(COLOR_PURPLE); break; + case IR24_MAGENTA : colorFromUint32(COLOR_MAGENTA); break; + case IR24_PINK : colorFromUint32(COLOR_PINK); break; + case IR24_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break; + case IR24_FLASH : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break; + case IR24_STROBE : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break; + case IR24_FADE : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break; + case IR24_SMOOTH : if (!applyPreset(4)) effectCurrent = FX_MODE_RAINBOW; break; + default: return; + } + lastValidCode = code; + colorUpdated(2); //for notifier, IR is considered a button input +} + +void decodeIR44(uint32_t code) +{ + //not implemented for now +} + +void initIR() +{ + if (irEnabled) + { + irrecv = new IRrecv(IR_PIN); + irrecv->enableIRIn(); + } + //irrecv.disableIRIn(); +} + +void handleIR() +{ + if (irEnabled && millis() - irCheckedTime > 120) + { + irCheckedTime = millis(); + if (irEnabled) + { + if (irrecv == NULL) + { + initIR(); return; + } + + if (irrecv->decode(&results)) + { + DEBUG_PRINTLN("IR recv"); + #ifdef DEBUG + Serial.println((uint32_t)results.value, HEX); + #endif + decodeIr(results.value); + irrecv->resume(); + } + } else if (irrecv != NULL) + { + delete irrecv; irrecv = NULL; + } + } +}