elli-2-modbus 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ python: ["3.10", "3.11", "3.12", "3.13"]
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: actions/setup-python@v5
12
+ with:
13
+ python-version: ${{ matrix.python }}
14
+ - run: pip install -e ".[test]"
15
+ - run: pytest
@@ -0,0 +1,19 @@
1
+ # Publishes to PyPI when a GitHub release is published.
2
+ # One-time setup on pypi.org: add a "trusted publisher" for this repo and workflow.
3
+ name: Publish
4
+ on:
5
+ release:
6
+ types: [published]
7
+ jobs:
8
+ pypi:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.13"
18
+ - run: pip install build && python -m build
19
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .DS_Store
7
+ dist/
8
+ *.egg-info/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Frane Bandov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.5
2
+ Name: elli-2-modbus
3
+ Version: 0.1.0
4
+ Summary: Local Modbus TCP control of Elli Charger 2 wallboxes (VW ID. Charger 2, Škoda, CUPRA)
5
+ Project-URL: Homepage, https://github.com/frane/elli-2-modbus
6
+ Project-URL: Issues, https://github.com/frane/elli-2-modbus/issues
7
+ Author: Frane Bandov
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: elli,ev-charger,home-assistant,modbus,volkswagen,wallbox
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: AsyncIO
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Home Automation
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.10
19
+ Provides-Extra: test
20
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
21
+ Requires-Dist: pytest>=8; extra == 'test'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # elli-2-modbus
25
+
26
+ **English** | [Deutsch](README.de.md)
27
+
28
+ Python library and CLI for local control of **Elli Charger 2** wallboxes over **Modbus TCP**. No cloud, no EEBUS, and no dependencies.
29
+
30
+ The Home Assistant integration built on it is [ha-elli-2-modbus](https://github.com/frane/ha-elli-2-modbus).
31
+
32
+ ## Supported wallboxes
33
+
34
+ Second-generation Elli wallboxes with firmware **R03.004.045.121-elli or newer** (the version that added the Modbus server):
35
+
36
+ - Elli Charger Connect 2, Pro 2, Pro 2 Eichrecht
37
+ - Volkswagen ID. Charger Connect 2 / Pro 2
38
+ - Škoda Charger Connect 2 / Pro 2
39
+ - CUPRA Charger 2 / Pro 2
40
+
41
+ Modbus runs alongside the Elli backend, so the Elli app, OCPP and firmware updates keep working.
42
+
43
+ ## Enable Modbus on the wallbox
44
+
45
+ Short version (detailed guide: [docs/enable-modbus.md](docs/enable-modbus.md)):
46
+
47
+ 1. Open the charger configuration in a browser at `https://<IP or hostname>`. Alternatively, connect to the wallbox hotspot and open `https://10.0.2.1`. Accept the certificate warning (**Advanced** → continue).
48
+ 2. Log in as **Service User** with the service user password from the access data card.
49
+ 3. **Software update**: the firmware must be **R03.004.045.121 or newer**.
50
+ 4. **Connections → Modbus server**: switch it **on**. Port 502, unit ID 1.
51
+ 5. Give the wallbox a fixed IP address (a DHCP reservation in your router).
52
+ 6. If something else controls the current, set **Charging management → Charging settings → PV surplus charging** to **off**.
53
+ 7. Test: `elli-2-modbus status <ip>`
54
+
55
+ The interface is also available in German, with the same steps: *Verbindungen → Modbus-Server*, *Ladeverwaltung → Ladeeinstellungen*.
56
+
57
+ ## CLI
58
+
59
+ ```bash
60
+ pip install elli-2-modbus
61
+
62
+ elli-2-modbus status 192.168.1.50 # read everything
63
+ elli-2-modbus status 192.168.1.50 --json
64
+ elli-2-modbus set-current 192.168.1.50 10 # allow charging with up to 10 A
65
+ elli-2-modbus stop 192.168.1.50 # block charging
66
+ elli-2-modbus set-failsafe 192.168.1.50 0 # what happens when Modbus traffic stops
67
+ elli-2-modbus set-watchdog 192.168.1.50 30
68
+ elli-2-modbus simulate --port 5020 # simulated wallbox for testing
69
+ ```
70
+
71
+ Without installing, from the repo: `PYTHONPATH=src python3 -m elli2modbus status <ip>`
72
+
73
+ ## Library
74
+
75
+ ```python
76
+ from elli2modbus import ElliCharger
77
+
78
+ async with ElliCharger("192.168.1.50") as charger:
79
+ info = await charger.read_info() # layout version, min/max current
80
+ status = await charger.read_status() # state, currents, voltages, power, energy, limits
81
+ if status.vehicle_connected:
82
+ await charger.set_current(10) # 0.1 A resolution
83
+ await charger.stop()
84
+ ```
85
+
86
+ The library raises three errors: `ModbusConnectionError` when the wallbox cannot be reached, `ModbusExceptionResponse` when it rejects the request, and `ValueError` when a value is out of range.
87
+
88
+ ## Things to know
89
+
90
+ - **Watchdog:** if the wallbox sees no Modbus traffic for the watchdog time (default 15 s), it falls back to the failsafe current. Poll faster than that, and set the failsafe current deliberately: 0 stops charging, 6 A or more keeps charging.
91
+ - **Maximum 16 A** over Modbus for now, including the 22 kW variants. Elli has announced 32 A for a future firmware.
92
+ - **No phase switching** over Modbus.
93
+ - Register 261 can report **less than you wrote**, because the wallbox's internal limits take priority. `status.current_limit` shows the limit that is actually in effect.
94
+ - Power is reported as apparent power (VA).
95
+
96
+ Register reference: [docs/registers.md](docs/registers.md).
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ python3 -m venv .venv && . .venv/bin/activate
102
+ pip install -e ".[test]"
103
+ pytest
104
+ ```
105
+
106
+ The simulator only implements registers from Elli's register list. Undocumented ones (for example Heidelberg's 13, 258, 259) return Modbus exception 2, like the real device.
107
+
108
+ *Not affiliated with Elli or Volkswagen Group Charging GmbH.*
@@ -0,0 +1,85 @@
1
+ # elli-2-modbus
2
+
3
+ [English](README.md) | **Deutsch**
4
+
5
+ Python-Bibliothek und Kommandozeilen-Tool, um **Elli Charger 2** Wallboxen lokal über **Modbus TCP** zu steuern. Ohne Cloud, ohne EEBUS und ohne Abhängigkeiten.
6
+
7
+ Die Home-Assistant-Integration dazu ist [ha-elli-2-modbus](https://github.com/frane/ha-elli-2-modbus).
8
+
9
+ ## Unterstützte Wallboxen
10
+
11
+ Elli-Wallboxen der zweiten Generation mit Firmware **R03.004.045.121-elli oder neuer** (seitdem gibt es den Modbus-Server):
12
+
13
+ - Elli Charger Connect 2, Pro 2, Pro 2 Eichrecht
14
+ - Volkswagen ID. Charger Connect 2 / Pro 2
15
+ - Škoda Charger Connect 2 / Pro 2
16
+ - CUPRA Charger 2 / Pro 2
17
+
18
+ Modbus läuft parallel zum Elli-Backend. Elli-App, OCPP und Firmware-Updates funktionieren also weiter.
19
+
20
+ ## Modbus an der Wallbox aktivieren
21
+
22
+ Kurzfassung (ausführlich: [docs/enable-modbus.de.md](docs/enable-modbus.de.md)):
23
+
24
+ 1. Wallbox-Konfiguration im Browser öffnen: `https://<IP oder Hostname>`, oder mit dem Hotspot der Wallbox verbinden und `https://10.0.2.1` öffnen. Die Zertifikatswarnung bestätigen (**Erweitert** → fortfahren).
25
+ 2. Als **Service User** mit dem Service-User-Passwort von der Zugangsdatenkarte anmelden.
26
+ 3. **Software-Update**: Die Firmware muss **R03.004.045.121 oder neuer** sein.
27
+ 4. **Verbindungen → Modbus-Server**: **einschalten**. Port 502, Modbus-ID 1.
28
+ 5. Der Wallbox eine feste IP geben (DHCP-Reservierung im Router).
29
+ 6. Wenn ein anderes System den Strom regelt: **Ladeverwaltung → Ladeeinstellungen → PV-Überschuss-Laden** auf **PV-Laden aus** stellen.
30
+ 7. Testen: `elli-2-modbus status <ip>`
31
+
32
+ Auf Englisch heißen die Menüs *Connections → Modbus server* und *Charging management → Charging settings*.
33
+
34
+ ## Kommandozeile
35
+
36
+ ```bash
37
+ pip install elli-2-modbus
38
+
39
+ elli-2-modbus status 192.168.1.50 # alles auslesen
40
+ elli-2-modbus status 192.168.1.50 --json
41
+ elli-2-modbus set-current 192.168.1.50 10 # Laden mit bis zu 10 A freigeben
42
+ elli-2-modbus stop 192.168.1.50 # Laden sperren
43
+ elli-2-modbus set-failsafe 192.168.1.50 0 # Verhalten, wenn der Modbus-Verkehr ausbleibt
44
+ elli-2-modbus set-watchdog 192.168.1.50 30
45
+ elli-2-modbus simulate --port 5020 # simulierte Wallbox zum Testen
46
+ ```
47
+
48
+ Ohne Installation, direkt aus dem Repo: `PYTHONPATH=src python3 -m elli2modbus status <ip>`
49
+
50
+ ## Bibliothek
51
+
52
+ ```python
53
+ from elli2modbus import ElliCharger
54
+
55
+ async with ElliCharger("192.168.1.50") as charger:
56
+ info = await charger.read_info() # Layout-Version, min./max. Strom
57
+ status = await charger.read_status() # Status, Ströme, Spannungen, Leistung, Energie, Grenzen
58
+ if status.vehicle_connected:
59
+ await charger.set_current(10) # Auflösung 0,1 A
60
+ await charger.stop()
61
+ ```
62
+
63
+ Die Bibliothek wirft drei Fehler: `ModbusConnectionError`, wenn die Wallbox nicht erreichbar ist, `ModbusExceptionResponse`, wenn sie die Anfrage ablehnt, und `ValueError`, wenn ein Wert außerhalb des Bereichs liegt.
64
+
65
+ ## Gut zu wissen
66
+
67
+ - **Watchdog:** Sieht die Wallbox länger als die Watchdog-Zeit (Standard 15 s) keinen Modbus-Verkehr, fällt sie auf den Failsafe-Strom zurück. Deshalb häufiger abfragen und den Failsafe-Strom bewusst setzen: 0 stoppt das Laden, ab 6 A lädt sie weiter.
68
+ - **Maximal 16 A** per Modbus, auch bei den 22-kW-Varianten. Elli hat 32 A für eine künftige Firmware angekündigt.
69
+ - **Keine Phasenumschaltung** per Modbus.
70
+ - Register 261 kann **weniger zurückmelden als geschrieben**, weil die internen Grenzen der Wallbox Vorrang haben. `status.current_limit` zeigt die Grenze, die tatsächlich gilt.
71
+ - Die Leistung wird als Scheinleistung (VA) gemeldet.
72
+
73
+ Register-Referenz: [docs/registers.md](docs/registers.md).
74
+
75
+ ## Entwicklung
76
+
77
+ ```bash
78
+ python3 -m venv .venv && . .venv/bin/activate
79
+ pip install -e ".[test]"
80
+ pytest
81
+ ```
82
+
83
+ Der Simulator kennt nur die Register aus Ellis Registerliste. Nicht dokumentierte Register (z. B. 13, 258 und 259 von Heidelberg) beantwortet er wie das echte Gerät mit Modbus-Exception 2.
84
+
85
+ *Kein offizielles Projekt von Elli oder der Volkswagen Group Charging GmbH.*
@@ -0,0 +1,85 @@
1
+ # elli-2-modbus
2
+
3
+ **English** | [Deutsch](README.de.md)
4
+
5
+ Python library and CLI for local control of **Elli Charger 2** wallboxes over **Modbus TCP**. No cloud, no EEBUS, and no dependencies.
6
+
7
+ The Home Assistant integration built on it is [ha-elli-2-modbus](https://github.com/frane/ha-elli-2-modbus).
8
+
9
+ ## Supported wallboxes
10
+
11
+ Second-generation Elli wallboxes with firmware **R03.004.045.121-elli or newer** (the version that added the Modbus server):
12
+
13
+ - Elli Charger Connect 2, Pro 2, Pro 2 Eichrecht
14
+ - Volkswagen ID. Charger Connect 2 / Pro 2
15
+ - Škoda Charger Connect 2 / Pro 2
16
+ - CUPRA Charger 2 / Pro 2
17
+
18
+ Modbus runs alongside the Elli backend, so the Elli app, OCPP and firmware updates keep working.
19
+
20
+ ## Enable Modbus on the wallbox
21
+
22
+ Short version (detailed guide: [docs/enable-modbus.md](docs/enable-modbus.md)):
23
+
24
+ 1. Open the charger configuration in a browser at `https://<IP or hostname>`. Alternatively, connect to the wallbox hotspot and open `https://10.0.2.1`. Accept the certificate warning (**Advanced** → continue).
25
+ 2. Log in as **Service User** with the service user password from the access data card.
26
+ 3. **Software update**: the firmware must be **R03.004.045.121 or newer**.
27
+ 4. **Connections → Modbus server**: switch it **on**. Port 502, unit ID 1.
28
+ 5. Give the wallbox a fixed IP address (a DHCP reservation in your router).
29
+ 6. If something else controls the current, set **Charging management → Charging settings → PV surplus charging** to **off**.
30
+ 7. Test: `elli-2-modbus status <ip>`
31
+
32
+ The interface is also available in German, with the same steps: *Verbindungen → Modbus-Server*, *Ladeverwaltung → Ladeeinstellungen*.
33
+
34
+ ## CLI
35
+
36
+ ```bash
37
+ pip install elli-2-modbus
38
+
39
+ elli-2-modbus status 192.168.1.50 # read everything
40
+ elli-2-modbus status 192.168.1.50 --json
41
+ elli-2-modbus set-current 192.168.1.50 10 # allow charging with up to 10 A
42
+ elli-2-modbus stop 192.168.1.50 # block charging
43
+ elli-2-modbus set-failsafe 192.168.1.50 0 # what happens when Modbus traffic stops
44
+ elli-2-modbus set-watchdog 192.168.1.50 30
45
+ elli-2-modbus simulate --port 5020 # simulated wallbox for testing
46
+ ```
47
+
48
+ Without installing, from the repo: `PYTHONPATH=src python3 -m elli2modbus status <ip>`
49
+
50
+ ## Library
51
+
52
+ ```python
53
+ from elli2modbus import ElliCharger
54
+
55
+ async with ElliCharger("192.168.1.50") as charger:
56
+ info = await charger.read_info() # layout version, min/max current
57
+ status = await charger.read_status() # state, currents, voltages, power, energy, limits
58
+ if status.vehicle_connected:
59
+ await charger.set_current(10) # 0.1 A resolution
60
+ await charger.stop()
61
+ ```
62
+
63
+ The library raises three errors: `ModbusConnectionError` when the wallbox cannot be reached, `ModbusExceptionResponse` when it rejects the request, and `ValueError` when a value is out of range.
64
+
65
+ ## Things to know
66
+
67
+ - **Watchdog:** if the wallbox sees no Modbus traffic for the watchdog time (default 15 s), it falls back to the failsafe current. Poll faster than that, and set the failsafe current deliberately: 0 stops charging, 6 A or more keeps charging.
68
+ - **Maximum 16 A** over Modbus for now, including the 22 kW variants. Elli has announced 32 A for a future firmware.
69
+ - **No phase switching** over Modbus.
70
+ - Register 261 can report **less than you wrote**, because the wallbox's internal limits take priority. `status.current_limit` shows the limit that is actually in effect.
71
+ - Power is reported as apparent power (VA).
72
+
73
+ Register reference: [docs/registers.md](docs/registers.md).
74
+
75
+ ## Development
76
+
77
+ ```bash
78
+ python3 -m venv .venv && . .venv/bin/activate
79
+ pip install -e ".[test]"
80
+ pytest
81
+ ```
82
+
83
+ The simulator only implements registers from Elli's register list. Undocumented ones (for example Heidelberg's 13, 258, 259) return Modbus exception 2, like the real device.
84
+
85
+ *Not affiliated with Elli or Volkswagen Group Charging GmbH.*
@@ -0,0 +1,62 @@
1
+ # Modbus TCP an der Elli Charger 2 aktivieren
2
+
3
+ [English](enable-modbus.md) | **Deutsch**
4
+
5
+ Gilt für Elli Charger Connect 2 / Pro 2 / Pro 2 Eichrecht, VW ID. Charger 2, Škoda Charger 2 und CUPRA Charger 2. Die Weboberfläche der Wallbox gibt es auf Deutsch und Englisch (sie richtet sich nach der Browsersprache). Menünamen stehen unten auf Deutsch, die englische Bezeichnung in Klammern.
6
+
7
+ Du brauchst die **Zugangsdatenkarte**, die bei der Wallbox lag. Darauf stehen WLAN-Name und -Passwort, der Hostname und das **Passwort für den Service User**.
8
+
9
+ ## 1. Wallbox-Konfiguration öffnen
10
+
11
+ **Variante A: über das Heimnetz** (Wallbox per LAN oder WLAN verbunden)
12
+
13
+ - Im Browser im selben Netz `https://<Hostname>` (von der Karte) oder `https://<IP der Wallbox>` öffnen. Die IP findest du in der Geräteliste deines Routers.
14
+
15
+ **Variante B: über den Hotspot der Wallbox**
16
+
17
+ - Mit dem WLAN der Wallbox verbinden (SSID und Passwort von der Karte) oder den QR-Code auf der Karte scannen.
18
+ - `https://10.0.2.1` öffnen.
19
+
20
+ Der Browser warnt vor einer unsicheren Verbindung, weil die Wallbox ein selbst signiertes Zertifikat nutzt. Auf **Erweitert** (*Advanced*) klicken und fortfahren.
21
+
22
+ ## 2. Als Service User anmelden
23
+
24
+ Rolle **Service User** wählen und das Service-User-Passwort von der Karte eingeben. Der Standard User darf keine Systemeinstellungen ändern.
25
+
26
+ ## 3. Firmware prüfen
27
+
28
+ Unter **Software-Update** (*Software update*) steht die installierte Version. Modbus braucht **R03.004.045.121-elli oder neuer**. Ist sie älter, zuerst aktualisieren (Elli-App oder *Software-Update*).
29
+
30
+ ## 4. Modbus-Server einschalten
31
+
32
+ **Verbindungen → Modbus-Server** (*Connections → Modbus server*) → **Modbus-Server** einschalten.
33
+
34
+ | Einstellung | Wert |
35
+ |---|---|
36
+ | Port | 502 |
37
+ | Modbus-ID (Unit ID) | 1 |
38
+
39
+ ## 5. Feste IP-Adresse vergeben
40
+
41
+ Die IP der Wallbox im Router reservieren (DHCP-Reservierung) oder unter **Verbindungen → Ethernet** (*Connections → Ethernet*) eine statische Adresse eintragen und DHCP ausschalten. Der Client muss im selben lokalen Netz sein; über LTE funktioniert es nicht.
42
+
43
+ ## 6. Eigenes PV-Überschussladen der Wallbox ausschalten
44
+
45
+ Wenn ein anderes System den Strom regelt, soll die Wallbox nicht gleichzeitig selbst regeln:
46
+
47
+ **Ladeverwaltung → Ladeeinstellungen → PV-Überschuss-Laden → PV-Laden aus** (*Charging management → Charging settings → PV surplus charging → off*).
48
+
49
+ ## 7. Testen
50
+
51
+ ```bash
52
+ pip install elli-2-modbus
53
+ elli-2-modbus status <IP der Wallbox>
54
+ ```
55
+
56
+ Du solltest Ladestatus, Spannungen und Stromgrenze sehen. Bei `cannot connect`: Ist der Modbus-Server an, die IP richtig, und sind beide Geräte im selben Netz?
57
+
58
+ ## Gut zu wissen
59
+
60
+ - Modbus läuft **zusätzlich** zum Elli-Backend. Elli-App, OCPP und Firmware-Updates funktionieren weiter.
61
+ - **Watchdog:** Sobald einmal Modbus-Verkehr stattgefunden hat, erwartet die Wallbox regelmäßigen Verkehr (Standard alle 15 s). Bleibt er aus, schaltet sie auf den **Failsafe-Strom**. Den bewusst setzen: `elli-2-modbus set-failsafe <ip> 0` stoppt das Laden, `6` lädt langsam weiter.
62
+ - **Autorisierung:** Modbus setzt die Stromgrenze. Ob ein Ladevorgang zusätzlich RFID oder App-Freigabe braucht, hängt von den Wallbox-Einstellungen ab. Für vollautomatisches Laden in der Elli-App *Sofortladen* (Laden ohne Authentifizierung) aktivieren.
@@ -0,0 +1,62 @@
1
+ # Enabling Modbus TCP on an Elli Charger 2
2
+
3
+ **English** | [Deutsch](enable-modbus.de.md)
4
+
5
+ Applies to Elli Charger Connect 2 / Pro 2 / Pro 2 Eichrecht, VW ID. Charger 2, Škoda Charger 2 and CUPRA Charger 2. The wallbox web interface is available in English and German (it follows the browser language). Menu names below are English, with the German label in brackets.
6
+
7
+ You need the **card with the access data** that came with the wallbox: Wi-Fi SSID and password, hostname, and the **service user password**.
8
+
9
+ ## 1. Open the charger configuration
10
+
11
+ **Option A: through your home network** (the wallbox is connected by LAN or Wi-Fi)
12
+
13
+ - In a browser on the same network, open `https://<hostname>` (hostname from the card) or `https://<IP of the wallbox>` (from your router's device list).
14
+
15
+ **Option B: through the wallbox hotspot**
16
+
17
+ - Connect to the wallbox Wi-Fi (SSID and password from the card), or scan the QR code on the card.
18
+ - Open `https://10.0.2.1`.
19
+
20
+ The browser warns about an insecure connection, because the wallbox uses a self-signed certificate. Click **Advanced** (*Erweitert*) and continue.
21
+
22
+ ## 2. Log in as Service User
23
+
24
+ Choose the role **Service User** and enter the service user password from the card. The Standard User cannot change system settings.
25
+
26
+ ## 3. Check the firmware
27
+
28
+ **Software update** (*Software-Update*) shows the installed version. Modbus needs **R03.004.045.121-elli or newer**. If the version is older, update first (Elli app or *Software update*).
29
+
30
+ ## 4. Turn on the Modbus server
31
+
32
+ **Connections → Modbus server** (*Verbindungen → Modbus-Server*) → switch **Modbus server** on.
33
+
34
+ | Setting | Value |
35
+ |---|---|
36
+ | Port | 502 |
37
+ | Unit ID (Modbus ID) | 1 |
38
+
39
+ ## 5. Give the wallbox a fixed IP address
40
+
41
+ Reserve the wallbox's IP in your router (DHCP reservation), or set a static address under **Connections → Ethernet** (*Verbindungen → Ethernet*) with DHCP turned off. The client must be on the same local network; this does not work over LTE.
42
+
43
+ ## 6. Turn off the wallbox's own PV surplus charging
44
+
45
+ When something else controls the current, the wallbox should not regulate on its own at the same time:
46
+
47
+ **Charging management → Charging settings → PV surplus charging → off** (*Ladeverwaltung → Ladeeinstellungen → PV-Überschuss-Laden → PV-Laden aus*).
48
+
49
+ ## 7. Test
50
+
51
+ ```bash
52
+ pip install elli-2-modbus
53
+ elli-2-modbus status <IP of the wallbox>
54
+ ```
55
+
56
+ You should see the charging state, voltages and the current limit. If you get `cannot connect`, check that the Modbus server is on, the IP is correct and both devices are on the same network.
57
+
58
+ ## Good to know
59
+
60
+ - Modbus runs **in addition** to the Elli backend. The Elli app, OCPP and firmware updates keep working.
61
+ - **Watchdog:** once Modbus traffic has started, the wallbox expects regular traffic (default every 15 s). If traffic stops, it switches to the **failsafe current**. Set it deliberately: `elli-2-modbus set-failsafe <ip> 0` stops charging, `6` keeps charging slowly.
62
+ - **Authorization:** Modbus sets the current limit. Whether a session also needs RFID or app authorization depends on the wallbox settings. For fully automatic charging, enable instant charging (charging without authentication) in the Elli app.
@@ -0,0 +1,41 @@
1
+ # Elli Charger 2 Modbus registers
2
+
3
+ Source: Elli "Modbus Register" list v1.0 (15 Oct 2025), valid from firmware R03.004.045.121-elli. Download: <https://www.elli.eco/de/downloads-charger2> → *Modbus Registerliste [EN]*.
4
+
5
+ Elli states that the layout follows the "Ghost" platform implementation from eSystems, which is the Heidelberg/Amperfied layout. In Elli's PDF, footnote numbers are printed directly after the addresses (e.g. `2613` = register 261, footnote 3).
6
+
7
+ Modbus TCP, port 502, unit ID 1. Big-endian, 16-bit registers.
8
+
9
+ ## Input registers (FC 0x04)
10
+
11
+ | Reg | Content | Unit / encoding |
12
+ |---|---|---|
13
+ | 4 | Register layout version | 0x0100 = 1.0.0 |
14
+ | 5 | Charging state | 2=A1, 3=A2, 4=B1, 5=B2, 6=C1, 7=C2, 8=derating, 9=E, 10=F, 11=ERR |
15
+ | 6, 7, 8 | Current L1, L2, L3 rms | 0.1 A |
16
+ | 9 | PCB temperature | int16, 0.1 °C |
17
+ | 10, 11, 12 | Voltage L1, L2, L3 rms | V |
18
+ | 14 | Power L1+L2+L3 | VA |
19
+ | 15 / 16 | Energy since power-on, high / low word | VAh (high × 65536 + low) |
20
+ | 17 / 18 | Energy since installation, high / low word | VAh |
21
+ | 100 | Hardware max current | A (currently 0..16)¹ |
22
+ | 101 | Hardware min current | A¹ |
23
+
24
+ Register 13 (Heidelberg: external lock) is **not** documented by Elli and is never read.
25
+
26
+ ## Holding registers (FC 0x03 read / 0x06 write)
27
+
28
+ | Reg | Content | Unit / range | Default |
29
+ |---|---|---|---|
30
+ | 257 | Modbus master watchdog timeout² | ms, 0 = off | 15000 |
31
+ | 261 | Maximal current command³ | 0.1 A: 0 or 60..160 | |
32
+ | 262 | Failsafe current (on loss of Modbus communication)⁴ | 0.1 A: 0 or 60..160 | |
33
+
34
+ Heidelberg registers 258 (standby) and 259 (remote lock) are **not** documented by Elli.
35
+
36
+ ## Footnotes (Elli)
37
+
38
+ 1. To correctly support the 22 kW variants, the value ranges will be extended to [0..32] in a future release.
39
+ 2. The timer only starts after an initial interaction between client and server (read or write).
40
+ 3. Unlike the Amperfied reference implementation, the "MaximalCurrentCommand" value can be further reduced by additional internal limit functions. Writing register 261 sets an active limit; internal automatic limits or other external EMS controls can reduce it further. A read of register 261 always shows the currently valid limit. The maximum will be raised to 32 A for the 22 kW variant.
41
+ 4. The value 0 for the error state is not supported. Later, maximum values of 32 A (= 320) will be supported here as well, for the 22 kW variant.
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "elli-2-modbus"
7
+ version = "0.1.0"
8
+ description = "Local Modbus TCP control of Elli Charger 2 wallboxes (VW ID. Charger 2, Škoda, CUPRA)"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "Frane Bandov" }]
13
+ requires-python = ">=3.10"
14
+ dependencies = []
15
+ keywords = ["elli", "wallbox", "ev-charger", "modbus", "home-assistant", "volkswagen"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Framework :: AsyncIO",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Home Automation",
23
+ "Typing :: Typed",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/frane/elli-2-modbus"
28
+ Issues = "https://github.com/frane/elli-2-modbus/issues"
29
+
30
+ [project.scripts]
31
+ elli-2-modbus = "elli2modbus.cli:main"
32
+
33
+ [project.optional-dependencies]
34
+ test = ["pytest>=8", "pytest-asyncio>=0.23"]
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/elli2modbus"]
38
+
39
+ [tool.pytest.ini_options]
40
+ asyncio_mode = "auto"
41
+ asyncio_default_fixture_loop_scope = "function"
42
+ testpaths = ["tests"]
43
+
44
+ [tool.ruff]
45
+ line-length = 100
@@ -0,0 +1,24 @@
1
+ """Local Modbus TCP control of Elli Charger 2 wallboxes."""
2
+
3
+ from .charger import ChargerInfo, ChargerStatus, ElliCharger
4
+ from .client import (
5
+ ModbusConnectionError,
6
+ ModbusError,
7
+ ModbusExceptionResponse,
8
+ ModbusTcpClient,
9
+ )
10
+ from .registers import ChargingState
11
+
12
+ __version__ = "0.1.0"
13
+
14
+ __all__ = [
15
+ "ChargerInfo",
16
+ "ChargerStatus",
17
+ "ChargingState",
18
+ "ElliCharger",
19
+ "ModbusConnectionError",
20
+ "ModbusError",
21
+ "ModbusExceptionResponse",
22
+ "ModbusTcpClient",
23
+ "__version__",
24
+ ]
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())