Skip to content

PLC

TODO: Use the actual request/response examples

Overview

The BESS RCU exposes a Modbus TCP server that provides real-time AC meter and Insulation monitoring device (isometer) data as holding registers. This document describes how to connect, the register map layout, data types, addressing convention, and includes request/response examples.

Connection Parameters

Parameter Value
Protocol Modbus TCP
IP Address 127.0.0.1 (default, configurable)
TCP Port 5020
Unit ID 1

Open a standard TCP socket to the server address and port, then exchange Modbus Application Protocol (MBAP) frames as described in the examples below.

Addressing Convention

This server uses 1-based register addressing.

  • Valid register addresses range from 1 to 9999.
  • There is no register at address 0.
  • The register addresses listed in the tables below are the exact addresses to place in the Modbus PDU Starting Address field. No additional offset or subtraction is required.

If Modbus Client communicates using 0-based offsets, start address must be calculated as shown below:

$$\text{Start Address (Offset)} = (\text{Register Address} - 1)$$

For example, reading FC03 from start address 768 (0x0300) corresponds to holding register 40001 + 768 = 40769.

Register Map Organization

All data is served on the Holding Register function (Function Code 0x03 — Read Holding Registers). Coils, Discrete Inputs, and Input Registers are present but currently unused.

The holding-register space is divided into two contiguous groups:

Group Address Range Description
AC Meter 0x03000x0338 (768 – 824) AC Power monitoring
Isometer 0x03600x036E (864 – 878) Insulation monitoring

Note: Gaps exist between defined registers within each group; reading an undefined address will return an error response.

AC Meter Registers

Address (hex) Address (dec) Name Data Type Words Resolution Offset Default Value Description
0x0300 768 ACM_STATUS UINT16 1 1.0 0 0 AC Meter status
0x0302 770 ACM_F FLOAT32 2 1.0 0 0.0 Frequency (Hz)
0x0310 784 ACM_V_A-B FLOAT32 2 1.0 0 0.0 Line (Grid) voltage A-B (V)
0x0312 786 ACM_V_B-C FLOAT32 2 1.0 0 0.0 Line (Grid) voltage B-C (V)
0x0314 788 ACM_V_C-A FLOAT32 2 1.0 0 0.0 Line (Grid) voltage C-A (V)
0x0316 790 ACM_I_A FLOAT32 2 0.001 0 0.0 Phase current A (A)
0x0318 792 ACM_I_B FLOAT32 2 0.001 0 0.0 Phase current B (A)
0x031A 794 ACM_I_C FLOAT32 2 0.001 0 0.0 Phase current C (A)
0x0320 800 ACM_ACTIVE_ENERGY_IMPORT FLOAT32 2 1.0 0 0.0 Active energy import (kWh)
0x0322 802 ACM_ACTIVE_ENERGY_EXPORT FLOAT32 2 1.0 0 0.0 Active energy export (kWh)
0x0324 804 ACM_ACTIVE_ENERGY_IMPORT_T FLOAT32 2 1.0 0 0.0 Active energy import on time (kWh)
0x0326 806 ACM_ACTIVE_ENERGY_EXPORT_T FLOAT32 2 1.0 0 0.0 Active energy export on time (kWh)
0x032A 810 ACM_REACTIVE_ENERGY_CAPACITIVE FLOAT32 2 1.0 0 0.0 Reactive energy capacitive (kVArh)
0x032C 812 ACM_REACTIVE_ENERGY_INDUCTIVE FLOAT32 2 1.0 0 0.0 Reactive energy inductive (kVArh)
0x032E 814 ACM_APPARENT_ENERGY FLOAT32 2 1.0 0 0.0 Apparent energy (kVAh)
0x0331 817 ACM_PF_1 FLOAT32 2 0.001 0 0.0 Power factor 1
0x0333 819 ACM_PF_2 FLOAT32 2 0.001 0 0.0 Power factor 2
0x0335 821 ACM_PF_3 FLOAT32 2 0.001 0 0.0 Power factor 3
0x0337 823 ACM_ERROR1 UINT16 1 1.0 0 0 AC Meter error code 1
0x0338 824 ACM_ERROR2 UINT16 1 1.0 0 0 AC Meter error code 2

Isometer Registers

Address (hex) Address (dec) Name Data Type Words Resolution Offset Default Value Description
0x0360 864 IMD_STATUS UINT16 1 1.0 0 0 Isometer status
0x0361 865 IMD_RF FLOAT32 2 1.0 0 0.0 Insulation resistance — PE to GND (kΩ)
0x0365 869 IMD_PE FLOAT32 2 1.0 0 0.0 PE leakage -Positive to ground (kΩ)
0x0367 871 IMD_NE FLOAT32 2 1.0 0 0.0 NE leakage - Negative to ground (kΩ)
0x0369 873 IMD_C FLOAT32 2 1.0 0 0.0 Insulation capacitance (µF)
0x036B 875 IMD_INSULATION_LIMIT_LEVEL1 UINT16 1 1.0 0 0 Insulation limit level 1 — warning
0x036C 876 IMD_INSULATION_LIMIT_LEVEL2 UINT16 1 1.0 0 0 Insulation limit level 2 — critical
0x036E 878 IMD_ERROR UINT16 1 1.0 0 0 Isometer error code

Data Types

Type Size Byte Order Description
UINT16 1 register (2 bytes) Big Endian Unsigned 16-bit integer
FLOAT32 2 registers (4 bytes) ABCD (Big Endian) IEEE 754 single-precision float

FLOAT32 Word Layout (ABCD — Big Endian)

A FLOAT32 value spans two consecutive 16-bit holding registers:

Register N     (High Word):  Byte A | Byte B
Register N+1   (Low Word):   Byte C | Byte D

To reconstruct the 32-bit float, concatenate the two registers in order (high word first) and interpret as IEEE 754.

Example: 200.0 V encoded as FLOAT32

IEEE 754:  0x43480000
High Word: 0x4348  (Register N)
Low Word:  0x0000  (Register N+1)

Communication Examples

All frames below use Modbus TCP (MBAP header + PDU). Byte values are shown in hexadecimal.

Example 1 — Read a UINT16 Register (ACM_STATUS)

Read 1 holding register starting at address 0x0300 (768).

Request:

03 03 00 00 01
PDU
  03    : Function Code (Read Holding Registers)
  03 00 : Starting Address (0x0300 = 768)
  00 01 : Quantity of Registers (1)

Response (ACM_STATUS = 0x0001):

03 02 00 01
PDU
  03    : Function Code
  02    : Byte Count (2 bytes = 1 register)
  00 01 : Holding Register 40769 — ACM_STATUS = 1

Example 2 — Read FLOAT32 Registers (Grid Voltages)

Read 6 holding registers starting at address 0x0310 (784), covering three FLOAT32 values: ACM_V_A-B, ACM_V_B-C, and ACM_V_C-A.

Request:

03 03 10 00 06
PDU
  03    : Function Code (Read Holding Registers)
  03 10 : Starting Address (0x0310 = 784)
  00 06 : Quantity of Registers (6)

Response (all three voltages = 200.0 V → IEEE 754 0x43480000):

03 0C 43 48 00 00 43 48 00 00 43 48 00 00
PDU
  03    : Function Code
  0C    : Byte Count (12 bytes = 6 registers)
  43 48 : Holding Register 40785 — ACM_V_A-B high word
  00 00 : Holding Register 40786 — ACM_V_A-B low word  → 0x43480000 = 200.0 V
  43 48 : Holding Register 40787 — ACM_V_B-C high word
  00 00 : Holding Register 40788 — ACM_V_B-C low word  → 0x43480000 = 200.0 V
  43 48 : Holding Register 40789 — ACM_V_C-A high word
  00 00 : Holding Register 40790 — ACM_V_C-A low word  → 0x43480000 = 200.0 V

Example 3 — Read Isometer Status and Insulation Resistance

Read 3 holding registers starting at address 0x0360 (864), covering IMD_STATUS (UINT16, 1 word) + IMD_RF (FLOAT32, 2 words).

Request:

03 03 60 00 03
PDU
  03    : Function Code (Read Holding Registers)
  03 60 : Starting Address (0x0360 = 864)
  00 03 : Quantity of Registers (3)

Response (IMD_STATUS = 0x0001, IMD_RF = 2000.0 kΩ (2 MΩ) → 0x44FA0000):

03 06 00 01 44 FA 00 00
PDU
  03    : Function Code
  06    : Byte Count (6 bytes = 3 registers)
  00 01 : Holding Register 40865 — IMD_STATUS = 1
  44 FA : Holding Register 40866 — IMD_RF high word
  00 00 : Holding Register 40867 — IMD_RF low word  → 0x44FA0000 ≈ 2000.0 kΩ (2 MΩ)

Error Responses

If a request targets an undefined register address or an invalid quantity, the server responds with an exception:

PDU  [0x83] [Exception Code]
Exception Code Meaning
0x01 Illegal Function
0x02 Illegal Data Address
0x03 Illegal Data Value

Quick Reference

  • Function Code: 0x03 (Read Holding Registers) for all data
  • Addressing: 1-based — use register addresses directly in the PDU
  • Byte Order: Big Endian (ABCD) for FLOAT32 values
  • FLOAT32: Always read 2 consecutive registers
  • UINT16: Read 1 register
  • Gaps: Not all addresses between defined registers are valid; only read the addresses listed in the register tables above