From 8cea4105eb539e7be0dbdbea4858b055d6d0a622 Mon Sep 17 00:00:00 2001 From: seo Date: Thu, 23 Jul 2026 01:15:41 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B0=B1=EB=9D=BC=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=A6=89=EC=8B=9C=20=EC=A0=81=EC=9A=A9=20=EB=8F=99=EC=9E=91=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- public/api.php | 3 +++ public/assets/app.js | 64 +++++++++++++++++++++++++++++++++----------- public/index.php | 2 +- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ad671de..7f1bace 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ API 응답의 `battery.enabled`는 false, `battery.removed`는 true로 내려가 - 팬 이상감지: 기준 표본 수, 최신 표본 제외 수, RPM/온도 이상 감지 차이, RPM/온도 복구 차이, RPM 감시 시작 PWM, alert 유지 중 반복 기록, 반복 기록 간격, 하강 변화 원인 후보 표시 여부 - UPS/배터리 설정: 현재 UPS 제거 상태에서는 설정 모달에서 숨겨지고, `battery.enabled=true`일 때만 배터리 예측 항목을 노출합니다. -디스플레이 회전/터치 좌표 설정은 DB가 아니라 라즈베리파이 부팅 파일에 저장합니다. 저장 전 기존 파일을 `.control-YYYYMMDD-HHMMSS.bak` 형식으로 백업하고, 변경 사항은 재부팅 후 적용됩니다. 구형 정품 7인치 Touch Display의 콘솔 회전은 `cmdline.txt`의 `video=DSI-1:800x480@60,rotate=...`를 사용하며, 터치 좌표 보정이 필요하면 `config.txt`의 `vc4-kms-dsi-7inch` overlay로 전환합니다. 백라이트 밝기와 백라이트 전원은 `/sys/class/backlight` 장치를 통해 즉시 적용되며 재부팅이 필요 없습니다. +디스플레이 회전/터치 좌표 설정은 DB가 아니라 라즈베리파이 부팅 파일에 저장합니다. 저장 전 기존 파일을 `.control-YYYYMMDD-HHMMSS.bak` 형식으로 백업하고, 변경 사항은 재부팅 후 적용됩니다. 구형 정품 7인치 Touch Display의 콘솔 회전은 `cmdline.txt`의 `video=DSI-1:800x480@60,rotate=...`를 사용하며, 터치 좌표 보정이 필요하면 `config.txt`의 `vc4-kms-dsi-7inch` overlay로 전환합니다. 백라이트 밝기와 백라이트 전원은 `/sys/class/backlight` 장치를 통해 슬라이더/토글 조작 직후 debounce 후 즉시 적용되며 재부팅이 필요 없습니다. 백라이트 전원을 끄면 brightness도 0으로 함께 맞춰 상태 일관성을 유지합니다. 설정 모달이 열려 있는 동안 1초 상태 갱신은 폼 DOM을 다시 만들지 않습니다. 입력 중인 값은 저장, 기본값 초기화, 닫기 전까지 유지되며, 백그라운드 snapshot은 내부 설정 payload만 갱신합니다. 단순 boolean 설정은 `켜기`/`끄기` 세그먼트로 표시합니다. diff --git a/public/api.php b/public/api.php index d7e5049..ab0417e 100644 --- a/public/api.php +++ b/public/api.php @@ -3700,6 +3700,9 @@ function touch_display_set_runtime(array $input): array $maxBrightness = touch_display_read_int($backlightPath . '/max_brightness') ?? 255; $brightness = max(0, min($maxBrightness, (int)($input['brightness'] ?? $maxBrightness))); $enabled = touch_display_bool($input['backlight_enabled'] ?? '1'); + if (!$enabled) { + $brightness = 0; + } touch_display_write_value($backlightPath . '/brightness', (string)$brightness); if (is_writable($backlightPath . '/bl_power') || is_readable($backlightPath . '/bl_power')) { diff --git a/public/assets/app.js b/public/assets/app.js index 4084247..e1ad980 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -70,6 +70,9 @@ fanApplying: false, fanApplyTimer: null, fanApplyPending: null, + touchRuntimeApplying: false, + touchRuntimeTimer: null, + touchRuntimePending: null, latestFanPwm: 0, fanCauseTick: 0, dmesgOpen: false, @@ -208,8 +211,6 @@ touchBacklight: 'Backlight', touchBrightness: 'Brightness', touchBacklightEnabled: 'Backlight power', - touchRuntimeSave: 'Apply brightness now', - touchRuntimeSaved: 'Brightness applied.', touchDisplayOverlay: 'Manual overlay', touchDisplayAutoDetect: 'Auto detect', touchDisplayEnabled: 'LCD output', @@ -384,8 +385,6 @@ touchBacklight: '백라이트', touchBrightness: '밝기', touchBacklightEnabled: '백라이트 전원', - touchRuntimeSave: '밝기 즉시 적용', - touchRuntimeSaved: '밝기를 적용했습니다.', touchDisplayOverlay: '수동 overlay', touchDisplayAutoDetect: '자동 감지', touchDisplayEnabled: 'LCD 출력', @@ -768,10 +767,6 @@ ${numberField('touch_sizex', t('touchSizeX'), config.touch_sizex || 800, 100, 4096)} ${numberField('touch_sizey', t('touchSizeY'), config.touch_sizey || 480, 100, 4096)} -
- - /boot/firmware/config.txt, /boot/firmware/cmdline.txt -
${backlight.available ? `

${escapeHtml(t('touchBacklight'))}

@@ -784,12 +779,12 @@
${checkboxField('backlight_enabled', t('touchBacklightEnabled'), backlight.enabled !== false).replaceAll('data-display-key', 'data-display-runtime-key')} -
- - ${escapeHtml(backlight.path || '')} -
` : ''} +
+ + /boot/firmware/config.txt, /boot/firmware/cmdline.txt +
`; } @@ -907,13 +902,29 @@ }); }); $('#touchDisplaySave', els.settingsBody)?.addEventListener('click', saveTouchDisplaySettings); - $('#touchRuntimeSave', els.settingsBody)?.addEventListener('click', saveTouchDisplayRuntime); const brightnessSlider = els.settingsBody.querySelector('[data-display-runtime-key="brightness"]'); const brightnessValue = $('#touchBrightnessValue', els.settingsBody); brightnessSlider?.addEventListener('input', () => { if (brightnessValue) { brightnessValue.textContent = `${brightnessSlider.value} / ${brightnessSlider.max}`; } + scheduleTouchDisplayRuntimeApply(); + }); + brightnessSlider?.addEventListener('change', scheduleTouchDisplayRuntimeApply); + const backlightToggle = els.settingsBody.querySelector('[data-display-runtime-key="backlight_enabled"]'); + backlightToggle?.addEventListener('change', () => { + if (!backlightToggle.checked && brightnessSlider) { + brightnessSlider.value = '0'; + if (brightnessValue) { + brightnessValue.textContent = `0 / ${brightnessSlider.max}`; + } + } else if (backlightToggle.checked && brightnessSlider && Number(brightnessSlider.value) <= 0) { + brightnessSlider.value = brightnessSlider.max || '255'; + if (brightnessValue) { + brightnessValue.textContent = `${brightnessSlider.value} / ${brightnessSlider.max}`; + } + } + scheduleTouchDisplayRuntimeApply(); }); } @@ -972,6 +983,9 @@ ? (input.checked ? '1' : '0') : input.value; }); + if (values.backlight_enabled === '0') { + values.brightness = '0'; + } return values; } @@ -994,18 +1008,36 @@ } } - async function saveTouchDisplayRuntime() { + function scheduleTouchDisplayRuntimeApply(values = currentTouchDisplayRuntimeValues()) { + clearTimeout(state.touchRuntimeTimer); + state.touchRuntimeTimer = setTimeout(() => { + applyTouchDisplayRuntime(values); + }, 150); + } + + async function applyTouchDisplayRuntime(values = currentTouchDisplayRuntimeValues()) { + if (state.touchRuntimeApplying) { + state.touchRuntimePending = values; + return; + } + try { + state.touchRuntimeApplying = true; const data = await api('touch_display_runtime_save', { - runtime: JSON.stringify(currentTouchDisplayRuntimeValues()), + runtime: JSON.stringify(values), }); state.settingsDirty = false; + state.touchRuntimeApplying = false; render(data); renderSettings(data.settings, { force: true }); - notice(t('touchRuntimeSaved'), 'success'); } catch (e) { console.error(e); notice(e.message || t('settingsSaveFailed'), 'error'); + } finally { + state.touchRuntimeApplying = false; + const pending = state.touchRuntimePending; + state.touchRuntimePending = null; + if (pending) applyTouchDisplayRuntime(pending); } } diff --git a/public/index.php b/public/index.php index b676a16..4afdf10 100644 --- a/public/index.php +++ b/public/index.php @@ -365,7 +365,7 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da} - +