Rework API input CSS: segments, remove led_count, HAOS light, test preview
API Input CSS rework:
- Remove led_count field from ApiInputColorStripSource (always auto-sizes)
- Add segment-based payload: solid, per_pixel, gradient modes
- Segments applied in order (last wins on overlap), auto-grow buffer
- Backward compatible: legacy {"colors": [...]} still works
- Pydantic validation: mode-specific field requirements
Test preview:
- Enable test preview button on api_input cards
- Hide LED/FPS controls for api_input (sender controls those)
- Show input source selector for all CSS tests (preselected)
- FPS sparkline chart using shared createFpsSparkline (same as target cards)
- Server only sends frames when push_generation changes (no idle frames)
HAOS integration:
- New light.py: ApiInputLight entity per api_input source (RGB + brightness)
- turn_on pushes solid segment, turn_off pushes fallback color
- Register wled_screen_controller.set_leds service for arbitrary segments
- New services.yaml with field definitions
- Coordinator: push_colors() and push_segments() methods
- Platform.LIGHT added to platforms list
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -710,6 +710,7 @@ export async function saveTemplate() {
|
||||
|
||||
showToast(templateId ? t('templates.updated') : t('templates.created'), 'success');
|
||||
templateModal.forceClose();
|
||||
captureTemplatesCache.invalidate();
|
||||
await loadCaptureTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error saving template:', error);
|
||||
@@ -729,6 +730,7 @@ export async function deleteTemplate(templateId) {
|
||||
throw new Error(error.detail || error.message || 'Failed to delete template');
|
||||
}
|
||||
showToast(t('templates.deleted'), 'success');
|
||||
captureTemplatesCache.invalidate();
|
||||
await loadCaptureTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error deleting template:', error);
|
||||
@@ -970,6 +972,7 @@ export async function saveAudioTemplate() {
|
||||
|
||||
showToast(templateId ? t('audio_template.updated') : t('audio_template.created'), 'success');
|
||||
audioTemplateModal.forceClose();
|
||||
audioTemplatesCache.invalidate();
|
||||
await loadAudioTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error saving audio template:', error);
|
||||
@@ -989,6 +992,7 @@ export async function deleteAudioTemplate(templateId) {
|
||||
throw new Error(error.detail || error.message || 'Failed to delete audio template');
|
||||
}
|
||||
showToast(t('audio_template.deleted'), 'success');
|
||||
audioTemplatesCache.invalidate();
|
||||
await loadAudioTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error deleting audio template:', error);
|
||||
@@ -2089,6 +2093,7 @@ export async function saveStream() {
|
||||
|
||||
showToast(streamId ? t('streams.updated') : t('streams.created'), 'success');
|
||||
streamModal.forceClose();
|
||||
streamsCache.invalidate();
|
||||
await loadPictureSources();
|
||||
} catch (error) {
|
||||
console.error('Error saving stream:', error);
|
||||
@@ -2108,6 +2113,7 @@ export async function deleteStream(streamId) {
|
||||
throw new Error(error.detail || error.message || 'Failed to delete stream');
|
||||
}
|
||||
showToast(t('streams.deleted'), 'success');
|
||||
streamsCache.invalidate();
|
||||
await loadPictureSources();
|
||||
} catch (error) {
|
||||
console.error('Error deleting stream:', error);
|
||||
@@ -2675,6 +2681,7 @@ export async function savePPTemplate() {
|
||||
|
||||
showToast(templateId ? t('postprocessing.updated') : t('postprocessing.created'), 'success');
|
||||
ppTemplateModal.forceClose();
|
||||
ppTemplatesCache.invalidate();
|
||||
await loadPPTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error saving PP template:', error);
|
||||
@@ -2735,6 +2742,7 @@ export async function deletePPTemplate(templateId) {
|
||||
throw new Error(error.detail || error.message || 'Failed to delete template');
|
||||
}
|
||||
showToast(t('postprocessing.deleted'), 'success');
|
||||
ppTemplatesCache.invalidate();
|
||||
await loadPPTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error deleting PP template:', error);
|
||||
@@ -2888,6 +2896,7 @@ export async function saveCSPT() {
|
||||
|
||||
showToast(templateId ? t('css_processing.updated') : t('css_processing.created'), 'success');
|
||||
csptModal.forceClose();
|
||||
csptCache.invalidate();
|
||||
await loadCSPTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error saving CSPT:', error);
|
||||
@@ -2920,6 +2929,7 @@ export async function deleteCSPT(templateId) {
|
||||
throw new Error(error.detail || error.message || 'Failed to delete template');
|
||||
}
|
||||
showToast(t('css_processing.deleted'), 'success');
|
||||
csptCache.invalidate();
|
||||
await loadCSPTemplates();
|
||||
} catch (error) {
|
||||
console.error('Error deleting CSPT:', error);
|
||||
|
||||
Reference in New Issue
Block a user