Remote Access: not experimental any more (#33148)

This commit is contained in:
Michael Geers 2026-08-24 21:26:45 +02:00 • committed by GitHub
parent 10c646e668
commit 442113e9ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 65 additions and 11 deletions

View file

@ -97,11 +97,31 @@
</small>
</label>
</div>
<div class="d-flex mb-1">
<input
id="resetRemote"
v-model="selectedReset.remote"
class="form-check-input"
type="checkbox"
/>
<label class="form-check-label ms-2" for="resetRemote">
<span>{{ $t("config.system.backupRestore.reset.remote") }}</span>
<br />
<small>
{{ $t("config.system.backupRestore.reset.remoteDescription") }}
</small>
</label>
</div>
</div>
<button
class="btn btn-outline-danger mt-3"
:disabled="!selectedReset.sessions && !selectedReset.settings"
:disabled="
!selectedReset.sessions &&
!selectedReset.settings &&
!selectedReset.remote
"
>
{{ $t("config.system.backupRestore.reset.action") }}
</button>
@ -192,6 +212,7 @@ export default defineComponent({
selectedReset: {
sessions: false,
settings: false,
remote: false,
},
file: null as File | null,
confirmType: "" as "backup" | "restore" | "reset" | "",
@ -228,6 +249,7 @@ export default defineComponent({
this.selectedReset = {
sessions: false,
settings: false,
remote: false,
};
this.file = null;
this.navigateHomeAfterRestart = false;

View file

@ -6,15 +6,18 @@
data-testid="remote-modal"
@open="onOpen"
>
<div class="alert alert-warning">
Development preview. Not ready for general use. Use with caution and monitor your system
closely. Feedback welcome!
</div>
<SponsorTokenRequired v-if="!isSponsor" feature class="mt-0" />
<ErrorMessage :error="error" />
<template v-if="view === 'list'">
<p>{{ $t("config.remote.description") }}</p>
<p>
{{ $t("config.remote.description") }}
<i18n-t tag="span" keypath="config.remote.privacy" scope="global">
<a :href="privacyPolicyLink" target="_blank">
{{ $t("config.remote.privacyLink") }}
</a>
</i18n-t>
</p>
<div class="form-check form-switch my-3">
<input
id="remoteEnabled"
@ -138,6 +141,10 @@ export default defineComponent({
status(): RemoteStatus {
return this.remote?.status ?? { connected: false, loginBlocked: false };
},
privacyPolicyLink(): string {
const path = this.$i18n.locale === "de" ? "" : "/en";
return `https://evcc.io${path}/datenschutz/`;
},
modalTitle(): string {
switch (this.view) {
case "create":
@ -145,7 +152,7 @@ export default defineComponent({
case "reveal":
return this.$t("config.remote.clientCreated");
default:
return `${this.$t("config.remote.title")} 🧪`;
return this.$t("config.remote.title");
}
},
},

View file

@ -419,8 +419,7 @@
</template>
</DeviceCard>
<DeviceCard
v-if="experimental"
:title="`${$t('config.remote.title')} 🧪`"
:title="$t('config.remote.title')"
editable
:unconfigured="isUnconfigured(remoteTags)"
data-testid="remote-access"

View file

@ -840,6 +840,8 @@
"noClients": "Noch keine Clients. Niemand kann sich verbinden.",
"password": "Passwort",
"passwordOnce": "Dieses Passwort wird nur einmal angezeigt. QR-Code scannen oder jetzt kopieren. Es wird später nicht mehr angezeigt.",
"privacy": "Mit der Aktivierung dieser Funktion akzeptierst du unsere {0}.",
"privacyLink": "Datenschutzerklärung",
"qrInstall": "Installiere die evcc-App für {ios} oder {android}.",
"qrScan": "Scanne den Code mit der Kamera deines Smartphones, um dich zu verbinden. Klicke ihn an, wenn du bereits dein Handy nutzt.",
"removeClient": "Client entfernen",
@ -916,6 +918,8 @@
"confirmationButton": "Zurücksetzen & Neustart",
"confirmationText": "Dies löscht deine ausgewählten Daten dauerhaft. Stelle sicher, dass du zuerst eine Sicherung heruntergeladen hast.",
"description": "Hast du Probleme mit der Konfiguration und möchtest von vorne beginnen? Lösche alle Daten und beginne neu.",
"remote": "Remotezugriff",
"remoteDescription": "Löscht Konfiguration und Zugangsdaten.",
"sessions": "Ladevorgänge",
"sessionsDescription": "Löscht den Verlauf deiner Ladevorgänge.",
"settings": "Konfiguration & Einstellungen",

View file

@ -840,6 +840,8 @@
"noClients": "No clients yet. No one can connect yet.",
"password": "Password",
"passwordOnce": "This password is shown only once. Scan the QR code or copy it now. You won't be able to see it again.",
"privacy": "By enabling this feature, you agree to our {0}.",
"privacyLink": "privacy policy",
"qrInstall": "Install the evcc app for {ios} or {android}.",
"qrScan": "Scan the code with your phone's camera to connect. Click it, if you're already using your phone.",
"removeClient": "Remove client",
@ -916,6 +918,8 @@
"confirmationButton": "Reset & restart",
"confirmationText": "This will permanently delete your selected data. Ensure you've downloaded a backup first.",
"description": "Having problems with configuration and want to start over? Delete all data and start fresh.",
"remote": "Remote access",
"remoteDescription": "Deletes configuration and credentials.",
"sessions": "Charging sessions",
"sessionsDescription": "Deletes your charging session history.",
"settings": "Configuration & settings",

View file

@ -15,6 +15,7 @@ import (
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/core/keys"
"github.com/evcc-io/evcc/core/loadpoint"
"github.com/evcc-io/evcc/core/site"
"github.com/evcc-io/evcc/server/assets"
@ -528,6 +529,7 @@ func resetDatabase(shutdown func()) http.HandlerFunc {
var req struct {
Sessions bool `json:"sessions"`
Settings bool `json:"settings"`
Remote bool `json:"remote"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
jsonError(w, http.StatusBadRequest, err)
@ -560,6 +562,15 @@ func resetDatabase(shutdown func()) http.HandlerFunc {
}
}
if req.Remote {
for _, key := range []string{keys.Remote, keys.RemoteClients, keys.RemoteLastSeen} {
if err := settings.Delete(key); err != nil {
jsonError(w, http.StatusInternalServerError, err)
return
}
}
}
// close db connection to avoid on-shutdown writes
if err := db.Close(); err != nil {
jsonError(w, http.StatusInternalServerError, err)

View file

@ -2197,7 +2197,7 @@
"post": {
"operationId": "resetDatabase",
"summary": "Reset database",
"description": "Selectively deletes sessions and/or settings from the database. Session users must supply the admin password in the X-Admin-Password header. API key holders via Bearer token are exempt. The instance restarts after a successful reset.",
"description": "Selectively deletes sessions, settings and/or remote access data from the database. Session users must supply the admin password in the X-Admin-Password header. API key holders via Bearer token are exempt. The instance restarts after a successful reset.",
"tags": [
"db"
],
@ -2228,6 +2228,10 @@
"settings": {
"type": "boolean",
"description": "Delete all settings, configs, and meters"
},
"remote": {
"type": "boolean",
"description": "Delete remote access configuration and registered clients"
}
}
}

View file

@ -1327,7 +1327,7 @@ paths:
post:
operationId: resetDatabase
summary: Reset database
description: "Selectively deletes sessions and/or settings from the database. Session users must supply the admin password in the X-Admin-Password header. API key holders via Bearer token are exempt. The instance restarts after a successful reset."
description: "Selectively deletes sessions, settings and/or remote access data from the database. Session users must supply the admin password in the X-Admin-Password header. API key holders via Bearer token are exempt. The instance restarts after a successful reset."
tags:
- db
security:
@ -1348,6 +1348,9 @@ paths:
settings:
type: boolean
description: Delete all settings, configs, and meters
remote:
type: boolean
description: Delete remote access configuration and registered clients
responses:
"204":
description: Reset successful, instance is restarting