OnChange-Method not called when variable changes on sensor-value

Hi folks and happy new year!

I got a new thing in IoT-Cloud working fine (3 bools, 3 switches in dashboard, 3 relays on MKR1000 are switching - all good).

But: reading distances from an ultrasonic-sensor and changing the variables depending on the distance like:

      //Schaltung der Relais
      if (wasserstand>0 && wasserstand < 20){
        pumpe1=false;
        pumpe2=false;
        pumpe3=false;
        alarm=false;
      };
      if (wasserstand>20 && wasserstand < 30){
        pumpe1=true;
        pumpe2=false;
        pumpe3=false;
        alarm=false;
      };
        if (wasserstand>30 && wasserstand < 40){
        pumpe1=true;
        pumpe2=true;
        pumpe3=false;
        alarm=false;
      };
  if (wasserstand>40 && wasserstand < 50){
        pumpe1=true;
        pumpe2=true;
        pumpe3=true;
        alarm=false;
      };
        if (wasserstand>50){
        pumpe1=true;
        pumpe2=true;
        pumpe3=true;
        alarm=true;
      };

just changes the variables (I see them changing in the dashboard) but the are not switching the relays any more. Sees like the OnChange-methods are not called by changing the variables programatically.

Any hints?

Whole code:

/* 
  Sketch generated by the Arduino IoT Cloud Thing "Wasserstandsensor Pumpensumpf"
  https://create.arduino.cc/cloud/things/b31282ed-a60e-45eb-be81-d1f37af85b22 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  float wasserstand;
  bool alarm;
  bool pumpe1;
  bool pumpe2;
  bool pumpe3;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
#include <HCSR04.h>

// LCD_I2C - Version: Latest 
#include <LCD_I2C.h>


LCD_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

UltraSonicDistanceSensor distanceSensor(4, 5);  // Initialize sensor that uses digital pins 13 and 12.

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change:
const long interval = 100;           // interval at which to measure distance (milliseconds)
float value = 0;
float factor = 0.01; // new measurements are only 1% of new value - 99% are build of the old value (flatten the peaks!)
float measurement=0;

//Thingspeak
const int myChannelNumber = 1006624;        // Thingspeak-Channel
const char *myWriteAPIKey = SECRET_WRITEAPIKEY ; // Thingspeak WriteAPI



void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 
  
    //Relaispins
    pinMode(A1, OUTPUT);
    pinMode(A2, OUTPUT);
    pinMode(A3, OUTPUT);
    pinMode(A4, OUTPUT);
    digitalWrite(A1, HIGH);
    digitalWrite(A2, HIGH);
    digitalWrite(A3, HIGH);
    digitalWrite(A4, HIGH);
    
     lcd.begin();   
     
       // Turn on the backlight
  lcd.backlight();
    
  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
}

void loop() {
  ArduinoCloud.update();
  // Your code here 
  
    // Every 100 miliseconds, do a measurement using the sensor and print the distance in centimeters.
    
    unsigned long currentMillis = millis();
      
    if (currentMillis - previousMillis >= interval) {
    // save the last time you measured distance
    
      previousMillis = currentMillis;
      measurement = distanceSensor.measureDistanceCm();
      value = value* (1-factor) + measurement * factor;
      
      Serial.print(value,1);
      Serial.println(" cm");
      wasserstand=float(int(value*10))/10;
      
      //LCD-Ausgabe
      lcd.clear();
      lcd.print("Wasserstand:");
      lcd.setCursor(5, 1);
      lcd.print(wasserstand);
      lcd.print(" cm");
      
      //Schaltung der Relais
      if (wasserstand>0 && wasserstand < 20){
        pumpe1=false;
        pumpe2=false;
        pumpe3=false;
        alarm=false;
      };
      if (wasserstand>20 && wasserstand < 30){
        pumpe1=true;
        pumpe2=false;
        pumpe3=false;
        alarm=false;
      };
        if (wasserstand>30 && wasserstand < 40){
        pumpe1=true;
        pumpe2=true;
        pumpe3=false;
        alarm=false;
      };
  if (wasserstand>40 && wasserstand < 50){
        pumpe1=true;
        pumpe2=true;
        pumpe3=true;
        alarm=false;
      };
        if (wasserstand>50){
        pumpe1=true;
        pumpe2=true;
        pumpe3=true;
        alarm=true;
      };
    };
  
  
}


/*
  Since Pumpe1 is READ_WRITE variable, onPumpe1Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onPumpe1Change()  {
  // Add your code here to act upon Pumpe1 change
  if (pumpe1){digitalWrite(A1, LOW);}else{digitalWrite(A1,HIGH);}
}


/*
  Since Pumpe2 is READ_WRITE variable, onPumpe2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onPumpe2Change()  {
  // Add your code here to act upon Pumpe2 change
   if (pumpe2){digitalWrite(A2, LOW);}else{digitalWrite(A2,HIGH);}
}

/*
  Since Pumpe3 is READ_WRITE variable, onPumpe3Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onPumpe3Change()  {
  // Add your code here to act upon Pumpe3 change
   if (pumpe3){digitalWrite(A3, LOW);}else{digitalWrite(A3,HIGH);}
}

/*
  Since Alarm is READ_WRITE variable, onAlarmChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onAlarmChange()  {
  // Add your code here to act upon Alarm change
   if (alarm){digitalWrite(A4, LOW);}else{digitalWrite(A4,HIGH);}
}
  // Defined in thingProperties.h
  initProperties();

Did you add anything to this .h file for your project? Otherwise I can't see how the code you posted can result in onPumpe1Change()...onPumpe3Change() being called.

No I did not, I thought, that the onChange-Method will be automatically called when the variable changes. You say I have to call it manually?

Since Pumpe1 is READ_WRITE variable, onPumpe1Change() is
executed every time a new value is received from IoT Cloud.

My code changes the values in IoT-Cloud, this I can see in the dashboard, so I thought the new value should trigger that method???

I never used Arduino IoT cloud and know nothing about it, so maybe I am missing something here. But I know C/C++ quite well.

I cannot see how your onPumpe1Change() can ever be called. You do not explicitly call it in your code. You do not pass the function as a parameter to another library to use as a "callback" so that the library can call it for you.

I cannot see where your variables like pumpe1 are declared. I was hoping you had done that in the .h file, and that maybe the onPumpe1Change() is referenced there also so that when ArduinoCloud.update() is called, it could detect that variables like pumpe1 have changed and call the function.

Perhaps you should post the .h file. Maybe it is automatically generated for you based on some parameters you set in some App or web page at some point?

manually calling the onChangeMethod solved my problem.

Helle Eifler, could you please share your final code ? I think I have the same issue.