Asyncio Python client for E3/DC's RSCP (Remote Storage Control Protocol)
Project description
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 (
0xDCE3magic, 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
- Python 3.9+
py3rijndael
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 callRscpEncryption.reset()(RscpConnection.connect()does this automatically). TAG_RSCP_AUTHENTICATIONresponses on failure come back asInt32instead of the declaredUChar8— handled as a special case inRscpValue.unpack.- Error tags use type id
0xFF; a 1-byte payload is anError8, a 4-byte payload anError32. CheckRscpValue.isErrorafter unpacking. - Ciphertext whose length is not a multiple of the block size cannot be decrypted —
decrypt()returnsNoneand a warning is logged. The caller is expected to read more bytes and retry. - Outgoing frames set nanoseconds to
0; onlyint(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.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rscp_lib-1.0.0.tar.gz.
File metadata
- Download URL: rscp_lib-1.0.0.tar.gz
- Upload date:
- Size: 52.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66d0d6a399e56c7192326de3ec6c8d790f6bab6d94e00cc615f07b71c822a939
|
|
| MD5 |
631fe71b76cd829f5b2d6f77345859c4
|
|
| BLAKE2b-256 |
0b5053ef1402899c05756b435e3eda18c2c5f96c56d0a49a962da44efe6664db
|
Provenance
The following attestation bundles were made for rscp_lib-1.0.0.tar.gz:
Publisher:
publish.yml on tobias-terhaar/rscp-lib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rscp_lib-1.0.0.tar.gz -
Subject digest:
66d0d6a399e56c7192326de3ec6c8d790f6bab6d94e00cc615f07b71c822a939 - Sigstore transparency entry: 1364863593
- Sigstore integration time:
-
Permalink:
tobias-terhaar/rscp-lib@4bbfaae463f52c6327584f3e552633cce2fac21c -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/tobias-terhaar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bbfaae463f52c6327584f3e552633cce2fac21c -
Trigger Event:
release
-
Statement type:
File details
Details for the file rscp_lib-1.0.0-py3-none-any.whl.
File metadata
- Download URL: rscp_lib-1.0.0-py3-none-any.whl
- Upload date:
- Size: 46.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
901a5698e69efbfe84c590c8a320ce1fb107363a1a6fce1e6f4060526ba4387c
|
|
| MD5 |
cc6e7693d9bf563c155cfc862f7a7270
|
|
| BLAKE2b-256 |
dbc5bbe99a1e2dca150f9eebc21f58154855dbef52115500a7c5fa8e2dd58b40
|
Provenance
The following attestation bundles were made for rscp_lib-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on tobias-terhaar/rscp-lib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rscp_lib-1.0.0-py3-none-any.whl -
Subject digest:
901a5698e69efbfe84c590c8a320ce1fb107363a1a6fce1e6f4060526ba4387c - Sigstore transparency entry: 1364863640
- Sigstore integration time:
-
Permalink:
tobias-terhaar/rscp-lib@4bbfaae463f52c6327584f3e552633cce2fac21c -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/tobias-terhaar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bbfaae463f52c6327584f3e552633cce2fac21c -
Trigger Event:
release
-
Statement type: