emelianov / modbus-esp8266

Most complete Modbus library for Arduino. A library that allows your Arduino board to communicate via Modbus protocol, acting as a master, slave or both. Supports network transport (Modbus TCP) and Serial line/RS-485 (Modbus RTU). Supports Modbus TCP Security for ESP8266/ESP32.
Other
518 stars 187 forks source link

How to send _non-standard_ commands #145

Closed leifclaesson closed 3 years ago

leifclaesson commented 3 years ago

I'm trying to communicate with the PZEM-004T energy meter. Documentation here.

modbus-esp8266 is working flawlessly with it (unlike the terribly written libraries specially made for it!) but...

The application layer use the Modbus-RTU protocol to communicate. At present, it only supports function codes such as 0x03 (Read Holding Register), 0x04 (Read Input Register), 0x06 (Write Single Register), 0x41 (Calibration), 0x42 (Reset energy).etc.

Notice here they simply invented their own modbus "command" rather than using one of the existing ones. It's not the way I would have done it, but I do need to use this command. Is there a facility to issue a custom command with modbus-esp8266? If not, may I request a feature? :)

leifclaesson commented 3 years ago

Continued: I have been able to issue the command by reading your source code and subclassing ModbusRTU and making my own function as follows:

uint16_t ModbusRTU_Raw::sendCustomCommand(uint8_t slaveId, uint8_t fn, cbTransaction cb, uint8_t* data, bool waitResponse)
{
    free(_frame);
    _len = 1;
    _frame = (uint8_t*) malloc(_len);
    _frame[0] = fn;

    TAddress x;

    return send(slaveId, x, cb, MODBUSIP_UNIT, data, waitResponse);
}

It actually works! The command is accepted by the energy meter and the counter is reset, and my transaction callback function is called. However the event result is of course an error (0xE1 - EX_GENERAL_FAILURE) since masterPDU does not have a handler for this non-standard response.

The documentation for the device says:

2.5 Reset energy 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. Correct reply: slave address + 0x42 + CRC check high byte + CRC check low byte. Error Reply: Slave address + 0xC2 + Abnormal code + CRC check high byte + CRC check low byte

It works as far as I can tell but please let me know if there is a better way to do this your library. :)

emelianov commented 3 years ago

Hello @leifclaesson Your idea and implementation is the only way available without changing the library code. You are quite right masterPDU contains reaction on known set of modbus commands. All the the other responses generates error. It's reasonable idea to extend the api with sendCustomCommand method and callback to process custom slave response. Just put to todo list for next release.

leifclaesson commented 3 years ago

Thank you @emelianov! :)