# HG changeset patch # User Michiel Broek # Date 1680376019 -7200 # Node ID 1659bd3c7a2b93048a8b3dd94753133fa018c083 # Parent 115e93bf87964240be4c7eb67cd9f56e52df2a8c Added task_out to drive the relays and led lights. Added NVS namespace to store the state of the outputs. Respond to subscribed MQTT topics to set new output values. diff -r 115e93bf8796 -r 1659bd3c7a2b main/CMakeLists.txt --- a/main/CMakeLists.txt Fri Mar 31 21:12:39 2023 +0200 +++ b/main/CMakeLists.txt Sat Apr 01 21:06:59 2023 +0200 @@ -1,2 +1,2 @@ -idf_component_register(SRCS config.c iotbalkon.c task_bmp280.c task_ina219.c task_wifi.c task_mqtt.c xutil.c +idf_component_register(SRCS config.c iotbalkon.c task_bmp280.c task_ina219.c task_wifi.c task_mqtt.c task_out.c xutil.c INCLUDE_DIRS ".") diff -r 115e93bf8796 -r 1659bd3c7a2b main/Kconfig.projbuild --- a/main/Kconfig.projbuild Fri Mar 31 21:12:39 2023 +0200 +++ b/main/Kconfig.projbuild Sat Apr 01 21:06:59 2023 +0200 @@ -84,4 +84,40 @@ endmenu + menu "Output ports" + + config OUT1_PIN + int "Relay 1 port pin" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 1 if IDF_TARGET_ESP32C3 + default 1 + help + Output relay 1, default GPIO port 1 + + config OUT2_PIN + int "Relay 2 port pin" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 0 if IDF_TARGET_ESP32C3 + default 0 + help + Output relay 2, default GPIO port 0 + + config OUT3_PIN + int "Dimmer 3 port pin" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 4 if IDF_TARGET_ESP32C3 + default 4 + help + Output dimmer 3, default GPIO port 4 + + config OUT4_PIN + int "Dimmer 4 port pin" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 5 if IDF_TARGET_ESP32C3 + default 5 + help + Output dimmer 4, default GPIO port 5 + + endmenu + endmenu diff -r 115e93bf8796 -r 1659bd3c7a2b main/config.h --- a/main/config.h Fri Mar 31 21:12:39 2023 +0200 +++ b/main/config.h Sat Apr 01 21:06:59 2023 +0200 @@ -25,6 +25,7 @@ #include "freertos/queue.h" #include "driver/gpio.h" #include "driver/i2c.h" +#include "driver/ledc.h" #include "esp_log.h" #include "esp_system.h" #include "esp_timer.h" @@ -51,6 +52,7 @@ #include "task_ina219.h" #include "task_wifi.h" #include "task_mqtt.h" +#include "task_out.h" #include "xutil.h" diff -r 115e93bf8796 -r 1659bd3c7a2b main/iotbalkon.c --- a/main/iotbalkon.c Fri Mar 31 21:12:39 2023 +0200 +++ b/main/iotbalkon.c Sat Apr 01 21:06:59 2023 +0200 @@ -21,8 +21,7 @@ static TaskHandle_t xTaskINA219 = NULL; static TaskHandle_t xTaskMQTT = NULL; static TaskHandle_t xTaskWifi = NULL; - -nvs_handle_t my_handle; +static TaskHandle_t xTaskOUT = NULL; #define MAX_LOOPS 32 #define SUB_TIME 1000 @@ -276,6 +275,7 @@ void app_main(void) { uint64_t totalTime, gTimeInMillis; + nvs_handle_t my_handle; #ifdef CONFIG_CODE_PRODUCTION ESP_LOGI(TAG, "Starting production"); @@ -390,8 +390,9 @@ xTaskCreate(&task_bmp280, "task_bmp280", 2560, NULL, 8, &xTaskBMP280); xTaskCreate(&task_ina219, "task_ina219", 2560, NULL, 8, &xTaskINA219); + xTaskCreate(&task_out, "task_out", 2560, NULL, 9, &xTaskOUT); // esp_log_level_set("MQTT_CLIENT", ESP_LOG_ERROR); - xTaskCreate(&task_mqtt, "task_mqtt", 4096, NULL, 5, &xTaskMQTT); + xTaskCreate(&task_mqtt, "task_mqtt", 4096, NULL, 5, &xTaskMQTT); // esp_log_level_set("wifi", ESP_LOG_ERROR); xTaskCreate(&task_wifi, "task_wifi", 4096, NULL, 3, &xTaskWifi); diff -r 115e93bf8796 -r 1659bd3c7a2b main/task_mqtt.c --- a/main/task_mqtt.c Fri Mar 31 21:12:39 2023 +0200 +++ b/main/task_mqtt.c Sat Apr 01 21:06:59 2023 +0200 @@ -39,6 +39,11 @@ extern float solarCurrent; extern float solarPower; +extern uint8_t Relay1; +extern uint8_t Relay2; +extern uint8_t Dimmer3; +extern uint8_t Dimmer4; + void connect_mqtt(bool state) { @@ -133,6 +138,11 @@ +bool do_event_data(char *check, char *topic, char *data) { + return false; +} + + void publish(void) { char *topic = NULL, *payload = NULL, buf[64]; @@ -190,13 +200,17 @@ xSemaphoreGive(xSemaphoreBMP280); } payload = xstrcat(payload, (char *)"},\"output\":{\"relay1\":"); - + sprintf(buf, "%d", Relay1); + payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"relay2\":"); - + sprintf(buf, "%d", Relay2); + payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"dimmer3\":"); - + sprintf(buf, "%d", Dimmer3); + payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)",\"dimmer4\":"); - + sprintf(buf, "%d", Dimmer4); + payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"}}"); topic = topic_base(); topic = xstrcat(topic, (char *)"status"); @@ -212,14 +226,18 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { + char *topic = NULL; + nvs_handle_t my_handle; + switch (event->event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - char *topic = topic_base(); + topic = topic_base(); topic = xstrcat(topic, (char *)"output/set/#"); ESP_LOGI(TAG, "Subscribe `%s' id %d", topic, esp_mqtt_client_subscribe(client, topic, 0)); free(topic); + topic = NULL; xEventGroupSetBits(xEventGroupMQTT, TASK_MQTT_CONNECTED); xEventGroupClearBits(xEventGroupMQTT, TASK_MQTT_DISCONNECTED); break; @@ -251,9 +269,91 @@ break; case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s ", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); + ESP_LOGI(TAG, "MQTT_EVENT_DATA len=%d", event->data_len); + bool gotit = false; + esp_err_t err; + char data[65]; + if (event->data_len < 65) + snprintf(data, 64, "%.*s", event->data_len, event->data); + else + data[0] = '\0'; + + topic = topic_base(); + topic = xstrcat(topic, (char *)"output/set/1"); + if (strncmp(topic, event->topic, event->topic_len) == 0) { + ESP_LOGI(TAG, "Got %s `%s' %d", topic, data, atoi(data)); + gotit = true; + if ((uint8_t)atoi(data) != Relay1) { + Relay1 = (uint8_t)atoi(data); + err = nvs_open("balkon", NVS_READWRITE, &my_handle); + if (err == ESP_OK) { + nvs_set_u8(my_handle, (char *)"out1", Relay1); + nvs_commit(my_handle); + nvs_close(my_handle); + } + } + } + free(topic); + topic = NULL; + + topic = topic_base(); + topic = xstrcat(topic, (char *)"output/set/2"); + if (strncmp(topic, event->topic, event->topic_len) == 0) { + ESP_LOGI(TAG, "Got %s `%s' %d", topic, data, atoi(data)); + gotit = true; + if ((uint8_t)atoi(data) != Relay2) { + Relay2 = (uint8_t)atoi(data); + err = nvs_open("balkon", NVS_READWRITE, &my_handle); + if (err == ESP_OK) { + nvs_set_u8(my_handle, (char *)"out2", Relay2); + nvs_commit(my_handle); + nvs_close(my_handle); + } + } + } + free(topic); + topic = NULL; + + topic = topic_base(); + topic = xstrcat(topic, (char *)"output/set/3"); + if (strncmp(topic, event->topic, event->topic_len) == 0) { + ESP_LOGI(TAG, "Got %s `%s' %d", topic, data, atoi(data)); + gotit = true; + if ((uint8_t)atoi(data) != Dimmer3) { + Dimmer3 = (uint8_t)atoi(data); + err = nvs_open("balkon", NVS_READWRITE, &my_handle); + if (err == ESP_OK) { + nvs_set_u8(my_handle, (char *)"out3", Dimmer3); + nvs_commit(my_handle); + nvs_close(my_handle); + } + } + } + free(topic); + topic = NULL; + + topic = topic_base(); + topic = xstrcat(topic, (char *)"output/set/4"); + if (strncmp(topic, event->topic, event->topic_len) == 0) { + ESP_LOGI(TAG, "Got %s `%s' %d", topic, data, atoi(data)); + gotit = true; + if ((uint8_t)atoi(data) != Dimmer4) { + Dimmer4 = (uint8_t)atoi(data); + err = nvs_open("balkon", NVS_READWRITE, &my_handle); + if (err == ESP_OK) { + nvs_set_u8(my_handle, (char *)"out4", Dimmer4); + nvs_commit(my_handle); + nvs_close(my_handle); + } + } + } + free(topic); + topic = NULL; + + if (! gotit) { + printf("TOPIC=%.*s ", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + } break; case MQTT_EVENT_ERROR: diff -r 115e93bf8796 -r 1659bd3c7a2b main/task_out.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/task_out.c Sat Apr 01 21:06:59 2023 +0200 @@ -0,0 +1,151 @@ +/** + * @file task_out.c + * @brief The FreeRTOS task to drive the outputs. + */ + + +#include "config.h" + + +static const char *TAG = "task_out"; + + + +#define OutputPin1 CONFIG_OUT1_PIN +#define OutputPin2 CONFIG_OUT2_PIN +#define OutputPin3 CONFIG_OUT3_PIN +#define OutputPin4 CONFIG_OUT4_PIN + +SemaphoreHandle_t xSemaphoreOUT = NULL; ///< Semaphore OUT task +OUT_State *out_state; ///< Public state for other tasks + +extern uint32_t Alarm; +extern uint8_t Relay1; +extern uint8_t Relay2; +extern uint8_t Dimmer3; +extern uint8_t Dimmer4; + + +/* + * Task to drive the outputs. + */ +void task_out(void *pvParameter) +{ + int val; + + ESP_LOGI(TAG, "Starting task OUT %d %d %d %d", Relay1, Relay2, Dimmer3, Dimmer4); + + xSemaphoreOUT = xSemaphoreCreateMutex(); + out_state = malloc(sizeof(OUT_State)); + out_state->error = OUT_ERR_NONE; + out_state->out1 = 0; + out_state->out2 = 0; + out_state->out3 = 0; + out_state->out4 = 0; + + gpio_reset_pin(OutputPin1); + gpio_reset_pin(OutputPin2); + gpio_reset_pin(OutputPin3); + gpio_reset_pin(OutputPin4); + + gpio_set_direction(OutputPin1, GPIO_MODE_OUTPUT); + gpio_set_direction(OutputPin2, GPIO_MODE_OUTPUT); + + /* + * Prepare the LEDC PWM channels + */ + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_LOW_SPEED_MODE, ///< Use high speed timer + .timer_num = LEDC_TIMER_0, ///< Timer 0 + .duty_resolution = LEDC_TIMER_10_BIT, ///< 10 bits resolution + .freq_hz = 100, ///< 100 Hz + .clk_cfg = LEDC_AUTO_CLK ///< Auto select PWM clock + }; + ledc_timer_config(&ledc_timer); + + ledc_channel_config_t dimmer_channel3 = { + .channel = LEDC_CHANNEL_0, + .duty = 0, ///< Default 0% + .gpio_num = OutputPin3, ///< Dimmer3 pin + .speed_mode = LEDC_LOW_SPEED_MODE, + .hpoint = 0, + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = LEDC_TIMER_0 ///< Timer 0 + }; + ledc_channel_config(&dimmer_channel3); + + ledc_channel_config_t dimmer_channel4 = { + .channel = LEDC_CHANNEL_1, + .duty = 1024, ///< Default 0% (inverted value) + .gpio_num = OutputPin4, ///< Dimmer4 pin + .speed_mode = LEDC_LOW_SPEED_MODE, + .hpoint = 0, + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = LEDC_TIMER_0 ///< Timer 0 + }; + ledc_channel_config(&dimmer_channel4); + + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); + + /* + * Task loop forever. + */ + ESP_LOGI(TAG, "Starting loop OUT task"); + + while (1) { + + if (xSemaphoreTake(xSemaphoreOUT, 25) == pdTRUE) { + + if (out_state->out1 != Relay1) { + out_state->out1 = Relay1; + if (Alarm) + gpio_set_level(OutputPin1, 0); + else + gpio_set_level(OutputPin1, Relay1); +// ESP_LOGI(TAG, "Relay1 %d %d", OutputPin1, Relay1); + } + if (out_state->out2 != Relay2) { + out_state->out2 = Relay2; + if (Alarm) + gpio_set_level(OutputPin2, 0); + else + gpio_set_level(OutputPin2, Relay2); +// ESP_LOGI(TAG, "Relay2 %d %d", OutputPin2, Relay2); + } + + if (out_state->out3 != Dimmer3) { + if (out_state->out3 < Dimmer3) { + out_state->out3++; + } else if (out_state->out3 > Dimmer3) { + out_state->out3--; + } + if (Alarm) + val = 0; + else + val = (out_state->out3 * 1024) / 100; + //ESP_LOGI(TAG, "Dimmer 3 %d val %d", out_state->out3, val); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, val); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); + } + if (out_state->out4 != Dimmer4) { + if (out_state->out4 < Dimmer4) { + out_state->out4++; + } else if (out_state->out4 > Dimmer4) { + out_state->out4--; + } + if (Alarm) + val = 0; + else + val = (out_state->out4 * 1024) / 100; + //ESP_LOGI(TAG, "Dimmer 4 %d val %d", out_state->out4, val); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, val); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); + } + xSemaphoreGive(xSemaphoreOUT); + } + vTaskDelay(20 / portTICK_PERIOD_MS); + } +} diff -r 115e93bf8796 -r 1659bd3c7a2b main/task_out.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/task_out.h Sat Apr 01 21:06:59 2023 +0200 @@ -0,0 +1,35 @@ +/** + * @file task_out.h + * @brief The FreeRTOS task to drive the output relays and dimmed leds. + */ + +#ifndef _TASK_OUT_H +#define _TASK_OUT_H + +/* + * Error codes in this task + */ +#define OUT_ERR_NONE 0 ///< No errors +#define OUT_ERR_READ 1 + + +/** + * @brief Structure containing the variables for the out task. + */ +typedef struct { + int error; ///< Error result + uint8_t out1; ///< Actual output state + uint8_t out2; + uint8_t out3; + uint8_t out4; +} OUT_State; + + +/** + * @brief The FreeRTOS task to update the outputs. + * @param pvParameters Parameters for the task. + */ +void task_out(void *pvParameters); + + +#endif diff -r 115e93bf8796 -r 1659bd3c7a2b main/task_wifi.c --- a/main/task_wifi.c Fri Mar 31 21:12:39 2023 +0200 +++ b/main/task_wifi.c Sat Apr 01 21:06:59 2023 +0200 @@ -99,7 +99,6 @@ if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { wifi_state->STA_connected = false; wifi_state->STA_online = false; - //wifi_state->STA_rssi = 0; xSemaphoreGive(xSemaphoreWiFi); } else { ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_DISCONNECTED"); @@ -151,11 +150,8 @@ } else { ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_LOST_IP"); } - connect_mqtt(false); - break; - - case IP_EVENT_AP_STAIPASSIGNED: - ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED"); + if (ready_mqtt()) + connect_mqtt(false); break; default: