From 1f217020d672a687fb595987e0aeaa9231efa995 Mon Sep 17 00:00:00 2001 From: ismail Date: Sat, 3 May 2025 11:50:44 +0300 Subject: [PATCH] Add RGB light as a device. --- examples/gpio/main/app_driver.c | 67 ++++++++++++++++++ examples/gpio/main/app_main.c | 119 +++++++++++++++++++++++++++++++- examples/gpio/main/app_priv.h | 12 ++++ 3 files changed, 197 insertions(+), 1 deletion(-) diff --git a/examples/gpio/main/app_driver.c b/examples/gpio/main/app_driver.c index 2b3e148..79d6e82 100644 --- a/examples/gpio/main/app_driver.c +++ b/examples/gpio/main/app_driver.c @@ -12,6 +12,10 @@ #include #include +#include +#include "esp_err.h" +#include "esp_rmaker_core.h" +#include "esp_rmaker_standard_types.h" #include "app_priv.h" #define RMT_TX_CHANNEL RMT_CHANNEL_0 @@ -27,6 +31,11 @@ #define WIFI_RESET_BUTTON_TIMEOUT 3 #define FACTORY_RESET_BUTTON_TIMEOUT 10 +static uint16_t rgb_hue = RGB_HUE_DEFAULT; +static uint16_t rgb_saturation = RGB_SATURATION_DEFAULT; +static uint16_t rgb_brightness = RGB_BRIGHTNESS_DEFAULT; +static bool rgb_power = RGB_POWER_DEFAULT; + esp_err_t app_driver_set_gpio(const char *name, bool state) { if (strcmp(name, "Red") == 0) { @@ -41,6 +50,62 @@ esp_err_t app_driver_set_gpio(const char *name, bool state) return ESP_OK; } + +esp_err_t app_light_set_led(uint32_t hue, uint32_t saturation, uint32_t brightness) +{ + // Her ne zaman bu bu işlev çağrılırsa, RGB ışığın gücü açılır + if (!rgb_power) { + rgb_power = true; + esp_rmaker_param_update_and_report( + esp_rmaker_device_get_param_by_type(light_device, ESP_RMAKER_PARAM_POWER), + esp_rmaker_bool(rgb_power)); + } + return ws2812_led_set_hsv(hue, saturation, brightness); +} + +esp_err_t app_light_set_power(bool power) +{ + rgb_power = power; + if (power) { + ws2812_led_set_hsv(rgb_hue, rgb_saturation, rgb_brightness); + } else { + ws2812_led_clear(); + } + return ESP_OK; +} + +esp_err_t app_light_init(void) +{ + esp_err_t ret = ws2812_led_init(); + if (ret != ESP_OK) { + return ret; + } + if (rgb_power) { + ret = ws2812_led_set_hsv(rgb_hue, rgb_saturation, rgb_brightness); + } else { + ret = ws2812_led_clear(); + } + return ESP_OK; +} + +esp_err_t app_light_set_brightness(uint16_t brightness) +{ + rgb_brightness = brightness; + return app_light_set_led(rgb_hue, rgb_saturation, brightness); +} + +esp_err_t app_light_set_hue(uint16_t hue) +{ + rgb_hue = hue; + return app_light_set_led(hue, rgb_saturation, rgb_brightness); +} + +esp_err_t app_light_set_saturation(uint16_t saturation) +{ + rgb_saturation = saturation; + return app_light_set_led(rgb_hue, saturation, rgb_brightness); +} + void app_driver_init() { app_reset_button_register(app_reset_button_create(BUTTON_GPIO, BUTTON_ACTIVE_LEVEL), @@ -58,4 +123,6 @@ void app_driver_init() gpio_set_level(OUTPUT_GPIO_RED, false); gpio_set_level(OUTPUT_GPIO_GREEN, false); gpio_set_level(OUTPUT_GPIO_BLUE, false); + + app_light_init(); } diff --git a/examples/gpio/main/app_main.c b/examples/gpio/main/app_main.c index 488ab44..fe2eb83 100644 --- a/examples/gpio/main/app_main.c +++ b/examples/gpio/main/app_main.c @@ -7,6 +7,7 @@ CONDITIONS OF ANY KIND, either express or implied. */ +#include #include #include #include @@ -14,7 +15,8 @@ #include #include -#include +#include +#include #include #include @@ -23,6 +25,101 @@ static const char *TAG = "app_main"; +esp_rmaker_device_t *light_device; + +#ifdef CONFIG_ESP_RMAKER_CMD_RESP_ENABLE + +#include "json_parser.h" +#include "esp_rmaker_cmd_resp.h" +#include + +static char resp_data[100]; + +/* Callback to handle commands received from the RainMaker cloud via the Command - Response Framework + * + * Sample payloads: + * - {"on":true} + * - {"brightness":30} + */ +esp_err_t led_light_cmd_handler(const void *in_data, size_t in_len, void **out_data, size_t *out_len, esp_rmaker_cmd_ctx_t *ctx, void *priv_data) +{ + if (in_data == NULL) { + ESP_LOGE(TAG, "No data received"); + return ESP_FAIL; + } + ESP_LOGI(TAG, "Received command: %s", (char *)in_data); + jparse_ctx_t jctx; + if (json_parse_start(&jctx, (char *)in_data, in_len) != 0) { + snprintf(resp_data, sizeof(resp_data), "{\"status\":\"fail\", \"description\":\"Invalid JSON\"}"); + } else { + int brightness; + bool on_state; + if (json_obj_get_int(&jctx, "brightness", &brightness) == 0) { + if (brightness < 0 || brightness > 100) { + snprintf(resp_data, sizeof(resp_data), "{\"status\":\"fail\", \"description\":\"Invalid brightness value\"}"); + } else { + app_light_set_brightness(brightness); + esp_rmaker_param_update_and_report( + esp_rmaker_device_get_param_by_type(light_device, ESP_RMAKER_PARAM_BRIGHTNESS), + esp_rmaker_int(brightness)); + snprintf(resp_data, sizeof(resp_data), "{\"status\":\"success\"}"); + } + } + else if (json_obj_get_bool(&jctx, "on", &on_state) == 0) { + app_light_set_power(on_state); + esp_rmaker_param_update_and_report( + esp_rmaker_device_get_param_by_type(light_device, ESP_RMAKER_PARAM_POWER), + esp_rmaker_bool(on_state)); + snprintf(resp_data, sizeof(resp_data), "{\"status\":\"success\"}"); + } + else { + snprintf(resp_data, sizeof(resp_data), "{\"status\":\"fail\", \"description\":\"Invalid param\"}"); + } + } + *out_data = resp_data; + *out_len = strlen(resp_data); + return ESP_OK; +} + +#endif /* CONFIG_ESP_RMAKER_CMD_RESP_ENABLE */ + +// Callback to handle param updates from the Rainmaker cloud +static esp_err_t bulk_write_cb(const esp_rmaker_device_t *device, const esp_rmaker_param_write_req_t write_req[], + uint8_t count, void *priv_data, esp_rmaker_write_ctx_t *ctx) +{ + if (ctx) { + ESP_LOGI(TAG, "Received write request via : %s", esp_rmaker_device_cb_src_to_str(ctx->src)); + } + ESP_LOGI(TAG, "Light received %d params in write", count); + for (int i = 0; i < count; i++) { + const esp_rmaker_param_t *param = write_req[i].param; + esp_rmaker_param_val_t val = write_req[i].val; + const char *device_name = esp_rmaker_device_get_name(device); + const char *param_name = esp_rmaker_param_get_name(param); + if (strcmp(param_name, ESP_RMAKER_DEF_POWER_NAME) == 0) { + ESP_LOGI(TAG, "Received value = %s for %s - %s", val.val.b ? "true" : "false", device_name, param_name); + app_light_set_power(val.val.b); + } + else if (strcmp(param_name, ESP_RMAKER_DEF_BRIGHTNESS_NAME) == 0) { + ESP_LOGI(TAG, "Received value = %d for %s - %s", val.val.i, device_name, param_name); + app_light_set_brightness(val.val.i); + } + else if (strcmp(param_name, ESP_RMAKER_DEF_HUE_NAME) == 0) { + ESP_LOGI(TAG, "Received value = %d for %s - %s", val.val.i, device_name, param_name); + app_light_set_hue(val.val.i); + } + else if (strcmp(param_name, ESP_RMAKER_DEF_SATURATION_NAME) == 0) { + ESP_LOGI(TAG, "Received value = %d for %s - %s", val.val.i, device_name, param_name); + app_light_set_saturation(val.val.i); + } + else { + ESP_LOGI(TAG, "Updating for %s", param_name); + } + esp_rmaker_param_update(param, val); + } + return ESP_OK; +} + /* Callback to handle commands received from the RainMaker cloud */ static esp_err_t write_cb(const esp_rmaker_device_t *device, const esp_rmaker_param_t *param, const esp_rmaker_param_val_t val, void *priv_data, esp_rmaker_write_ctx_t *ctx) @@ -36,6 +133,7 @@ static esp_err_t write_cb(const esp_rmaker_device_t *device, const esp_rmaker_pa return ESP_OK; } + void app_main() { /* Initialize Application specific hardware drivers and @@ -86,15 +184,34 @@ void app_main() esp_rmaker_node_add_device(node, gpio_device); + // Create the light device + light_device = esp_rmaker_lightbulb_device_create("Light", NULL, RGB_POWER_DEFAULT); + esp_rmaker_device_add_bulk_cb(light_device, bulk_write_cb, NULL); + + esp_rmaker_device_add_param(light_device, esp_rmaker_brightness_param_create(ESP_RMAKER_DEF_BRIGHTNESS_NAME, RGB_BRIGHTNESS_DEFAULT)); + esp_rmaker_device_add_param(light_device, esp_rmaker_hue_param_create(ESP_RMAKER_DEF_HUE_NAME, RGB_HUE_DEFAULT)); + esp_rmaker_device_add_param(light_device, esp_rmaker_saturation_param_create(ESP_RMAKER_DEF_SATURATION_NAME, RGB_SATURATION_DEFAULT)); + + esp_rmaker_node_add_device(node, light_device); + /* Enable OTA */ esp_rmaker_ota_enable_default(); /* Enable Insights. Requires CONFIG_ESP_INSIGHTS_ENABLED=y */ app_insights_enable(); +#ifdef CONFIG_ESP_RMAKER_CMD_RESP_ENABLE + /* Register the command response handler */ + esp_rmaker_cmd_register(ESP_RMAKER_CMD_CUSTOM_START, + ESP_RMAKER_USER_ROLE_PRIMARY_USER | ESP_RMAKER_USER_ROLE_SECONDARY_USER, + led_light_cmd_handler, false, NULL); +#endif /* CONFIG_ESP_RMAKER_CMD_RESP_ENABLE */ + /* Start the ESP RainMaker Agent */ esp_rmaker_start(); + err = app_network_set_custom_mfg_data(MGF_DATA_DEVICE_TYPE_LIGHT, MFG_DATA_DEVICE_SUBTYPE_LIGHT); + /* Start the Wi-Fi. * If the node is provisioned, it will start connection attempts, * else, it will start Wi-Fi provisioning. The function will return diff --git a/examples/gpio/main/app_priv.h b/examples/gpio/main/app_priv.h index f83ff9a..15015f9 100644 --- a/examples/gpio/main/app_priv.h +++ b/examples/gpio/main/app_priv.h @@ -10,5 +10,17 @@ #include #include +#define RGB_POWER_DEFAULT false +#define RGB_HUE_DEFAULT 180 +#define RGB_SATURATION_DEFAULT 100 +#define RGB_BRIGHTNESS_DEFAULT 25 + +extern esp_rmaker_device_t *light_device; + void app_driver_init(void); esp_err_t app_driver_set_gpio(const char *name, bool state); +esp_err_t app_light_set(uint32_t hue, uint32_t saturation, uint32_t brightness); +esp_err_t app_light_set_power(bool power); +esp_err_t app_light_set_brightness(uint16_t brightness); +esp_err_t app_light_set_hue(uint16_t hue); +esp_err_t app_light_set_saturation(uint16_t saturation); \ No newline at end of file