Skip to main content

Solar inverter monitoring script for RS485 serial communication

Project description

Solar-RS485-Monitor

Solar inverter monitoring script for RS485/serial communication.

The collector reads inverter data, prints the parsed result as JSON, and can optionally append rows to Google Sheets.

Supported Inverter Scope

The current code was written and tested for InoElectric IEPVS-3.5-G1/G2 inverters.

The request frame, response frame length, data offsets, scaling rules, CRC order, and metric interpretation are product-specific. If you use a different inverter model, check that product's specification or manual first, then update both sides of the protocol handling:

  • Request frame: set INVERTER_REQUEST_HEX to the product-specific request frame. If your environment describes this as a TCP header or protocol header, treat that product-specific header/request bytes as part of this value.
  • Response validation: set INVERTER_FRAME_LENGTH, INVERTER_DATA_LENGTH, INVERTER_CRC_ORDER, and INVERTER_ID according to the product's response format.
  • Response parsing: update parse_frame() in src/solar_rs485_monitor/collector.py if the product returns fields at different byte offsets, uses different units, or uses different scaling.

Do not assume another RS485 inverter will expose the same data layout just because the serial/TCP connection succeeds.

Current Connection Modes

The serial connection is configured with SERIAL_PORT in .env.

Two modes are supported:

  1. Local USB RS485 adapter
  2. TCP access to the RS485 USB adapter attached to the remote RS485 host using socat

Internally, the code uses pyserial's serial_for_url(), so both a normal device path and a pyserial URL work with the same setting.

Setup

Create .env from the template.

cp .env.template .env

Install from PyPI after the package is published:

pip install solar-rs485-monitor

For local development with uv and the project .venv:

uv venv --python 3.14 .venv
uv pip install --python .venv/bin/python -e .

Run the installed console command:

solar-rs485-monitor

Serial Configuration

Edit .env and enable exactly one SERIAL_PORT line.

For direct USB access:

SERIAL_PORT="/dev/ttyUSB0"
#SERIAL_PORT="socket://192.168.35.6:9600"

For the current development setup, where the RS485 USB adapter is attached to a remote RS485 host and WSL connects to it over TCP:

#SERIAL_PORT="/dev/ttyUSB0"
SERIAL_PORT="socket://192.168.35.6:9600"

Keep both lines in the file if that is convenient, but only one should be uncommented. If both are uncommented, the last parsed value can win and make the active connection unclear.

Other serial settings:

SERIAL_BAUDRATE="9600"
SERIAL_TIMEOUT="1.0"

Remote RS485 Host TCP Forwarding

In this project setup, the remote RS485 host is the device physically connected to the inverter RS485 USB converter. Because VS Code and development work may run from WSL, that host forwards /dev/ttyUSB0 over TCP with socat.

/usr/bin/socat TCP-LISTEN:9600,reuseaddr,fork FILE:/dev/ttyUSB0,raw,echo=0

Then set .env in the WSL development environment:

SERIAL_PORT="socket://RS485_HOST_IP:9600"

Example:

SERIAL_PORT="socket://192.168.35.6:9600"

If the inverter does not respond over TCP, also check that the remote RS485 host serial device is using the expected speed. Depending on the adapter and OS configuration, you may need to include the baud rate in the socat file options, for example:

/usr/bin/socat TCP-LISTEN:9600,reuseaddr,fork FILE:/dev/ttyUSB0,raw,echo=0,b9600

Inverter Protocol Configuration

The inverter request and expected response format are also configured in .env.

INVERTER_NAME="YOUR_INVERTER_NAME"
INVERTER_ID="1"
INVERTER_REQUEST_HEX="7e0101d188"
INVERTER_FRAME_LENGTH="33"
INVERTER_DATA_LENGTH="26"
INVERTER_CRC_ORDER="LH"

INVERTER_VERIFY_CRC is optional and defaults to true.

INVERTER_VERIFY_CRC="true"

Run

Collect once and print JSON:

solar-rs485-monitor

Override the port temporarily from the command line:

solar-rs485-monitor --port socket://192.168.35.6:9600

Repeat collection every 60 seconds:

solar-rs485-monitor --interval 60

Write collected rows to Google Sheets:

solar-rs485-monitor --google-sheet

Repeat collection and write to Google Sheets:

solar-rs485-monitor --interval 60 --google-sheet

Package Build

This project is structured as a PyPI package.

Build the source distribution and wheel:

uv build

The build outputs are created under dist/:

dist/solar_rs485_monitor-0.1.0.tar.gz
dist/solar_rs485_monitor-0.1.0-py3-none-any.whl

PyPI publishing is intentionally not handled by this repository code. Publish from your Git workflow after building and verifying the package.

Google Sheets Configuration

To use --google-sheet, configure these values in .env:

GOOGLE_SHEET_NAME="YOUR_GOOGLE_SHEET_FILE_NAME"
GOOGLE_WORKSHEET_NAME="YOUR_GOOGLE_SHEET_NAME"

Also provide the Google service account fields from .env.template.

The spreadsheet must be shared with the service account email:

GOOGLE_CLIENT_EMAIL="service-account@your-project-id.iam.gserviceaccount.com"

The collector creates the header row automatically if the worksheet is empty. If row 1 already exists and does not match the expected schema, the script stops with a header mismatch error.

Output

The script prints one JSON object per collection attempt.

Collected Metrics

For InoElectric IEPVS-3.5-G1/G2, the current parser interprets the response data payload as follows. Multi-byte values are decoded as big-endian unsigned integers.

Output field Data bytes Scale Unit Description
@timestamp N/A N/A ISO 8601 UTC Collection timestamp generated by the collector
inverter_name N/A N/A text Name from INVERTER_NAME
inverter_id frame byte 1 1 numeric ID Inverter ID returned by the device
pv_voltage_v data 0-1 1 V PV input voltage
pv_current_a data 2-3 1 A PV input current
pv_power_w data 4-5 1 W PV input power
grid_voltage_v data 6-7 1 V Grid voltage
grid_current_a data 8-9 1 A Grid current
current_output_w data 10-11 1 W Current AC output power
power_factor_pct data 12-13 0.1 % Power factor percentage
frequency_hz data 14-15 0.1 Hz Grid frequency
total_generation_kwh data 16-23 0.001 kWh Total accumulated generation
fault_code data 24-25 1 code Raw fault code
fault derived from fault_code N/A boolean true when fault_code != 0
raw_frame_hex full frame N/A hex bytes Raw response frame for debugging

Successful reads include fields such as:

{
  "@timestamp": "2026-06-29T00:00:00+00:00",
  "inverter_name": "YOUR_INVERTER_NAME",
  "inverter_id": 1,
  "pv_voltage_v": 0,
  "pv_current_a": 0,
  "pv_power_w": 0,
  "grid_voltage_v": 0,
  "grid_current_a": 0,
  "current_output_w": 0,
  "power_factor_pct": 0.0,
  "frequency_hz": 0.0,
  "total_generation_kwh": 0.0,
  "fault_code": 0,
  "fault": false,
  "raw_frame_hex": "..."
}

Errors are also printed as JSON:

{
  "@timestamp": "2026-06-29T00:00:00+00:00",
  "inverter_name": "YOUR_INVERTER_NAME",
  "error": "No response from inverter"
}

Troubleshooting

  • No response from inverter: check SERIAL_PORT, remote RS485 host IP, TCP port, RS485 wiring, inverter ID, and baud rate.
  • Connection refused: socat is not running, the IP/port is wrong, or a firewall is blocking access.
  • CRC mismatch: check INVERTER_CRC_ORDER, request bytes, and whether the expected frame length matches the actual inverter response.
  • Google Sheet not found or access denied: share the spreadsheet with GOOGLE_CLIENT_EMAIL.
  • Google worksheet not found: create the worksheet tab or fix GOOGLE_WORKSHEET_NAME.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

solar_rs485_monitor-0.0.2.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

solar_rs485_monitor-0.0.2-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file solar_rs485_monitor-0.0.2.tar.gz.

File metadata

  • Download URL: solar_rs485_monitor-0.0.2.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for solar_rs485_monitor-0.0.2.tar.gz
Algorithm Hash digest
SHA256 8677bd7cf73afe62b30086f3c67639ef2cbd1c422cd4f9d736ff144ce3bbfc7e
MD5 255d0e1b2100afc3eb932a33632cdadc
BLAKE2b-256 7519d14e097ec463051ddc398027a3ee949e13770ee017d9615a4e71d14da998

See more details on using hashes here.

Provenance

The following attestation bundles were made for solar_rs485_monitor-0.0.2.tar.gz:

Publisher: pypi-publish.yml on call518/Solar-RS485-Monitor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file solar_rs485_monitor-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for solar_rs485_monitor-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0b2a411f4c90ea987b4f5a6823cd5cde2fb4211e02b407cc48a55fd60b485cb0
MD5 d709d93a10003127ae092e18e82004d6
BLAKE2b-256 42292fbd2b8d5d101f61439cb1d7eaf5f52131926a670d11db98973503ff4933

See more details on using hashes here.

Provenance

The following attestation bundles were made for solar_rs485_monitor-0.0.2-py3-none-any.whl:

Publisher: pypi-publish.yml on call518/Solar-RS485-Monitor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page