} aqi_data_t;
+#ifdef CONFIG_PWM_ENABLED
+#include "driver/ledc.h"
+#define LEDC_TIMER LEDC_TIMER_0
+#define LEDC_MODE LEDC_LOW_SPEED_MODE
+#define R1_CHANNEL LEDC_CHANNEL_0
+#define R2_CHANNEL LEDC_CHANNEL_1
+#define G1_CHANNEL LEDC_CHANNEL_2
+#define G2_CHANNEL LEDC_CHANNEL_3
+#define B1_CHANNEL LEDC_CHANNEL_4
+#define B2_CHANNEL LEDC_CHANNEL_5
+#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
+#define LEDC_DUTY (4096) // Set duty to 50%. (2 ** 13) * 50% = 4096
+#define LEDC_FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz
+
+typedef struct pwm_data_s {
+ uint8_t msg[1024];
+ int len;
+} pwm_data_t;
+#endif
+
typedef struct report_data_s {
#ifdef CONFIG_UART_ENABLED
uint16_t pm10;
#endif
+#ifdef CONFIG_PWM_ENABLED
+static QueueHandle_t pwm_queue;
+#endif
+
// for tracking and reporting device uptime
static uint32_t device_uptime_seconds = 0;
}
+#ifdef CONFIG_PWM_ENABLED
+static void pwm_task(void* discard){
+
+
+ // initialize PWM hardware
+ // Prepare and then apply the LEDC PWM timer configuration
+ ledc_timer_config_t ledc_timer = {
+ .speed_mode = LEDC_MODE,
+ .timer_num = LEDC_TIMER,
+ .duty_resolution = LEDC_DUTY_RES,
+ .freq_hz = LEDC_FREQUENCY, // Set output frequency at 5 kHz
+ .clk_cfg = LEDC_AUTO_CLK
+ };
+ ESP_LOGI(TAG, "configuring ledc timer");
+ ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
+
+ // Prepare and then apply the LEDC PWM channel configuration
+ ledc_channel_config_t ledc_channel = {
+ .speed_mode = LEDC_MODE,
+ .channel = R1_CHANNEL,
+ .timer_sel = LEDC_TIMER,
+ .intr_type = LEDC_INTR_DISABLE,
+ .gpio_num = CONFIG_PWM_R1_GPIO,
+ .duty = 0, // Set duty to 0%
+ .hpoint = 0
+ };
+ ESP_LOGI(TAG, "configuring R1 PWM");
+ ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
+
+
+ ledc_channel.channel = G1_CHANNEL;
+ ledc_channel.gpio_num = CONFIG_PWM_G1_GPIO;
+
+ ESP_LOGI(TAG, "configuring G1 PWM");
+ ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
+
+ ledc_channel.channel = B1_CHANNEL;
+ ledc_channel.gpio_num = CONFIG_PWM_B1_GPIO;
+
+ ESP_LOGI(TAG, "configuring B1 PWM");
+ ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
+
+
+
+
+
+
+ //create a queue to handle gpio event from isr
+ // 1kb, should be enough for parsing?
+ pwm_queue = xQueueCreate(10, sizeof(pwm_data_t));
+ pwm_data_t recv;
+ ESP_LOGI(TAG, "waiting for pwm events");
+ cJSON* current_pwm;
+ cJSON* red_json;
+ cJSON* green_json;
+ cJSON* blue_json;
+ for(;;) {
+ if(xQueueReceive(pwm_queue, &recv, portMAX_DELAY)) {
+ ESP_LOGI(TAG, "received PWM data string %s len %d", recv.msg, recv.len);
+ current_pwm = cJSON_ParseWithLength(&recv.msg, recv.len);
+ if (cJSON_IsObject(current_pwm)){
+ ESP_LOGI(TAG, "parsed successfully I think");
+ char *json_string = cJSON_Print(current_pwm);
+ ESP_LOGI(TAG, "full json string decoded as %s", json_string);
+ red_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "red");
+ if (cJSON_IsNumber(red_json)){
+ ESP_LOGI(TAG, "parsed red float %f", red_json->valuedouble);
+ float red_duty_float = (float)(pow(2,13)) * red_json->valuedouble;
+ int red_duty_int = (int)red_duty_float;
+
+ ESP_LOGI(TAG, "red duty int calculated as %d", red_duty_int);
+ ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, R1_CHANNEL, red_duty_int));
+ // Update duty to apply the new value
+ ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, R1_CHANNEL));
+
+ }
+
+ green_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "green");
+ if (cJSON_IsNumber(green_json)){
+ ESP_LOGI(TAG, "parsed green float %f", green_json->valuedouble);
+ float green_duty_float = (float)(pow(2,13)) * green_json->valuedouble;
+ int green_duty_int = (int)green_duty_float;
+
+ ESP_LOGI(TAG, "green duty int calculated as %d", green_duty_int);
+ ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, G1_CHANNEL, green_duty_int));
+ // Update duty to apply the new value
+ ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, G1_CHANNEL));
+
+ }
+
+
+ blue_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "blue");
+ if (cJSON_IsNumber(blue_json)){
+ ESP_LOGI(TAG, "parsed blue float %f", blue_json->valuedouble);
+ float blue_duty_float = (float)(pow(2,13)) * blue_json->valuedouble;
+ int blue_duty_int = (int)blue_duty_float;
+
+ ESP_LOGI(TAG, "blue duty int calculated as %d", blue_duty_int);
+ ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, B1_CHANNEL, blue_duty_int));
+ // Update duty to apply the new value
+ ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, B1_CHANNEL));
+
+ }
+
+ } else {
+ ESP_LOGE(TAG, "failed to parse json successfully!");
+ }
+ cJSON_Delete(current_pwm);
+
+ }
+ }
+
+
+}
+#endif
+
#if defined(CONFIG_MOTION_FIRST_ENABLED) || defined(CONFIG_MOTION_SECOND_ENABLED)
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
mqtt_connected = true;
mqtt_was_reinit = false;
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
+// need to subscribe to MQTT topic for updates
+#ifdef CONFIG_PWM_ENABLED
+ int subret = esp_mqtt_client_subscribe(mqtt_client, CONFIG_PWM_TOPIC, 0);
+ if (subret == -1 ){
+ ESP_LOGE(TAG, "error subscribing to %s", CONFIG_PWM_TOPIC);
+ } else {
+ ESP_LOGI(TAG, "subscribed to %s for PWM updates", CONFIG_PWM_TOPIC);
+ }
+#endif
break;
case MQTT_EVENT_DISCONNECTED:
if ( event->client != mqtt_client ){
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
+ pwm_data_t sendpwm;
+ pwm_data_t* sendpwm_ptr = &sendpwm; //malloc(sizeof(pwm_data_t));
+ memset(sendpwm_ptr, 0, 1024);
+ memcpy(sendpwm_ptr->msg, event->data, event->data_len);
+ sendpwm_ptr->len = event->data_len;
+ printf("sendpwm msg: %s\nlen: %d\n", sendpwm_ptr->msg, sendpwm_ptr->len);
+
+ xQueueSend(pwm_queue, sendpwm_ptr, portMAX_DELAY);
+
break;
case MQTT_EVENT_ERROR:
if ( mqtt_client != NULL && event->client != mqtt_client ){
//runit();
#endif
+#ifdef CONFIG_PWM_ENABLED
+ ESP_LOGI(TAG, "installing pwm task");
+ xTaskCreate(pwm_task, "pwm_task", 4096, NULL, 2, NULL);
+#endif
#ifdef CONFIG_OT_ENABLED
esp_vfs_eventfd_config_t eventfd_config = {
.max_fds = 3,