<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dimmer problem (value changes by the sensor)]]></title><description><![CDATA[<p dir="auto">Hi<br />
I have a problem with Dimmer updated by “sensor” rotary encoder from Mysensors gateway.</p>
<p dir="auto">Project:<br />
The Rotary encoder updates the dimmer by a value in the domoticz, then by the script or group other dimmers are updated with the same value (rotary encoder).</p>
<p dir="auto">What works:<br />
Dimmer is successfully updated by (sensor) mysensors gateway, I see visually that value bar is moving and setup on correct value, but…</p>
<p dir="auto">Does not works:<br />
...that's it, nothing changes on other dimmers, like rotary was set up with value but not trigger, no actions are made. In the dimmer log tab, I can see when dimmer from the dashboard is setup (set up: specific value ) and linked dimmers are updated too, but when the main dimmer is updated by rotary encoder there is only “ON’ word and linked dimmers do not receive any data.</p>
<p dir="auto">This is a bug? Wrong Arduino script? Or do I have to do additional actions in domoticz? :?</p>
<pre><code>// ========================================================
// INCLUDES
// ========================================================
#define MY_GATEWAY_SERIAL
#define MY_DEBUG
// for display
#include &lt;Arduino.h&gt;
#include &lt;Wire.h&gt;
#include &lt;U8g2lib.h&gt;
#include &lt;MySensors.h&gt;
// for timer
#include &lt;TimerOne.h&gt;
// for rotary encoder
#include &lt;Rotary.h&gt;

// ========================================================
// DEBUG
// ========================================================


//=========================================================
//sciemniacz
//=======================================================
#define FADE_DELAY 10              // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
#define SEND_THROTTLE_DELAY 400    // Number of milliseconds before sending after user stops turning knob 
#define SN "DimmableLED 2"
#define SV "1"
#define EEPROM_DIM_LEVEL_LAST 1
#define EEPROM_DIM_LEVEL_SAVE 2
#define LIGHT_OFF 0
#define LIGHT_ON 1
int dimValue;
int fadeTo;
int fadeDelta;
byte oldButtonVal;
bool changedByKnob=false;
bool sendDimValue=false;
unsigned long lastFadeStep;
unsigned long sendDimTimeout;
char convBuffer[10];
#define LED_PIN 7           // Arduino pin attached to MOSFET Gate pin
MyMessage dimmer_msg(1, V_PERCENTAGE);
MyMessage light_msg(1, V_STATUS);
MyMessage dimmerinp(8, V_PERCENTAGE);
MyMessage lightinp(8, V_STATUS);
static int16_t currentLevel = 0;  // Current dim level...
#define LIGHT_OFF 0
#define LIGHT_ON 1
int16_t last_state = LIGHT_ON;
int16_t last_dim = 100;
int16_t dupa = 10;
// ========================================================
// DEFAULTS
// ========================================================

#define VERSION_TITLE "OLED MENU PAGES"
#define VERSION_HW "Corridor 2 Rev. B"
#define VERSION_SUBTITLE "by @schlueri 2017"
#define VERSION "0.32B"

// Status LED
#define STATUS_LED_PIN 9
bool statusLedOn = false;

// Timer
#define TIMER 1000

// Display and menu stuff
int displayCurrentPage = 0;
bool setNeedsDisplay = false;

// Main menu fixed to 3 items, left, center, right...
#define MENU_SELECTED_TIMEOUT 4000
#define MENU_POS_Y 62
#define MENU_POS_Y_HIDDEN 76
#define MENU_ANIMATION_PIXEL_STEP 2
String menuItems[3] = {"MAIN", "NETWORK", "SETUP"};
int menuActive = 1;             // left active
int menuSelected = menuActive;  // selected
bool menuPageMode = true;      // true =&gt; rotary encoder control page and not menu

// Menu animation
bool menuAnimationRunning = true;
int menuPosY = MENU_POS_Y;

// Rotary encoder with switch
#define ROTARY_SWITCH 5  // A1
#define ROTARY_PIN1 2
#define ROTARY_PIN2 3
#define ROTARY_ACCEL_OFFSET1 20
#define ROTARY_ACCEL_OFFSET2 50
#define ROTARY_ACCEL_OFFSET3 70
unsigned long rotaryLastMove;
bool rotaryButtonPressed = false;


// Test slider
int sliderPosX = 64;

// Logic
long int heartbeat = 0;
#define HEARTBEAT_TRIGGER 1000
#define HEARTBEAT_TRIGGER_TIME 50

// ========================================================
// PAGES STUFF
// ========================================================

#define SETUP_MENU_ITEMS 8
String setupMenuItems[SETUP_MENU_ITEMS] = {"EXIT", "LDR LEVEL", "LDR THRESHOLD", "PIR SENSOR", "LED COLOR", "LED ANIMATION", "LED OUT TEST", "VERSION &amp; INFO"};
int setupMenuSelected = 0;

// ========================================================
// INITS
// ========================================================

// Display
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// Rotary Encoder
Rotary rotary = Rotary(ROTARY_PIN1, ROTARY_PIN2);

// ========================================================
// SETUP
// ========================================================
 
void setup()
{
  // put your setup code here, to run once:

  // Status LED
  pinMode(STATUS_LED_PIN, OUTPUT);
  digitalWrite(STATUS_LED_PIN, HIGH);

#ifdef DEBUG
  Serial.begin(DEBUG_BAUD);
  Serial.println("DEBUG MODE");
  Serial.print("Version ");
  Serial.print(VERSION);
  Serial.print("\n\n");
#endif

  // Menu Button
  pinMode(ROTARY_SWITCH, INPUT);
  digitalWrite(ROTARY_SWITCH, INPUT_PULLUP);

#ifdef BUTTON1_PIN
  pinMode(BUTTON1_PIN, INPUT);
  digitalWrite(BUTTON1_PIN, INPUT_PULLUP);
#endif

  // OLED Display
  u8g2.begin(/* menu_select_pin= */ 5, /* menu_next_pin= */ 0, /* menu_prev_pin= */ 0, /* menu_home_pin= */ 0);

  setNeedsDisplay = true;

  Timer1.initialize(TIMER);
  Timer1.attachInterrupt(timerEvent);

=======================================

 fadeTo = dimValue = 0;

  update_light();
}

// ========================================================
// LOOP
// ========================================================

void loop() {
  // put your main code here, to run repeatedly:

  digitalWrite(STATUS_LED_PIN, statusLedOn);

  if (menuAnimationRunning) {
    if (menuPageMode &amp;&amp; menuPosY &lt; MENU_POS_Y_HIDDEN) {
      // do animation
      menuPosY = menuPosY + MENU_ANIMATION_PIXEL_STEP;
      setNeedsDisplay = true;
    }
    if (!menuPageMode &amp;&amp; menuPosY &gt; MENU_POS_Y) {
      // do animation
      menuPosY = menuPosY - MENU_ANIMATION_PIXEL_STEP;
      setNeedsDisplay = true;
    }
  }
  if (menuAnimationRunning &amp;&amp; (menuPosY == MENU_POS_Y || menuPosY == MENU_POS_Y_HIDDEN)) {
    // looks like animation is done
    menuAnimationRunning = false;
  }

  if (setNeedsDisplay) {
   
    displayRenderCurrentPage();
    setNeedsDisplay = false;
  }
  
checkRotaryEncoder();

 {
  //In MySensors2.x, first message must come from within loop()
  static bool first_message_sent = false;
  if ( first_message_sent == false ) {
    Serial.println( "Sending initial state..." );
    send_dimmer_message();
    send_status_message();
    first_message_sent = true;
  }
}
}
// ========================================================
// TIMER
// ========================================================

void timerEvent() {
  // Heartbeat
  if (heartbeat &gt; HEARTBEAT_TRIGGER) {
    statusLedOn = true;
  }
  if (heartbeat &gt; HEARTBEAT_TRIGGER + HEARTBEAT_TRIGGER_TIME) {
    statusLedOn = false;
    heartbeat = 0;
  }
  heartbeat++;

  // Menu logic
  unsigned long timeOffset = millis() - rotaryLastMove;
  if (timeOffset &gt; MENU_SELECTED_TIMEOUT) {
    // deselect menu
    menuSelected = menuActive;
    rotaryLastMove = millis();
    setNeedsDisplay = true;
  }
  
  // Rotary Encoder
  unsigned char result = rotary.process();
  if (result) {

    if (!menuPageMode) {
      if (result == DIR_CW) {
        // right
        if (menuSelected &lt; 3) {
          menuSelected++;
        }
      } else {
        // left
        if (menuSelected &gt; 1) {
          menuSelected--;
        }
      }
      setNeedsDisplay = true;
    } else {

      // Acceleration
      byte acceleration = 1;
      unsigned long timeOffset = millis() - rotaryLastMove;
      
      //Serial.println(timeOffset);

      if (displayCurrentPage == 0 || displayCurrentPage == 1) {
        if (timeOffset &lt; ROTARY_ACCEL_OFFSET1) {
          acceleration = 16;
        } else if (timeOffset &lt; ROTARY_ACCEL_OFFSET2) {
          acceleration = 4;
        } else if (timeOffset &lt; ROTARY_ACCEL_OFFSET3) {
          acceleration = 2;
        }
      
        // Development test =&gt; control slider
        if (result == DIR_CW) {
          // right
          if (sliderPosX &lt; 128) {
            sliderPosX = sliderPosX + acceleration;
          }
        } else {
          // left
          if (sliderPosX &gt; 0) {
            sliderPosX = sliderPosX - acceleration;
          }
        }
        setNeedsDisplay = true;
      }

      if (displayCurrentPage == 2) {
        if (result == DIR_CW) {
          // right
          setupMenuSelected++;
        } else {
          // left
          setupMenuSelected--;
        }
        if (setupMenuSelected &gt; SETUP_MENU_ITEMS - 1) {
          setupMenuSelected = SETUP_MENU_ITEMS - 1;
        }
        if (setupMenuSelected &lt; 1) {
          setupMenuSelected = 0;
        }
        setNeedsDisplay = true;
      }

    }

    rotaryLastMove = millis();
    
  }

  // Rotary button
  if (buttonEvent()) {
    rotaryLastMove = millis();
    if (menuActive == menuSelected) {
      if (!menuPageMode) {
        // give controls to page (button press on selected page)
        menuPageMode = true;
        menuAnimationRunning = true;
        
        sliderPosX = 64;
        
        setNeedsDisplay = true;
        
        #ifdef DEBUG
        Serial.println("PAGE MODE ON");
        #endif
      } else {
        menuPageMode = false;   
        menuAnimationRunning = true;
        setNeedsDisplay = true;
        sliderPosX = 64;

        setupMenuSelected = 0;
        
        #ifdef DEBUG
        Serial.println("PAGE MODE OFF"); 
        #endif
      }
    }
    if (!menuPageMode) {
      menuActive = menuSelected;
      if (menuActive == 1) {
        displayCurrentPage = 0;
      }
      if (menuActive == 2) {
        displayCurrentPage = 1;
      }
      if (menuActive == 3) {
        displayCurrentPage = 2;
      }
      setNeedsDisplay = true;
    }
  }

  // Action button =&gt; reset page mode during development
#ifdef BUTTON1_PIN
  if (digitalRead(BUTTON1_PIN) == 0 &amp;&amp; menuPageMode) {
    menuPageMode = false;   
    menuAnimationRunning = true;
    setNeedsDisplay = true;
   // sliderPosX = 64;
    #ifdef DEBUG
    Serial.println("PAGE MODE OFF"); 
    #endif
  }
#endif
  
}

// ========================================================
// MENU BUTTON
// ========================================================

bool buttonEvent() {
  bool result = false;
  bool menuButton = false;
  if (digitalRead(ROTARY_SWITCH) == 1) {
    menuButton = true;
  }
  if (menuButton &amp;&amp; !rotaryButtonPressed) {
    rotaryButtonPressed = true;
  } else if (!menuButton &amp;&amp; rotaryButtonPressed) {
    rotaryButtonPressed = false;
    result = true;
    // FIXME: debounce for try, check if it's really needed
    //delay(4);
  }
  return result;
}

// ========================================================
// DISPLAY - Screen Drawing
// ========================================================

void displayRenderCurrentPage() {
  // OLED Display update
  u8g2.firstPage();
  do {

    if (displayCurrentPage == 0) {
      u8g2.setFont(u8g2_font_8x13B_tr);
      u8g2.drawStr(0, 12, "Main Page");
    }

    if (displayCurrentPage == 1) {
      u8g2.setFont(u8g2_font_8x13B_tr);
      u8g2.drawStr(0, 12, "Network Page");
    }

    if (displayCurrentPage == 2) {
      if (!menuPageMode) {
        u8g2.setFont(u8g2_font_8x13B_tr);
        u8g2.drawStr(0, 10, "Setup Page");
        u8g2.setFont(u8g2_font_5x7_tr);
        u8g2.drawStr(0, 28, "PRESS BUTTON FOR SUBMENU");
      } else {
        drawPageMenu();

        if (setupMenuSelected == 0) {
          u8g2.setFont(u8g2_font_5x7_tr);
          u8g2.drawStr(0, 28, "DEMO MODE");
          u8g2.drawStr(0, 38, "PRESS BUTTON TO EXIT");
        }

        if (setupMenuSelected == 7) {
          // Version &amp; Info
          u8g2.setFont(u8g2_font_5x7_tr);
          u8g2.setCursor(0, 28);
          u8g2.print(VERSION_TITLE);
          u8g2.print(" ");
          u8g2.print(VERSION);

          u8g2.setCursor(0, 38);
          u8g2.print(VERSION_SUBTITLE);

          u8g2.setCursor(0, 56);
          u8g2.print("HW: ");
          u8g2.print(VERSION_HW);
          

        }
      }
    }

    if (displayCurrentPage == 0 || displayCurrentPage == 1) {
      u8g2.setFont(u8g2_font_5x7_tr);
      if (menuPageMode) { 
        u8g2.drawStr(0, 28, "ROTARY CONTROL ON PAGE");
        u8g2.setCursor(0, 46);
        u8g2.print("VALUE ");
        u8g2.print(sliderPosX);
      } else {
        u8g2.drawStr(0, 28, "ROTARY CONTROL ON MENU");
      }
      drawSlider(31);
    }

    drawMenuBar();
    
  } while ( u8g2.nextPage() );
}

void drawPageMenu() {
  u8g2.setFont(u8g2_font_6x12_tr);
  if (displayCurrentPage == 2) {
    String text = setupMenuItems[setupMenuSelected];
    // center text
    int textWidth = u8g2.getStrWidth(text.c_str());
    int textX = (128 - textWidth) / 2;
    int textXPadding = 4;
    u8g2.drawRBox(textX - textXPadding, 0, textWidth + textXPadding + textXPadding, 11, 2);
    u8g2.setDrawColor(0);
    u8g2.setCursor(textX, 11 - 2);
    u8g2.print(text);
    u8g2.setDrawColor(1);

    bool drawLeftTriangle = false;
    bool drawRightTriangle = false;

    if (setupMenuSelected &lt; SETUP_MENU_ITEMS - 1) {
      drawRightTriangle = true;
    }
    if (setupMenuSelected &gt; 0) {
      drawLeftTriangle = true;
    }

    if (drawLeftTriangle) {
      // Triangle left
      u8g2.drawTriangle(4, 1, 4, 9, 0, 5);
    }
    if (drawRightTriangle) {
      // Triangle right
      u8g2.drawTriangle(128 - 5, 1, 128 - 5, 9, 127, 5);
    }
    u8g2.drawHLine(0, 14, 128);
  }
  
}

void drawSlider(int yPos) {
  u8g2.drawFrame(0, yPos, 100, 6);
  if (sliderPosX &lt; 1) {
    sliderPosX = 0;
  }
  if (sliderPosX &gt; 100) {
    sliderPosX = 100;
  }
  u8g2.drawVLine(sliderPosX, yPos, 6);
}

void drawMenuBar() {
  int textX = 0;
  int textY = menuPosY;
  int textWidth = 0;
  int textXPadding = 4;
  
  u8g2.setFont(u8g2_font_6x12_tr);
  u8g2.setDrawColor(1);

  u8g2.drawHLine(0, textY - 11 - 2, 128);

  if (textY &lt; MENU_POS_Y_HIDDEN) {
    // center menu
    String text = menuItems[1];
    textWidth = u8g2.getStrWidth(text.c_str());
    textX = (128 - textWidth) / 2;
    if (menuActive == 2) {
      u8g2.drawRBox(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(0);
    } 
    if (menuActive != menuSelected &amp;&amp; menuSelected == 2) {
      u8g2.drawRFrame(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(1);
    }
  
    u8g2.setCursor(textX, textY);
    u8g2.print(text);
    u8g2.setDrawColor(1);
  
    // left menu
    text = menuItems[0];
    textX = textXPadding;
    textWidth = u8g2.getStrWidth(text.c_str());
    if (menuActive == 1) {
      u8g2.drawRBox(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(0);
    } 
    if (menuActive != menuSelected &amp;&amp; menuSelected == 1) {
      u8g2.drawRFrame(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(1);
    }
    u8g2.setCursor(textX, textY);
    u8g2.print(text);
    u8g2.setDrawColor(1);
  
    // right menu
    text = menuItems[2];
    textWidth = u8g2.getStrWidth(text.c_str());
    textX = 128 - textWidth - textXPadding;
    if (menuActive == 3) {
      u8g2.drawRBox(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(0);
    }
    if (menuActive != menuSelected &amp;&amp; menuSelected == 3) {
      u8g2.drawRFrame(textX - textXPadding, textY + 2 - 11, textWidth + textXPadding + textXPadding, 11, 2);
      u8g2.setDrawColor(1);
    }
    u8g2.setCursor(textX, textY);
    u8g2.print(text);
    u8g2.setDrawColor(1);
  }
  
}

void presentation() {
  sendSketchInfo(SN, SV);
  // led
  present(1, S_DIMMER, 1);
     // rotary
    present( 8, S_DIMMER, 1 );

    
}

void receive(const MyMessage &amp;message)

{
  //When receiving a V_STATUS command, switch the light between OFF
  //and the last received dimmer value  
  
 if (message.sensor == 1){
    if (message.type == V_STATUS) 
  {
    Serial.println( "V_STATUS command received..." );

    int lstate = message.getInt();
    if (( lstate &lt; 0 ) || ( lstate &gt; 1 )) {
      Serial.println( "V_STATUS data invalid (should be 0/1)" );
      return;
    }
    last_state = lstate;

    //If last dimmer state is zero, set dimmer to 100
    if (( last_state == LIGHT_ON ) &amp;&amp; ( last_dim == 0 )) {
      last_dim=10;
    }

    //Update constroller status
    send_status_message();

  } else if (message.type == V_PERCENTAGE)
  {
    Serial.println( "V_PERCENTAGE command received..." );
    int dim_value = constrain( message.getInt(), 0, 100 );
    if ( dim_value == 0 ) {
      last_state = LIGHT_OFF;

      //Update constroller with dimmer value &amp; status
      send_dimmer_message();
      send_status_message();      
    } else {
      last_state = LIGHT_ON;
      last_dim = dim_value;

      //Update constroller with dimmer value
      send_dimmer_message();
    }

  } else {
    Serial.println( "Invalid command received..." );
    return;
  }

  //Here you set the actual light state/level
  update_light();
}
}   


void update_light()
{
  //For this example, just print the light status to console.
  if ( last_state == LIGHT_OFF ) {
    Serial.println( "Light state: OFF" );
  } else {
    Serial.print( "Light state: ON, Level: " );
    Serial.println( last_dim );
   analogWrite( LED_PIN, (last_dim) );
  }
}

void send_dimmer_message()
{
  send( dimmer_msg.set( last_dim ) );
}

void send_status_message()
{
  if ( last_state == LIGHT_OFF ) {
    send( light_msg.set( (int16_t)0) );
  } else {
    send( light_msg.set( (int16_t)1) );
  }
}

void checkRotaryEncoder() {

  if (sliderPosX &gt; 100) {
    sliderPosX = 100;
  } else if (sliderPosX &lt; 0) {
    sliderPosX = 0;
  }
  if (sliderPosX != dupa) { 
    dupa = sliderPosX;
    changedByKnob = true;
  send_dimmer_message_rottary();
  }
}


void send_dimmer_message_rottary()
{
 send(dimmerinp.set(dupa),1);
}```</code></pre>
]]></description><link>https://forum.mysensors.org/topic/9581/dimmer-problem-value-changes-by-the-sensor</link><generator>RSS for Node</generator><lastBuildDate>Mon, 09 Mar 2026 08:40:27 GMT</lastBuildDate><atom:link href="https://forum.mysensors.org/topic/9581.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 08 Aug 2018 16:32:29 GMT</pubDate><ttl>60</ttl></channel></rss>