I've modify _P027_INA219 plugin for energy meter F&F LE-01MW https://www.fif.com.pl/en/usage-electri ... -01mw.html and like to share the code to one who could verify this. It works for me on Wemos D1 PRO board with RS485 converter.
BR
Code: Select all
#ifdef USES_P185
// #######################################################################################################
// ############################# Plugin 185: F&F LE-01MW #################################################
// #######################################################################################################
/*
Circuit wiring
GPIO Setting 1 -> RX
GPIO Setting 2 -> TX
GPIO Setting 3 -> DE/RE pin for MAX485
Use 1kOhm in serie on datapins!
*/
#define PLUGIN_185
#define PLUGIN_ID_185 185
#define PLUGIN_NAME_185 "Energy - F&F LE-01MW [TESTING]"
#define PLUGIN_VALUENAME1_185 ""
#define Plugin_DEV_ID PCONFIG(0)
#define Plugin_DEV_ID_LABEL PCONFIG_LABEL(0)
#define Plugin_MODEL PCONFIG(1)
#define Plugin_MODEL_LABEL PCONFIG_LABEL(1)
#define Plugin_BAUDRATE PCONFIG(2)
#define Plugin_BAUDRATE_LABEL PCONFIG_LABEL(2)
#define Plugin_QUERY1 PCONFIG(3)
#define Plugin_QUERY2 PCONFIG(4)
#define Plugin_QUERY3 PCONFIG(5)
#define Plugin_QUERY4 PCONFIG(6)
#define Plugin_DEPIN CONFIG_PIN3
#define Plugin_NR_OUTPUT_VALUES VARS_PER_TASK
#define Plugin_QUERY1_CONFIG_POS 3
#define Plugin_QUERY_V 0
#define Plugin_QUERY_A 1
#define Plugin_QUERY_W 2
#define Plugin_QUERY_VAR 3
#define Plugin_QUERY_VA 4
#define Plugin_QUERY_Wh 5
#define Plugin_QUERY_varh 6
#define Plugin_QUERY_Pf 7
#define Plugin_QUERY_f 8
#define Plugin_NR_OUTPUT_OPTIONS 9 // Must be the last one
#define Plugin_DEV_ID_DFLT 1 // Modbus communication address
#define Plugin_MODEL_DFLT 0 //
#define Plugin_BAUDRATE_DFLT 4 // 19200 baud
#define Plugin_QUERY1_DFLT Plugin_QUERY_V
#define Plugin_QUERY2_DFLT Plugin_QUERY_A
#define Plugin_QUERY3_DFLT Plugin_QUERY_W
#define Plugin_QUERY4_DFLT Plugin_QUERY_Wh
#define Plugin_MEASUREMENT_INTERVAL 60000L
#include <ESPeasySerial.h>
#include "_Plugin_Helper.h"
#include "src/Helpers/Modbus_RTU.h"
struct Plugin_data_struct : public PluginTaskData_base {
Plugin_data_struct() {}
~Plugin_data_struct() {
reset();
}
void reset() {
modbus.reset();
}
bool init(const int16_t serial_rx, const int16_t serial_tx, int8_t dere_pin,
unsigned int baudrate, uint8_t modbusAddress) {
return modbus.init(serial_rx, serial_tx, baudrate, modbusAddress, dere_pin);
}
bool isInitialized() const {
return modbus.isInitialized();
}
ModbusRTU_struct modbus;
};
unsigned int _plugin_185_last_measurement = 0;
boolean Plugin_185(byte function, struct EventStruct *event, String& string) {
boolean success = false;
switch (function) {
case PLUGIN_DEVICE_ADD: {
Device[++deviceCount].Number = PLUGIN_ID_185;
Device[deviceCount].Type = DEVICE_TYPE_SERIAL_PLUS1; // connected through 3 datapins
Device[deviceCount].VType = SENSOR_TYPE_QUAD;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = Plugin_NR_OUTPUT_VALUES;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME: {
string = F(PLUGIN_NAME_185);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES: {
for (byte i = 0; i < VARS_PER_TASK; ++i) {
if (i < Plugin_NR_OUTPUT_VALUES) {
const byte pconfigIndex = i + Plugin_QUERY1_CONFIG_POS;
byte choice = PCONFIG(pconfigIndex);
safe_strncpy(
ExtraTaskSettings.TaskDeviceValueNames[i],
Plugin_valuename(choice, false),
sizeof(ExtraTaskSettings.TaskDeviceValueNames[i]));
} else {
ZERO_FILL(ExtraTaskSettings.TaskDeviceValueNames[i]);
}
}
break;
}
case PLUGIN_GET_DEVICEGPIONAMES: {
serialHelper_getGpioNames(event);
event->String3 = formatGpioName_output_optional("DE");
break;
}
case PLUGIN_WEBFORM_SHOW_CONFIG:
{
string += serialHelper_getSerialTypeLabel(event);
success = true;
break;
}
case PLUGIN_SET_DEFAULTS: {
Plugin_DEV_ID = Plugin_DEV_ID_DFLT;
Plugin_MODEL = Plugin_MODEL_DFLT;
Plugin_BAUDRATE = Plugin_BAUDRATE_DFLT;
Plugin_QUERY1 = Plugin_QUERY1_DFLT;
Plugin_QUERY2 = Plugin_QUERY2_DFLT;
Plugin_QUERY3 = Plugin_QUERY3_DFLT;
Plugin_QUERY4 = Plugin_QUERY4_DFLT;
success = true;
break;
}
case PLUGIN_WRITE: {
break;
}
case PLUGIN_WEBFORM_LOAD: {
serialHelper_webformLoad(event);
{
// Modbus parameters put in scope to make sure the String array will not keep memory occupied.
String options_baudrate[6];
for (int i = 0; i < 6; ++i) {
options_baudrate[i] = String(StorageValueToBaudrate(i));
}
addFormNumericBox(F("Modbus Address"), Plugin_DEV_ID_LABEL, Plugin_DEV_ID, 1,
247);
addFormSelector(F("Baud Rate"), Plugin_BAUDRATE_LABEL, 6, options_baudrate,
NULL, Plugin_BAUDRATE);
}
Plugin_data_struct *Plugin_data =
static_cast<Plugin_data_struct *>(getPluginTaskData(event->TaskIndex));
if ((nullptr != Plugin_data) && Plugin_data->isInitialized()) {
String detectedString = Plugin_data->modbus.detected_device_description;
if (detectedString.length() > 0) {
addFormNote(detectedString);
}
addRowLabel(F("Checksum (pass/fail/nodata)"));
uint32_t reads_pass, reads_crc_failed, reads_nodata;
Plugin_data->modbus.getStatistics(reads_pass, reads_crc_failed, reads_nodata);
String chksumStats;
chksumStats = reads_pass;
chksumStats += '/';
chksumStats += reads_crc_failed;
chksumStats += '/';
chksumStats += reads_nodata;
addHtml(chksumStats);
addFormSubHeader(F("Calibration"));
addFormSubHeader(F("Logged Values"));
ShowValueLoadPage(Plugin_QUERY_VAR, event);
ShowValueLoadPage(Plugin_QUERY_VA, event);
ShowValueLoadPage(Plugin_QUERY_Wh, event);
ShowValueLoadPage(Plugin_QUERY_varh, event);
ShowValueLoadPage(Plugin_QUERY_Pf, event);
ShowValueLoadPage(Plugin_QUERY_f, event);
// Checkbox is always presented unchecked.
// Must check and save to clear the stored accumulated values in the sensor.
addFormCheckBox(F("Clear logged values"), F("Plugin_clear_log"), false);
addFormNote(F("Will clear all logged values when checked and saved"));
}
{
// In a separate scope to free memory of String array as soon as possible
sensorTypeHelper_webformLoad_header();
String options[Plugin_NR_OUTPUT_OPTIONS];
for (int i = 0; i < Plugin_NR_OUTPUT_OPTIONS; ++i) {
options[i] = Plugin_valuename(i, true);
}
for (byte i = 0; i < Plugin_NR_OUTPUT_VALUES; ++i) {
const byte pconfigIndex = i + Plugin_QUERY1_CONFIG_POS;
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, Plugin_NR_OUTPUT_OPTIONS, options);
}
}
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE: {
serialHelper_webformSave(event);
// Save normal parameters
for (int i = 0; i < Plugin_QUERY1_CONFIG_POS; ++i) {
pconfig_webformSave(event, i);
}
// Save output selector parameters.
for (byte i = 0; i < Plugin_NR_OUTPUT_VALUES; ++i) {
const byte pconfigIndex = i + Plugin_QUERY1_CONFIG_POS;
const byte choice = PCONFIG(pconfigIndex);
sensorTypeHelper_saveOutputSelector(event, pconfigIndex, i, Plugin_valuename(choice, false));
}
Plugin_data_struct *Plugin_data =
static_cast<Plugin_data_struct *>(getPluginTaskData(event->TaskIndex));
if ((nullptr != Plugin_data) && Plugin_data->isInitialized()) {
// wstawic zapis do rejestrów jeśli trzeba
}
success = true;
break;
}
case PLUGIN_INIT: {
const int16_t serial_rx = CONFIG_PIN1;
const int16_t serial_tx = CONFIG_PIN2;
initPluginTaskData(event->TaskIndex, new (std::nothrow) Plugin_data_struct());
Plugin_data_struct *Plugin_data =
static_cast<Plugin_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr == Plugin_data) {
return success;
}
if (Plugin_data->init(serial_rx, serial_tx, Plugin_DEPIN,
StorageValueToBaudrate(Plugin_BAUDRATE),
Plugin_DEV_ID)) {
serialHelper_log_GpioDescription(serial_rx, serial_tx);
success = true;
} else {
clearPluginTaskData(event->TaskIndex);
}
break;
}
case PLUGIN_EXIT: {
clearPluginTaskData(event->TaskIndex);
success = true;
break;
}
case PLUGIN_READ: {
Plugin_data_struct *Plugin_data =
static_cast<Plugin_data_struct *>(getPluginTaskData(event->TaskIndex));
if ((nullptr != Plugin_data) && Plugin_data->isInitialized()) {
for (int i = 0; i < Plugin_NR_OUTPUT_VALUES; ++i) {
UserVar[event->BaseVarIndex + i] = ReadValue(PCONFIG(i + Plugin_QUERY1_CONFIG_POS), event);
delay(1);
}
success = true;
}
break;
}
}
return success;
}
String Plugin_valuename(byte value_nr, bool displayString) {
switch (value_nr) {
case Plugin_QUERY_V: return displayString ? F("Voltage (V)") : F("V");
case Plugin_QUERY_A: return displayString ? F("Current (A)") : F("A");
case Plugin_QUERY_W: return displayString ? F("Power (W)") : F("W");
case Plugin_QUERY_VAR: return displayString ? F("Power reactive (var)") : F("VAR");
case Plugin_QUERY_VA: return displayString ? F("Power apparent (VA)") : F("VA");
case Plugin_QUERY_Wh: return displayString ? F("Total active Energy (Wh)") : F("Wh");
case Plugin_QUERY_varh: return displayString ? F("Total reactive Energy (VARh)") : F("varh");
case Plugin_QUERY_Pf: return displayString ? F("Phase coef. ()") : F("Pf");
case Plugin_QUERY_f: return displayString ? F("Frequency (Hz)") : F("f");
}
return "";
}
int StorageValueToBaudrate(byte baudrate_setting) {
switch (baudrate_setting) {
case 0:
return 1200;
case 1:
return 2400;
case 2:
return 4800;
case 3:
return 9600;
case 4:
return 19200;
case 5:
return 38500;
}
return 19200;
}
float ReadValue(byte query, struct EventStruct *event) {
Plugin_data_struct *Plugin_data =
static_cast<Plugin_data_struct *>(getPluginTaskData(event->TaskIndex));
byte errorcode = 0;
if ((nullptr != Plugin_data) && Plugin_data->isInitialized()) {
switch (query) {
case Plugin_QUERY_V:
return Plugin_data->modbus.readHoldingRegister(0x0131, errorcode);
case Plugin_QUERY_A:
return Plugin_data->modbus.read_32b_HoldingRegister(0x0139);
case Plugin_QUERY_W:
return Plugin_data->modbus.read_32b_HoldingRegister(0x0140); //
case Plugin_QUERY_VAR:
return Plugin_data->modbus.read_32b_HoldingRegister(0x0148); //
case Plugin_QUERY_VA:
return Plugin_data->modbus.read_32b_HoldingRegister(0x0150); //
case Plugin_QUERY_Wh:
return Plugin_data->modbus.read_32b_HoldingRegister(0xA000); //
case Plugin_QUERY_varh:
return Plugin_data->modbus.read_32b_HoldingRegister(0xA01E);
case Plugin_QUERY_Pf:
return Plugin_data->modbus.readHoldingRegister(0x0158, errorcode) ; // *0.001 in GIU
case Plugin_QUERY_f:
return Plugin_data->modbus.readHoldingRegister(0x0130, errorcode) ; // * 0.01 in GUI
}
}
return 0.0;
}
void ShowValueLoadPage(byte query, struct EventStruct *event) {
addRowLabel(Plugin_valuename(query, true));
addHtml(String(ReadValue(query, event)));
}
#endif // USES_P185