You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 513cb77
Browse filesBrowse the repository at this point in the historyBrowse files
feat(modbus): let the connection be kept between polls, off by default
Dialling a fresh connection for every read is the unusual choice for modbus
TCP; one connection held open is the normal one. datalogger.persistent_
connection does that, and is off by default because it is a trade rather than
an improvement: this datalogger accepts one connection at a time, so holding
ours keeps everything else -- Solis Cloud included -- off the stick, where
hanging up leaves a gap in every poll cycle where something else can get in.
The client is now the app's rather than the poll's. ensure_connected is the
only thing that dials, drop_connection the only thing that throws one away,
and release_connection at the end of a good poll is the single place the
setting is read. That also means a read that raised redials here instead of
leaving pymodbus to do it out of sight, and a poll that could not read the
whole span drops the connection so the next one starts fresh -- which is what
every poll did before, so turning the setting on cannot make a bad morning
worse than it already was.
ensure_connected checks whether the client still holds a socket before
reusing it. pymodbus closes its own socket when the peer hangs up mid-read
(_handle_abrupt_socket_close) and its next request dials again silently, which
is precisely the case being measured here: it would have counted as zero
reconnects, on a socket carrying none of the keepalive set below.
Keepalive is set on every connection: SO_KEEPALIVE, 30 seconds idle, then
three probes five seconds apart, so a datalogger that vanished while the app
slept is declared dead by the kernel inside 45 seconds instead of by the next
read timing out CHUNK_ATTEMPTS times over. The option names are Linux's and
the container is Alpine, but the tests run on macOS, so each is applied only
where the platform has it.
Every connection logs one numbered line saying why the previous one ended, at
info when the setting is on and debug when it is off -- 2880 lines a day
otherwise, saying only that the app is working as configured. That line is the
point of shipping the setting at all: these sticks are widely reported to hang
up on an idle connection after a minute or two, and at a 30 second poll
interval that would mean reconnecting nearly every poll and gaining nothing.
It cannot be settled from here, only measured. Turn it on, leave it a day,
count the lines. Then the setting and the losing branch both go, and that
removal is the breaking change worth a 4.0.0.
The online transition needed no change: #181 already moved it off the
handshake and onto the first chunk of registers that arrives, which is the
only thing a reused connection could have said it from anyway. A poll whose
reads are all refused still counts against the retry budget, kept connection
or not, and a test pins it.
The stub datalogger and the query/polls fixtures moved from test_modbus_read
to conftest so the new connection lifetime tests poll the same stub.
Closes#172
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BizgAhMgYcmMXjHFX7pbbs
Copy file name to clipboardExpand all lines: readme.md
+23-1Lines changed: 23 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,7 +41,7 @@ Because it works! If I for some reason would stop using this myself then I will
41
41
42
42
### Does Solis Cloud still work?
43
43
44
-
Most other integrations that I found all stated that Solis Cloud would not work when polling the data logger over MODBUS. In my brief and short testing Solid Cloud still works, but not perfectly. My guess is that most other integrations keeps the connection with the data logger alive while this project closes the connection when its done and then reconnects when it's time for the next update. By "not perfectly" I mean that I can see that Solis Cloud is not always updated every 5 minutes. Sometimes it takes 15-20 minutes between updates but I've always seen that the data logger sooner or later are able to send data to Solis Cloud. And if I stop the script/Docker container I always seen an update in Solid cloud within 10 minutes without having to restart the data logger.
44
+
Most other integrations that I found all stated that Solis Cloud would not work when polling the data logger over MODBUS. In my brief and short testing Solid Cloud still works, but not perfectly. My guess is that most other integrations keeps the connection with the data logger alive while this project closes the connection when its done and then reconnects when it's time for the next update. That is still the default, and `datalogger.persistent_connection` is the setting that changes it — see [Keeping the connection open](#keeping-the-connection-open). By "not perfectly" I mean that I can see that Solis Cloud is not always updated every 5 minutes. Sometimes it takes 15-20 minutes between updates but I've always seen that the data logger sooner or later are able to send data to Solis Cloud. And if I stop the script/Docker container I always seen an update in Solid cloud within 10 minutes without having to restart the data logger.
45
45
46
46
### Is it possible to control the inverter?
47
47
@@ -62,6 +62,28 @@ Maybe, I have no plans for it at the moment. My main goal is to get the data int
62
62
## Getting started
63
63
Prepare a config file. Use `config.example.yaml` and modify it to your needs and save it as `config.yaml`. Most values should be self-explanatory. `register_chunks` is set to 20 by default but during my testing I've been able to query my datalogger for more than 80 registers at the same time.
64
64
65
+
### Keeping the connection open
66
+
By default the app dials a connection to the data logger, reads, and hangs up again on every poll. For MODBUS TCP that's the unusual choice — one connection held open is the normal one — and `datalogger.persistent_connection: True` does that instead:
67
+
68
+
```yaml
69
+
datalogger:
70
+
persistent_connection: True
71
+
```
72
+
73
+
It's off by default because it's a trade, not an improvement. The data logger accepts **one connection at a time**, so while this app holds it, nothing else can talk to the stick — Solis Cloud included. Hanging up after each poll leaves a gap in every cycle where something else can get in.
74
+
75
+
Whether it's worth the trade is a question about your stick, not about this app: these WiFi sticks are widely reported to close an idle connection themselves after a minute or two, and at a 30 second poll interval that would mean reconnecting nearly every poll and gaining nothing. So the app logs a line for every connection it opens, numbered and saying why the previous one ended:
76
+
77
+
```
78
+
Connected to datalogger, connection 12 since startup, previous one ended because a read raised OSError: Connection reset by peer
79
+
```
80
+
81
+
Turn the setting on, leave it a day, and count those lines. One or two means the connection is surviving. One per poll means the stick is hanging up and the setting is buying nothing.
82
+
83
+
Either way the app sets TCP keepalive on the socket, so a data logger that vanishes while the app is sleeping is noticed by the kernel within about 45 seconds instead of by the next read timing out three times over.
84
+
85
+
Expect this setting to go away once there are enough measurements to pick a winner. Whichever behaviour loses will be removed along with it.
86
+
65
87
### Upgrading to 3.0
66
88
**`inverter.max_power_kw` is now required and the container won't start without it.** Set it to the nameplate rating of your inverter, in kW:
0 commit comments