mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 10:23:41 +00:00
Improve polling indicator with service-level communication state
Previously, isPolling was manually set in individual refresh functions, which didn't cover all BLE communication and could have race conditions. Now the communication indicator is driven by the service layer: - Added isCommunicating state to BrotherPP1Service - setCommunicating() called at queue processing boundaries - onCommunicationChange() callback subscription pattern - Hook subscribes to service communication state automatically Benefits: - Indicator shows for ALL BLE commands (status, progress, service count, etc) - Prevents race conditions from overlapping command queue processing - More accurate representation of actual BLE communication - Cleaner code - no manual setIsPolling in each function The indicator now properly shows whenever the command queue is being processed, regardless of which specific command triggered it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
37f80051e0
commit
b7ea024df3
2 changed files with 59 additions and 7 deletions
|
|
@ -27,7 +27,7 @@ export function useBrotherMachine() {
|
||||||
);
|
);
|
||||||
const [uploadProgress, setUploadProgress] = useState<number>(0);
|
const [uploadProgress, setUploadProgress] = useState<number>(0);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isPolling, setIsPolling] = useState(false);
|
const [isCommunicating, setIsCommunicating] = useState(false);
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
const [resumeAvailable, setResumeAvailable] = useState(false);
|
const [resumeAvailable, setResumeAvailable] = useState(false);
|
||||||
|
|
@ -36,6 +36,12 @@ export function useBrotherMachine() {
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Subscribe to service communication state
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = service.onCommunicationChange(setIsCommunicating);
|
||||||
|
return unsubscribe;
|
||||||
|
}, [service]);
|
||||||
|
|
||||||
// Define checkResume first (before connect uses it)
|
// Define checkResume first (before connect uses it)
|
||||||
const checkResume = useCallback(async (): Promise<PesPatternData | null> => {
|
const checkResume = useCallback(async (): Promise<PesPatternData | null> => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -133,14 +139,11 @@ export function useBrotherMachine() {
|
||||||
if (!isConnected) return;
|
if (!isConnected) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsPolling(true);
|
|
||||||
const state = await service.getMachineState();
|
const state = await service.getMachineState();
|
||||||
setMachineStatus(state.status);
|
setMachineStatus(state.status);
|
||||||
setMachineError(state.error);
|
setMachineError(state.error);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : "Failed to get status");
|
setError(err instanceof Error ? err.message : "Failed to get status");
|
||||||
} finally {
|
|
||||||
setIsPolling(false);
|
|
||||||
}
|
}
|
||||||
}, [service, isConnected]);
|
}, [service, isConnected]);
|
||||||
|
|
||||||
|
|
@ -168,6 +171,22 @@ export function useBrotherMachine() {
|
||||||
}
|
}
|
||||||
}, [service, isConnected]);
|
}, [service, isConnected]);
|
||||||
|
|
||||||
|
const refreshServiceCount = useCallback(async () => {
|
||||||
|
if (!isConnected || !machineInfo) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const counts = await service.getServiceCount();
|
||||||
|
setMachineInfo({
|
||||||
|
...machineInfo,
|
||||||
|
serviceCount: counts.serviceCount,
|
||||||
|
totalCount: counts.totalCount,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// Don't set error for service count failures - it's not critical
|
||||||
|
console.warn("Failed to get service count:", err);
|
||||||
|
}
|
||||||
|
}, [service, isConnected, machineInfo]);
|
||||||
|
|
||||||
const loadCachedPattern =
|
const loadCachedPattern =
|
||||||
useCallback(async (): Promise<{ pesData: PesPatternData; patternOffset?: { x: number; y: number } } | null> => {
|
useCallback(async (): Promise<{ pesData: PesPatternData; patternOffset?: { x: number; y: number } } | null> => {
|
||||||
if (!resumeAvailable) return null;
|
if (!resumeAvailable) return null;
|
||||||
|
|
@ -349,8 +368,16 @@ export function useBrotherMachine() {
|
||||||
}
|
}
|
||||||
}, pollInterval);
|
}, pollInterval);
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
// Separate interval for service count (slower update rate - every 10 seconds)
|
||||||
}, [isConnected, machineStatus, refreshStatus, refreshProgress]);
|
const serviceCountInterval = setInterval(async () => {
|
||||||
|
await refreshServiceCount();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
clearInterval(serviceCountInterval);
|
||||||
|
};
|
||||||
|
}, [isConnected, machineStatus, refreshStatus, refreshProgress, refreshServiceCount]);
|
||||||
|
|
||||||
// Refresh pattern info when status changes to SEWING_WAIT
|
// Refresh pattern info when status changes to SEWING_WAIT
|
||||||
// (indicates pattern was just uploaded or is ready)
|
// (indicates pattern was just uploaded or is ready)
|
||||||
|
|
@ -372,7 +399,7 @@ export function useBrotherMachine() {
|
||||||
sewingProgress,
|
sewingProgress,
|
||||||
uploadProgress,
|
uploadProgress,
|
||||||
error,
|
error,
|
||||||
isPolling,
|
isPolling: isCommunicating,
|
||||||
isUploading,
|
isUploading,
|
||||||
isDeleting,
|
isDeleting,
|
||||||
resumeAvailable,
|
resumeAvailable,
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,29 @@ export class BrotherPP1Service {
|
||||||
private readCharacteristic: BluetoothRemoteGATTCharacteristic | null = null;
|
private readCharacteristic: BluetoothRemoteGATTCharacteristic | null = null;
|
||||||
private commandQueue: Array<() => Promise<void>> = [];
|
private commandQueue: Array<() => Promise<void>> = [];
|
||||||
private isProcessingQueue = false;
|
private isProcessingQueue = false;
|
||||||
|
private isCommunicating = false;
|
||||||
|
private communicationCallbacks: Set<(isCommunicating: boolean) => void> = new Set();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to communication state changes
|
||||||
|
* @param callback Function called when communication state changes
|
||||||
|
* @returns Unsubscribe function
|
||||||
|
*/
|
||||||
|
onCommunicationChange(callback: (isCommunicating: boolean) => void): () => void {
|
||||||
|
this.communicationCallbacks.add(callback);
|
||||||
|
// Immediately call with current state
|
||||||
|
callback(this.isCommunicating);
|
||||||
|
return () => {
|
||||||
|
this.communicationCallbacks.delete(callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private setCommunicating(value: boolean) {
|
||||||
|
if (this.isCommunicating !== value) {
|
||||||
|
this.isCommunicating = value;
|
||||||
|
this.communicationCallbacks.forEach(callback => callback(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async connect(): Promise<void> {
|
async connect(): Promise<void> {
|
||||||
this.device = await navigator.bluetooth.requestDevice({
|
this.device = await navigator.bluetooth.requestDevice({
|
||||||
|
|
@ -103,6 +126,7 @@ export class BrotherPP1Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isProcessingQueue = true;
|
this.isProcessingQueue = true;
|
||||||
|
this.setCommunicating(true);
|
||||||
|
|
||||||
while (this.commandQueue.length > 0) {
|
while (this.commandQueue.length > 0) {
|
||||||
const command = this.commandQueue.shift();
|
const command = this.commandQueue.shift();
|
||||||
|
|
@ -117,6 +141,7 @@ export class BrotherPP1Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isProcessingQueue = false;
|
this.isProcessingQueue = false;
|
||||||
|
this.setCommunicating(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue