Skip to main content

rscp_lib

An asyncio Python client library for E3/DC's RSCP (Remote Storage Control Protocol) — the TCP protocol used to communicate with E3/DC home-storage and energy-management devices (default port 5033).

The library handles the full protocol stack:

  • TCP framing (0xDCE3 magic, timestamp, length)
  • AES/Rijndael-256 CBC encryption with stateful IV chaining
  • Authentication (user/password)
  • Typed tag/value (TLV) (de)serialization, including nested containers
  • A small path/filter query language for extracting values from responses

Requirements

pip install py3rijndael

Installation

The package is not yet published to PyPI. Install directly from the repository:

pip install git+https://github.com/<your-user>/e3dc_rscp_lib.git

or clone and add the project root to your PYTHONPATH.

Quick start

import asyncio

from rscp_lib.RscpConnection import RscpConnection
from rscp_lib.RscpEncryption import RscpEncryption
from rscp_lib.RscpFrame import RscpFrame
from rscp_lib.RscpValue import RscpValue


async def main():
    cipher = RscpEncryption("YOUR_RSCP_PASSPHRASE")
    conn = RscpConnection(
        host="192.168.1.50",
        port=5033,
        ciphersuite=cipher,
        username="user@example.com",
        password="portal-password",
    )

    await conn.connect()
    if not await conn.authorize():
        raise RuntimeError("authentication failed")

    # Request the current PV power
    request = RscpValue().withTagName("TAG_EMS_REQ_POWER_PV", None)
    await conn.send(RscpFrame().packFrame(request))

    data = await conn.receive()
    frame = RscpFrame()
    frame.unpack(data)

    for value in frame.getRscpValues():
        print(value.toString())

    conn.disconnect()


asyncio.run(main())

Building requests

Simple values use withTagName:

RscpValue().withTagName("TAG_EMS_REQ_POWER_BAT", None)

Nested containers can be built declaratively via construct_rscp_value:

req = RscpValue.construct_rscp_value(
    "TAG_RSCP_REQ_AUTHENTICATION",
    [
        ["TAG_RSCP_AUTHENTICATION_USER", "user@example.com"],
        ["TAG_RSCP_AUTHENTICATION_PASSWORD", "secret"],
    ],
)

Reading responses

For navigating deeply nested container responses, use the path helper:

values = frame.getRscpValues()

# Direct child
soc = RscpValue.get_tag_by_path(values, "TAG_EMS_BAT_SOC")

# Nested path
v = RscpValue.get_tag_by_path(values, "TAG_PVI_DATA/TAG_PVI_DC_POWER")

# Filter a container by a child tag's value, then descend
string0 = RscpValue.get_tag_by_path(
    values,
    "TAG_PVI_DATA(TAG_PVI_INDEX==0)/TAG_PVI_DC_POWER",
)

Architecture

The stack is built from four composable layers:

Layer Module Responsibility
Tag/Value (TLV) RscpValue.py Typed tag-value encoding with nested containers
Frame RscpFrame.py Wire frame header, timestamp, and length
Encryption RscpEncryption.py Rijndael-256 CBC with rolling IV
Connection RscpConnection.py Async TCP socket, authentication, send/receive

RscpTags.py contains the full tag dictionary (tag name → tag code + declared type), used for both packing outgoing values and decoding incoming ones.

Protocol notes

A few things worth knowing when extending the library:

  • Encryption IVs start as 0xff × 32 and are updated to the last ciphertext block after every operation. A new connection must call RscpEncryption.reset() (RscpConnection.connect() does this automatically).
  • TAG_RSCP_AUTHENTICATION responses on failure come back as Int32 instead of the declared UChar8 — handled as a special case in RscpValue.unpack.
  • Error tags use type id 0xFF; a 1-byte payload is an Error8, a 4-byte payload an Error32. Check RscpValue.isError after unpacking.
  • Ciphertext whose length is not a multiple of the block size cannot be decrypted — decrypt() returns None and a warning is logged. The caller is expected to read more bytes and retry.
  • Outgoing frames set nanoseconds to 0; only int(time.time()) is transmitted.

Status

This is an independent implementation of the RSCP protocol based on publicly available documentation and is not affiliated with or endorsed by E3/DC GmbH. The tag dictionary is fairly complete, but not every tag combination has been exercised against real hardware. Contributions and bug reports are welcome.

License

The code is distributed under MIT license. See LICENSE file for details.

Metadata

Release files for rscp-lib 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rscp-lib 1.0.2
File Size Uploaded
rscp_lib-1.0.2.tar.gz 52.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rscp-lib 1.0.2
File Interpreter ABI Platform
rscp_lib-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 98.7 kB

Release files / rscp_lib-1.0.2.tar.gz

Download URL rscp_lib-1.0.2.tar.gz
Size 52.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a7e7893360e66cd551184510a23a664490a2103e050fb20cfeb8ede45e3e041f
BLAKE2b-256 checksum
How to use checksums
bb68fede0c3a1e5f7b0ef82c85e1b88db9ecc3fec13038e5d945f2563baf8356
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / rscp_lib-1.0.2-py3-none-any.whl

Download URL rscp_lib-1.0.2-py3-none-any.whl
Size 46.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1cc9722578c93aa6a4505952f429ec05e8874f9df91781d36581c16e3aa0a2ac
BLAKE2b-256 checksum
How to use checksums
82d2b8f80ab31be8a61991fd9ffc3d4c0ae70084ee9901d1018eb18c3ca6322d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page