Hi,
I recently purchased a solar charge controller (Epever Tracer 3906BP) which has a Modbus RTU port that can be used to get data (battery voltage, solar panels voltage, etc) from the device.
On the documentation of the solar charge controller I read:
- The default controller ID number is “1”, we can modify the ID via PC common software
- Serial communication parameters: baud rate 115200, data bits 8, stop bits 1, no data flow control.
- Register address uses hexadecimal format, the base address offset is 0x00
- All 32-bit-length data uses two 16-bit registers to represent (L and H register, respectively), for example, the value of the array rated power is 3000, data multiple is 100, the data of L register (address 0x3002) is 0x93E0 and the data of H register (address 0x3003) is 0x0004.
I have connected the Epever to a RPi via a FTDI chip (RS485 to USB) and I am able to get data (battery voltage in the example below) from it via a simple C++ software:
uint8_t* cmd = {0x01, 0x04, 0x33, 0x1a, 0x00, 0x01 };
uint16_t crc = ModRTU_CRC(cmd, 6);
uint8_t crc_a = (uint8_t)(crc >> 8);
uint8_t crc_b = (uint8_t)(crc);
uint8_t buffer[8];
buffer[0] = cmd[0];
buffer[1] = cmd[1];
buffer[2] = cmd[2];
buffer[3] = cmd[3];
buffer[4] = cmd[4];
buffer[5] = cmd[5];
buffer[6] = crc_a;
buffer[7] = crc_b;
//for (int i = 0; i < 8; i++){debug("Writing 0x%02X ", buffer[i]);}
size_t size = 8;
m_uart->flush();
m_uart->write(buffer,size);
Counter<float> timer(1.0);
int index = 0;
uint8_t bfr[255];
uint16_t val = 0;
while (!timer.overflow() && index < size-1)
{
if (!Poll::poll(*m_uart, timer.getRemaining()))
break;
size_t bytes_read = m_uart->read(bfr+index, sizeof(bfr));
index +=bytes_read;
print("EPEVER read: %d bytes", bytes_read);
}
if(index == size-1){
val = (uint16_t)bfr[3] << 8 | (uint16_t)bfr[4];
print("EPEVER says: %d, in hex it is 0x%04x", val,val);
}
return val;
}
uint16_t ModRTU_CRC(uint8_t* cmd, int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (uint16_t)cmd[pos]; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
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
}
}
// Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
crc = (crc >> 8) | (crc << 8); // endiannes
return crc;
}
With that code I am able to get data from the device. The returned ‘val’ is a uint16_t that I then cast to double.
I would like to do the same with a TRB246 that I recently purchased.
I have connected the Epever wire A to TRB246 D+ and Epever wire B to TRB246 D-.
Could you please guide me on the setup of Modbus RTU on the TRB246 side? I assume that the TRB246 should act as master in the Modbus network and that from it I should be able to poll data from the Epever, same was as I do with the RPi.
Could you please help with this configuration and if there is some quick script or tool that I can use via CLI on the TRB246 to check the electrical connection and then retrieve some data via Modbus? I was thinking about making a bash script, but not sure that is ideal.
Thank you,
Alberto