Skip to content

Conversation

@Maschga
Copy link
Collaborator

@Maschga Maschga commented Jan 23, 2026

Fix #26596
Ref #26615

πŸƒβ€βž‘οΈ run EEBus automatically at startup
🚩 add services section for OCPP, SHM and EEBus
πŸ“„ modal is readonly if configured in evcc.yaml

TODO:

  • all fields are advanced
  • add warning
  • autocompletion for interfaces (?)
  • improve i18n strings
  • add e2e tests
  • redact private cert
grafik grafik

\cc @andig @naltatis

@Maschga Maschga added the ux User experience/ interface label Jan 23, 2026
@naltatis naltatis self-assigned this Jan 24, 2026
@naltatis
Copy link
Member

I've added shipid/ski fields and explanation. Also adjusted the json save/delete workflow. The roundtrip should work now.

@Maschga Can you do the e2e? Basic flow like verify values exist on start. Change shipid and restart. Verify SKI changes after reboot when user deletes config and restarts.

Also noticed that private key is not redacted yet.

Bildschirmfoto 2026-01-27 um 16 44 07 Bildschirmfoto 2026-01-27 um 16 44 12 Bildschirmfoto 2026-01-27 um 16 44 50

@naltatis
Copy link
Member

autocompletion for interfaces (?)

Since we're currently still using the hacky "list as texturea" ui I'd not do autocomplete. We should upgrade the ui in da dedicated ticket and make it a list of inputs. Doing a similar thing in #26698 for zones. Could be similar.

@Maschga Maschga changed the base branch from feat/eebus-always-on to master January 28, 2026 12:53
@naltatis naltatis assigned andig and unassigned naltatis Jan 31, 2026
@andig
Copy link
Member

andig commented Jan 31, 2026

Just noticed that ship-id is optional. It must be required, same for the certificates.

@CiNcH83
Copy link
Contributor

CiNcH83 commented Jan 31, 2026

According to documentation:

Γ„ndere diesen Wert nicht manuell, wenn du nicht genau weißt, was du tust.

SHIPID ist ypically generated from the machine-id. If there is none or there is a plant ID, the plant ID is used instead. IMHO plant ID is the important param, especially if the goal is to be able to move the whole EEBUS configuration to another device which is why I don't want to use machine-id. Also see this discussion.

@andig
Copy link
Member

andig commented Jan 31, 2026

@naltatis kΓΆnnen wir den Dokustyle von "Du" auf matter of fact umstellen?

@DerAndereAndi
Copy link
Contributor

Just noticed that ship-id is optional. It must be required, same for the certificates.

The user should NOT provide it. It should be generated and currently is generated on every startup assuming the machine-id/plantid are stable.

@andig
Copy link
Member

andig commented Jan 31, 2026

It already is ;)

@naltatis
Copy link
Member

naltatis commented Feb 1, 2026

assuming the machine-id/plantid are stable

Is there any benefit in using the machine-id instead of a randomly auto-generated plantid? Wouldn't it be preferable in all cases to have it plantid based so it's portable when switching hardware? The current mechanism was built before evcc had reliable state management.

@andig
Copy link
Member

andig commented Feb 1, 2026

The user should NOT provide it. It should be generated and currently is generated on every startup assuming the machine-id/plantid are stable.

Let's not get confused. The whole purpose for having this optionally user-defined is to use migration from whatever previous status.

@CiNcH83
Copy link
Contributor

CiNcH83 commented Feb 1, 2026

Wouldn't it be preferable in all cases to have it plantid based so it's portable when switching hardware?

That's exactly why I switched to plant ID. Maybe somebody is still interested in this posting. I had different plant IDs in yaml and db for a reason I don't know. Migrating the configuration from yaml to db would have required me to alter the db manually since plant ID cannot be altered from UI.

@naltatis
Copy link
Member

naltatis commented Feb 1, 2026

The whole purpose for having this optionally user-defined is to use migration from whatever previous status.

For this case the user has to know his previous SHIP-ID. It's currently not part of our backup. In a case of hardware failure he won't be able to look up his original SHIP-ID in his old setup. Maybe it's something the user has in another form (email to grid operator) or can retrieve it from another system.

But to repeat my question: Is there still any benefit to have it machine id specific? I currently dont see it. For me it seems like id-stability is very important, though and having to repair is trouble.

@andig
Copy link
Member

andig commented Feb 1, 2026

PlantID is OT here. Let's stay on topic.

@andig
Copy link
Member

andig commented Feb 1, 2026

But to repeat my question: Is there still any benefit to have it machine id specific? I currently dont see it. For me it seems like id-stability is very important, though and having to repair is trouble.

Machine ID is what gives ID stability.

@naltatis
Copy link
Member

naltatis commented Feb 1, 2026

PlantID is OT here. Let's stay on topic.
Machine ID is what gives ID stability.

This is not correct. Plant ID is used and on-demand created, when we can't retrieve a machine id (e.g. docker).

@andig andig marked this pull request as draft February 1, 2026 10:50
@andig andig marked this pull request as ready for review February 1, 2026 10:55
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The new util.Masked helper takes an any and compares it to "", which will panic for non-string types; consider changing the signature to accept string (or explicitly type-assert with a safe default) so you don't risk runtime panics when masking arbitrary values.
  • In EebusModal the PropertyCertField update handlers no-op when values.certificate is undefined, so users cannot create a new certificate object from an initially empty config; it would be more robust to initialize values.certificate = { public: '', private: '' } before assigning into its fields.
  • The allowPub special case for keys.EEBus prevents publishing updates on config changes, which means the frontend store will not reflect edited EEBus settings until a full refresh; consider publishing a proper ConfigStatus wrapper instead of disabling pub entirely so the UI stays in sync without overwriting the global info structure.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new util.Masked helper takes an `any` and compares it to `""`, which will panic for non-string types; consider changing the signature to accept `string` (or explicitly type-assert with a safe default) so you don't risk runtime panics when masking arbitrary values.
- In EebusModal the `PropertyCertField` update handlers no-op when `values.certificate` is undefined, so users cannot create a new certificate object from an initially empty config; it would be more robust to initialize `values.certificate = { public: '', private: '' }` before assigning into its fields.
- The `allowPub` special case for `keys.EEBus` prevents publishing updates on config changes, which means the frontend store will not reflect edited EEBus settings until a full refresh; consider publishing a proper `ConfigStatus` wrapper instead of disabling pub entirely so the UI stays in sync without overwriting the global info structure.

## Individual Comments

### Comment 1
<location> `server/eebus/types.go:55-64` </location>
<code_context>
+	return fmt.Sprintf("%s-%0x", "EVCC", protectedID[:8])
+}
+
+func DefaultConfig(conf *Config) (*Config, error) {
+	cert, err := CreateCertificate()
+	if err != nil {
+		return nil, err
+	}
+
+	public, private, err := GetX509KeyPair(cert)
+	if err != nil {
+		return nil, err
+	}
+
+	res := Config{
+		Port:   4712,
+		ShipID: createShipID(),
+		Certificate: Certificate{
+			Public:  public,
+			Private: private,
+		},
+	}
+
+	return &res, nil
+}
+
</code_context>

<issue_to_address>
**issue (bug_risk):** DefaultConfig ignores the incoming config and always overwrites all fields, which can unexpectedly discard user settings.

`DefaultConfig` builds a new `Config` and ignores `conf`, so any partially configured state (e.g. custom port or ShipID without a certificate) is completely replaced. If the intent is to fill in only missing values, consider copying `*conf` and only setting defaults for zero-valued fields (`Port`, `ShipID`, `Certificate`) before returning. The unused `conf *Config` parameter is a strong hint that the current behavior may not match the intended design.
</issue_to_address>

### Comment 2
<location> `cmd/helper.go:126-135` </location>
<code_context>
 }
+
+// migrateYamlToJson converts a settings value from yaml to json if needed
+func migrateYamlToJson[T any](key string, res *T) error {
+	if settings.IsJson(key) {
+		return settings.Json(key, res)
+	}
+
+	if err := settings.Yaml(key, new(T), res); err != nil {
+		return err
+	}
+
+	settings.SetJson(key, res)
+
+	return nil
</code_context>

<issue_to_address>
**issue (bug_risk):** migrateYamlToJson ignores potential errors from SetJson, which can hide persistence failures.

Here you correctly return errors from `settings.Json`/`settings.Yaml` but ignore the result of `settings.SetJson`. If persisting the migrated value fails, the function still returns `nil`, so callers like `configureEEBus`/`configureModbusProxy` will treat the migration as successful.

Please capture and return the `SetJson` error, e.g.:
```go
if err := settings.SetJson(key, res); err != nil {
    return err
}
return nil
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.

Comment on lines +55 to +64
func DefaultConfig(conf *Config) (*Config, error) {
cert, err := CreateCertificate()
if err != nil {
return nil, err
}

public, private, err := GetX509KeyPair(cert)
if err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): DefaultConfig ignores the incoming config and always overwrites all fields, which can unexpectedly discard user settings.

DefaultConfig builds a new Config and ignores conf, so any partially configured state (e.g. custom port or ShipID without a certificate) is completely replaced. If the intent is to fill in only missing values, consider copying *conf and only setting defaults for zero-valued fields (Port, ShipID, Certificate) before returning. The unused conf *Config parameter is a strong hint that the current behavior may not match the intended design.

Comment on lines +126 to +135
func migrateYamlToJson[T any](key string, res *T) error {
if settings.IsJson(key) {
return settings.Json(key, res)
}

if err := settings.Yaml(key, new(T), res); err != nil {
return err
}

settings.SetJson(key, res)
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): migrateYamlToJson ignores potential errors from SetJson, which can hide persistence failures.

Here you correctly return errors from settings.Json/settings.Yaml but ignore the result of settings.SetJson. If persisting the migrated value fails, the function still returns nil, so callers like configureEEBus/configureModbusProxy will treat the migration as successful.

Please capture and return the SetJson error, e.g.:

if err := settings.SetJson(key, res); err != nil {
    return err
}
return nil

@andig andig merged commit 768656e into evcc-io:master Feb 1, 2026
8 checks passed
@naltatis
Copy link
Member

naltatis commented Feb 1, 2026

This is not correct. Plant ID is used and on-demand created, when we can't retrieve a machine id (e.g. docker).

Question resolved. The new process generates and persists the SHIP-ID on first start. So portability is guaranteed through db backup/restore. MachineId/PlantId is only relevant for initial config generation.

@andig andig mentioned this pull request Feb 1, 2026
@Maschga Maschga deleted the eebus-always-on-ui branch February 1, 2026 11:08
@CiNcH83
Copy link
Contributor

CiNcH83 commented Feb 1, 2026

Question resolved. The new process generates and persists the SHIP-ID on first start. So portability is guaranteed through db backup/restore. MachineId/PlantId is only relevant form initial config generation.

Thanks for the clarification. Will try EEBUS auto-configuration in tomorrow's nightly.

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

Labels

ux User experience/ interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setup EEBUS by default

5 participants