285 lines
11 KiB
C++
285 lines
11 KiB
C++
/*
|
|
* IRlicht -- a 4-channel (RGBW) controller for LED-lamps, based on Arduino and
|
|
* controlled via infrared by a universal remote.
|
|
*
|
|
* Copyright 2014 Ronald Schaten <http://www.schatenseite.de>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include <IRremote.h>
|
|
|
|
// pins on which the LEDs are connected
|
|
#define LED_WHITE 5
|
|
#define LED_GREEN 6
|
|
#define LED_BLUE 10
|
|
#define LED_RED 9
|
|
|
|
// use examples included in IRremote-library to find the correct values for
|
|
// your remote.
|
|
#define IR_PIN 2
|
|
#define IR_PROTOCOL 1
|
|
#define IR_FILTER 0xF70000
|
|
#define IR_MASK 0xFF0000
|
|
#define IR_KEY_1 0xF720DF
|
|
#define IR_KEY_2 0xF710EF
|
|
#define IR_KEY_3 0xF730CF
|
|
#define IR_KEY_4 0xF70000 // key is broken on my remote :-(
|
|
#define IR_KEY_5 0xF728D7
|
|
#define IR_KEY_6 0xF7A05F
|
|
#define IR_KEY_7 0xF7906F
|
|
#define IR_KEY_8 0xF7B04F
|
|
#define IR_KEY_9 0xF78877
|
|
#define IR_KEY_FLASH 0xF7D02F
|
|
#define IR_KEY_STROBE 0xF7F00F
|
|
#define IR_KEY_FADE 0xF7C837
|
|
#define IR_KEY_SMOOTH 0xF7E817
|
|
#define IR_KEY_DIM 0xF7807F
|
|
#define IR_KEY_BRIGHT 0xF700FF
|
|
#define IR_KEY_ALLON 0xF7C03F
|
|
#define IR_KEY_ALLOFF 0xF740BF
|
|
#define IR_KEY_LIGHT10 0xF7A857
|
|
#define IR_KEY_LIGHT11 0xF7609F
|
|
#define IR_KEY_LIGHT12 0xF750AF
|
|
#define IR_KEY_LIGHT13 0xF7708F
|
|
#define IR_KEY_LIGHT14 0xF748B7
|
|
#define IR_KEY_LIGHT15 0xF76897
|
|
#define IR_KEY_LIGHT16 0xF7E01F
|
|
|
|
// main modes of operation
|
|
#define MODE_OFF 0x00
|
|
#define MODE_CONSTANT 0x01
|
|
#define MODE_FLASH 0x02
|
|
#define MODE_STROBE 0x03
|
|
#define MODE_FADE 0x04
|
|
#define MODE_SMOOTH 0x05
|
|
|
|
// initial brightness levels
|
|
int levelRed = 0x00; // colors are off
|
|
int levelGreen = 0x00;
|
|
int levelBlue = 0x00;
|
|
int levelWhite = 0x10; // white is on a dark level
|
|
int levelTotal = 0x80; // overall, everything is dimmed to half
|
|
|
|
int mode = MODE_CONSTANT; // initial mode
|
|
int modestep = 0;
|
|
int modeincrement = 1;
|
|
int animationspeed = 5;
|
|
long steplength = 0;
|
|
|
|
IRrecv irrecv(IR_PIN);
|
|
decode_results results;
|
|
|
|
// setRGBW sets all outputs
|
|
void setRGBW(int red, int green, int blue, int white) {
|
|
// dim all channels according to levelTotal
|
|
red = map(red, 0x00, 0xff, 0x00, levelTotal);
|
|
green = map(green, 0x00, 0xff, 0x00, levelTotal);
|
|
blue = map(blue, 0x00, 0xff, 0x00, levelTotal);
|
|
white = map(white, 0x00, 0xff, 0x00, levelTotal);
|
|
if (mode != MODE_STROBE) {
|
|
// keep output at least at 0x01 if channel is not turned off
|
|
// unless we're in strobe mode, which means that lights should turn off completely
|
|
if (levelRed > 0) { red = constrain(red, 0x01, 0xff); }
|
|
if (levelGreen > 0) { green = constrain(green, 0x01, 0xff); }
|
|
if (levelBlue > 0) { blue = constrain(blue, 0x01, 0xff); }
|
|
if (levelWhite > 0) { white = constrain(white, 0x01, 0xff); }
|
|
}
|
|
// set output
|
|
analogWrite(LED_RED, red);
|
|
analogWrite(LED_GREEN, green);
|
|
analogWrite(LED_BLUE, blue);
|
|
analogWrite(LED_WHITE, white);
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(9600);
|
|
pinMode(LED_RED, OUTPUT);
|
|
pinMode(LED_GREEN, OUTPUT);
|
|
pinMode(LED_BLUE, OUTPUT);
|
|
pinMode(LED_WHITE, OUTPUT);
|
|
setRGBW(levelRed, levelGreen, levelBlue, levelWhite);
|
|
irrecv.enableIRIn(); // Start the receiver
|
|
}
|
|
|
|
void loop() {
|
|
if (irrecv.decode(&results)) {
|
|
// we received a new keypress from IR
|
|
if (results.decode_type == IR_PROTOCOL) {
|
|
if (results.value != 0xFFFFFFFF) { // only react to presses
|
|
//if (results.value & IR_MASK == IR_FILTER) {
|
|
Serial.println(results.value);
|
|
switch (results.value) {
|
|
case IR_KEY_1: mode = MODE_CONSTANT; levelRed += 51; if (levelRed > 0xff) { levelRed = 0x00; } break;
|
|
case IR_KEY_2: mode = MODE_CONSTANT; levelGreen += 51; if (levelGreen > 0xff) { levelGreen = 0x00; } break;
|
|
case IR_KEY_3: mode = MODE_CONSTANT; levelBlue += 51; if (levelBlue > 0xff) { levelBlue = 0x00; } break;
|
|
case IR_KEY_4: mode = MODE_CONSTANT; levelRed = levelBlue = levelGreen = levelWhite = 0xff; break;
|
|
case IR_KEY_5: mode = MODE_CONSTANT; levelWhite += 51; if (levelWhite > 0xff) { levelWhite = 0x00; } break;
|
|
case IR_KEY_6: mode = MODE_CONSTANT; levelRed = levelBlue = levelGreen = levelWhite = 0x00; break;
|
|
case IR_KEY_7:
|
|
mode = MODE_CONSTANT;
|
|
if (levelRed == levelGreen && levelBlue == 0) {
|
|
// we have the right color tone, just set brightness
|
|
levelRed += 51; if (levelRed > 0xff) { levelRed = 0x00; };
|
|
levelGreen += 51; if (levelGreen > 0xff) { levelGreen = 0x00; };
|
|
} else {
|
|
// select color tone
|
|
levelRed = levelGreen = 51;
|
|
levelBlue = 0;
|
|
}
|
|
break;
|
|
case IR_KEY_8:
|
|
mode = MODE_CONSTANT;
|
|
if (levelGreen == levelBlue && levelRed == 0) {
|
|
// we have the right color tone, just set brightness
|
|
levelGreen += 51; if (levelGreen > 0xff) { levelGreen = 0x00; };
|
|
levelBlue += 51; if (levelBlue > 0xff) { levelBlue = 0x00; };
|
|
} else {
|
|
// select color tone
|
|
levelGreen = levelBlue = 51;
|
|
levelRed = 0;
|
|
}
|
|
break;
|
|
case IR_KEY_9:
|
|
mode = MODE_CONSTANT;
|
|
if (levelBlue == levelRed && levelGreen == 0) {
|
|
// we have the right color tone, just set brightness
|
|
levelBlue += 51; if (levelBlue > 0xff) { levelBlue = 0x00; };
|
|
levelRed += 51; if (levelRed > 0xff) { levelRed = 0x00; };
|
|
} else {
|
|
// select color tone
|
|
levelBlue = levelRed = 51;
|
|
levelGreen = 0;
|
|
}
|
|
break;
|
|
case IR_KEY_FLASH:
|
|
mode == MODE_FLASH ? mode = MODE_CONSTANT : mode = MODE_FLASH;
|
|
steplength = 0;
|
|
break;
|
|
case IR_KEY_STROBE:
|
|
mode == MODE_STROBE ? mode = MODE_CONSTANT : mode = MODE_STROBE;
|
|
steplength = 0;
|
|
break;
|
|
case IR_KEY_FADE:
|
|
mode == MODE_FADE ? mode = MODE_CONSTANT : mode = MODE_FADE;
|
|
steplength = 0;
|
|
break;
|
|
case IR_KEY_SMOOTH:
|
|
mode == MODE_SMOOTH ? mode = MODE_CONSTANT : mode = MODE_SMOOTH;
|
|
steplength = 0;
|
|
modeincrement = 1;
|
|
break;
|
|
case IR_KEY_DIM: levelTotal = constrain(levelTotal-0x10, 0x01, 0xff); break;
|
|
case IR_KEY_BRIGHT: levelTotal = constrain(levelTotal+0x10, 0x01, 0xff); break;
|
|
case IR_KEY_ALLON: animationspeed = constrain(animationspeed+1, 1, 15); break;
|
|
case IR_KEY_ALLOFF: animationspeed = constrain(animationspeed-1, 1, 15); break;
|
|
default:
|
|
Serial.print("proto: ");
|
|
Serial.print(results.decode_type, DEC);
|
|
Serial.print(" code: ");
|
|
Serial.println(results.value, HEX);
|
|
break;
|
|
}
|
|
if (mode == MODE_CONSTANT) {
|
|
setRGBW(levelRed, levelGreen, levelBlue, levelWhite);
|
|
}
|
|
}
|
|
}
|
|
irrecv.resume(); // Receive the next value
|
|
}
|
|
switch (mode) {
|
|
case MODE_CONSTANT:
|
|
// do nothing, it's constant after all...
|
|
break;
|
|
case MODE_STROBE:
|
|
// flash all active channels
|
|
modestep = constrain(modestep, 0, 1);
|
|
steplength--;
|
|
if (steplength <= 0) {
|
|
if (modestep == 1) {
|
|
modestep = 0;
|
|
setRGBW(levelRed, levelGreen, levelBlue, levelWhite);
|
|
} else {
|
|
modestep = 1;
|
|
setRGBW(0x00, 0x00, 0x00, 0x00);
|
|
}
|
|
steplength = animationspeed * 10000L;
|
|
}
|
|
break;
|
|
case MODE_FLASH:
|
|
// flash between all colors
|
|
modestep = constrain(modestep, 0, 5);
|
|
steplength--;
|
|
if (steplength <= 0) {
|
|
switch (modestep) {
|
|
case 0: levelRed = 0xff; levelGreen = 0x00; levelBlue = 0x00; modestep = 1; break;
|
|
case 1: levelRed = 0xff; levelGreen = 0xff; levelBlue = 0x00; modestep = 2; break;
|
|
case 2: levelRed = 0x00; levelGreen = 0xff; levelBlue = 0x00; modestep = 3; break;
|
|
case 3: levelRed = 0x00; levelGreen = 0xff; levelBlue = 0xff; modestep = 4; break;
|
|
case 4: levelRed = 0x00; levelGreen = 0x00; levelBlue = 0xff; modestep = 5; break;
|
|
case 5: levelRed = 0xff; levelGreen = 0x00; levelBlue = 0xff; modestep = 0; break;
|
|
}
|
|
setRGBW(levelRed, levelGreen, levelBlue, levelWhite);
|
|
steplength = animationspeed * 10000L;
|
|
}
|
|
break;
|
|
case MODE_FADE:
|
|
// fade between all colors
|
|
modestep = constrain(modestep, 0x00, 6 * 0xff);
|
|
steplength--;
|
|
if (steplength <= 0) {
|
|
if (modestep < 1 * 0xff) { // red on, increment green
|
|
levelRed = 0xff; levelGreen = modestep % 0xff; levelBlue = 0x00;
|
|
} else if (modestep < 2 * 0xff) { // green on, decrement red
|
|
levelRed = 0xff - modestep % 0xff; levelGreen = 0xff; levelBlue = 0x00;
|
|
} else if (modestep < 3 * 0xff) { // green on, increment blue
|
|
levelRed = 0x00; levelGreen = 0xff; levelBlue = modestep % 0xff;
|
|
} else if (modestep < 4 * 0xff) { // blue on, decrement green
|
|
levelRed = 0x00; levelGreen = 0xff - modestep % 0xff; levelBlue = 0xff;
|
|
} else if (modestep < 5 * 0xff) { // blue on, increment red
|
|
levelRed = modestep % 0xff; levelGreen = 0x00; levelBlue = 0xff;
|
|
} else { // red on, decrement blue
|
|
levelRed = 0xff; levelGreen = 0x00; levelBlue = 0xff - modestep % 0xff;
|
|
}
|
|
setRGBW(levelRed, levelGreen, levelBlue, levelWhite);
|
|
steplength = animationspeed * 10000L / 0xff;
|
|
modestep++;
|
|
if (modestep >= 6 * 0xff) {
|
|
modestep = 0;
|
|
}
|
|
}
|
|
break;
|
|
case MODE_SMOOTH:
|
|
// smooth fading of all active channels
|
|
modestep = constrain(modestep, 0x00, 0xff);
|
|
steplength--;
|
|
if (steplength <= 0) {
|
|
int red = map(levelRed, 0x00, 0xff, 0x00, modestep);
|
|
int green = map(levelGreen, 0x00, 0xff, 0x00, modestep);
|
|
int blue = map(levelBlue, 0x00, 0xff, 0x00, modestep);
|
|
int white = map(levelWhite, 0x00, 0xff, 0x00, modestep);
|
|
setRGBW(red, green, blue, white);
|
|
steplength = animationspeed * 10000L / 0xff;
|
|
modestep += modeincrement;
|
|
if (modestep <= 0x00 || modestep >= 0xff) {
|
|
modeincrement = -modeincrement;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// vim:filetype=c:ts=2
|