mirror of https://github.com/arendst/Tasmota.git
Add command ModuleAddress 1/2/3
Add command ModuleAddress 1/2/3 to set Pzem module address when a single module is connected (#2315)
This commit is contained in:
parent
d193b8cb1a
commit
7b70c042bd
|
@ -12,6 +12,7 @@
|
|||
* Add initial support for up to three PZEM-004T on serial connection with addresses x.x.x.1 (default), 2 and 3 (#2315)
|
||||
* Add initial support for up to three PZEM-003/-017 on serial modbus connection with addresses 1 (default), 2 and 3 (#2315)
|
||||
* Add driver USE_SDM630_2 as future replacement for USE_SDM630 - Pls test and report
|
||||
* Add command ModuleAddress 1/2/3 to set Pzem module address when a single module is connected (#2315)
|
||||
*
|
||||
* 6.6.0.11 20190907
|
||||
* Change Settings crc calculation allowing short term backward compatibility
|
||||
|
|
|
@ -279,6 +279,8 @@ enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FU
|
|||
FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_BUTTON_PRESSED,
|
||||
FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, FUNC_WEB_ADD_HANDLER, FUNC_SET_CHANNELS};
|
||||
|
||||
enum AddressConfigSteps { ADDR_IDLE, ADDR_RECEIVE, ADDR_SEND };
|
||||
|
||||
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
|
||||
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_MAX };
|
||||
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote";
|
||||
|
|
|
@ -37,14 +37,15 @@
|
|||
#define D_CMND_VOLTAGECAL "VoltageCal"
|
||||
#define D_CMND_CURRENTCAL "CurrentCal"
|
||||
#define D_CMND_TARIFF "Tariff"
|
||||
#define D_CMND_MODULEADDRESS "ModuleAddress"
|
||||
|
||||
enum EnergyCommands {
|
||||
CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL,
|
||||
CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET };
|
||||
CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS };
|
||||
|
||||
const char kEnergyCommands[] PROGMEM = "|" // No prefix
|
||||
D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|"
|
||||
D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|"
|
||||
D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_MODULEADDRESS "|"
|
||||
#ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|"
|
||||
#ifdef USE_ENERGY_POWER_LIMIT
|
||||
|
@ -57,7 +58,7 @@ const char kEnergyCommands[] PROGMEM = "|" // No prefix
|
|||
|
||||
void (* const EnergyCommand[])(void) PROGMEM = {
|
||||
&CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal,
|
||||
&CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet,
|
||||
&CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet, &CmndModuleAddress,
|
||||
#ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
&CmndPowerDelta, &CmndPowerLow, &CmndPowerHigh, &CmndVoltageLow, &CmndVoltageHigh, &CmndCurrentLow, &CmndCurrentHigh,
|
||||
#ifdef USE_ENERGY_POWER_LIMIT
|
||||
|
@ -614,6 +615,16 @@ void CmndFrequencySet(void)
|
|||
}
|
||||
}
|
||||
|
||||
void CmndModuleAddress(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy.phase_count)) {
|
||||
Energy.command_code = CMND_MODULEADDRESS;
|
||||
if (XnrgCall(FUNC_COMMAND)) { // Module address
|
||||
ResponseCmndDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
void CmndPowerDelta(void)
|
||||
{
|
||||
|
|
|
@ -59,8 +59,9 @@ TasmotaSerial *PzemSerial = nullptr;
|
|||
struct PZEM {
|
||||
float energy = 0;
|
||||
uint8_t send_retry = 0;
|
||||
uint8_t read_state = 0;
|
||||
uint8_t read_state = 0; // Set address
|
||||
uint8_t phase = 0;
|
||||
uint8_t address = 0;
|
||||
} Pzem;
|
||||
|
||||
struct PZEMCommand {
|
||||
|
@ -70,8 +71,6 @@ struct PZEMCommand {
|
|||
uint8_t crc;
|
||||
};
|
||||
|
||||
IPAddress pzem_ip(192, 168, 1, 1);
|
||||
|
||||
uint8_t PzemCrc(uint8_t *data)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
|
@ -86,10 +85,10 @@ void PzemSend(uint8_t cmd)
|
|||
PZEMCommand pzem;
|
||||
|
||||
pzem.command = cmd;
|
||||
for (uint32_t i = 0; i < sizeof(pzem.addr) -1; i++) {
|
||||
pzem.addr[i] = pzem_ip[i];
|
||||
}
|
||||
pzem.addr[3] = pzem_ip[3] + Pzem.phase;
|
||||
pzem.addr[0] = 0; // Address 0.0.0.1
|
||||
pzem.addr[1] = 0;
|
||||
pzem.addr[2] = 0;
|
||||
pzem.addr[3] = ((PZEM_SET_ADDRESS == cmd) && Pzem.address) ? Pzem.address : 1 + Pzem.phase;
|
||||
pzem.data = 0;
|
||||
|
||||
uint8_t *bytes = (uint8_t*)&pzem;
|
||||
|
@ -97,6 +96,8 @@ void PzemSend(uint8_t cmd)
|
|||
|
||||
PzemSerial->flush();
|
||||
PzemSerial->write(bytes, sizeof(pzem));
|
||||
|
||||
Pzem.address = 0;
|
||||
}
|
||||
|
||||
bool PzemReceiveReady(void)
|
||||
|
@ -209,6 +210,9 @@ void PzemEvery200ms(void)
|
|||
if (Pzem.phase >= Energy.phase_count) {
|
||||
Pzem.phase = 0;
|
||||
}
|
||||
if (Pzem.address) {
|
||||
Pzem.read_state = 0; // Set address
|
||||
}
|
||||
Pzem.send_retry = 5;
|
||||
PzemSend(pzem_commands[Pzem.read_state]);
|
||||
}
|
||||
|
@ -230,6 +234,7 @@ void PzemSnsInit(void)
|
|||
}
|
||||
Energy.phase_count = 3; // Start off with three phases
|
||||
Pzem.phase = 2;
|
||||
Pzem.read_state = 1;
|
||||
} else {
|
||||
energy_flg = ENERGY_NONE;
|
||||
}
|
||||
|
@ -242,6 +247,18 @@ void PzemDrvInit(void)
|
|||
}
|
||||
}
|
||||
|
||||
bool PzemCommand(void)
|
||||
{
|
||||
bool serviced = true;
|
||||
|
||||
if (CMND_MODULEADDRESS == Energy.command_code) {
|
||||
Pzem.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3
|
||||
}
|
||||
else serviced = false; // Unknown command
|
||||
|
||||
return serviced;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
@ -254,6 +271,9 @@ bool Xnrg03(uint8_t function)
|
|||
case FUNC_EVERY_200_MSECOND:
|
||||
if (PzemSerial) { PzemEvery200ms(); }
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = PzemCommand();
|
||||
break;
|
||||
case FUNC_INIT:
|
||||
PzemSnsInit();
|
||||
break;
|
||||
|
|
|
@ -40,6 +40,8 @@ struct PZEMAC {
|
|||
float energy = 0;
|
||||
uint8_t send_retry = 0;
|
||||
uint8_t phase = 0;
|
||||
uint8_t address = 0;
|
||||
uint8_t address_step = ADDR_IDLE;
|
||||
} PzemAc;
|
||||
|
||||
void PzemAcEverySecond(void)
|
||||
|
@ -49,27 +51,34 @@ void PzemAcEverySecond(void)
|
|||
if (data_ready) {
|
||||
uint8_t buffer[30]; // At least 5 + (2 * 10) = 25
|
||||
|
||||
uint8_t error = PzemAcModbus->ReceiveBuffer(buffer, 10);
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, (buffer[2]) ? buffer[2] +5 : sizeof(buffer));
|
||||
uint8_t registers = 10;
|
||||
if (ADDR_RECEIVE == PzemAc.address_step) {
|
||||
registers = 2; // Need 1 byte extra as response is F8 06 00 02 00 01 FD A3
|
||||
PzemAc.address_step--;
|
||||
}
|
||||
uint8_t error = PzemAcModbus->ReceiveBuffer(buffer, registers);
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, PzemAcModbus->ReceiveCount());
|
||||
|
||||
if (error) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PAC: PzemAc %d error %d"), PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, error);
|
||||
} else {
|
||||
Energy.data_valid = 0;
|
||||
if (10 == registers) {
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
||||
// 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34
|
||||
// Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc--
|
||||
Energy.voltage[PzemAc.phase] = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V
|
||||
Energy.current[PzemAc.phase] = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; // 4294967.000 A
|
||||
Energy.active_power[PzemAc.phase] = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; // 429496729.0 W
|
||||
Energy.frequency[PzemAc.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz
|
||||
Energy.power_factor[PzemAc.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
||||
// 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34
|
||||
// Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc--
|
||||
Energy.voltage[PzemAc.phase] = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V
|
||||
Energy.current[PzemAc.phase] = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; // 4294967.000 A
|
||||
Energy.active_power[PzemAc.phase] = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; // 429496729.0 W
|
||||
Energy.frequency[PzemAc.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz
|
||||
Energy.power_factor[PzemAc.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00
|
||||
|
||||
PzemAc.energy += (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]); // 4294967295 Wh
|
||||
if (PzemAc.phase == Energy.phase_count -1) {
|
||||
EnergyUpdateTotal(PzemAc.energy, false);
|
||||
PzemAc.energy = 0;
|
||||
PzemAc.energy += (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]); // 4294967295 Wh
|
||||
if (PzemAc.phase == Energy.phase_count -1) {
|
||||
EnergyUpdateTotal(PzemAc.energy, false);
|
||||
PzemAc.energy = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +89,12 @@ void PzemAcEverySecond(void)
|
|||
PzemAc.phase = 0;
|
||||
}
|
||||
PzemAc.send_retry = ENERGY_WATCHDOG;
|
||||
PzemAcModbus->Send(PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, 0x04, 0, 10);
|
||||
if (ADDR_SEND == PzemAc.address_step) {
|
||||
PzemAcModbus->Send(0xF8, 0x06, 0x0002, (uint16_t)PzemAc.address);
|
||||
PzemAc.address_step--;
|
||||
} else {
|
||||
PzemAcModbus->Send(PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, 0x04, 0, 10);
|
||||
}
|
||||
}
|
||||
else {
|
||||
PzemAc.send_retry--;
|
||||
|
@ -110,6 +124,19 @@ void PzemAcDrvInit(void)
|
|||
}
|
||||
}
|
||||
|
||||
bool PzemAcCommand(void)
|
||||
{
|
||||
bool serviced = true;
|
||||
|
||||
if (CMND_MODULEADDRESS == Energy.command_code) {
|
||||
PzemAc.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3
|
||||
PzemAc.address_step = ADDR_SEND;
|
||||
}
|
||||
else serviced = false; // Unknown command
|
||||
|
||||
return serviced;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
@ -122,6 +149,9 @@ bool Xnrg05(uint8_t function)
|
|||
case FUNC_ENERGY_EVERY_SECOND:
|
||||
if (uptime > 4) { PzemAcEverySecond(); } // Fix start up issue #5875
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = PzemAcCommand();
|
||||
break;
|
||||
case FUNC_INIT:
|
||||
PzemAcSnsInit();
|
||||
break;
|
||||
|
|
|
@ -40,6 +40,8 @@ struct PZEMDC {
|
|||
float energy = 0;
|
||||
uint8_t send_retry = 0;
|
||||
uint8_t channel = 0;
|
||||
uint8_t address = 0;
|
||||
uint8_t address_step = ADDR_IDLE;
|
||||
} PzemDc;
|
||||
|
||||
void PzemDcEverySecond(void)
|
||||
|
@ -49,25 +51,32 @@ void PzemDcEverySecond(void)
|
|||
if (data_ready) {
|
||||
uint8_t buffer[26]; // At least 5 + (2 * 8) = 21
|
||||
|
||||
uint8_t error = PzemDcModbus->ReceiveBuffer(buffer, 8);
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, sizeof(buffer));
|
||||
uint8_t registers = 8;
|
||||
if (ADDR_RECEIVE == PzemDc.address_step) {
|
||||
registers = 2; // Need 1 byte extra as response is F8 06 00 02 00 01 FD A3
|
||||
PzemDc.address_step--;
|
||||
}
|
||||
uint8_t error = PzemDcModbus->ReceiveBuffer(buffer, registers);
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, PzemDcModbus->ReceiveCount());
|
||||
|
||||
if (error) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PDC: PzemDc %d error %d"), PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, error);
|
||||
} else {
|
||||
Energy.data_valid = 0;
|
||||
if (8 == registers) {
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||
// 01 04 10 05 40 00 0A 00 0D 00 00 00 02 00 00 00 00 00 00 D6 29
|
||||
// Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc--
|
||||
Energy.voltage[PzemDc.channel] = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V
|
||||
Energy.current[PzemDc.channel] = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A
|
||||
Energy.active_power[PzemDc.channel] = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||
// 01 04 10 05 40 00 0A 00 0D 00 00 00 02 00 00 00 00 00 00 D6 29
|
||||
// Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc--
|
||||
Energy.voltage[PzemDc.channel] = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V
|
||||
Energy.current[PzemDc.channel] = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A
|
||||
Energy.active_power[PzemDc.channel] = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; // 429496729.0 W
|
||||
|
||||
PzemDc.energy += (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]); // 4294967295 Wh
|
||||
if (PzemDc.channel == Energy.phase_count -1) {
|
||||
EnergyUpdateTotal(PzemDc.energy, false);
|
||||
PzemDc.energy = 0;
|
||||
PzemDc.energy += (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]); // 4294967295 Wh
|
||||
if (PzemDc.channel == Energy.phase_count -1) {
|
||||
EnergyUpdateTotal(PzemDc.energy, false);
|
||||
PzemDc.energy = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +87,12 @@ void PzemDcEverySecond(void)
|
|||
PzemDc.channel = 0;
|
||||
}
|
||||
PzemDc.send_retry = ENERGY_WATCHDOG;
|
||||
PzemDcModbus->Send(PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, 0x04, 0, 8);
|
||||
if (ADDR_SEND == PzemDc.address_step) {
|
||||
PzemDcModbus->Send(0xF8, 0x06, 0x0002, (uint16_t)PzemDc.address);
|
||||
PzemDc.address_step--;
|
||||
} else {
|
||||
PzemDcModbus->Send(PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, 0x04, 0, 8);
|
||||
}
|
||||
}
|
||||
else {
|
||||
PzemDc.send_retry--;
|
||||
|
@ -109,6 +123,19 @@ void PzemDcDrvInit(void)
|
|||
}
|
||||
}
|
||||
|
||||
bool PzemDcCommand(void)
|
||||
{
|
||||
bool serviced = true;
|
||||
|
||||
if (CMND_MODULEADDRESS == Energy.command_code) {
|
||||
PzemDc.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3
|
||||
PzemDc.address_step = ADDR_SEND;
|
||||
}
|
||||
else serviced = false; // Unknown command
|
||||
|
||||
return serviced;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
@ -121,6 +148,9 @@ bool Xnrg06(uint8_t function)
|
|||
case FUNC_ENERGY_EVERY_SECOND:
|
||||
if (uptime > 4) { PzemDcEverySecond(); } // Fix start up issue #5875
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = PzemDcCommand();
|
||||
break;
|
||||
case FUNC_INIT:
|
||||
PzemDcSnsInit();
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue