Skip to content

Rainmaker library extension #6813

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 6, 2022
34 changes: 34 additions & 0 deletions libraries/RainMaker/examples/RMakerCustomAirCooler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# ESP RainMaker Custom Device

This example demonstrates how to build a custom device to be used with ESP RainMaker using Mode, Range and Toggle Parameters.

## What to expect in this example?

- This example sketch uses the on board Boot button and GPIOs 16, 17, 18, 19, 21, 22 to demonstrate an ESP RainMaker AirCooler device.
- After compiling and flashing the example, add your device using the [ESP RainMaker phone apps](https://rainmaker.espressif.com/docs/quick-links.html#phone-apps) by scanning the QR code.
- Toggling the power state from the phone app will toggle GPIO 16.
- Pressing the Boot button will toggle the power state (GPIO 16) and the same will reflect on the phone app.
- Toggling the swing state from the phone app will toggle GPIO 17.
- Changing the mode from the phone app will toggle the GPIOs 18 (auto), 19 (cool) and 21 (heat)
- Changing the Speed slider from the phone app will dimming GPIO 22
- You can also change the Level from the phone app and see it reflect on the device as a print message.

### Output

```
Received value = true for Air Cooler - Power
Received value = false for Air Cooler - Power
Received value = true for Air Cooler - Swing
Received value = false for Air Cooler - Swing
Received value = 0 for Air Cooler - Speed
Received value = 255 for Air Cooler - Speed
Received value = Auto for Air Cooler - Mode
Received value = Cool for Air Cooler - Mode
Received value = Heat for Air Cooler - Mode
Toggle power state to false.
Toggle power state to false.
```

### Resetting the device
- Press and Hold the Boot button for more than 3 seconds and then release to reset Wi-Fi configuration.
- Press and Hold the Boot button for more than 10 seconds and then release to reset to factory defaults.
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
//This example demonstrates the ESP RainMaker with a custom Air Cooler device
#include "RMaker.h"
#include "WiFi.h"
#include "WiFiProv.h"
#include "led_strip.h"

#define DEFAULT_POWER_MODE true
#define DEFAULT_SWING false
#define DEFAULT_SPEED 0
#define DEFAULT_MODE "Auto"

const char *service_name = "PROV_1234";
const char *pop = "abcd1234";

#if CONFIG_IDF_TARGET_ESP32C3
//GPIO for push button
static int gpio_reset = 9;
//GPIO for virtual device
static int gpio_power = 7;
static int gpio_swing = 3;
static int gpio_mode_auto = 4;
static int gpio_mode_cool = 5;
static int gpio_mode_heat = 6;
static int gpio_speed = 10;

#else
//GPIO for push button
static int gpio_reset = 0;
//GPIO for virtual device
static int gpio_power = 16;
static int gpio_swing = 17;
static int gpio_mode_auto = 18;
static int gpio_mode_cool = 19;
static int gpio_mode_heat = 21;
static int gpio_speed = 22;
#endif

bool power_state = true;

// The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
// But, you can also define custom devices using the 'Device' base class object, as shown here
static Device my_device("Air Cooler", "my.device.air-cooler", NULL);

void sysProvEvent(arduino_event_t *sys_event)
{
switch (sys_event->event_id) {
case ARDUINO_EVENT_PROV_START:
#if CONFIG_IDF_TARGET_ESP32S2
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
printQR(service_name, pop, "softap");
#else
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
printQR(service_name, pop, "ble");
#endif
break;
default:;
}
}

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();
const char *param_name = param->getParamName();

if(strcmp(param_name, "Power") == 0) {
Serial.printf("Received value = %s for %s - %s\n", val.val.b? "true" : "false", device_name, param_name);
power_state = val.val.b;
(power_state == false) ? digitalWrite(gpio_power, LOW) : digitalWrite(gpio_power, HIGH);
param->updateAndReport(val);
} else if (strcmp(param_name, "Swing") == 0) {
Serial.printf("\nReceived value = %s for %s - %s\n", val.val.b? "true" : "false", device_name, param_name);
bool swing = val.val.b;
(swing == false) ? digitalWrite(gpio_swing, LOW) : digitalWrite(gpio_swing, HIGH);
param->updateAndReport(val);
} else if (strcmp(param_name, "Speed") == 0) {
Serial.printf("\nReceived value = %d for %s - %s\n", val.val.i, device_name, param_name);
int speed = val.val.i;
analogWrite(gpio_speed, speed);
param->updateAndReport(val);
} else if (strcmp(param_name, "Mode") == 0) {
const char* mode = val.val.s;
if (strcmp(mode, "Auto") == 0) {
digitalWrite(gpio_mode_auto, HIGH);
digitalWrite(gpio_mode_heat, LOW);
digitalWrite(gpio_mode_cool, LOW);
} else if (strcmp(mode, "Heat") == 0) {
digitalWrite(gpio_mode_auto, LOW);
digitalWrite(gpio_mode_heat, HIGH);
digitalWrite(gpio_mode_cool, LOW);
} else if (strcmp(mode, "Cool") == 0) {
digitalWrite(gpio_mode_auto, LOW);
digitalWrite(gpio_mode_heat, LOW);
digitalWrite(gpio_mode_cool, HIGH);
}
Serial.printf("\nReceived value = %s for %s - %s\n", val.val.s, device_name, param_name);
param->updateAndReport(val);
}
}

void setup()
{
Serial.begin(115200);
pinMode(gpio_reset, INPUT_PULLUP);
pinMode(gpio_power, OUTPUT);
digitalWrite(gpio_power, DEFAULT_POWER_MODE);
pinMode(gpio_swing, OUTPUT);
digitalWrite(gpio_swing, DEFAULT_SWING);
pinMode(gpio_mode_auto, OUTPUT);
if (strcmp(DEFAULT_MODE, "Auto") == 0) digitalWrite(gpio_mode_auto, HIGH);
pinMode(gpio_mode_cool, OUTPUT);
if (strcmp(DEFAULT_MODE, "Cool") == 0) digitalWrite(gpio_mode_auto, HIGH);
pinMode(gpio_mode_heat, OUTPUT);
if (strcmp(DEFAULT_MODE, "Heat") == 0) digitalWrite(gpio_mode_auto, HIGH);
pinMode(gpio_speed, OUTPUT);
analogWrite(gpio_speed, DEFAULT_SPEED);

Node my_node;
my_node = RMaker.initNode("ESP RainMaker Node");

//Create custom air cooler device
my_device.addNameParam();
my_device.addPowerParam(DEFAULT_POWER_MODE);
my_device.assignPrimaryParam(my_device.getParamByName(ESP_RMAKER_DEF_POWER_NAME));

Param swing("Swing", ESP_RMAKER_PARAM_TOGGLE, value(DEFAULT_SWING), PROP_FLAG_READ | PROP_FLAG_WRITE);
swing.addUIType(ESP_RMAKER_UI_TOGGLE);
my_device.addParam(swing);

Param speed("Speed", ESP_RMAKER_PARAM_RANGE, value(DEFAULT_SPEED), PROP_FLAG_READ | PROP_FLAG_WRITE);
speed.addUIType(ESP_RMAKER_UI_SLIDER);
speed.addBounds(value(0), value(255), value(1));
my_device.addParam(speed);

static const char* modes[] = { "Auto", "Cool", "Heat" };
Param mode_param("Mode", ESP_RMAKER_PARAM_MODE, value("Auto"), PROP_FLAG_READ | PROP_FLAG_WRITE);
mode_param.addValidStrList(modes, 3);
mode_param.addUIType(ESP_RMAKER_UI_DROPDOWN);
my_device.addParam(mode_param);

my_device.addCb(write_callback);

//Add custom Air Cooler device to the node
my_node.addDevice(my_device);

//This is optional
// RMaker.enableOTA(OTA_USING_PARAMS);
//If you want to enable scheduling, set time zone for your region using setTimeZone().
//The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html
// RMaker.setTimeZone("Asia/Shanghai");
//Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone
// RMaker.enableTZService();

RMaker.enableSchedule();

RMaker.start();

WiFi.onEvent(sysProvEvent);
#if CONFIG_IDF_TARGET_ESP32S2
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
#else
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#endif
}

void loop()
{
if(digitalRead(gpio_reset) == LOW) { //Push button pressed

// Key debounce handling
delay(100);
int startTime = millis();
while(digitalRead(gpio_reset) == LOW) delay(50);
int press_duration = millis() - startTime;

if (press_duration > 10000) {
// If key pressed for more than 10secs, reset all
Serial.printf("Reset to factory.\n");
RMakerFactoryReset(2);
} else if (press_duration > 3000) {
Serial.printf("Reset Wi-Fi.\n");
// If key pressed for more than 3secs, but less than 10, reset Wi-Fi
RMakerWiFiReset(2);
} else {
// Toggle device state
power_state = !power_state;
Serial.printf("Toggle power state to %s.\n", power_state ? "true" : "false");
my_device.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, power_state);
(power_state == false) ? digitalWrite(gpio_power, LOW) : digitalWrite(gpio_power, HIGH);
}
}
delay(100);
}
8 changes: 8 additions & 0 deletions libraries/RainMaker/src/RMakerParam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ esp_err_t Param::updateAndReport(param_val_t val)
}
return err;
}

esp_err_t Param::addValidStrList(const char **string_list, uint8_t count) {
esp_err_t err = esp_rmaker_param_add_valid_str_list(getParamHandle(), string_list, count);
if (err != ESP_OK) {
log_e("Add valid string list error");
}
return err;
}
#endif
1 change: 1 addition & 0 deletions libraries/RainMaker/src/RMakerParam.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ class Param
esp_err_t addUIType(const char *ui_type);
esp_err_t addBounds(param_val_t min, param_val_t max, param_val_t step);
esp_err_t updateAndReport(param_val_t val);
esp_err_t addValidStrList(const char **string_list, uint8_t count);
};
#endif
5 changes: 5 additions & 0 deletions libraries/RainMaker/src/RMakerType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ param_val_t value(float fval)
{
return esp_rmaker_float(fval);
}

param_val_t value(const char* sval)
{
return esp_rmaker_str(sval);
}
#endif
1 change: 1 addition & 0 deletions libraries/RainMaker/src/RMakerType.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ param_val_t value(int);
param_val_t value(bool);
param_val_t value(char *);
param_val_t value(float);
param_val_t value(const char*);
#endif