Initial commit

This commit is contained in:
Kai Jan Kriegel 2023-07-24 02:02:48 +02:00
commit 0d603b7d26
No known key found for this signature in database
17 changed files with 1269 additions and 0 deletions

101
.gitignore vendored Normal file
View File

@ -0,0 +1,101 @@
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,c,c++
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,c,c++
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
### C++ ###
# Prerequisites
# Compiled Object files
*.slo
# Precompiled Headers
# Compiled Dynamic libraries
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
# Executables
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,c,c++
build/
managed_components/
sdkconfig
sdkconfig.old

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"idf.adapterTargetName": "esp32c3",
"idf.flashType": "UART",
"idf.port": "/dev/cu.usbserial-1320"
}

8
CMakeLists.txt Normal file
View File

@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(fabmeter)

51
dependencies.lock Normal file
View File

@ -0,0 +1,51 @@
dependencies:
espressif/cbor:
component_hash: 440f4ee4504841cc9b4f3a8ef755776a612ac9dace355514c68b999868f990ff
source:
service_url: https://api.components.espressif.com/
type: service
version: 0.6.0~1
espressif/esp-modbus:
component_hash: a03225cc0775fb4f495ff1ca56a91d0b4d4f7ba9961838dee6b04476e71a5347
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.0.11
espressif/esp_diag_data_store:
component_hash: 31f8e570af6186788e3130fc67c5391593f17ac3cbc761a8affc50510de7cdbe
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.0.0
espressif/esp_diagnostics:
component_hash: 856abf2f06f5e43a52767e221a6ac2554c944f7708781156f939249491cea3f1
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.0.0
espressif/esp_insights:
component_hash: 94ca222800cdb5abb4d68ef4e8f11c62c9d46614c63783e0d3e6fa15e248fc35
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.0.0
espressif/led_strip:
component_hash: 1f8cc130ebd557fde64c02fe5fad0cb36d69947498c540ace6f425e1083d7773
source:
service_url: https://api.components.espressif.com/
type: service
version: 2.4.1
espressif/rmaker_common:
component_hash: 7b8398212884abfea6199430cb40162c501b93c0c26e0ae90bbe2a3d1112f2d0
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.4.2
idf:
component_hash: null
source:
type: idf
version: 5.1.0
manifest_hash: de1b2f078e7c29abca615624a54fb96595c3dfdb9d0ecd691a3f119da081b339
target: esp32c3
version: 1.0.0

4
main/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
idf_component_register(SRCS "modbus_params.c" "fabmeter.c" "initializers.c" "mqtt_event_handler.c" "net_event_handler.c"
INCLUDE_DIRS ".")
# component_compile_options(-Wno-error=format= -Wno-format)

171
main/Kconfig.projbuild Normal file
View File

@ -0,0 +1,171 @@
menu "FabMeter Configuration"
config FABMETER_ID
int "FabMeter ID"
default 1
help
Numerical ID of the FabLight device
config PIN_DEBUG_LED
int "Debug LED pin"
default 8
help
GPIO pin number for the debug LED
menu "WiFi"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
choice WIFI_SCAN_METHOD
prompt "scan method"
default WIFI_FAST_SCAN
help
scan method for the esp32 to use
config WIFI_FAST_SCAN
bool "fast"
config WIFI_ALL_CHANNEL_SCAN
bool "all"
endchoice
endmenu
menu "MQTT"
config BROKER_URI
string "Broker URL"
default "mqtts://mqtt.eclipseprojects.io:8883"
help
URL of an mqtt broker which this example connects to.
config BROKER_CERTIFICATE_OVERRIDE
string "Broker certificate override"
default ""
help
Please leave empty if broker certificate included from a textfile; otherwise fill in a base64 part of PEM
format certificate
config BROKER_CERTIFICATE_OVERRIDDEN
bool
default y if BROKER_CERTIFICATE_OVERRIDE != ""
endmenu
menu "Modbus Configuration"
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
config MB_UART_PORT_ONE
bool
default y
depends on (ESP_CONSOLE_UART_NUM !=1) && (SOC_UART_NUM > 1)
config MB_UART_PORT_TWO
bool
default y
depends on (ESP_CONSOLE_UART_NUM !=2) && (SOC_UART_NUM > 2)
config MB_UART_PORT_NUM
int "UART port number"
range 0 2 if MB_UART_PORT_TWO
default 2 if MB_UART_PORT_TWO
range 0 1 if MB_UART_PORT_ONE
default 1 if MB_UART_PORT_ONE
help
UART communication port number for Modbus.
config MB_UART_BAUD_RATE
int "UART communication speed"
range 1200 115200
default 9600
help
UART communication speed for Modbus.
choice
prompt "UART parity"
default MB_UART_PARITY_DISABLE
help
UART parity for Modbus.
config MB_UART_PARITY_DISABLE
bool "None"
config MB_UART_PARITY_EVEN
bool "Even"
config MB_UART_PARITY_ODD
bool "Odd"
endchoice
config MB_UART_PARITY
int
default 0 if MB_UART_PARITY_DISABLE
default 2 if MB_UART_PARITY_EVEN
default 3 if MB_UART_PARITY_ODD
config MB_UART_STOP_BITS
int "UART stop bits"
default 1
range 1 2
help
UART stop bits for Modbus.
config MB_UART_RXD
int "UART RXD pin number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 22 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
default 8 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3 ||\
IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO number for UART RX pin. See UART documentation for more information
about available pin numbers for UART.
config MB_UART_TXD
int "UART TXD pin number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 23 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
default 9 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3 ||\
IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO number for UART TX pin. See UART documentation for more information
about available pin numbers for UART.
config MB_UART_RTS
int "UART RTS pin number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3 ||\
IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO number for UART RTS pin. This pin is connected to
~RE/DE pin of RS485 transceiver to switch direction.
See UART documentation for more information about available pin
numbers for UART.
choice MB_COMM_MODE
prompt "Modbus communication mode"
default MB_COMM_MODE_RTU if CONFIG_FMB_COMM_MODE_RTU_EN
help
Selection of Modbus communication mode option for Modbus.
config MB_COMM_MODE_RTU
bool "RTU mode"
depends on FMB_COMM_MODE_RTU_EN
config MB_COMM_MODE_ASCII
bool "ASCII mode"
depends on FMB_COMM_MODE_ASCII_EN
endchoice
endmenu
endmenu

315
main/fabmeter.c Normal file
View File

@ -0,0 +1,315 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <esp_crt_bundle.h>
#include <esp_insights.h>
#include <mqtt_client.h>
#include "modbus_params.h" // for modbus parameters structures
#include "mbcontroller.h"
#include "sdkconfig.h"
#include "modbus_utils.h"
#include "mqtt_event_handler.h"
#include "net_event_handler.h"
#include "initializers.h"
#define ESP_INSIGHTS_AUTH_KEY "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYzI3N2M3NzUtZDNjNy00NjEzLWIwMzctYjYxZGVjNmUyMGRmIiwiaXNzIjoiZTMyMmI1OWMtNjNjYy00ZTQwLThlYTItNGU3NzY2NTQ1Y2NhIiwic3ViIjoiYjExZWMyZWEtZGE5Ni00ZTQyLWIzODktOWU2MGNlM2U3Y2ZkIiwiZXhwIjoyMDA1MDA0ODk0LCJpYXQiOjE2ODk2NDQ4OTR9.FOPLo6qvkVI5k0M0j8YWonc7jRrTc6wG1p0001awcC6bWEOIxoheY69ZXSbn94vFiCtLyWAJafce3QrLJWgW0THDxGZaUNrjijqLXdKie7qEOVinjsdwILomIMa_NpSVLwZimAkd6B_uw1hk5RqooW2JzJeLYLX5i7oUgSAwZgvjN_cfCS2emrSKpZXD-CaDlNMGjt97VXzj4UFuDsNCWLaW0gEr5RcMMnYFwSxkLgv1NOWGQKfm1mZCRA_swCyxvjX4UrjlWSQZemqiqBMgnW7sBAyG5-UFGu1Fc-MfBfoB9aGblPE7LDwMeT1jgJUaJ9puhDFMY-v4Ilw8jUttzA"
// 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 300
// 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)
static const char *TAG = "FABMETER";
// 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)
};
// 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[] = {
// { 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_INP_U_L1N, STR("Phase 1 line to neutral"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0000, 2,
INPUT_OFFSET(voltage_L1N), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_L2N, STR("Phase 2 line to neutral"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0002, 2,
INPUT_OFFSET(voltage_L2N), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_L3N, STR("Phase 3 line to neutral"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0004, 2,
INPUT_OFFSET(voltage_L3N), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ},
{ CID_INP_I_L1, STR("Phase 1 current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0006, 2,
INPUT_OFFSET(current_L1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_I_L2, STR("Phase 2 current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0008, 2,
INPUT_OFFSET(current_L2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_I_L3, STR("Phase 3 current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x000A, 2,
INPUT_OFFSET(current_L3), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_P_L1, STR("Phase 1 active power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x000C, 2,
INPUT_OFFSET(active_power_L1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_P_L2, STR("Phase 2 active power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x000E, 2,
INPUT_OFFSET(active_power_L2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_P_L3, STR("Phase 3 active power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0010, 2,
INPUT_OFFSET(active_power_L3), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_S_L1, STR("Phase 1 apparent power"), STR("VA"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0012, 2,
INPUT_OFFSET(apparent_power_L1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_S_L2, STR("Phase 2 apparent power"), STR("VA"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0014, 2,
INPUT_OFFSET(apparent_power_L2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_S_L3, STR("Phase 3 apparent power"), STR("VA"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0016, 2,
INPUT_OFFSET(apparent_power_L3), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_Q_L1, STR("Phase 1 reactive power"), STR("VAR"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0018,
2, INPUT_OFFSET(reactive_power_L1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_Q_L2, STR("Phase 2 reactive power"), STR("VAR"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x001A,
2, INPUT_OFFSET(reactive_power_L2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_Q_L3, STR("Phase 3 reactive power"), STR("VAR"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x001C,
2, INPUT_OFFSET(reactive_power_L3), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_PF_L1, STR("Phase 1 power factor"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x001E, 2,
INPUT_OFFSET(power_factor_L1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_PF_L2, STR("Phase 2 power factor"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0020, 2,
INPUT_OFFSET(power_factor_L2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_PF_L3, STR("Phase 3 power factor"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0022, 2,
INPUT_OFFSET(power_factor_L3), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_LN_AVG, STR("Average line-to-neutral voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x002A,
2, INPUT_OFFSET(voltage_avg_LN), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_I_L_AVG, STR("Average line current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x002E,
2, INPUT_OFFSET(current_avg), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_I_SUM, STR("Sum of line currents"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0030,
2, INPUT_OFFSET(current_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_P_SUM, STR("Total system power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0034,
2, INPUT_OFFSET(active_power_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_S_SUM, STR("Total system apparent power"), STR("VA"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0038,
2, INPUT_OFFSET(apparent_power_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_Q_SUM, STR("Total system reactive power"), STR("VAR"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x003C,
2, INPUT_OFFSET(reactive_power_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_PF_SUM, STR("Total system power factor"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x003E,
2, INPUT_OFFSET(power_factor_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_FREQ, STR("Line frequency"), STR("Hz"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0046, 2,
INPUT_OFFSET(frequency), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_IMP, STR("Imported energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0048, 2,
INPUT_OFFSET(active_energy_import), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_EXP, STR("Exported energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x004A, 2,
INPUT_OFFSET(active_energy_export), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_L1L2, STR("Phase 1 to phase 2 voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x004C,
2, INPUT_OFFSET(voltage_L1L2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_L2L3, STR("Phase 2 to phase 3 voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x004E,
2, INPUT_OFFSET(voltage_L2L3), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_L3L1, STR("Phase 3 to phase 1 voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0050,
2, INPUT_OFFSET(voltage_L3L1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_U_LL_AVG, STR("Average line-to-line voltage"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0052,
2, INPUT_OFFSET(voltage_avg_LL), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_I_N, STR("Neutral current"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0054,
2, INPUT_OFFSET(current_N), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_SUM, STR("Total Energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0156,
2, INPUT_OFFSET(active_energy_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_Eq_SUM, STR("Total reactive Energy"), STR("kVARh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0158,
2, INPUT_OFFSET(reactive_energy_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_RESET_SUM, STR("resettable total energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0180,
2, INPUT_OFFSET(active_energy_resettable_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_Eq_RESET_SUM, STR("resettable total reactive energy"), STR("kVARh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0182,
2, INPUT_OFFSET(reactive_energy_resettable_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_RESET_IMP, STR("resettable total imported energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0184,
2, INPUT_OFFSET(active_energy_import_resettable), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_RESET_EXP, STR("resettable total exported energy"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0186,
2, INPUT_OFFSET(active_energy_export_resettable), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_E_NET, STR("Net kWh (Import - Export)"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x018C,
2, INPUT_OFFSET(active_energy_net), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_P_IMP_SUM, STR("Total imported power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0500,
2, INPUT_OFFSET(active_power_import_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_INP_P_EXP_SUM, STR("Total exported power"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0x0502,
2, INPUT_OFFSET(active_power_export_sum), PARAM_TYPE_FLOAT, 4, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_HLD_SYS_TYPE, STR("System Type"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x000A,
2, HOLD_OFFSET(sys_type), PARAM_TYPE_FLOAT, 4, OPTS( 1, 3, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_PULSE_WIDTH, STR("Pulse Width"), STR("ms"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x000C,
2, HOLD_OFFSET(pulse_width), PARAM_TYPE_FLOAT, 4, OPTS( 60, 200, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_KPPA, STR("Key Parameter Programming Authorization (KPPA)"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x000E,
2, HOLD_OFFSET(kppa), PARAM_TYPE_FLOAT, 4, OPTS( 0, 1, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_PARITY_AND_STOP, STR("Parity and stop bit"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0012,
2, HOLD_OFFSET(kppa), PARAM_TYPE_FLOAT, 4, OPTS( 0, 3, 0 ), PAR_PERMS_READ_WRITE},
{ CID_HLD_MB_ADDR, STR("Modbus address"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0014,
2, HOLD_OFFSET(modbus_addr), PARAM_TYPE_FLOAT, 4, OPTS( 1, 247, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_PULSE_CONST, STR("Pulse Constant"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0016,
2, HOLD_OFFSET(pulse_const), PARAM_TYPE_FLOAT, 4, OPTS( 0, 3, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_PASSWD, STR("Password"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0018,
2, HOLD_OFFSET(password), PARAM_TYPE_FLOAT, 4, OPTS( 0, 9999, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_BAUDRATE, STR("Baudrate"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x001C,
2, HOLD_OFFSET(baudrate), PARAM_TYPE_FLOAT, 4, OPTS( 0, 5, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_AUTO_SCROLL_TIME, STR("Auto Scroll Time"), STR("s"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x003A,
2, HOLD_OFFSET(auto_scroll_time), PARAM_TYPE_FLOAT, 4, OPTS( 0, 60, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_BACKLIGHT_TIME, STR("Backlight Time"), STR("min"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x003C,
2, HOLD_OFFSET(backlight_time), PARAM_TYPE_FLOAT, 4, OPTS( 0, 121, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_PULSE_1_E_TYPE, STR("Pulse 1 Energy Type"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x0056,
2, HOLD_OFFSET(pulse_1_energy_type), PARAM_TYPE_FLOAT, 4, OPTS( 0, 4, 0 ), PAR_PERMS_READ_WRITE },
{ CID_HLD_RST_HIST, STR("Reset historical data"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0xF010,
1, HOLD_OFFSET(reset_history), PARAM_TYPE_U16, 2, OPTS( 0, 1, 0 ), PAR_PERMS_WRITE },
{ CID_HLD_SERIAL, STR("Serial number"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0xFC00,
2, HOLD_OFFSET(serial_number), PARAM_TYPE_U16, 2, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_HLD_METER_TYPE, STR("Meter type"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0xFC02,
1, HOLD_OFFSET(meter_type), PARAM_TYPE_U16, 2, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
{ CID_HLD_METER_FIRMWARE, STR("Firmware version"), STR(""), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0xFC84,
1, HOLD_OFFSET(fw_version), PARAM_TYPE_U16, 2, OPTS( 0, 0, 0 ), PAR_PERMS_READ },
};
// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
// User operation function to read slave values and check alarm
static void modbus_poller(void *arg)
{
esp_err_t err = ESP_OK;
uint32_t value = 0;
uint8_t type = 0;
const mb_parameter_descriptor_t* param_descriptor = NULL;
char topic[512];
ESP_LOGI(TAG, "Start modbus poller");
for(;;) {
// 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);
assert(temp_data_ptr);
type = param_descriptor->param_type;
extern esp_mqtt_client_handle_t mqtt_client;
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)&value, &type);
if (err == ESP_OK) {
*(uint32_t*)temp_data_ptr = __beswap_32(value);
char payload[32];
switch (param_descriptor->param_type)
{
case PARAM_TYPE_FLOAT:
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%"PRIu32") read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
*(float*)temp_data_ptr,
*(uint32_t*)temp_data_ptr);
snprintf(topic, 512, "fabmeter/%05d/%s", CONFIG_FABMETER_ID, (char*)param_descriptor->param_key);
snprintf(payload, 32, "%f", *(float*)temp_data_ptr);
esp_mqtt_client_publish(mqtt_client, topic, payload, 0, 0, 0);
break;
case PARAM_TYPE_U8:
ESP_LOGI(TAG, "Characteristic #%d %s value = 0x%"PRIu8" read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
*(uint8_t*)temp_data_ptr);
snprintf(topic, 512, "fabmeter/%05d/%s", CONFIG_FABMETER_ID, (char*)param_descriptor->param_key);
snprintf(payload, 32, "0x%"PRIu8"", *(uint8_t*)temp_data_ptr);
esp_mqtt_client_publish(mqtt_client, topic, payload, 0, 0, 0);
break;
case PARAM_TYPE_U16:
ESP_LOGI(TAG, "Characteristic #%d %s value = 0x%"PRIu16" read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
*(uint16_t*)temp_data_ptr);
snprintf(topic, 512, "fabmeter/%05d/%s", CONFIG_FABMETER_ID, (char*)param_descriptor->param_key);
snprintf(payload, 32, "0x%"PRIu16"", *(uint16_t*)temp_data_ptr);
esp_mqtt_client_publish(mqtt_client, topic, payload, 0, 0, 0);
break;
case PARAM_TYPE_U32:
ESP_LOGI(TAG, "Characteristic #%d %s value = 0x%"PRIu32" read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
*(uint32_t*)temp_data_ptr);
snprintf(topic, 512, "fabmeter/%05d/%s", CONFIG_FABMETER_ID, (char*)param_descriptor->param_key);
snprintf(payload, 32, "0x%"PRIu32"", *(uint32_t*)temp_data_ptr);
esp_mqtt_client_publish(mqtt_client, topic, payload, 0, 0, 0);
break;
case PARAM_TYPE_ASCII:
ESP_LOGI(TAG, "Characteristic #%d %s value = %s read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)temp_data_ptr);
snprintf(topic, 512, "fabmeter/%05d/%s", CONFIG_FABMETER_ID, (char*)param_descriptor->param_key);
snprintf(payload, 32, "%s", (char*)temp_data_ptr);
esp_mqtt_client_publish(mqtt_client, topic, payload, 0, 0, 0);
break;
default:
break;
}
} else {
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%d (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
(char*)esp_err_to_name(err));
}
vTaskDelay(POLL_TIMEOUT_TICS); // delay between cids
}
}
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS); // delay between updates
}
}
void app_main(void)
{
extern led_strip_handle_t debug_led;
esp_insights_config_t config = {
.log_type = ESP_DIAG_LOG_TYPE_ERROR,
.auth_key = ESP_INSIGHTS_AUTH_KEY,
};
// Initialization of device peripheral and objects
init_led_strip();
ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0xFF, 0, 0));
ESP_ERROR_CHECK(led_strip_refresh(debug_led));
init_eventloop();
init_nvs();
init_wifi();
esp_insights_init(&config);
init_mqtt();
ESP_ERROR_CHECK(init_modbus(&device_parameters[0], num_device_parameters));
vTaskDelay(10);
modbus_poller(NULL);
}

19
main/idf_component.yml Normal file
View File

@ -0,0 +1,19 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp-modbus: "^1.0.11"
espressif/led_strip: "^2.3.1"
espressif/esp_insights: "^1.0.0"
## Required IDF version
idf:
version: ">=4.1.0"
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true

174
main/initializers.c Normal file
View File

@ -0,0 +1,174 @@
#include <mbcontroller.h>
#include <led_strip.h>
#include <esp_event.h>
#include <esp_wifi.h>
#include <esp_crt_bundle.h>
#include <mqtt_client.h>
#include <nvs_flash.h>
#include "initializers.h"
#include "net_event_handler.h"
#include "mqtt_event_handler.h"
#include "sdkconfig.h"
#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000)
char TAG[] = "initializers";
led_strip_handle_t debug_led;
esp_mqtt_client_handle_t mqtt_client;
// Modbus master initialization
esp_err_t init_modbus(const mb_parameter_descriptor_t* device_parameters, const uint16_t num_device_parameters)
{
// Initialize and start Modbus controller
mb_communication_info_t comm = {
.port = MB_PORT_NUM,
#if CONFIG_MB_COMM_MODE_ASCII
.mode = MB_MODE_ASCII,
#elif CONFIG_MB_COMM_MODE_RTU
.mode = MB_MODE_RTU,
#endif
.baudrate = MB_DEV_SPEED,
.parity = MB_PARITY
};
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%"PRIu32").",
(uint32_t)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%"PRIu32").",
(uint32_t)err);
// Set UART pin numbers
err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
CONFIG_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%"PRIu32").", (uint32_t)err);
err = mbc_master_start();
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller start fail, returns(0x%"PRIu32").",
(uint32_t)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%"PRIu32").", (uint32_t)err);
// Set UART stop bits
err = uart_set_stop_bits(MB_PORT_NUM, MB_STOP_BITS);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set stop bits failure, uart_set_stop_bits() returned (0x%"PRIu32").", (uint32_t)err);
vTaskDelay(5);
err = mbc_master_set_descriptor(device_parameters, num_device_parameters);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller set descriptor fail, returns(0x%"PRIu32").",
(uint32_t)err);
ESP_LOGI(TAG, "Modbus master stack initialized...");
return err;
}
esp_err_t init_led_strip() {
// LED strip general initialization, according to your led board design
led_strip_config_t debug_led_config = {
.strip_gpio_num = CONFIG_PIN_DEBUG_LED, // The GPIO that connected to the LED strip's data line
.max_leds = 1, // The number of LEDs in the strip,
.led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip
.led_model = LED_MODEL_WS2812, // LED strip model
.flags.invert_out = false, // whether to invert the output signal
};
// LED strip backend configuration: RMT
led_strip_rmt_config_t debug_led_rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption
.resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency
.flags.with_dma = false, // DMA feature is available on ESP target like ESP32-S3
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&debug_led_config, &debug_led_rmt_config, &debug_led));
ESP_LOGI("led", "Created LED strip object with RMT backend for debug LED");
return ESP_OK;
}
esp_err_t init_eventloop() {
esp_err_t ret = esp_event_loop_create_default();
ESP_ERROR_CHECK(ret);
return ret;
}
esp_err_t init_wifi() {
esp_err_t ret;
ret = esp_netif_init();
ESP_ERROR_CHECK(ret);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ret = esp_wifi_init(&cfg);
ESP_ERROR_CHECK(ret);
ret = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &network_event_handler, NULL, NULL);
ESP_ERROR_CHECK(ret);
ret = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &network_event_handler, NULL, NULL);
ESP_ERROR_CHECK(ret);
// Initialize default station as network interface instance (esp-netif)
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
// Initialize and start WiFi
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASSWORD,
.scan_method = CONFIG_WIFI_FAST_SCAN ? WIFI_FAST_SCAN : WIFI_ALL_CHANNEL_SCAN,
.sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
.threshold.rssi = -127,
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
},
};
ret = esp_wifi_set_mode(WIFI_MODE_STA);
ESP_ERROR_CHECK(ret);
ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
ESP_ERROR_CHECK(ret);
ret = esp_wifi_start();
ESP_ERROR_CHECK(ret);
return ret;
}
esp_err_t init_nvs() {
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
return ret;
}
esp_err_t init_mqtt() {
esp_err_t ret;
const esp_mqtt_client_config_t mqtt_cfg = {
.broker = {
.address.uri = CONFIG_BROKER_URI,
.verification.crt_bundle_attach = esp_crt_bundle_attach
}
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
ret = esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, NULL);
ESP_ERROR_CHECK(ret);
ret = esp_mqtt_client_start(client);
ESP_ERROR_CHECK(ret);
mqtt_client = client;
return ret;
}

16
main/initializers.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <esp_err.h>
#include "mbcontroller.h"
#define MB_PORT_NUM (CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
#define MB_DEV_SPEED (CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
#define MB_PARITY (CONFIG_MB_UART_PARITY) // Parity used for Modbus communication
#define MB_STOP_BITS (CONFIG_MB_UART_STOP_BITS) // Number of stop bits used for UART communication
esp_err_t init_modbus(const mb_parameter_descriptor_t* device_parameters, const uint16_t num_device_parameters);
esp_err_t init_led_strip();
esp_err_t init_eventloop();
esp_err_t init_wifi();
esp_err_t init_nvs();
esp_err_t init_mqtt();

21
main/modbus_params.c Normal file
View File

@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*=====================================================================================
* Description:
* C file to define parameter storage instances
*====================================================================================*/
#include "modbus_params.h"
// Here are the user defined instances for device parameters packed by 1 byte
// These are keep the values that can be accessed from Modbus master
holding_reg_params_t holding_reg_params = { 0 };
input_reg_params_t input_reg_params = { 0 };
coil_reg_params_t coil_reg_params = { 0 };
discrete_reg_params_t discrete_reg_params = { 0 };

179
main/modbus_params.h Normal file
View File

@ -0,0 +1,179 @@
/*
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*=====================================================================================
* Description:
* The Modbus parameter structures used to define Modbus instances that
* can be addressed by Modbus protocol. Define these structures per your needs in
* your application. Below is just an example of possible parameters.
*====================================================================================*/
#ifndef _DEVICE_PARAMS
#define _DEVICE_PARAMS
#include <stdint.h>
// This file defines structure of modbus parameters which reflect correspond modbus address space
// for each modbus register type (coils, discreet inputs, holding registers, input registers)
#pragma pack(push, 1)
typedef struct
{
uint8_t discrete_input0:1;
uint8_t discrete_input1:1;
uint8_t discrete_input2:1;
uint8_t discrete_input3:1;
uint8_t discrete_input4:1;
uint8_t discrete_input5:1;
uint8_t discrete_input6:1;
uint8_t discrete_input7:1;
uint8_t discrete_input_port1:8;
} discrete_reg_params_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t coils_port0;
uint8_t coils_port1;
} coil_reg_params_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
float voltage_L1N; // 0
float voltage_L2N; // 2
float voltage_L3N; // 4
float current_L1; // 6
float current_L2; // 8
float current_L3; // 10
float active_power_L1; // 12
float active_power_L2; // 14
float active_power_L3; // 16
float apparent_power_L1; // 18
float apparent_power_L2; // 20
float apparent_power_L3; // 22
float reactive_power_L1; // 24
float reactive_power_L2; // 26
float reactive_power_L3; // 28
float power_factor_L1; // 30
float power_factor_L2; // 32
float power_factor_L3; // 34
float voltage_avg_LN; // 36
float current_avg; // 38
float current_sum; // 40
float active_power_sum; // 42
float apparent_power_sum; // 44
float reactive_power_sum; // 46
float power_factor_sum; // 48
float frequency; // 50
float active_energy_import; // 52
float active_energy_export; // 54
float voltage_L1L2; // 56
float voltage_L2L3; // 58
float voltage_L3L1; // 60
float voltage_avg_LL; // 62
float current_N; // 64
float active_energy_sum; // 66
float reactive_energy_sum; // 68
float active_energy_resettable_sum; // 70
float reactive_energy_resettable_sum; // 72
float active_energy_import_resettable; // 74
float active_energy_export_resettable; // 76
float active_energy_net; // 78
float active_power_import_sum; // 80
float active_power_export_sum; // 82
} input_reg_params_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
float sys_type; // 0
float pulse_width; // 2
float kppa; // 4
float parrity_and_stop; // 6
float modbus_addr; // 8
float pulse_const; // 10
float password; // 12
float baudrate; // 14
float auto_scroll_time; // 16
float backlight_time; // 18
float pulse_1_energy_type; // 20
uint16_t reset_history; // 22
uint32_t serial_number; // 24
uint16_t meter_type; // 28
uint16_t fw_version; // 30
} holding_reg_params_t;
#pragma pack(pop)
extern holding_reg_params_t holding_reg_params;
extern input_reg_params_t input_reg_params;
extern coil_reg_params_t coil_reg_params;
extern discrete_reg_params_t discrete_reg_params;
// Enumeration of all supported CIDs for device (used in parameter definition table)
enum {
CID_INP_U_L1N = 0, // Input voltage L1-N
CID_INP_U_L2N, // Input voltage L2-N
CID_INP_U_L3N, // Input voltage L3-N
CID_INP_I_L1, // Input current L1
CID_INP_I_L2, // Input current L2
CID_INP_I_L3, // Input current L3
CID_INP_P_L1, // Input active power L1
CID_INP_P_L2, // Input active power L2
CID_INP_P_L3, // Input active power L3
CID_INP_S_L1, // Input apparent power L1
CID_INP_S_L2, // Input apparent power L2
CID_INP_S_L3, // Input apparent power L3
CID_INP_Q_L1, // Input reactive power L1
CID_INP_Q_L2, // Input reactive power L2
CID_INP_Q_L3, // Input reactive power L3
CID_INP_PF_L1, // Input power factor L1
CID_INP_PF_L2, // Input power factor L2
CID_INP_PF_L3, // Input power factor L3
CID_INP_U_LN_AVG, // Input voltage L-N average
CID_INP_I_L_AVG, // Input current L average
CID_INP_I_SUM, // Input current sum
CID_INP_P_SUM, // Input active power sum
CID_INP_S_SUM, // Input apparent power sum
CID_INP_Q_SUM, // Input reactive power sum
CID_INP_PF_SUM, // Input power factor average
CID_INP_FREQ, // Input frequency
CID_INP_E_IMP, // Input energy import
CID_INP_E_EXP, // Input energy export
CID_INP_U_L1L2, // Input voltage L1-L2
CID_INP_U_L2L3, // Input voltage L2-L3
CID_INP_U_L3L1, // Input voltage L3-L1
CID_INP_U_LL_AVG, // Input voltage L-L average
CID_INP_I_N, // Input current N
CID_INP_E_SUM, // Input energy sum
CID_INP_Eq_SUM, // Input energy reactive sum
CID_INP_E_RESET_SUM, // Input resettable energy sum
CID_INP_Eq_RESET_SUM, // Input resettable reactive energy sum
CID_INP_E_RESET_IMP, // Input resettable energy import
CID_INP_E_RESET_EXP, // Input resettable energy export
CID_INP_E_NET, // Input net energy *import - export*
CID_INP_P_IMP_SUM, // Input power import sum
CID_INP_P_EXP_SUM, // Input power export sum
CID_HLD_SYS_TYPE, // System type (1 - Single phase, 3 - Three phase)
CID_HLD_PULSE_WIDTH, // Pulse width (60ms, 100ms, 200ms)
CID_HLD_KPPA, // Key Parameter Programming Authorization (0 - not authorized, 1 - authorized)
CID_HLD_PARITY_AND_STOP, // Parity and stop bits (0 - 1 stop bit, no parity, 1 - 1 stop bit, even parity, 2 - 1 stop bit, odd parity, 3 - 2 stop bits, no parity)
CID_HLD_MB_ADDR, // Modbus address (1-247)
CID_HLD_PULSE_CONST,// Pulse constant (0 - 1000 imp/kWh, 1 - 100 imp/kWh, 2 - 10 imp/kWh, 3 - 1 imp/kWh)
CID_HLD_PASSWD, // Password (0 - 9999, default 1000)
CID_HLD_BAUDRATE, // Baudrate (0 - 2400, 1 - 4800, 2 - 9600, 3 - 19200, 5 - 1200)
CID_HLD_AUTO_SCROLL_TIME, // Auto scroll time (0-60 - time in seconds)
CID_HLD_BACKLIGHT_TIME, // Backlight time (0-121, 0 - always on, 121, always off, 1-120 - time in seconds)
CID_HLD_PULSE_1_E_TYPE, // Pulse 1 energy type (1 - import, 2 - total, 3 - export)
CID_HLD_RST_HIST, // Reset history (0x0003 - reset energy info)
CID_HLD_SERIAL, // Serial number (uint32_t, read only)
CID_HLD_METER_TYPE, // Meter type (0x0089 - SDM72D-M-2, read only)
CID_HLD_METER_FIRMWARE // Meter firmware (Format XX.YY, XX = data[0], YY = data[1] , read only)
};
#endif // !defined(_DEVICE_PARAMS)

61
main/modbus_utils.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// 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 }
// BigEndian 32bit swap
// just swap the two 16 bit registers since the two bytes in each
// register are already swapped (BigEndian) as per modbus standard.
# define __beswap_32(x) \
(__extension__ \
({ uint32_t __bsx = (x); \
((((__bsx) >> 16) & 0xffff) | (((__bsx) & 0xffff) << 16)); }))
// 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("MB_UTILS", "Wrong parameter offset for CID #%d", param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
}
#ifdef __cplusplus
}
#endif

79
main/mqtt_event_handler.c Normal file
View File

@ -0,0 +1,79 @@
#include "mqtt_event_handler.h"
#include <esp_log.h>
#include <mqtt_client.h>
#include "sdkconfig.h"
/*
* @brief Event handler registered to receive MQTT events
*
* This function is called by the MQTT client event loop.
*
* @param handler_args user data registered to the event.
* @param base Event base for the handler(always MQTT Base in this example).
* @param event_id The id for the received event.
* @param event_data The data for the event, esp_mqtt_event_handle_t.
*/
void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
ESP_LOGD("mqtt", "Event dispatched from event loop base=%s, event_id=%" PRIu32, base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t) event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI("mqtt", "MQTT_EVENT_CONNECTED");
char id[6] = "00000";
sprintf(id, "%05d", CONFIG_FABMETER_ID);
// Register Meter
msg_id = esp_mqtt_client_publish(client, "fabmeter", id, 0, 0, 0);
ESP_LOGI("mqtt", "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI("mqtt", "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI("mqtt", "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI("mqtt", "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI("mqtt", "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI("mqtt", "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
char* topic = strndup(event->topic, event->topic_len);
ESP_LOGI("mqtt", "TOPIC=%s", topic);
free(topic);
// if (ret != ESP_OK) {
// ESP_LOGE("mqtt", "Error handling MQTT command: %s", esp_err_to_name(ret));
// }
break;
case MQTT_EVENT_ERROR:
ESP_LOGE("mqtt", "MQTT_EVENT_ERROR");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
ESP_LOGE("mqtt", "Last error code reported from esp-tls: 0x%x",
event->error_handle->esp_tls_last_esp_err);
ESP_LOGE("mqtt", "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err);
ESP_LOGE("mqtt", "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno,
strerror(event->error_handle->esp_transport_sock_errno));
} else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
ESP_LOGE("mqtt", "Connection refused error: 0x%x", event->error_handle->connect_return_code);
} else {
ESP_LOGW("mqtt", "Unknown error type: 0x%x", event->error_handle->error_type);
}
break;
default:
ESP_LOGI("mqtt", "Other event id:%d", event->event_id);
break;
}
}

23
main/mqtt_event_handler.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <esp_event.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* @brief Event handler registered to receive MQTT events
*
* This function is called by the MQTT client event loop.
*
* @param handler_args user data registered to the event.
* @param base Event base for the handler(always MQTT Base in this example).
* @param event_id The id for the received event.
* @param event_data The data for the event, esp_mqtt_event_handle_t.
*/
void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
#ifdef __cplusplus
}
#endif

28
main/net_event_handler.c Normal file
View File

@ -0,0 +1,28 @@
#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <led_strip.h>
#include "net_event_handler.h"
extern led_strip_handle_t debug_led;
void network_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0xFF, 0xFF, 0));
ESP_ERROR_CHECK(led_strip_refresh(debug_led));
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0xFF, 0xFF, 0));
ESP_ERROR_CHECK(led_strip_refresh(debug_led));
esp_wifi_connect();
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
ESP_LOGI("network", "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0, 0xFF, 0));
ESP_ERROR_CHECK(led_strip_refresh(debug_led));
vTaskDelay(pdMS_TO_TICKS(1000));
ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0, 0, 0));
ESP_ERROR_CHECK(led_strip_refresh(debug_led));
}
}

14
main/net_event_handler.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <esp_event.h>
#include <led_strip.h>
void network_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
#ifdef __cplusplus
}
#endif