EEBus: expose SHIP installation QR code (#30840)

This commit is contained in:
andig 2026-06-16 12:21:37 +02:00 • committed by GitHub
parent 0d9bb385f1
commit ebe4a3d6a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 57 additions and 0 deletions

View file

@ -90,6 +90,7 @@ Deep documentation on specific subsystems is available in `docs/agents/`. Load w
- No em dashes (—) in comments, commit messages, or docs. Use periods, commas, or colons
- Project name is `evcc`, always lowercase
- In user-facing strings, only mention `evcc` when needed to understand the context. Inside evcc's own UI the self-reference is usually redundant
- Acronyms uppercase in prose: OCPP, MQTT, HEMS, SoC
- Terminology: German "Phasensaldierung" (meter netting signed power across phases each instant) is "summative energy measurement" in English. Avoid "phase balancing" (means load balancing) and "net metering" (a billing scheme)
- Commit subjects: `Component: short description`, no trailing period. Sub-scope in parens: `Meter (Home Assistant): ...`. Use `chore:`/`fix:`/`docs:` only for non-feature changes

View file

@ -40,6 +40,14 @@
class="form-control text-muted"
/>
</FormRow>
<FormRow
v-if="qrDataUrl"
:id="formId('qr-display')"
:label="$t('config.eebus.qr')"
:help="$t('config.eebus.qrExplain')"
>
<img :src="qrDataUrl" :alt="$t('config.eebus.qr')" class="qr-code" />
</FormRow>
<PropertyCollapsible v-if="!fromYaml">
<template #advanced>
<div class="alert alert-danger">
@ -118,6 +126,7 @@
<script lang="ts">
import type { PropType } from "vue";
import QRCode from "qrcode";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { EebusConfig, EebusStatus, YamlSource } from "@/types/evcc";
import JsonModal from "./JsonModal.vue";
@ -143,11 +152,32 @@ export default {
yamlSource: String as PropType<YamlSource>,
},
emits: ["changed"],
data() {
return {
qrDataUrl: null as string | null,
};
},
computed: {
fromYaml(): boolean {
return this.yamlSource === "file";
},
},
watch: {
"status.qr": {
immediate: true,
async handler(qr?: string) {
if (!qr) {
this.qrDataUrl = null;
return;
}
try {
this.qrDataUrl = await QRCode.toDataURL(qr, { width: 200, margin: 1 });
} catch {
this.qrDataUrl = null;
}
},
},
},
methods: {
formId(s: string) {
return `eebus-${s}`;
@ -155,3 +185,9 @@ export default {
},
};
</script>
<style scoped>
.qr-code {
image-rendering: pixelated;
}
</style>

View file

@ -571,6 +571,7 @@ export type EebusConfig = {
export type EebusStatus = {
ski: string;
qr?: string;
};
export type ModbusProxy = {

View file

@ -220,6 +220,8 @@
"interfacesHelp": "Begrenzt die Netzwerkschnittstellen, die EEBus nutzen soll, um Kommunikationsprobleme zu vermeiden. Feld leer lassen, um alle Schnittstellen zu verwenden. Ein Eintrag pro Zeile.",
"port": "Port",
"portHelp": "Der zu verwendende Port.",
"qr": "Kopplungscode",
"qrExplain": "Während der Installation von einem anderen EEBus-Gerät scannen, um automatisch zu koppeln, ohne die SKI manuell einzugeben.",
"removeConfirm": "Die gesamte EEBus-Konfiguration wird entfernt. Neue Zertifikate und Kennungen werden beim nächsten Start generiert. Bist du sicher?",
"shipid": "SHIP-ID",
"shipidExplain": "Permanente Gerätekennung zur Identifikation im EEBus-Netzwerk.",

View file

@ -220,6 +220,8 @@
"interfacesHelp": "Limit the network interfaces that EEBus should use to avoid communication problems. Leave the field blank to use all interfaces. One entry per line.",
"port": "Port",
"portHelp": "The port to be used.",
"qr": "Pairing code",
"qrExplain": "Scan from another EEBus device during installation to pair automatically, without entering the SKI manually.",
"removeConfirm": "All EEBus configuration will be removed. New certificates and identifiers will be generated on next start. Are you sure?",
"shipid": "SHIP-ID",
"shipidExplain": "Permanent device identifier for identification in the EEBus network.",

View file

@ -89,11 +89,26 @@ var Instance *EEBus
func GetStatus() any {
return struct {
Ski string `json:"ski"`
QR string `json:"qr,omitempty"`
}{
Ski: Ski(),
QR: qrCode(),
}
}
// qrCode returns the SHIP installation QR code text per EEBus SHIP installation
// requirements, or empty if unavailable
func qrCode() string {
if Instance == nil {
return ""
}
qr, err := Instance.service.QRCodeText()
if err != nil {
return ""
}
return qr
}
func NewServer(other Config) (*EEBus, error) {
cc := Config{
Port: 4712,