Skip to content

Power Meter Reading with Schneider EasyLogic™ PM2200 series #6188

Description

@sensorthai

Hi,
I try to create new Power Meter Sensor for Schneider EasyLogic™ PM2200
but it reboot after send
Any one investigate for me ?

http://www.schneider-electric.com/resources/sites/SCHNEIDER_ELECTRIC/content/live/FAQS/307000/FA307813/en_US/Public_PM2xxx_PMC%20Register%20List_v1001.xlsx

`
00:00:00 WIF: Connecting to AP2 4G-CPE-020331 in mode 11N as SONOFF_CB3D6F...
00:00:04 WIF: Connected
00:00:04 HTP: Web server active on SONOFF_CB3D6Fwith IP address 192.168.100.195
00:00:05 MQT: Attempting connection...
00:00:05 MQT: Connected
00:00:06 MQT: v1/devices/me/LWT = Online (retained)
00:00:06 MQT: v1/devices/me/cmnd/rpc/request/ =
00:00:06 MQT: v1/devices/me/attributes = {"Module":"WiFi-EZ001","Version":"6.5.0(sonoff)","FallbackTopic":"cmnd/DVES_CB3D6F_fb/","GroupTopic":"capteur"}
00:00:06 MQT: v1/devices/me/attributes = {"WebServerMode":"Admin","Hostname":"SONOFF_CB3D6F","IPAddress":"192.168.100.195"}
00:00:06 MQT: v1/devices/me/attributes = {"RestartReason":"Fatal exception:0 flag:2 (EXCEPTION) epc1:0x40204900 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000000 depc:0x00000000"}
11:06:09 MQT: v1/devices/me/attributes = {"Uptime":"0T00:00:14","SleepMode":"Dynamic","Sleep":50,"LoadAvg":19,"AP":2,"SSId":"4G-CPE-020331","BSSId":"00:03:7F:86:6B:40","Channel":7,"RSSI":98,"LinkCount":1,"Downtime":"0T00:00:04"}
11:06:09 MQT: v1/devices/me/telemetry = {"ts":1565150769000 ,"values":{"ANALOG_A0":9,"PM_Total":51.241,"PM_Frequency":50.01,"PM_Active_L1":0,"PM_Active_L2":0,"PM_Active_L3":0,"PM_ReActive_L1":-0,"PM_ReActive_L2":0,"PM_ReActive_L3":0,"PM_PF_L1":null,"PM_PF_L2":null,"PM_PF_L3":null,"PM_Volt_L1":119,"PM_Volt_L2":0,"PM_Volt_L3":120,"PM_Current_L1":0.000,"PM_Current_L2":0.000,"PM_Current_L3":0.000}}
11:06:10 MQT: Attempting connection...
11:06:10 MQT: Connected
11:06:10 MQT: v1/devices/me/LWT = Online (retained)
11:06:10 MQT: v1/devices/me/cmnd/rpc/request/ =

Exception (0):
epc1=0x40204900 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ctx: sys
sp: 3ffffc30 end: 3fffffb0 offset: 01a0

stack>>>
3ffffdd0: 40107402 00dd9999 00000019 00000100
3ffffde0: c0036035 401003ca 00000001 00000000
3ffffdf0: 00000000 40100197 00000000 00000022
3ffffe00: 3fffc200 401073c8 3fffc258 4000050c
3ffffe10: 4000437d 00000030 00000018 ffffffff
3ffffe20: 60000200 00000008 00021700 80000000
3ffffe30: 20000000 3fff7bf8 80000000 200fc280
3ffffe40: 80000000 3fffc6fc 3ffeef74 3fff7bfc
3ffffe50: 00000074 000fc280 60000600 00000030
3ffffe60: ffffffff 0000000c 00000000 4020490f
3ffffe70: 4010746d 00080000 00000000 4010745c
3ffffe80: c0036035 00bdf6ba 00000000 4000050c
3ffffe90: 00000000 00000000 0000001f 40104301
3ffffea0: 4000050c 401073c8 3fffc258 4000050c
3ffffeb0: 40000f68 00000030 00000014 ffffffff
3ffffec0: 40000f58 00000000 00000020 00000000
3ffffed0: 00000000 4023a558 00000000 bfffffff
3ffffee0: ffffffff 3fffc6fc 3ffeef74 3fffdab0
3ffffef0: 00000000 3fffdcb0 3ffef030 00000030
3fffff00: 00000000 400042db 3ffead71 60000600
3fffff10: 40004b31 3fff797c 000002f4 000fc000
3fffff20: 40104866 3ffef020 3ffeeec0 401070c8
3fffff30: 4023a029 3ffeeec0 3ffef020 020649ff
3fffff40: 3fff797c 00001000 4023a4be 00000008
3fffff50: 3ffef020 3ffeef74 4023a56b 3ffeef74
3fffff60: 3ffef020 00a1ce43 4023a480 000000f2
3fffff70: 4023c791 3ffeef74 3ffef020 020623f8
3fffff80: 4023c7d6 3fffdab0 00000000 3fffdcb0
3fffff90: 3ffef038 00000000 40000f65 3fffdab0
3fffffa0: 40000f49 00003603 3fffdab0 40000f49
<<<stack<<<

ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v3fff3e48
~ld

00:00:00 Project capteur Capteur Version 6.5.0(sonoff)-2_3_0

ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v3fff3e48
~ld
`

here is my code which modify from xsns_25_sdm630.ino

`/*
xsns_25_pm2200.ino - Eastron pm2200-Modbus energy meter support for Sonoff-Tasmota

Copyright (C) 2019 Gennaro Tortone

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
*/

#ifdef USE_PM2200

/*********************************************************************************************\

#define XSNS_91 91

#include <TasmotaSerial.h>

TasmotaSerial *PM2200Serial;

uint8_t pm2200_type = 1;
//uint8_t pm2200_state = 0;

float pm2200_voltage[] = {0,0,0};
float pm2200_current[] = {0,0,0};
float pm2200_active_power[] = {0,0,0};
float pm2200_reactive_power[] = {0,0,0};
float pm2200_power_factor[] = {0,0,0};
float pm2200_energy_total = 0;
float pm2200_frequency = 0;

bool PM2200_ModbusReceiveReady(void)
{
return (PM2200Serial->available() > 1);
}

void PM2200_ModbusSend(uint8_t function_code, uint16_t start_address, uint16_t register_count)
{
uint8_t frame[8];

frame[0] = 0x01; // default PM2200 Modbus address
frame[1] = function_code;

frame[2] = (uint8_t)(start_address >> 8);
frame[3] = (uint8_t)(start_address);
frame[4] = (uint8_t)(register_count >> 8);
frame[5] = (uint8_t)(register_count);

uint16_t crc = PM2200_calculateCRC(frame, 6); // calculate out crc only from first 6 bytes
frame[6] = lowByte(crc);
frame[7] = highByte(crc);

while (PM2200Serial->available() > 0) { // read serial if any old data is available
PM2200Serial->read();
}

PM2200Serial->flush();
PM2200Serial->write(frame, sizeof(frame));
}

uint8_t PM2200_ModbusReceive(float *value)
{
uint8_t buffer[9];

*value = NAN;
uint8_t len = 0;
while (PM2200Serial->available() > 0) {
buffer[len++] = (uint8_t)PM2200Serial->read();
}

if (len < 9)
return 3; // SDM_ERR_NOT_ENOUGHT_BYTES

if (len == 9) {

if (buffer[0] == 0x01 && buffer[1] == 0x03 && buffer[2] == 4) {   // check node number, op code and reply bytes count hjk347

  if((PM2200_calculateCRC(buffer, 7)) == ((buffer[8] << 8) | buffer[7])) {  //calculate crc from first 7 bytes and compare with received crc (bytes 7 & 8)

    ((uint8_t*)value)[3] = buffer[3];
    ((uint8_t*)value)[2] = buffer[4];
    ((uint8_t*)value)[1] = buffer[5];
    ((uint8_t*)value)[0] = buffer[6];

  } else return 1; // SDM_ERR_CRC_ERROR

} else return 2;  // SDM_ERR_WRONG_BYTES

}

return 0; // SDM_ERR_NO_ERROR
}

uint16_t PM2200_calculateCRC(uint8_t *frame, uint8_t num)
{
uint16_t crc, flag;
crc = 0xFFFF;
for (uint8_t i = 0; i < num; i++) {
crc ^= frame[i];
for (uint8_t j = 8; j; j--) {
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
} else { // Else LSB is not set
crc >>= 1; // Just shift right
}
}
}
return crc;
}

/*********************************************************************************************/

const uint16_t pm2200_start_addresses[] {
0x0BCB, // L1 - Voltage A-B [V] 3020
0x0BCD, // L2 - Voltage B-C [V] 3022
0x0BCF, // L3 - Voltage C-A [V] 3024
0x0BB7, // L1 - Current A [A] 3000
0x0BB9, // L2 - Current B [A] 3002
0x0BBB, // L3 - Current C [A] 3004
0x0BED, // L1 - Active Power A [kW] 3054
0x0BEF, // L2 - Active Power B [kW] 3056
0x0BF1, // L3 - Active Power C [kW] 3058
0x0B5F, // L1 - Reactive Power A [kVAR] 3062
0x0BF5, // L2 - Reactive Power B [kVAR] 3064
0x0BF9, // L3 - Reactive Power C [kVAR] 3066
0x0C05, // L1 - Power Factor A 3078
0x0C07, // L2 - Power Factor B 3080
0x0C09, // L3 - Power Factor C 3082
0x0A8B, // Active Power Total 3000
0x0C25 // Frequency

};

uint8_t pm2200_read_state = 0;
uint8_t pm2200_send_retry = 0;

void PM2200250ms(void) // Every 250 mSec
{
// pm2200_state++;
// if (6 == pm2200_state) { // Every 300 mSec
// pm2200_state = 0;

float value = 0;
bool data_ready = PM2200_ModbusReceiveReady();

if (data_ready) {
  uint8_t error = PM2200_ModbusReceive(&value);
  if (error) {
    snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "PM2200 response error %d"), error);
    AddLog(LOG_LEVEL_DEBUG);
  } else {

    switch(pm2200_read_state) {
      case 0:
        pm2200_voltage[0] = value;
        break;

      case 1:
        pm2200_voltage[1] = value;
        break;

      case 2:
        pm2200_voltage[2] = value;
        break;

      case 3:
        pm2200_current[0] = value;
        break;

      case 4:
        pm2200_current[1] = value;
        break;

      case 5:
        pm2200_current[2] = value;
        break;

      case 6:
        pm2200_active_power[0] = value;
        break;

      case 7:
        pm2200_active_power[1] = value;
        break;

      case 8:
        pm2200_active_power[2] = value;
        break;

      case 9:
        pm2200_reactive_power[0] = value;
        break;

      case 10:
        pm2200_reactive_power[1] = value;
        break;

      case 11:
        pm2200_reactive_power[2] = value;
        break;

      case 12:
        pm2200_power_factor[0] = value;
        break;

      case 13:
        pm2200_power_factor[1] = value;
        break;

      case 14:
        pm2200_power_factor[2] = value;
        break;

      case 15:
        pm2200_energy_total = value;
        break;

      case 16:
        pm2200_frequency = value;
        break;
    } // end switch

    pm2200_read_state++;

    if (sizeof(pm2200_start_addresses)/2 == pm2200_read_state) {
      pm2200_read_state = 0;
    }
  }
} // end data ready

if (0 == pm2200_send_retry || data_ready) {
  pm2200_send_retry = 5;
   PM2200_ModbusSend(0x03, pm2200_start_addresses[pm2200_read_state], 2);
} else {
  pm2200_send_retry--;
}

// } // end 300 ms
}

void PM2200Init(void)
{
pm2200_type = 0;
if ((pin[GPIO_PM2200_RX] < 99) && (pin[GPIO_PM2200_TX] < 99)) {
PM2200Serial = new TasmotaSerial(pin[GPIO_PM2200_RX], pin[GPIO_PM2200_TX], 1);
#ifdef PM2200_SPEED
if (PM2200Serial->begin(PM2200_SPEED)) {
#else
if (PM2200Serial->begin(2400)) {
#endif
if (PM2200Serial->hardwareSerial()) { ClaimSerial(); }
pm2200_type = 1;
}
}
}

#ifdef USE_WEBSERVER
const char HTTP_SNS_PM2200_DATA[] PROGMEM = "%s"
"{s}PM2200 " D_VOLTAGE "{m}%s/%s/%s " D_UNIT_VOLT "{e}"
"{s}PM2200 " D_CURRENT "{m}%s/%s/%s " D_UNIT_AMPERE "{e}"
"{s}PM2200 " D_POWERUSAGE_ACTIVE "{m}%s/%s/%s k" D_UNIT_WATT "{e}"
"{s}PM2200 " D_POWERUSAGE_REACTIVE "{m}%s/%s/%s k" D_UNIT_VAR "{e}"
"{s}PM2200 " D_POWER_FACTOR "{m}%s/%s/%s{e}"
"{s}PM2200 " D_ENERGY_TOTAL "{m}%s k" D_UNIT_WATTHOUR "{e}"
"{s}PM2200 Frequency {m}%s Hz {e}";
#endif // USE_WEBSERVER

void PM2200Show(bool json)
{
char voltage_l1[33];
dtostrfd(pm2200_voltage[0], Settings.flag2.voltage_resolution, voltage_l1);
char voltage_l2[33];
dtostrfd(pm2200_voltage[1], Settings.flag2.voltage_resolution, voltage_l2);
char voltage_l3[33];
dtostrfd(pm2200_voltage[2], Settings.flag2.voltage_resolution, voltage_l3);
char current_l1[33];
dtostrfd(pm2200_current[0], Settings.flag2.current_resolution, current_l1);
char current_l2[33];
dtostrfd(pm2200_current[1], Settings.flag2.current_resolution, current_l2);
char current_l3[33];
dtostrfd(pm2200_current[2], Settings.flag2.current_resolution, current_l3);
char active_power_l1[33];
dtostrfd(pm2200_active_power[0], Settings.flag2.wattage_resolution, active_power_l1);
char active_power_l2[33];
dtostrfd(pm2200_active_power[1], Settings.flag2.wattage_resolution, active_power_l2);
char active_power_l3[33];
dtostrfd(pm2200_active_power[2], Settings.flag2.wattage_resolution, active_power_l3);
char reactive_power_l1[33];
dtostrfd(pm2200_reactive_power[0], Settings.flag2.wattage_resolution, reactive_power_l1);
char reactive_power_l2[33];
dtostrfd(pm2200_reactive_power[1], Settings.flag2.wattage_resolution, reactive_power_l2);
char reactive_power_l3[33];
dtostrfd(pm2200_reactive_power[2], Settings.flag2.wattage_resolution, reactive_power_l3);
char power_factor_l1[33];
dtostrfd(pm2200_power_factor[0], 2, power_factor_l1);
char power_factor_l2[33];
dtostrfd(pm2200_power_factor[1], 2, power_factor_l2);
char power_factor_l3[33];
dtostrfd(pm2200_power_factor[2], 2, power_factor_l3);
char energy_total[33];
dtostrfd(pm2200_energy_total, Settings.flag2.energy_resolution, energy_total);
char energy_frequency[33];
dtostrfd(pm2200_frequency, 2, energy_frequency);

if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"PM_Total":%s,"PM_Frequency":%s,"PM_Active_L1":%s,"PM_Active_L2":%s,"PM_Active_L3":%s,"PM_ReActive_L1":%s,"PM_ReActive_L2":%s,"PM_ReActive_L3":%s,"PM_PF_L1":%s,"PM_PF_L2":%s,"PM_PF_L3":%s,"PM_Volt_L1":%s,"PM_Volt_L2":%s,"PM_Volt_L3":%s,"PM_Current_L1":%s,"PM_Current_L2":%s,"PM_Current_L3":%s"),
mqtt_data, energy_total,energy_frequency,
active_power_l1, active_power_l2, active_power_l3,
// "4000","5000","6000",
reactive_power_l1, reactive_power_l2, reactive_power_l3,
// "1000","2000","3000",
power_factor_l1, power_factor_l2, power_factor_l3,
// "1.1","1.2","1.3",
voltage_l1, voltage_l2, voltage_l3,
current_l1, current_l2, current_l3);

#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_PM2200_DATA, mqtt_data,
voltage_l1, voltage_l2, voltage_l3, current_l1, current_l2, current_l3,
active_power_l1, active_power_l2, active_power_l3,
reactive_power_l1, reactive_power_l2, reactive_power_l3,
power_factor_l1, power_factor_l2, power_factor_l3, energy_total,energy_frequency);
#endif // USE_WEBSERVER
}
}

/*********************************************************************************************\

  • Interface
    *********************************************************************************************/

bool Xsns91(byte function)
{
bool result = false;

if (pm2200_type) {
switch (function) {
case FUNC_INIT:
PM2200Init();
break;
case FUNC_EVERY_250_MSECOND:
//case FUNC_EVERY_SECOND:
PM2200250ms();
break;
case FUNC_JSON_APPEND:
PM2200Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_APPEND:
PM2200Show(0);
break;
#endif // USE_WEBSERVER
}
}
return result;
}

#endif
`

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementType - Enhancement that will be worked on

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions