Refactor sensor ID usage and types, add CO2 metrics, update docs
- Standardize on `sensor.sensor_id` throughout components and stores - Add average and max CO2 metrics to sensor store and HomeView - Improve type safety for sensors, actions, and API calls - Update AGENTS.md with repository guidelines - Refine settings store types and utility functions - Add WindowWithAuth interface for auth store access - Minor bug fixes and code cleanup
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-medium text-gray-900">{{ sensor.name }}</h3>
|
||||
<p class="text-sm text-gray-500">{{ sensor.id }}</p>
|
||||
<p class="text-sm text-gray-500">{{ sensor.sensor_id }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -30,9 +30,9 @@
|
||||
<!-- Room Assignment -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Room Assignment</label>
|
||||
<select
|
||||
:value="sensor.room"
|
||||
@change="$emit('updateRoom', sensor.id, ($event.target as HTMLSelectElement).value)"
|
||||
<select
|
||||
:value="sensor.room"
|
||||
@change="$emit('updateRoom', sensor.sensor_id, ($event.target as HTMLSelectElement).value)"
|
||||
class="w-full px-3 py-2 border border-gray-200 rounded-lg bg-white text-sm"
|
||||
>
|
||||
<option value="">Unassigned</option>
|
||||
@@ -100,7 +100,7 @@
|
||||
<span class="font-medium">Location:</span>
|
||||
<div>{{ sensor.metadata.location }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="sensor.lastSeen">
|
||||
<span class="font-medium">Last Seen:</span>
|
||||
<div>{{ formatTime(sensor.lastSeen) }}</div>
|
||||
</div>
|
||||
@@ -166,26 +166,27 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useSensorStore } from '@/stores/sensor'
|
||||
import type { SensorDevice, SensorAction } from '@/services'
|
||||
|
||||
const props = defineProps<{
|
||||
sensor: any
|
||||
sensor: SensorDevice
|
||||
availableRooms: string[]
|
||||
isExecutingAction?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
updateRoom: [sensorId: string, newRoom: string]
|
||||
executeAction: [sensor: any, action: any]
|
||||
executeAction: [sensor: SensorDevice, action: SensorAction]
|
||||
}>()
|
||||
|
||||
const sensorStore = useSensorStore()
|
||||
|
||||
const getSensorValues = (sensor: any) => {
|
||||
const getSensorValues = (sensor: SensorDevice) => {
|
||||
const values = []
|
||||
|
||||
// Get real-time sensor reading from store
|
||||
const latestReading = sensorStore.latestReadings.get(sensor.id) || sensorStore.latestReadings.get(sensor.sensor_id)
|
||||
console.log(`[Detailed] Getting values for sensor ${sensor.id}, found reading:`, latestReading)
|
||||
const latestReading = sensorStore.latestReadings.get(sensor.sensor_id)
|
||||
console.log(`[Detailed] Getting values for sensor ${sensor.sensor_id}, found reading:`, latestReading)
|
||||
console.log('[Detailed] Available readings:', Array.from(sensorStore.latestReadings.keys()))
|
||||
console.log(`[Detailed] Sensor capabilities:`, sensor.capabilities?.monitoring)
|
||||
|
||||
@@ -315,25 +316,24 @@ 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.sensor_id)
|
||||
})
|
||||
|
||||
const getDefaultTags = (sensor: any) => {
|
||||
const tags = [sensor.type]
|
||||
|
||||
if (sensor.metadata.battery) {
|
||||
const getDefaultTags = (sensor: SensorDevice): string[] => {
|
||||
const tags: string[] = [sensor.type]
|
||||
|
||||
if (sensor.metadata?.battery) {
|
||||
tags.push('wireless')
|
||||
} else {
|
||||
tags.push('wired')
|
||||
}
|
||||
|
||||
|
||||
if (sensor.capabilities.actions.length > 0) {
|
||||
tags.push('controllable')
|
||||
} else {
|
||||
tags.push('monitor-only')
|
||||
}
|
||||
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
|
||||
@@ -131,14 +131,20 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import type { SensorDevice, SensorAction } from '@/services'
|
||||
|
||||
interface ActionParameters {
|
||||
value?: number | string | boolean
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
sensor: any
|
||||
action: any
|
||||
sensor: SensorDevice
|
||||
action: SensorAction
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
execute: [sensorId: string, actionId: string, parameters: any]
|
||||
execute: [sensorId: string, actionId: string, parameters: ActionParameters]
|
||||
close: []
|
||||
}>()
|
||||
|
||||
@@ -182,7 +188,7 @@ const getUnit = () => {
|
||||
const executeAction = async () => {
|
||||
isExecuting.value = true
|
||||
|
||||
const parameters: any = {}
|
||||
const parameters: ActionParameters = {}
|
||||
|
||||
if (props.action.type === 'adjust') {
|
||||
if (hasNumericRange.value) {
|
||||
@@ -195,7 +201,7 @@ const executeAction = async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
emit('execute', props.sensor.id, props.action.id, parameters)
|
||||
emit('execute', props.sensor.sensor_id, props.action.id, parameters)
|
||||
} catch (error) {
|
||||
console.error('Failed to execute action:', error)
|
||||
} finally {
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
* Provides reactive API state management
|
||||
*/
|
||||
import { ref, reactive } from 'vue'
|
||||
import {
|
||||
sensorsApi,
|
||||
roomsApi,
|
||||
analyticsApi,
|
||||
import {
|
||||
sensorsApi,
|
||||
roomsApi,
|
||||
analyticsApi,
|
||||
healthApi,
|
||||
type SensorInfo,
|
||||
type SensorDevice,
|
||||
type SensorType,
|
||||
type SensorStatus,
|
||||
type SensorMetadata,
|
||||
type RoomInfo,
|
||||
type RoomData,
|
||||
type AnalyticsSummary,
|
||||
@@ -69,23 +72,23 @@ export function useSensorsApi() {
|
||||
error: null
|
||||
})
|
||||
|
||||
const sensors = ref<SensorInfo[]>([])
|
||||
const currentSensor = ref<SensorInfo | null>(null)
|
||||
const sensors = ref<SensorDevice[]>([])
|
||||
const currentSensor = ref<SensorDevice | null>(null)
|
||||
const sensorData = ref<DataResponse | null>(null)
|
||||
|
||||
const { handleApiCall } = useApi()
|
||||
|
||||
const fetchSensors = async (params?: {
|
||||
room?: string
|
||||
sensor_type?: any
|
||||
status?: any
|
||||
sensor_type?: SensorType
|
||||
status?: SensorStatus
|
||||
}) => {
|
||||
const result = await handleApiCall(
|
||||
() => sensorsApi.getSensors(params),
|
||||
state
|
||||
)
|
||||
if (result) {
|
||||
sensors.value = result
|
||||
if (result && result.sensors) {
|
||||
sensors.value = result.sensors
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -129,7 +132,7 @@ export function useSensorsApi() {
|
||||
|
||||
const updateSensorMetadata = async (
|
||||
sensorId: string,
|
||||
metadata: Record<string, any>
|
||||
metadata: SensorMetadata
|
||||
) => {
|
||||
return handleApiCall(
|
||||
() => sensorsApi.updateSensorMetadata(sensorId, metadata),
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
// Base configuration
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000'
|
||||
|
||||
// Extend Window interface for auth store
|
||||
interface WindowWithAuth extends Window {
|
||||
__AUTH_STORE__?: {
|
||||
getAuthHeader: () => Record<string, string>
|
||||
ensureAuthenticated: () => Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
// API Response types
|
||||
export interface ApiResponse<T = any> {
|
||||
export interface ApiResponse<T = unknown> {
|
||||
data: T
|
||||
total_count?: number
|
||||
query?: any
|
||||
query?: Record<string, unknown>
|
||||
execution_time_ms?: number
|
||||
}
|
||||
|
||||
@@ -71,7 +79,7 @@ export interface SensorReading {
|
||||
value: number
|
||||
unit: string
|
||||
}
|
||||
metadata?: Record<string, any>
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface RoomInfo {
|
||||
@@ -169,7 +177,7 @@ export interface SystemEvent {
|
||||
event_type: string
|
||||
severity: 'info' | 'warning' | 'error' | 'critical'
|
||||
message: string
|
||||
details?: Record<string, any>
|
||||
details?: Record<string, unknown>
|
||||
sensor_id?: string
|
||||
room?: string
|
||||
}
|
||||
@@ -187,6 +195,9 @@ export interface SensorDevice {
|
||||
actions: SensorAction[]
|
||||
}
|
||||
metadata: SensorMetadata
|
||||
tags?: string[]
|
||||
lastSeen?: number
|
||||
total_readings?: number
|
||||
}
|
||||
|
||||
export interface SensorAction {
|
||||
@@ -231,6 +242,7 @@ export enum SensorStatus {
|
||||
ONLINE = 'online',
|
||||
OFFLINE = 'offline',
|
||||
ERROR = 'error',
|
||||
ACTIVE = 'active',
|
||||
}
|
||||
|
||||
export interface SensorMetadata {
|
||||
@@ -242,6 +254,7 @@ export interface SensorMetadata {
|
||||
model?: string
|
||||
firmware?: string
|
||||
battery?: number
|
||||
signalStrength?: number
|
||||
created_at?: string
|
||||
updated_at?: string
|
||||
manufacturer?: string
|
||||
@@ -277,7 +290,7 @@ class ApiClient {
|
||||
// Dynamically get auth headers to avoid circular imports
|
||||
try {
|
||||
// Try to get from window first (for when store is exposed)
|
||||
const authStore = (window as any).__AUTH_STORE__
|
||||
const authStore = (window as WindowWithAuth).__AUTH_STORE__
|
||||
if (authStore && typeof authStore.getAuthHeader === 'function') {
|
||||
return authStore.getAuthHeader()
|
||||
}
|
||||
@@ -333,7 +346,7 @@ class ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
async get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
|
||||
async get<T>(endpoint: string, params?: Record<string, string | number | boolean | string[]>): Promise<T> {
|
||||
const url = new URL(`${this.baseUrl}${endpoint}`)
|
||||
|
||||
if (params) {
|
||||
@@ -366,14 +379,14 @@ class ApiClient {
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
async post<T>(endpoint: string, data?: any): Promise<T> {
|
||||
async post<T>(endpoint: string, data?: Record<string, unknown> | unknown[]): Promise<T> {
|
||||
return this.request<T>(endpoint, {
|
||||
method: 'POST',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
})
|
||||
}
|
||||
|
||||
async put<T>(endpoint: string, data?: any): Promise<T> {
|
||||
async put<T>(endpoint: string, data?: Record<string, unknown> | unknown[]): Promise<T> {
|
||||
return this.request<T>(endpoint, {
|
||||
method: 'PUT',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
|
||||
@@ -77,12 +77,22 @@ export const sensorsApi = {
|
||||
}): Promise<{
|
||||
data: SensorReading[]
|
||||
count: number
|
||||
export_params: any
|
||||
export_params: {
|
||||
start_time: number
|
||||
end_time: number
|
||||
sensor_ids?: string
|
||||
format?: 'json' | 'csv'
|
||||
}
|
||||
}> {
|
||||
return apiClient.get<{
|
||||
data: SensorReading[]
|
||||
count: number
|
||||
export_params: any
|
||||
export_params: {
|
||||
start_time: number
|
||||
end_time: number
|
||||
sensor_ids?: string
|
||||
format?: 'json' | 'csv'
|
||||
}
|
||||
}>('/api/v1/export', params)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@ import {
|
||||
type HealthCheck,
|
||||
} from '@/services'
|
||||
|
||||
// Extend Window interface for auth store
|
||||
interface WindowWithAuth extends Window {
|
||||
__AUTH_STORE__?: {
|
||||
ensureAuthenticated: () => Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
export const useAnalyticsStore = defineStore('analytics', () => {
|
||||
// State
|
||||
const analyticsData = ref<{
|
||||
@@ -41,7 +48,7 @@ export const useAnalyticsStore = defineStore('analytics', () => {
|
||||
console.warn('Authentication error detected, attempting to re-authenticate...')
|
||||
|
||||
try {
|
||||
const authStore = (window as any).__AUTH_STORE__
|
||||
const authStore = (window as WindowWithAuth).__AUTH_STORE__
|
||||
if (authStore && typeof authStore.ensureAuthenticated === 'function') {
|
||||
const authSuccess = await authStore.ensureAuthenticated()
|
||||
if (authSuccess) {
|
||||
|
||||
@@ -3,6 +3,13 @@ import { ref, reactive } from 'vue'
|
||||
import { roomsApi, type RoomInfo as ApiRoomInfo, type SensorReading } from '@/services'
|
||||
import { useSensorStore } from './sensor'
|
||||
|
||||
// Extend Window interface for auth store
|
||||
interface WindowWithAuth extends Window {
|
||||
__AUTH_STORE__?: {
|
||||
ensureAuthenticated: () => Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
interface RoomMetrics {
|
||||
room: string
|
||||
sensors: string[]
|
||||
@@ -221,7 +228,7 @@ export const useRoomStore = defineStore('room', () => {
|
||||
console.warn('Authentication error detected, attempting to re-authenticate...')
|
||||
|
||||
try {
|
||||
const authStore = (window as any).__AUTH_STORE__
|
||||
const authStore = (window as WindowWithAuth).__AUTH_STORE__
|
||||
if (authStore && typeof authStore.ensureAuthenticated === 'function') {
|
||||
const authSuccess = await authStore.ensureAuthenticated()
|
||||
if (authSuccess) {
|
||||
|
||||
@@ -6,13 +6,21 @@ import {
|
||||
type SensorDevice,
|
||||
type SensorStatus,
|
||||
type SensorReading,
|
||||
type SensorMetadata,
|
||||
} from '@/services'
|
||||
|
||||
// Extend Window interface for auth store
|
||||
interface WindowWithAuth extends Window {
|
||||
__AUTH_STORE__?: {
|
||||
ensureAuthenticated: () => Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
export const useSensorStore = defineStore('sensor', () => {
|
||||
// State
|
||||
const sensorDevices = reactive<Map<string, SensorDevice>>(new Map())
|
||||
const latestReadings = reactive<Map<string, SensorReading>>(new Map())
|
||||
const sensorsData = reactive<Map<string, any>>(new Map()) // Legacy support
|
||||
const sensorsData = reactive<Map<string, SensorReading>>(new Map()) // Legacy support - deprecated, use latestReadings instead
|
||||
const recentlyUpdatedSensors = reactive<Set<string>>(new Set()) // Track recently updated sensors
|
||||
const totalReadings = ref<number>(0) // Total number of readings across all sensors
|
||||
const apiLoading = ref<boolean>(false)
|
||||
@@ -27,6 +35,26 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
).length
|
||||
})
|
||||
|
||||
// Aggregated CO2 metrics
|
||||
const averageCO2Level = computed<number>(() => {
|
||||
const readings = Array.from(latestReadings.values())
|
||||
const co2Readings = readings.filter(r => r.co2?.value !== undefined)
|
||||
|
||||
if (co2Readings.length === 0) return 0
|
||||
|
||||
const totalCO2 = co2Readings.reduce((sum, r) => sum + (r.co2?.value || 0), 0)
|
||||
return totalCO2 / co2Readings.length
|
||||
})
|
||||
|
||||
const maxCO2Level = computed<number>(() => {
|
||||
const readings = Array.from(latestReadings.values())
|
||||
const co2Values = readings
|
||||
.filter(r => r.co2?.value !== undefined)
|
||||
.map(r => r.co2?.value || 0)
|
||||
|
||||
return co2Values.length > 0 ? Math.max(...co2Values) : 0
|
||||
})
|
||||
|
||||
// Actions
|
||||
function updateSensorRoom(sensorId: string, newRoom: string): void {
|
||||
const sensor = sensorDevices.get(sensorId)
|
||||
@@ -93,7 +121,7 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
console.warn('Authentication error detected, attempting to re-authenticate...')
|
||||
|
||||
try {
|
||||
const authStore = (window as any).__AUTH_STORE__
|
||||
const authStore = (window as WindowWithAuth).__AUTH_STORE__
|
||||
if (authStore && typeof authStore.ensureAuthenticated === 'function') {
|
||||
const authSuccess = await authStore.ensureAuthenticated()
|
||||
if (authSuccess) {
|
||||
@@ -193,7 +221,7 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
let totalReadingsCount: number = 0
|
||||
|
||||
result.sensors.forEach((sensor) => {
|
||||
const sensorKey: string = sensor._id || sensor.sensor_id
|
||||
const sensorKey: string = sensor.sensor_id
|
||||
const sensorType: string = sensor.sensor_type || sensor.type
|
||||
const sensorName: string = sensor.name || ''
|
||||
|
||||
@@ -204,14 +232,12 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
|
||||
const normalizedSensor = {
|
||||
...sensor,
|
||||
id: sensorKey,
|
||||
type: sensorType,
|
||||
capabilities: {
|
||||
actions: [], // Default empty actions array
|
||||
monitoring:
|
||||
sensor.capabilities?.monitoring ||
|
||||
getDefaultMonitoringCapabilities(sensorType, sensorName),
|
||||
...sensor.capabilities,
|
||||
actions: sensor.capabilities?.actions || [],
|
||||
},
|
||||
metadata: {
|
||||
model: sensor.metadata?.model || 'Unknown',
|
||||
@@ -221,10 +247,10 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
signalStrength: sensor.metadata?.signalStrength,
|
||||
...sensor.metadata,
|
||||
},
|
||||
lastSeen: sensor.last_seen || Date.now() / 1000,
|
||||
lastSeen: sensor.lastSeen || Date.now() / 1000,
|
||||
}
|
||||
|
||||
sensorDevices.set(sensorKey, normalizedSensor)
|
||||
sensorDevices.set(sensorKey, normalizedSensor as SensorDevice)
|
||||
})
|
||||
|
||||
// Update total readings
|
||||
@@ -246,7 +272,7 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
return handleApiCall(() => sensorsApi.getSensorData(sensorId, params))
|
||||
}
|
||||
|
||||
async function updateApiSensorMetadata(sensorId: string, metadata: Record<string, any>) {
|
||||
async function updateApiSensorMetadata(sensorId: string, metadata: SensorMetadata) {
|
||||
return handleApiCall(() => sensorsApi.updateSensorMetadata(sensorId, metadata))
|
||||
}
|
||||
|
||||
@@ -276,6 +302,8 @@ export const useSensorStore = defineStore('sensor', () => {
|
||||
// Computed
|
||||
totalSensors,
|
||||
activeSensors,
|
||||
averageCO2Level,
|
||||
maxCO2Level,
|
||||
|
||||
// Actions
|
||||
updateEnergySensors,
|
||||
|
||||
@@ -33,6 +33,18 @@ interface AppSettings {
|
||||
developerMode: boolean
|
||||
}
|
||||
|
||||
// Type for setting values
|
||||
type SettingValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| Theme
|
||||
| Language
|
||||
| NavigationMode
|
||||
| UISettings
|
||||
| NotificationSettings
|
||||
| AppSettings
|
||||
|
||||
const DEFAULT_SETTINGS: AppSettings = {
|
||||
theme: 'system',
|
||||
language: 'en',
|
||||
@@ -93,8 +105,9 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function updateSetting(path: string, value: any) {
|
||||
function updateSetting(path: string, value: SettingValue): void {
|
||||
const keys = path.split('.')
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let current: any = settings
|
||||
|
||||
for (let i = 0; i < keys.length - 1; i++) {
|
||||
@@ -105,8 +118,9 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getSetting(path: string): any {
|
||||
function getSetting(path: string): SettingValue | undefined {
|
||||
const keys = path.split('.')
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let current: any = settings
|
||||
|
||||
for (const key of keys) {
|
||||
@@ -114,7 +128,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
if (current === undefined) break
|
||||
}
|
||||
|
||||
return current
|
||||
return current as SettingValue | undefined
|
||||
}
|
||||
|
||||
function exportSettings(): string {
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
:content="websocketStore.isConnected ? 'Connected' : 'Disconnected'"
|
||||
/>
|
||||
<MetricCard title="Average Usage" :content="averageEnergyUsage" details="kWh" />
|
||||
<MetricCard title="Average CO2" :content="averageCO2" details="ppm" />
|
||||
<MetricCard title="Max CO2" :content="maxCO2" details="ppm" />
|
||||
<GraphMetricCard
|
||||
title="Real-time Energy"
|
||||
:content="currentEnergyValue"
|
||||
@@ -29,18 +31,6 @@
|
||||
:trend-data="energyStore.energyHistory.slice(-8)"
|
||||
trend-direction="neutral"
|
||||
/>
|
||||
<GraphMetricCard
|
||||
title="Current Knowledge"
|
||||
content="86%"
|
||||
:trend-data="[203, 78, 80, 82, 142, 85, 85, 86]"
|
||||
trend-direction="down"
|
||||
/>
|
||||
<GraphMetricCard
|
||||
title="Knowledge Gain"
|
||||
content="+34%"
|
||||
:trend-data="[20, 25, 28, 30, 32, 33, 34, 34]"
|
||||
trend-direction="neutral"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<RealtimeEnergyChartCard title="Month" />
|
||||
@@ -66,11 +56,13 @@ import SensorConsumptionTable from '@/components/cards/SensorConsumptionTable.vu
|
||||
import RoomMetricsCard from '@/components/cards/RoomMetricsCard.vue'
|
||||
import AirQualityCard from '@/components/cards/AirQualityCard.vue'
|
||||
import { useEnergyStore } from '@/stores/energy'
|
||||
import { useSensorStore } from '@/stores/sensor'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
import { computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useWebSocketStore } from '@/stores/websocket'
|
||||
|
||||
const energyStore = useEnergyStore()
|
||||
const sensorStore = useSensorStore()
|
||||
const websocketStore = useWebSocketStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
@@ -83,6 +75,14 @@ const averageEnergyUsage = computed(() => {
|
||||
return energyStore.averageEnergyUsage.toFixed(2)
|
||||
})
|
||||
|
||||
const averageCO2 = computed(() => {
|
||||
return Math.round(sensorStore.averageCO2Level)
|
||||
})
|
||||
|
||||
const maxCO2 = computed(() => {
|
||||
return Math.round(sensorStore.maxCO2Level)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
settingsStore.initialize()
|
||||
|
||||
|
||||
@@ -201,6 +201,7 @@ import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useSensorStore } from '@/stores/sensor'
|
||||
import { useRoomStore } from '@/stores/room'
|
||||
import { useWebSocketStore } from '@/stores/websocket'
|
||||
import type { SensorDevice, SensorAction } from '@/services'
|
||||
import ActionModal from '@/components/modals/ActionModal.vue'
|
||||
import RoomManagementModal from '@/components/modals/RoomManagementModal.vue'
|
||||
import SimpleSensorCard from '@/components/cards/SimpleSensorCard.vue'
|
||||
@@ -217,8 +218,8 @@ const selectedType = ref('')
|
||||
const selectedStatus = ref('')
|
||||
|
||||
const showActionModal = ref(false)
|
||||
const selectedSensor = ref<any>(null)
|
||||
const selectedAction = ref<any>(null)
|
||||
const selectedSensor = ref<SensorDevice | null>(null)
|
||||
const selectedAction = ref<SensorAction | null>(null)
|
||||
const isExecutingAction = ref(false)
|
||||
|
||||
const showRoomManagementModal = ref(false)
|
||||
@@ -241,17 +242,22 @@ const updateRoom = (sensorId: string, newRoom: string) => {
|
||||
sensorStore.updateSensorRoom(sensorId, newRoom)
|
||||
}
|
||||
|
||||
const executeAction = (sensor: any, action: any) => {
|
||||
const executeAction = (sensor: SensorDevice, action: SensorAction) => {
|
||||
if (action.parameters) {
|
||||
selectedSensor.value = sensor
|
||||
selectedAction.value = action
|
||||
showActionModal.value = true
|
||||
} else {
|
||||
handleActionExecute(sensor.id, action.id, {})
|
||||
handleActionExecute(sensor.sensor_id, action.id, {})
|
||||
}
|
||||
}
|
||||
|
||||
const handleActionExecute = async (sensorId: string, actionId: string, parameters: any) => {
|
||||
interface ActionParameters {
|
||||
value?: number | string | boolean
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const handleActionExecute = async (sensorId: string, actionId: string, parameters: ActionParameters) => {
|
||||
isExecutingAction.value = true
|
||||
try {
|
||||
await sensorStore.executeSensorAction(sensorId, actionId)
|
||||
|
||||
Reference in New Issue
Block a user