Add API integration for sensors and rooms management
Integrate sensorsApi and roomsApi services into energy store. Add API state, loading/error handling, and async functions for fetching sensor and room data. Update room loading logic to fetch from API. Expose new API functions for analytics and health endpoints. Update SensorManagementView to use localhost WebSocket for real-time updates.
This commit is contained in:
30
src/services/roomsApi.ts
Normal file
30
src/services/roomsApi.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Rooms API Service
|
||||||
|
* Handles room-related API calls
|
||||||
|
*/
|
||||||
|
import { apiClient, type RoomInfo, type RoomData } from './api'
|
||||||
|
|
||||||
|
export const roomsApi = {
|
||||||
|
/**
|
||||||
|
* Get list of all rooms with sensor counts and latest metrics
|
||||||
|
*/
|
||||||
|
async getRooms(): Promise<RoomInfo[]> {
|
||||||
|
return apiClient.get<RoomInfo[]>('/api/v1/rooms')
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get historical data for a specific room
|
||||||
|
*/
|
||||||
|
async getRoomData(
|
||||||
|
roomName: string,
|
||||||
|
params?: {
|
||||||
|
start_time?: number
|
||||||
|
end_time?: number
|
||||||
|
limit?: number
|
||||||
|
},
|
||||||
|
): Promise<RoomData> {
|
||||||
|
return apiClient.get<RoomData>(`/api/v1/rooms/${encodeURIComponent(roomName)}/data`, params)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default roomsApi
|
||||||
98
src/services/sensorsApi.ts
Normal file
98
src/services/sensorsApi.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* Sensors API Service
|
||||||
|
* Handles sensor-related API calls
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
apiClient,
|
||||||
|
type SensorInfo,
|
||||||
|
type SensorReading,
|
||||||
|
type DataQuery,
|
||||||
|
type DataResponse,
|
||||||
|
type SensorType,
|
||||||
|
type SensorStatus,
|
||||||
|
} from './api'
|
||||||
|
|
||||||
|
export const sensorsApi = {
|
||||||
|
/**
|
||||||
|
* Get all sensors with optional filtering
|
||||||
|
*/
|
||||||
|
async getSensors(params?: {
|
||||||
|
room?: string
|
||||||
|
sensor_type?: SensorType
|
||||||
|
status?: SensorStatus
|
||||||
|
}): Promise<SensorInfo[]> {
|
||||||
|
return apiClient.get<SensorInfo[]>('/api/v1/sensors', params)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get detailed information about a specific sensor
|
||||||
|
*/
|
||||||
|
async getSensor(sensorId: string): Promise<SensorInfo> {
|
||||||
|
return apiClient.get<SensorInfo>(`/api/v1/sensors/${sensorId}`)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get historical data for a specific sensor
|
||||||
|
*/
|
||||||
|
async getSensorData(
|
||||||
|
sensorId: string,
|
||||||
|
params?: {
|
||||||
|
start_time?: number
|
||||||
|
end_time?: number
|
||||||
|
limit?: number
|
||||||
|
offset?: number
|
||||||
|
},
|
||||||
|
): Promise<DataResponse> {
|
||||||
|
return apiClient.get<DataResponse>(`/api/v1/sensors/${sensorId}/data`, params)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advanced data query with multiple filters
|
||||||
|
*/
|
||||||
|
async queryData(query: DataQuery): Promise<DataResponse> {
|
||||||
|
return apiClient.post<DataResponse>('/api/v1/data/query', query)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update sensor metadata
|
||||||
|
*/
|
||||||
|
async updateSensorMetadata(
|
||||||
|
sensorId: string,
|
||||||
|
metadata: Record<string, any>,
|
||||||
|
): Promise<{ message: string }> {
|
||||||
|
return apiClient.put<{ message: string }>(`/api/v1/sensors/${sensorId}/metadata`, metadata)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete sensor and all its data
|
||||||
|
*/
|
||||||
|
async deleteSensor(sensorId: string): Promise<{
|
||||||
|
message: string
|
||||||
|
readings_deleted: number
|
||||||
|
metadata_deleted?: boolean
|
||||||
|
}> {
|
||||||
|
return apiClient.delete(`/api/v1/sensors/${sensorId}`)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export sensor data for specified time range
|
||||||
|
*/
|
||||||
|
async exportData(params: {
|
||||||
|
start_time: number
|
||||||
|
end_time: number
|
||||||
|
sensor_ids?: string
|
||||||
|
format?: 'json' | 'csv'
|
||||||
|
}): Promise<{
|
||||||
|
data: SensorReading[]
|
||||||
|
count: number
|
||||||
|
export_params: any
|
||||||
|
}> {
|
||||||
|
return apiClient.get<{
|
||||||
|
data: SensorReading[]
|
||||||
|
count: number
|
||||||
|
export_params: any
|
||||||
|
}>('/api/v1/export', params)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default sensorsApi
|
||||||
@@ -1,5 +1,18 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
|
import {
|
||||||
|
sensorsApi,
|
||||||
|
roomsApi,
|
||||||
|
analyticsApi,
|
||||||
|
healthApi,
|
||||||
|
type SensorInfo as ApiSensorInfo,
|
||||||
|
type RoomInfo as ApiRoomInfo,
|
||||||
|
type AnalyticsSummary,
|
||||||
|
type EnergyTrends,
|
||||||
|
type RoomComparison,
|
||||||
|
type SystemStatus,
|
||||||
|
type HealthCheck
|
||||||
|
} from '@/services'
|
||||||
|
|
||||||
const MAX_DATA_POINTS = 100 // Keep the last 100 data points for the chart
|
const MAX_DATA_POINTS = 100 // Keep the last 100 data points for the chart
|
||||||
|
|
||||||
@@ -96,29 +109,46 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
const roomsData = reactive<Map<string, RoomMetrics>>(new Map())
|
const roomsData = reactive<Map<string, RoomMetrics>>(new Map())
|
||||||
const latestReadings = reactive<Map<string, SensorReading>>(new Map())
|
const latestReadings = reactive<Map<string, SensorReading>>(new Map())
|
||||||
const sensorDevices = reactive<Map<string, SensorDevice>>(new Map())
|
const sensorDevices = reactive<Map<string, SensorDevice>>(new Map())
|
||||||
const availableRooms = ref<string[]>([
|
const availableRooms = ref<string[]>([])
|
||||||
'Conference Room A',
|
const roomsLoading = ref<boolean>(false)
|
||||||
'Conference Room B',
|
const roomsLoaded = ref<boolean>(false)
|
||||||
'Office Floor 1',
|
|
||||||
'Office Floor 2',
|
// API integration state
|
||||||
'Kitchen',
|
const apiSensors = ref<ApiSensorInfo[]>([])
|
||||||
'Lobby',
|
const apiRooms = ref<ApiRoomInfo[]>([])
|
||||||
'Server Room',
|
const analyticsData = ref<{
|
||||||
'Storage Room',
|
summary: AnalyticsSummary | null
|
||||||
'Meeting Room 1',
|
trends: EnergyTrends | null
|
||||||
'Meeting Room 2'
|
roomComparison: RoomComparison | null
|
||||||
])
|
}>({
|
||||||
|
summary: null,
|
||||||
|
trends: null,
|
||||||
|
roomComparison: null
|
||||||
|
})
|
||||||
|
const systemStatus = ref<SystemStatus | null>(null)
|
||||||
|
const healthStatus = ref<HealthCheck | null>(null)
|
||||||
|
const apiLoading = ref(false)
|
||||||
|
const apiError = ref<string | null>(null)
|
||||||
|
|
||||||
let socket: WebSocket | null = null
|
let socket: WebSocket | null = null
|
||||||
const newDataBuffer: (LegacyEnergyData | SensorReading)[] = []
|
const newDataBuffer: (LegacyEnergyData | SensorReading)[] = []
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
function connect(url: string) {
|
function connect(url: string) {
|
||||||
if (isConnected.value) {
|
if (isConnected.value && socket) {
|
||||||
console.log('Already connected.')
|
console.log('Already connected.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close any existing connection first
|
||||||
|
if (socket) {
|
||||||
|
socket.onclose = null
|
||||||
|
socket.onerror = null
|
||||||
|
socket.onmessage = null
|
||||||
|
socket.close()
|
||||||
|
socket = null
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Connecting to WebSocket at ${url}`)
|
console.log(`Connecting to WebSocket at ${url}`)
|
||||||
socket = new WebSocket(url)
|
socket = new WebSocket(url)
|
||||||
|
|
||||||
@@ -130,14 +160,35 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
socket.onmessage = (event) => {
|
socket.onmessage = (event) => {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data)
|
const data = JSON.parse(event.data)
|
||||||
|
|
||||||
|
// Handle proxy info message from API Gateway
|
||||||
|
if (data.type === 'proxy_info' && data.sensor_service_url) {
|
||||||
|
console.log('Received proxy info, reconnecting to sensor service...')
|
||||||
|
// Close current connection gracefully
|
||||||
|
if (socket) {
|
||||||
|
socket.onclose = null // Prevent triggering disconnect handlers
|
||||||
|
socket.close()
|
||||||
|
socket = null
|
||||||
|
}
|
||||||
|
// Set disconnected state temporarily
|
||||||
|
isConnected.value = false
|
||||||
|
|
||||||
|
// Connect directly to sensor service after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('Connecting directly to sensor service at ws://localhost:8007/ws')
|
||||||
|
connect('ws://localhost:8007/ws')
|
||||||
|
}, 100)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
newDataBuffer.push(data)
|
newDataBuffer.push(data)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing incoming data:', error)
|
console.error('Error parsing incoming data:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.onclose = () => {
|
socket.onclose = (event) => {
|
||||||
console.log('WebSocket connection closed.')
|
console.log(`WebSocket connection closed. Code: ${event.code}, Reason: ${event.reason}`)
|
||||||
isConnected.value = false
|
isConnected.value = false
|
||||||
socket = null
|
socket = null
|
||||||
}
|
}
|
||||||
@@ -145,7 +196,9 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
socket.onerror = (error) => {
|
socket.onerror = (error) => {
|
||||||
console.error('WebSocket error:', error)
|
console.error('WebSocket error:', error)
|
||||||
isConnected.value = false
|
isConnected.value = false
|
||||||
socket = null
|
if (socket) {
|
||||||
|
socket = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the buffer at intervals
|
// Process the buffer at intervals
|
||||||
@@ -153,11 +206,17 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
if (newDataBuffer.length > 0) {
|
if (newDataBuffer.length > 0) {
|
||||||
const data = newDataBuffer.shift() // Get the oldest data point
|
const data = newDataBuffer.shift() // Get the oldest data point
|
||||||
if (data) {
|
if (data) {
|
||||||
|
// Skip non-data messages (connection establishment, proxy info, etc.)
|
||||||
|
if (data.type && (data.type === 'connection_established' || data.type === 'proxy_info')) {
|
||||||
|
console.log('Received system message:', data.type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Handle both legacy and new data formats
|
// Handle both legacy and new data formats
|
||||||
if (isLegacyData(data)) {
|
if (isLegacyData(data)) {
|
||||||
latestMessage.value = data
|
latestMessage.value = data
|
||||||
updateSensorData(data)
|
updateSensorData(data)
|
||||||
|
|
||||||
// Update time series for chart
|
// Update time series for chart
|
||||||
const newLabel = new Date(data.timestamp * 1000).toLocaleTimeString()
|
const newLabel = new Date(data.timestamp * 1000).toLocaleTimeString()
|
||||||
timeSeriesData.labels.push(newLabel)
|
timeSeriesData.labels.push(newLabel)
|
||||||
@@ -165,7 +224,7 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
} else {
|
} else {
|
||||||
// Handle new multi-metric data
|
// Handle new multi-metric data
|
||||||
updateRoomData(data)
|
updateRoomData(data)
|
||||||
|
|
||||||
// Update time series for chart (use energy values)
|
// Update time series for chart (use energy values)
|
||||||
const newLabel = new Date(data.timestamp * 1000).toLocaleTimeString()
|
const newLabel = new Date(data.timestamp * 1000).toLocaleTimeString()
|
||||||
timeSeriesData.labels.push(newLabel)
|
timeSeriesData.labels.push(newLabel)
|
||||||
@@ -426,18 +485,67 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Room management functions
|
// Room management functions
|
||||||
|
const loadRoomsFromAPI = async (): Promise<void> => {
|
||||||
|
if (roomsLoading.value || roomsLoaded.value) {
|
||||||
|
return // Already loading or loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
roomsLoading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to load from microservices API first
|
||||||
|
const response = await fetch('/api/v1/rooms/names')
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json()
|
||||||
|
if (data.rooms && Array.isArray(data.rooms)) {
|
||||||
|
availableRooms.value = data.rooms.sort()
|
||||||
|
roomsLoaded.value = true
|
||||||
|
console.log('Loaded rooms from microservices API:', data.rooms.length)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: try direct sensor service connection
|
||||||
|
const directResponse = await fetch('http://localhost:8007/rooms/names')
|
||||||
|
|
||||||
|
if (directResponse.ok) {
|
||||||
|
const data = await directResponse.json()
|
||||||
|
if (data.rooms && Array.isArray(data.rooms)) {
|
||||||
|
availableRooms.value = data.rooms.sort()
|
||||||
|
roomsLoaded.value = true
|
||||||
|
console.log('Loaded rooms from sensor service:', data.rooms.length)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both fail, use empty list and log warning
|
||||||
|
console.warn('Failed to load rooms from API, starting with empty list')
|
||||||
|
availableRooms.value = []
|
||||||
|
roomsLoaded.value = true
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading rooms:', error)
|
||||||
|
// Start with empty list on error
|
||||||
|
availableRooms.value = []
|
||||||
|
roomsLoaded.value = true
|
||||||
|
} finally {
|
||||||
|
roomsLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addRoom(roomName: string): boolean {
|
function addRoom(roomName: string): boolean {
|
||||||
if (!roomName.trim()) return false
|
if (!roomName.trim()) return false
|
||||||
|
|
||||||
// Check if room already exists
|
// Check if room already exists
|
||||||
if (availableRooms.value.includes(roomName.trim())) {
|
if (availableRooms.value.includes(roomName.trim())) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add room to available rooms list
|
// Add room to available rooms list
|
||||||
availableRooms.value.push(roomName.trim())
|
availableRooms.value.push(roomName.trim())
|
||||||
availableRooms.value.sort() // Keep rooms sorted alphabetically
|
availableRooms.value.sort() // Keep rooms sorted alphabetically
|
||||||
|
|
||||||
console.log(`Added new room: ${roomName}`)
|
console.log(`Added new room: ${roomName}`)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -487,10 +595,178 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API Integration Functions
|
||||||
|
async function handleApiCall<T>(apiCall: () => Promise<T>): Promise<T | null> {
|
||||||
|
apiLoading.value = true
|
||||||
|
apiError.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await apiCall()
|
||||||
|
return result
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'
|
||||||
|
|
||||||
|
// Handle authentication errors
|
||||||
|
if (errorMessage.includes('401') || errorMessage.includes('Authorization')) {
|
||||||
|
console.warn('Authentication error detected, attempting to re-authenticate...')
|
||||||
|
|
||||||
|
// Try to get fresh auth token
|
||||||
|
try {
|
||||||
|
const authStore = (window as any).__AUTH_STORE__
|
||||||
|
if (authStore && typeof authStore.ensureAuthenticated === 'function') {
|
||||||
|
const authSuccess = await authStore.ensureAuthenticated()
|
||||||
|
if (authSuccess) {
|
||||||
|
console.log('Re-authentication successful, retrying API call...')
|
||||||
|
// Retry the original API call
|
||||||
|
try {
|
||||||
|
const retryResult = await apiCall()
|
||||||
|
return retryResult
|
||||||
|
} catch (retryError) {
|
||||||
|
const retryErrorMessage = retryError instanceof Error ? retryError.message : 'Retry failed'
|
||||||
|
apiError.value = retryErrorMessage
|
||||||
|
console.error('API retry failed:', retryErrorMessage)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (authError) {
|
||||||
|
console.error('Re-authentication failed:', authError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiError.value = errorMessage
|
||||||
|
console.error('API call failed:', errorMessage)
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
apiLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sensors API functions
|
||||||
|
async function fetchApiSensors(params?: { room?: string; sensor_type?: any; status?: any }) {
|
||||||
|
const result = await handleApiCall(() => sensorsApi.getSensors(params))
|
||||||
|
if (result) {
|
||||||
|
apiSensors.value = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchApiSensorData(
|
||||||
|
sensorId: string,
|
||||||
|
params?: { start_time?: number; end_time?: number; limit?: number; offset?: number }
|
||||||
|
) {
|
||||||
|
return handleApiCall(() => sensorsApi.getSensorData(sensorId, params))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateApiSensorMetadata(sensorId: string, metadata: Record<string, any>) {
|
||||||
|
return handleApiCall(() => sensorsApi.updateSensorMetadata(sensorId, metadata))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteApiSensor(sensorId: string) {
|
||||||
|
return handleApiCall(() => sensorsApi.deleteSensor(sensorId))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportApiData(params: {
|
||||||
|
start_time: number
|
||||||
|
end_time: number
|
||||||
|
sensor_ids?: string
|
||||||
|
format?: 'json' | 'csv'
|
||||||
|
}) {
|
||||||
|
return handleApiCall(() => sensorsApi.exportData(params))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rooms API functions
|
||||||
|
async function fetchApiRooms() {
|
||||||
|
const result = await handleApiCall(() => roomsApi.getRooms())
|
||||||
|
if (result) {
|
||||||
|
apiRooms.value = result
|
||||||
|
// Update available rooms from API data
|
||||||
|
const roomNames = result.map(room => room.room).filter(name => name)
|
||||||
|
if (roomNames.length > 0) {
|
||||||
|
availableRooms.value = [...new Set([...availableRooms.value, ...roomNames])].sort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchApiRoomData(
|
||||||
|
roomName: string,
|
||||||
|
params?: { start_time?: number; end_time?: number; limit?: number }
|
||||||
|
) {
|
||||||
|
return handleApiCall(() => roomsApi.getRoomData(roomName, params))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analytics API functions
|
||||||
|
async function fetchAnalyticsSummary(hours: number = 24) {
|
||||||
|
const result = await handleApiCall(() => analyticsApi.getAnalyticsSummary(hours))
|
||||||
|
if (result) {
|
||||||
|
analyticsData.value.summary = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchEnergyTrends(hours: number = 168) {
|
||||||
|
const result = await handleApiCall(() => analyticsApi.getEnergyTrends(hours))
|
||||||
|
if (result) {
|
||||||
|
analyticsData.value.trends = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchRoomComparison(hours: number = 24) {
|
||||||
|
const result = await handleApiCall(() => analyticsApi.getRoomComparison(hours))
|
||||||
|
if (result) {
|
||||||
|
analyticsData.value.roomComparison = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchSystemEvents(params?: {
|
||||||
|
severity?: string
|
||||||
|
event_type?: string
|
||||||
|
hours?: number
|
||||||
|
limit?: number
|
||||||
|
}) {
|
||||||
|
return handleApiCall(() => analyticsApi.getEvents(params))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Health API functions
|
||||||
|
async function fetchSystemStatus() {
|
||||||
|
const result = await handleApiCall(() => healthApi.getStatus())
|
||||||
|
if (result) {
|
||||||
|
systemStatus.value = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchHealthStatus() {
|
||||||
|
const result = await handleApiCall(() => healthApi.getHealth())
|
||||||
|
if (result) {
|
||||||
|
healthStatus.value = result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize data from APIs
|
||||||
|
async function initializeFromApi() {
|
||||||
|
await Promise.allSettled([
|
||||||
|
loadRoomsFromAPI(), // Load room names first
|
||||||
|
fetchApiSensors(),
|
||||||
|
fetchApiRooms(),
|
||||||
|
fetchAnalyticsSummary(),
|
||||||
|
fetchSystemStatus(),
|
||||||
|
fetchHealthStatus()
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize mock sensors on store creation
|
// Initialize mock sensors on store creation
|
||||||
initializeMockSensors()
|
initializeMockSensors()
|
||||||
|
|
||||||
|
// Load rooms from API on store initialization
|
||||||
|
loadRoomsFromAPI()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
// WebSocket state
|
||||||
isConnected,
|
isConnected,
|
||||||
latestMessage,
|
latestMessage,
|
||||||
timeSeriesData,
|
timeSeriesData,
|
||||||
@@ -499,6 +775,19 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
latestReadings,
|
latestReadings,
|
||||||
sensorDevices,
|
sensorDevices,
|
||||||
availableRooms,
|
availableRooms,
|
||||||
|
roomsLoading,
|
||||||
|
roomsLoaded,
|
||||||
|
|
||||||
|
// API state
|
||||||
|
apiSensors,
|
||||||
|
apiRooms,
|
||||||
|
analyticsData,
|
||||||
|
systemStatus,
|
||||||
|
healthStatus,
|
||||||
|
apiLoading,
|
||||||
|
apiError,
|
||||||
|
|
||||||
|
// WebSocket functions
|
||||||
connect,
|
connect,
|
||||||
disconnect,
|
disconnect,
|
||||||
getCO2Status,
|
getCO2Status,
|
||||||
@@ -506,9 +795,26 @@ export const useEnergyStore = defineStore('energy', () => {
|
|||||||
executeSensorAction,
|
executeSensorAction,
|
||||||
getSensorsByRoom,
|
getSensorsByRoom,
|
||||||
getSensorsByType,
|
getSensorsByType,
|
||||||
|
loadRoomsFromAPI,
|
||||||
addRoom,
|
addRoom,
|
||||||
removeRoom,
|
removeRoom,
|
||||||
getRoomStats,
|
getRoomStats,
|
||||||
getAllRoomsWithStats
|
getAllRoomsWithStats,
|
||||||
|
|
||||||
|
// API functions
|
||||||
|
fetchApiSensors,
|
||||||
|
fetchApiSensorData,
|
||||||
|
updateApiSensorMetadata,
|
||||||
|
deleteApiSensor,
|
||||||
|
exportApiData,
|
||||||
|
fetchApiRooms,
|
||||||
|
fetchApiRoomData,
|
||||||
|
fetchAnalyticsSummary,
|
||||||
|
fetchEnergyTrends,
|
||||||
|
fetchRoomComparison,
|
||||||
|
fetchSystemEvents,
|
||||||
|
fetchSystemStatus,
|
||||||
|
fetchHealthStatus,
|
||||||
|
initializeFromApi
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -24,7 +24,10 @@
|
|||||||
<!-- Filters -->
|
<!-- Filters -->
|
||||||
<div class="flex flex-col sm:flex-row gap-4 flex-1">
|
<div class="flex flex-col sm:flex-row gap-4 flex-1">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<select v-model="selectedRoom" class="px-4 py-2 border border-gray-200 rounded-lg bg-white flex-1">
|
<select
|
||||||
|
v-model="selectedRoom"
|
||||||
|
class="px-4 py-2 border border-gray-200 rounded-lg bg-white flex-1"
|
||||||
|
>
|
||||||
<option value="">All Rooms</option>
|
<option value="">All Rooms</option>
|
||||||
<option v-for="room in energyStore.availableRooms" :key="room" :value="room">
|
<option v-for="room in energyStore.availableRooms" :key="room" :value="room">
|
||||||
{{ room }}
|
{{ room }}
|
||||||
@@ -36,7 +39,12 @@
|
|||||||
title="Manage Rooms"
|
title="Manage Rooms"
|
||||||
>
|
>
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="hidden sm:inline">Rooms</span>
|
<span class="hidden sm:inline">Rooms</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -201,10 +209,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Room Management Modal -->
|
<!-- Room Management Modal -->
|
||||||
<RoomManagementModal
|
<RoomManagementModal v-if="showRoomManagementModal" @close="showRoomManagementModal = false" />
|
||||||
v-if="showRoomManagementModal"
|
|
||||||
@close="showRoomManagementModal = false"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -360,7 +365,7 @@ const getOccupancyColor = (occupancy: string) => {
|
|||||||
// WebSocket connection for real-time updates
|
// WebSocket connection for real-time updates
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!energyStore.isConnected) {
|
if (!energyStore.isConnected) {
|
||||||
energyStore.connect('ws://192.168.1.73:8000/ws')
|
energyStore.connect('ws://localhost:8000/ws')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user