solaredge_meterproxy is a python tool that responds to Modbus requests from SolarEdge power inverters with data from unsupported kWh meters. While SolarEdge only supports a limited number of revenue meters, by masquerading as a supported meter it is possible to supply your own meter values to the SolarEdge inverter for production, consumption, import/export monitoring, and export limitation.
This tool simulates one or more WattNode WNC-3Y-400-MB revenue meters, functionally similar to the rebranded SE-WNC-3Y-400-MB-K1. The Modbus registers of these simulated meters can then be updated with values from otherwise unsupported kWh meters, or sourced from a variety of data sources.
SolarEdge inverters only use Modbus RTU over RS485 to communicate with meters, this project supports both Modbus RTU when connected directly to an inverter over RS485, and Modbus TCP in case a Modbus TCP gateway is connected to the inverter. This functionality has been tested using an ICP-DAS tGW-715 and Elfin EE11 Modbus TCP to RTU gateway.
Supported devices and data sources:
Decide whether you will be running a Modbus RTU or Modbus TCP server. If your device is directly connected to the inverter via RS485 using a serial device or USB dongle, choose Modbus RTU. If you have a Modbus TCP gateway connected to your inverter, choose Modbus TCP.
Run semp-rtu.py
on a device connected via RS485 to a SolarEdge inverter.
usage: semp-rtu.py [-h] [-c CONFIG] [-v]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
-v, --verbose
By default, semp-rtu.py
assumes your RS485 device is located at /dev/ttyUSB0
with a baud rate of 9600
. While configuring and testing solaredge_meterproxy, you should run semp-rtu.py
in verbose mode. The Modbus server and source meter configurations can be set in semp-rtu.conf
. See Configuration File for more information.
Run semp-tcp.py
on a device on the same network as a Modbus TCP gateway connected via RS485 to a SolarEdge inverter.
usage: semp-tcp.py [-h] [-c CONFIG] [-v]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
-v, --verbose
Before running semp-tcp.py
, configure a TCP IP and port for it to listen on. Your Modbus TCP gateway will need to be configured as TCP client, connecting to the IP and port you assigned semp-tcp.py
. While configuring and testing solaredge_meterproxy, you should run semp-tcp.py
in verbose mode. The Modbus server and source meter configurations can be set in semp-tcp.conf
. See Configuration File for more information.
Configuration of the inverter takes place in the SetApp interface or the LCD display on the inverter. For more information, please read SolarEdge's SetApp documentation. You will need a SolarEdge installer account to access the SetApp application. The account is free, and the app is available on both iOS and Android.
If you have multiple SolarEdge inverters connected via Modbus, are currently using the SunSpec Modbus logger function, or have one or more revenue meters connected via Modbus, please read all instructions below to be sure you know what you are doing. This guide assumes both RS485 ports are unused and disconnected.
First, ensure your SolarEdge inverter's Modbus address is set to 1:
Now, add a meter:
The SolarEdge inverter will now try to connect to a meter with Modbus address 2 on the RS485 device you selected. If you have configured and started solaredge_meterproxy with a matching meter configuration you should see a Meters section at the bottom of the Status page. Depending on the function selected, metering functionality should now be available.
If, after configuring a meter in the SetApp interface, you see only meter connection errors, set log_level
to DEBUG
in your configuration file. After starting solaredge_meterproxy you should see Modbus read requests from the inverter. If you do, please open an issue with copies of these and your configuration file. If you don't, check your connection, RS485 adapter, or Modbus TCP gateway settings.
The server, and one or more source meters, can be configured in a python configparser
formatted configuration file. If a configuration file is not specified, and semp-rtu.conf
of semp-tcp.conf
are not found, generic defaults will be loaded. Provide an alternate configuration file using the --config
parameter.
For an overview of all configurable parameters, see semp-rtu.conf
or semp-tcp.conf
.
Device scripts contain additional, often required, configuration parameters. Consult the relevant device script for an overview when configuring source meters.
An example Modbus RTU configuration, with a SDM120 source that is accessible over Modbus TCP:
[server]
device = /dev/ttyUSB0
baud = 9600
log_level = INFO
meters = meter1
[meter1]
type=sdm120
host=10.0.0.124
port=502
src_address=1
dst_address=2
An example Modbus TCP configuration, with a SDM120 source that is accessible over Modbus RTU:
[server]
address = 10.0.0.123
port = 5502
log_level = INFO
meters = sdm120
[sdm120]
type=sdm120
device=/dev/ttyUSB0
baud=9600
src_address=1
dst_address=2
If you receive DEBUG: Frame check failed, ignoring!!
errors, the Modbus TCP gateway is probably sending you RTU frames inside TCP packets. In that case, set the framer = rtu
configuration parameter inside the [server]
block.
Support for various kWh meters can be added by creating a Python script in the devices
directory. This script should adhere to the following:
device()
function.values()
function./devices/generic.py
.For a skeleton implementation, see /devices/generic.py
.
The device()
function is called once. It gets passed a configparser
object with the device's configuration parameters, as configured in the configuration file. It must return a data structure which contains either an active connection, or enough information to identify the device in a data store. This data structure will be passed to the values()
function.
While the intent is to masquerade another Modbus RTU or Modbus TCP device, it is possible to use virtually any type of data store. InfluxDB, or SQLite, for example.
The values()
function is called every refresh_rate
seconds. It gets passed the data structure returned by device()
, and must return a dict
. The /devices/generic.py
script contains a list of all possible dictionary keys. It is not required to return all, or in fact any, keys. Functionality of the SolarEdge inverter will depend on the values provided.
Single phase devices should put the single phase values in the generic and first phase specific values, for example: power_active
and p1_power_active
, but also voltage_ln
and p1n_voltage
.
Contributions are more than welcome, especially new device scripts, or modifications which broaden the use case of this tool.