add net manager

This commit is contained in:
2025-06-09 10:51:02 +01:00
parent 66cc449143
commit 4892718736
178 changed files with 1256 additions and 1109 deletions

View File

@@ -9,6 +9,6 @@ idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "lib/cAT/src"
PRIV_INCLUDE_DIRS "src"
PRIV_REQUIRES nvs_flash app_update json driver esp_http_client esp_netif esp_wifi esp_timer esp_hw_support
REQUIRES network config evse peripherals protocols meter_orno ocpp)
REQUIRES network config evse peripherals protocols ocpp)
set_source_files_properties(lib/cAT/src/cat.c PROPERTIES COMPILE_FLAGS -Wno-maybe-uninitialized)

View File

@@ -1,9 +0,0 @@
set(srcs
"src/evsemeter_modbus.c"
"src/evsemeter_ade7758.c"
"src/evsemeter_events.c"
)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
REQUIRES esp_event meter_orno meter_ade7758)

View File

@@ -1,24 +0,0 @@
#ifndef EVSEMETER_H_
#define EVSEMETER_H_
#include "esp_err.h"
#include "esp_event_base.h"
#ifdef __cplusplus
extern "C" {
#endif
ESP_EVENT_DECLARE_BASE(EVSEMETER_EVENT);
typedef enum {
EVSEMETER_EVENT_UPDATE
} evsemeter_event_id_t;
esp_err_t evsemeter_init(void);
esp_err_t evsemeter_read_current(float *current);
#ifdef __cplusplus
}
#endif
#endif /* EVSEMETER_H_ */

View File

@@ -1,22 +0,0 @@
#include "evsemeter.h"
#include "esp_event.h"
#include "esp_log.h"
#include "meter_ade7758.h"
static const char *TAG = "evsemeter_ade7758";
esp_err_t evsemeter_init(void)
{
ESP_LOGI(TAG, "Initializing EVSE meter (ADE7758)");
return ESP_OK;
}
esp_err_t evsemeter_read_current(float *current)
{
if (!current) {
return ESP_ERR_INVALID_ARG;
}
esp_event_post(EVSEMETER_EVENT, EVSEMETER_EVENT_UPDATE, current, sizeof(float), portMAX_DELAY);
return ESP_OK;
}

View File

@@ -1,3 +0,0 @@
#include "evsemeter.h"
ESP_EVENT_DEFINE_BASE(EVSEMETER_EVENT);

View File

@@ -1,22 +0,0 @@
#include "evsemeter.h"
#include "orno_modbus.h"
#include "esp_event.h"
#include "esp_log.h"
static const char *TAG = "evsemeter_modbus";
esp_err_t evsemeter_init(void)
{
ESP_LOGI(TAG, "Initializing EVSE meter (Modbus)");
return orno_modbus_init();
}
esp_err_t evsemeter_read_current(float *current)
{
esp_err_t err = orno_modbus_read_current(ORNO_METER_EVSE, current);
if (err == ESP_OK)
{
esp_event_post(EVSEMETER_EVENT, EVSEMETER_EVENT_UPDATE, current, sizeof(float), portMAX_DELAY);
}
return err;
}

View File

@@ -1,8 +0,0 @@
set(srcs
"src/gridmeter_modbus.c"
"src/gridmeter_events.c"
)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
REQUIRES esp_event meter_orno meter_zigbee)

View File

@@ -1,24 +0,0 @@
#ifndef GRIDMETER_H_
#define GRIDMETER_H_
#include "esp_err.h"
#include "esp_event_base.h"
#ifdef __cplusplus
extern "C" {
#endif
ESP_EVENT_DECLARE_BASE(GRIDMETER_EVENT);
typedef enum {
GRIDMETER_EVENT_UPDATE
} gridmeter_event_id_t;
esp_err_t gridmeter_init(void);
esp_err_t gridmeter_read_current(float *current);
#ifdef __cplusplus
}
#endif
#endif /* GRIDMETER_H_ */

View File

@@ -1,3 +0,0 @@
#include "gridmeter.h"
ESP_EVENT_DEFINE_BASE(GRIDMETER_EVENT);

View File

@@ -1,22 +0,0 @@
#include "gridmeter.h"
#include "orno_modbus.h"
#include "esp_event.h"
#include "esp_log.h"
static const char *TAG = "gridmeter_modbus";
esp_err_t gridmeter_init(void)
{
ESP_LOGI(TAG, "Initializing grid meter (Modbus)");
return orno_modbus_init();
}
esp_err_t gridmeter_read_current(float *current)
{
esp_err_t err = orno_modbus_read_current(ORNO_METER_GRID, current);
if (err == ESP_OK)
{
esp_event_post(GRIDMETER_EVENT, GRIDMETER_EVENT_UPDATE, current, sizeof(float), portMAX_DELAY);
}
return err;
}

View File

@@ -4,4 +4,4 @@ set(srcs
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
REQUIRES esp_event gridmeter evsemeter)
REQUIRES esp_event evse)

View File

@@ -1,6 +1,4 @@
#include "loadbalancer.h"
#include "gridmeter.h"
#include "evsemeter.h"
#include "evse_api.h"
#include "esp_event.h"
#include "esp_log.h"
@@ -23,6 +21,8 @@ static input_filter_t evse_filter;
static void grid_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
{
/*
if (id == GRIDMETER_EVENT_UPDATE && data)
{
float raw;
@@ -30,10 +30,13 @@ static void grid_event_handler(void *arg, esp_event_base_t base, int32_t id, voi
grid_current = input_filter_update(&grid_filter, raw);
ESP_LOGD(TAG, "Grid current (filtered): %.2f A", grid_current);
}
*/
}
static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
{
/*
if (id == EVSEMETER_EVENT_UPDATE && data)
{
float raw;
@@ -41,12 +44,14 @@ static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, voi
evse_current = input_filter_update(&evse_filter, raw);
ESP_LOGD(TAG, "EVSE current (filtered): %.2f A", evse_current);
}
*/
}
void loadbalancer_init(void)
{
ESP_LOGI(TAG, "Initializing load balancer");
/*
input_filter_init(&grid_filter, 0.3f);
input_filter_init(&evse_filter, 0.3f);
@@ -63,6 +68,7 @@ void loadbalancer_init(void)
if (xTaskCreate(loadbalancer_task, "loadbalancer", 4096, NULL, 5, NULL) != pdPASS) {
ESP_LOGE(TAG, "Failed to create loadbalancer task");
}
*/
}
void loadbalancer_task(void *param)

View File

@@ -1,9 +0,0 @@
idf_component_register(
SRCS
"src/ade7758.c"
"src/meter_ade7758.c"
INCLUDE_DIRS
"include"
REQUIRES
driver evse nvs_flash esp_timer
)

View File

@@ -1,70 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Inicializa o driver do medidor (SPI, mutex, registradores ADE7758).
*/
esp_err_t meter_init(void);
/**
* @brief Inicia a tarefa de leitura de dados do medidor.
*/
esp_err_t meter_start(void);
/**
* @brief Para a tarefa de leitura e limpa os dados internos.
*/
void meter_stop(void);
/**
* @brief Verifica se o medidor está em execução.
*
* @return true se a tarefa estiver ativa, false caso contrário.
*/
bool meter_is_running(void);
/**
* @brief Limpa os dados armazenados no medidor (zera todos os valores).
*/
void meter_clear_data(void);
// ----- Leituras por fase (L1, L2, L3) -----
// Tensão RMS (em volts)
float meter_get_vrms_l1(void);
float meter_get_vrms_l2(void);
float meter_get_vrms_l3(void);
// Corrente RMS (em amperes)
float meter_get_irms_l1(void);
float meter_get_irms_l2(void);
float meter_get_irms_l3(void);
// Potência ativa (W)
int meter_get_watt_l1(void);
int meter_get_watt_l2(void);
int meter_get_watt_l3(void);
// Potência reativa (VAR)
int meter_get_var_l1(void);
int meter_get_var_l2(void);
int meter_get_var_l3(void);
// Potência aparente (VA)
int meter_get_va_l1(void);
int meter_get_va_l2(void);
int meter_get_va_l3(void);
// (Opcional) contador de watchdog para diagnóstico
uint32_t meter_get_watchdog_counter(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,22 @@
# List the source files to be compiled
set(srcs
"driver/meter_ade7758/meter_ade7758.c"
"driver/meter_orno/meter_orno513.c"
"driver/meter_orno/meter_orno516.c"
"driver/meter_orno/modbus_params.c"
"driver/meter_zigbee/meter_zigbee.c"
"src/meter_manager.c"
)
# List the include directories
set(includes
"include"
"driver/meter_ade7758"
"driver/meter_orno"
"driver/meter_zigbee"
)
# Register the component with the ESP-IDF build system
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${includes}"
REQUIRES esp_event esp-modbus)

View File

@@ -12,8 +12,7 @@
#include "driver/spi_master.h"
#define TAG "meter"
#define TAG "meter_ade7758"
// === Configurações de hardware ===
#define PIN_NUM_CLK 15
@@ -35,23 +34,23 @@ typedef struct {
int watt[3];
int var[3]; // reservados
int va[3]; // reservados
} meter_internal_data_t;
} meter_ade7758_internal_data_t;
static meter_internal_data_t meter_data;
static meter_ade7758_internal_data_t meter_data;
static TaskHandle_t meter_task = NULL;
static SemaphoreHandle_t meter_mutex = NULL;
static uint32_t meter_watchdog_counter = 0;
// === Utilitários internos ===
static void meter_clear_internal_data(void) {
static void meter_ade7758_clear_internal_data(void) {
if (meter_mutex && xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
memset(&meter_data, 0, sizeof(meter_data));
xSemaphoreGive(meter_mutex);
}
}
static bool meter_read_internal(meter_internal_data_t *out) {
static bool meter_ade7758_read_internal(meter_ade7758_internal_data_t *out) {
if (!out) return false;
if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) {
*out = meter_data;
@@ -61,13 +60,13 @@ static bool meter_read_internal(meter_internal_data_t *out) {
return false;
}
static void meter_task_func(void *param) {
static void meter_ade7758_task_func(void *param) {
ESP_LOGI(TAG, "Meter task started");
meter_internal_data_t previous = {0};
meter_ade7758_internal_data_t previous = {0};
while (true) {
meter_internal_data_t current = {0};
meter_ade7758_internal_data_t current = {0};
current.vrms[0] = avrms() / VRMS_CAL;
current.vrms[1] = bvrms() / VRMS_CAL;
@@ -96,8 +95,8 @@ static void meter_task_func(void *param) {
// === Interface pública: controle ===
esp_err_t meter_init(void) {
ESP_LOGI(TAG, "Inicializando medidor...");
esp_err_t meter_ade7758_init(void) {
ESP_LOGI(TAG, "Inicializando medidor ADE7758...");
if (!meter_mutex) {
meter_mutex = xSemaphoreCreateMutex();
@@ -107,7 +106,7 @@ esp_err_t meter_init(void) {
}
}
meter_clear_internal_data();
meter_ade7758_clear_internal_data();
esp_err_t err = Init(EEPROM_HOST, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK);
if (err != ESP_OK) {
@@ -124,54 +123,54 @@ esp_err_t meter_init(void) {
return ESP_OK;
}
esp_err_t meter_start(void) {
esp_err_t meter_ade7758_start(void) {
if (meter_task) return ESP_ERR_INVALID_STATE;
meter_clear_internal_data();
BaseType_t result = xTaskCreate(meter_task_func, "meter_task", 4096, NULL, 5, &meter_task);
meter_ade7758_clear_internal_data();
BaseType_t result = xTaskCreate(meter_ade7758_task_func, "meter_ade7758_task", 4096, NULL, 5, &meter_task);
return result == pdPASS ? ESP_OK : ESP_FAIL;
}
void meter_stop(void) {
void meter_ade7758_stop(void) {
if (meter_task) {
vTaskDelete(meter_task);
meter_task = NULL;
}
meter_clear_internal_data();
meter_ade7758_clear_internal_data();
}
bool meter_is_running(void) {
bool meter_ade7758_is_running(void) {
return meter_task != NULL;
}
void meter_clear_data(void) {
meter_clear_internal_data();
void meter_ade7758_clear_data(void) {
meter_ade7758_clear_internal_data();
}
// === Interface pública: acesso aos dados ===
float meter_get_vrms_l1(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.vrms[0] : 0; }
float meter_get_vrms_l2(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.vrms[1] : 0; }
float meter_get_vrms_l3(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.vrms[2] : 0; }
float meter_ade7758_get_vrms_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[0] : 0; }
float meter_ade7758_get_vrms_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[1] : 0; }
float meter_ade7758_get_vrms_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[2] : 0; }
float meter_get_irms_l1(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.irms[0] : 0; }
float meter_get_irms_l2(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.irms[1] : 0; }
float meter_get_irms_l3(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.irms[2] : 0; }
float meter_ade7758_get_irms_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[0] : 0; }
float meter_ade7758_get_irms_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[1] : 0; }
float meter_ade7758_get_irms_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[2] : 0; }
int meter_get_watt_l1(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.watt[0] : 0; }
int meter_get_watt_l2(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.watt[1] : 0; }
int meter_get_watt_l3(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.watt[2] : 0; }
int meter_ade7758_get_watt_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[0] : 0; }
int meter_ade7758_get_watt_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[1] : 0; }
int meter_ade7758_get_watt_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[2] : 0; }
int meter_get_var_l1(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.var[0] : 0; }
int meter_get_var_l2(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.var[1] : 0; }
int meter_get_var_l3(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.var[2] : 0; }
int meter_ade7758_get_var_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[0] : 0; }
int meter_ade7758_get_var_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[1] : 0; }
int meter_ade7758_get_var_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[2] : 0; }
int meter_get_va_l1(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.va[0] : 0; }
int meter_get_va_l2(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.va[1] : 0; }
int meter_get_va_l3(void) { meter_internal_data_t d; return meter_read_internal(&d) ? d.va[2] : 0; }
int meter_ade7758_get_va_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[0] : 0; }
int meter_ade7758_get_va_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[1] : 0; }
int meter_ade7758_get_va_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[2] : 0; }
// === Diagnóstico ===
uint32_t meter_get_watchdog_counter(void) {
uint32_t meter_ade7758_get_watchdog_counter(void) {
return meter_watchdog_counter;
}

View File

@@ -0,0 +1,70 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Inicializa o driver do medidor ADE7758 (SPI, mutex, registradores).
*/
esp_err_t meter_ade7758_init(void);
/**
* @brief Inicia a tarefa de leitura de dados do medidor ADE7758.
*/
esp_err_t meter_ade7758_start(void);
/**
* @brief Para a tarefa de leitura e limpa os dados internos do medidor ADE7758.
*/
void meter_ade7758_stop(void);
/**
* @brief Verifica se o medidor ADE7758 está em execução.
*
* @return true se a tarefa estiver ativa, false caso contrário.
*/
bool meter_ade7758_is_running(void);
/**
* @brief Limpa os dados armazenados no medidor ADE7758 (zera todos os valores).
*/
void meter_ade7758_clear_data(void);
// ----- Leituras por fase (L1, L2, L3) -----
// Tensão RMS (em volts)
float meter_ade7758_get_vrms_l1(void);
float meter_ade7758_get_vrms_l2(void);
float meter_ade7758_get_vrms_l3(void);
// Corrente RMS (em amperes)
float meter_ade7758_get_irms_l1(void);
float meter_ade7758_get_irms_l2(void);
float meter_ade7758_get_irms_l3(void);
// Potência ativa (W)
int meter_ade7758_get_watt_l1(void);
int meter_ade7758_get_watt_l2(void);
int meter_ade7758_get_watt_l3(void);
// Potência reativa (VAR)
int meter_ade7758_get_var_l1(void);
int meter_ade7758_get_var_l2(void);
int meter_ade7758_get_var_l3(void);
// Potência aparente (VA)
int meter_ade7758_get_va_l1(void);
int meter_ade7758_get_va_l2(void);
int meter_ade7758_get_va_l3(void);
// (Opcional) contador de watchdog para diagnóstico
uint32_t meter_ade7758_get_watchdog_counter(void);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
#ifndef METER_ORNO516_H_
#define METER_ORNO516_H_
#ifndef ORNO_MODBUS_H_
#define ORNO_MODBUS_H_
#include <stdbool.h>
#include "esp_err.h"
@@ -70,4 +70,4 @@ uint32_t meter_get_watchdog_counter(void);
}
#endif
#endif /* METER_ORNO516_H_ */
#endif /* ORNO_MODBUS_H_ */

View File

@@ -0,0 +1,325 @@
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "esp_log.h"
#include "meter_orno513.h"
#include "modbus_params.h" // for modbus parameters structures
#include "mbcontroller.h"
#include "sdkconfig.h"
#define TXD_PIN (GPIO_NUM_17)
#define RXD_PIN (GPIO_NUM_16)
static const char *TAG = "serial_mdb";
static bool enabled = false;
static bool meterState = false;
static bool meterTest = false;
static TaskHandle_t serial_mdb_task = NULL;
#define MB_PORT_NUM 2 //(CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
#define MB_DEV_SPEED 9600 //(CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
#define MB_UART_TXD 17
#define MB_UART_RXD 16
#define MB_UART_RTS 5
// The number of parameters that intended to be used in the particular control process
#define MASTER_MAX_CIDS num_device_parameters
// Number of reading of parameters from slave
#define MASTER_MAX_RETRY 30
// Timeout to update cid over Modbus
#define UPDATE_CIDS_TIMEOUT_MS (3000)
#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS)
// Timeout between polls
#define POLL_TIMEOUT_MS (500)
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_PERIOD_MS)
// Timeout between errors
#define ERROR_TIMEOUT_MS (1000)
#define ERROR_TIMEOUT_TICS (ERROR_TIMEOUT_MS / portTICK_PERIOD_MS)
// The macro to get offset for parameter in the appropriate structure
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
// Discrete offset macro
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
#define STR(fieldname) ((const char *)(fieldname))
// Options can be used as bit masks or parameter limits
#define OPTS(min_val, max_val, step_val) \
{ \
.opt1 = min_val, .opt2 = max_val, .opt3 = step_val}
// Enumeration of modbus device addresses accessed by master device
enum
{
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
};
// Enumeration of all supported CIDs for device (used in parameter definition table)
enum
{
CID_HOLD_DATA_0 = 0,
CID_HOLD_DATA_1 = 1,
CID_HOLD_DATA_2 = 2,
CID_HOLD_DATA_3 = 3,
CID_HOLD_DATA_4 = 4,
CID_HOLD_DATA_5 = 5,
CID_HOLD_DATA_6 = 6
};
#define SN 0x1000
#define METERID 0x1003
#define FW 0x1004
#define L1VOLTAGE 0x0100
#define L1CURRENT 0x0102
#define ACTIVEPOWER 0x0104
#define APPARENTPOWER 0x0106
#define REACTIVEPOWER 0x0108
#define TOTALFACTIVE 0x010E
#define TOTALRACTIVE 0x0118
// Example Data (Object) Dictionary for Modbus parameters:
const mb_parameter_descriptor_t device_parameters[] = {
{CID_HOLD_DATA_0, STR("TOTALFACTIVE"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALFACTIVE, 2,
HOLD_OFFSET(holding_data0), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_HOLD_DATA_1, STR("TOTALRACTIVE"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALRACTIVE, 2,
HOLD_OFFSET(holding_data1), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_HOLD_DATA_2, STR("ACTIVEPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, ACTIVEPOWER, 2,
HOLD_OFFSET(holding_data2), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_HOLD_DATA_3, STR("APPARENTPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, APPARENTPOWER, 2,
HOLD_OFFSET(holding_data3), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_HOLD_DATA_4, STR("REACTIVEPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, REACTIVEPOWER, 2,
HOLD_OFFSET(holding_data4), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_HOLD_DATA_5, STR("L1CURRENT"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2,
HOLD_OFFSET(holding_data5), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_HOLD_DATA_6, STR("L1VOLTAGE"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1VOLTAGE, 2,
HOLD_OFFSET(holding_data6), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}
};
// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
// Function to get pointer to parameter storage (instance) according to parameter description table
static void *master_get_param_data(const mb_parameter_descriptor_t *param_descriptor)
{
assert(param_descriptor != NULL);
void *instance_ptr = NULL;
if (param_descriptor->param_offset != 0)
{
switch (param_descriptor->mb_param_type)
{
case MB_PARAM_HOLDING:
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_INPUT:
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_COIL:
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_DISCRETE:
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
break;
default:
instance_ptr = NULL;
break;
}
}
else
{
ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
}
// Float - Mid-Little Endian (CDAB)
float ReverseFloat(const float inFloat)
{
float retVal;
char *floatToConvert = (char *)&inFloat;
char *returnFloat = (char *)&retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[2];
returnFloat[1] = floatToConvert[3];
returnFloat[2] = floatToConvert[0];
returnFloat[3] = floatToConvert[1];
return retVal;
}
static void serial_mdb_task_func(void *param)
{
ESP_LOGI(TAG, "serial_mdb_task_func");
esp_err_t err = ESP_OK;
float l1current = 0;
int error_count = 0;
bool alarm_state = false;
const mb_parameter_descriptor_t *param_descriptor = NULL;
ESP_LOGI(TAG, "Start modbus...");
while (true)
{
// Read all found characteristics from slave(s)
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
{
// Get data from parameters description table
err = mbc_master_get_cid_info(cid, &param_descriptor);
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
{
void *temp_data_ptr = master_get_param_data(param_descriptor);
uint8_t type = 0;
err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key,
(uint8_t *)temp_data_ptr, &type);
if (err == ESP_OK)
{
error_count = 0;
meterState = true;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT))
{
int value = *(int *)temp_data_ptr;
ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = %d (0x%" PRIx32 ") read successful.",
param_descriptor->cid,
param_descriptor->param_key,
param_descriptor->param_units,
value,
*(uint32_t *)temp_data_ptr);
if (((value > param_descriptor->param_opts.max) ||
(value < param_descriptor->param_opts.min)))
{
alarm_state = true;
break;
}
}
}
else
{
if (error_count > 3 && !meterTest)
{
meterState = false;
vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls
}
else
{
error_count++;
}
ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
param_descriptor->param_key,
(int)err,
(char *)esp_err_to_name(err));
}
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
}
}
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
}
if (alarm_state)
{
ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid);
}
else
{
ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY);
}
ESP_LOGI(TAG, "Destroy master...");
ESP_ERROR_CHECK(mbc_master_destroy());
}
// Modbus master initialization
static esp_err_t master_init(void)
{
mb_communication_info_t comm = {
.port = MB_PORT_NUM,
.mode = MB_MODE_RTU,
.baudrate = MB_DEV_SPEED,
.parity = UART_PARITY_DISABLE};
void *master_handler = NULL;
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail.");
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail, returns(0x%x).", (int)err);
err = mbc_master_setup((void *)&comm);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller setup fail, returns(0x%x).", (int)err);
err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD,
MB_UART_RTS, UART_PIN_NO_CHANGE);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
err = mbc_master_start();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller start fail, returned (0x%x).", (int)err);
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);
vTaskDelay(5);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller set descriptor fail, returns(0x%x).", (int)err);
ESP_LOGI(TAG, "Modbus master stack initialized...");
return err;
}
// Function to start the meter
esp_err_t meter_orno513_start(void)
{
ESP_LOGI(TAG, "Starting MDB Serial");
// Call the initialization function directly
esp_err_t err = master_init(); // Don't wrap this in ESP_ERROR_CHECK
ESP_ERROR_CHECK(err); // Check if there was an error during initialization
// Create the task for reading Modbus data
xTaskCreate(serial_mdb_task_func, "serial_mdb_task", 4 * 1024, NULL, 5, &serial_mdb_task);
return err;
}
// Function to stop the meter
void meter_orno513_stop(void)
{
ESP_LOGI(TAG, "Stopping");
if (serial_mdb_task)
{
vTaskDelete(serial_mdb_task);
serial_mdb_task = NULL;
}
uart_driver_delete(MB_PORT_NUM);
}

View File

@@ -0,0 +1,60 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Inicializa o driver do medidor ORNO 513 (SPI, mutex, registradores).
*/
esp_err_t meter_orno513_init(void);
/**
* @brief Inicia a tarefa de leitura de dados do medidor ORNO 513.
*/
esp_err_t meter_orno513_start(void);
/**
* @brief Para a tarefa de leitura e limpa os dados internos do medidor ORNO 513.
*/
void meter_orno513_stop(void);
/**
* @brief Verifica se o medidor ORNO 513 está em execução.
*
* @return true se a tarefa estiver ativa, false caso contrário.
*/
bool meter_orno513_is_running(void);
/**
* @brief Limpa os dados armazenados no medidor ORNO 513 (zera todos os valores).
*/
void meter_orno513_clear_data(void);
// ----- Leituras por fase (L1) -----
// Tensão RMS (em volts)
float meter_orno513_get_vrms_l1(void);
// Corrente RMS (em amperes)
float meter_orno513_get_irms_l1(void);
// Potência ativa (W)
int meter_orno513_get_watt_l1(void);
// Potência reativa (VAR)
int meter_orno513_get_var_l1(void);
// Potência aparente (VA)
int meter_orno513_get_va_l1(void);
// (Opcional) contador de watchdog para diagnóstico
uint32_t meter_orno513_get_watchdog_counter(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,383 @@
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "esp_log.h"
#include "meter_orno516.h"
#include "modbus_params.h" // for modbus parameters structures
#include "mbcontroller.h"
#include "sdkconfig.h"
#define TXD_PIN (GPIO_NUM_17)
#define RXD_PIN (GPIO_NUM_16)
static const char *TAG = "serial_mdb_orno516";
static bool enabled = false;
static bool meterState = false;
static bool meterTest = false;
static TaskHandle_t serial_mdb_task = NULL;
#define MB_PORT_NUM 2 //(CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
#define MB_DEV_SPEED 9600 //(CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
// #define MB_PARITY_EVEN
#define MB_UART_TXD 17
#define MB_UART_RXD 16
#define MB_UART_RTS 5
// Note: Some pins on target chip cannot be assigned for UART communication.
// See UART documentation for selected board and target to configure pins using Kconfig.
// The number of parameters that intended to be used in the particular control process
#define MASTER_MAX_CIDS num_device_parameters_orno516
// Number of reading of parameters from slave
#define MASTER_MAX_RETRY 30
// Timeout to update cid over Modbus
#define UPDATE_CIDS_TIMEOUT_MS (5000)
#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS)
// Timeout between polls
#define POLL_TIMEOUT_MS (1)
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_PERIOD_MS)
// Timeout between erros
#define ERROR_TIMEOUT_MS (30000)
#define ERROR_TIMEOUT_TICS (ERROR_TIMEOUT_MS / portTICK_PERIOD_MS)
// The macro to get offset for parameter in the appropriate structure
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
// Discrete offset macro
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
#define STR(fieldname) ((const char *)(fieldname))
// Options can be used as bit masks or parameter limits
#define OPTS(min_val, max_val, step_val) \
{ \
.opt1 = min_val, .opt2 = max_val, .opt3 = step_val}
// Enumeration of modbus device addresses accessed by master device
enum
{
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
};
// Enumeration of all supported CIDs for device (used in parameter definition table)
enum
{
CID_HOLD_DATA_0 = 0,
CID_HOLD_DATA_1 = 1,
CID_HOLD_DATA_2 = 2,
CID_HOLD_DATA_3 = 3,
CID_HOLD_DATA_4 = 4,
CID_HOLD_DATA_5 = 5,
CID_HOLD_DATA_6 = 6
};
#define SN 0x01
#define METERID 0x02
#define L1VOLTAGE 0x000E
#define L2VOLTAGE 0x0010
#define L3VOLTAGE 0x0012
#define L1CURRENT 0x0016
#define L2CURRENT 0x0018
#define L3CURRENT 0x001A
#define TOTALACTIVEPOWER 0x001C
// Example Data (Object) Dictionary for Modbus parameters:
// The CID field in the table must be unique.
// Modbus Slave Addr field defines slave address of the device with correspond parameter.
// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such).
// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the characteristic accordingly.
// The Instance Offset defines offset in the appropriate parameter structure that will be used as instance to save parameter value.
// Data Type, Data Size specify type of the characteristic and its data size.
// Parameter Options field specifies the options that can be used to process parameter value (limits or masks).
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
const mb_parameter_descriptor_t device_parameters_orno516[] = {
// { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
{CID_HOLD_DATA_0, STR("L1"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2,
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
{CID_HOLD_DATA_1, STR("L2"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L2CURRENT, 2,
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
{CID_HOLD_DATA_2, STR("L3"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L3CURRENT, 2,
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}
};
// Calculate number of parameters in the table
const uint16_t num_device_parameters_orno516 = (sizeof(device_parameters_orno516) / sizeof(device_parameters_orno516[0]));
// The function to get pointer to parameter storage (instance) according to parameter description table
static void *master_get_param_data_orno516(const mb_parameter_descriptor_t *param_descriptor)
{
assert(param_descriptor != NULL);
void *instance_ptr = NULL;
if (param_descriptor->param_offset != 0)
{
switch (param_descriptor->mb_param_type)
{
case MB_PARAM_HOLDING:
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_INPUT:
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_COIL:
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_DISCRETE:
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
break;
default:
instance_ptr = NULL;
break;
}
}
else
{
ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
}
// Float - Mid-Little Endian (CDAB)
float ReverseFloat_orno516(const float inFloat)
{
float retVal;
char *floatToConvert = (char *)&inFloat;
char *returnFloat = (char *)&retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[2];
returnFloat[1] = floatToConvert[3];
returnFloat[2] = floatToConvert[0];
returnFloat[3] = floatToConvert[1];
return retVal;
}
static void serial_mdb_task_func_orno516(void *param)
{
ESP_LOGI(TAG, "serial_mdb_task_func_orno516");
esp_err_t err = ESP_OK;
float maxcurrent = 0;
float l1current = 0;
float l2current = 0;
float l3current = 0;
int error_count = 0;
bool alarm_state = false;
const mb_parameter_descriptor_t *param_descriptor = NULL;
ESP_LOGI(TAG, "Start modbus...");
while (true)
{
// Read all found characteristics from slave(s)
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
{
// Get data from parameters description table
// and use this information to fill the characteristics description table
// and having all required fields in just one table
err = mbc_master_get_cid_info(cid, &param_descriptor);
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
{
void *temp_data_ptr = master_get_param_data_orno516(param_descriptor);
uint8_t type = 0;
err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key,
(uint8_t *)temp_data_ptr, &type);
if (err == ESP_OK)
{
error_count = 0;
meterState = true;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT))
{
float value = *(float *)temp_data_ptr;
value = ReverseFloat_orno516(value);
switch (cid)
{
case 0:
maxcurrent = 0;
l1current = 0;
l2current = 0;
l3current = 0;
l1current = value;
break;
case 1:
l2current = value;
break;
case 2:
l3current = value;
break;
default:
// code block
}
ESP_LOGD(TAG, "Characteristic #%u %s (%s) value = %f (0x%" PRIx32 ") read successful.",
param_descriptor->cid,
param_descriptor->param_key,
param_descriptor->param_units,
value,
*(uint32_t *)temp_data_ptr);
if (((value > param_descriptor->param_opts.max) ||
(value < param_descriptor->param_opts.min)))
{
alarm_state = true;
break;
}
}
}
else
{
if (error_count > 3 && !meterTest)
{
meterState = false;
vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls
}
else
{
error_count++;
}
ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
param_descriptor->param_key,
(int)err,
(char *)esp_err_to_name(err));
}
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
}
}
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
}
if (alarm_state)
{
ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid);
}
else
{
ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY);
}
ESP_LOGI(TAG, "Destroy master...");
ESP_ERROR_CHECK(mbc_master_destroy());
}
// Modbus master initialization
static esp_err_t master_init_orno516(void)
{
// Initialize and start Modbus controller
mb_communication_info_t comm = {
//.slave_addr = 1,
.port = MB_PORT_NUM,
.mode = MB_MODE_RTU,
.baudrate = MB_DEV_SPEED,
.parity = UART_PARITY_EVEN};
void *master_handler = NULL;
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail.");
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail, returns(0x%x).", (int)err);
err = mbc_master_setup((void *)&comm);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller setup fail, returns(0x%x).", (int)err);
// Set UART pin numbers
err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD,
MB_UART_RTS, UART_PIN_NO_CHANGE);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
err = mbc_master_start();
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller start fail, returned (0x%x).", (int)err);
// Set driver mode to Half Duplex
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);
vTaskDelay(5);
err = mbc_master_set_descriptor(&device_parameters_orno516[0], num_device_parameters_orno516);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller set descriptor fail, returns(0x%x).", (int)err);
ESP_LOGI(TAG, "Modbus master stack initialized...");
return err;
}
/**
* @brief Set meter model
*
*/
void serial_mdb_set_model_orno516(bool _enabled)
{
enabled = _enabled;
}
/**
* @brief Set meter state
*
*/
bool serial_mdb_get_meter_state_orno516()
{
return meterState;
}
/**
* @brief Set meter test state
*
*/
void serial_mdb_set_meter_test_orno516(bool _meterTest)
{
meterTest = _meterTest;
}
esp_err_t serial_mdb_start_orno516()
{
ESP_LOGI(TAG, "Starting MDB Serial");
// Call the initialization function and check for errors
esp_err_t err = master_init_orno516();
ESP_ERROR_CHECK(err); // Check if there was an error during initialization
// Create the task to handle the MDB serial communication
xTaskCreate(serial_mdb_task_func_orno516, "serial_mdb_task_orno516", 4 * 1024, NULL, 5, &serial_mdb_task);
return err;
}
void serial_mdb_stop_orno516(void)
{
ESP_LOGI(TAG, "Stopping");
if (serial_mdb_task)
{
vTaskDelete(serial_mdb_task);
serial_mdb_task = NULL;
}
uart_driver_delete(MB_PORT_NUM);
}

View File

@@ -0,0 +1,73 @@
#ifndef METER_ORNO516_H_
#define METER_ORNO516_H_
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Inicializa o driver do medidor ORNO 516 (SPI, mutex, registradores).
*
* @return esp_err_t Retorna ESP_OK se a inicialização for bem-sucedida, caso contrário retorna um erro.
*/
esp_err_t meter_init_orno516(void);
/**
* @brief Inicia a tarefa de leitura de dados do medidor ORNO 516.
*
* @return esp_err_t Retorna ESP_OK se a tarefa for iniciada com sucesso, caso contrário retorna um erro.
*/
esp_err_t meter_start_orno516(void);
/**
* @brief Para a tarefa de leitura e limpa os dados internos do medidor ORNO 516.
*/
void meter_stop_orno516(void);
/**
* @brief Verifica se o medidor ORNO 516 está em execução.
*
* @return true Se a tarefa estiver ativa, false caso contrário.
*/
bool meter_is_running_orno516(void);
/**
* @brief Limpa os dados armazenados no medidor ORNO 516 (zera todos os valores).
*/
void meter_clear_data_orno516(void);
// ----- Leituras por fase (L1, L2, L3) -----
// Tensão RMS (em volts)
float meter_get_vrms_l1_orno516(void);
float meter_get_vrms_l2_orno516(void);
float meter_get_vrms_l3_orno516(void);
// Corrente RMS (em amperes)
float meter_get_irms_l1_orno516(void);
float meter_get_irms_l2_orno516(void);
float meter_get_irms_l3_orno516(void);
// Potência ativa (W)
int meter_get_watt_l1_orno516(void);
int meter_get_watt_l2_orno516(void);
int meter_get_watt_l3_orno516(void);
// Potência reativa (VAR)
int meter_get_var_l1_orno516(void);
int meter_get_var_l2_orno516(void);
int meter_get_var_l3_orno516(void);
// Potência aparente (VA)
int meter_get_va_l1_orno516(void);
int meter_get_va_l2_orno516(void);
int meter_get_va_l3_orno516(void);
// (Opcional) contador de watchdog para diagnóstico
uint32_t meter_get_watchdog_counter_orno516(void);
#ifdef __cplusplus
}
#endif
#endif /* METER_ORNO516_H_ */

View File

@@ -69,6 +69,12 @@ typedef struct
uint32_t holding_data5;
uint32_t holding_data6;
uint32_t holding_data7;
uint32_t holding_data8;
uint32_t holding_data9;
uint32_t holding_data10;
uint32_t holding_data11;
uint32_t holding_data12;
uint32_t holding_data13;
} holding_reg_params_t;
#pragma pack(pop)

View File

@@ -1,5 +1,4 @@
#include "meter_zigbee.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

View 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

View File

@@ -0,0 +1,29 @@
#ifndef METER_MANAGER_H
#define METER_MANAGER_H
#include "esp_err.h"
// Definindo tipos de medidores possíveis para EVSE e Grid
typedef enum {
METER_TYPE_NONE, // Nenhum medidor
METER_TYPE_EVSE_ADE7758, // EVSE com ADE7758
METER_TYPE_GRID_ORNO513, // Grid com ORNO 513
METER_TYPE_GRID_ORNO516, // Grid com ORNO 516
METER_TYPE_GRID_ZIGBEE // Grid com Zigbee
} meter_type_t;
// Funções para inicializar e gerenciar o medidor EVSE (pode ser ADE7758)
esp_err_t meter_manager_init_evse(meter_type_t evse_type); // Inicializa o medidor EVSE (ex: ADE7758)
esp_err_t meter_manager_start_evse(meter_type_t evse_type); // Inicia o EVSE com o tipo especificado
esp_err_t meter_manager_stop_evse(void); // Para o EVSE
// Funções para inicializar e gerenciar o medidor Grid (pode ser ORNO 513, ORNO 516 ou Zigbee)
esp_err_t meter_manager_init_grid(meter_type_t grid_type); // Inicializa o medidor Grid (ORNO 513, ORNO 516, Zigbee)
esp_err_t meter_manager_start_grid(meter_type_t grid_type); // Inicia o medidor Grid com o tipo especificado
esp_err_t meter_manager_stop_grid(void); // Para o medidor Grid
// Funções para ler dados dos medidores
esp_err_t meter_manager_read_current(meter_type_t meter_type, float *current); // Lê a corrente do medidor
esp_err_t meter_manager_read_voltage(meter_type_t meter_type, float *voltage); // Lê a tensão do medidor
#endif // METER_MANAGER_H

View File

@@ -0,0 +1,138 @@
#include "meter_manager.h"
#include "esp_log.h"
#include "meter_ade7758.h"
#include "meter_orno513.h"
#include "meter_orno516.h"
#include "meter_zigbee.h"
static const char *TAG = "meter_manager";
// Variáveis para armazenar o tipo de medidor atual
static meter_type_t current_meter_type = METER_TYPE_NONE;
esp_err_t meter_init(meter_type_t meter_type) {
current_meter_type = meter_type;
ESP_LOGI(TAG, "Initializing meter of type: %d", meter_type);
switch (current_meter_type) {
case METER_TYPE_EVSE_ADE7758:
return meter_ade7758_init(); // Inicializa o medidor ADE7758 (EVSE)
case METER_TYPE_GRID_ORNO513:
return meter_orno513_init(); // Inicializa o medidor ORNO 513 ou 516 (Grid)
case METER_TYPE_GRID_ORNO516:
return meter_init_orno516(); // Inicializa o medidor ORNO 513 ou 516 (Grid)
case METER_TYPE_GRID_ZIGBEE:
return meter_init_zigbee(); // Inicializa o medidor Zigbee (Grid)
default:
ESP_LOGE(TAG, "Unsupported meter type");
return ESP_ERR_INVALID_ARG;
}
}
esp_err_t meter_start(void) {
if (current_meter_type == METER_TYPE_NONE) {
ESP_LOGE(TAG, "Meter type is not initialized");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGI(TAG, "Starting meter");
switch (current_meter_type) {
case METER_TYPE_EVSE_ADE7758:
return meter_ade7758_start();
case METER_TYPE_GRID_ORNO513:
return meter_orno513_start();
case METER_TYPE_GRID_ORNO516:
return meter_start_orno516();
case METER_TYPE_GRID_ZIGBEE:
return meter_start_zigbee();
default:
ESP_LOGE(TAG, "Unsupported meter type");
return ESP_ERR_INVALID_ARG;
}
}
void meter_stop(void) {
if (current_meter_type == METER_TYPE_NONE) {
ESP_LOGE(TAG, "Meter is not initialized");
return;
}
ESP_LOGI(TAG, "Stopping meter");
switch (current_meter_type) {
case METER_TYPE_EVSE_ADE7758:
meter_ade7758_stop();
break;
case METER_TYPE_GRID_ORNO513:
meter_orno513_stop();
break;
case METER_TYPE_GRID_ORNO516:
meter_stop_orno516();
break;
case METER_TYPE_GRID_ZIGBEE:
meter_stop_zigbee();
break;
default:
ESP_LOGE(TAG, "Unsupported meter type");
break;
}
}
bool meter_is_running(void) {
if (current_meter_type == METER_TYPE_NONE) {
ESP_LOGE(TAG, "Meter is not initialized");
return false;
}
switch (current_meter_type) {
case METER_TYPE_EVSE_ADE7758:
return meter_ade7758_is_running();
case METER_TYPE_GRID_ORNO513:
return meter_orno513_is_running();
case METER_TYPE_GRID_ORNO516:
return meter_is_running_orno516();
case METER_TYPE_GRID_ZIGBEE:
return meter_is_running_zigbee();
default:
ESP_LOGE(TAG, "Unsupported meter type");
return false;
}
}
float meter_get_vrms_l1(void) {
if (current_meter_type == METER_TYPE_NONE) return 0;
switch (current_meter_type) {
case METER_TYPE_EVSE_ADE7758:
return meter_ade7758_get_vrms_l1();
case METER_TYPE_GRID_ORNO513:
return meter_orno513_get_vrms_l1();
case METER_TYPE_GRID_ORNO516:
return meter_get_vrms_l1_orno516();
case METER_TYPE_GRID_ZIGBEE:
return meter_get_vrms_l1_zigbee();
default:
ESP_LOGE(TAG, "Unsupported meter type for reading vrms_l1");
return 0;
}
}
// Continue as funções `meter_get_*` para cada tipo de dado (corrente, potência, etc.)
float meter_get_irms_l1(void) {
if (current_meter_type == METER_TYPE_NONE) return 0;
switch (current_meter_type) {
case METER_TYPE_EVSE_ADE7758:
return meter_ade7758_get_irms_l1();
case METER_TYPE_GRID_ORNO513:
return meter_orno513_get_irms_l1();
case METER_TYPE_GRID_ORNO516:
return meter_get_irms_l1_orno516();
case METER_TYPE_GRID_ZIGBEE:
return meter_get_irms_l1_zigbee();
default:
ESP_LOGE(TAG, "Unsupported meter type for reading irms_l1");
return 0;
}
}
// You should add the rest of the functions similarly as you progress

View File

@@ -1,8 +0,0 @@
set(srcs
"src/modbus_params.c" "src/orno513.c" "src/orno516.c"
)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_REQUIRES nvs_flash driver
REQUIRES esp-modbus)

View File

@@ -1,70 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Inicializa o driver do medidor (SPI, mutex, registradores ADE7758).
*/
esp_err_t meter_init(void);
/**
* @brief Inicia a tarefa de leitura de dados do medidor.
*/
esp_err_t meter_start(void);
/**
* @brief Para a tarefa de leitura e limpa os dados internos.
*/
void meter_stop(void);
/**
* @brief Verifica se o medidor está em execução.
*
* @return true se a tarefa estiver ativa, false caso contrário.
*/
bool meter_is_running(void);
/**
* @brief Limpa os dados armazenados no medidor (zera todos os valores).
*/
void meter_clear_data(void);
// ----- Leituras por fase (L1, L2, L3) -----
// Tensão RMS (em volts)
float meter_get_vrms_l1(void);
float meter_get_vrms_l2(void);
float meter_get_vrms_l3(void);
// Corrente RMS (em amperes)
float meter_get_irms_l1(void);
float meter_get_irms_l2(void);
float meter_get_irms_l3(void);
// Potência ativa (W)
int meter_get_watt_l1(void);
int meter_get_watt_l2(void);
int meter_get_watt_l3(void);
// Potência reativa (VAR)
int meter_get_var_l1(void);
int meter_get_var_l2(void);
int meter_get_var_l3(void);
// Potência aparente (VA)
int meter_get_va_l1(void);
int meter_get_va_l2(void);
int meter_get_va_l3(void);
// (Opcional) contador de watchdog para diagnóstico
uint32_t meter_get_watchdog_counter(void);
#ifdef __cplusplus
}
#endif

View File

@@ -1,267 +0,0 @@
/**************************************
* INCLUDES
**************************************/
#include "meter_orno513.h"
#include "esp_log.h"
#include "modbus_params.h"
#include "mbcontroller.h"
#include "sdkconfig.h"
#include "meter_orno513.h"
/**************************************
* DEFINES E CONFIGURAÇÕES
**************************************/
#define TAG "ORNO513"
#define MB_PORT_NUM 2
#define MB_DEV_SPEED 9600
#define MB_UART_TXD 17
#define MB_UART_RXD 16
#define MB_UART_RTS 5
#define MASTER_MAX_RETRY 30
#define POLL_TIMEOUT_TICS pdMS_TO_TICKS(500)
#define UPDATE_CIDS_TIMEOUT_TICS pdMS_TO_TICKS(3000)
#define ERROR_TIMEOUT_MS 1000
#define STR(fieldname) ((const char *)(fieldname))
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
/**************************************
* VARIÁVEIS GLOBAIS
**************************************/
static bool enabled = false;
static bool meterState = false;
static bool meterTest = false;
static TaskHandle_t serial_mdb_task = NULL;
/**************************************
* ENUMS E CONSTANTES DE PARAMETROS
**************************************/
enum {
MB_DEVICE_ADDR1 = 1
};
enum {
CID_TOTALFACTIVE = 0,
CID_TOTALRACTIVE,
CID_ACTIVEPOWER,
CID_APPARENTPOWER,
CID_REACTIVEPOWER,
CID_L1CURRENT,
CID_L1VOLTAGE
};
#define TOTALFACTIVE 0x010E
#define TOTALRACTIVE 0x0118
#define ACTIVEPOWER 0x0104
#define APPARENTPOWER 0x0106
#define REACTIVEPOWER 0x0108
#define L1CURRENT 0x0102
#define L1VOLTAGE 0x0100
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
const mb_parameter_descriptor_t device_parameters[] = {
{CID_TOTALFACTIVE, STR("Total Active"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALFACTIVE, 2, HOLD_OFFSET(holding_data0), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_TOTALRACTIVE, STR("Total Reactive"),STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALRACTIVE, 2, HOLD_OFFSET(holding_data1), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_ACTIVEPOWER, STR("Active Power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, ACTIVEPOWER, 2, HOLD_OFFSET(holding_data2), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_APPARENTPOWER, STR("Apparent Power"),STR("VA"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, APPARENTPOWER,2, HOLD_OFFSET(holding_data3), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_REACTIVEPOWER, STR("Reactive Power"),STR("var"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, REACTIVEPOWER,2, HOLD_OFFSET(holding_data4), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_L1CURRENT, STR("L1 Current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2, HOLD_OFFSET(holding_data5), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ},
{CID_L1VOLTAGE, STR("L1 Voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1VOLTAGE, 2, HOLD_OFFSET(holding_data6), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}
};
const uint16_t num_device_parameters = sizeof(device_parameters) / sizeof(device_parameters[0]);
/**************************************
* FUNÇÕES AUXILIARES
**************************************/
static void *master_get_param_data(const mb_parameter_descriptor_t *desc) {
assert(desc != NULL);
switch (desc->mb_param_type) {
case MB_PARAM_HOLDING: return ((void *)&holding_reg_params + desc->param_offset - 1);
case MB_PARAM_INPUT: return ((void *)&input_reg_params + desc->param_offset - 1);
case MB_PARAM_COIL: return ((void *)&coil_reg_params + desc->param_offset - 1);
case MB_PARAM_DISCRETE: return ((void *)&discrete_reg_params + desc->param_offset - 1);
default:
ESP_LOGE(TAG, "Unknown register type for CID %u", desc->cid);
return NULL;
}
}
/**************************************
* TAREFA PRINCIPAL DO MODBUS
**************************************/
static void serial_mdb_task_func(void *param) {
ESP_LOGI(TAG, "Modbus polling started");
esp_err_t err;
int error_count = 0;
void *modbus_ctx = NULL; // Inicializando o contexto Modbus
// Inicializando o Modbus Master
err = mbc_master_init(MB_PORT_SERIAL_MASTER, &modbus_ctx);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize Modbus master");
return;
}
while (true) {
// Se o Modbus não estiver habilitado e não for modo de teste, aguarda e continua o loop
if (!enabled && !meterTest) {
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
continue;
}
for (uint16_t cid = 0; cid < num_device_parameters; cid++) {
const mb_parameter_descriptor_t *desc = NULL;
// Obtém as informações do CID, agora com o contexto
err = mbc_master_get_cid_info(modbus_ctx, cid, &desc);
if (err != ESP_OK || !desc) {
continue; // Se falhar, pula para o próximo CID
}
// Obtém os dados associados ao CID
void *data = master_get_param_data(desc);
if (!data) {
continue; // Se falhar ao obter os dados, pula para o próximo CID
}
uint8_t type = 0;
// Realiza a leitura do parâmetro Modbus
err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data, &type);
if (err == ESP_OK) {
// Se a leitura for bem-sucedida, trata os dados lidos
if (type == PARAM_TYPE_FLOAT) {
float val = *(float *)data;
ESP_LOGI(TAG, "CID %u [%s] = %.2f %s", desc->cid, desc->param_key, val, desc->param_units);
} else {
int val = *(int *)data;
ESP_LOGI(TAG, "CID %u [%s] = %d %s", desc->cid, desc->param_key, val, desc->param_units);
}
meterState = true;
error_count = 0;
// Verifica se o valor está dentro dos limites
if (desc->param_opts.min != 0 || desc->param_opts.max != 0) {
if (desc->param_opts.max && val > desc->param_opts.max) {
ESP_LOGW(TAG, "CID %u value out of range! %d > %d", desc->cid, val, desc->param_opts.max);
}
if (desc->param_opts.min && val < desc->param_opts.min) {
ESP_LOGW(TAG, "CID %u value out of range! %d < %d", desc->cid, val, desc->param_opts.min);
}
}
} else {
ESP_LOGE(TAG, "Failed to read CID %u (%s), err=0x%x", cid, desc->param_key, err);
error_count++;
// Se muitos erros consecutivos ocorrerem, desabilita a leitura do medidor
if (error_count > 3 && !meterTest) {
meterState = false;
vTaskDelay(pdMS_TO_TICKS(ERROR_TIMEOUT_MS * error_count)); // Atraso antes de tentar novamente
}
}
// Espera um tempo antes de ler o próximo CID
vTaskDelay(POLL_TIMEOUT_TICS);
}
// Espera antes de realizar a próxima rodada de leitura
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
}
}
/**************************************
* INICIALIZAÇÃO DO MASTER MODBUS
**************************************/
static esp_err_t master_init(void) {
void *handler = NULL; // Este é o contexto de comunicação Modbus
mb_communication_info_t comm = {
.port = MB_PORT_NUM,
.mode = MB_MODE_RTU,
.baudrate = MB_DEV_SPEED,
.parity = UART_PARITY_DISABLE // Configuração de paridade
};
// Inicializa o Modbus Master, passando o handler para ser preenchido
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &handler);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao inicializar o Modbus Master, erro = 0x%x", err);
return err; // Retorna o erro caso falhe
}
// Configura a comunicação Modbus
err = mbc_master_setup(&comm);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha na configuração do Modbus, erro = 0x%x", err);
return err;
}
// Configura os pinos UART para Modbus RTU
err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, MB_UART_RTS, UART_PIN_NO_CHANGE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao configurar os pinos UART, erro = 0x%x", err);
return err;
}
// Configura o UART para RS485 Half-Duplex
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao configurar o modo UART para RS485, erro = 0x%x", err);
return err;
}
// Inicia o Modbus Master
err = mbc_master_start();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao iniciar o Modbus Master, erro = 0x%x", err);
return err;
}
// Atraso para garantir que tudo tenha sido configurado corretamente
vTaskDelay(pdMS_TO_TICKS(5));
// Configura o descritor do Modbus Master para os parâmetros do dispositivo
err = mbc_master_set_descriptor(device_parameters, num_device_parameters);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao configurar o descritor Modbus, erro = 0x%x", err);
return err;
}
ESP_LOGI(TAG, "Modbus master initialized successfully.");
return ESP_OK; // Sucesso
}
/**************************************
* API PÚBLICA
**************************************/
void serial_mdb_start() {
ESP_LOGI(TAG, "Iniciando MDB Serial");
enabled = meter_get_model() != ENERGY_METER_NONE;
master_init();
xTaskCreate(serial_mdb_task_func, "serial_mdb_task", 4096, NULL, 5, &serial_mdb_task);
}
void serial_mdb_stop() {
ESP_LOGI(TAG, "Parando MDB Serial");
if (serial_mdb_task) {
vTaskDelete(serial_mdb_task);
serial_mdb_task = NULL;
}
uart_driver_delete(MB_PORT_NUM);
}
void serial_mdb_set_model(bool _enabled) {
enabled = _enabled;
}
void serial_mdb_set_meter_test(bool _meterTest) {
meterTest = _meterTest;
}
bool serial_mdb_get_meter_state() {
return meterState;
}

View File

@@ -1,404 +0,0 @@
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "esp_log.h"
#include "meter_orno516.h"
#include "modbus_params.h"
#include "mbcontroller.h"
#include "sdkconfig.h"
#define TAG "ORNO516"
#define MB_PORT_NUM 2
#define MB_DEV_SPEED 9600
#define MB_UART_TXD 17
#define MB_UART_RXD 16
#define MB_UART_RTS 5
#define MASTER_MAX_RETRY 30
#define UPDATE_CIDS_TIMEOUT_TICS pdMS_TO_TICKS(5000)
#define POLL_TIMEOUT_TICS pdMS_TO_TICKS(1)
#define ERROR_TIMEOUT_TICS pdMS_TO_TICKS(30000)
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
#define STR(name) ((const char *)(name))
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
static bool enabled = false;
static bool meterState = false;
static bool meterTest = false;
static TaskHandle_t serial_mdb_task = NULL;
enum {
MB_DEVICE_ADDR1 = 1
};
enum {
CID_L1CURRENT = 0,
CID_L2CURRENT,
CID_L3CURRENT,
CID_L1VOLTAGE,
CID_L2VOLTAGE,
CID_L3VOLTAGE,
CID_TOTALACTIVEPOWER,
CID_TOTALREACTIVEPOWER,
CID_TOTALAPPARENTPOWER,
CID_TOTALACTIVEENERGY,
CID_TOTALREACTIVEENERGY,
CID_TOTALAPPARENTENERGY,
CID_POWERFACTORTOTAL,
CID_FREQUENCY
};
#define L1CURRENT 0x0016
#define L2CURRENT 0x0018
#define L3CURRENT 0x001A
#define L1VOLTAGE 0x000E
#define L2VOLTAGE 0x0010
#define L3VOLTAGE 0x0012
#define TOTALACTIVEPOWER 0x001C
#define TOTALREACTIVEPOWER 0x0024
#define TOTALAPPARENTPOWER 0x002C
#define TOTALACTIVEENERGY 0x0100
#define TOTALREACTIVEENERGY 0x0108
#define TOTALAPPARENTENERGY 0x0110
#define POWERFACTORTOTAL 0x0118
#define FREQUENCY 0x0120
const mb_parameter_descriptor_t device_parameters[] = {
{CID_L1CURRENT, STR("L1 Current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2, HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
{CID_L2CURRENT, STR("L2 Current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L2CURRENT, 2, HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
{CID_L3CURRENT, STR("L3 Current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L3CURRENT, 2, HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ},
{CID_L1VOLTAGE, STR("L1 Voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1VOLTAGE, 2, HOLD_OFFSET(holding_data3), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ},
{CID_L2VOLTAGE, STR("L2 Voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L2VOLTAGE, 2, HOLD_OFFSET(holding_data4), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ},
{CID_L3VOLTAGE, STR("L3 Voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L3VOLTAGE, 2, HOLD_OFFSET(holding_data5), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ},
{CID_TOTALACTIVEPOWER, STR("Total Active Power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALACTIVEPOWER, 2, HOLD_OFFSET(holding_data6), PARAM_TYPE_FLOAT, 4, OPTS(0, 10000, 1), PAR_PERMS_READ},
{CID_TOTALREACTIVEPOWER, STR("Total Reactive Power"), STR("var"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALREACTIVEPOWER, 2, HOLD_OFFSET(holding_data7), PARAM_TYPE_FLOAT, 4, OPTS(0, 10000, 1), PAR_PERMS_READ},
{CID_TOTALAPPARENTPOWER, STR("Total Apparent Power"), STR("VA"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALAPPARENTPOWER, 2, HOLD_OFFSET(holding_data8), PARAM_TYPE_FLOAT, 4, OPTS(0, 10000, 1), PAR_PERMS_READ},
{CID_TOTALACTIVEENERGY, STR("Total Active Energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALACTIVEENERGY, 2, HOLD_OFFSET(holding_data9), PARAM_TYPE_FLOAT, 4, OPTS(0, 100000, 1), PAR_PERMS_READ},
{CID_TOTALREACTIVEENERGY, STR("Total Reactive Energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALREACTIVEENERGY, 2, HOLD_OFFSET(holding_data10), PARAM_TYPE_FLOAT, 4, OPTS(0, 100000, 1), PAR_PERMS_READ},
{CID_TOTALAPPARENTENERGY, STR("Total Apparent Energy"), STR("kVAh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALAPPARENTENERGY, 2, HOLD_OFFSET(holding_data11), PARAM_TYPE_FLOAT, 4, OPTS(0, 100000, 1), PAR_PERMS_READ},
{CID_POWERFACTORTOTAL, STR("Power Factor Total"), STR("-"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, POWERFACTORTOTAL, 2, HOLD_OFFSET(holding_data12), PARAM_TYPE_FLOAT, 4, OPTS(-1.0, 1.0, 0.01), PAR_PERMS_READ},
{CID_FREQUENCY, STR("Frequency"), STR("Hz"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, FREQUENCY, 2, HOLD_OFFSET(holding_data13), PARAM_TYPE_FLOAT, 4, OPTS(45, 65, 0.1), PAR_PERMS_READ}
};
const uint16_t num_device_parameters = sizeof(device_parameters) / sizeof(device_parameters[0]);
// (Task function, master_init, e funções públicas como serial_mdb_start, stop, etc.)
// The function to get pointer to parameter storage (instance) according to parameter description table
static void *master_get_param_data(const mb_parameter_descriptor_t *param_descriptor)
{
assert(param_descriptor != NULL);
void *instance_ptr = NULL;
if (param_descriptor->param_offset != 0)
{
switch (param_descriptor->mb_param_type)
{
case MB_PARAM_HOLDING:
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_INPUT:
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_COIL:
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
break;
case MB_PARAM_DISCRETE:
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
break;
default:
instance_ptr = NULL;
break;
}
}
else
{
ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
}
// Float - Mid-Little Endian (CDAB)
float ReverseFloat(const float inFloat)
{
float retVal;
char *floatToConvert = (char *)&inFloat;
char *returnFloat = (char *)&retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[2];
returnFloat[1] = floatToConvert[3];
returnFloat[2] = floatToConvert[0];
returnFloat[3] = floatToConvert[1];
return retVal;
}
static void serial_mdb_task_func(void *param)
{
ESP_LOGI(TAG, "serial_mdb_task_func");
esp_err_t err = ESP_OK;
float maxcurrent = 0;
float l1current = 0;
float l2current = 0;
float l3current = 0;
int error_count = 0;
bool alarm_state = false;
const mb_parameter_descriptor_t *param_descriptor = NULL;
ESP_LOGI(TAG, "Start modbus...");
while (true)
{
if ((evse_state_is_charging(evse_get_state()) && enabled) || (meterTest && enabled))
{
// Read all found characteristics from slave(s)
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
{
// Get data from parameters description table
// and use this information to fill the characteristics description table
// and having all required fields in just one table
err = mbc_master_get_cid_info(cid, &param_descriptor);
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
{
void *temp_data_ptr = master_get_param_data(param_descriptor);
uint8_t type = 0;
err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key,
(uint8_t *)temp_data_ptr, &type);
if (err == ESP_OK)
{
error_count = 0;
meterState = true;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT))
{
float value = *(float *)temp_data_ptr;
value = ReverseFloat(value);
switch (cid)
{
case 0:
setMaxGridCurrent(grid_get_max_current() * 10);
maxcurrent = 0;
l1current = 0;
l2current = 0;
l3current = 0;
l1current = value;
break;
case 1:
l2current = value;
break;
case 2:
l3current = value;
maxcurrent = (l1current > l2current) ? l1current : l2current;
maxcurrent = (maxcurrent > l3current) ? maxcurrent : l3current;
//maxcurrent = (maxcurrent * 5) + 25;
setLiveGridCurrent((int)maxcurrent * 10);
break;
default:
// code block
}
ESP_LOGD(TAG, "Characteristic #%u %s (%s) value = %f (0x%" PRIx32 ") read successful.",
param_descriptor->cid,
param_descriptor->param_key,
param_descriptor->param_units,
value,
*(uint32_t *)temp_data_ptr);
if (((value > param_descriptor->param_opts.max) ||
(value < param_descriptor->param_opts.min)))
{
alarm_state = true;
break;
}
}
else
{
uint8_t state = *(uint8_t *)temp_data_ptr;
const char *rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
if ((state & param_descriptor->param_opts.opt2) == param_descriptor->param_opts.opt2)
{
ESP_LOGI(TAG, "Characteristic 6 #%u %s (%s) value = %s (0x%" PRIx8 ") read successful.",
param_descriptor->cid,
param_descriptor->param_key,
param_descriptor->param_units,
(const char *)rw_str,
*(uint8_t *)temp_data_ptr);
}
else
{
ESP_LOGE(TAG, "Characteristic 7 #%u %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
param_descriptor->cid,
param_descriptor->param_key,
param_descriptor->param_units,
(const char *)rw_str,
*(uint8_t *)temp_data_ptr);
alarm_state = true;
break;
}
if (state & param_descriptor->param_opts.opt1)
{
alarm_state = true;
break;
}
}
}
else
{
if (error_count > 3 && !meterTest)
{
meterState = false;
vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls
}
else
{
error_count++;
}
ESP_LOGE(TAG, "Characteristic 8 #%u (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
param_descriptor->param_key,
(int)err,
(char *)esp_err_to_name(err));
}
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
}
}
}
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS);
}
if (alarm_state)
{
ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid);
}
else
{
ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY);
}
ESP_LOGI(TAG, "Destroy master...");
ESP_ERROR_CHECK(mbc_master_destroy());
/*
while (true)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
*/
}
// Modbus master initialization
static esp_err_t master_init(void)
{
// Initialize and start Modbus controller
mb_communication_info_t comm = {
//.slave_addr = 1,
.port = MB_PORT_NUM,
.mode = MB_MODE_RTU,
.baudrate = MB_DEV_SPEED,
.parity = UART_PARITY_EVEN};
void *master_handler = NULL;
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail.");
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail, returns(0x%x).", (int)err);
err = mbc_master_setup((void *)&comm);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller setup fail, returns(0x%x).", (int)err);
// Set UART pin numbers
err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD,
MB_UART_RTS, UART_PIN_NO_CHANGE);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
err = mbc_master_start();
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller start fail, returned (0x%x).", (int)err);
// Set driver mode to Half Duplex
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);
vTaskDelay(5);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller set descriptor fail, returns(0x%x).", (int)err);
ESP_LOGI(TAG, "Modbus master stack initialized...");
return err;
}
/**
* @brief Set meter model
*
*/
void serial_mdb_set_model(bool _enabled)
{
enabled = _enabled;
}
/**
* @brief Set meter state
*
*/
bool serial_mdb_get_meter_state()
{
return meterState;
}
/**
* @brief Set meter state
*
*/
void serial_mdb_set_meter_test(bool _meterTest)
{
meterTest = _meterTest;
}
void serial_mdb_start()
{
ESP_LOGI(TAG, "Starting MDB Serial");
enabled = meter_get_model() != ENERGY_METER_NONE;
ESP_ERROR_CHECK(master_init());
xTaskCreate(serial_mdb_task_func, "serial_mdb_task", 4 * 1024, NULL, 5, &serial_mdb_task);
}
void serial_mdb_stop(void)
{
ESP_LOGI(TAG, "Stopping");
if (serial_mdb_task)
{
vTaskDelete(serial_mdb_task);
serial_mdb_task = NULL;
}
// if (port != -1)
//{
uart_driver_delete(MB_PORT_NUM);
// port = -1;
//}
}

View File

@@ -1,7 +0,0 @@
set(srcs
"src/meter_zigbee.c"
)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_REQUIRES driver)

View File

@@ -1,88 +0,0 @@
#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.)
*/
esp_err_t meter_init(void);
/**
* @brief Inicia a tarefa de leitura dos dados do medidor Zigbee.
*/
esp_err_t meter_start(void);
/**
* @brief Interrompe a tarefa e limpa recursos (UART, mutex).
*/
void meter_stop(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(void);
/**
* @brief Limpa todos os dados armazenados em memória.
*/
void meter_clear_data(void);
// ----------------------
// Leituras por fase (L1, L2, L3)
// ----------------------
// Corrente RMS (em amperes)
float meter_get_irms_l1(void);
float meter_get_irms_l2(void);
float meter_get_irms_l3(void);
// Tensão RMS (em volts)
float meter_get_vrms_l1(void);
float meter_get_vrms_l2(void);
float meter_get_vrms_l3(void);
// Potência ativa (W)
int meter_get_watt_l1(void);
int meter_get_watt_l2(void);
int meter_get_watt_l3(void);
// Potência reativa (VAR)
int meter_get_var_l1(void);
int meter_get_var_l2(void);
int meter_get_var_l3(void);
// Potência aparente (VA)
int meter_get_va_l1(void);
int meter_get_va_l2(void);
int meter_get_va_l3(void);
// ----------------------
// Dados adicionais
// ----------------------
/**
* @brief Retorna a frequência da rede em Hz.
*/
float meter_get_frequency(void);
/**
* @brief Retorna o fator de potência médio.
*/
float meter_get_power_factor(void);
/**
* @brief Retorna a energia total acumulada (kWh ou Wh, dependendo do dispositivo).
*/
float meter_get_total_energy(void);
#ifdef __cplusplus
}
#endif

View File

@@ -6,7 +6,6 @@
#include "evse_state.h"
#include "esp_wifi.h"
#include "orno_modbus.h"
#include "nvs.h"
/* MicroOcpp includes */

6
dependencies.lock Executable file → Normal file
View File

@@ -6,11 +6,11 @@ dependencies:
type: service
version: 0.5.3
espressif/esp-modbus:
component_hash: 260482d114dfc6d62e731214454dc1d5e8194689465ecc41ee48acc700a700dc
component_hash: 5d5e90b9e55721a8a194b301ad8102d4affb647f47b74cd413ff7d1ce2c1169c
source:
service_url: https://api.components.espressif.com/
type: service
version: 2.0.2
version: 1.0.18
espressif/mdns:
component_hash: 3ec0af5f6bce310512e90f482388d21cc7c0e99668172d2f895356165fc6f7c5
source:
@@ -28,6 +28,6 @@ dependencies:
source:
type: idf
version: 5.3.0
manifest_hash: 253b38bbacb90b7a58fb4e0a96c88ab21a32954ca3fb9d40351fb0e858008c75
manifest_hash: 934a9d746c65c54673c89e0201c09a3bdccec9ea3fd2bcff03ef8525f1d77443
target: esp32
version: 1.0.0

2
main/idf_component.yml Normal file → Executable file
View File

@@ -1,7 +1,7 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp-modbus: "*"
espressif/mdns: "=*"
espressif/ntc_driver: "^0.3.0"
espressif/esp-modbus: "=1.0.18"
idf:
version: ">=5.1.0"

View File

View File

View File

0
managed_components/espressif__cmake_utilities/Kconfig Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

0
managed_components/espressif__mdns/.component_hash Normal file → Executable file
View File

0
managed_components/espressif__mdns/.cz.yaml Normal file → Executable file
View File

0
managed_components/espressif__mdns/CHANGELOG.md Normal file → Executable file
View File

0
managed_components/espressif__mdns/CMakeLists.txt Normal file → Executable file
View File

0
managed_components/espressif__mdns/Kconfig Normal file → Executable file
View File

0
managed_components/espressif__mdns/LICENSE Normal file → Executable file
View File

0
managed_components/espressif__mdns/README.md Normal file → Executable file
View File

View File

0
managed_components/espressif__mdns/idf_component.yml Normal file → Executable file
View File

0
managed_components/espressif__mdns/include/mdns.h Normal file → Executable file
View File

View File

0
managed_components/espressif__mdns/mdns.c Normal file → Executable file
View File

0
managed_components/espressif__mdns/mdns_console.c Normal file → Executable file
View File

0
managed_components/espressif__mdns/mdns_mem_caps.c Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

Some files were not shown because too many files have changed in this diff Show More