Clockwise from top: USB 3.0 powered hub, RS-485 USB dongle, Arduino RS-485 to TTL module and NodeMCU ESP-12E ESP8266 |
The Schneider PM1200 3-phase Power Meter has an RS-485 interface and would make a great IoT device.
Schneider PM1200 Power Meter |
Fuji FRENIC 15KW Inverter |
The ESP8266 is incredibly tempting as such an IoT gateway. It is low-cost, low-power and the WiFi module allows for a much safer non-galvanic, isolated data connection. Similar devices like the monster 10-30KW Inverters used in escalators, cranes, etc can be monitored safely from the cloud this way.
As usual I used a low-cost (RM3.38) Arduino RS-485 to serial TTL module. Now this is a 5V device and since the ESP8266 is strictly a 3.3V device, we should really use a logic level converter, but at a pinch it should work at 3.3V, especially if I powered it from the ESP-12E.
I also used a modified version of the Trialcommand ESP8255 Master Modbus RTU (RS232) sketch. This in turn use the SoftwareSerial library, which essentially determined the wiring diagram.
RS-485 to 5V TTL module |
MOSFET-based Logic Level Converter |
The wiring diagram (sans level converter) is:
ESP12-E RS-485 PCB
3V3
GND
D5 ------- *RE
D6 ------- DE
D7 ------- RO
D8 ------- DI
NodeMCU ESP-12E Pinout |
The wiring really makes sense when you look at the MAX485E IC datasheet:
Notice the MAX485E is a half-duplex device |
I made a little ribbon cable with Moles 0.1" pitch Molex connectors:
Cable assembly. Right, top: data & control, right bottom: rs-485 power. Left: ESP-12E |
When assembled the RS-485 module looked like this:
Download the libraries and copy them into your Arduino IDE libraries folder.
$ls -lt /root/Arduino/libraries
total 16
drwxr-xr-x 4 root root 4096 Apr 26 20:44 Time-master
-rw-r--r-- 1 root root 87 Feb 27 07:20 readme.txt
drwxr-xr-x 2 heong users 4096 Mar 15 2017 ModBusMaster232
drwxr-xr-x 3 heong users 4096 Mar 15 2017 SoftwareSerial
Since the ESP8266-Modbus-RTU-Master library uses full duplex TTL RS-232 I put in a tiny patch to convert it to half duplex required by the MAX485E. The file is ./libraries/ModBusMaster232/ModbusMaster232^Cpp and the change is in boldface at line 735:
#define not_RE 14 // D5. Enable receiver, active low
#define DE 12 // D6 Enable Transmitter, active high
u16CRC = 0xFFFF;
for (i = 0; i < u8ModbusADUSize; i++)
{
//Function crc16 for ESP8266 - PDAControl
u16CRC = _crc16_update2(u16CRC, u8ModbusADU[i]);
}
u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
u8ModbusADU[u8ModbusADUSize] = 0;
// transmit request
digitalWrite(not_RE, HIGH); // cmheong Set max485 to transmit
digitalWrite(DE, HIGH);
for (i = 0; i < u8ModbusADUSize; i++)
{
swSer.print(char(u8ModbusADU[i]));
delay(2); // cmheong 2018-07-26
}
u16CRC = 0xFFFF;
for (i = 0; i < u8ModbusADUSize; i++)
{
//Function crc16 for ESP8266 - PDAControl
u16CRC = _crc16_update2(u16CRC, u8ModbusADU[i]);
}
u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
u8ModbusADU[u8ModbusADUSize] = 0;
// transmit request
digitalWrite(not_RE, HIGH); // cmheong Set max485 to transmit
digitalWrite(DE, HIGH);
for (i = 0; i < u8ModbusADUSize; i++)
{
swSer.print(char(u8ModbusADU[i]));
delay(2); // cmheong 2018-07-26
}
I modified the Trialcommand sketch (patches in boldface):
#include <ModbusMaster232.h>
#include <SoftwareSerial.h> // Modbus RTU pins D7(13),D8(15) RX,TX
// MAX485 half duplex control lines
#define not_RE 14 // D5. Enable receiver, active low
#define DE 12 // D6 Enable Transmitter, active high
// Instantiate ModbusMaster object as slave ID 1
ModbusMaster232 node(1);
void setup()
{
pinMode(not_RE, OUTPUT);
pinMode(DE, OUTPUT);
// default to transmit mode to reduce noise
digitalWrite(not_RE, HIGH); // disable receiver
digitalWrite(DE, HIGH); // enable transmitter
Serial.begin(9600);
delay(100);
node.begin(9600); // Modbus RTU
delay(100);
Serial.println("Connected ");
Serial.println("Modbus RTU Master Online");
}
void loop()
{
//Website http://trialcommand.com
///////// Holding Register [0] A [9] = 10 Holding Registers Escritura
///////// Holding Register [0] A [9] = 10 Holding Registers Writing
int Mdelay = 500; // from 5
node.readDiscreteInputs(0, 1);
Serial.print("[0] ");
Serial.print(node.getResponseBuffer(0));
node.clearResponseBuffer();
delay(Mdelay);
node.writeSingleRegister(0x1001, 0xff);
delay(Mdelay);
}
There you have it: the ESP8266 NodeMCU ESP-12E will now be able to request digital input from the modbus device as well as output to it. Having obtained the data it will now need to relay it to the Internet via its webpage, which will be shown in Part 2.
Happy Trails.