MySensors Gatway dimmers & Home assistant



  • Hi there,
    i am having strange issues with MySensors & Home assistant.
    Whenever i request a light change state in hass, the dimmer first goes to 100% before going to the state i requested.
    I used the example code as on the front page:
    here 's a snippet:

    void receive(const MyMessage &message)
    {
        if ((message.type == V_LIGHT || message.type == V_DIMMER) && message.sensor==1) {
            int requestedLevel = atoi( message.data );
            requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
            requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
            requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
            whiteLed = requestedLevel;
            fadeWhiteToLevel( requestedLevel )
        }
    
    

    Skip unnecessary 2nd light (behaviour is the same)

    void fadeWhiteToLevel( int toLevel )
    {
    
        int delta = ( toLevel - currentWhiteLevel ) < 0 ? -1 : 1;
    
        while ( currentWhiteLevel != toLevel ) {
            currentWhiteLevel += delta;
            analogWrite( LED_WHITE, (int)(currentWhiteLevel / 100. * 255) );
            delay( FADE_DELAY );
        }
       send(lightMsgWhite.set(currentWhiteLevel > 0));
       send(dimmerMsgWhite.set(currentWhiteLevel) );
       whiteLed= currentWhiteLevel;
    }
    


  • what is currentWhiteLevel? The state variable seems to be whiteLed, right?
    currentWhiteLevel is not initalized before the loop starts and is not necessarily == whiteLed when fadeWhiteToLevel starts



  • the whiteLed is used in my button part
    full code

      #include <MySensors.h>
    // Set blinking period
    //?#define MY_DEFAULT_LED_BLINK_PERIOD 300
    
    // Inverses the behavior of leds
    //#define MY_WITH_LEDS_BLINKING_INVERSE
    
    #define CHILD_ID_TEMP 0
    #define CHILD_ID_LIGHT_WHITE 1
    #define CHILD_ID_LIGHT_BLUE 2
    #define CHILD_ID_SWITCH_WHITE 3
    #define CHILD_ID_SWITCH_BLUE 4
    
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); // 0
    MyMessage dimmerMsgWhite(CHILD_ID_LIGHT_WHITE, V_DIMMER);
    MyMessage lightMsgWhite(CHILD_ID_LIGHT_WHITE, V_LIGHT);
    MyMessage dimmerMsgBlue(CHILD_ID_LIGHT_BLUE, V_DIMMER);
    MyMessage lightMsgBlue(CHILD_ID_LIGHT_BLUE, V_LIGHT);
    MyMessage switchMsgWhite(CHILD_ID_SWITCH_WHITE, S_BINARY);
    MyMessage switchMsgBlue(CHILD_ID_SWITCH_BLUE, S_BINARY);
    // Dimmer variables
    static int16_t currentWhiteLevel = 0;
    static int16_t currentBlueLevel =0;
    #define LED_WHITE 6
    #define LED_BLUE 5
    #define FADE_DELAY 70
    #define BUZZER 9
    #define whiteButton 7
    #define blueButton 8
    
    //Aqua Temp variables
    int tempPin = A5;    
    int samples = 100; 
    int sampletime = 25;
    int tempReading;
    float allSamples=0;
    unsigned long probeTime = 0;
    const long aqua_interval = (5 * 60000);
    // Button variables
    boolean blueButtonState =0;
    boolean whiteButtonState=0;
    boolean lastBlueButtonState=0;
    boolean lastWhiteButtonState=0;
    int whiteLed=0;
    int blueLed=0;
    void setup()
    {
        // Setup locally attached sensors
         #define aref_voltage 3.3; 
        // If you want to set the aref to something other than 5v
        analogReference(INTERNAL);
        // read to stabalize aref thingy
         float voltage = analogRead(tempPin) * 1.1;
         delay(500);
        // request( CHILD_ID_LIGHT_WHITE, V_DIMMER );
        // send(lightMsgWhite.set(currentLevel > 0 ? 1 : 0));
        // send(dimmerMsgWhite.set(currentLevel));
        // request( CHILD_ID_LIGHT_BLUE, V_DIMMER );
        // send(lightMsgBlue.set(currentLevel > 0 ? 1 : 0));
        // send(dimmerMsgBlue.set(currentLevel));
         pinMode(whiteButton, INPUT);
         pinMode(blueButton, INPUT);
    
         // tell HASS that everything is off after reset:
         send(lightMsgBlue.set(0) );
    
         send(lightMsgWhite.set(0));
    }
    
    void presentation()
    {
      sendSketchInfo("Aquarium", "1.4");
      present(CHILD_ID_TEMP, S_TEMP); 
      present(CHILD_ID_LIGHT_WHITE, S_DIMMER );
      present(CHILD_ID_LIGHT_BLUE, S_DIMMER );
    
    
        // Present locally attached sensors
    }
    
    
    
    
    
    void loop()
    {
      delay(50);
      // check Button Press
      checkButtonClick();
        // Send locally attached sensor data here
    }
    
    void receive(const MyMessage &message)
    {
        if ((message.type == V_LIGHT || message.type == V_DIMMER) && message.sensor==1) {
            int requestedLevel = atoi( message.data );
            requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
            requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
            requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
            whiteLed = requestedLevel;
            fadeWhiteToLevel( requestedLevel );
        }
    if ((message.type == V_LIGHT || message.type == V_DIMMER) && message.sensor==2) {
            int requestedLevel = atoi( message.data );
            requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
            requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
            requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
            fadeBlueToLevel( requestedLevel );
        }
    
        
    }
    void fadeWhiteToLevel( int toLevel )
    {
        int delta = ( toLevel - currentWhiteLevel ) < 0 ? -1 : 1;
        while ( currentWhiteLevel != toLevel ) {
            currentWhiteLevel += delta;
            analogWrite( LED_WHITE, (int)(currentWhiteLevel / 100. * 255) );
            delay( FADE_DELAY );
        }
       send(lightMsgWhite.set(currentWhiteLevel > 0));
       send(dimmerMsgWhite.set(currentWhiteLevel) );
       whiteLed= currentWhiteLevel;
    }
    
    void fadeBlueToLevel( int toLevel )
    {
        int delta = ( toLevel - currentBlueLevel ) < 0 ? -1 : 1;
        while ( currentBlueLevel != toLevel ) {
            currentBlueLevel += delta;
            analogWrite( LED_BLUE, (int)(currentBlueLevel / 100. * 255) );
            delay( FADE_DELAY );
        }
        send(lightMsgBlue.set(currentBlueLevel > 0));
        send(dimmerMsgBlue.set(currentBlueLevel) );
        blueLed= currentBlueLevel;
    }
    
    
    
    void checkButtonClick()
    {
      // read buttons
      blueButtonState = digitalRead(whiteButton);
      whiteButtonState = digitalRead(blueButton);
     
      delay(25);
      
      if (blueButtonState != lastBlueButtonState && blueButtonState==true) {
     // toggle light
      lastBlueButtonState=true;
      if (blueLed > 1) { 
         fadeBlueToLevel( 0 );
        } else  {
          fadeBlueToLevel(100);
          }
      }
    
     
      if (whiteButtonState != lastWhiteButtonState && whiteButtonState==true) {
     // toggle light
      lastWhiteButtonState=true;
          
      if (whiteLed > 1 ) {
            fadeWhiteToLevel( 0 );     
      } else {
          fadeWhiteToLevel(100);
          whiteLed = 100;
      }
      }
     if (blueButtonState != lastBlueButtonState && blueButtonState==false) {
      lastBlueButtonState=false;
      }
     if (whiteButtonState != lastWhiteButtonState && whiteButtonState==false) {
      lastWhiteButtonState=false;
      }
       
    }
        
    


  • Hm not sure. Put some Serial.pintln debug messages to see what actually happens.



  • @pansen cannot use that because hass communicates over the serial port 😞



  • I'm confused, your arduino node is connected to something via serial?



  • You should get rid of whiteLed (replace it with currentWhiteLevel). There is no need for two state variables for the same thing. I think they can even run out of sync, when the button is pressed while the message is processed.

    However, I am not really sure if they are responsible for your issue.



  • @pansen yes the USB is connectec to my Raspberry pi which is running Home Assistant.
    over the USB connection the Mysensors messages are done .
    So when the Home assistant is running i have no access to the serial console.
    I Can serial print some things which will show up in the HASS log files as incorrect messages but thats not instant feedback



  • @enlo i wil try that.


  • Plugin Developer

    @Richard-van-der-Plas

    Hi!

    If the light is not already on when you request a brightness change from home assistant, it will send a V_LIGHT message to turn the light on, to the device. The device will process that message in receive and this is an important line:

    requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
    

    It means that it will set requestedLevel to 100 if receiving a V_LIGHT message type. So it will reply home assistant with two messages. First a message of V_LIGHT to turn the light on, and then a message of V_DIMMER with payload 100.

    send(lightMsgWhite.set(currentWhiteLevel > 0));
    send(dimmerMsgWhite.set(currentWhiteLevel) );
    

    This is why the brightness always goes to 100 before being set to your requested value. It's only on the second message from home assistant that the light will actually turn to the requested brightness. This should not be the case if the light is already on, when requesting a new brightness. Then the brightness should change to the correct level directly.

    If you want to avoid the former behavior, you should decouple the replies to home assistant. Only answer a V_LIGHT message with a V_LIGHT message and only answer a V_DIMMER message with a V_DIMMER message.

    Edit:
    Caveat is that if not setting dimmer level and sending a V_DIMMER message when receiving the V_LIGHT message, the device will have the previous brightness setting until receiving the message with V_DIMMER and new level.

    It's not really about decoupling the replies but about decoupling the logic that handles the incoming values and what actions to take for changing the dimmer. Sorry for being unclear above.



  • @martinhjelmare How can i fix that, read your story twice, know what you mean, but don know the solution 🙂
    i think i need to split
    ((message.type == V_LIGHT || message.type == V_DIMMER) && message.sensor==2)
    is that correct ?


  • Plugin Developer

    Yes, exactly. Have one logic when receiving a V_LIGHT message and another logic when receiving a V_DIMMER message. I can post example code in a bit, currently on mobile.



  • @martinhjelmare ok ill wait,
    meanwhile splitted the Message.type== V_LIGHT & == V_DIMMER into 2 different ifs.
    created a quick serial.println on the vlight, and see in my HASS that indeed changing the dim level on the led when off , triggers a v_light and turns it to 100%
    -Update indeed when removing the V_LIGHT message type behaviour is okay, but im unable to turn off the light

    • Following code is now testing:
    if ((message.type == V_LIGHT) && message.sensor==1) {
            int requestedLevel = atoi( message.data );
           Serial.print("message:"); 
           Serial.println(requestedLevel);
           Serial.print("VLIGHT DETECTET set to:"); 
           requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
           Serial.println(requestedLevel);
           if (requestedLevel <1) {fadeWhiteToLevel( requestedLevel );}
        }
    

    Behaviour is better now
    only issue i now have is the 255 values of arduino to the 100 of HASS ,


  • Plugin Developer

    This should work, but I haven't tested it:

    void receive(const MyMessage &message) {
      if ((message.type == V_LIGHT && message.sensor==1) {
        int lightState = message.getInt();
        if (( lightState == 1 ) && ( currentWhiteLevel == 0 )) {
          requestedLevel = 100;
        } else {
          requestedLevel = lightState > 0 ? currentWhiteLevel : 0;
        }
      }
      if (message.type == V_DIMMER && message.sensor==1)) {
        int requestedLevel = message.getInt();
        requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
        requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
      }
      whiteLed = requestedLevel;
      fadeWhiteToLevel( requestedLevel );
    }
    

    Edit:
    It's not really about decoupling the replies but about decoupling the logic that handles the incoming values and what actions to take for changing the dimmer. Sorry for being unclear above.



  • i have fixed it like this :

    void receive(const MyMessage &message)
    {
        if ((message.type == V_LIGHT)) {
    
            // V_LIGHT command received, only do something when 0
            
            int requestedLevel = atoi( message.data );
    
    
            if (requestedLevel ==0 && message.sensor == 1) {fadeWhiteToLevel( requestedLevel );}
            if (requestedLevel ==0 && message.sensor == 2) {fadeBlueToLevel( requestedLevel );}
    
    
        }
        
    if ((message.type == V_DIMMER) ) {
    
            //  Retrieve the dim level from the incoming request message
            int requestedLevel = atoi( message.data );
    
            // Clip incoming level to valid range of 0 to 100
            requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
            requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
            if (message.sensor == 1) {fadeWhiteToLevel( requestedLevel );}
            if (message.sensor == 2) {fadeBlueToLevel( requestedLevel );}
    
            fadeBlueToLevel( requestedLevel );
    
        }
    

  • Plugin Developer

    But then how would you turn the light on without using the brightess slider in home assistant?



  • @martinhjelmare indeed that doesn't work anymore, i have to turn on the light with the slider.
    But because its alwas an automation that turns on the light, that isnt such a big problem. i m trying to keep the code as small ass possible, because i have to add a dallas temperature controller to it, and its already complaining about low storage 😞

    Sketch uses 10020 bytes (69%) of program storage space. Maximum is 14336 bytes.
    Global variables use 850 bytes (83%) of dynamic memory, leaving 174 bytes for local variables. Maximum is 1024 bytes.
    

    In your code i also see this line:

    if (( lightState == 1 ) && ( currentWhiteLevel == 0 )) {
         requestedLevel = 100;
       } else {
         requestedLevel = lightState > 0 ? currentWhiteLevel : 0;
       }
    

    what does that do when light is on & level is 0 turn it to 100% else ???


  • Plugin Developer

    If you request the light to turn on and current level is 0, we don't want the light to remain at 0 level, so we set it to 100 instead.

    Edit:
    I think you can save memory in other parts of your sketch, if you need. But you're not at 100% yet, so I wouldn't worry until I hit the limit.



  • I understand your statement, but that's where it went wrong,
    The hass also sends lights on when changing the dim value so it first goes to 100 ?
    other question
    Any idea how i can change the delta of 1 & -1 of 100% to 1 & -1 of 255 steps the arduino can cope ?


  • Plugin Developer

    We only set the level to 100 when current level is 0, otherwise we set to same level as current level.

    Look at map function for remapping brightness.
    https://www.arduino.cc/en/Reference/Map



  • @martinhjelmare Thanks for the input, when i arrive home ill update my code 🙂


Log in to reply
 

Suggested Topics

  • 87
  • 8
  • 1
  • 3
  • 5
  • 10

11
Online

11.4k
Users

11.1k
Topics

112.7k
Posts