import React, { useState, useEffect, useRef } from 'react'; import { changeWeightScalePort, changeWeightScaleWeight, GlobalWeightScalePort } from '../../Features/BookingScreen/BookingData/BookingData'; import { useDispatch } from 'react-redux'; import { useSelector } from 'react-redux'; const WeightScaleApp = ({ weightscaleclose }) => { const dispatch = useDispatch(); const weightscaleport = useSelector(GlobalWeightScalePort) const [weight, setWeight] = useState(null); const [connected, setConnected] = useState(false); const [serviceRunning, setServiceRunning] = useState(false); const [history, setHistory] = useState([]); const wsRef = useRef(null); const reconnectTimeoutRef = useRef(null); const connectionAttempts = useRef(0); const shouldReconnect = useRef(true); const isConnecting = useRef(false); const pollIntervalRef = useRef(null); const lastStableWeightRef = useRef(null); const WS_URL = 'ws://localhost:8080'; const CONTROL_URL = 'http://localhost:8081'; useEffect(() => { // Quick initial check and connect checkAndConnect(); return () => { shouldReconnect.current = false; if (wsRef.current) wsRef.current.close(); if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current); if (pollIntervalRef.current) clearInterval(pollIntervalRef.current); }; }, []); useEffect(() => { if (weightscaleport) { startService(); } else{ stopService(); } }, [weightscaleport]); // useEffect(() => { // if (!connected) { // weightscaleclose(false); // } // }, [connected]); const checkAndConnect = async () => { // Quick non-blocking status check checkServiceStatus().then(status => { if (status?.running) { setServiceRunning(true); shouldReconnect.current = true; // Connect immediately setTimeout(() => connectWebSocket(), 50); } }); }; const checkServiceStatus = async () => { try { const controller = new AbortController(); setTimeout(() => controller.abort(), 800); // Fast timeout const response = await fetch(`${CONTROL_URL}/status`, { signal: controller.signal }); const data = await response.json(); setServiceRunning(data.running); return data; } catch (error) { return null; } }; const openAndroidApp = () => { try { const scheme = 'pozoprinter'; const packageName = 'com.example.pozoprinter'; window.location.href = `${scheme}://#Intent;scheme=${scheme};package=${packageName}NewConfigCheckSWeightScaleNewConfigCheckEServiceConditionSstartServiceConditionE;end;`; } catch (e) { console.error('Failed to open Android app', e); } }; const startService = async () => { // Immediate UI response shouldReconnect.current = true; // Clean up immediately if (wsRef.current) { wsRef.current.close(); wsRef.current = null; } if (reconnectTimeoutRef.current) { clearTimeout(reconnectTimeoutRef.current); reconnectTimeoutRef.current = null; } if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } isConnecting.current = false; connectionAttempts.current = 0; // Quick status check (non-blocking) const status = await checkServiceStatus(); if (status?.running) { // Service already running - connect immediately setServiceRunning(true); setTimeout(() => connectWebSocket(), 50); return; } // Try HTTP start (non-blocking, short timeout) try { const controller = new AbortController(); setTimeout(() => controller.abort(), 1000); fetch(`${CONTROL_URL}/start`, { method: 'POST', signal: controller.signal }) .then(res => res.json()) .then(data => { if (data.success) { setServiceRunning(true); setTimeout(() => connectWebSocket(), 200); } else { // HTTP failed, open Android app openAndroidApp(); startPolling(); } }) .catch(() => { // HTTP failed, open Android app openAndroidApp(); startPolling(); }); } catch (error) { openAndroidApp(); startPolling(); } }; const startPolling = () => { // Quick polling to detect when service starts let attempts = 0; pollIntervalRef.current = setInterval(async () => { attempts++; if (attempts > 15) { // 15 seconds max if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } return; } const status = await checkServiceStatus(); if (status?.running) { if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } setServiceRunning(true); setTimeout(() => connectWebSocket(), 100); } }, 1000); }; const stopService = async () => { // Immediate UI response shouldReconnect.current = false; isConnecting.current = false; // Stop polling immediately if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } // Clear reconnection if (reconnectTimeoutRef.current) { clearTimeout(reconnectTimeoutRef.current); reconnectTimeoutRef.current = null; } // Close WebSocket immediately if (wsRef.current) { wsRef.current.close(); wsRef.current = null; } // Update UI immediately setConnected(false); weightscaleclose(false); dispatch(changeWeightScalePort(false)); setWeight(null); dispatch(changeWeightScaleWeight(null)); setServiceRunning(false); connectionAttempts.current = 0; // Send stop request (fire and forget - don't wait) try { const controller = new AbortController(); setTimeout(() => controller.abort(), 500); fetch(`${CONTROL_URL}/stop`, { method: 'POST', signal: controller.signal }).catch(() => {}); } catch (error) {} }; const connectWebSocket = () => { if (isConnecting.current || !shouldReconnect.current) return; if (wsRef.current?.readyState === WebSocket.OPEN || wsRef.current?.readyState === WebSocket.CONNECTING) { return; } if (wsRef.current) { try { wsRef.current.close(); } catch (e) {} wsRef.current = null; } try { isConnecting.current = true; const ws = new WebSocket(WS_URL); wsRef.current = ws; ws.onopen = () => { console.log('✅ Connected'); setConnected(true); setServiceRunning(true); connectionAttempts.current = 0; isConnecting.current = false; if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } if (reconnectTimeoutRef.current) { clearTimeout(reconnectTimeoutRef.current); reconnectTimeoutRef.current = null; } }; ws.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.type === 'weight') { setWeight(data); const w = data?.weight; // Only update global state when the reading is usable const isValidNumber = typeof w === 'number' && !Number.isNaN(w); if ( isValidNumber && data.stable && // <- only when stable w !== lastStableWeightRef.current ) { lastStableWeightRef.current = w; dispatch(changeWeightScaleWeight(w)); } setHistory(prev => [data, ...prev].slice(0, 10)); } else if (data.type === 'status') { setConnected(data.connected); weightscaleclose(data.connected); dispatch(changeWeightScalePort(data.connected)); if (data.running !== undefined) setServiceRunning(data.running); } } catch (error) {} }; ws.onerror = () => { isConnecting.current = false; }; ws.onclose = () => { setConnected(false); weightscaleclose(false); dispatch(changeWeightScalePort(false)); wsRef.current = null; isConnecting.current = false; if (shouldReconnect.current) { connectionAttempts.current++; const delay = Math.min(1000 * Math.pow(1.5, connectionAttempts.current), 5000); reconnectTimeoutRef.current = setTimeout(() => { if (shouldReconnect.current && !isConnecting.current) { connectWebSocket(); } }, delay); } }; } catch (error) { setConnected(false); weightscaleclose(false); dispatch(changeWeightScalePort(false)); wsRef.current = null; isConnecting.current = false; if (shouldReconnect.current) { setTimeout(() => { if (shouldReconnect.current && !isConnecting.current) { connectWebSocket(); } }, 1000); } } }; const formatTime = (timestamp) => { return new Date(timestamp).toLocaleTimeString(); }; return ( <> //
//
//
//

USB Weight Scale

//
//
// // {connected ? 'Connected' : 'Disconnected'} // //
//
//

// WebSocket: {WS_URL} | Control: {CONTROL_URL} //

//
//
//

Service Control

//
// // //
//
// // {serviceRunning ? '● Service Running' : '○ Service Stopped'} // // {connectionAttempts.current > 0 && !connected && ( // // 🔄 Reconnecting... (attempt {connectionAttempts.current}) // // )} //
//
//
// {weight ? ( //
//
// // {weight.weight.toFixed(2)} // // // {weight.unit} // //
//
//
// {weight.stable ? '✓ Stable' : '⋯ Measuring'} //
// // {formatTime(weight.timestamp)} // //
//
// ) : ( //
//
⚖️
//

// {connected // ? 'Place item on scale...' // : serviceRunning // ? 'Connecting...' // : 'Click "Start Service" to begin'} //

//
// )} //
// {history.length > 0 && ( //
//

Recent Readings

//
// {history.map((reading) => ( //
//
// // {reading.weight.toFixed(2)} {reading.unit} // // {reading.stable && ( // // Stable // // )} //
// // {formatTime(reading.timestamp)} // //
// ))} //
//
// )} // {!connected && !serviceRunning && ( //
//

// 🎯 Service Not Running //

//

// Click "Start Service" to connect to the weight scale //

//
    //
  • Service will start automatically
  • //
  • USB scale should be connected to Android device
  • //
  • WebSocket server on port 8080
  • //
//
// )} //
); }; export default WeightScaleApp;