Update camera management and MQTT logging for improved functionality
- Changed log level in configuration from WARNING to INFO for better visibility of system operations. - Enhanced StandaloneAutoRecorder initialization to accept camera manager, state manager, and event system for improved modularity. - Updated recording routes to handle optional request bodies and improved error logging for better debugging. - Added checks in CameraMonitor to determine if a camera is already in use before initialization, enhancing resource management. - Improved MQTT client logging to provide more detailed connection and message handling information. - Added new MQTT event handling capabilities to the VisionApiClient for better tracking of machine states.
This commit is contained in:
@@ -197,8 +197,9 @@ export const CameraCard: React.FC<CameraCardProps> = ({
|
||||
onClick={() => onStopStreaming(cameraName)}
|
||||
className="flex items-center justify-center px-3 py-2 text-sm font-medium text-white bg-orange-600 rounded-lg hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2 transition-colors"
|
||||
title="Stop streaming"
|
||||
style={{ backgroundColor: '#ea580c', color: '#ffffff' }}
|
||||
>
|
||||
<svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24">
|
||||
<svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" strokeWidth={2} viewBox="0 0 24 24" style={{ color: '#ffffff' }}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
@@ -211,9 +212,10 @@ export const CameraCard: React.FC<CameraCardProps> = ({
|
||||
<button
|
||||
onClick={() => onRestart(cameraName)}
|
||||
className="w-full px-4 py-2 text-sm font-medium text-white bg-orange-600 rounded-lg hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2 transition-colors"
|
||||
style={{ backgroundColor: '#ea580c', color: '#ffffff' }}
|
||||
>
|
||||
<span className="flex items-center justify-center">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<span className="flex items-center justify-center" style={{ color: '#ffffff' }}>
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" style={{ color: '#ffffff' }}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
Restart Camera
|
||||
|
||||
@@ -85,6 +85,21 @@ export interface MqttStatus {
|
||||
uptime_seconds: number
|
||||
}
|
||||
|
||||
export interface MqttEvent {
|
||||
machine_name: string
|
||||
topic: string
|
||||
payload: string
|
||||
normalized_state: string
|
||||
timestamp: string
|
||||
message_number: number
|
||||
}
|
||||
|
||||
export interface MqttEventsResponse {
|
||||
events: MqttEvent[]
|
||||
total_events: number
|
||||
last_updated: string | null
|
||||
}
|
||||
|
||||
export interface StartRecordingResponse {
|
||||
success: boolean
|
||||
message: string
|
||||
@@ -220,6 +235,10 @@ class VisionApiClient {
|
||||
return this.request('/mqtt/status')
|
||||
}
|
||||
|
||||
async getMqttEvents(limit: number = 50): Promise<MqttEventsResponse> {
|
||||
return this.request(`/mqtt/events?limit=${limit}`)
|
||||
}
|
||||
|
||||
async startRecording(cameraName: string, filename?: string): Promise<StartRecordingResponse> {
|
||||
return this.request(`/cameras/${cameraName}/start-recording`, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -1,25 +1,57 @@
|
||||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { StatusWidget } from './StatusWidget'
|
||||
import type { SystemStatus } from '../services/api'
|
||||
import { visionApi, type SystemStatus, type MqttEvent } from '../services/api'
|
||||
|
||||
interface MqttStatusWidgetProps {
|
||||
systemStatus: SystemStatus | null
|
||||
}
|
||||
|
||||
export const MqttStatusWidget: React.FC<MqttStatusWidgetProps> = ({ systemStatus }) => {
|
||||
const [lastEvent, setLastEvent] = useState<MqttEvent | null>(null)
|
||||
const isConnected = systemStatus?.mqtt_connected ?? false
|
||||
const lastMessage = systemStatus?.last_mqtt_message
|
||||
|
||||
// Fetch the last MQTT event
|
||||
useEffect(() => {
|
||||
const fetchLastEvent = async () => {
|
||||
try {
|
||||
const eventsData = await visionApi.getMqttEvents(1).catch(() => null)
|
||||
if (eventsData && eventsData.events.length > 0) {
|
||||
setLastEvent(eventsData.events[0])
|
||||
}
|
||||
} catch (error) {
|
||||
// Silently fail - don't clutter console
|
||||
}
|
||||
}
|
||||
|
||||
fetchLastEvent()
|
||||
// Refresh every 5 seconds
|
||||
const interval = setInterval(fetchLastEvent, 5000)
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
const formatLastEvent = () => {
|
||||
if (!lastEvent) return null
|
||||
|
||||
const time = new Date(lastEvent.timestamp).toLocaleTimeString()
|
||||
return `${lastEvent.machine_name}: ${lastEvent.normalized_state.toUpperCase()} (${time})`
|
||||
}
|
||||
|
||||
const subtitle = lastEvent
|
||||
? formatLastEvent()
|
||||
: lastMessage
|
||||
? `Last: ${new Date(lastMessage).toLocaleTimeString()}`
|
||||
: 'No messages'
|
||||
|
||||
return (
|
||||
<StatusWidget
|
||||
title="MQTT Status"
|
||||
status={isConnected}
|
||||
statusText={isConnected ? 'Connected' : 'Disconnected'}
|
||||
subtitle={lastMessage ? `Last: ${new Date(lastMessage).toLocaleTimeString()}` : 'No messages'}
|
||||
subtitle={subtitle || undefined}
|
||||
icon={
|
||||
<div className={`w-3 h-3 rounded-full ${isConnected ? 'bg-green-500 animate-pulse' : 'bg-red-500'}`} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user