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. Controllers
  3. OpenHAB
  4. AC Dimmer with OpenHab

AC Dimmer with OpenHab

Scheduled Pinned Locked Moved OpenHAB
10 Posts 8 Posters 12.3k Views 5 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.
  • Q Offline
    Q Offline
    quocanhcgd
    wrote on last edited by
    #1

    Here my code.

    /*
    AC Light Control
    Uses up and down buttons to set levels
    makes use of a timer interrupt to set the level of dimming
    */
    #include <SPI.h>
    #include <MySensor.h>  
    #include <TimerOne.h>
    #include <Bounce2.h>
    #define SN "AC Dimmer control"
    #define SV "1.0"
    #define NODE_ID 30  //change to a number to assign a specific ID
    #define FADE_DELAY 100  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
    #define FADE_PERCENTAGE 5 //The percentage the fade level will be changed when a button is pressed
    volatile int i=0;               // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
    volatile boolean zero_cross=0;  // Flag to indicate we have crossed zero
    int AC_pin = 3;                 // Output to Opto Triac
    int UP_BUTTON_PIN = 5;                 // Arduino Digital I/O pin number for the fade up button 
    int DOWN_BUTTON_PIN = 6;                 // Arduino Digital I/O pin number for the fade down button 
    int POWER_BUTTON_PIN = 7;                 // Arduino Digital I/O pin number for the power button 
    
    int freqStep = 75;              // This is the delay-per-brightness step in microseconds. It allows for 128 steps
                                    // If using 60 Hz grid frequency set this to 65
    MySensor gw;
    //Tuy chinh lai
    static int currentLevel = 128;  // Current dim level...
    uint8_t fadeLevel = 128; //used to store the fade level when using the buttons
    uint8_t upPreviousValue;
    uint8_t downPreviousValue;
    uint8_t powerPreviousValue;
    
    Bounce upDebouncer = Bounce();
    Bounce downDebouncer = Bounce();
    Bounce powerDebouncer = Bounce();
    MyMessage dimmerMsg(AC_pin, V_DIMMER);
    MyMessage lightMsg(AC_pin, V_LIGHT);
    
    unsigned long previousMillis = 0; // last time update 
    unsigned long upPreviousMillis = 0;
    unsigned long downPreviousMillis = 0; 
    unsigned long buttonFadeDelay = 200; 
    
    // =Het tuy chinh lai
    
    
    void setup() {  // Begin setup
      Serial.begin(115200);
      /// - Setup Mysensors
      Serial.println( SN ); 
      gw.begin( incomingMessage,  NODE_ID, true);
      // Register the LED Dimmable Light with the gateway
      gw.present( 3, S_DIMMER );
      
      gw.sendSketchInfo(SN, SV);
      // Pull the gateway's current dim level - restore light level upon sendor node power-up
      gw.request( 3, V_DIMMER );
      // - Het setup mysensors
      //Setup the button
      /*pinMode(buton1, INPUT);  // set buton1 pin as input
      pinMode(buton2, INPUT);  // set buton1 pin as input
      pinMode(buton3, INPUT);  // set buton1 pin as input*/
         // Setup the button
      pinMode(UP_BUTTON_PIN,INPUT);
      pinMode(DOWN_BUTTON_PIN,INPUT);
      pinMode(POWER_BUTTON_PIN,INPUT);
      
      // Activate internal pull-up
      digitalWrite(UP_BUTTON_PIN,LOW);
      digitalWrite(DOWN_BUTTON_PIN,LOW);
      digitalWrite(POWER_BUTTON_PIN,LOW);
      
      // After setting up the button, setup debouncer
      upDebouncer.attach(UP_BUTTON_PIN);
      downDebouncer.attach(DOWN_BUTTON_PIN);
      powerDebouncer.attach(POWER_BUTTON_PIN);
      upDebouncer.interval(5);
      downDebouncer.interval(5);
      powerDebouncer.interval(5);
      
      //Setup AC PIN
      pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
      attachInterrupt(0, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
      Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
      Timer1.attachInterrupt(dim_check, freqStep);      // Go to dim_check procedure every 75 uS (50Hz)  or 65 uS (60Hz)
      // Use the TimerOne Library to attach an interrupt
      
    }
    
    void zero_cross_detect() {    
      zero_cross = true;               // set flag for dim_check function that a zero cross has occured
      i=0;                             // stepcounter to 0.... as we start a new cycle
      digitalWrite(AC_pin, LOW);
    }                                 
    
    // Turn on the TRIAC at the appropriate time
    // We arrive here every 75 (65) uS
    // First check if a flag has been set
    // Then check if the counter 'i' has reached the dimming level
    // if so.... switch on the TRIAC and reset the counter
    void dim_check() {                   
      if(zero_cross == true) {              
        if(i>=fadeLevel) {                     
          digitalWrite(AC_pin, HIGH);  // turn on light       
          i=0;  // reset time step counter                         
          zero_cross=false;    // reset zero cross detection flag
        } 
        else {
          i++;  // increment time step counter                     
        }                                
      }    
    }                                      
    
    void loop() {  
        gw.process();
        /*
    There are 3 buttons attached to the mirror.  One is an on/off button and the other two will fade up/fade down.  
    The sensor will remember the last fade state and fade the lights to that level next time they are turned on.
    
    If fade up or fade down button is pressed it should store that value into a variable and when the ON button is pressed
    it will fade to that previous value.
     */ 
     //up button
      upDebouncer.update();
        // Get the update value
        uint8_t upValue = upDebouncer.read();
        
        unsigned long upCurrentMillis = millis();
        
        if(upCurrentMillis - upPreviousMillis > buttonFadeDelay){
          if ((upValue == HIGH) && (fadeLevel<128)) { //Because of the internal pullup resistors LOW = button is presssed
               fadeLevel = fadeLevel < 8 ? 0 : fadeLevel;
               if (fadeLevel > 8)
              { fadeLevel -= (FADE_PERCENTAGE * 1.28);
            } else {
              fadeLevel = 8;
            }
               fadeToLevel( fadeLevel );
               Serial.println(fadeLevel);
          }
          upPreviousMillis = upCurrentMillis;
        }
      
     // down button
     downDebouncer.update();
        // Get the update value
        uint8_t downValue = downDebouncer.read();
        
        unsigned long downCurrentMillis = millis();
        
        if(downCurrentMillis - downPreviousMillis > buttonFadeDelay){
          if ((downValue == HIGH) && (fadeLevel>0)) {                
             fadeLevel += (FADE_PERCENTAGE * 1.28);
             fadeLevel = fadeLevel > 128 ? 121 : fadeLevel;
             fadeToLevel( fadeLevel );
             Serial.println(fadeLevel);                 
          }
          downPreviousMillis = downCurrentMillis;
        }
     // Power button
     powerDebouncer.update();
        // Get the update value
        uint8_t powerValue = powerDebouncer.read();
        
        if(powerValue != powerPreviousValue){
          if (powerValue == HIGH) {
          Serial.print("Power Button Pressed. fadeLevel is ");
          Serial.println(fadeLevel);
         
            if (currentLevel < 128) {
              
             fadeToLevel( 128 );
             fadeLevel = 128;
            }
            else{
              if (fadeLevel == 128) {
                fadeToLevel(64);
                fadeLevel = 64;
              }
              else{
                fadeToLevel(fadeLevel);
              }
            }
          }
          powerPreviousValue = powerValue;
        }
     
    }
    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;
        
       
        float percent_level;
        percent_level = 128 - (requestedLevel * 1.28);
        fadeToLevel( percent_level );
         Serial.print( "Changing level to " );
        Serial.print( requestedLevel );
        Serial.print( ", from " ); 
        Serial.println( currentLevel );
        // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
        gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));
    
        // hek comment: Is this really nessesary?
        gw.send( dimmerMsg.set(currentLevel) );
    
       
        }
    }
    
    /***
     *  This method provides a graceful fade up/down effect
     */
    void fadeToLevel( int toLevel ) {
      Serial.print("toLevel Value: ");
     Serial.println(toLevel);
    
      
      int delta = ( currentLevel - toLevel ) < 0 ? 1 : -1;
      Serial.print("delta Value: ");
     Serial.println(delta);
      while ( currentLevel != toLevel ) {
        currentLevel += delta;
       // analogWrite( MIRROR_LED_PIN, (int)(currentLevel / 100. * 255) );
        delay( FADE_DELAY );
        
         fadeLevel = toLevel;
      }
    
       // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
    // gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));  //used to send status of light (on/off) to Vera
      gw.send( dimmerMsg.set((int)currentLevel/100*128) );
      
    }
    
    

    OpenHab item

    Dimmer	Dimmed_Light	"Dimmer Light [%d %%]"	<slider>	(all,node1)		{ mqtt=">[mymqtt:/MyMQTT/30/3/V_DIMMER:state:*:default]" }
    

    Openhab sitemap

    Slider item=Dimmed_Light
    

    Openhab Rules

    /**
     * This is a demo rule which simulates a real dimmer by reacting to increase/decrease commands 
     * and posting an updated state on the bus 
     */
    rule "Dimmed Light"
    	when
    		Item Dimmed_Light received command
    	then
    		var Number percent = 100
    		if(Dimmed_Light.state instanceof DecimalType) percent = Dimmed_Light.state as DecimalType 
    			
    		if(receivedCommand==INCREASE) percent = percent + 5
    		if(receivedCommand==DECREASE) percent = percent - 5
    
    		if(percent<0)   percent = 0
    		if(percent>100) percent = 100
    		
    		postUpdate(Dimmed_Light, percent);
    end
    

    I have a problem:
    When i use fade up or fade down , openhab don't receive a value. But i use the fade up and fade down from openhab to AC module , the light dimmer okie.
    How can i fix it ?
    Thanks

    DrJeffD C 2 Replies Last reply
    0
    • Q quocanhcgd

      Here my code.

      /*
      AC Light Control
      Uses up and down buttons to set levels
      makes use of a timer interrupt to set the level of dimming
      */
      #include <SPI.h>
      #include <MySensor.h>  
      #include <TimerOne.h>
      #include <Bounce2.h>
      #define SN "AC Dimmer control"
      #define SV "1.0"
      #define NODE_ID 30  //change to a number to assign a specific ID
      #define FADE_DELAY 100  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
      #define FADE_PERCENTAGE 5 //The percentage the fade level will be changed when a button is pressed
      volatile int i=0;               // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
      volatile boolean zero_cross=0;  // Flag to indicate we have crossed zero
      int AC_pin = 3;                 // Output to Opto Triac
      int UP_BUTTON_PIN = 5;                 // Arduino Digital I/O pin number for the fade up button 
      int DOWN_BUTTON_PIN = 6;                 // Arduino Digital I/O pin number for the fade down button 
      int POWER_BUTTON_PIN = 7;                 // Arduino Digital I/O pin number for the power button 
      
      int freqStep = 75;              // This is the delay-per-brightness step in microseconds. It allows for 128 steps
                                      // If using 60 Hz grid frequency set this to 65
      MySensor gw;
      //Tuy chinh lai
      static int currentLevel = 128;  // Current dim level...
      uint8_t fadeLevel = 128; //used to store the fade level when using the buttons
      uint8_t upPreviousValue;
      uint8_t downPreviousValue;
      uint8_t powerPreviousValue;
      
      Bounce upDebouncer = Bounce();
      Bounce downDebouncer = Bounce();
      Bounce powerDebouncer = Bounce();
      MyMessage dimmerMsg(AC_pin, V_DIMMER);
      MyMessage lightMsg(AC_pin, V_LIGHT);
      
      unsigned long previousMillis = 0; // last time update 
      unsigned long upPreviousMillis = 0;
      unsigned long downPreviousMillis = 0; 
      unsigned long buttonFadeDelay = 200; 
      
      // =Het tuy chinh lai
      
      
      void setup() {  // Begin setup
        Serial.begin(115200);
        /// - Setup Mysensors
        Serial.println( SN ); 
        gw.begin( incomingMessage,  NODE_ID, true);
        // Register the LED Dimmable Light with the gateway
        gw.present( 3, S_DIMMER );
        
        gw.sendSketchInfo(SN, SV);
        // Pull the gateway's current dim level - restore light level upon sendor node power-up
        gw.request( 3, V_DIMMER );
        // - Het setup mysensors
        //Setup the button
        /*pinMode(buton1, INPUT);  // set buton1 pin as input
        pinMode(buton2, INPUT);  // set buton1 pin as input
        pinMode(buton3, INPUT);  // set buton1 pin as input*/
           // Setup the button
        pinMode(UP_BUTTON_PIN,INPUT);
        pinMode(DOWN_BUTTON_PIN,INPUT);
        pinMode(POWER_BUTTON_PIN,INPUT);
        
        // Activate internal pull-up
        digitalWrite(UP_BUTTON_PIN,LOW);
        digitalWrite(DOWN_BUTTON_PIN,LOW);
        digitalWrite(POWER_BUTTON_PIN,LOW);
        
        // After setting up the button, setup debouncer
        upDebouncer.attach(UP_BUTTON_PIN);
        downDebouncer.attach(DOWN_BUTTON_PIN);
        powerDebouncer.attach(POWER_BUTTON_PIN);
        upDebouncer.interval(5);
        downDebouncer.interval(5);
        powerDebouncer.interval(5);
        
        //Setup AC PIN
        pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
        attachInterrupt(0, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
        Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
        Timer1.attachInterrupt(dim_check, freqStep);      // Go to dim_check procedure every 75 uS (50Hz)  or 65 uS (60Hz)
        // Use the TimerOne Library to attach an interrupt
        
      }
      
      void zero_cross_detect() {    
        zero_cross = true;               // set flag for dim_check function that a zero cross has occured
        i=0;                             // stepcounter to 0.... as we start a new cycle
        digitalWrite(AC_pin, LOW);
      }                                 
      
      // Turn on the TRIAC at the appropriate time
      // We arrive here every 75 (65) uS
      // First check if a flag has been set
      // Then check if the counter 'i' has reached the dimming level
      // if so.... switch on the TRIAC and reset the counter
      void dim_check() {                   
        if(zero_cross == true) {              
          if(i>=fadeLevel) {                     
            digitalWrite(AC_pin, HIGH);  // turn on light       
            i=0;  // reset time step counter                         
            zero_cross=false;    // reset zero cross detection flag
          } 
          else {
            i++;  // increment time step counter                     
          }                                
        }    
      }                                      
      
      void loop() {  
          gw.process();
          /*
      There are 3 buttons attached to the mirror.  One is an on/off button and the other two will fade up/fade down.  
      The sensor will remember the last fade state and fade the lights to that level next time they are turned on.
      
      If fade up or fade down button is pressed it should store that value into a variable and when the ON button is pressed
      it will fade to that previous value.
       */ 
       //up button
        upDebouncer.update();
          // Get the update value
          uint8_t upValue = upDebouncer.read();
          
          unsigned long upCurrentMillis = millis();
          
          if(upCurrentMillis - upPreviousMillis > buttonFadeDelay){
            if ((upValue == HIGH) && (fadeLevel<128)) { //Because of the internal pullup resistors LOW = button is presssed
                 fadeLevel = fadeLevel < 8 ? 0 : fadeLevel;
                 if (fadeLevel > 8)
                { fadeLevel -= (FADE_PERCENTAGE * 1.28);
              } else {
                fadeLevel = 8;
              }
                 fadeToLevel( fadeLevel );
                 Serial.println(fadeLevel);
            }
            upPreviousMillis = upCurrentMillis;
          }
        
       // down button
       downDebouncer.update();
          // Get the update value
          uint8_t downValue = downDebouncer.read();
          
          unsigned long downCurrentMillis = millis();
          
          if(downCurrentMillis - downPreviousMillis > buttonFadeDelay){
            if ((downValue == HIGH) && (fadeLevel>0)) {                
               fadeLevel += (FADE_PERCENTAGE * 1.28);
               fadeLevel = fadeLevel > 128 ? 121 : fadeLevel;
               fadeToLevel( fadeLevel );
               Serial.println(fadeLevel);                 
            }
            downPreviousMillis = downCurrentMillis;
          }
       // Power button
       powerDebouncer.update();
          // Get the update value
          uint8_t powerValue = powerDebouncer.read();
          
          if(powerValue != powerPreviousValue){
            if (powerValue == HIGH) {
            Serial.print("Power Button Pressed. fadeLevel is ");
            Serial.println(fadeLevel);
           
              if (currentLevel < 128) {
                
               fadeToLevel( 128 );
               fadeLevel = 128;
              }
              else{
                if (fadeLevel == 128) {
                  fadeToLevel(64);
                  fadeLevel = 64;
                }
                else{
                  fadeToLevel(fadeLevel);
                }
              }
            }
            powerPreviousValue = powerValue;
          }
       
      }
      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;
          
         
          float percent_level;
          percent_level = 128 - (requestedLevel * 1.28);
          fadeToLevel( percent_level );
           Serial.print( "Changing level to " );
          Serial.print( requestedLevel );
          Serial.print( ", from " ); 
          Serial.println( currentLevel );
          // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
          gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));
      
          // hek comment: Is this really nessesary?
          gw.send( dimmerMsg.set(currentLevel) );
      
         
          }
      }
      
      /***
       *  This method provides a graceful fade up/down effect
       */
      void fadeToLevel( int toLevel ) {
        Serial.print("toLevel Value: ");
       Serial.println(toLevel);
      
        
        int delta = ( currentLevel - toLevel ) < 0 ? 1 : -1;
        Serial.print("delta Value: ");
       Serial.println(delta);
        while ( currentLevel != toLevel ) {
          currentLevel += delta;
         // analogWrite( MIRROR_LED_PIN, (int)(currentLevel / 100. * 255) );
          delay( FADE_DELAY );
          
           fadeLevel = toLevel;
        }
      
         // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
      // gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));  //used to send status of light (on/off) to Vera
        gw.send( dimmerMsg.set((int)currentLevel/100*128) );
        
      }
      
      

      OpenHab item

      Dimmer	Dimmed_Light	"Dimmer Light [%d %%]"	<slider>	(all,node1)		{ mqtt=">[mymqtt:/MyMQTT/30/3/V_DIMMER:state:*:default]" }
      

      Openhab sitemap

      Slider item=Dimmed_Light
      

      Openhab Rules

      /**
       * This is a demo rule which simulates a real dimmer by reacting to increase/decrease commands 
       * and posting an updated state on the bus 
       */
      rule "Dimmed Light"
      	when
      		Item Dimmed_Light received command
      	then
      		var Number percent = 100
      		if(Dimmed_Light.state instanceof DecimalType) percent = Dimmed_Light.state as DecimalType 
      			
      		if(receivedCommand==INCREASE) percent = percent + 5
      		if(receivedCommand==DECREASE) percent = percent - 5
      
      		if(percent<0)   percent = 0
      		if(percent>100) percent = 100
      		
      		postUpdate(Dimmed_Light, percent);
      end
      

      I have a problem:
      When i use fade up or fade down , openhab don't receive a value. But i use the fade up and fade down from openhab to AC module , the light dimmer okie.
      How can i fix it ?
      Thanks

      DrJeffD Offline
      DrJeffD Offline
      DrJeff
      wrote on last edited by
      #2

      @quocanhcgd Can you share the A/C dimmer design? I'm trying to do the same. Found many examples but building a circuit with a triac and zerocrossing.
      Thanks,
      Jeff

      1 Reply Last reply
      0
      • Q quocanhcgd

        Here my code.

        /*
        AC Light Control
        Uses up and down buttons to set levels
        makes use of a timer interrupt to set the level of dimming
        */
        #include <SPI.h>
        #include <MySensor.h>  
        #include <TimerOne.h>
        #include <Bounce2.h>
        #define SN "AC Dimmer control"
        #define SV "1.0"
        #define NODE_ID 30  //change to a number to assign a specific ID
        #define FADE_DELAY 100  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
        #define FADE_PERCENTAGE 5 //The percentage the fade level will be changed when a button is pressed
        volatile int i=0;               // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
        volatile boolean zero_cross=0;  // Flag to indicate we have crossed zero
        int AC_pin = 3;                 // Output to Opto Triac
        int UP_BUTTON_PIN = 5;                 // Arduino Digital I/O pin number for the fade up button 
        int DOWN_BUTTON_PIN = 6;                 // Arduino Digital I/O pin number for the fade down button 
        int POWER_BUTTON_PIN = 7;                 // Arduino Digital I/O pin number for the power button 
        
        int freqStep = 75;              // This is the delay-per-brightness step in microseconds. It allows for 128 steps
                                        // If using 60 Hz grid frequency set this to 65
        MySensor gw;
        //Tuy chinh lai
        static int currentLevel = 128;  // Current dim level...
        uint8_t fadeLevel = 128; //used to store the fade level when using the buttons
        uint8_t upPreviousValue;
        uint8_t downPreviousValue;
        uint8_t powerPreviousValue;
        
        Bounce upDebouncer = Bounce();
        Bounce downDebouncer = Bounce();
        Bounce powerDebouncer = Bounce();
        MyMessage dimmerMsg(AC_pin, V_DIMMER);
        MyMessage lightMsg(AC_pin, V_LIGHT);
        
        unsigned long previousMillis = 0; // last time update 
        unsigned long upPreviousMillis = 0;
        unsigned long downPreviousMillis = 0; 
        unsigned long buttonFadeDelay = 200; 
        
        // =Het tuy chinh lai
        
        
        void setup() {  // Begin setup
          Serial.begin(115200);
          /// - Setup Mysensors
          Serial.println( SN ); 
          gw.begin( incomingMessage,  NODE_ID, true);
          // Register the LED Dimmable Light with the gateway
          gw.present( 3, S_DIMMER );
          
          gw.sendSketchInfo(SN, SV);
          // Pull the gateway's current dim level - restore light level upon sendor node power-up
          gw.request( 3, V_DIMMER );
          // - Het setup mysensors
          //Setup the button
          /*pinMode(buton1, INPUT);  // set buton1 pin as input
          pinMode(buton2, INPUT);  // set buton1 pin as input
          pinMode(buton3, INPUT);  // set buton1 pin as input*/
             // Setup the button
          pinMode(UP_BUTTON_PIN,INPUT);
          pinMode(DOWN_BUTTON_PIN,INPUT);
          pinMode(POWER_BUTTON_PIN,INPUT);
          
          // Activate internal pull-up
          digitalWrite(UP_BUTTON_PIN,LOW);
          digitalWrite(DOWN_BUTTON_PIN,LOW);
          digitalWrite(POWER_BUTTON_PIN,LOW);
          
          // After setting up the button, setup debouncer
          upDebouncer.attach(UP_BUTTON_PIN);
          downDebouncer.attach(DOWN_BUTTON_PIN);
          powerDebouncer.attach(POWER_BUTTON_PIN);
          upDebouncer.interval(5);
          downDebouncer.interval(5);
          powerDebouncer.interval(5);
          
          //Setup AC PIN
          pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
          attachInterrupt(0, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
          Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
          Timer1.attachInterrupt(dim_check, freqStep);      // Go to dim_check procedure every 75 uS (50Hz)  or 65 uS (60Hz)
          // Use the TimerOne Library to attach an interrupt
          
        }
        
        void zero_cross_detect() {    
          zero_cross = true;               // set flag for dim_check function that a zero cross has occured
          i=0;                             // stepcounter to 0.... as we start a new cycle
          digitalWrite(AC_pin, LOW);
        }                                 
        
        // Turn on the TRIAC at the appropriate time
        // We arrive here every 75 (65) uS
        // First check if a flag has been set
        // Then check if the counter 'i' has reached the dimming level
        // if so.... switch on the TRIAC and reset the counter
        void dim_check() {                   
          if(zero_cross == true) {              
            if(i>=fadeLevel) {                     
              digitalWrite(AC_pin, HIGH);  // turn on light       
              i=0;  // reset time step counter                         
              zero_cross=false;    // reset zero cross detection flag
            } 
            else {
              i++;  // increment time step counter                     
            }                                
          }    
        }                                      
        
        void loop() {  
            gw.process();
            /*
        There are 3 buttons attached to the mirror.  One is an on/off button and the other two will fade up/fade down.  
        The sensor will remember the last fade state and fade the lights to that level next time they are turned on.
        
        If fade up or fade down button is pressed it should store that value into a variable and when the ON button is pressed
        it will fade to that previous value.
         */ 
         //up button
          upDebouncer.update();
            // Get the update value
            uint8_t upValue = upDebouncer.read();
            
            unsigned long upCurrentMillis = millis();
            
            if(upCurrentMillis - upPreviousMillis > buttonFadeDelay){
              if ((upValue == HIGH) && (fadeLevel<128)) { //Because of the internal pullup resistors LOW = button is presssed
                   fadeLevel = fadeLevel < 8 ? 0 : fadeLevel;
                   if (fadeLevel > 8)
                  { fadeLevel -= (FADE_PERCENTAGE * 1.28);
                } else {
                  fadeLevel = 8;
                }
                   fadeToLevel( fadeLevel );
                   Serial.println(fadeLevel);
              }
              upPreviousMillis = upCurrentMillis;
            }
          
         // down button
         downDebouncer.update();
            // Get the update value
            uint8_t downValue = downDebouncer.read();
            
            unsigned long downCurrentMillis = millis();
            
            if(downCurrentMillis - downPreviousMillis > buttonFadeDelay){
              if ((downValue == HIGH) && (fadeLevel>0)) {                
                 fadeLevel += (FADE_PERCENTAGE * 1.28);
                 fadeLevel = fadeLevel > 128 ? 121 : fadeLevel;
                 fadeToLevel( fadeLevel );
                 Serial.println(fadeLevel);                 
              }
              downPreviousMillis = downCurrentMillis;
            }
         // Power button
         powerDebouncer.update();
            // Get the update value
            uint8_t powerValue = powerDebouncer.read();
            
            if(powerValue != powerPreviousValue){
              if (powerValue == HIGH) {
              Serial.print("Power Button Pressed. fadeLevel is ");
              Serial.println(fadeLevel);
             
                if (currentLevel < 128) {
                  
                 fadeToLevel( 128 );
                 fadeLevel = 128;
                }
                else{
                  if (fadeLevel == 128) {
                    fadeToLevel(64);
                    fadeLevel = 64;
                  }
                  else{
                    fadeToLevel(fadeLevel);
                  }
                }
              }
              powerPreviousValue = powerValue;
            }
         
        }
        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;
            
           
            float percent_level;
            percent_level = 128 - (requestedLevel * 1.28);
            fadeToLevel( percent_level );
             Serial.print( "Changing level to " );
            Serial.print( requestedLevel );
            Serial.print( ", from " ); 
            Serial.println( currentLevel );
            // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
            gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));
        
            // hek comment: Is this really nessesary?
            gw.send( dimmerMsg.set(currentLevel) );
        
           
            }
        }
        
        /***
         *  This method provides a graceful fade up/down effect
         */
        void fadeToLevel( int toLevel ) {
          Serial.print("toLevel Value: ");
         Serial.println(toLevel);
        
          
          int delta = ( currentLevel - toLevel ) < 0 ? 1 : -1;
          Serial.print("delta Value: ");
         Serial.println(delta);
          while ( currentLevel != toLevel ) {
            currentLevel += delta;
           // analogWrite( MIRROR_LED_PIN, (int)(currentLevel / 100. * 255) );
            delay( FADE_DELAY );
            
             fadeLevel = toLevel;
          }
        
           // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
        // gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));  //used to send status of light (on/off) to Vera
          gw.send( dimmerMsg.set((int)currentLevel/100*128) );
          
        }
        
        

        OpenHab item

        Dimmer	Dimmed_Light	"Dimmer Light [%d %%]"	<slider>	(all,node1)		{ mqtt=">[mymqtt:/MyMQTT/30/3/V_DIMMER:state:*:default]" }
        

        Openhab sitemap

        Slider item=Dimmed_Light
        

        Openhab Rules

        /**
         * This is a demo rule which simulates a real dimmer by reacting to increase/decrease commands 
         * and posting an updated state on the bus 
         */
        rule "Dimmed Light"
        	when
        		Item Dimmed_Light received command
        	then
        		var Number percent = 100
        		if(Dimmed_Light.state instanceof DecimalType) percent = Dimmed_Light.state as DecimalType 
        			
        		if(receivedCommand==INCREASE) percent = percent + 5
        		if(receivedCommand==DECREASE) percent = percent - 5
        
        		if(percent<0)   percent = 0
        		if(percent>100) percent = 100
        		
        		postUpdate(Dimmed_Light, percent);
        end
        

        I have a problem:
        When i use fade up or fade down , openhab don't receive a value. But i use the fade up and fade down from openhab to AC module , the light dimmer okie.
        How can i fix it ?
        Thanks

        C Offline
        C Offline
        C.r.a.z.y.
        wrote on last edited by
        #3

        @quocanhcgd Can you share the A/C dimmer design?

        1 Reply Last reply
        0
        • FotoFieberF Offline
          FotoFieberF Offline
          FotoFieber
          Hardware Contributor
          wrote on last edited by FotoFieber
          #4

          Working on a solution for 220V/50 hz based on http://www.instructables.com/id/Arduino-controlled-light-dimmer-The-circuit/

          Dimmer.fzz

          I didn't have a symbol for TIC206 and H11AA1, so be careful and read the schematics.

          When all parts have arrived and I had time to test it, I will report here.

          https://oshpark.com/shared_projects/3skWWYHF

          DrJeffD 1 Reply Last reply
          0
          • FotoFieberF FotoFieber

            Working on a solution for 220V/50 hz based on http://www.instructables.com/id/Arduino-controlled-light-dimmer-The-circuit/

            Dimmer.fzz

            I didn't have a symbol for TIC206 and H11AA1, so be careful and read the schematics.

            When all parts have arrived and I had time to test it, I will report here.

            https://oshpark.com/shared_projects/3skWWYHF

            DrJeffD Offline
            DrJeffD Offline
            DrJeff
            wrote on last edited by
            #5

            @FotoFieber I got a circuit working, But I don't know how to write the code to dim, and work remotely. I used BT137 Triacs instead of TIC206 because of availability. The main issue I had with a 110V/60Hz was the resistor pulling the zerocross Pin high, It would not work but when I removed the resistor all functional?! The schematic I used it was from Inmojo here it is http://bit.ly/1C1xCOS
            It works well the only adjustments needed is how low and how high you dim the circuit. Now the code part is what I need. I will give the above code a spin, It looks like the dimmer mirror code from @petewill.

            1 Reply Last reply
            0
            • T Offline
              T Offline
              thomasdc
              wrote on last edited by thomasdc
              #6

              were you (someone) able to debug the 'fading' funciton in the code? i think its a problem in the while loop in the arduino/mysensors code the while loop is done, but only when the while loop is comletely through , the 'dimvalue' gets updated/changed

              EDIT:
              this works!

              /*
              AC Light Control
              Uses up and down buttons to set levels
              makes use of a timer interrupt to set the level of dimming
              */
              #include <SPI.h>
              #include <MySensor.h>  
              #include <TimerOne.h>
              
              #define SN "AC Dimmer control"
              #define SV "1.0"
              #define NODE_ID 30  //change to a number to assign a specific ID
              #define FADE_DELAY 50  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
              #define FADE_PERCENTAGE 5 //The percentage the fade level will be changed when a button is pressed
              volatile int i=0;               // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
              volatile boolean zero_cross=0;  // Flag to indicate we have crossed zero
              int AC_pin = 6;                 // Output to Opto Triac
              
              int freqStep = 75;              // This is the delay-per-brightness step in microseconds. It allows for 128 steps
                                              // If using 60 Hz grid frequency set this to 65
              MySensor gw;
              //Tuy chinh lai
              static int currentLevel = 128;  // Current dim level...
              uint8_t fadeLevel = 128; //used to store the fade level when using the buttons
              uint8_t upPreviousValue;
              uint8_t downPreviousValue;
              uint8_t powerPreviousValue;
              
              
              MyMessage dimmerMsg(AC_pin, V_DIMMER);
              MyMessage lightMsg(AC_pin, V_LIGHT);
              
              
              
              // =Het tuy chinh lai
              
              
              void setup() {  // Begin setup
                Serial.begin(115200);
                /// - Setup Mysensors
                Serial.println( SN ); 
                gw.begin( incomingMessage,  NODE_ID, true);
                // Register the LED Dimmable Light with the gateway
                gw.present( 6, S_DIMMER );
                
                gw.sendSketchInfo(SN, SV);
                // Pull the gateway's current dim level - restore light level upon sendor node power-up
                gw.request( 6, V_DIMMER );
              
              
                
                //Setup AC PIN
                pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
                attachInterrupt(1, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
                Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
                Timer1.attachInterrupt(dim_check, freqStep);      // Go to dim_check procedure every 75 uS (50Hz)  or 65 uS (60Hz)
                // Use the TimerOne Library to attach an interrupt
                
              }
              
              void zero_cross_detect() {    
                zero_cross = true;               // set flag for dim_check function that a zero cross has occured
                i=0;                             // stepcounter to 0.... as we start a new cycle
                digitalWrite(AC_pin, LOW);
              }                                 
              
              // Turn on the TRIAC at the appropriate time
              // We arrive here every 75 (65) uS
              // First check if a flag has been set
              // Then check if the counter 'i' has reached the dimming level
              // if so.... switch on the TRIAC and reset the counter
              
              void dim_check() {                   
                if(zero_cross == true) {              
                  if(i>=fadeLevel) {                     
                    digitalWrite(AC_pin, HIGH);  // turn on light       
                    i=0;  // reset time step counter                         
                    zero_cross=false;    // reset zero cross detection flag
                  } 
                  else {
                    i++;  // increment time step counter                     
                  }                                
                }    
              }
              
                                          
              
              void loop() {  
                  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;
                  
                 
                  float percent_level;
                  percent_level = 128 - (requestedLevel * 1.28);
                  fadeToLevel( percent_level );
                   Serial.print( "Changing level to " );
                  Serial.print( requestedLevel );
                  Serial.print( ", from " ); 
                  Serial.println( currentLevel );
                  // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
                 //  gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));
              
                  // hek comment: Is this really nessesary?
                 // gw.send( dimmerMsg.set(currentLevel) );
              
                
                  }
              }
              
              /***
               *  This method provides a graceful fade up/down effect
               */
              void fadeToLevel( int toLevel ) {
                Serial.print("toLevel Value: ");
               Serial.println(toLevel);
              
                
                int delta = ( currentLevel - toLevel ) < 0 ? 1 : -1;
                Serial.print("delta Value: ");
               Serial.println(delta);
                while ( currentLevel != toLevel ) {
                  currentLevel += delta;
              
               fadeLevel= ((int)currentLevel);
                  delay( FADE_DELAY );
                  //fadeLevel = toLevel;
              
                 
              
                }
              
              
                
              }
              
              ahmedadelhosniA 1 Reply Last reply
              0
              • J Offline
                J Offline
                jemish
                wrote on last edited by
                #7

                Can we control AC ceiling fan using openhab dimmer.
                I get circuit schematic for AC fan dimmer.96_1257497893.gif

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  jemish
                  wrote on last edited by
                  #8

                  can we control it?

                  1 Reply Last reply
                  0
                  • T thomasdc

                    were you (someone) able to debug the 'fading' funciton in the code? i think its a problem in the while loop in the arduino/mysensors code the while loop is done, but only when the while loop is comletely through , the 'dimvalue' gets updated/changed

                    EDIT:
                    this works!

                    /*
                    AC Light Control
                    Uses up and down buttons to set levels
                    makes use of a timer interrupt to set the level of dimming
                    */
                    #include <SPI.h>
                    #include <MySensor.h>  
                    #include <TimerOne.h>
                    
                    #define SN "AC Dimmer control"
                    #define SV "1.0"
                    #define NODE_ID 30  //change to a number to assign a specific ID
                    #define FADE_DELAY 50  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
                    #define FADE_PERCENTAGE 5 //The percentage the fade level will be changed when a button is pressed
                    volatile int i=0;               // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
                    volatile boolean zero_cross=0;  // Flag to indicate we have crossed zero
                    int AC_pin = 6;                 // Output to Opto Triac
                    
                    int freqStep = 75;              // This is the delay-per-brightness step in microseconds. It allows for 128 steps
                                                    // If using 60 Hz grid frequency set this to 65
                    MySensor gw;
                    //Tuy chinh lai
                    static int currentLevel = 128;  // Current dim level...
                    uint8_t fadeLevel = 128; //used to store the fade level when using the buttons
                    uint8_t upPreviousValue;
                    uint8_t downPreviousValue;
                    uint8_t powerPreviousValue;
                    
                    
                    MyMessage dimmerMsg(AC_pin, V_DIMMER);
                    MyMessage lightMsg(AC_pin, V_LIGHT);
                    
                    
                    
                    // =Het tuy chinh lai
                    
                    
                    void setup() {  // Begin setup
                      Serial.begin(115200);
                      /// - Setup Mysensors
                      Serial.println( SN ); 
                      gw.begin( incomingMessage,  NODE_ID, true);
                      // Register the LED Dimmable Light with the gateway
                      gw.present( 6, S_DIMMER );
                      
                      gw.sendSketchInfo(SN, SV);
                      // Pull the gateway's current dim level - restore light level upon sendor node power-up
                      gw.request( 6, V_DIMMER );
                    
                    
                      
                      //Setup AC PIN
                      pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
                      attachInterrupt(1, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
                      Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
                      Timer1.attachInterrupt(dim_check, freqStep);      // Go to dim_check procedure every 75 uS (50Hz)  or 65 uS (60Hz)
                      // Use the TimerOne Library to attach an interrupt
                      
                    }
                    
                    void zero_cross_detect() {    
                      zero_cross = true;               // set flag for dim_check function that a zero cross has occured
                      i=0;                             // stepcounter to 0.... as we start a new cycle
                      digitalWrite(AC_pin, LOW);
                    }                                 
                    
                    // Turn on the TRIAC at the appropriate time
                    // We arrive here every 75 (65) uS
                    // First check if a flag has been set
                    // Then check if the counter 'i' has reached the dimming level
                    // if so.... switch on the TRIAC and reset the counter
                    
                    void dim_check() {                   
                      if(zero_cross == true) {              
                        if(i>=fadeLevel) {                     
                          digitalWrite(AC_pin, HIGH);  // turn on light       
                          i=0;  // reset time step counter                         
                          zero_cross=false;    // reset zero cross detection flag
                        } 
                        else {
                          i++;  // increment time step counter                     
                        }                                
                      }    
                    }
                    
                                                
                    
                    void loop() {  
                        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;
                        
                       
                        float percent_level;
                        percent_level = 128 - (requestedLevel * 1.28);
                        fadeToLevel( percent_level );
                         Serial.print( "Changing level to " );
                        Serial.print( requestedLevel );
                        Serial.print( ", from " ); 
                        Serial.println( currentLevel );
                        // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
                       //  gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));
                    
                        // hek comment: Is this really nessesary?
                       // gw.send( dimmerMsg.set(currentLevel) );
                    
                      
                        }
                    }
                    
                    /***
                     *  This method provides a graceful fade up/down effect
                     */
                    void fadeToLevel( int toLevel ) {
                      Serial.print("toLevel Value: ");
                     Serial.println(toLevel);
                    
                      
                      int delta = ( currentLevel - toLevel ) < 0 ? 1 : -1;
                      Serial.print("delta Value: ");
                     Serial.println(delta);
                      while ( currentLevel != toLevel ) {
                        currentLevel += delta;
                    
                     fadeLevel= ((int)currentLevel);
                        delay( FADE_DELAY );
                        //fadeLevel = toLevel;
                    
                       
                    
                      }
                    
                    
                      
                    }
                    
                    ahmedadelhosniA Offline
                    ahmedadelhosniA Offline
                    ahmedadelhosni
                    wrote on last edited by
                    #9

                    @thomasdc Does this method of using the timer interrupts + pin interrupts worked well with you ? You didn't need to disable interrupts sometimes between subroutines calls ?

                    I am just asking because a year and a half ago I tried to do this using a PIC and it worked well when I was using delay function to delay the firing of the Triac after zero crossing is detected, but after I switched to a non blockage technique and used a time overflow, I found that sometimes the lamp just flickers for a moment while the fading is working. It happened randomly and I couldn't know the reason.

                    1 Reply Last reply
                    0
                    • P Offline
                      P Offline
                      palmerfarmer
                      wrote on last edited by
                      #10

                      How easy is this to convert to work with domoticz?

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


                      15

                      Online

                      11.7k

                      Users

                      11.2k

                      Topics

                      113.1k

                      Posts


                      Copyright 2025 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