Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions src/components/configuration/BlueOSAlertsConfig.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<template>
<ExpansiblePanel :is-expanded="true" no-top-divider>
<template #title>BlueOS monitoring alerts:</template>
<template #info>
Configure alerts for BlueOS system monitoring including CPU temperature and usage thresholds. <br />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Configure alerts for BlueOS system monitoring including CPU temperature and usage thresholds. <br />
Configure alerts for BlueOS system monitoring, including CPU temperature and usage thresholds. <br />

Set custom thresholds and minimum intervals between alerts to prevent spam.
</template>
<template #content>
<div class="ml-4 mb-4 mr-4">
<table class="w-full">
<thead>
<tr>
<th class="text-center text-sm font-medium text-slate-200 pb-3 w-12"></th>
<th class="text-center text-sm font-medium text-slate-200 pb-3 w-40">Alert Type</th>
<th class="text-center text-sm font-medium text-slate-200 pb-3 w-32">Threshold</th>
<th class="text-center text-sm font-medium text-slate-200 pb-3 w-32">Min Interval (s)</th>
<th class="text-center text-sm font-medium text-slate-200 pb-3 w-24">Level</th>
</tr>
</thead>
<tbody>
<!-- CPU Temperature Configuration -->
<tr class="border-b border-slate-600">
<td class="py-3 text-center">
<input
v-model="vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].enabled"
type="checkbox"
class="w-4 h-4"
/>
Comment on lines +24 to +28
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use the v-checkbox as on the elements below to keep UI consistency

</td>
<td class="py-3 text-center">
<span class="text-sm font-medium">CPU Temperature</span>
</td>
<td class="py-3 text-center">
<div class="flex items-center justify-center gap-2">
<input
v-model.number="vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].threshold"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure if this is the correct approach to do that, the system-information page has the /platform endpoint where it returns platform specific data, in this case, for the raspberry, it returns the events such as thermal throttle, under voltage, and others.
For a complete list, check here:
https://github.com/patrickelectric/linux2rest/blob/master/src/features/platform/raspberry.rs#L10

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I like the idea of implementing the undervoltage and throttling warns as well.

About allowing customization of the threshold for those that have continuous values, it is needed since each platform behaves differently, and the user will know better than anyone what is a safe level for their mission and when they need to be warned to take action.

type="number"
class="px-2 py-1 rounded-sm bg-[#FFFFFF22] w-16 text-sm text-center"
:disabled="!vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].enabled"
/>
<span class="text-xs text-slate-300">°C</span>
</div>
</td>
<td class="py-3 text-center">
<input
v-model.number="cpuTemperatureIntervalSeconds"
type="number"
class="px-2 py-1 rounded-sm bg-[#FFFFFF22] w-16 text-sm text-center"
:disabled="!vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].enabled"
/>
</td>
<td class="py-3 text-center">
<select
v-model="vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].level"
class="px-2 py-1 rounded-sm bg-[#FFFFFF22] text-sm w-24"
:disabled="!vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].enabled"
>
<option value="success">Success</option>
<option value="info">Info</option>
<option value="warning">Warning</option>
<option value="error">Error</option>
<option value="critical">Critical</option>
</select>
Comment on lines +53 to +63
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use v-select on dark mode as a standard to keep UI consistency

</td>
</tr>
<!-- CPU Usage Configuration -->
<tr>
<td class="py-3 text-center">
<input
v-model="vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].enabled"
type="checkbox"
class="w-4 h-4"
/>
</td>
<td class="py-3 text-center">
<span class="text-sm font-medium">CPU Usage</span>
</td>
<td class="py-3 text-center">
<div class="flex items-center justify-center gap-2">
<input
v-model.number="vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].threshold"
type="number"
class="px-2 py-1 rounded-sm bg-[#FFFFFF22] w-16 text-sm text-center"
:disabled="!vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].enabled"
/>
<span class="text-xs text-slate-300">%</span>
</div>
</td>
<td class="py-3 text-center">
<input
v-model.number="cpuUsageIntervalSeconds"
type="number"
class="px-2 py-1 rounded-sm bg-[#FFFFFF22] w-16 text-sm text-center"
:disabled="!vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].enabled"
/>
</td>
<td class="py-3 text-center">
<select
v-model="vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].level"
class="px-2 py-1 rounded-sm bg-[#FFFFFF22] text-sm w-24"
:disabled="!vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].enabled"
>
<option value="success">Success</option>
<option value="info">Info</option>
<option value="warning">Warning</option>
<option value="error">Error</option>
<option value="critical">Critical</option>
</select>
</td>
</tr>
</tbody>
</table>
</div>
</template>
</ExpansiblePanel>
</template>

<script setup lang="ts">
import { computed } from 'vue'

import ExpansiblePanel from '@/components/ExpansiblePanel.vue'
import { useVehicleAlerterStore } from '@/stores/vehicleAlerter'

const vehicleAlerterStore = useVehicleAlerterStore()

// Convert between seconds (UI) and milliseconds (store)
const cpuTemperatureIntervalSeconds = computed({
get: () => vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].minInterval / 1000,
set: (value: number) => {
vehicleAlerterStore.blueOsAlertsConfig['cpu-temperature'].minInterval = value * 1000
},
})

const cpuUsageIntervalSeconds = computed({
get: () => vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].minInterval / 1000,
set: (value: number) => {
vehicleAlerterStore.blueOsAlertsConfig['cpu-usage'].minInterval = value * 1000
},
})
</script>
21 changes: 21 additions & 0 deletions src/libs/blueos/definitions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Register BlueOS variables in the data lake
export const blueOsVariables = {
cpuTemp: {
id: 'blueos/cpu/tempC',
name: 'BlueOS CPU Temperature',
type: 'number',
description: 'The average temperature of the BlueOS CPU cores in °C.',
},
cpuUsageAverage: {
id: 'blueos/cpu/usageAverage',
name: 'BlueOS CPU Usage',
type: 'number',
description: 'The average usage of the BlueOS CPU cores in %.',
},
cpuFrequencyAverage: {
id: 'blueos/cpu/frequencyAverage',
name: 'BlueOS CPU Frequency',
type: 'number',
description: 'The average frequency of the BlueOS CPU cores in Hz.',
},
}
12 changes: 1 addition & 11 deletions src/stores/mainVehicle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getVehicleName,
setKeyDataOnCockpitVehicleStorage,
} from '@/libs/blueos'
import { blueOsVariables } from '@/libs/blueos/definitions'
import * as Connection from '@/libs/connection/connection'
import { ConnectionManager } from '@/libs/connection/connection-manager'
import type { Package } from '@/libs/connection/m2r/messages/mavlink2rest'
Expand Down Expand Up @@ -587,17 +588,6 @@ export const useMainVehicleStore = defineStore('main-vehicle', () => {

updateVehicleId()

// Register BlueOS variables in the data lake
const blueOsVariables = {
cpuTemp: { id: 'blueos/cpu/tempC', name: 'CPU Temperature', type: 'number' },
cpuUsageAverage: { id: 'blueos/cpu/usageAverage', name: 'BlueOS CPU Usage (average)', type: 'number' },
cpuFrequencyAverage: {
id: 'blueos/cpu/frequencyAverage',
name: 'BlueOS CPU Frequency (average)',
type: 'number',
},
}

const cpuUsageVariableId = (cpuName: string): string => `blueos/${cpuName}/usage`
const cpuFrequencyVariableId = (cpuName: string): string => `blueos/${cpuName}/frequency`

Expand Down
37 changes: 37 additions & 0 deletions src/stores/vehicleAlerter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { defineStore } from 'pinia'
import { watch } from 'vue'

import { useBlueOsStorage } from '@/composables/settingsSyncer'
import { listenDataLakeVariable } from '@/libs/actions/data-lake'
import { blueOsVariables } from '@/libs/blueos/definitions'
import { useAlertStore } from '@/stores/alert'
import { useMainVehicleStore } from '@/stores/mainVehicle'
import { Alert, AlertLevel } from '@/types/alert'
Expand Down Expand Up @@ -35,4 +38,38 @@ export const useVehicleAlerterStore = defineStore('vehicle-alerter', () => {
alertStore.pushAlert(new Alert(alertLevel, `Vehicle ${alertMessage}`))
}
)

// BlueOS alerts
const blueOsAlertsConfig = useBlueOsStorage('cockpit-blueos-alerts-config', {
'cpu-temperature': { enabled: true, minInterval: 60000, threshold: 85, level: AlertLevel.Warning },
'cpu-usage': { enabled: true, minInterval: 60000, threshold: 80, level: AlertLevel.Warning },
})

// BlueOS CPU Temperature Alert
let lastBlueOsCpuTemperatureAlertTimestamp = 0
listenDataLakeVariable(blueOsVariables.cpuTemp.id, (data) => {
const tempConfig = blueOsAlertsConfig.value['cpu-temperature']
const thresholdExceeded = Number(data) > tempConfig.threshold
const minIntervalReached = Date.now() - lastBlueOsCpuTemperatureAlertTimestamp >= tempConfig.minInterval
if (tempConfig.enabled && thresholdExceeded && minIntervalReached) {
alertStore.pushAlert(new Alert(tempConfig.level, `BlueOS CPU Temperature threshold exceeded: ${data} °C`))
lastBlueOsCpuTemperatureAlertTimestamp = Date.now()
}
})

// BlueOS CPU Usage Alert
let lastBlueOsCpuUsageAlertTimestamp = 0
listenDataLakeVariable(blueOsVariables.cpuUsageAverage.id, (data) => {
const usageConfig = blueOsAlertsConfig.value['cpu-usage']
const thresholdExceeded = Number(data) > usageConfig.threshold
const minIntervalReached = Date.now() - lastBlueOsCpuUsageAlertTimestamp >= usageConfig.minInterval
if (usageConfig.enabled && thresholdExceeded && minIntervalReached) {
alertStore.pushAlert(new Alert(usageConfig.level, `BlueOS CPU Usage threshold exceeded: ${data} %`))
lastBlueOsCpuUsageAlertTimestamp = Date.now()
}
})

return {
blueOsAlertsConfig,
}
})
38 changes: 20 additions & 18 deletions src/views/ConfigurationAlertsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,29 @@
class="flex flex-col justify-around align-start ml-5 max-h-[85vh] overflow-y-auto"
:class="interfaceStore.isOnSmallScreen ? 'max-w-[70vw]' : 'max-w-[40vw]'"
>
<!-- BlueOS Alerts Configuration -->
<BlueOSAlertsConfig />
<ExpansiblePanel :is-expanded="!interfaceStore.isOnPhoneScreen" no-top-divider>
<template #title>Voice alerts:</template>
<template #title>Text to speech:</template>
<template #info>
Enable voice alerts to receive audible notifications about system and vehicle activities. <br />
Select specific alert levels to customize which types of notifications you receive.
Enable text to speech to receive audible notifications of the system alerts. <br />
Select specific alert levels to customize which ones will be spoken.
</template>
<template #content>
<v-switch
v-model="alertStore.enableVoiceAlerts"
label="Enable voice alerts"
color="white"
class="-mt-4 -mb-2 ml-3"
/>
<span class="text-sm font-medium mt-4">Alert levels:</span>
<div class="flex flex-row items-center mb-4 ml-2 gap-x-16">
<v-switch v-model="alertStore.enableVoiceAlerts" label="Enable" color="white" hide-details />
<div class="flex flex-row items-center">
<span class="text-sm font-medium">Voice:</span>
<Dropdown
v-model="alertStore.selectedAlertSpeechVoiceName"
:options="alertStore.availableAlertSpeechVoiceNames"
name-key="name"
value-key="value"
class="max-w-[350px] ml-3"
/>
</div>
</div>
<span class="text-sm font-medium mt-4">Levels to speak:</span>
<div class="flex flex-wrap items-center justify-start">
<div
v-for="enabledLevel in alertStore.enabledAlertLevels"
Expand All @@ -34,14 +43,6 @@
/>
</div>
</div>
<span class="text-sm font-medium mt-4">Alert voice:</span>
<Dropdown
v-model="alertStore.selectedAlertSpeechVoiceName"
:options="alertStore.availableAlertSpeechVoiceNames"
name-key="name"
value-key="value"
class="max-w-[350px] mt-2 mb-4 ml-2"
/>
</template>
</ExpansiblePanel>
<!-- Armed Menu Warning Toggle -->
Expand All @@ -61,6 +62,7 @@
<script setup lang="ts">
import { capitalize } from 'vue'

import BlueOSAlertsConfig from '@/components/configuration/BlueOSAlertsConfig.vue'
import Dropdown from '@/components/Dropdown.vue'
import ExpansiblePanel from '@/components/ExpansiblePanel.vue'
import { useAlertStore } from '@/stores/alert'
Expand Down
Loading