#include "meter_zigbee.h" #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_log.h" #include "esp_system.h" #include "driver/uart.h" #include "driver/gpio.h" #include "meter_events.h" #define TAG "meter_zigbee" // UART config #define UART_PORT UART_NUM_1 #define TXD_PIN GPIO_NUM_17 #define RXD_PIN GPIO_NUM_16 #define UART_BUF_SIZE 128 #define RX_FRAME_SIZE 14 // Zigbee Attribute IDs #define ATTR_CURRENT_L1 0x0006 #define ATTR_CURRENT_L2 0x0007 #define ATTR_CURRENT_L3 0x0008 #define ATTR_VOLTAGE_L1 0x0266 #define ATTR_CURRENT_L1_ALT 0x0267 #define ATTR_POWER_L1 0x0268 #define ATTR_VOLTAGE_L2 0x0269 #define ATTR_CURRENT_L2_ALT 0x026A #define ATTR_POWER_L2 0x026B #define ATTR_VOLTAGE_L3 0x026C #define ATTR_CURRENT_L3_ALT 0x026D #define ATTR_POWER_L3 0x026E #define ATTR_FREQUENCY 0x0265 #define ATTR_POWER_FACTOR 0x020F #define ATTR_TOTAL_ENERGY 0x0201 #define PHASE_COUNT 3 #define PHASE_L1 0 #define PHASE_L2 1 #define PHASE_L3 2 // Internal meter state typedef struct { float vrms[PHASE_COUNT]; float irms[PHASE_COUNT]; int watt[PHASE_COUNT]; int var[PHASE_COUNT]; int va[PHASE_COUNT]; float frequency; float power_factor; float total_energy; } meter_zigbee_data_t; static bool phase_updated[PHASE_COUNT] = {false, false, false}; static meter_zigbee_data_t meter_data = {0}; static SemaphoreHandle_t meter_mutex = NULL; static TaskHandle_t meter_zigbee_task = NULL; bool meter_zigbee_is_running(void) { return meter_zigbee_task != NULL; } void send_stop_command(void) { //const char *cmd = "stop\n"; // Comando enviado para o outro lado interpretar e dormir //uart_write_bytes(UART_PORT, cmd, strlen(cmd)); //uart_wait_tx_done(UART_PORT, pdMS_TO_TICKS(100)); // Aguarda envio terminar } static void meter_zigbee_post_event(void) { meter_event_data_t evt = { .source = "GRID", .frequency = meter_data.frequency, .power_factor = meter_data.power_factor, .total_energy = meter_data.total_energy }; memcpy(evt.vrms, meter_data.vrms, sizeof(evt.vrms)); memcpy(evt.irms, meter_data.irms, sizeof(evt.irms)); memcpy(evt.watt, meter_data.watt, sizeof(evt.watt)); esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, &evt, sizeof(evt), pdMS_TO_TICKS(10)); if (err != ESP_OK) { ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err)); } } static void handle_zigbee_frame(const uint8_t *buf, size_t len) { ESP_LOGI(TAG, "Received UART frame (%d bytes):", len); ESP_LOG_BUFFER_HEX(TAG, buf, len); if (len < RX_FRAME_SIZE) { ESP_LOGW(TAG, "Invalid frame: too short (len = %d)", len); return; } uint16_t attr = buf[2] | (buf[3] << 8); uint8_t size = buf[5]; if (size != 8) { ESP_LOGW(TAG, "Unsupported payload size: %d", size); return; } uint16_t volt_raw = (buf[6] << 8) | buf[7]; uint32_t current_raw = (buf[8] << 16) | (buf[9] << 8) | buf[10]; uint32_t power_raw = (buf[11] << 16) | (buf[12] << 8) | buf[13]; float volt = volt_raw / 10.0f; float current = current_raw / 1000.0f; float power = power_raw; ESP_LOGI(TAG, "Parsed Attr 0x%04X: V=%.1fV I=%.2fA P=%.1fW", attr, volt, current, power); if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { switch (attr) { case ATTR_CURRENT_L1: case ATTR_CURRENT_L1_ALT: meter_data.irms[PHASE_L1] = current; meter_data.vrms[PHASE_L1] = volt; meter_data.watt[PHASE_L1] = (int)power; phase_updated[PHASE_L1] = true; break; case ATTR_CURRENT_L2: case ATTR_CURRENT_L2_ALT: meter_data.irms[PHASE_L2] = current; meter_data.vrms[PHASE_L2] = volt; meter_data.watt[PHASE_L2] = (int)power; phase_updated[PHASE_L2] = true; break; case ATTR_CURRENT_L3: case ATTR_CURRENT_L3_ALT: meter_data.irms[PHASE_L3] = current; meter_data.vrms[PHASE_L3] = volt; meter_data.watt[PHASE_L3] = (int)power; phase_updated[PHASE_L3] = true; break; case ATTR_POWER_FACTOR: meter_data.power_factor = 0; break; case ATTR_FREQUENCY: meter_data.frequency = 0; break; case ATTR_TOTAL_ENERGY: meter_data.total_energy = 0; break; default: ESP_LOGW(TAG, "Unknown attr: 0x%04X", attr); break; } xSemaphoreGive(meter_mutex); } // Verifica se todas as 3 fases foram atualizadas if (phase_updated[PHASE_L1] && phase_updated[PHASE_L2] && phase_updated[PHASE_L3]) { meter_zigbee_post_event(); memset(phase_updated, 0, sizeof(phase_updated)); } } static void meter_zigbee_task_func(void *param) { uint8_t *buf = malloc(RX_FRAME_SIZE); if (!buf) { ESP_LOGE(TAG, "Failed to allocate buffer"); vTaskDelete(NULL); return; } ESP_LOGI(TAG, "Zigbee meter task started"); while (1) { int len = uart_read_bytes(UART_PORT, buf, RX_FRAME_SIZE, pdMS_TO_TICKS(5000)); if (len == RX_FRAME_SIZE) { handle_zigbee_frame(buf, len); } else if (len == 0) { ESP_LOGD(TAG, "UART timeout with no data"); } else { ESP_LOGW(TAG, "Incomplete frame received (%d bytes)", len); } } free(buf); vTaskDelete(NULL); } esp_err_t meter_zigbee_init(void) { ESP_LOGI(TAG, "Initializing Zigbee meter"); if (!meter_mutex) { meter_mutex = xSemaphoreCreateMutex(); if (!meter_mutex) return ESP_ERR_NO_MEM; } uart_config_t config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_DEFAULT }; ESP_ERROR_CHECK(uart_param_config(UART_PORT, &config)); ESP_ERROR_CHECK(uart_set_pin(UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install(UART_PORT, UART_BUF_SIZE * 2, 0, 0, NULL, 0)); return ESP_OK; } esp_err_t meter_zigbee_start(void) { if (meter_zigbee_task) return ESP_ERR_INVALID_STATE; xTaskCreate(meter_zigbee_task_func, "meter_zigbee_task", 4096, NULL, 3, &meter_zigbee_task); return ESP_OK; } void meter_zigbee_stop(void) { //send_stop_command(); //vTaskDelay(pdMS_TO_TICKS(100)); // Aguarda o outro lado processar if (meter_zigbee_task) { vTaskDelete(meter_zigbee_task); meter_zigbee_task = NULL; } uart_driver_delete(UART_PORT); if (meter_mutex) { vSemaphoreDelete(meter_mutex); meter_mutex = NULL; } }