Fix LED color events and improve screenshot capture

- Fix LED color publisher: uncomment display_colors_tx.send() to enable LED color events
- Replace rust_swift_screencapture with screen-capture-kit for better macOS compatibility
- Add bounds checking in LED color processing to prevent array index errors
- Update screenshot manager to use CGDisplay as fallback implementation
- Fix frontend screenshot URL protocol to use ambient-light://
- Add debug logging for LED color events in frontend
- Remove debug logs that were added for troubleshooting
- Update dependencies and remove CMake-dependent paho-mqtt temporarily

This resolves the issue where LED color events were not being sent to the frontend,
enabling real-time LED color visualization in the UI.
This commit is contained in:
2025-06-30 14:35:03 +08:00
parent 91983e6728
commit b1fd751090
10 changed files with 1844 additions and 1494 deletions

View File

@ -13,6 +13,7 @@ import {
LedStripConfigurationContextType,
} from '../../contexts/led-strip-configuration.context';
export const LedStripConfiguration = () => {
createEffect(() => {
invoke<string>('list_display_info').then((displays) => {
@ -45,11 +46,17 @@ export const LedStripConfiguration = () => {
// listen to led_colors_changed event
createEffect(() => {
const unlisten = listen<Uint8ClampedArray>('led_colors_changed', (event) => {
console.log('Received led_colors_changed event:', {
hidden: window.document.hidden,
colorsLength: event.payload.length,
firstFewColors: Array.from(event.payload.slice(0, 12))
});
if (!window.document.hidden) {
const colors = event.payload;
setLedStripStore({
colors,
});
console.log('Updated ledStripStore.colors with length:', colors.length);
}
});
@ -61,11 +68,17 @@ export const LedStripConfiguration = () => {
// listen to led_sorted_colors_changed event
createEffect(() => {
const unlisten = listen<Uint8ClampedArray>('led_sorted_colors_changed', (event) => {
console.log('Received led_sorted_colors_changed event:', {
hidden: window.document.hidden,
sortedColorsLength: event.payload.length,
firstFewSortedColors: Array.from(event.payload.slice(0, 12))
});
if (!window.document.hidden) {
const sortedColors = event.payload;
setLedStripStore({
sortedColors,
});
console.log('Updated ledStripStore.sortedColors with length:', sortedColors.length);
}
});

View File

@ -60,15 +60,18 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
);
if (index === -1) {
console.log(`LED strip not found for display ${localProps.config.display_id}, border ${localProps.config.border}`);
return;
}
const mapper = ledStripStore.mappers[index];
if (!mapper) {
console.log(`Mapper not found for index ${index}`);
return;
}
const offset = mapper.pos * 3;
console.log(`Updating LED strip colors for ${localProps.config.border}, offset: ${offset}, colors length: ${ledStripStore.colors.length}`);
const colors = new Array(localProps.config.len).fill(null).map((_, i) => {
const index = offset + i * 3;
@ -77,6 +80,7 @@ export const LedStripPart: Component<LedStripPartProps> = (props) => {
})`;
});
console.log(`Generated ${colors.length} colors for ${localProps.config.border}:`, colors.slice(0, 3));
setColors(colors);
});

View File

@ -1,4 +1,3 @@
import { convertFileSrc } from '@tauri-apps/api/tauri';
import {
Component,
createEffect,
@ -79,26 +78,43 @@ export const ScreenView: Component<ScreenViewProps> = (props) => {
let stopped = false;
const frame = async () => {
const { drawWidth, drawHeight } = drawInfo();
const url = convertFileSrc(
`displays/${localProps.displayId}?width=${drawWidth}&height=${drawHeight}`,
'ambient-light',
);
await fetch(url, {
mode: 'cors',
})
.then((res) => res.body?.getReader().read())
.then((buffer) => {
if (buffer?.value) {
setImageData({
buffer: new Uint8ClampedArray(buffer?.value),
width: drawWidth,
height: drawHeight,
});
} else {
setImageData(null);
}
draw();
// Skip if dimensions are not ready
if (drawWidth <= 0 || drawHeight <= 0) {
console.log('Skipping frame: invalid dimensions', { drawWidth, drawHeight });
return;
}
const url = `ambient-light://displays/${localProps.displayId}?width=${drawWidth}&height=${drawHeight}`;
console.log('Fetching screenshot:', url);
try {
const response = await fetch(url, {
mode: 'cors',
});
if (!response.ok) {
console.error('Screenshot fetch failed:', response.status, response.statusText);
return;
}
const buffer = await response.body?.getReader().read();
if (buffer?.value) {
console.log('Screenshot received, size:', buffer.value.length);
setImageData({
buffer: new Uint8ClampedArray(buffer?.value),
width: drawWidth,
height: drawHeight,
});
} else {
console.log('No screenshot data received');
setImageData(null);
}
draw();
} catch (error) {
console.error('Screenshot fetch error:', error);
}
};
(async () => {
@ -107,7 +123,11 @@ export const ScreenView: Component<ScreenViewProps> = (props) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
continue;
}
await frame();
// Add a small delay to prevent overwhelming the backend
await new Promise((resolve) => setTimeout(resolve, 33)); // ~30 FPS
}
})();
@ -122,9 +142,14 @@ export const ScreenView: Component<ScreenViewProps> = (props) => {
onMount(() => {
setCtx(canvas.getContext('2d'));
new ResizeObserver(() => {
// Initial size setup
resetSize();
resizeObserver = new ResizeObserver(() => {
resetSize();
}).observe(root);
});
resizeObserver.observe(root);
});
onCleanup(() => {