diff --git a/src/components/devices/OpenwbConfigProxy.vue b/src/components/devices/OpenwbConfigProxy.vue
index 91aeb3ab..442eb1e5 100644
--- a/src/components/devices/OpenwbConfigProxy.vue
+++ b/src/components/devices/OpenwbConfigProxy.vue
@@ -3,9 +3,9 @@
:is="getComponent()"
:device="device"
:component="component"
- :configuration="component ? component.configuration : device.configuration"
- :device-id="device.id"
- :device-type="device.type"
+ :configuration="component ? component.configuration : device?.configuration"
+ :device-id="device?.id"
+ :device-type="device?.type"
:component-id="component ? component.id : undefined"
:component-type="component ? component.type : undefined"
@update:configuration="updateConfiguration($event)"
@@ -26,7 +26,7 @@ export default {
emits: ["update:configuration"],
methods: {
getComponent() {
- console.debug(`loading component: ${this.device.type} / ${this.component?.type}`);
+ console.debug(`loading component: ${this.device?.type} / ${this.component?.type}`);
if (this.component !== undefined) {
return defineAsyncComponent({
loader: () => import(`./${this.device.vendor}/${this.device.type}/${this.component.type}.vue`),
@@ -34,7 +34,7 @@ export default {
});
} else {
return defineAsyncComponent({
- loader: () => import(`./${this.device.vendor}/${this.device.type}/device.vue`),
+ loader: () => import(`./${this.device.vendor}/${this.device?.type}/device.vue`),
errorComponent: OpenwbDeviceConfigFallback,
});
}
diff --git a/src/views/ChargePointInstallation.vue b/src/views/ChargePointInstallation.vue
index 36e417c3..2a04e017 100644
--- a/src/views/ChargePointInstallation.vue
+++ b/src/views/ChargePointInstallation.vue
@@ -526,17 +526,22 @@ export default {
let chargePoints = this.getWildcardTopics("openWB/chargepoint/+/config");
let myObj = {};
for (const [key, element] of Object.entries(chargePoints)) {
- if (element.type === "internal_openwb" || this.$store.state.mqtt["openWB/general/extern"] === false) {
+ if (
+ element &&
+ typeof element === "object" &&
+ (element.type === "internal_openwb" || this.$store.state.mqtt["openWB/general/extern"] === false)
+ ) {
myObj[key] = element;
}
}
return myObj;
},
},
- chargePointTemplates: {
- get() {
- return this.getWildcardTopics("openWB/chargepoint/template/+");
- },
+ chargePointTemplates() {
+ const chargePointTemplates = this.getWildcardTopics("openWB/chargepoint/template/+");
+ return Object.fromEntries(
+ Object.entries(chargePointTemplates).filter(([, template]) => template && typeof template === "object"),
+ );
},
chargePointTemplateList: {
get() {
diff --git a/src/views/HardwareInstallation.vue b/src/views/HardwareInstallation.vue
index 55cc7119..ac9969d4 100644
--- a/src/views/HardwareInstallation.vue
+++ b/src/views/HardwareInstallation.vue
@@ -62,10 +62,10 @@
-
+
@@ -89,15 +89,15 @@
Es wurden noch keine Komponenten zu diesem Gerät angelegt.
-
- {{ installedComponent.name }}
+
+ {{ installedComponent?.name }}
Optional: zusätzliche Information für den Systembericht.
@@ -133,7 +133,7 @@
Optional: zusätzliche Information für den Systembericht.
@@ -147,19 +147,19 @@
@@ -175,7 +175,7 @@
Dieses System bietet keine Komponenten zur Installation an.
-
+
template && typeof template === "object"),
+ );
},
- installedComponents: {
- get() {
- return this.getWildcardTopics("openWB/system/device/+/component/+/config");
- },
+ installedComponents() {
+ const installedComponents = this.getWildcardTopics("openWB/system/device/+/component/+/config");
+ return Object.fromEntries(
+ Object.entries(installedComponents).filter(([, template]) => template && typeof template === "object"),
+ );
},
vendorList: {
get() {
- if (this.$store.state.mqtt["openWB/system/configurable/devices_components"] === undefined) {
+ const devicesComponents = this.$store.state.mqtt["openWB/system/configurable/devices_components"];
+ if (!devicesComponents) {
return [];
}
- return Object.entries(this.$store.state.mqtt["openWB/system/configurable/devices_components"])
+ return Object.entries(devicesComponents)
.map(([groupKey, group]) => {
+ // Fallback für group.vendors
+ const vendors = group?.vendors || {};
return {
- label: group.group_name,
- options: Object.entries(group.vendors)
- .map(([vendorKey, vendor]) => {
- return {
- value: [groupKey, vendorKey],
- text: vendor.vendor_name,
- };
- })
+ label: group?.group_name || "",
+ options: Object.entries(vendors)
+ .map(([vendorKey, vendor]) => ({
+ value: [groupKey, vendorKey],
+ text: vendor?.vendor_name || "",
+ }))
.sort((a, b) => a.text.localeCompare(b.text)),
};
})
- .sort((a, b) => -a.label.localeCompare(b.label)); // reverse order to have "openWB" at the top
+ .sort((a, b) => -a.label.localeCompare(b.label));
},
},
deviceList: {
@@ -320,15 +323,17 @@ export default {
return [];
}
let [groupKey, vendorKey] = this.selectedVendor;
- return Object.entries(
- this.$store.state.mqtt["openWB/system/configurable/devices_components"][groupKey].vendors[vendorKey].devices,
- )
- .map(([deviceKey, device]) => {
- return {
- value: [vendorKey, deviceKey],
- text: device.device_name,
- };
- })
+ const devices =
+ this.$store.state.mqtt["openWB/system/configurable/devices_components"]?.[groupKey]?.vendors?.[vendorKey]
+ ?.devices;
+ if (!devices) {
+ return [];
+ }
+ return Object.entries(devices)
+ .map(([deviceKey, device]) => ({
+ value: [vendorKey, deviceKey],
+ text: device.device_name,
+ }))
.sort((a, b) => a.text.localeCompare(b.text));
},
},
diff --git a/src/views/IoConfig.vue b/src/views/IoConfig.vue
index af83eec5..2fb27385 100644
--- a/src/views/IoConfig.vue
+++ b/src/views/IoConfig.vue
@@ -199,10 +199,11 @@ export default {
return this.$store.state.mqtt["openWB/system/configurable/io_devices"];
},
},
- installedIoDevices: {
- get() {
- return this.getWildcardTopics("openWB/system/io/+/config");
- },
+ installedIoDevices() {
+ const installedIoDevices = this.getWildcardTopics("openWB/system/io/+/config");
+ return Object.fromEntries(
+ Object.entries(installedIoDevices).filter(([, template]) => template && typeof template === "object"),
+ );
},
ioActionList: {
get() {
diff --git a/src/views/MqttBridgeConfig.vue b/src/views/MqttBridgeConfig.vue
index 1961c112..4e3c845e 100644
--- a/src/views/MqttBridgeConfig.vue
+++ b/src/views/MqttBridgeConfig.vue
@@ -47,7 +47,7 @@
:name="'mqttBridgeConfigurationForm' + getMqttBridgeIndex(mqttBridgeKey)"
>
Die Bezeichnung darf nur aus Buchstaben ohne Umlaute und Zahlen bestehen.
@@ -84,7 +84,7 @@
class: 'btn-outline-success',
},
]"
- :model-value="mqttBridge.active"
+ :model-value="mqttBridge?.active"
@update:model-value="updateState(mqttBridgeKey, $event, 'active')"
/>
@@ -93,7 +93,7 @@
title="Entfernter Server"
subtype="host"
required
- :model-value="mqttBridge.remote.host"
+ :model-value="mqttBridge?.remote?.host"
@update:model-value="updateState(mqttBridgeKey, $event, 'remote.host')"
/>
@@ -137,7 +137,7 @@
subtype="text"
required
pattern="[A-Za-z0-9_\-]+"
- :model-value="mqttBridge.remote.client_id"
+ :model-value="mqttBridge?.remote?.client_id"
@update:model-value="updateState(mqttBridgeKey, $event, 'remote.client_id')"
>
@@ -157,7 +157,7 @@
text: 'v3.1.1',
},
]"
- :model-value="mqttBridge.remote.protocol"
+ :model-value="mqttBridge?.remote?.protocol"
@update:model-value="updateState(mqttBridgeKey, $event, 'remote.protocol')"
/>
@@ -206,7 +206,7 @@
class: 'btn-outline-success',
},
]"
- :model-value="mqttBridge.remote.try_private"
+ :model-value="mqttBridge?.remote?.try_private"
@update:model-value="updateState(mqttBridgeKey, $event, 'remote.try_private')"
>
@@ -232,7 +232,7 @@
class: 'btn-outline-success',
},
]"
- :model-value="mqttBridge.data_transfer.status"
+ :model-value="mqttBridge?.data_transfer?.status"
@update:model-value="updateState(mqttBridgeKey, $event, 'data_transfer.status')"
>
@@ -254,7 +254,7 @@
class: 'btn-outline-success',
},
]"
- :model-value="mqttBridge.data_transfer.graph"
+ :model-value="mqttBridge?.data_transfer?.graph"
@update:model-value="updateState(mqttBridgeKey, $event, 'data_transfer.graph')"
>
@@ -279,7 +279,7 @@
class: 'btn-outline-success',
},
]"
- :model-value="mqttBridge.data_transfer.configuration"
+ :model-value="mqttBridge?.data_transfer?.configuration"
@update:model-value="updateState(mqttBridgeKey, $event, 'data_transfer.configuration')"
>
@@ -331,13 +331,17 @@ export default {
computed: {
configuredMqttBridges: {
get() {
- let bridges = this.getWildcardTopics("openWB/system/mqtt/bridge/+");
- for (const [key, value] of Object.entries(bridges)) {
- if (value.remote.is_openwb_cloud) {
- delete bridges[key];
+ const bridges = this.getWildcardTopics("openWB/system/mqtt/bridge/+");
+ if (!bridges || typeof bridges !== "object") {
+ return {};
+ }
+ const filtered = { ...bridges };
+ for (const [key, value] of Object.entries(filtered)) {
+ if (value?.remote?.is_openwb_cloud) {
+ delete filtered[key];
}
}
- return bridges;
+ return filtered;
},
},
},
diff --git a/src/views/VehicleConfig.vue b/src/views/VehicleConfig.vue
index 764971be..c71c0914 100644
--- a/src/views/VehicleConfig.vue
+++ b/src/views/VehicleConfig.vue
@@ -96,7 +96,7 @@
Optional: zusätzliche Information für den Systembericht.
@@ -104,7 +104,7 @@
@@ -132,7 +132,7 @@
Fahrzeugzuordnung per ID-Tags
-
+
Einstellungen zur Fahrzeugzuordnung finden sich unter
Einstellungen - Identifikation .
@@ -169,7 +169,7 @@
class="mb-2"
title="SoC-Modul des Fahrzeugs"
:options="socModuleList"
- :model-value="$store.state.mqtt['openWB/vehicle/' + vehicleId + '/soc_module/config'].type"
+ :model-value="$store.state.mqtt['openWB/vehicle/' + vehicleId + '/soc_module/config']?.type"
@update:model-value="updateSelectedSocModule(vehicleId, $event)"
>
@@ -189,7 +189,7 @@
infolge von zeitlicher Verzögerungen kommen. Hilfestellung erfolgt primär im openWB-Forum.
-
+
template && typeof template === "object"),
+ );
},
evTemplateList: {
get() {
@@ -1500,10 +1503,13 @@ export default {
return myList;
},
},
- chargeTemplates: {
- get() {
- return this.getWildcardTopics("openWB/vehicle/template/charge_template/+");
- },
+ chargeTemplates() {
+ const chargeTemplates = this.getWildcardTopics("openWB/vehicle/template/charge_template/+");
+ return Object.fromEntries(
+ // Filter out temporarily undefined entries caused by async MQTT (unsubscribe/resubscribe),
+ // (on button push, discard changes) so templates never try to render incomplete data.
+ Object.entries(chargeTemplates).filter(([, template]) => template && typeof template === "object"),
+ );
},
chargeTemplateList: {
get() {