iobroker.eos-admin 7.9.27 → 7.9.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -3
- package/admin/jsonConfig.json5 +1 -21
- package/adminWww/assets/Adapters-B5_jQ7DE.js +2 -2
- package/adminWww/assets/bootstrap-COulQZax.js +1 -1
- package/adminWww/css/eos-branding.css +128 -239
- package/adminWww/index.html +4 -4
- package/adminWww/js/eos-branding.js +136 -41
- package/adminWww/js/eos-security-ui.js +1 -1
- package/build/lib/web.js +0 -12
- package/build/main.js +5 -10
- package/docs/NEXOWATT_EOS_UI_V28_UPDATE_FIX_DE.md +43 -0
- package/io-package.json +884 -883
- package/package.json +5 -4
- package/tools/nexowatt-generate-eos-admin-repo-entry.cjs +21 -2
- package/tools/nexowatt-generate-repo-entry.cjs +1 -31
- package/tools/nexowatt-patch-repo.cjs +31 -8
- package/tools/nexowatt-repair-eos-admin-update.cjs +15 -0
- package/tools/nexowatt-validate-package.cjs +3 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
window.NEXOWATT_EOS_UI_VERSION = 'v27-
|
|
4
|
+
window.NEXOWATT_EOS_UI_VERSION = 'v27-logo-nav-assist-polish';
|
|
5
5
|
|
|
6
6
|
const BRAND = 'NexoWatt EOS';
|
|
7
7
|
const EOS_MEANING = 'Energy Operation System';
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
protectedAdapters: ['eos-admin', 'backitup'],
|
|
73
73
|
},
|
|
74
74
|
securityFetchStarted: false,
|
|
75
|
+
assistOpen: false,
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
const safe = fn => {
|
|
@@ -490,44 +491,6 @@
|
|
|
490
491
|
removeLogoutButton();
|
|
491
492
|
};
|
|
492
493
|
|
|
493
|
-
const NAV_COMPACT_KEY = 'nexowatt.eos.navCompact';
|
|
494
|
-
|
|
495
|
-
const setNavCompact = value => safe(() => {
|
|
496
|
-
const active = !!value;
|
|
497
|
-
document.documentElement.classList.toggle('eos-nav-compact', active);
|
|
498
|
-
window.localStorage && window.localStorage.setItem(NAV_COMPACT_KEY, active ? '1' : '0');
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
const restoreNavCompact = () => safe(() => {
|
|
502
|
-
const saved = window.localStorage && window.localStorage.getItem(NAV_COMPACT_KEY);
|
|
503
|
-
if (saved === '1') document.documentElement.classList.add('eos-nav-compact');
|
|
504
|
-
if (saved === '0') document.documentElement.classList.remove('eos-nav-compact');
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
const bindCompactNavToggle = header => safe(() => {
|
|
508
|
-
if (!header) return;
|
|
509
|
-
restoreNavCompact();
|
|
510
|
-
const controls = Array.from(header.querySelectorAll('button, .MuiIconButton-root, [role="button"]'));
|
|
511
|
-
controls.forEach(control => {
|
|
512
|
-
if (control.dataset.eosCompactToggleBound === '1') return;
|
|
513
|
-
control.dataset.eosCompactToggleBound = '1';
|
|
514
|
-
control.setAttribute('title', 'Menü kompakt/erweitert anzeigen');
|
|
515
|
-
control.setAttribute('aria-label', 'Menü kompakt/erweitert anzeigen');
|
|
516
|
-
const toggle = event => {
|
|
517
|
-
event.preventDefault();
|
|
518
|
-
event.stopPropagation();
|
|
519
|
-
if (event.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
520
|
-
setNavCompact(!document.documentElement.classList.contains('eos-nav-compact'));
|
|
521
|
-
scheduleFullPatch(0);
|
|
522
|
-
return false;
|
|
523
|
-
};
|
|
524
|
-
control.addEventListener('click', toggle, true);
|
|
525
|
-
control.addEventListener('keydown', event => {
|
|
526
|
-
if (event.key === 'Enter' || event.key === ' ') toggle(event);
|
|
527
|
-
}, true);
|
|
528
|
-
});
|
|
529
|
-
});
|
|
530
|
-
|
|
531
494
|
const hideNativeLogoutNav = () => safe(() => {
|
|
532
495
|
const candidates = Array.from(document.querySelectorAll('.MuiDrawer-paper a, .MuiDrawer-paper button, .MuiDrawer-paper .MuiListItem-root, .MuiDrawer-paper .MuiListItemButton-root, .MuiDrawer-paper [role=\"button\"]'));
|
|
533
496
|
candidates.forEach(el => {
|
|
@@ -556,7 +519,26 @@
|
|
|
556
519
|
}
|
|
557
520
|
if (header) {
|
|
558
521
|
header.classList.add('eos-native-drawer-header');
|
|
559
|
-
|
|
522
|
+
const toggleButton = header.querySelector('button, .MuiIconButton-root, [role="button"]');
|
|
523
|
+
if (toggleButton && !toggleButton.dataset.eosNavCompactToggle) {
|
|
524
|
+
toggleButton.dataset.eosNavCompactToggle = 'true';
|
|
525
|
+
toggleButton.classList.add('eos-nav-compact-toggle');
|
|
526
|
+
toggleButton.setAttribute('title', 'Navigation kompakt/normal umschalten');
|
|
527
|
+
toggleButton.setAttribute('aria-label', 'Navigation kompakt/normal umschalten');
|
|
528
|
+
const toggleCompact = event => {
|
|
529
|
+
event.preventDefault();
|
|
530
|
+
event.stopPropagation();
|
|
531
|
+
if (event.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
532
|
+
const compact = !document.documentElement.classList.contains('eos-nav-compact');
|
|
533
|
+
document.documentElement.classList.toggle('eos-nav-compact', compact);
|
|
534
|
+
safe(() => localStorage.setItem('nexowatt:eosNavCompact', compact ? '1' : '0'));
|
|
535
|
+
toggleButton.setAttribute('aria-pressed', compact ? 'true' : 'false');
|
|
536
|
+
};
|
|
537
|
+
toggleButton.addEventListener('click', toggleCompact, true);
|
|
538
|
+
toggleButton.addEventListener('keydown', event => {
|
|
539
|
+
if (event.key === 'Enter' || event.key === ' ') toggleCompact(event);
|
|
540
|
+
}, true);
|
|
541
|
+
}
|
|
560
542
|
const img = header.querySelector('img');
|
|
561
543
|
if (img) patchImage(img);
|
|
562
544
|
const avatarImg = header.querySelector('.MuiAvatar-img');
|
|
@@ -767,6 +749,116 @@
|
|
|
767
749
|
});
|
|
768
750
|
});
|
|
769
751
|
|
|
752
|
+
|
|
753
|
+
const applyNavCompactPreference = () => safe(() => {
|
|
754
|
+
const compact = localStorage.getItem('nexowatt:eosNavCompact') === '1';
|
|
755
|
+
document.documentElement.classList.toggle('eos-nav-compact', compact);
|
|
756
|
+
document.querySelectorAll('.eos-nav-compact-toggle').forEach(button => {
|
|
757
|
+
button.setAttribute('aria-pressed', compact ? 'true' : 'false');
|
|
758
|
+
button.setAttribute('title', compact ? 'Navigation normal anzeigen' : 'Navigation kompakt anzeigen');
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
const assistContext = () => {
|
|
763
|
+
const routes = routeInfo();
|
|
764
|
+
if (routes.adapters) return {
|
|
765
|
+
title: 'Module einrichten',
|
|
766
|
+
text: 'Wähle zuerst das passende Modul, prüfe Version und Instanzstatus und öffne dann die Konfiguration über die drei Punkte oder das Werkzeug-Symbol.',
|
|
767
|
+
steps: ['Modul suchen', 'Instanz anlegen', 'Verbindung testen', 'Datenpunkte prüfen']
|
|
768
|
+
};
|
|
769
|
+
if (routes.instances) return {
|
|
770
|
+
title: 'Dienste prüfen',
|
|
771
|
+
text: 'Kontrolliere Status, Port, Speicherverbrauch und Logmeldungen. Gestoppte Dienste erst nach Ursache und Abhängigkeiten prüfen.',
|
|
772
|
+
steps: ['Status ansehen', 'Log öffnen', 'Konfiguration prüfen', 'Dienst neu starten']
|
|
773
|
+
};
|
|
774
|
+
if (routes.users) return {
|
|
775
|
+
title: 'Zugänge & Rechte',
|
|
776
|
+
text: 'Installateure und Endkunden sollten nur die Module sehen, die sie wirklich bedienen dürfen. Geschützte EOS-Module bleiben Administratoren vorbehalten.',
|
|
777
|
+
steps: ['Benutzer wählen', 'Rolle zuordnen', 'Rechteprofil setzen', 'Löschschutz prüfen']
|
|
778
|
+
};
|
|
779
|
+
if (routeInfo().intro) return {
|
|
780
|
+
title: 'EOS Cockpit',
|
|
781
|
+
text: 'Beginne mit Systemstatus, Hosts und gesicherten Basisdiensten. Danach Module Schritt für Schritt freischalten.',
|
|
782
|
+
steps: ['System prüfen', 'Sicherung prüfen', 'Module planen', 'Rechte vergeben']
|
|
783
|
+
};
|
|
784
|
+
return {
|
|
785
|
+
title: 'EOS Bedienhilfe',
|
|
786
|
+
text: 'Ich unterstütze dich beim Einrichten, Prüfen und Absichern deiner EOS-Module.',
|
|
787
|
+
steps: ['Ziel beschreiben', 'Modul auswählen', 'Parameter prüfen', 'Test starten']
|
|
788
|
+
};
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
const assistAnswer = query => {
|
|
792
|
+
const q = normalize(query);
|
|
793
|
+
if (!q) return 'Beschreibe kurz, was eingerichtet werden soll, zum Beispiel: PV, Speicher, Wallbox, Modbus, Backup oder Benutzerrechte.';
|
|
794
|
+
if (/wallbox|evcs|lade|auto|ocpp/.test(q)) return 'Für Ladepunkte: zuerst OCPP/EVCS-Modul installieren, Verbindung zur Wallbox prüfen, Ladepunkt-ID setzen, danach Datenpunkte für Status, Leistung und Freigabe testen.';
|
|
795
|
+
if (/pv|solar|wechselrichter|sun2000|fronius|kostal|sma/.test(q)) return 'Für PV/Wechselrichter: IP-Adresse, Modbus/TCP oder Hersteller-API aktivieren, Abfrageintervall moderat setzen und danach Erzeugung, Bezug und Einspeisung in den Datenpunkten prüfen.';
|
|
796
|
+
if (/speicher|batterie|akku/.test(q)) return 'Für Speicher: Kommunikationsweg prüfen, Lade-/Entladeleistung und SoC-Datenpunkte kontrollieren und Grenzwerte erst setzen, wenn Livewerte plausibel sind.';
|
|
797
|
+
if (/modbus/.test(q)) return 'Für Modbus: Host/IP, Port 502, Unit-ID und Registertabelle prüfen. Danach erst lesen testen, dann Schreibrechte gezielt freischalten.';
|
|
798
|
+
if (/mqtt/.test(q)) return 'Für MQTT: Broker-Adresse, Zugangsdaten, Topic-Struktur und TLS prüfen. Danach mit einem Test-Topic starten und erst dann produktive Topics freigeben.';
|
|
799
|
+
if (/backup|sicherung|restore/.test(q)) return 'Für Sicherung: BackItUp aktiv halten, Zielpfad oder Cloud-Ziel prüfen, Test-Backup starten und Restore-Hinweise dokumentieren.';
|
|
800
|
+
if (/rechte|benutzer|installateur|kunde|admin/.test(q)) return 'Für Rechte: Benutzer in Rollen trennen. Installateure dürfen konfigurieren, aber geschützte EOS-Systemmodule nicht löschen. Endkunden bekommen nur Bedien- und Leserechte.';
|
|
801
|
+
if (/fehler|log|offline|404|timeout/.test(q)) return 'Bei Fehlern: zuerst Systemlogs öffnen, betroffene Instanz filtern, letzte Änderung prüfen, Dienst neu starten und danach Port/WebSocket/Repository prüfen.';
|
|
802
|
+
return 'Vorschlag: Starte mit dem passenden Modul, prüfe die Verbindung, kontrolliere die erzeugten Datenpunkte und sichere danach die Rechte. Für konkrete Hilfe nenne bitte Modulname und Zielgerät.';
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
const ensureEosAssist = () => safe(() => {
|
|
806
|
+
const hasApp = !!document.getElementById('app-paper');
|
|
807
|
+
if (!hasApp || isLoginView()) {
|
|
808
|
+
document.getElementById('eos-assist-root')?.remove();
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
let root = document.getElementById('eos-assist-root');
|
|
812
|
+
if (!root) {
|
|
813
|
+
root = document.createElement('section');
|
|
814
|
+
root.id = 'eos-assist-root';
|
|
815
|
+
root.className = 'eos-assist-root';
|
|
816
|
+
document.body.appendChild(root);
|
|
817
|
+
}
|
|
818
|
+
const ctx = assistContext();
|
|
819
|
+
root.classList.toggle('eos-assist-open', !!state.assistOpen);
|
|
820
|
+
root.innerHTML = `
|
|
821
|
+
<button class="eos-assist-button" type="button" aria-expanded="${state.assistOpen ? 'true' : 'false'}">
|
|
822
|
+
<span class="eos-assist-dot"></span><strong>EOS Assist</strong><small>Einrichtungshilfe</small>
|
|
823
|
+
</button>
|
|
824
|
+
<div class="eos-assist-panel" role="dialog" aria-label="EOS Assist Einrichtungshilfe">
|
|
825
|
+
<div class="eos-assist-head">
|
|
826
|
+
<div><strong>${ctx.title}</strong><span>${ctx.text}</span></div>
|
|
827
|
+
<button type="button" class="eos-assist-close" aria-label="EOS Assist schließen">×</button>
|
|
828
|
+
</div>
|
|
829
|
+
<div class="eos-assist-steps">${ctx.steps.map(step => `<span>${step}</span>`).join('')}</div>
|
|
830
|
+
<label class="eos-assist-input-label">Was möchtest du einrichten?</label>
|
|
831
|
+
<div class="eos-assist-input-row"><input class="eos-assist-input" placeholder="z. B. Wallbox, PV, Modbus, Rechte..." /><button type="button" class="eos-assist-send">Fragen</button></div>
|
|
832
|
+
<div class="eos-assist-answer">${assistAnswer('')}</div>
|
|
833
|
+
</div>
|
|
834
|
+
`;
|
|
835
|
+
const openButton = root.querySelector('.eos-assist-button');
|
|
836
|
+
const closeButton = root.querySelector('.eos-assist-close');
|
|
837
|
+
const input = root.querySelector('.eos-assist-input');
|
|
838
|
+
const send = root.querySelector('.eos-assist-send');
|
|
839
|
+
const answer = root.querySelector('.eos-assist-answer');
|
|
840
|
+
openButton?.addEventListener('click', event => {
|
|
841
|
+
event.preventDefault();
|
|
842
|
+
state.assistOpen = !state.assistOpen;
|
|
843
|
+
root.classList.toggle('eos-assist-open', state.assistOpen);
|
|
844
|
+
openButton.setAttribute('aria-expanded', state.assistOpen ? 'true' : 'false');
|
|
845
|
+
if (state.assistOpen) setTimeout(() => input?.focus(), 40);
|
|
846
|
+
});
|
|
847
|
+
closeButton?.addEventListener('click', event => {
|
|
848
|
+
event.preventDefault();
|
|
849
|
+
state.assistOpen = false;
|
|
850
|
+
root.classList.remove('eos-assist-open');
|
|
851
|
+
openButton?.setAttribute('aria-expanded', 'false');
|
|
852
|
+
});
|
|
853
|
+
const ask = () => {
|
|
854
|
+
if (answer) answer.textContent = assistAnswer(input?.value || '');
|
|
855
|
+
};
|
|
856
|
+
send?.addEventListener('click', ask);
|
|
857
|
+
input?.addEventListener('keydown', event => {
|
|
858
|
+
if (event.key === 'Enter') ask();
|
|
859
|
+
});
|
|
860
|
+
});
|
|
861
|
+
|
|
770
862
|
const patchDocumentMeta = () => safe(() => {
|
|
771
863
|
document.title = BRAND_LONG;
|
|
772
864
|
const theme = document.querySelector('meta[name="theme-color"]');
|
|
@@ -784,6 +876,8 @@
|
|
|
784
876
|
patchDocumentMeta();
|
|
785
877
|
patchLogin();
|
|
786
878
|
patchShell();
|
|
879
|
+
applyNavCompactPreference();
|
|
880
|
+
ensureEosAssist();
|
|
787
881
|
ensureRightsHelper();
|
|
788
882
|
ensurePermissionPresets();
|
|
789
883
|
ensureSettingsDialogClasses();
|
|
@@ -801,6 +895,8 @@
|
|
|
801
895
|
normalizeBadAddressAfterLogin();
|
|
802
896
|
patchLogin();
|
|
803
897
|
patchShell();
|
|
898
|
+
applyNavCompactPreference();
|
|
899
|
+
ensureEosAssist();
|
|
804
900
|
ensureRightsHelper();
|
|
805
901
|
ensurePermissionPresets();
|
|
806
902
|
ensureSettingsDialogClasses();
|
|
@@ -859,7 +955,6 @@
|
|
|
859
955
|
});
|
|
860
956
|
|
|
861
957
|
forceLoginGlobals();
|
|
862
|
-
restoreNavCompact();
|
|
863
958
|
if (document.readyState === 'loading') {
|
|
864
959
|
document.addEventListener('DOMContentLoaded', () => {
|
|
865
960
|
fullPatch();
|
package/build/lib/web.js
CHANGED
|
@@ -491,14 +491,6 @@ class Web {
|
|
|
491
491
|
legacyAdminAdapter: 'admin',
|
|
492
492
|
legacyAdminInstance: 'admin.0',
|
|
493
493
|
protectedAdapters: this.getEosProtectedAdapterNames(),
|
|
494
|
-
eosAssistantEnabled: this.settings.eosAssistantEnabled !== false,
|
|
495
|
-
eosAssistantMode: this.settings.eosAssistantMode || 'local',
|
|
496
|
-
eosAssistantAdminOnly: this.settings.eosAssistantAdminOnly === true,
|
|
497
|
-
assistant: {
|
|
498
|
-
enabled: this.settings.eosAssistantEnabled !== false,
|
|
499
|
-
mode: this.settings.eosAssistantMode || 'local',
|
|
500
|
-
adminOnly: this.settings.eosAssistantAdminOnly === true,
|
|
501
|
-
},
|
|
502
494
|
});
|
|
503
495
|
}
|
|
504
496
|
|
|
@@ -729,10 +721,6 @@ class Web {
|
|
|
729
721
|
hideLegacyAdminFromNonAdmins: true,
|
|
730
722
|
restrictProtectedAdapterControls: true,
|
|
731
723
|
protectedAdapters: ['eos-admin'],
|
|
732
|
-
eosAssistantEnabled: true,
|
|
733
|
-
eosAssistantMode: 'local',
|
|
734
|
-
eosAssistantAdminOnly: false,
|
|
735
|
-
assistant: { enabled: true, mode: 'local', adminOnly: false },
|
|
736
724
|
});
|
|
737
725
|
});
|
|
738
726
|
};
|
package/build/main.js
CHANGED
|
@@ -828,13 +828,8 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
828
828
|
}
|
|
829
829
|
let changed = false;
|
|
830
830
|
obj.common = obj.common || {};
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
obj.common.dontDelete = true;
|
|
834
|
-
changed = true;
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
else if (obj.common.dontDelete === true && id !== `system.adapter.${EOS_ADMIN_ADAPTER_NAME}`) {
|
|
831
|
+
// v28: do not use common.dontDelete for EOS protection because it can block adapter upgrades.
|
|
832
|
+
if (obj.common.dontDelete === true) {
|
|
838
833
|
delete obj.common.dontDelete;
|
|
839
834
|
changed = true;
|
|
840
835
|
}
|
|
@@ -870,7 +865,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
870
865
|
const isEosAdmin = adapter === EOS_ADMIN_ADAPTER_NAME;
|
|
871
866
|
const adminOnlyAcl = isEosAdmin || this.shouldApplyAdminOnlyAclToProtectedAdapters();
|
|
872
867
|
let changed = await this.ensureObjectProtectionPolicy(`system.adapter.${adapter}`, {
|
|
873
|
-
keepDontDelete:
|
|
868
|
+
keepDontDelete: false,
|
|
874
869
|
adminOnlyAcl,
|
|
875
870
|
});
|
|
876
871
|
try {
|
|
@@ -880,7 +875,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
880
875
|
});
|
|
881
876
|
for (const row of instances.rows) {
|
|
882
877
|
changed = (await this.ensureObjectProtectionPolicy(row.id, {
|
|
883
|
-
keepDontDelete:
|
|
878
|
+
keepDontDelete: false,
|
|
884
879
|
adminOnlyAcl,
|
|
885
880
|
})) || changed;
|
|
886
881
|
}
|
|
@@ -889,7 +884,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
889
884
|
this.log.warn(`Cannot protect instances of adapter "${adapter}": ${e instanceof Error ? e.message : e}`);
|
|
890
885
|
}
|
|
891
886
|
if (changed) {
|
|
892
|
-
this.log.info(`EOS
|
|
887
|
+
this.log.info(`EOS ACL/UI delete guard applied to adapter "${adapter}"`);
|
|
893
888
|
}
|
|
894
889
|
}
|
|
895
890
|
async ensureLegacyAdminLocked() {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# NexoWatt EOS Admin v28 Update-Fix
|
|
2
|
+
|
|
3
|
+
Diese Version behebt den Update-Stopp des eigenständigen `eos-admin` Adapters.
|
|
4
|
+
|
|
5
|
+
## Ursachen
|
|
6
|
+
|
|
7
|
+
Es gab zwei technische Ursachen:
|
|
8
|
+
|
|
9
|
+
1. Der gebaute Adapter-Frontend-Bundle enthielt noch den alten Self-Update-Check `adapterName === "admin"`. Dadurch nutzte `eos-admin` beim Klick auf Update nicht den Webserver-Updatepfad, sondern den normalen Terminal-Befehl. Beim Update der gerade laufenden Oberfläche kann das hängen bleiben.
|
|
10
|
+
2. Frühere Builds konnten `common.dontDelete=true` auf `system.adapter.eos-admin` setzen. Das schützt zwar gegen Löschen, kann aber den ioBroker-Upgrade-Ablauf stören, weil Updates Adapterobjekte ersetzen oder neu schreiben müssen.
|
|
11
|
+
|
|
12
|
+
## Lösung
|
|
13
|
+
|
|
14
|
+
- Der gebaute Adapter-Bundle nutzt jetzt `adapterName === "eos-admin"`.
|
|
15
|
+
- Der Webserver-Updater sendet jetzt `adapterName: "eos-admin"` an den js-controller.
|
|
16
|
+
- `eos-admin` wird aus „Update alle“ herausgefiltert, damit die laufende Oberfläche nicht über den normalen Terminal-Befehl aktualisiert wird.
|
|
17
|
+
- `common.stopBeforeUpdate=false` im Repository und im Adapter-Metadata.
|
|
18
|
+
- `common.dontDelete=false` und `common.nondeletable=false`.
|
|
19
|
+
- Löschschutz erfolgt über ACLs, EOS UI-Regeln und Security Guard, nicht über objektbasierte Update-Blocker.
|
|
20
|
+
|
|
21
|
+
## Reparatur bestehender Installationen
|
|
22
|
+
|
|
23
|
+
Vor dem Update von älteren v24–v27 Installationen einmalig die alten Sperrflags entfernen:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cd /opt/iobroker
|
|
27
|
+
|
|
28
|
+
iobroker object set system.adapter.eos-admin common.dontDelete=false || true
|
|
29
|
+
iobroker object set system.adapter.eos-admin common.nondeletable=false || true
|
|
30
|
+
iobroker object set system.adapter.eos-admin common.stopBeforeUpdate=false || true
|
|
31
|
+
|
|
32
|
+
iobroker object set system.adapter.eos-admin.0 common.dontDelete=false || true
|
|
33
|
+
iobroker object set system.adapter.eos-admin.0 common.nondeletable=false || true
|
|
34
|
+
|
|
35
|
+
iobroker update https://iobroker.live/repo/repo-nexowatt.json
|
|
36
|
+
iobroker upgrade eos-admin https://iobroker.live/repo/repo-nexowatt.json
|
|
37
|
+
iobroker upload eos-admin
|
|
38
|
+
iobroker restart eos-admin.0
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Löschschutz
|
|
42
|
+
|
|
43
|
+
Der harte Objekt-Flag `dontDelete` wird in v28 bewusst entfernt, weil er den Updatepfad blockieren kann. Der Schutz gegen Löschen erfolgt über EOS-Admin-Rechte, ACL/Guard und ausgeblendete Löschaktionen für Nicht-Administratoren. `nondeletable` bleibt `false`, damit Updates immer möglich bleiben.
|