gemu2015 / Sonoff-Tasmota

Tasmota Fork TCS34725,PN532_i2,ccc1101 Moritz support,m5stack 4,7 epaper, hotplug drivers
GNU General Public License v3.0
24 stars 19 forks source link

PZEM Driver #11

Open meingraham opened 4 years ago

meingraham commented 4 years ago

@gemu2015

Some discussion on Discord re: 3-phase power monitoring with Tasmota. In particular, using multiple inexpensive PZEM-004T modules. I suggested that perhaps the smart meter interface you added recently might be a means to achieve that. The main issue that most mentioned is the advanced skill level required. Understanding how to compile all the appropriate features, understanding the meter protocol, coding the appropriate descriptor, etc. Although the smart meter interface provide a great deal of flexibility and expandability, it may be too much for "average" users.

For users who just want a black box solution, the thought of enhancing the current PZEM driver to add addressability of multiple modules was considered. Do you think this is feasible?

ESPHome seems to be supporting more of this type of capability, I don't care for ESPHome, but many high profile users seems to be considering it over Tasmota, especially if they are Home Assistant users. With the advent of more ESP32 based devices (e.g., https://circuitsetup.us/index.php/product/expandable-6-channel-esp32-energy-meter/), ESPHome is making an inroads since they support the ESP32.

Anyway, I thought I'd reach out to get your thoughts about enhancing the PZEM driver for "simple" 3-phase monitors.

Regards.

Mike

P.S. I don't even have a need for a 3-phase monitor :wink: But there have been several threads with this topic so I think it is relevant.

gemu2015 commented 4 years ago

@meingraham

multiple PZEM support could be easily added with a few minor modifications to my driver.

according the complexity of coding the descriptors you are true, but once you have a descriptor it is simply a copy and paste operation.

i will think of the 3 module expansion and once ready i will make a pr. since i don't have any PZEM someone who has should try the driver then. i can provide a descriptor from the data sheet to start with

Gerhard

gemu2015 commented 4 years ago

@meingraham i have implemented a one phase PZEM decoder now. if you know someone to test it he may download my fork and give it a try. if it works i will implement the 3 phases.

greetings

Gerhard

>D

>B ->sensor53 r

>M 1 +1,3,p,0,9600,PZEM1,1,1,b0c0a8010100,b1c0a8010100,b2c0a8010100,b3c0a8010100

1,a0vvvvvvxx00xx@i0:1,Voltage P1,V,Voltage_P1,2 1,a1ccccccxx00xx@i1:1,Current P1,A,Current_P1,2 1,a2uuuuxxxx00xx@i2:1,active Power P1,W,Power_P1,2 1,a3eeeeeexx00xx@i3:1Energy P1,W,Energy_P1,2 #

gemu2015 commented 4 years ago

updated driver available

better descriptor

>D >B ->sensor53 r

>M 1 +1,3,p,0,9600,PZEM1,1,1,b0,b1,b2,b3

1,a0vvvvvvxx00xx@1,Voltage P1,V,Voltage_P1,2 1,a1ccccccxx00xx@1,Current P1,A,Current_P1,2 1,a2ppppxxxx00xx@1,Active Power P1,W,Power_P1,2 1,a3eeeeeexx00xx@1,Energy P1,kWh,Energy_P1,2 #

gemu2015 commented 4 years ago

3 Phase PZEM driver

>D

>B ->sensor53 r

>M 3 +1,3,p,0,9600,PZEM_1,1,2,b0,b1,b2,b3 +2,2,p,0,9600,PZEM_2,4,2,b0,b1,b2,b3 +3,14,p,0,9600,PZEM_3,12,2,b0,b1,b2,b3

1,a0vvvvvvxx00xx@1,Voltage,V,Voltage,2 1,a1ccccccxx00xx@1,Current,A,Current,2 1,a2ppppxxxx00xx@1,Active Power,W,Power,2 1,a3eeeeeexx00xx@1,Energy,kWh,Energy,2 2,a0vvvvvvxx00xx@1,Voltage,V,Voltage,2 2,a1ccccccxx00xx@1,Current,A,Current,2 2,a2ppppxxxx00xx@1,Active Power,W,Power,2 2,a3eeeeeexx00xx@1,Energy,kWh,Energy,2 3,a0vvvvvvxx00xx@1,Voltage,V,Voltage,2 3,a1ccccccxx00xx@1,Current,A,Current,2 3,a2ppppxxxx00xx@1,Active Power,W,Power,2 3,a3eeeeeexx00xx@1,Energy,kWh,Energy,2 #

meingraham commented 4 years ago

@gemu2015

I have made several changes to the smart meter wiki article. Please review.

Sensor53 command has no documentation. I need to add this to the Commands page. What does r mean? Are there other values?

For any of these meters, how are the GPIO specified in the Template/Module? What are the component types to use? For example, typically one would specify the PZEM Tx/Rx in the Tasmota setup. You can only specify one PZEM in this manner and the specific components associates which driver to use. To use this driver (53), one cannot use the Tasmota component definitions; correct?

Have you considered also the Modbus PZEM (v3) so you only need one pair of GPIO and allow all PZEM to be connected to the same GPIO and then specify each by "addressing" it via the serial protocol before requesting data from each PZEM? I'm referring to this post. Or can this already be done using the MODBUS part of your driver?

For the PZEM descriptor, what is b0,b1,b2,b3? What are a0/a1/a2/a3? I can infer that v/c/p/e are for voltage/current/power/energy. Why are these "special" characters required? The other protocols just assume that there are numerals which are then decoded into the specified variable.

Mike

gemu2015 commented 4 years ago

@meingraham

i will check your changes tomorrow

sensor53 r resets the driver with the new descriptor sensor53 cx nnnn presets the counter x (1..4) to the value nnnn (counter mode)

for debugging: sensor53 dx dumps the meter x (1..5) input to the console for debug purposes (this disables the decoder) sensor53 d0 is needed to revert to decoding mode

the gpio pins may only be defined in the descriptor, in Tasmota GPIO selector they must be set to "none" otherwise a "double GPIO define error" is emitted in console and the descriptor is ignored

the PZEM support is only for the PZEM-04 (not the MODBUS version) the a0,a1,a2,a3 transmit block designators define the PZEM registers to access. this one uses a very special coding which i had to implement with the literals v/c/p/e

the PZEM MODBUS version however is NOT compatible to the standard MODBUS decoder which uses float numbers. the MODBUS PZEM uses half word registers. this device may be probably decoded in RAW mode.

I personally would NEVER use PZEM for 3 phases. there are cheap complete 3 phase meters with MODBUS which provide a lot more functions, are much more precise and support reverse currents (for solar feeds) which is not possible with PZEM

Gerhard

meingraham commented 4 years ago

I'll add the Sensor53 documentation. Thanks

Vital information. I suspected as much. I wanted to confirm - the gpio pins may only be defined in the descriptor, in Tasmota GPIO selector they must be set to "none" otherwise a "double GPIO define error" is emitted in console and the descriptor is ignored

the PZEM support is only for the PZEM-04 (not the MODBUS version)
the a0,a1,a2,a3 transmit block designators define the PZEM registers to access.
this one uses a very special coding which i had to implement with the literals v/c/p/e

I'll incorporate this into the article after you've had a chance to review my other changes.

I agree that using 3 PZEM-004T for 3-phase is a "kludgy"/"sketchy" solution. I would be interested in what 3-phase MODBUS devices you recommend. I rather steer users toward that and then use the MODBUS feature of your smart meter interface to integrate with Tasmota.

Mike

gemu2015 commented 4 years ago

"c = set the driver to counter mode and preset counter (x = 1..5) to value"

cmd sensor95 cx does not switch to counter mode but presets a counter of a meter when in counter mode

=> c = preset a counter in counter mode (x = 1..5) to value

probably we should include the sensor53 cmds also in the sensor description file.

according to PZEM i hesitate to put it into the documentation

  1. it is not yet tested and not yet merged
  2. Theo has an easy to use PZEM driver for 3 variants and since i would not recommend a 3 phase driver users should use Theos version.

according to the MODBUS driver my solution has the advantage of being adaptable to various meters and indeed addressing more then on device over a single MODBUS is possible.

for 3 phase meters i would use the Eastron sdm530 or sdm630 (about 80-100 Euros)

or

at amazon or eBay there are a lot of 3 phase meters with MODBUS starting from about 50 Euros.

or this very cheap china import (31 Dollars)

https://www.aliexpress.com/item/33039151836.html?mb=mylGLEyZ6gyW6Zg&srcSns=Copy%20to%20Clipboard&tid=white_backgroup_101&tt=sns_Copy&aff_platform=default&cpt=1567930010043&sk=5w4aliIM&aff_trace_key=1c693e1cbd104222922b3295e301f74e-1567930010043-09490-5w4aliIM&businessType=ProductDetail&templateId=white_backgroup_101&platform=AE&terminal_id=3638e64a8cdb478680d9479bb208c39c

meingraham commented 4 years ago

Sensor95? I saw where you changed the descriptors a few days ago from 95 to 53. I have documented Sensor53 and included that in the meter documentation. What is Sensor95?

I don't understand what you mean by this -

"c = set the driver to counter mode and preset counter (x = 1..5) to value"

cmd sensor95 cx does not switch to counter mode but presets a counter of a meter when in counter mode

=> c = preset a counter in counter mode (x = 1..5) to value

probably we should include the sensor53 cmds also in the sensor description file.
gemu2015 commented 4 years ago

sorry sensor95 was the name for this driver i used for the last 2 years before merging to tasmota.

you wrote in the wiki "c = set the driver to counter mode and preset counter (x = 1..5) to value"

BUT sensor53 cx does NOT switch to counter mode but presets a counter of a meter WHEN in counter mode

rt400 commented 4 years ago

hi.. well i have a 3 PZEM04T v3.0 . i can be your tester if you like just tell me what to do and i can report back to you the result

gemu2015 commented 4 years ago

@rt400 ok then first lets test a single device. download my fork and compile with

undef USE_RULES

define USE_SCRIPTER

define USE_SML_M

you should see the default OBIS device in WEBUI and in configuration you should see the submenu "edit script"

now copy the above single device descriptor in the edit script edit window, check enable script and save. your should now see the PZEM entries on the main page.

the descriptor assumes esp8266 RX and TX , so connect these to the PZEM.

hopefully now you should see the PZEM values in the WEBUI

if this works we may try the 3 phases solution

thanks

rt400 commented 4 years ago

got a error :

sonoff:29:143: error: core_version.h: No such file or directory

compilation terminated.

exit status 1
core_version.h: No such file or directory 

i used with 2.5.2 core also downgrade to 2.3.0 and still got this error

gemu2015 commented 4 years ago

ok to check i downloaded my own repo and compiled with platformio. and it worked (select your preferred language version)

if you use Arduino IDE i have no advice whats wrong

but you may use the official Tasmota DEV version and simply replace the sml53 file with the one from my fork.

i meantime realized that you have the PZEM v3 with MODBUS telegram. i have to make a slight change for that and the above descriptors won't work.

try to get scripting to work in the meantime.

i will be back with a MODBUS descriptor later.

gemu2015 commented 4 years ago

here is a PZEM v3 descriptor use the very last sml version from GitHub

D

B =>sensor53 r

M 1 +1,3,m,0,9600,PZEM3,1,1,01040000,01040001,01040003,01040005

1,010404uuuuxxxxxxxx@i0:10,Voltage,V,voltage,2 1,010404uuuuuuuuxxxx@i1:1000,Current,A,current,4 1,010404uuuuuuuuxxxx@i2:10,Power,W,power,2 1,010404uuuuuuuuxxxx@i3:1000,Energy,kWh,energy,4 #

fitim7 commented 4 years ago

Is „USE_SCRIPT“ already implemented for ESP32? Getting weird errors here:

.pioenvs/tasmota32-DE/src/tasmota.ino.cpp.o:(.literal._Z6Xdrv10h+0x28): undefined reference to `ScriptWebShow(char)'
.pioenvs/tasmota32-DE/src/tasmota.ino.cpp.o: In function `Xdrv10(unsigned char)':
/Users/fits/Downloads/Sonoff-Tasmota-universal8/tasmota/xdrv_10_scripter.ino:5108: undefined reference to `ScriptWebShow(char)'

Same happening for „USE_LIGHT“

gemu2015 commented 4 years ago

yes script works well on ESP32. you must define both

define USE_SCRIPT

define USE_SCRIPT_WEB_DISPLAY

this is due to a bug in scripter i removed it now.

fitim7 commented 4 years ago

You sir saved my day. Thank you. And yes, I define both, just wanted to show the problem here. Btw. This also happens with "USE_LIGHT" in ESP32:

.pioenvs/tasmota32-DE/src/tasmota.ino.cpp.o:(.literal._Z6Xdrv10h+0x28): undefined reference to `ScriptWebShow(char)'
.pioenvs/tasmota32-DE/src/tasmota.ino.cpp.o: In function `Xdrv10(unsigned char)':
/Users/fits/Downloads/Sonoff-Tasmota-universal8/tasmota/xdrv_04_light.ino:330: undefined reference to `ScriptWebShow(char)'
collect2: error: ld returned 1 exit status
*** [.pioenvs/tasmota32-DE/firmware.elf] Error 1
gemu2015 commented 4 years ago

its not related to ESP32, it happens also with esp8266

strange however that the error is reported for light driver which has no reference to ScriptWebShow

fitim7 commented 4 years ago

Hmm, okay that's weird. So the only way to handle this for me is:

#undef USE_LIGHT

Thank you my friend! Script working now btw ! :)

gemu2015 commented 4 years ago

define USE_SCRIPT

define USE_SCRIPT_WEB_DISPLAY

define USE_LIGHT

works for me at least with my latest version

herrfrei commented 4 years ago

I have a question that is not specially for the PZEM driver but for scripts in general: I want to compute a load mean value from the measurements when they arrive and transmit this value with >J. Right now I don't know where to get the values from the >M section to compute a variable.

Any ideas?

kugelkopf123 commented 4 years ago

@herrfrei Look at the example in the docs. https://tasmota.github.io/docs/Smart-Meter-Interface/#landis-gyr-zmr120ares2r2sfcs-obis

The >>T section.

Sent with GitHawk

herrfrei commented 4 years ago

Thanks for the hint. The >T section is filled on teleperiod. Not when new data arrive. I get updates every second, but want to sent the MQTT message every 60 seconds. So I need to update the power value when the new data arrive and not when they are published.

gemu2015 commented 4 years ago

you may access the >M registers directly with sml[x] x being the line of definition 1 ... N (html lines not counted) these are updated when they arrive from serial port remark: the SML section works with double, scripter with float. in very rare cases this may cause an accuracy lost.

gemu2015 commented 4 years ago

you must compile with #define USE_SML_SCRIPT_CMD

herrfrei commented 4 years ago

Many thanks for the hint!

onley commented 2 years ago

Is this discussion what led to the ModuleAddress command and if so would it be possible to expand this from 3 addresses? I am considering using these PZEM modules to monitor multiple circuits at the service panel and would like to be able to connect multiple modules to a single wemo D1 but the current ModuleAddress command only allows for 3 unique addresses and they seem to be related in a 3 phase arrangement where as I would like the different modules to be completely separate topics.

gemu2015 commented 2 years ago

PZEM is no longer officially supported by this driver because the Tasmota standard PZEM driver works for most users. however the code is still there and might still work with SML it is possible to have more than 3 devices on the same bus. i myself prefer MODBUS devices however there is also a new version of the PZEM device that has a MODBUS protocol. i would suggest to take these devices if you prefer clamp meters. to set the module ID you must connect one module after the other and issue a set module id cmd before you can connect them all in parallel.

onley commented 2 years ago

Thank you, I will pursue the Tasmota PZEM driver, I thought that's what this was. Sorry.

onley commented 2 years ago

I have got this working but the ModuleAddress command results in

12:22:34.766 CMD: ModuleAddress 2 12:22:34.774 MQT: stat/Wemo/RESULT = {"Command":"Unknown"}

I assume that command went away with undef of rules what is the syntax of the set module id command you refer to above?

BTW the script above need some modification for a PZEM004T V3.0

D

B =>sensor53 r

M 2 +1,3,m,0,9600,PZEM3,1,1,01040000,01040001,01040003,01040005,01040007,01040008 +2,3,m,0,9600,PZEM3,1,1,01040000,01040001,01040003,01040005,01040007,01040008

1,010404UUuuxxxxxxxx@i0:10,Voltage,V,voltage,2 1,010404UUuuUUuuxxxx@i1:100000000,Current,A,current,4 1,010404UUuuUUuuxxxx@i2:1000000,Power,W,power,2 1,010404UUuuUUuuxxxx@i3:1000000000,Energy,kWh,energy,4 1,010404UUuuxxxxxxxx@i4:10,Frequency,Hz,Frequency,2 1,010404UUuuxxxxxxxx@i5:100,Power Factor,PF,Power Factor,2 2,010404UUuuxxxxxxxx@i0:10,Voltage,V,voltage,2 2,010404UUuuUUuuxxxx@i1:100000000,Current,A,current,4 2,010404UUuuUUuuxxxx@i2:1000000,Power,W,power,2 2,010404UUuuUUuuxxxx@i3:1000000000,Energy,kWh,energy,4 2,010404UUuuxxxxxxxx@i4:10,Frequency,Hz,Frequency,2 2,010404UUuuxxxxxxxx@i5:100,Power Factor,PF,Power Factor,2

#

onley commented 2 years ago

Please disregard the script above, The driver seems to be reading data in the wrong order. The current and power data is low 16 bits then high 16 bits so I can get reasonable readings if I only read the first 16 bits and divide by 1000 for current but will not be able to read above 65 amps. did this change with PZEM004T V3.0? image

gemu2015 commented 2 years ago

Multiple MODBUS devices on the same bus are defined as one meter only. There is an example in the docs with 4 meters in parallel Start with one meter and only expand if this one meter works as expected

onley commented 2 years ago

Thank you, I'm in a little over my head but that example helped. I have one meter working and am working on the scripting for the second meter but do you have any advice for transposing the order of the high and low words for current and power? Can this be accomplished in the decoding or does it have to be done in the driver itself?

gemu2015 commented 2 years ago

each transfer request gets 2 registers, so you should decode high and low at once. see how this is done in most MODBUS examples using either uuUUuuUU or UUuuUUuu for fetching an unsigned 32 bit value (depending on byte order)

onley commented 2 years ago

I saw that but it's the words that backwards not the bytes within the words.

onley commented 2 years ago

Currently I am only decoding the low order word and ignoring the high order word but that will bite me on loads greater than 65 amps.

gemu2015 commented 2 years ago

ok, that is currently not supported. it would be possible to swap words in script but i will implement a word swap in SML tomorrow and will post the modified source code here.

onley commented 2 years ago

Thanks.

gemu2015 commented 2 years ago

ok here is an update.

to swap words add an s to the 32 bit decode

e.g.

uuUUuuUUs

xsns_53_sml.ino.zip

onley commented 2 years ago

I'm compiling on gitpod, What source do I need to update to use the new code.

onley commented 2 years ago

I figured it out, it works great. Thank you so much for your help, this level of coding is way above my head. If there is any way I can support your work let me know.

onley commented 2 years ago

I have a script running and reading multiple meters and it all works but I would like to be able to reset the PZEM from mqtt so was wondering if there was a way to have a subroutine in the script that would send the reset string to the PZEM. Also the documentation states that %var% substitution is allowed in descriptors if compiled with SML_REPLACE_VARS but I can only get substitution work in the decode section not the descriptor section. Am I reading this wrong?

gemu2015 commented 2 years ago

yes SML_REPLACE_VARS ist static and only in decode section.

i added a dynamic write cmd which inserts a hex string into write sequence.

hstr="00ffabcd" sml(1 3 hstr)

1 argument = meter number 2 argument function selector here 3 3 argument a string with hex value to be sent as binary

this string is sent only once and inserted into the defined send values.

try this

Archiv.zip

onley commented 2 years ago

What is the function selector? Is it the code for reading or writing? For example the PZEM uses 04 to read measurement, 03 to read parameters and 06 to write a register. If so the reset for the PZEM is just meter address + 0x42 + crc so what would I use for a place holder for function?

The command format of the master to reset the slave's energy is (total 4 bytes): Slave address + 0x42 + CRC check high byte + CRC check low byte.

gemu2015 commented 2 years ago

oh sorry that cmd assumes 6 bytes. i have to check how to adjust this

gemu2015 commented 2 years ago

ok, checked, should also work with 4 bytes in raw mode

so send (assuming 03 is device address, and meter number is 1, crc is calculated inside function)

sml(1 3 "r0342")

onley commented 2 years ago

I'm not getting a reset. I have verified the command string by coding the script with

M 1 +1,3,m,0,9600,ENERGY,1,1,1542 #

and it will reset the meter total but using

sml(1 3 "r1542")

has no effect.

gemu2015 commented 2 years ago

You need the r for raw mode like in my example

onley commented 2 years ago

The r is in the quotes above