c++arduinoesp32arduino-idearduino-esp32

How to add a water level sensor device through using ESP Rainmaker at Arduino IDE?


I would like to ask on how you do specifically add a water level device using ESP Rainmaker?

Because it seems that whenever I try to create one, there's always these PARAM errors.

This is how I declared the water level sensor device:

 static Device water_level_sensor("Water Level Sensor");

Then this is how I add a water level parameter:

static Param water_level_param("Water Level", "percentage", RMAKER_VAL_TYPE_INTEGER, 0);

This is how I would send the sensor result to the ESP Rainmaker:

water_level_param.updateAndReport((param_val_t)water_level_percentage); 

In this line is where the error usually occurs:

 static Param water_level_param("Water Level", "percentage", RMAKER_VAL_TYPE_INTEGER, 0); 

The error states that:

error: no matching function for call to 'Param::Param(const char [12], const char [11], esp_rmaker_val_type_t, int)'
 static Param water_level_param("Water Level", "percentage", RMAKER_VAL_TYPE_INTEGER, 0); 

My goal is to display the water level sensor result, along with the temperature and humidity at the ESP Rainmaker App, but it seems that it's not possible at the moment due to these param errors.

This is my full source code (wherein it captures the temperature and humidity (from DHT11) and water level results (from the water level sensor) and passes it to the ESP Rainmaker App):

#include "RMaker.h"
#include <RMakerParam.h>
#include <RMakerDevice.h>
#include <RMakerNode.h>
#include <WiFi.h>
#include <WiFiProv.h>
#include <DHT.h>
#include <SimpleTimer.h>
#include <wifi_provisioning/manager.h>

// Set Default Values
#define DEFAULT_Temperature 0
#define DEFAULT_Humidity 0

// BLE Credentials
const char *service_name = "myservice";
const char *pop = "mypass";

// GPIO
static uint8_t gpio_reset = 0;
static uint8_t DHTPIN = 23;

bool wifi_connected = false;

DHT dht(DHTPIN, DHT11);

SimpleTimer Timer;

// Declaring Devices
static TemperatureSensor temperature("Temperature");
static TemperatureSensor humidity("Humidity");
static Device water_level_sensor("Water Level Sensor");

void sysProvEvent(arduino_event_t *sys_event) {
    switch (sys_event->event_id) {
        case ARDUINO_EVENT_PROV_START:
#if CONFIG_IDF_TARGET_ESP32
            Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
            printQR(service_name, pop, "ble");
#else
            Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
            printQR(service_name, pop, "softap");
#endif
            break;
        case ARDUINO_EVENT_WIFI_STA_CONNECTED:
            Serial.printf("\nConnected to Wi-Fi!\n");
            wifi_connected = true;
            delay(500);
            break;
        case ARDUINO_EVENT_PROV_CRED_RECV: {
            Serial.println("\nReceived Wi-Fi credentials");
            Serial.print("\tSSID : ");
            Serial.println((const char *)sys_event->event_info.prov_cred_recv.ssid);
            Serial.print("\tPassword : ");
            Serial.println((char const *)sys_event->event_info.prov_cred_recv.password);
            break;
        }
        case ARDUINO_EVENT_PROV_INIT:
            wifi_prov_mgr_disable_auto_stop(10000);
            break;
        case ARDUINO_EVENT_PROV_CRED_SUCCESS:
            Serial.println("Stopping Provisioning!!!");
            wifi_prov_mgr_stop_provisioning();
            break;
    }
}

void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx) {
    const char *device_name = device->getDeviceName();
    Serial.println(device_name);
    const char *param_name = param->getParamName();
}

void setup() {
    Serial.begin(115200);

    // Configure the input GPIOs
    pinMode(gpio_reset, INPUT);

    // Beginning Sensor
    dht.begin();

    // Declaring Node
    Node my_node = RMaker.initNode("ESP32 Project 2");

    // Adding Devices in Node
    my_node.addDevice(temperature);
    my_node.addDevice(humidity);
    my_node.addDevice(water_level_sensor);

    // Enable OTA
    RMaker.enableOTA(OTA_USING_PARAMS);

    // Enable timezone service
    RMaker.enableTZService();

    // Enable scheduling
    RMaker.enableSchedule();

    Serial.printf("\nStarting ESP-RainMaker\n");
    RMaker.start();

    // Timer for Sending Sensor's Data
    Timer.setInterval(3000);

    WiFi.onEvent(sysProvEvent);

#if CONFIG_IDF_TARGET_ESP32
    WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#else
    WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
#endif

    // Add water level parameter
    static Param water_level_param("Water Level", "percentage", RMAKER_VAL_TYPE_INTEGER, 0);
    water_level_sensor.addParam(water_level_param);
}

void loop() {
    if (Timer.isReady() && wifi_connected) {
        // Check if the timer is ready
        Serial.println("Sending Sensor's Data");
        Send_Sensor();
        Timer.reset(); // Reset the timer
    }

    // Logic to Reset RainMaker
    if (digitalRead(gpio_reset) == LOW) {
        // Push button pressed
        Serial.printf("Reset Button Pressed!\n");
        // Key debounce handling
        delay(100);
        int startTime = millis();
        while (digitalRead(gpio_reset) == LOW)
            delay(50);
        int endTime = millis();

        if ((endTime - startTime) > 10000) {
            // If key pressed for more than 10secs, reset all
            Serial.printf("Reset to factory.\n");
            wifi_connected = false;
            RMakerFactoryReset(2);
        } else if ((endTime - startTime) > 3000) {
            Serial.printf("Reset Wi-Fi.\n");
            wifi_connected = false;
            // If key pressed for more than 3secs, but less than 10, reset Wi-Fi
            RMakerWiFiReset(2);
        }
    }
    delay(100);
}

void Send_Sensor() {
    // Read temperature, humidity, and water level
    float h = dht.readHumidity();
    float t = dht.readTemperature();
    int water_level_reading = readWaterLevel();

    // Check if the readings are valid
    if (isnan(h) || isnan(t) || water_level_reading == -1) {
        Serial.println("Failed to read from sensors");
        return;
    }

    // Print sensor readings
    Serial.print("Temperature - ");
    Serial.println(t);
    Serial.print("Humidity - ");
    Serial.println(h);
    Serial.print("Water Level - ");
    Serial.println(water_level_reading);

    // Update and report temperature parameter
    temperature.updateAndReportParam("Temperature", t);

    // Update and report humidity parameter
    humidity.updateAndReportParam("Humidity", h);

    // Update and report water level parameter
    float water_level_percentage = map(water_level_reading, 0, 4095, 0, 100);
    water_level_percentage = constrain(water_level_percentage, 0, 100);
    water_level_param.updateAndReport((param_val_t)water_level_percentage);
}

int readWaterLevel() {
    const int POWER_PIN = 17; // GPIO pin connected to power pin of water level sensor
    const int SIGNAL_PIN = 36; // GPIO pin connected to signal pin of water level sensor

    int value = -1;

    // Power on the sensor
    pinMode(POWER_PIN, OUTPUT);
    digitalWrite(POWER_PIN, HIGH);
    delay(10);

    // Read the analog value from the sensor
    pinMode(SIGNAL_PIN, INPUT);
    value = analogRead(SIGNAL_PIN);

    // Power off the sensor
    digitalWrite(POWER_PIN, LOW);

    return value;
}

I run this source code using Arduino IDE.

These are all the supported device types for Rainmaker. It clearly shows that water level sensor is not there: Devices source: https://rainmaker.espressif.com/docs/standard-types.html

It probably seems that there's still an issue with the Param constructor parameters. The error indicates that there is no matching function for the given parameters.

This calls out that the parameters were incorrect, thus I am really not sure on what is the correct signature for the parameters, especially for a water level sensor, which is not even at the supported devices, thus, I am trying to transform the water level sensor as a "custom device" in order for it to display its values at the ESP Rainmaker App.

Your responses and feedbacks would definitely help me a lot in this project that I am currently working on. Thank you very much!


Solution

  • As you can see in Param constructor calls:

    Param(const char *param_name, const char *param_type, param_val_t val, uint8_t properties)
    {
        param_handle = esp_rmaker_param_create(param_name, param_type, val, properties);
    }
    

    Which calls:

    esp_rmaker_param_t *esp_rmaker_param_create(const char *param_name, const char *type,
            esp_rmaker_param_val_t val, uint8_t properties)
    {...
    

    Where esp_rmaker_param_val_t is a struct:

    /** ESP RainMaker Parameter Value */
    typedef struct {
        /** Type of Value */
        esp_rmaker_val_type_t type;
        /** Actual value. Depends on the type */
        esp_rmaker_val_t val;
    } esp_rmaker_param_val_t;
    

    So you not only need the type RMAKER_VAL_TYPE_INTEGER but the value too at the third parameter of to create the right struct:

    static Param water_level_param(...);
    

    If you want to look at the code yourself: https://github.com/espressif/arduino-esp32/tree/2479efb10d2709246a41562b8a626c7ed14ee164/libraries/RainMaker