Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. My Project
  3. 5 Channel (RGBWW) LED Dimmer With Rotary Encoder

5 Channel (RGBWW) LED Dimmer With Rotary Encoder

Scheduled Pinned Locked Moved My Project
8 Posts 5 Posters 6.9k Views 9 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • sowardS Offline
    sowardS Offline
    soward
    wrote on last edited by
    #1

    Using a RGBW LED strip, I put over & under cabinet lights in the kitchen, but I wanted some more direct white light right over the stove, so I added an additional white strip there. I also wanted to be able to control it manually, so I tied in a rotary encoder with push-button switch.

    All 5 (RGBWW) are controllable as separate dimmable lights via mySensors + VERA as usual. The final W tied to the encoder can have it's illumination increased/decreased by a turn of the knob, and updates mySensors/VERA on change. Pushing the button will turn off the strip completely if it is on, and restore it to the last known brightness value if it is off.

    Presently it is still on a breadboard while I find the time to master Kicad, or decide that will never happen and solder it together on a perfboard. I am using an external 12V CC supply feeding both a pro mini and 5 MOSFETs to drive the LED strips. It has been running for about 7 months now -- since the breadboard sits on the back top of the cabinets, it provides a low incentive to reconfigure the hardware.

    Most recent sketch:

    /***
     * 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 );
      }
    }
    
    1 Reply Last reply
    2
    • HoffanH Offline
      HoffanH Offline
      Hoffan
      wrote on last edited by
      #2

      Any pictures on this

      sowardS 1 Reply Last reply
      1
      • HoffanH Hoffan

        Any pictures on this

        sowardS Offline
        sowardS Offline
        soward
        wrote on last edited by
        #3

        @Hoffan Sure here's a few:
        Breadboard on top of cabinet:
        IMG_2704.jpg
        Controls sample in HomeWave iOS App:
        IMG_2705.jpg
        Green and Stove strip on:
        IMG_2703.jpg
        All Whites on (Stove strip is 'warm white' ~3K):
        IMG_2702.jpg
        Hack Job under cabinet mounting and wiring:
        IMG_2701.jpg
        Purple:
        IMG_2700.jpg

        Moshe LivneM 1 Reply Last reply
        0
        • sowardS soward

          @Hoffan Sure here's a few:
          Breadboard on top of cabinet:
          IMG_2704.jpg
          Controls sample in HomeWave iOS App:
          IMG_2705.jpg
          Green and Stove strip on:
          IMG_2703.jpg
          All Whites on (Stove strip is 'warm white' ~3K):
          IMG_2702.jpg
          Hack Job under cabinet mounting and wiring:
          IMG_2701.jpg
          Purple:
          IMG_2700.jpg

          Moshe LivneM Offline
          Moshe LivneM Offline
          Moshe Livne
          Hero Member
          wrote on last edited by
          #4

          @soward did you think to adjust the colours to reflect the surface temperature? this looks like a cooking surface below? one of these you forget to turn off? you can add reddish ting to the light to remind you its on. can be cool (ha! pan intended)

          sowardS 1 Reply Last reply
          0
          • Moshe LivneM Moshe Livne

            @soward did you think to adjust the colours to reflect the surface temperature? this looks like a cooking surface below? one of these you forget to turn off? you can add reddish ting to the light to remind you its on. can be cool (ha! pan intended)

            sowardS Offline
            sowardS Offline
            soward
            wrote on last edited by
            #5

            @Moshe-Livne that would be interesting. I've not looked for any cheap IR temp sensors, though I'm sure there must be something. Of course the stove has a 'hot surface' warning LED itself, but that's not as interesting!

            Moshe LivneM 1 Reply Last reply
            0
            • Q Offline
              Q Offline
              Qu3Uk
              wrote on last edited by
              #6

              Nice project, I'm looking to do something similar, just need to source a powersupply.

              1 Reply Last reply
              0
              • sowardS soward

                @Moshe-Livne that would be interesting. I've not looked for any cheap IR temp sensors, though I'm sure there must be something. Of course the stove has a 'hot surface' warning LED itself, but that's not as interesting!

                Moshe LivneM Offline
                Moshe LivneM Offline
                Moshe Livne
                Hero Member
                wrote on last edited by
                #7

                @soward maybe http://www.aliexpress.com/item/MLX90614ESF-BAA-IC-THERMOMETER-IR-5V-TO-39/32324392117.html?spm=2114.32010308.4.29.7pOwHH?

                1 Reply Last reply
                0
                • H Offline
                  H Offline
                  humblehacker
                  wrote on last edited by
                  #8

                  Great Work!
                  I too am trying something similar- http://forum.mysensors.org/topic/2601/dimmable-led-with-rotary-encoder-example-for-rgb/5. Only my aim is to use the encoder to control full size RGB lighting zones via Home-Assistant and MiLight. Any tips would be greatly appreciated!

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  21

                  Online

                  11.7k

                  Users

                  11.2k

                  Topics

                  113.0k

                  Posts


                  Copyright 2019 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • MySensors
                  • OpenHardware.io
                  • Categories
                  • Recent
                  • Tags
                  • Popular