Add device-type metrics and improve sensor capability detection

- Show device-specific metrics (e.g. brightness, setpoint) for lighting,
HVAC, and security sensors when no standard monitoring is present - Add
helper to infer monitoring capabilities from sensor type or name -
Animate sensor cards when recently updated - Remove debug console logs
from stores - Normalize sensor data structure and capability defaults in
store
This commit is contained in:
rafaeldpsilva
2025-09-30 15:07:50 +01:00
parent 3681890ec5
commit 5cb87ef5c5
4 changed files with 228 additions and 59 deletions

View File

@@ -13,9 +13,12 @@
</div>
</div>
<div class="flex items-center gap-2">
<div
class="w-2 h-2 rounded-full"
:class="getSensorStatusColor(sensor.status)"
<div
class="w-2 h-2 rounded-full transition-all duration-300"
:class="[
getSensorStatusColor(sensor.status),
isRecentlyUpdated ? 'animate-pulse shadow-lg shadow-green-400/50' : ''
]"
></div>
<span class="text-xs text-gray-500 capitalize">{{ sensor.status }}</span>
</div>
@@ -163,6 +166,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useEnergyStore } from '@/stores/energy'
import { useSensorStore } from '@/stores/sensor'
const props = defineProps<{
sensor: any
@@ -176,6 +180,7 @@ const emit = defineEmits<{
}>()
const energyStore = useEnergyStore()
const sensorStore = useSensorStore()
const getSensorValues = (sensor: any) => {
const values = []
@@ -184,10 +189,12 @@ const getSensorValues = (sensor: any) => {
const latestReading = energyStore.latestReadings.get(sensor.id)
console.log(`[Detailed] Getting values for sensor ${sensor.id}, found reading:`, latestReading)
console.log('[Detailed] Available readings:', Array.from(energyStore.latestReadings.keys()))
if (sensor.capabilities.monitoring.includes('energy')) {
const energyValue = latestReading?.energy?.value?.toFixed(2) ||
energyStore.latestMessage?.value?.toFixed(2) ||
console.log(`[Detailed] Sensor capabilities:`, sensor.capabilities?.monitoring)
// Only show energy if the sensor actually monitors energy
if (sensor.capabilities?.monitoring?.includes('energy')) {
const energyValue = latestReading?.energy?.value?.toFixed(2) ||
energyStore.latestMessage?.value?.toFixed(2) ||
'0.00'
values.push({
type: 'energy',
@@ -196,8 +203,9 @@ const getSensorValues = (sensor: any) => {
unit: latestReading?.energy?.unit || energyStore.latestMessage?.unit || 'kWh'
})
}
if (sensor.capabilities.monitoring.includes('co2')) {
// Only show CO2 if the sensor monitors CO2
if (sensor.capabilities?.monitoring?.includes('co2')) {
const co2Value = latestReading?.co2?.value || Math.floor(Math.random() * 800 + 350)
values.push({
type: 'co2',
@@ -206,9 +214,10 @@ const getSensorValues = (sensor: any) => {
unit: latestReading?.co2?.unit || 'ppm'
})
}
if (sensor.capabilities.monitoring.includes('temperature')) {
const tempValue = latestReading?.temperature?.value?.toFixed(1) ||
// Only show temperature if the sensor monitors temperature
if (sensor.capabilities?.monitoring?.includes('temperature')) {
const tempValue = latestReading?.temperature?.value?.toFixed(1) ||
(Math.random() * 8 + 18).toFixed(1)
values.push({
type: 'temperature',
@@ -217,8 +226,9 @@ const getSensorValues = (sensor: any) => {
unit: latestReading?.temperature?.unit || '°C'
})
}
if (sensor.capabilities.monitoring.includes('humidity')) {
// Only show humidity if the sensor monitors humidity
if (sensor.capabilities?.monitoring?.includes('humidity')) {
values.push({
type: 'humidity',
label: 'Humidity',
@@ -226,8 +236,9 @@ const getSensorValues = (sensor: any) => {
unit: '%'
})
}
if (sensor.capabilities.monitoring.includes('motion')) {
// Only show motion if the sensor monitors motion
if (sensor.capabilities?.monitoring?.includes('motion')) {
values.push({
type: 'motion',
label: 'Motion Status',
@@ -235,21 +246,83 @@ const getSensorValues = (sensor: any) => {
unit: ''
})
}
// Add device uptime
// Show device-specific metrics based on sensor type if no specific monitoring capabilities
if (values.length === 0 && sensor.type) {
switch (sensor.type) {
case 'lighting':
values.push({
type: 'brightness',
label: 'Brightness Level',
value: Math.floor(Math.random() * 100),
unit: '%'
})
values.push({
type: 'power',
label: 'Power Draw',
value: Math.floor(Math.random() * 50 + 5),
unit: 'W'
})
break
case 'hvac':
values.push({
type: 'setpoint',
label: 'Target Temperature',
value: (Math.random() * 6 + 18).toFixed(1),
unit: '°C'
})
values.push({
type: 'mode',
label: 'Operating Mode',
value: ['Heat', 'Cool', 'Auto', 'Fan'][Math.floor(Math.random() * 4)],
unit: ''
})
break
case 'security':
values.push({
type: 'status',
label: 'Security Status',
value: Math.random() > 0.8 ? 'Alert' : 'Normal',
unit: ''
})
values.push({
type: 'armed',
label: 'System Armed',
value: Math.random() > 0.5 ? 'Yes' : 'No',
unit: ''
})
break
default:
// Generic fallback for unknown sensor types
values.push({
type: 'status',
label: 'Device Status',
value: sensor.status === 'online' ? 'Active' : 'Inactive',
unit: ''
})
}
}
// Always add device uptime for detailed view
values.push({
type: 'uptime',
label: 'Uptime',
value: Math.floor(Math.random() * 30 + 1),
unit: 'days'
})
return values
}
// Reactive sensor values that update automatically
const sensorValues = computed(() => getSensorValues(props.sensor))
// Check if sensor was recently updated for pulsing animation
const isRecentlyUpdated = computed(() => {
return sensorStore.recentlyUpdatedSensors.has(props.sensor.id) ||
sensorStore.recentlyUpdatedSensors.has(props.sensor.sensor_id)
})
const getDefaultTags = (sensor: any) => {
const tags = [sensor.type]

View File

@@ -13,7 +13,10 @@
</div>
<!-- Status Indicator -->
<div class="flex items-center gap-1">
<div class="w-2 h-2 rounded-full" :class="getSensorStatusColor(sensor.status)"></div>
<div
class="w-2 h-2 rounded-full transition-all duration-300"
:class="[getSensorStatusColor(sensor.status)]"
></div>
<span class="text-xs text-gray-500 capitalize">{{ sensor.status }}</span>
</div>
</div>
@@ -21,7 +24,12 @@
<!-- Sensor Values -->
<div class="mb-3">
<div class="grid grid-cols-2 gap-2 text-xs">
<div v-for="metric in sensorValues" :key="metric.type" class="bg-gray-50 rounded p-2">
<div
v-for="metric in sensorValues"
:key="metric.type"
class="bg-gray-50 rounded p-2"
:class="[isRecentlyUpdated ? 'animate-pulse bg-gray-400/50' : '']"
>
<div class="text-gray-600 mb-1">{{ metric.label }}</div>
<div class="font-medium text-gray-900">
{{ metric.value }} <span class="text-gray-500">{{ metric.unit }}</span>
@@ -85,8 +93,10 @@ const getSensorValues = (sensor: any) => {
const latestReading = energyStore.latestReadings.get(sensor.sensor_id)
console.log(`Getting values for sensor ${sensor.sensor_id}, found reading:`, latestReading)
console.log(`Sensor capabilities:`, sensor.capabilities?.monitoring)
if (sensor.capabilities.monitoring.includes('energy')) {
// Only show energy if the sensor actually monitors energy
if (sensor.capabilities?.monitoring?.includes('energy')) {
const energyValue =
latestReading?.energy?.value?.toFixed(2) ||
energyStore.latestMessage?.value?.toFixed(2) ||
@@ -99,7 +109,8 @@ const getSensorValues = (sensor: any) => {
})
}
if (sensor.capabilities.monitoring.includes('co2')) {
// Only show CO2 if the sensor monitors CO2
if (sensor.capabilities?.monitoring?.includes('co2')) {
const co2Value = latestReading?.co2?.value || Math.floor(Math.random() * 800 + 350)
values.push({
type: 'co2',
@@ -109,7 +120,8 @@ const getSensorValues = (sensor: any) => {
})
}
if (sensor.capabilities.monitoring.includes('temperature')) {
// Only show temperature if the sensor monitors temperature
if (sensor.capabilities?.monitoring?.includes('temperature')) {
const tempValue =
latestReading?.temperature?.value?.toFixed(1) || (Math.random() * 8 + 18).toFixed(1)
values.push({
@@ -120,8 +132,8 @@ const getSensorValues = (sensor: any) => {
})
}
if (sensor.capabilities.monitoring.includes('humidity')) {
// Fallback to mock data for humidity as it's not in current data model
// Only show humidity if the sensor monitors humidity
if (sensor.capabilities?.monitoring?.includes('humidity')) {
values.push({
type: 'humidity',
label: 'Humidity',
@@ -130,7 +142,8 @@ const getSensorValues = (sensor: any) => {
})
}
if (sensor.capabilities.monitoring.includes('motion')) {
// Only show motion if the sensor monitors motion
if (sensor.capabilities?.monitoring?.includes('motion')) {
values.push({
type: 'motion',
label: 'Motion',
@@ -139,14 +152,60 @@ const getSensorValues = (sensor: any) => {
})
}
// If no monitoring capabilities, show generic status
if (values.length === 0) {
values.push({
type: 'status',
label: 'Status',
value: sensor.status === 'online' ? 'Active' : 'Inactive',
unit: '',
})
// Show device-specific metrics based on sensor type if no specific monitoring capabilities
if (values.length === 0 && sensor.type) {
switch (sensor.type) {
case 'lighting':
values.push({
type: 'brightness',
label: 'Brightness',
value: Math.floor(Math.random() * 100),
unit: '%',
})
values.push({
type: 'power',
label: 'Power',
value: Math.floor(Math.random() * 50 + 5),
unit: 'W',
})
break
case 'hvac':
values.push({
type: 'setpoint',
label: 'Set Point',
value: (Math.random() * 6 + 18).toFixed(1),
unit: '°C',
})
values.push({
type: 'mode',
label: 'Mode',
value: ['Heat', 'Cool', 'Auto'][Math.floor(Math.random() * 3)],
unit: '',
})
break
case 'security':
values.push({
type: 'status',
label: 'Security',
value: Math.random() > 0.8 ? 'Alert' : 'Normal',
unit: '',
})
values.push({
type: 'armed',
label: 'Armed',
value: Math.random() > 0.5 ? 'Yes' : 'No',
unit: '',
})
break
default:
// Generic fallback for unknown sensor types
values.push({
type: 'status',
label: 'Status',
value: sensor.status === 'online' ? 'Active' : 'Inactive',
unit: '',
})
}
}
return values
@@ -157,8 +216,10 @@ const sensorValues = computed(() => getSensorValues(props.sensor))
// Check if sensor was recently updated for pulsing animation
const isRecentlyUpdated = computed(() => {
return sensorStore.recentlyUpdatedSensors.has(props.sensor.id) ||
sensorStore.recentlyUpdatedSensors.has(props.sensor.sensor_id)
return (
sensorStore.recentlyUpdatedSensors.has(props.sensor.id) ||
sensorStore.recentlyUpdatedSensors.has(props.sensor.sensor_id)
)
})
const getSensorTypeIcon = (type: string) => {
@@ -189,7 +250,7 @@ const getSensorTypeStyle = (type: string) => {
const getSensorStatusColor = (status: string) => {
switch (status) {
case 'online':
case 'active':
return 'bg-green-500'
case 'offline':
return 'bg-gray-400'