Another MYS RGB Encoder example- http://forum.mysensors.org/topic/1626/5-channel-rgbww-led-dimmer-with-rotary-encoder/3
I might just have enough to work with now:)
/***
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* DESCRIPTION
* This sketch provides 4 channels of Dimmable LED Lights using PWM for the MySensors.org project
* Inspired by the PWM example sketcy by <henrik.ekblad@gmail.com> and Bruce Lacey.
*
* REVISION HISTORY
* Version 0.1 - Sept 5, 2014 John Soward <soward@soward.net> -- Initial implementation based on example scripts.
* Version 0.2 - Sept 7, 2014 -- <soward@soward.net> -- Adjust Timer resolution, neaten up, separate debugging output
* Version 0.3 - July 5, 2015 -- <soward@soward.net> Pin changes, use Bounce2, update encoder state when brightness changed via mySensors net
*
***/
#define DEBUG 0
#define SN "RGBWW DIM + ENC"
#define SV "0.3"
#include <Encoder.h> // Using https://www.pjrc.com/teensy/arduino_libraries/Encoder.zip
#include <Bounce2.h>
#include <MySensor.h>
#include <SPI.h>
// Ardunio pro mini's have PWM only on 3,5,6,9,10,11
// See http://arduino.cc/en/Main/ArduinoBoardProMini
#define RED 3 // Arduino pin attached to MOSFET Gate pin
#define GREEN 5
#define BLUE 6
#define WHT 9
#define WHT2 10 //WHT2 is a pure white strip, distinct from the RGBW strip for over stove use
// Rotary Encoder connections
// Better response if one or both of the encoder triggers is on an interrupt pin
#define ENC_SWITCH 8
#define ENC_A 2
#define ENC_B A2
#define ENC_SCALE 2.56 // scaling encoder 256 steps to 100%
#define FADE_DELAY 5 // Delay in ms
#define FADE_DELAY_FACTOR 16
// MySenor uses pin 9 for CE by default, , can be changed here.
// Pin 10 used for CS can also be changed.
MySensor gw(4,7);
Encoder myEnc(ENC_A, ENC_B);
Bounce PowerButton = Bounce();
static int levels[5]; // Current dim levels...
MyMessage dimMsgs[5];
MyMessage lightMsgs[5];
int rotValue = 0; // encoder position (for WHT2)
int lastBrightness; // last 'on' brightness (for WHT2)
void setup()
{
//Increase Timer frequency to prevent flicker in Pins 5,6 PWM
// This alters the performance of millis(), micros() & delay() (basically by 1/16) Unless wiring.c is modified.
// See http://playground.arduino.cc/Main/TimerPWMCheatsheet
// W/O this change, a low frequency 'beat' or flicker was exhibited when PWM'ing Pin 5 or 6 and another other pin (on Pro Mini 8Mhz clone)
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
pinMode(RED,OUTPUT);
pinMode(GREEN,OUTPUT);
pinMode(BLUE,OUTPUT);
pinMode(WHT,OUTPUT);
pinMode(WHT2,OUTPUT);
pinMode(ENC_SWITCH,INPUT);
digitalWrite(ENC_SWITCH,HIGH);
PowerButton.attach(ENC_SWITCH);
PowerButton.interval(80);
// FIXME Mnemonics for the colors/names/locations of the lights could be useful here.
for (int i = 0; i < 5; i++) {
dimMsgs[i] = MyMessage(i,V_DIMMER);
lightMsgs[i] = MyMessage(i,V_LIGHT);
levels[i] = 20;
}
startupDance();
analogWrite(WHT2,0);
#ifdef DEBUG
Serial.println( SN );
#endif
gw.begin( incomingMessage );
// Register each color LED Dimmable Light with the gateway
gw.present( 0, S_DIMMER );
gw.present( 1, S_DIMMER );
gw.present( 2, S_DIMMER );
gw.present( 3, S_DIMMER );
gw.present( 4, S_DIMMER );
gw.sendSketchInfo(SN, SV);
// Pull the gateway's current dim level - restore light level upon sendor node power-up
gw.request( 0, V_DIMMER );
gw.request( 1, V_DIMMER );
gw.request( 2, V_DIMMER );
gw.request( 3, V_DIMMER );
gw.request( 4, V_DIMMER );
}
void loop()
{
// Encoder and button handling.
// In this implemenation the Encoder and button control the 2nd White strip, position 4 in the array of strips)
// The encoder will brighten/dim the strip from it's current value.
// The button will turn off the strip if it is on, or return it to it's last known brightness if it is off
bool needsUpdate = false;
int newRotValue = myEnc.read();
if (newRotValue != rotValue) { // I guess it really has changed
Serial.print("Encoder update:");
Serial.println(newRotValue);
if (newRotValue > 255 || newRotValue < 0) {
myEnc.write(rotValue); // Enforce max/min
} else {
rotValue = newRotValue;
needsUpdate = true;
}
}
if (PowerButton.update()) {
if (!PowerButton.read()) {
Serial.println("Button pushed");
Serial.print("lastBrightness: ");Serial.println(lastBrightness);
Serial.print("rotValue: ");Serial.println(rotValue);
if (rotValue) { // we are on, need to go off
lastBrightness = rotValue;
rotValue = 0;
} else {
rotValue = lastBrightness;
}
myEnc.write(rotValue);
needsUpdate = true;
}
}
if (needsUpdate) {
int normalizedValue = rotValue / ENC_SCALE;
fadeLEDToLevel(4,normalizedValue,0);
gw.send(dimMsgs[4].set(normalizedValue));
gw.send(lightMsgs[4].set(normalizedValue > 0 ? 1 : 0));
}
// Standard mySensors message processing (no sleep)
gw.process();
}
void incomingMessage(const MyMessage &message) {
if (message.type == V_LIGHT || message.type == V_DIMMER) {
// Retrieve the power or dim level from the incoming request message
int requestedLevel = atoi( message.data );
// Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on]
requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
// Clip incoming level to valid range of 0 to 100
requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
requestedLevel = requestedLevel < 0 ? 0 : requestedLevel;
#ifdef DEBUG
Serial.print( "On child id ");
Serial.print(message.sensor);
Serial.print( " Changing level to " );
Serial.print( requestedLevel );
Serial.print( ", from " );
Serial.println( levels[message.sensor]);
#endif
fadeLEDToLevel( message.sensor,requestedLevel,FADE_DELAY*FADE_DELAY_FACTOR );
// Sensor 4 is the strip attached the the encoder, update the encoders value, using the scaling factor
// FIXME Mnemonics might make this more readable/extensible.
if (message.sensor == 4) {
myEnc.write(requestedLevel*ENC_SCALE);
}
// Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
gw.send(lightMsgs[message.sensor].set(levels[message.sensor] > 0 ? 1 : 0));
// hek comment: Is this really nessesary?
// soward: Probably not, unless there exists some reason why the requested value does not equal
// the set value
gw.send( dimMsgs[message.sensor].set(levels[message.sensor]) );
}
}
void startupDance() {
int i,j;
// Bring each color up and down independently
for (i=0;i<5;i++) {
fadeLEDToLevel(i,100,1);
delay(50*FADE_DELAY_FACTOR);
fadeLEDToLevel(i,0,1);
}
//Bringing each color up sequentially, then back down to 2
for (i=0;i<5;i++) {
fadeLEDToLevel(i,100,1);
}
delay(50*FADE_DELAY_FACTOR);
for (i=0;i<5;i++) {
fadeLEDToLevel(i,2,1);
}
}
// Helper function to map controller pins to names for strips
int pinForID(int ledID) {
switch (ledID) {
case 0: return RED;
case 1: return GREEN;
case 2: return BLUE;
case 3: return WHT;
case 4: return WHT2;
return 0; // Default to Red
}
}
/***
* This method provides a graceful fade up/down effect
*/
void fadeLEDToLevel( int theLED, int toLevel, int wait ) {
int delta = ( toLevel - levels[theLED] ) < 0 ? -1 : 1;
while ( levels[theLED] != toLevel ) {
levels[theLED] += delta;
analogWrite( pinForID(theLED), (int)(levels[theLED] / 100. * 255) );
delay( wait );
}
}
7
POSTS 1.1k
VIEWS Reply