Project

e3dc-mqtt

0.0
No release in over 3 years
MQTT bridge for E3DC solar battery systems using the RSCP protocol
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 0.6
~> 4.0
 Project Readme

e3dc-mqtt-ruby

A Ruby bridge between E3DC solar battery storage systems and MQTT, using the RSCP protocol. Ruby port of e3dc-mqtt-go / e3dc-mqtt-rs with feature parity for the read side.

Repository: https://github.com/isnogudus/e3dc-mqtt-ruby

Features

  • Real-time power values (PV, battery, grid, home, wallbox)
  • Battery state of charge, cycle count, cell voltages/temperatures
  • Daily statistics (production, consumption, autarky)
  • Delta-based publishing (only changed values hit the broker)
  • Aligned polling intervals (ticks on clock boundaries)
  • TLS with verification toggle, LWT
  • Pure-Ruby RSCP implementation — no C extensions, no FFI
  • Complete RSCP tag registry (3564 tags, auto-generated from the Go reference)

Requirements

  • Ruby ≥ 3.4 (uses Data.define)
  • An E3DC system with the RSCP interface enabled
  • An MQTT broker

Installation

bundle install
cp config.toml.example config.toml
$EDITOR config.toml            # fill in RSCP host/user/password/key + MQTT

Configuration

log_level = "INFO"             # DEBUG, INFO, WARN, ERROR

[e3dc]
host = "192.168.1.100"
port = 5033                    # default
username = "your_username"
password = "your_password"
key = "your_rscp_key"
interval = "5s"                # polling interval (min 5s)
statistic_update_interval = "5m"

[mqtt]
url = "ssl://broker:8883"      # or tcp://broker:1883
root = "e3dc"                  # topic prefix
client_id = "e3dc-mqtt-ruby"
username = ""                  # optional
password = ""                  # optional
tls_verify = true              # set false for self-signed certs

Running

bundle exec bin/e3dc-mqtt -c config.toml

For a one-shot liveness probe without touching MQTT:

bundle exec bin/probe -c config.toml

The bridge follows a "let it crash" model — on errors it exits with a specific code and a supervisor (systemd, runit, Docker) should restart it.

Exit codes

Code Meaning
0 Clean shutdown
1 Configuration error
4 E3DC connection error
5 MQTT connection error
6 System-info error
10 Status publish error
11 Statistics publish error
12 Battery publish error

MQTT topics

All topics are prefixed with {root}/{model}-{serial}/.

  • online — retained LWT (true/false)
  • info — retained JSON system info
  • status/… — 5-second cadence (pv, grid, battery, autarky, …)
  • status_sums/…statistic_update_interval cadence (daily totals)
  • status/battery:N/… and status/battery:N/dcb:M/… — battery detail

Full topic list: see e3dc-mqtt-go README.

Architecture

lib/e3dc_mqtt/
├── config.rb            TOML loader + validation
├── types.rb             Data.define value types (Status, BatteryData, …)
├── app.rb               Main loop, aligned tickers, signals
├── e3dc.rb              High-level E3DC client (status, info, stats, batteries)
├── mqtt_client.rb       Delta-publish, JSON, LWT, TLS verify toggle
└── rscp/                Pure-Ruby RSCP protocol
    ├── constants.rb     Frame layout, control-field masks
    ├── data_type.rb     18 RSCP types (pack/unpack)
    ├── message.rb       Message value + codec (with container recursion)
    ├── frame.rb         Frame writer/reader + CRC32
    ├── rijndael256.rb   Rijndael-256 CBC (32-byte block, 14 rounds)
    ├── tags.rb          Generated: 3564 tags, 712 declared data types
    └── client.rb        TCP + auth + send/receive (stateful CBC)

Regenerating the tag registry

The tag registry in lib/e3dc_mqtt/rscp/tags.rb is generated from the Go reference's tag.go and tag_datatype.go. To pick up new tags when the Go library updates:

ruby tools/generate_tags.rb             # uses default Go module cache path
ruby tools/generate_tags.rb /path/to/go-rscp/rscp

Tests

bundle exec rake test

Covers the config loader, the RSCP framing round-trip, Rijndael-256 against known Go-reference vectors, the tag registry, and an end-to-end loopback test of the RSCP client (real TCP server, full auth handshake, stateful CBC across messages).

Credits

Ported from and verified against these upstream projects:

  • spali/go-rscp — the Go RSCP library. Structural reference for framing, tag registry, data-type marshalling, and the client/auth flow. tools/generate_tags.rb parses its sources verbatim.
  • azihsoyn/rijndael256 — the Go Rijndael-256 implementation the rscp/rijndael256.rb port is based on. The single-block and CBC outputs match byte-for-byte. The original ancestor is agl/pond.
  • isnogudus/e3dc-mqtt-go — the Go MQTT bridge. Blueprint for the high-level E3DC::Client structure, MQTT topic naming, delta publishing, and the daily-statistics boundary logic.
  • isnogudus/e3dc-mqtt-rs — the Rust MQTT bridge. Cross-checked for protocol details and tag coverage.

License

MIT — see LICENSE. Third-party attributions (for the Rijndael-256 port and the go-rscp-derived tag registry) are preserved in NOTICE.