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.

Sat, 01 Apr 2023 21:06:59 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 01 Apr 2023 21:06:59 +0200
changeset 9
1659bd3c7a2b
parent 8
115e93bf8796
child 10
eee990609da7

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.

main/CMakeLists.txt file | annotate | diff | comparison | revisions
main/Kconfig.projbuild file | annotate | diff | comparison | revisions
main/config.h file | annotate | diff | comparison | revisions
main/iotbalkon.c file | annotate | diff | comparison | revisions
main/task_mqtt.c file | annotate | diff | comparison | revisions
main/task_out.c file | annotate | diff | comparison | revisions
main/task_out.h file | annotate | diff | comparison | revisions
main/task_wifi.c file | annotate | diff | comparison | revisions
--- 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 ".")
--- 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
--- 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"
 
 
--- 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);
 
--- 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:
--- /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);
+    }
+}
--- /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
--- 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:

mercurial