add orno driver

This commit is contained in:
2025-06-08 18:35:32 +01:00
parent 03de00b93f
commit 12dfa85820
17 changed files with 1689 additions and 673 deletions

View File

@@ -1,33 +1,102 @@
#include "meter_zigbee.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"
#include "meter_zigbee.h"
#include <math.h>
#define TAG "meter_zigbee"
#define TXD_PIN (GPIO_NUM_17)
#define RXD_PIN (GPIO_NUM_16)
#define BUF_SIZE 128
#define RX_BUF_SIZE 14
// 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
#define VOLTAGE_CURRENT1_ATTR 0x0006
#define VOLTAGE_CURRENT2_ATTR 0x0007
#define VOLTAGE_CURRENT3_ATTR 0x0008
// Zigbee Attribute IDs
#define ATTR_CURRENT_L1 0x0006
#define ATTR_CURRENT_L2 0x0007
#define ATTR_CURRENT_L3 0x0008
static TaskHandle_t meter_zigbee_task = NULL;
static float l1_current = 0, l2_current = 0, l3_current = 0;
#define ATTR_VOLTAGE_L1 0x0266
#define ATTR_CURRENT_L1_ALT 0x0267
#define ATTR_POWER_L1 0x0268
static float decode_current(const uint8_t *buf) {
#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 void decode_frame(const uint8_t *buf) {
uint16_t attr_code = buf[1] | (buf[2] << 8);
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) {
@@ -35,35 +104,62 @@ static void decode_frame(const uint8_t *buf) {
return;
}
float current = decode_current(buf);
ESP_LOGI(TAG, "Attr 0x%04X - Current: %.2f A", attr_code, current);
float value = decode_float(buf);
ESP_LOGI(TAG, "Attr 0x%04X = %.2f", attr, value);
switch (attr_code) {
case VOLTAGE_CURRENT1_ATTR: l1_current = current; break;
case VOLTAGE_CURRENT2_ATTR: l2_current = current; break;
case VOLTAGE_CURRENT3_ATTR: l3_current = current; break;
default:
ESP_LOGW(TAG, "Unknown attribute code: 0x%04X", attr_code);
return;
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);
}
float max_current = fmaxf(fmaxf(l1_current, l2_current), l3_current);
ESP_LOGI(TAG, "Max current: %.2f A", max_current);
}
static void meter_zigbee_task_func(void *param) {
ESP_LOGI(TAG, "Zigbee meter task started");
uint8_t *buf = malloc(RX_BUF_SIZE);
// ---------- 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_NUM_1, buf, RX_BUF_SIZE, pdMS_TO_TICKS(1000));
int len = uart_read_bytes(UART_PORT, buf, RX_FRAME_SIZE, pdMS_TO_TICKS(1000));
if (len >= 10) {
decode_frame(buf);
handle_zigbee_frame(buf);
}
}
@@ -71,39 +167,112 @@ static void meter_zigbee_task_func(void *param) {
vTaskDelete(NULL);
}
int meter_zigbee_send_data(const char *data) {
int len = strlen(data);
int sent = uart_write_bytes(UART_NUM_1, data, len);
ESP_LOGI(TAG, "Sent %d bytes", sent);
return sent;
}
// ---------- Public API (meter.h) ----------
void meter_zigbee_start(void) {
ESP_LOGI(TAG, "Starting Zigbee UART");
esp_err_t meter_init(void) {
ESP_LOGI(TAG, "Initializing Zigbee meter");
uart_config_t uart_config = {
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,
.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_NUM_1, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL,0));
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));
xTaskCreate(meter_zigbee_task_func, "meter_zigbee_task", 4096, NULL, 5, &meter_zigbee_task);
return ESP_OK;
}
void meter_zigbee_stop(void) {
ESP_LOGI(TAG, "Stopping Zigbee UART");
esp_err_t meter_start(void) {
if (meter_task) return ESP_ERR_INVALID_STATE;
if (meter_zigbee_task) {
vTaskDelete(meter_zigbee_task);
meter_zigbee_task = NULL;
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_NUM_1);
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;
}