diff --git a/Web App/web/src/views/Settings.vue b/Web App/web/src/views/Settings.vue
index b363472..21ea9d1 100644
--- a/Web App/web/src/views/Settings.vue
+++ b/Web App/web/src/views/Settings.vue
@@ -405,7 +405,7 @@ async function testToyotaConnection() {
const anker = ref(null); // resolved view from the server
const ankerScope = ref("user"); // "user" | "org" (org admins only)
-const ankerForm = ref({ email: "", password: "", country: "" });
+const ankerForm = ref({ email: "", password: "", country: "", controlMode: "off" });
const ankerSaving = ref(false);
const ankerSaved = ref(false);
const ankerError = ref("");
@@ -440,9 +440,46 @@ function fillAnkerForm() {
email: f.email?.locked ? "" : f.email?.own || "",
password: "",
country: f.country?.locked ? "" : f.country?.own || "",
+ // controlMode isn't secret, so show the effective value when it's locked.
+ controlMode: f.controlMode?.locked ? f.controlMode?.effective || "off" : f.controlMode?.own || "off",
};
}
+// Effective OCPP control mode (off | own | proxy) — gates the control panel.
+const ankerControlMode = computed(() => anker.value?.controlMode || "off");
+
+// --- Anker Solix OCPP control (per-charger provisioning + connection status) ---
+const ankerCtlSerial = ref("");
+const ankerCtl = ref(null); // { endpoint, token, connected, status, ... }
+const ankerCtlLoading = ref(false);
+const ankerCtlError = ref("");
+
+async function loadAnkerControl() {
+ const sn = ankerCtlSerial.value.trim();
+ if (!sn) return;
+ ankerCtlError.value = "";
+ ankerCtlLoading.value = true;
+ try {
+ ankerCtl.value = await api.getAnkerControl(sn);
+ } catch (e) {
+ ankerCtlError.value = e.message;
+ } finally {
+ ankerCtlLoading.value = false;
+ }
+}
+
+async function generateAnkerToken() {
+ const sn = ankerCtlSerial.value.trim();
+ if (!sn) return;
+ ankerCtlError.value = "";
+ try {
+ await api.ankerControlToken(sn);
+ await loadAnkerControl();
+ } catch (e) {
+ ankerCtlError.value = e.message;
+ }
+}
+
function applyAnkerView(body) {
anker.value = body;
if (ankerScope.value === "org" && !body.canEditOrg) ankerScope.value = "user";
@@ -479,7 +516,7 @@ async function saveAnkerSettings() {
ankerSaving.value = true;
ankerSaved.value = false;
const config = {};
- for (const k of ["email", "password", "country"]) {
+ for (const k of ["email", "password", "country", "controlMode"]) {
if (ankerLocked(k)) continue;
if (k === "password" && !ankerForm.value.password) continue;
config[k] = ankerForm.value[k];
@@ -1045,6 +1082,16 @@ onBeforeUnmount(() => {
{{ ankerSourceLabel('country') }}
{{ t("settings.integrations.countryHint") }}
+