diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a96126e6..ac9a99da1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,7 @@ set (VENUS_QML_MODULE_SOURCES components/Led.qml components/LoadGraph.qml components/LoadGraphShapePath.qml + components/MultiServiceDeviceModel.qml components/NavBar.qml components/NavButton.qml components/NotificationDelegate.qml @@ -238,6 +239,7 @@ set (VENUS_QML_MODULE_SOURCES components/SegmentedButtonRow.qml components/SeparatorBar.qml components/ServiceDeviceModel.qml + components/ServiceModelLoader.qml components/SettingsRangeSlider.qml components/SettingsSlider.qml components/ShinyProgressArc.qml @@ -380,7 +382,6 @@ set (VENUS_QML_MODULE_SOURCES data/Batteries.qml data/DataManager.qml data/DcInputs.qml - data/DcLoads.qml data/DigitalInputs.qml data/EnvironmentInputs.qml data/Ess.qml @@ -405,7 +406,6 @@ set (VENUS_QML_MODULE_SOURCES data/common/AcInput.qml data/common/DcDevice.qml data/common/DcInput.qml - data/common/DcLoad.qml data/common/DeviceModel.qml data/common/EnvironmentInput.qml data/common/EssData.qml @@ -783,7 +783,6 @@ endif() set(Dbus_QML_MODULE_SOURCES data/dbus/DBusDataManager.qml data/dbus/DcInputsImpl.qml - data/dbus/DcLoadsImpl.qml data/dbus/EnvironmentInputsImpl.qml data/dbus/EssImpl.qml data/dbus/EvChargersImpl.qml @@ -902,7 +901,6 @@ endif() # Mqtt_QML_MODULE set(Mqtt_QML_MODULE_SOURCES data/mqtt/DcInputsImpl.qml - data/mqtt/DcLoadsImpl.qml data/mqtt/EnvironmentInputsImpl.qml data/mqtt/EssImpl.qml data/mqtt/EvChargersImpl.qml diff --git a/Global.qml b/Global.qml index c57099a68..565a22d94 100644 --- a/Global.qml +++ b/Global.qml @@ -31,7 +31,6 @@ QtObject { property var acInputs property var batteries property var dcInputs - property var dcLoads property var digitalInputs property var environmentInputs property var ess @@ -103,7 +102,6 @@ QtObject { acInputs = null batteries = null dcInputs = null - dcLoads = null digitalInputs = null environmentInputs = null ess = null diff --git a/components/AllDevicesModel.qml b/components/AllDevicesModel.qml index f24086f34..80e91dbcc 100644 --- a/components/AllDevicesModel.qml +++ b/components/AllDevicesModel.qml @@ -12,7 +12,7 @@ AggregateDeviceModel { sourceModels: [ batteryDevices, Global.dcInputs.model, - Global.dcLoads.model, + combinedDcLoadsModel, digitalInputDevices, Global.environmentInputs.model, Global.evChargers.model, @@ -40,6 +40,11 @@ AggregateDeviceModel { modelId: "battery" } + readonly property MultiServiceDeviceModel combinedDcLoadsModel: MultiServiceDeviceModel { + serviceTypes: ["dcload", "dcsystem", "dcdc"] + modelId: "combinedDcloads" + } + readonly property ServiceDeviceModel digitalInputDevices: ServiceDeviceModel { serviceType: "digitalinput" modelId: "digitalinput" diff --git a/components/MultiServiceDeviceModel.qml b/components/MultiServiceDeviceModel.qml new file mode 100644 index 000000000..ed31e3909 --- /dev/null +++ b/components/MultiServiceDeviceModel.qml @@ -0,0 +1,40 @@ +/* +** Copyright (C) 2024 Victron Energy B.V. +** See LICENSE.txt for license information. +*/ + +import QtQuick +import Victron.VenusOS + +// Provides a generic DeviceModel for a set of service types. +// +// All services found for the specified types will be added and removed as Device objects. + +DeviceModel { + id: root + + required property var serviceTypes + + readonly property Instantiator _serviceObjects: Instantiator { + model: root.serviceTypes + delegate: Instantiator { + required property string modelData + readonly property ServiceModelLoader modelLoader: ServiceModelLoader { + serviceType: modelData + } + + model: modelLoader.item + delegate: Device { + id: device + serviceUid: model.uid + onValidChanged: { + if (valid) { + root.addDevice(device) + } else { + root.removeDevice(device.serviceUid) + } + } + } + } + } +} diff --git a/components/ServiceDeviceModel.qml b/components/ServiceDeviceModel.qml index 74d6f4dcd..bab5b4ca5 100644 --- a/components/ServiceDeviceModel.qml +++ b/components/ServiceDeviceModel.qml @@ -30,24 +30,7 @@ DeviceModel { } } - readonly property Loader modelLoader: Loader { - sourceComponent: BackendConnection.type === BackendConnection.MqttSource ? _mqttModelComponent - : _dbusOrMockModelComponent - } - - readonly property Component _dbusOrMockModelComponent: Component { - VeQItemSortTableModel { - dynamicSortFilter: true - filterRole: VeQItemTableModel.UniqueIdRole - filterRegExp: "^%1/com\.victronenergy\.%2\.".arg(BackendConnection.uidPrefix()).arg(root.serviceType) - model: Global.dataServiceModel - } - } - - readonly property Component _mqttModelComponent: Component { - VeQItemTableModel { - uids: [ "mqtt/" + root.serviceType ] - flags: VeQItemTableModel.AddChildren | VeQItemTableModel.AddNonLeaves | VeQItemTableModel.DontAddItem - } + readonly property ServiceModelLoader modelLoader: ServiceModelLoader { + serviceType: root.serviceType } } diff --git a/components/ServiceModelLoader.qml b/components/ServiceModelLoader.qml new file mode 100644 index 000000000..aea955f48 --- /dev/null +++ b/components/ServiceModelLoader.qml @@ -0,0 +1,32 @@ +/* +** Copyright (C) 2024 Victron Energy B.V. +** See LICENSE.txt for license information. +*/ + +import QtQuick +import Victron.VenusOS + +Loader { + id: root + + required property string serviceType + + sourceComponent: BackendConnection.type === BackendConnection.MqttSource ? _mqttModelComponent + : _dbusOrMockModelComponent + + readonly property Component _dbusOrMockModelComponent: Component { + VeQItemSortTableModel { + dynamicSortFilter: true + filterRole: VeQItemTableModel.UniqueIdRole + filterRegExp: "^%1/com\.victronenergy\.%2\.".arg(BackendConnection.uidPrefix()).arg(root.serviceType) + model: Global.dataServiceModel + } + } + + readonly property Component _mqttModelComponent: Component { + VeQItemTableModel { + uids: [ "mqtt/" + root.serviceType ] + flags: VeQItemTableModel.AddChildren | VeQItemTableModel.AddNonLeaves | VeQItemTableModel.DontAddItem + } + } +} diff --git a/components/widgets/DcLoadsWidget.qml b/components/widgets/DcLoadsWidget.qml index 31da8796d..4a0dfe741 100644 --- a/components/widgets/DcLoadsWidget.qml +++ b/components/widgets/DcLoadsWidget.qml @@ -24,15 +24,15 @@ OverviewWidget { title: qsTrId("overview_widget_dcloads_title") icon.source: "qrc:/images/dcloads.svg" type: VenusOS.OverviewWidget_Type_DcLoads - enabled: Global.dcLoads.model.count > 0 + enabled: Global.allDevicesModel.combinedDcLoadsModel.count > 0 quantityLabel.dataObject: Global.system.dc onClicked: { - if (Global.dcLoads.model.count > 1) { + if (Global.allDevicesModel.combinedDcLoadsModel.count > 1) { Global.pageManager.pushPage(deviceListPageComponent, { "title": root.title }) } else { - root._showSettingsPage(Global.dcLoads.model.firstObject) + root._showSettingsPage(Global.allDevicesModel.combinedDcLoadsModel.firstObject) } } @@ -41,7 +41,7 @@ OverviewWidget { Page { GradientListView { - model: Global.dcLoads.model + model: Global.allDevicesModel.combinedDcLoadsModel delegate: ListTextGroup { id: deviceDelegate @@ -50,11 +50,16 @@ OverviewWidget { text: device.name textModel: [ - Units.getCombinedDisplayText(VenusOS.Units_Volt_DC, device.voltage), - Units.getCombinedDisplayText(VenusOS.Units_Amp, device.current), - Units.getCombinedDisplayText(VenusOS.Units_Watt, device.power), + Units.getCombinedDisplayText(VenusOS.Units_Volt_DC, dcDevice.voltage), + Units.getCombinedDisplayText(VenusOS.Units_Amp, dcDevice.current), + Units.getCombinedDisplayText(VenusOS.Units_Watt, dcDevice.power), ] + DcDevice { + id: dcDevice + serviceUid: deviceDelegate.device.serviceUid + } + ListPressArea { id: delegatePressArea diff --git a/data/DataManager.qml b/data/DataManager.qml index 7799c7ee4..b6a7b00da 100644 --- a/data/DataManager.qml +++ b/data/DataManager.qml @@ -16,7 +16,6 @@ Item { && !!Global.acInputs && !!Global.batteries && !!Global.dcInputs - && !!Global.dcLoads && !!Global.digitalInputs && !!Global.environmentInputs && !!Global.ess @@ -96,7 +95,6 @@ Item { AcInputs {} Batteries {} DcInputs {} - DcLoads {} DigitalInputs {} EnvironmentInputs {} Ess {} diff --git a/data/DcLoads.qml b/data/DcLoads.qml deleted file mode 100644 index c5a3ce61e..000000000 --- a/data/DcLoads.qml +++ /dev/null @@ -1,17 +0,0 @@ -/* -** Copyright (C) 2023 Victron Energy B.V. -** See LICENSE.txt for license information. -*/ - -import QtQuick -import Victron.VenusOS - -QtObject { - id: root - - property DeviceModel model: DeviceModel { - modelId: "dcLoads" - } - - Component.onCompleted: Global.dcLoads = root -} diff --git a/data/common/DcLoad.qml b/data/common/DcLoad.qml deleted file mode 100644 index 81b8faeb1..000000000 --- a/data/common/DcLoad.qml +++ /dev/null @@ -1,21 +0,0 @@ -/* -** Copyright (C) 2023 Victron Energy B.V. -** See LICENSE.txt for license information. -*/ - -import QtQuick -import Victron.VenusOS - -DcDevice { - id: dcLoad - - onValidChanged: { - if (!!Global.dcLoads) { - if (valid) { - Global.dcLoads.model.addDevice(dcLoad) - } else { - Global.dcLoads.model.removeDevice(dcLoad.serviceUid) - } - } - } -} diff --git a/data/dbus/DBusDataManager.qml b/data/dbus/DBusDataManager.qml index e96fe18de..944f790d4 100644 --- a/data/dbus/DBusDataManager.qml +++ b/data/dbus/DBusDataManager.qml @@ -11,7 +11,6 @@ QtObject { id: root property var dcInputs: DcInputsImpl { } - property var dcLoads: DcLoadsImpl { } property var environmentInputs: EnvironmentInputsImpl { } property var ess: EssImpl { } property var evChargers: EvChargersImpl { } diff --git a/data/dbus/DcLoadsImpl.qml b/data/dbus/DcLoadsImpl.qml deleted file mode 100644 index dc5799f2a..000000000 --- a/data/dbus/DcLoadsImpl.qml +++ /dev/null @@ -1,50 +0,0 @@ -/* -** Copyright (C) 2023 Victron Energy B.V. -** See LICENSE.txt for license information. -*/ - -import QtQuick -import Victron.VenusOS - -Instantiator { - id: root - - readonly property Instantiator dcloadObjects: Instantiator { - model: VeQItemSortTableModel { - dynamicSortFilter: true - filterRole: VeQItemTableModel.UniqueIdRole - filterRegExp: "^dbus/com\.victronenergy\.dcload\." - model: Global.dataServiceModel - } - - delegate: DcLoad { - serviceUid: model.uid - } - } - - readonly property Instantiator dcsystemObjects: Instantiator { - model: VeQItemSortTableModel { - dynamicSortFilter: true - filterRole: VeQItemTableModel.UniqueIdRole - filterRegExp: "^dbus/com\.victronenergy\.dcsystem\." - model: Global.dataServiceModel - } - - delegate: DcLoad { - serviceUid: model.uid - } - } - - readonly property Instantiator dcdcObjects: Instantiator { - model: VeQItemSortTableModel { - dynamicSortFilter: true - filterRole: VeQItemTableModel.UniqueIdRole - filterRegExp: "^dbus/com\.victronenergy\.dcdc\." - model: Global.dataServiceModel - } - - delegate: DcLoad { - serviceUid: model.uid - } - } -} diff --git a/data/mock/DcLoadsImpl.qml b/data/mock/DcLoadsImpl.qml index d7c4b7ee7..9f9405a88 100644 --- a/data/mock/DcLoadsImpl.qml +++ b/data/mock/DcLoadsImpl.qml @@ -64,16 +64,16 @@ QtObject { } property Timer updateDcValues: Timer { - running: Global.mockDataSimulator.timersActive - interval: 1000 + running: Global.mockDataSimulator.timersActive && !!(Global.allDevicesModel?.combinedDcLoadsModel) + interval: 500 repeat: true - triggeredOnStart: true onTriggered: { let totalPower = NaN - for (let i = 0; i < Global.dcLoads.model.count; ++i) { - const dcLoad = Global.dcLoads.model.deviceAt(i) - totalPower = Units.sumRealNumbers(totalPower, dcLoad.power) + for (let i = 0; i < Global.allDevicesModel.combinedDcLoadsModel.count; ++i) { + const dcLoad = Global.allDevicesModel.combinedDcLoadsModel.deviceAt(i) + const power = Global.mockDataSimulator.mockValue(dcLoad.serviceUid + "/Dc/0/Power") + totalPower = Units.sumRealNumbers(totalPower, power) } Global.mockDataSimulator.setMockValue("com.victronenergy.system/Dc/System/Power", totalPower) @@ -83,7 +83,7 @@ QtObject { } property Component dcLoadComponent: Component { - DcLoad { + Device { id: dcLoad property string serviceType diff --git a/data/mqtt/DcLoadsImpl.qml b/data/mqtt/DcLoadsImpl.qml deleted file mode 100644 index 148791b59..000000000 --- a/data/mqtt/DcLoadsImpl.qml +++ /dev/null @@ -1,44 +0,0 @@ -/* -** Copyright (C) 2023 Victron Energy B.V. -** See LICENSE.txt for license information. -*/ - -import QtQuick -import Victron.VenusOS - -Instantiator { - id: root - - readonly property Instantiator dcloadObjects: Instantiator { - model: VeQItemTableModel { - uids: ["mqtt/dcload"] - flags: VeQItemTableModel.AddChildren | VeQItemTableModel.AddNonLeaves | VeQItemTableModel.DontAddItem - } - - delegate: DcLoad { - serviceUid: model.uid - } - } - - readonly property Instantiator dcsystemObjects: Instantiator { - model: VeQItemTableModel { - uids: ["mqtt/dcsystem"] - flags: VeQItemTableModel.AddChildren | VeQItemTableModel.AddNonLeaves | VeQItemTableModel.DontAddItem - } - - delegate: DcLoad { - serviceUid: model.uid - } - } - - readonly property Instantiator dcdcObjects: Instantiator { - model: VeQItemTableModel { - uids: ["mqtt/dcdc"] - flags: VeQItemTableModel.AddChildren | VeQItemTableModel.AddNonLeaves | VeQItemTableModel.DontAddItem - } - - delegate: DcLoad { - serviceUid: model.uid - } - } -} diff --git a/data/mqtt/MqttDataManager.qml b/data/mqtt/MqttDataManager.qml index 7521a69f7..0abe83826 100644 --- a/data/mqtt/MqttDataManager.qml +++ b/data/mqtt/MqttDataManager.qml @@ -11,7 +11,6 @@ QtObject { id: root property var dcInputs: DcInputsImpl { } - property var dcLoads: DcLoadsImpl { } property var environmentInputs: EnvironmentInputsImpl { } property var ess: EssImpl { } property var evChargers: EvChargersImpl { } diff --git a/pages/OverviewPage.qml b/pages/OverviewPage.qml index 8732701ec..0491f64a1 100644 --- a/pages/OverviewPage.qml +++ b/pages/OverviewPage.qml @@ -41,7 +41,7 @@ SwipeViewPage { + (Global.acInputs.input2?.operational ? 1 : 0) + (Global.system.showInputLoads ? 1 : 0) + (Global.system.hasAcOutSystem ? 1 : 0) - + (Global.dcLoads.model.count === 0 || isNaN(Global.system.dc.power) ? 0 : 1) + + (Global.allDevicesModel.combinedDcLoadsModel.count === 0 || isNaN(Global.system.dc.power) ? 0 : 1) + (Global.solarChargers.model.count === 0 ? 0 : 1) + (Global.evChargers.model.count === 0 ? 0 : 1) + Global.evChargers.acInputPositionCount @@ -340,7 +340,7 @@ SwipeViewPage { } else { essentialLoadsWidget.size = VenusOS.OverviewWidget_Size_Zero } - if (Global.dcLoads.model.count > 0 || !isNaN(Global.system.dc.power)) { + if (Global.allDevicesModel.combinedDcLoadsModel.count > 0 || !isNaN(Global.system.dc.power)) { widgets.push(_createWidget(VenusOS.OverviewWidget_Type_DcLoads)) } _rightWidgets = widgets