Support partial sensor readings and improve room metrics aggregation

- Allow room and card components to handle rooms with missing energy or
CO2 data - Update RoomMetrics type to make energy and co2 fields
optional - Track which sensors provide energy or CO2 data per room -
Aggregate room metrics only from available data (partial readings) -
Update AirQualityCard and RoomMetricsCard to safely access optional
fields - Set MAX_HISTORY_POINTS to 48 in energy store - Improve
robustness of API room fetching and data mapping - Update CLAUDE.md with
new partial reading support and data flow details
This commit is contained in:
rafaeldpsilva
2025-10-03 10:51:48 +01:00
parent f96456ed29
commit e2cf2bc782
6 changed files with 308 additions and 69 deletions

View File

@@ -13,9 +13,9 @@
<h3 class="font-medium text-gray-900">{{ room.room }}</h3>
<div class="flex items-center gap-2">
<!-- CO2 Status Indicator -->
<div
<div
class="w-3 h-3 rounded-full"
:class="getCO2StatusColor(room.co2.status)"
:class="getCO2StatusColor(room.co2!.status)"
></div>
<!-- Occupancy Indicator -->
<div class="flex items-center gap-1 text-xs text-gray-500">
@@ -32,15 +32,15 @@
<!-- Energy -->
<div class="bg-blue-50 rounded p-2">
<div class="text-blue-600 font-medium">Energy</div>
<div class="text-blue-900">{{ room.energy.current.toFixed(2) }} {{ room.energy.unit }}</div>
<div class="text-blue-600 text-xs">Total: {{ room.energy.total.toFixed(2) }}</div>
<div class="text-blue-900">{{ room.energy!.current.toFixed(2) }} {{ room.energy!.unit }}</div>
<div class="text-blue-600 text-xs">Total: {{ room.energy!.total.toFixed(2) }}</div>
</div>
<!-- CO2 -->
<div class="rounded p-2" :class="getCO2BackgroundColor(room.co2.status)">
<div class="font-medium" :class="getCO2TextColor(room.co2.status)">CO2</div>
<div :class="getCO2TextColor(room.co2.status)">{{ Math.round(room.co2.current) }} {{ room.co2.unit }}</div>
<div class="text-xs" :class="getCO2TextColor(room.co2.status)">{{ room.co2.status.toUpperCase() }}</div>
<div class="rounded p-2" :class="getCO2BackgroundColor(room.co2!.status)">
<div class="font-medium" :class="getCO2TextColor(room.co2!.status)">CO2</div>
<div :class="getCO2TextColor(room.co2!.status)">{{ Math.round(room.co2!.current) }} {{ room.co2!.unit }}</div>
<div class="text-xs" :class="getCO2TextColor(room.co2!.status)">{{ room.co2!.status.toUpperCase() }}</div>
</div>
</div>
@@ -77,18 +77,19 @@ import { useRoomStore } from '@/stores/room'
const roomStore = useRoomStore()
const roomsList = computed(() => {
return Array.from(roomStore.roomsData.values()).sort((a, b) =>
a.room.localeCompare(b.room)
)
return Array.from(roomStore.roomsData.values())
.filter(room => room.energy && room.co2) // Only show rooms with both metrics
.sort((a, b) => a.room.localeCompare(b.room))
})
const totalEnergy = computed(() => {
return roomsList.value.reduce((sum, room) => sum + room.energy.current, 0)
return roomsList.value.reduce((sum, room) => sum + (room.energy?.current || 0), 0)
})
const averageCO2 = computed(() => {
if (roomsList.value.length === 0) return 0
return roomsList.value.reduce((sum, room) => sum + room.co2.current, 0) / roomsList.value.length
const total = roomsList.value.reduce((sum, room) => sum + (room.co2?.current || 0), 0)
return total / roomsList.value.length
})
const getCO2StatusColor = (status: string) => {