add net manager
This commit is contained in:
277
components/meter_manager/driver/meter_zigbee/meter_zigbee.c
Executable file
277
components/meter_manager/driver/meter_zigbee/meter_zigbee.c
Executable file
@@ -0,0 +1,277 @@
|
||||
#include "meter_zigbee.h"
|
||||
#include <string.h>
|
||||
#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"
|
||||
|
||||
#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 meter_zigbee_data_t meter_data = {0};
|
||||
static SemaphoreHandle_t meter_mutex = NULL;
|
||||
static TaskHandle_t meter_task = NULL;
|
||||
|
||||
// ---------- Utils ----------
|
||||
|
||||
static inline float decode_float(const uint8_t *buf) {
|
||||
return (buf[9] + (buf[8] << 8) + (buf[7] << 16)) / 100.0f;
|
||||
}
|
||||
|
||||
static float meter_data_get_float(const float *arr, uint8_t phase) {
|
||||
float val = 0.0f;
|
||||
if (phase >= PHASE_COUNT) return 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
val = arr[phase];
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static int meter_data_get_int(const int *arr, uint8_t phase) {
|
||||
int val = 0;
|
||||
if (phase >= PHASE_COUNT) return 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
val = arr[phase];
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void meter_data_clear(void) {
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
memset(&meter_data, 0, sizeof(meter_data));
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Frame Handler ----------
|
||||
|
||||
static void handle_zigbee_frame(const uint8_t *buf) {
|
||||
uint16_t attr = buf[1] | (buf[2] << 8);
|
||||
uint8_t size = buf[4];
|
||||
|
||||
if (size != 8) {
|
||||
ESP_LOGW(TAG, "Unexpected data size: %d", size);
|
||||
return;
|
||||
}
|
||||
|
||||
float value = decode_float(buf);
|
||||
ESP_LOGI(TAG, "Attr 0x%04X = %.2f", attr, value);
|
||||
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
switch (attr) {
|
||||
case ATTR_CURRENT_L1:
|
||||
case ATTR_CURRENT_L1_ALT:
|
||||
meter_data.irms[0] = value;
|
||||
break;
|
||||
|
||||
case ATTR_CURRENT_L2:
|
||||
case ATTR_CURRENT_L2_ALT:
|
||||
meter_data.irms[1] = value;
|
||||
break;
|
||||
|
||||
case ATTR_CURRENT_L3:
|
||||
case ATTR_CURRENT_L3_ALT:
|
||||
meter_data.irms[2] = value;
|
||||
break;
|
||||
|
||||
case ATTR_VOLTAGE_L1: meter_data.vrms[0] = value; break;
|
||||
case ATTR_VOLTAGE_L2: meter_data.vrms[1] = value; break;
|
||||
case ATTR_VOLTAGE_L3: meter_data.vrms[2] = value; break;
|
||||
|
||||
case ATTR_POWER_L1: meter_data.watt[0] = (int)value; break;
|
||||
case ATTR_POWER_L2: meter_data.watt[1] = (int)value; break;
|
||||
case ATTR_POWER_L3: meter_data.watt[2] = (int)value; break;
|
||||
|
||||
case ATTR_POWER_FACTOR: meter_data.power_factor = value; break;
|
||||
case ATTR_FREQUENCY: meter_data.frequency = value; break;
|
||||
case ATTR_TOTAL_ENERGY: meter_data.total_energy = value; break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unknown attr: 0x%04X", attr);
|
||||
break;
|
||||
}
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Task ----------
|
||||
|
||||
static void meter_task_func(void *param) {
|
||||
uint8_t *buf = malloc(RX_FRAME_SIZE);
|
||||
if (!buf) {
|
||||
ESP_LOGE(TAG, "Memory allocation failed");
|
||||
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(1000));
|
||||
if (len >= 10) {
|
||||
handle_zigbee_frame(buf);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// ---------- Public API (meter.h) ----------
|
||||
|
||||
esp_err_t meter_init(void) {
|
||||
ESP_LOGI(TAG, "Initializing Zigbee meter");
|
||||
|
||||
if (!meter_mutex) {
|
||||
meter_mutex = xSemaphoreCreateMutex();
|
||||
if (!meter_mutex) return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
meter_data_clear();
|
||||
|
||||
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_start(void) {
|
||||
if (meter_task) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
xTaskCreate(meter_task_func, "meter_zigbee_task", 4096, NULL, 5, &meter_task);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void meter_stop(void) {
|
||||
if (meter_task) {
|
||||
vTaskDelete(meter_task);
|
||||
meter_task = NULL;
|
||||
}
|
||||
|
||||
uart_driver_delete(UART_PORT);
|
||||
|
||||
if (meter_mutex) {
|
||||
vSemaphoreDelete(meter_mutex);
|
||||
meter_mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool meter_is_running(void) {
|
||||
return meter_task != NULL;
|
||||
}
|
||||
|
||||
void meter_clear_data(void) {
|
||||
meter_data_clear();
|
||||
}
|
||||
|
||||
// ---------- RMS Current ----------
|
||||
float meter_get_irms_l1(void) { return meter_data_get_float(meter_data.irms, PHASE_L1); }
|
||||
float meter_get_irms_l2(void) { return meter_data_get_float(meter_data.irms, PHASE_L2); }
|
||||
float meter_get_irms_l3(void) { return meter_data_get_float(meter_data.irms, PHASE_L3); }
|
||||
|
||||
// ---------- RMS Voltage ----------
|
||||
float meter_get_vrms_l1(void) { return meter_data_get_float(meter_data.vrms, PHASE_L1); }
|
||||
float meter_get_vrms_l2(void) { return meter_data_get_float(meter_data.vrms, PHASE_L2); }
|
||||
float meter_get_vrms_l3(void) { return meter_data_get_float(meter_data.vrms, PHASE_L3); }
|
||||
|
||||
// ---------- Active Power ----------
|
||||
int meter_get_watt_l1(void) { return meter_data_get_int(meter_data.watt, PHASE_L1); }
|
||||
int meter_get_watt_l2(void) { return meter_data_get_int(meter_data.watt, PHASE_L2); }
|
||||
int meter_get_watt_l3(void) { return meter_data_get_int(meter_data.watt, PHASE_L3); }
|
||||
|
||||
// ---------- Reactive Power ----------
|
||||
int meter_get_var_l1(void) { return meter_data_get_int(meter_data.var, PHASE_L1); }
|
||||
int meter_get_var_l2(void) { return meter_data_get_int(meter_data.var, PHASE_L2); }
|
||||
int meter_get_var_l3(void) { return meter_data_get_int(meter_data.var, PHASE_L3); }
|
||||
|
||||
// ---------- Apparent Power ----------
|
||||
int meter_get_va_l1(void) { return meter_data_get_int(meter_data.va, PHASE_L1); }
|
||||
int meter_get_va_l2(void) { return meter_data_get_int(meter_data.va, PHASE_L2); }
|
||||
int meter_get_va_l3(void) { return meter_data_get_int(meter_data.va, PHASE_L3); }
|
||||
|
||||
// ---------- Extra Data ----------
|
||||
float meter_get_frequency(void) {
|
||||
float v = 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
v = meter_data.frequency;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
float meter_get_power_factor(void) {
|
||||
float v = 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
v = meter_data.power_factor;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
float meter_get_total_energy(void) {
|
||||
float v = 0;
|
||||
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
v = meter_data.total_energy;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
98
components/meter_manager/driver/meter_zigbee/meter_zigbee.h
Executable file
98
components/meter_manager/driver/meter_zigbee/meter_zigbee.h
Executable file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do medidor Zigbee (UART, mutex, etc.).
|
||||
*
|
||||
* @return ESP_OK se a inicialização for bem-sucedida, erro caso contrário.
|
||||
*/
|
||||
esp_err_t meter_init_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Inicia a tarefa de leitura dos dados do medidor Zigbee.
|
||||
*
|
||||
* @return ESP_OK se a tarefa for iniciada com sucesso, erro caso contrário.
|
||||
*/
|
||||
esp_err_t meter_start_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Interrompe a tarefa e limpa recursos (UART, mutex, etc.).
|
||||
*/
|
||||
void meter_stop_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Verifica se o medidor Zigbee está em execução.
|
||||
*
|
||||
* @return true se a tarefa está ativa, false se não.
|
||||
*/
|
||||
bool meter_is_running_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Limpa todos os dados armazenados em memória.
|
||||
*/
|
||||
void meter_clear_data_zigbee(void);
|
||||
|
||||
// ----------------------
|
||||
// Leituras por fase (L1, L2, L3)
|
||||
// ----------------------
|
||||
|
||||
// Corrente RMS (em amperes)
|
||||
float meter_get_irms_l1_zigbee(void);
|
||||
float meter_get_irms_l2_zigbee(void);
|
||||
float meter_get_irms_l3_zigbee(void);
|
||||
|
||||
// Tensão RMS (em volts)
|
||||
float meter_get_vrms_l1_zigbee(void);
|
||||
float meter_get_vrms_l2_zigbee(void);
|
||||
float meter_get_vrms_l3_zigbee(void);
|
||||
|
||||
// Potência ativa (W)
|
||||
int meter_get_watt_l1_zigbee(void);
|
||||
int meter_get_watt_l2_zigbee(void);
|
||||
int meter_get_watt_l3_zigbee(void);
|
||||
|
||||
// Potência reativa (VAR)
|
||||
int meter_get_var_l1_zigbee(void);
|
||||
int meter_get_var_l2_zigbee(void);
|
||||
int meter_get_var_l3_zigbee(void);
|
||||
|
||||
// Potência aparente (VA)
|
||||
int meter_get_va_l1_zigbee(void);
|
||||
int meter_get_va_l2_zigbee(void);
|
||||
int meter_get_va_l3_zigbee(void);
|
||||
|
||||
// ----------------------
|
||||
// Dados adicionais
|
||||
// ----------------------
|
||||
|
||||
/**
|
||||
* @brief Retorna a frequência da rede em Hz.
|
||||
*
|
||||
* @return Valor da frequência da rede em Hz.
|
||||
*/
|
||||
float meter_get_frequency_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Retorna o fator de potência médio.
|
||||
*
|
||||
* @return Valor do fator de potência médio.
|
||||
*/
|
||||
float meter_get_power_factor_zigbee(void);
|
||||
|
||||
/**
|
||||
* @brief Retorna a energia total acumulada (kWh ou Wh, dependendo do dispositivo).
|
||||
*
|
||||
* @return Valor da energia total acumulada.
|
||||
*/
|
||||
float meter_get_total_energy_zigbee(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user