Skip to content

Conversation

@iseeberg79
Copy link
Contributor

@iseeberg79 iseeberg79 commented Dec 8, 2025

This PR enables auto-filling of device parameters in the configuration UI by reading actual values from the device.

Adds HTTP service endpoint /api/modbus/params for reading device parameters based on template definitions without creating a full device instance.

Features (fixes #25857):

  • Dynamic register reading using template configurations
  • Automatic scaling and type conversion

Usage examples:

  • ModbusTCP
  - name: capacity
    type: int
    unit: kWh
    advanced: true
    usages: ["battery"]
    service: modbus/params?uri={host}:{port}&id={id}&address=1068&type=holding&encoding=float32s&scale=0.001&resulttype=int
  • rs485serial
  - name: capacity
    type: float
    unit: kWh
    advanced: true
    usages: ["battery"]
    service: modbus/params?device={device}&baudrate={baudrate}&comset={comset}&id={id}&address=1068&type=holding&encoding=float32s&scale=0.001

recently updated to reduce to:

- name: maxacpower
  service: modbus/read?address=1069&type=holding&encoding=float32s&scale=0.001&{modbus}

TODO:

  • refactor datalist handling (less duplicate code) @naltatis

@andig andig added enhancement New feature or request needs documentation Triggers issue creation in evcc-io/docs labels Dec 8, 2025
@andig
Copy link
Member

andig commented Dec 8, 2025

Das ist grausig viel Logik. Warum muss der modbus Service etwas vin templates wissen? Die sollten ihm egal sein! Spannend ist allerdings die Modbus Config. Dafür hatte ich keine gute Idee :/

@iseeberg79
Copy link
Contributor Author

iseeberg79 commented Dec 8, 2025

Das ist grausig viel Logik. Warum muss der modbus Service etwas vin templates wissen? Die sollten ihm egal sein! Spannend ist allerdings die Modbus Config. Dafür hatte ich keine gute Idee :/

Die zu ermittelnden Register lädt er aus dem Template zur Laufzeit, nachdem die Modbus-Konfiguration verfügbar ist. Dafür der Name des Templates. Man könnte das Laden des Template ggf. überflüssig machen: statt properties, mehr URL Parameter. Auch deinen Hinweis mit dem modbus-Plugin.. - schau' ich mir an.

Die UI Integration ist etwas schwierig, wg. der Einschränkung mit den dataLists und der Positionierung des clear-Feldes bei Feldern mit Einheit. Das ist noch unschön, überlappt aber so aktuell nicht mehr - die Ausrichtung passt aktuell nicht.
Ich stell' das mal hinten an erstmal... - ich hatte zuerst die Werte direkt in die Felder geschrieben, wenn initial - das widerspricht aber der aktuellen Integration/Tests aus demo-service. Die Dropdown's sind schon ganz charmant...

image

@andig
Copy link
Member

andig commented Dec 9, 2025

Die zu ermittelnden Register lädt er aus dem Template zur Laufzeit,

Die gehören in den Serviceaufruf. HA zeigt wie's geht:

service: homeassistant/entities?uri={uri}&domain=sensor

Die uri wird dynamisch vom UI da rein gebastelt. Ich weiss nur nicht ob/wie wir das für Modbus zum Leben erwecken können.

/cc @naltatis

@iseeberg79
Copy link
Contributor Author

iseeberg79 commented Dec 9, 2025

Ich bin einen Entwurf weiter, klappt soweit auch mit URL Parametern, ist übersichtlicher. Ein Update heute Abend!

Problematisch ist die Parallelität der Browseranfragen und Wiederverwendung des Modbus-Plugins, theoretisch läuft es.

Praktisch blockierte da gerade etwas, was einen weiteren echten Gerätetest braucht.

Der aktuelle Ansatz ist unnötig aufwändig, läuft aber.

@andig
Copy link
Member

andig commented Dec 9, 2025

Checks gerne ein, ich kann auch testen.

@iseeberg79
Copy link
Contributor Author

Checks gerne ein, ich kann auch testen.

jetzt aber...

@iseeberg79
Copy link
Contributor Author

@andig I'd like to push the commits for the service dependencies as suggested above, going for:

- name: maxacpower
  service:
    endpoint: modbus/read
    params:
      uri: "{host}:{port}"
      address: 1069
      type: holding
      encoding: float32s
    dependencies:
      - [host, port, id]
      - [device, baudrate, comset, id]

@naltatis not going to disrupt changes from your side, ok?

@iseeberg79
Copy link
Contributor Author

iseeberg79 commented Dec 23, 2025

I've prepared some UI tests as well, but skipped here initially
common got added because of some functions I'd like to re-use for a http service later

@naltatis
Copy link
Member

naltatis commented Dec 24, 2025

That's ugly since it will create a non-empty parameter in the device case. But can be worked around in the backend. Makes sense that parameters still need to be specified in the uri for this purpose.
Or maybe just unused ones.

I'd prefer not mixing explicit param definition with placeholder substitution like we see with uri here. Do we need this extra flexibility?

  service:
    endpoint: modbus/read
    params:
-     uri: "{host}:{port}"
      address: 1069
      type: holding
      encoding: float32s
    dependencies:
      - [host, port, id]
      - [device, baudrate, comset, id]

I like the idea of having fixed params and dynamic dependencies, but keeping them as distinct concepts. Then questions like missing values or how to handle deps that are also placeholders would disappear.

If we really need the flexibility (uri) another, maybe simpler, solution could be to stick to the existing logic of url substitution and service being a string but allowing multiples. Could look like this:

  service:
    - modbus/read?address=1069&type=holding&encoding=float32s&id={id}&uri={host}:{port}
    - modbus/read?address=1069&type=holding&encoding=float32s&id={id}&device={device}&baudrate={baudrate}&comset={comset}

Then the first server string where all placeholders can be filled would be used. Drawback with this solution is that we'd have to repeat static values.

@iseeberg79
Copy link
Contributor Author

I think the flexibility is required because of URI might getting build by different fields. Specially having the extension for http-templates in mind we have to deal with host plus port, additional protocol, URL parts or host:port in one field.

This approach does support any UI field combination which is relevant looking at modbus and http templates.

I really like this approach but see more UI complexity as well.
URL style is fine, too - see initial description, but one line + deps I'd prefer.

@andig
Copy link
Member

andig commented Dec 24, 2025

Then the first server string where all placeholders can be filled would be used. Drawback with this solution is that we'd have to repeat static values

I like the idea. Maybe at a later stage we'll need to add optional parameters (?). @naltatis one thing that's a striking is that the auth service is done differently by specifying the actual parameters. Does it make sense to do both in the same way?

@naltatis
Copy link
Member

naltatis commented Dec 24, 2025

one thing that's a striking is that the auth service is done differently by specifying the actual parameters. Does it make sense to do both in the same way?

We have to things at play here:

a) being able to remap or concat params from user input (host:port)
b) supporting alternative param combinations (modbus tcp / serial)

In the auth case we have none of there requirements. There it's fine to 1:1 pass user fields to the service endpoint. However we could also expand this in the future to support remapping input field to param (a) if we really need it:

auth:
  type: demo
  params: 
    - server
    - method

as well as interpolation

auth:
  type: demo
  params: 
    server: "{protocol}{host}"
    method: "{method}"

But coming back to the actual topic here let's look at b). Do we really have the use-case for these alternative combinations outside of modbus? Modbus configuration is a special candidate in many places of evcc (docs, config ui, templates ,..). Maybe it would also be fine to introduce a dedicated modbus (meta)-param and keep the logic of "required params for tcp/serial" in UI.

Idea:

 service: modbus/read?address=1069&type=holding&foo={foo}&encoding=float32s&{modbus}

Where {modbus} will be expanded to host=..&port=..&id=.. or device=..&baudrate=..&comset=..id=.. depending on user input by the UI.

We could write the above example also in endpoint + params structure, but this would the primarily be a readability difference.

@andig
Copy link
Member

andig commented Dec 24, 2025

Maybe it would also be fine to introduce a dedicated modbus (meta)-param and keep the logic of "required params for tcp/serial" in UI.

Like it! Advantage: much less copy/paste since we'll need this pattern quite a lot!

We could write the above example also in endpoint + params structure, but this would the primarily be a readability difference.

Yagni? Can still do that later on.

@iseeberg79
Copy link
Contributor Author

Modbus configuration is a special candidate

Agreed on this. Also identified modbus and http as candidates for this use case. Only modbus has this serial or tcp selection.

@iseeberg79
Copy link
Contributor Author

Where {modbus} will be expanded to host=..&port=..&id=.. or device=..&baudrate=..&comset=..id=.. depending on user input by the UI.

did not expect it to reduce complexity that much, great suggestion!

@andig andig added the prio Priority label Dec 27, 2025
Copy link
Member

@naltatis naltatis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added e2e tests, found a couple of bugs around how we handled modbus default values. This should all work fine now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs documentation Triggers issue creation in evcc-io/docs prio Priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support reading configuration values from devices

3 participants