5import QGroundControl.Controls
6import QGroundControl.FactControls
8//-------------------------------------------------------------------------
12 objectName: "toolbar_batteryIndicator"
13 anchors.top: parent.top
14 anchors.bottom: parent.bottom
15 width: batteryIndicatorRow.width
17 property bool showIndicator: _activeVehicle && _activeVehicle.batteries.count > 0
18 property bool waitForParameters: false
19 property Component expandedPageComponent
21 property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
22 property var _batterySettings: QGroundControl.settingsManager.batteryIndicatorSettings
23 property Fact _indicatorDisplay: _batterySettings.valueDisplay
24 property bool _showPercentage: _indicatorDisplay.rawValue === 0
25 property bool _showVoltage: _indicatorDisplay.rawValue === 1
26 property bool _showBoth: _indicatorDisplay.rawValue === 2
27 property int _lowestBatteryId: -1 // -1: show all batteries, otherwise show only battery with this id
29 // Properties to hold the thresholds
30 property int threshold1: _batterySettings.threshold1.rawValue
31 property int threshold2: _batterySettings.threshold2.rawValue
33 function _recalcLowestBatteryIdFromVoltage() {
35 // If there is only one battery then it is the lowest
36 if (_activeVehicle.batteries.count === 1) {
37 _lowestBatteryId = _activeVehicle.batteries.get(0).id.rawValue
41 // If we have valid voltage for all batteries we use that to determine lowest battery
42 let allHaveVoltage = true
43 for (var i = 0; i < _activeVehicle.batteries.count; i++) {
44 let battery = _activeVehicle.batteries.get(i)
45 if (isNaN(battery.voltage.rawValue)) {
46 allHaveVoltage = false
51 let lowestBattery = _activeVehicle.batteries.get(0)
52 let lowestBatteryId = lowestBattery.id.rawValue
53 for (var i = 1; i < _activeVehicle.batteries.count; i++) {
54 let battery = _activeVehicle.batteries.get(i)
55 if (battery.voltage.rawValue < lowestBattery.voltage.rawValue) {
56 lowestBattery = battery
57 lowestBatteryId = battery.id.rawValue
60 _lowestBatteryId = lowestBatteryId
65 // Couldn't determine lowest battery, show all
69 function _recalcLowestBatteryIdFromPercentage() {
71 // If there is only one battery then it is the lowest
72 if (_activeVehicle.batteries.count === 1) {
73 _lowestBatteryId = _activeVehicle.batteries.get(0).id.rawValue
77 // If we have valid percentage for all batteries we use that to determine lowest battery
78 let allHavePercentage = true
79 for (var i = 0; i < _activeVehicle.batteries.count; i++) {
80 let battery = _activeVehicle.batteries.get(i)
81 if (isNaN(battery.percentRemaining.rawValue)) {
82 allHavePercentage = false
86 if (allHavePercentage) {
87 let lowestBattery = _activeVehicle.batteries.get(0)
88 let lowestBatteryId = lowestBattery.id.rawValue
89 for (var i = 1; i < _activeVehicle.batteries.count; i++) {
90 let battery = _activeVehicle.batteries.get(i)
91 if (battery.percentRemaining.rawValue < lowestBattery.percentRemaining.rawValue) {
92 lowestBattery = battery
93 lowestBatteryId = battery.id.rawValue
96 _lowestBatteryId = lowestBatteryId
101 // Couldn't determine lowest battery, show all
102 _lowestBatteryId = -1
105 function _recalcLowestBatteryIdFromChargeState() {
106 if (_activeVehicle) {
107 // If there is only one battery then it is the lowest
108 if (_activeVehicle.batteries.count === 1) {
109 _lowestBatteryId = _activeVehicle.batteries.get(0).id.rawValue
113 // If we have valid chargeState for all batteries we use that to determine lowest battery
114 let allHaveChargeState = true
115 for (var i = 0; i < _activeVehicle.batteries.count; i++) {
116 let battery = _activeVehicle.batteries.get(i)
117 if (battery.chargeState.rawValue === MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_UNDEFINED) {
118 allHaveChargeState = false
122 if (allHaveChargeState) {
123 let lowestBattery = _activeVehicle.batteries.get(0)
124 let lowestBatteryId = lowestBattery.id.rawValue
125 for (var i = 1; i < _activeVehicle.batteries.count; i++) {
126 let battery = _activeVehicle.batteries.get(i)
127 if (battery.chargeState.rawValue > lowestBattery.chargeState.rawValue) {
128 lowestBattery = battery
129 lowestBatteryId = battery.id.rawValue
132 _lowestBatteryId = lowestBatteryId
137 // Couldn't determine lowest battery, show all
138 _lowestBatteryId = -1
141 function _recalcLowestBatteryId() {
142 if (!_activeVehicle || _activeVehicle.batteries.count === 0) {
143 _lowestBatteryId = -1
146 if (_batterySettings.valueDisplay.rawValue === 0) {
147 // User wants percentage display so use that if available
148 _recalcLowestBatteryIdFromPercentage()
149 } else if (_batterySettings.valueDisplay.rawValue === 1) {
150 // User wants voltage display so use that if available
151 _recalcLowestBatteryIdFromVoltage()
153 // If we still dont have a lowest battery id then try charge state
154 if (_lowestBatteryId === -1) {
155 _recalcLowestBatteryIdFromChargeState()
159 Component.onCompleted: _recalcLowestBatteryId()
162 target: _activeVehicle ? _activeVehicle.batteries : null
163 function onCountChanged() {_recalcLowestBatteryId() }
166 QGCPalette { id: qgcPal }
169 id: batteryIndicatorRow
170 anchors.top: parent.top
171 anchors.bottom: parent.bottom
172 spacing: ScreenTools.defaultFontPixelWidth / 2
175 model: _activeVehicle ? _activeVehicle.batteries : 0
178 Layout.fillHeight: true
179 sourceComponent: batteryVisual
180 visible: control._lowestBatteryId === -1 || object.id.rawValue === control._lowestBatteryId || !control._batterySettings.consolidateMultipleBatteries.rawValue
182 property var battery: object
189 onClicked: mainWindow.showIndicatorDrawer(batteryPopup, control)
196 showExpand: expandedComponent ? true : false
197 waitForParameters: false
198 expandedComponentWaitForParameters: true
199 contentComponent: batteryContentComponent
200 expandedComponent: batteryExpandedComponent
208 Layout.fillHeight: true
209 spacing: ScreenTools.defaultFontPixelWidth / 4
211 function getBatteryColor() {
212 switch (battery.chargeState.rawValue) {
213 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_OK:
214 if (!isNaN(battery.percentRemaining.rawValue)) {
215 if (battery.percentRemaining.rawValue > threshold1) {
216 return qgcPal.colorGreen
217 } else if (battery.percentRemaining.rawValue > threshold2) {
218 return qgcPal.colorYellowGreen
220 return qgcPal.colorYellow
225 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_LOW:
226 return qgcPal.colorOrange
227 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_CRITICAL:
228 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_EMERGENCY:
229 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_FAILED:
230 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_UNHEALTHY:
231 return qgcPal.colorRed
237 function getBatterySvgSource() {
238 switch (battery.chargeState.rawValue) {
239 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_OK:
240 if (!isNaN(battery.percentRemaining.rawValue)) {
241 if (battery.percentRemaining.rawValue > threshold1) {
242 return "/qmlimages/BatteryGreen.svg"
243 } else if (battery.percentRemaining.rawValue > threshold2) {
244 return "/qmlimages/BatteryYellowGreen.svg"
246 return "/qmlimages/BatteryYellow.svg"
249 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_LOW:
250 return "/qmlimages/BatteryOrange.svg" // Low with orange svg
251 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_CRITICAL:
252 return "/qmlimages/BatteryCritical.svg" // Critical with red svg
253 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_EMERGENCY:
254 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_FAILED:
255 case MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_UNHEALTHY:
256 return "/qmlimages/BatteryEMERGENCY.svg" // Exclamation mark
258 return "/qmlimages/Battery.svg" // Fallback if percentage is unavailable
262 function getBatteryPercentageText() {
263 if (!isNaN(battery.percentRemaining.rawValue)) {
264 if (battery.percentRemaining.rawValue > 98.9) {
267 return battery.percentRemaining.valueString + battery.percentRemaining.units
269 } else if (!isNaN(battery.voltage.rawValue)) {
270 return battery.voltage.valueString + battery.voltage.units
271 } else if (battery.chargeState.rawValue !== MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_UNDEFINED) {
272 return battery.chargeState.enumStringValue
277 function getBatteryVoltageText() {
278 if (!isNaN(battery.voltage.rawValue)) {
279 return battery.voltage.valueString + battery.voltage.units
280 } else if (battery.chargeState.rawValue !== MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_UNDEFINED) {
281 return battery.chargeState.enumStringValue
287 id: debounceRecalcTimer
292 control._recalcLowestBatteryId()
296 target: battery.percentRemaining
297 function onRawValueChanged() {
298 debounceRecalcTimer.restart()
302 target: battery.voltage
303 function onRawValueChanged() {
304 debounceRecalcTimer.restart()
308 target: battery.chargeState
309 function onRawValueChanged() {
310 debounceRecalcTimer.restart()
315 anchors.top: parent.top
316 anchors.bottom: parent.bottom
318 sourceSize.width: width
319 source: getBatterySvgSource()
320 fillMode: Image.PreserveAspectFit
321 color: getBatteryColor()
325 id: batteryInfoColumn
326 anchors.top: parent.top
327 anchors.bottom: parent.bottom
331 Layout.alignment: Qt.AlignHCenter
332 verticalAlignment: Text.AlignVCenter
334 text: getBatteryPercentageText()
335 font.pointSize: _showBoth ? ScreenTools.defaultFontPointSize : ScreenTools.mediumFontPointSize
336 visible: _showBoth || _showPercentage
340 Layout.alignment: Qt.AlignHCenter
341 font.pointSize: _showBoth ? ScreenTools.defaultFontPointSize : ScreenTools.mediumFontPointSize
343 text: getBatteryVoltageText()
344 visible: _showBoth || _showVoltage
351 id: batteryContentComponent
354 spacing: ScreenTools.defaultFontPixelHeight / 2
357 id: batteryValuesAvailableComponent
360 property bool functionAvailable: battery.function.rawValue !== MAVLinkEnums.MAV_BATTERY_FUNCTION_UNKNOWN
361 property bool showFunction: functionAvailable && battery.function.rawValue != MAVLinkEnums.MAV_BATTERY_FUNCTION_ALL
362 property bool temperatureAvailable: !isNaN(battery.temperature.rawValue)
363 property bool currentAvailable: !isNaN(battery.current.rawValue)
364 property bool mahConsumedAvailable: !isNaN(battery.mahConsumed.rawValue)
365 property bool timeRemainingAvailable: !isNaN(battery.timeRemaining.rawValue)
366 property bool percentRemainingAvailable: !isNaN(battery.percentRemaining.rawValue)
367 property bool chargeStateAvailable: battery.chargeState.rawValue !== MAVLinkEnums.MAV_BATTERY_CHARGE_STATE_UNDEFINED
372 model: _activeVehicle ? _activeVehicle.batteries : 0
374 SettingsGroupLayout {
375 heading: qsTr("Battery %1").arg(_activeVehicle.batteries.length === 1 ? qsTr("Status") : object.id.rawValue)
379 property var batteryValuesAvailable: batteryValuesAvailableLoader.item
382 id: batteryValuesAvailableLoader
383 sourceComponent: batteryValuesAvailableComponent
385 property var battery: object
389 label: qsTr("Charge State")
390 labelText: object.chargeState.enumStringValue
391 visible: batteryValuesAvailable.chargeStateAvailable
395 label: qsTr("Remaining")
396 labelText: object.timeRemainingStr.value
397 visible: batteryValuesAvailable.timeRemainingAvailable
401 label: qsTr("Remaining")
402 labelText: object.percentRemaining.valueString + " " + object.percentRemaining.units
403 visible: batteryValuesAvailable.percentRemainingAvailable
407 label: qsTr("Voltage")
408 labelText: object.voltage.valueString + " " + object.voltage.units
412 label: qsTr("Consumed")
413 labelText: object.mahConsumed.valueString + " " + object.mahConsumed.units
414 visible: batteryValuesAvailable.mahConsumedAvailable
418 label: qsTr("Temperature")
419 labelText: object.temperature.valueString + " " + object.temperature.units
420 visible: batteryValuesAvailable.temperatureAvailable
424 label: qsTr("Function")
425 labelText: object.function.enumStringValue
426 visible: batteryValuesAvailable.showFunction
434 id: batteryExpandedComponent
437 spacing: ScreenTools.defaultFontPixelHeight / 2
439 property real batteryIconHeight: ScreenTools.defaultFontPixelWidth * 3
441 FactPanelController { id: controller }
443 SettingsGroupLayout {
444 heading: qsTr("Battery Display")
445 Layout.fillWidth: true
448 Layout.fillWidth: true
449 fact: _batterySettings.consolidateMultipleBatteries
450 text: qsTr("Only show battery with lowest charge")
451 visible: fact.userVisible
454 LabelledFactComboBox {
456 fact: _batterySettings.valueDisplay
457 visible: fact.userVisible
461 QGCLabel { text: qsTr("Coloring") }
464 spacing: ScreenTools.defaultFontPixelWidth
468 spacing: ScreenTools.defaultFontPixelWidth * 0.05 // Tighter spacing for icon and label
470 source: "/qmlimages/BatteryGreen.svg"
472 height: batteryIconHeight
473 fillMode: Image.PreserveAspectFit
474 color: qgcPal.colorGreen
476 QGCLabel { text: qsTr("100%") }
481 spacing: ScreenTools.defaultFontPixelWidth * 0.05 // Tighter spacing for icon and field
483 source: "/qmlimages/BatteryYellowGreen.svg"
485 height: batteryIconHeight
486 fillMode: Image.PreserveAspectFit
487 color: qgcPal.colorYellowGreen
491 fact: _batterySettings.threshold1
492 implicitWidth: ScreenTools.defaultFontPixelWidth * 6
493 height: ScreenTools.defaultFontPixelHeight * 1.5
494 enabled: fact.userVisible
496 // Validate and set the new threshold value
497 _batterySettings.setThreshold1(parseInt(text));
504 spacing: ScreenTools.defaultFontPixelWidth * 0.05 // Tighter spacing for icon and field
506 source: "/qmlimages/BatteryYellow.svg"
508 height: batteryIconHeight
509 fillMode: Image.PreserveAspectFit
510 color: qgcPal.colorYellow
513 fact: _batterySettings.threshold2
514 implicitWidth: ScreenTools.defaultFontPixelWidth * 6
515 height: ScreenTools.defaultFontPixelHeight * 1.5
516 enabled: fact.userVisible
518 // Validate and set the new threshold value
519 _batterySettings.setThreshold2(parseInt(text));
526 spacing: ScreenTools.defaultFontPixelWidth * 0.05 // Tighter spacing for icon and label
528 source: "/qmlimages/BatteryOrange.svg"
530 height: batteryIconHeight
531 fillMode: Image.PreserveAspectFit
532 color: qgcPal.colorOrange
534 QGCLabel { text: qsTr("Low") }
539 spacing: ScreenTools.defaultFontPixelWidth * 0.05 // Tighter spacing for icon and label
541 source: "/qmlimages/BatteryCritical.svg"
543 height: batteryIconHeight
544 fillMode: Image.PreserveAspectFit
545 color: qgcPal.colorRed
547 QGCLabel { text: qsTr("Critical") }
554 Layout.fillWidth: true
555 source: _activeVehicle.expandedToolbarIndicatorSource("Battery")
558 SettingsGroupLayout {
559 visible: _activeVehicle.autopilotPlugin.knownVehicleComponentAvailable(AutoPilotPlugin.KnownPowerVehicleComponent) &&
560 QGroundControl.corePlugin.showAdvancedUI
563 label: qsTr("Vehicle Power")
564 buttonText: qsTr("Configure")
567 mainWindow.showKnownVehicleComponentConfigPage(AutoPilotPlugin.KnownPowerVehicleComponent)
568 mainWindow.closeIndicatorDrawer()