Need help displaying data to IoT cloud percentage widget

Hi everyone, I'm working on my project to build a water monitoring with hc-sr04 sensor and esp8266 as microcontroller. Everything is working fine with my code for giving the water level measurement, buzzer as warning sound and i created code to calculate percent value of the water level measurement which results are displayed on the 16x2 LCD, but i'm still confused n can't find a way to make code for showing my realtime data to the percentage widget on iot cloud because the sensor value on percentage widget stays zero/"--". Can anyone help me to figure out how to complete this code? or give me an insight so i can finish my project,
thx

image

#include <ESP8266WiFi.h>
#include <NewPing.h>
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
#include "thingProperties.h"

#define triggerPin    D6                          // Pin D6 NodeMCU sebagai OUTPUT ke Trig Pin HC-SR04
#define echoPin       D7                          // Pin D7 NodeMCU sebagai INPUT dari Echo Pin HC-SR04
#define MAX_DISTANCE  36                          // Maksimal jarak yang diukur berdasarkan ketinggian bak
#define MIN_DISTANCE  5
#define BUZZER        D5                          // Pin D3 BUZZER sebagai OUTPUT



hd44780_I2Cexp lcd;
long currentMillis, lastMillis;                   // Gunakan non blocking delay, millis()
const long interval = 1000;                       // Interval untuk menampilkan hasil pengukuran setiap 1000ms / 1 detik
NewPing sonar (triggerPin, echoPin, MAX_DISTANCE);// NewPing konstruk sonar
int percentage;


void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.backlight();
  pinMode(D5, OUTPUT);
  digitalWrite(D5, HIGH);
  initProperties();
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
}

double getDistance() {
  int distance = sonar.ping_cm();
  return distance;
}


void loop() {
  ArduinoCloud.update();
  currentMillis = millis();
  int distance = sonar.ping_cm();
  if (distance <= 0) {
    Serial.println("Out of range");
  }
}

void onDistanceSensorChange() {
  int distance = sonar.ping_cm();
  float percentage = 100 - ((100 / 36) * (distance - 5));      // mendapatkan nilai persen dari jarak hasil pengukuran sensor
  if (distance <= 0) {
    percentage = 0;
  } else if (distance > 36) {
    percentage = 0;
  }

  if (currentMillis - lastMillis >= interval) {     // tampilkan hasil pengukuran pada serial monitor setiap 1 detik
    Serial.print("Jarak : ");
    Serial.print(getDistance(), 1);                 // menampilkan 1 angka desimal
    Serial.println("cm");
    lastMillis = currentMillis;
  }
  
  Serial.print(getDistance());
  Serial.println(percentage);
  lcd.setCursor(0, 0);
  lcd.print("JUMLAH AIR BAK 1");
  lcd.setCursor(0, 1);
  lcd.print(percentage);
  lcd.print("%  ");
  delay(1000);
  
  if (percentage < 40) {        // Jika air pada bak kurang dari 40% maka buzzer akan menyala
    digitalWrite(D5, LOW);
    delay(50);
    digitalWrite(D5, HIGH);
    delay(50);
  } else if (percentage > 100){     // Jika air pada bak lebih dari 100% maka buzzer akan mati
    digitalWrite(D5, LOW);
    delay(50);
    digitalWrite(D5, HIGH);
    delay(50);
  }

}

Please post this file also: thingProperties.h

I can see a error which will cause your percentage reading to be inaccurate, although it does not explain why the widget does not update.

float percentage = 100 - ((100 / 36) * (distance - 5));      // mendapatkan nilai persen dari jarak hasil pengukuran sensor

This part of the calculation

(100 / 36)

will give the result 2, not the 2.77 you might be expecting.

Try

(100.0 / 36)

oh wow this adds my knowledge about the formula.

also the file thingproperties.h

// Code generated by Arduino IoT Cloud, DO NOT EDIT.

#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>

const char DEVICE_LOGIN_NAME[]  = "73e1f0aa-d55a-4f1d-a47f-eb5d056c94c2";

const char SSID[]               = SECRET_SSID;    // Network SSID (name)
const char PASS[]               = SECRET_OPTIONAL_PASS;    // Network password (use for WPA, or use as key for WEP)
const char DEVICE_KEY[]  = SECRET_DEVICE_KEY;    // Secret device password

void onDistanceSensorChange();

int distanceSensor;

void initProperties(){

  ArduinoCloud.setBoardId(DEVICE_LOGIN_NAME);
  ArduinoCloud.setSecretDeviceKey(DEVICE_KEY);
  ArduinoCloud.addProperty(distanceSensor, READWRITE, 1 * SECONDS, onDistanceSensorChange);

}

WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);

Thanks for that. Unfortunately I'm not sure I can help you, because I don't understand myself what is going on!

I would expect that onDistanceSensorChange() function would get called only when the variable distanceSensor changes. This variable is never changed by your code, so I would expect that onDistanceSensorChange() would never be called.

However, you said that the LCD display is getting updated. The only place in your code where the LCD is updated is in the function onDistanceSensorChange(), so that must be getting called somehow. That's what I don't understand.

But I have a theory.

In this line

ArduinoCloud.addProperty(distanceSensor, READWRITE, 1 * SECONDS, onDistanceSensorChange);

a parameter is given which is 1 second. So maybe onDistanceSensorChange() gets called every second even if the value of distanceSensor has not changed.

What I suggest is to add this line at the end of onDistanceSensorChange() (meaning just before the final } of the function):

  distanceSensor = percentage;
1 Like

hmm okey i'll try it soon :smile:

i've tried adding the program with

and this show the value in the widget and the measurement once
Screenshot 2023-06-11 120811


Screenshot 2023-06-11 121251

again i tried delete the code of distanceSensor = percentage; and make the measurement to 24cm
and the result changes once on value widget and the measurement as well


Screenshot 2023-06-11 122520
Screenshot 2023-06-11 122608

This leads me to the conclusion that the data/value on the widget will only change if there is a code change, while if there is a change in the measurement distance does not affect data changes.
And yeah this makes me even more confused :face_with_spiral_eyes:

Your explanation has confused me also!

But I think my theory is correct, the widget will only update when your code changes the value of distanceSensor. This is the variable which the ArduinoIoTCloud.h or Arduino_ConnectionHandler.h library is monitoring. It will not monitor other variables in your code and will not react in any way when their values change.

hahaha sorry my explanation so confusing :smiley:

yap more like that

anyways, do you have some similar references on this issue?

No, I don't. There must be some documentation about the Arduino IoT cloud on the Arduino website somewhere, but I have not read it or used Arduino IoT cloud before.

@akbarafiq the onDistanceSensorChange callback is only called when you manually change the value from the dashboard or suring the connection phase of the board due to the sync event.

What i suggest you is to assign the value of the distanceSensor property inside you loop() function:

void loop() {
  ArduinoCloud.update();
  currentMillis = millis();
  distanceSensor = sonar.ping_cm();
  if (distanceSensor <= 0) {
    Serial.println("Out of range");
  }
}

I've tried changing the formula a few days ago as your suggested, either because I'm stupid and a beginner like there's no difference and I haven't found the right formula
can you specifically show me the exact formula or fix the formula in loop() based on the code above as you suggested?

@akbarafiq have you managed to solve this issue? If no please share the full sketch and i will take a look.

#include <Wire.h>
#include "thingProperties.h"
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
#define triggerPin  D6
#define echoPin     D7
#define buzer     D5


long duration, jarak;
int tinggi_wadah = 36;
int flag = 0;
hd44780_I2Cexp lcd;

void buz() {
  for (int i = 0; i <= 1; i++){
    digitalWrite(buzer, LOW);
    delay(100);
    digitalWrite(buzer, HIGH);
    delay(100);
  }
}

void waterFullMessage(){
  lcd.setCursor(0, 1);
  lcd.print("AIR PENUH");
}

void waterDropMessage() {
  lcd.setCursor(0, 1);
  lcd.print("AIR HABIS");
}

void clear_lcd(){
  lcd.setCursor(0, 1);
  lcd.print("         ");
}

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);
  lcd.begin(16, 2);
  lcd.backlight();
  pinMode(triggerPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(buzer, OUTPUT);
  initProperties();
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);   // Connect to Arduino IoT Cloud
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
  buz();
  flag = 0;
}

void loop() {
  ArduinoCloud.update();

  digitalWrite(triggerPin, LOW);
  delayMicroseconds(2);
  digitalWrite(triggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  jarak = (duration / 2) / 29.1;
  tinggi = tinggi_wadah - jarak;
  tinggi = map(tinggi, 0, 36, 0, 110);
  Serial.println("Jarak :");
  Serial.print(tinggi);
  Serial.println(" cm");
  lcd.setCursor(0, 0); 
  lcd.print(String() + "Tinggi:" + tinggi + " %" + "  ");
  
  if (tinggi <= 30) {
    waterDropMessage();
    buz();
  }
  else if (tinggi >= 90 && flag == 0) {
    waterFullMessage();
    digitalWrite(D5, LOW);
    delay(100);
    digitalWrite(D5, HIGH);
    delay(100);
  }
  else if (tinggi <= 89) {
    clear_lcd();
    flag = 0;
  }
  else {
    digitalWrite(buzer, HIGH);
  }
  delay(500);
}

void onTinggiChange()  {
}

@pennam i've tried to assign the value inside the loop() then i changed the distance formula sonar.ping_cm with pulseIn and then i'm using map(). but actually I still want to use sonar.ping_cm instead of pulseIn but I don't know how to put it in the loop()

all of the code work for me, but i think there's some of lack in my code especially how to clear the lcd after send a waterdrop and waterfull message

btw thank you for the feedback

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.