reaper7 / SDM_Energy_Meter

reading SDM72 SDM120 SDM220 SDM230 SDM630 modbus energy meters from arduino (esp8266, esp32, avr)
247 stars 97 forks source link

Add option to read asynchronous + finetune timings + add some registers #79

Closed TD-er closed 1 year ago

TD-er commented 1 year ago

I'm using your library in ESPEasy. But I had to make a few changes to allow for async reading (thus no active waiting for a reply) The 'old' way is still possible, so it is just an extra option.

Also added some extra registers and tweaked some timings to speed up handling reading registers.

reaper7 commented 1 year ago

I don't actively use this library anymore, It's hard for me to check if it's working correctly.

If the facilities you introduced work properly, I must rely on your opinion.

maybe you want to become a contributor because I won't be able to make more advanced changes (without the ability to test) ??

if there is an option to run asynchronously, examples don't need to be changed as well? does asynchronous reading happen in the same way as the "old" one? there is no need to check state of the response in the loop?

TD-er commented 1 year ago

Just to give some explanation to what I did and why... In ESPEasy I do need to get many tasks running (a task is an instance of some plugin, which is the code to interact with some hardware) and thus I can't wait for a reply.

So what I did was, I made a list of struct SDM_RegisterReadQueueElement, which contains an id (the modbus address), a register number and some info (ESPEasy specific) about where to store the read register value and the current state of the pending request.

This is then continuously processed in SDM_loopRegisterReadQueue

That's where I do interact with your library. So I needed 3 new functions:

So for the end user using your library nothing has changed, apart from the extra new functions I mentioned before. The old function to send a request and wait till a reply was received is now doing those steps in 1 function call (and implement some timeout check)

I also added some minor changes so I can also use hardware DE/RE toggling and collision detection which is possible on ESP32. In order to use collision detection, you must have /RE connected to GND.

This is how it looks like in ESPEasy: image

This node does have 3 DIN modules connected and is now running 6 days 6 hours, so the 5419145 register reads are done roughly 10x per sec, taking about 13.6 msec per call. (@ 9600 baud) So instead of waiting and doing nothing, I only need 13.6% of the time dealing with reading those Eastron modules, regardless of how many there are connected and can deal with other stuff in the mean time :)

TD-er commented 1 year ago

About your question of me becoming a contributor... I just am about to change the way how all plugins in ESPEasy for modbus devices are interacting with the Modbus device. So that means I have to completely change the code for reading Eastron modules (have to split it in a central manager collecting all modbus register values and handling conflicts of all devices on the same bus). This means it is no longer in any way compatible with your library's interface and thus this was more like a PR to you to give back a little bit of code for anyone to use as the current implementation of it is still compatible with your original interface.

reaper7 commented 1 year ago

on compilation I get this error message

C:\Programy\arduino_projekty\libraries\SDM_Energy_Meter\SDM.cpp: In member function 'void SDM::modbusWrite(uint8_t*, size_t)':
C:\Programy\arduino_projekty\libraries\SDM_Energy_Meter\SDM.cpp:392:80: error: 'using SoftwareSerial = using UART = class EspSoftwareSerial::BasicUART<EspSoftwareSerial::GpioCapabilities>' {aka 'class EspSoftwareSerial::BasicUART<EspSoftwareSerial::GpioCapabilities>'} has no member named 'getBaudRate'; did you mean 'baudRate'?
  392 |     const unsigned long waitForBytesSent_ms = (messageLength * 11000) / sdmSer.getBaudRate() + 1;
      |                                                                                ^~~~~~~~~~~
      |                                                                                baudRate

I don't see the getBaudRate function in the espsoftwareserial library

TD-er commented 1 year ago

Ah OK, I will have a look at it, on what versions of HW/SW serial this was introduced or maybe it is called differently on HW/SW serial. If it isn't a member function on either one, maybe the baud rate should be stored then as a member.

Will get back on this asap.

TD-er commented 1 year ago

Was a bit silly from me to not even use the member variable _baud but instead query the serial port. The function to get the actual baud rate from the serial port is baudRate(). Just checked and both SoftwareSerial as well as Hardware serial on ESP8266 do have this function, but no idea if other platforms have such functions (and aren't returning 0) so it is best to just use the member variable _baud.