Use native Guition panel configuration and add light card styling
This commit is contained in:
@@ -100,7 +100,7 @@ inline lv_obj_t *plain(lv_obj_t *parent, int x, int y, int w, int h) {
|
||||
lv_obj_set_pos(obj, x, y); lv_obj_set_size(obj, w, h);
|
||||
return obj;
|
||||
}
|
||||
inline void setup(lv_obj_t *parent, const lv_font_t *font, int width, int height) {
|
||||
inline void setup(lv_obj_t *parent, const lv_font_t *font, int width, int height, bool light_theme = false) {
|
||||
if (ready) return;
|
||||
ready = true;
|
||||
bool large = width >= 480;
|
||||
@@ -114,7 +114,7 @@ inline void setup(lv_obj_t *parent, const lv_font_t *font, int width, int height
|
||||
auto &row = rows[i]; row.index = i;
|
||||
row.box = plain(parent, margin, top + i * spacing, w, spacing - 2);
|
||||
lv_obj_set_style_text_font(row.box, font, 0);
|
||||
lv_obj_set_style_text_color(row.box, lv_color_hex(0xEEEEF2), 0);
|
||||
lv_obj_set_style_text_color(row.box, lv_color_hex(light_theme ? 0x1B1B1B : 0xEEEEF2), 0);
|
||||
auto *label = lv_label_create(row.box); lv_label_set_text(label, names[i]);
|
||||
lv_obj_set_pos(label, 2, 0);
|
||||
row.value = lv_label_create(row.box); lv_obj_align(row.value, LV_ALIGN_TOP_RIGHT, -2, 0);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace runtime_tiles {
|
||||
inline bool enabled = false;
|
||||
inline bool light_theme = false;
|
||||
inline Model model;
|
||||
inline int active_index = -1;
|
||||
inline uint32_t last_received = 0;
|
||||
@@ -210,11 +211,14 @@ inline void render(lv_obj_t *room) {
|
||||
if (w.cached_active == static_cast<int>(on)) continue;
|
||||
w.cached_active = on;
|
||||
uint32_t accent = t.domain() == "light" ? 0xE4B23C : t.domain() == "climate" ? 0xF18750 : 0x548BD4;
|
||||
lv_obj_set_style_bg_color(w.tile, lv_color_hex(on ? 0xF5F1E8 : 0x202A38), 0);
|
||||
lv_obj_set_style_bg_color(w.circle, lv_color_hex(on ? accent : 0x303A48), 0);
|
||||
lv_obj_set_style_text_color(w.icon, lv_color_hex(on ? 0xFFFFFF : accent), 0);
|
||||
lv_obj_set_style_text_color(w.title, lv_color_hex(on ? 0x172232 : 0xF3F5F7), 0);
|
||||
lv_obj_set_style_text_color(w.value, lv_color_hex(on ? 0x46525E : 0xAFBAC8), 0);
|
||||
lv_obj_set_style_bg_color(w.tile, lv_color_hex(light_theme ? 0xFFFFFF : (on ? 0xF5F1E8 : 0x526C85)), 0);
|
||||
lv_obj_set_style_border_width(w.tile, 1, 0);
|
||||
lv_obj_set_style_border_opa(w.tile, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_color(w.tile, lv_color_hex(light_theme ? 0xDDDDDD : (on ? 0xF5F1E8 : 0x9CB3C8)), 0);
|
||||
lv_obj_set_style_bg_color(w.circle, lv_color_hex(light_theme ? (on ? 0xD5EEFC : 0xF0F0F0) : (on ? accent : 0x263B50)), 0);
|
||||
lv_obj_set_style_text_color(w.icon, lv_color_hex(light_theme ? (on ? 0x009FE3 : 0x9E9E9E) : (on ? 0x172232 : 0xF3F5F7)), 0);
|
||||
lv_obj_set_style_text_color(w.title, lv_color_hex(light_theme ? 0x1B1B1B : (on ? 0x172232 : 0xF3F5F7)), 0);
|
||||
lv_obj_set_style_text_color(w.value, lv_color_hex(light_theme ? 0x616161 : (on ? 0x46525E : 0xF0F4F8)), 0);
|
||||
}
|
||||
}
|
||||
inline std::string vacuum_option(unsigned index) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Observe a screen over its encrypted API; does not wake it or operate HA devices."""
|
||||
import argparse
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
import time
|
||||
import yaml
|
||||
from aioesphomeapi import APIClient, LogLevel
|
||||
|
||||
async def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--host', required=True)
|
||||
parser.add_argument('--name', required=True)
|
||||
parser.add_argument('--seconds', type=int, default=720)
|
||||
parser.add_argument('--secrets', type=Path, default=Path(__file__).resolve().parents[1] / 'secrets.yaml')
|
||||
args = parser.parse_args()
|
||||
if not 1 <= args.seconds <= 86400:
|
||||
parser.error('--seconds must be between 1 and 86400')
|
||||
key = yaml.safe_load(args.secrets.read_text())['api_encryption_key']
|
||||
client = APIClient(args.host, 6053, noise_psk=key, expected_name=args.name,
|
||||
client_info='Read-only display observation')
|
||||
await client.connect(login=True)
|
||||
try:
|
||||
info = await client.device_info()
|
||||
print(f'Connected: {info.name}, firmware {info.project_version}, {info.compilation_time}', flush=True)
|
||||
_, actions = await client.list_entities_services()
|
||||
state_action = next(action for action in actions if action.name == 'ui_state')
|
||||
def log(message):
|
||||
line = message.message.decode(errors='replace') if isinstance(message.message, bytes) else message.message
|
||||
if '[ui_diag' in line or '[health' in line:
|
||||
print(line, flush=True)
|
||||
client.subscribe_logs(log, log_level=LogLevel.LOG_LEVEL_DEBUG, dump_config=False)
|
||||
end = time.monotonic() + args.seconds
|
||||
while time.monotonic() < end:
|
||||
await client.execute_service(state_action, {})
|
||||
await asyncio.sleep(min(30, max(0, end - time.monotonic())))
|
||||
# Confirms a live API response, not just a local connection flag.
|
||||
await client.device_info()
|
||||
print('Observation completed. Physical display quality still requires visual inspection.', flush=True)
|
||||
finally:
|
||||
await client.disconnect()
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
+6
-4
@@ -6,8 +6,10 @@ ST7701S RGB-display en **GT911 capacitieve touch**, ESP32-S3, 16 MB flash en
|
||||
altijd de elektronica. Dit profiel configureert geen relais.
|
||||
|
||||
Hardwarebron: [ESPHome Guition-bordbeschrijving](https://devices.esphome.io/devices/guition-esp32-s3-4848s040/)
|
||||
en het ingebouwde [MIPI RGB-model](https://esphome.io/components/display/mipi_rgb/).
|
||||
De daadwerkelijk geïnstalleerde ESPHome 2026.6.2 bevat dit model.
|
||||
en de ingebouwde [ST7701S-driver](https://esphome.io/components/display/st7701s/).
|
||||
De paneelconfiguratie volgt de originele, fysiek schoon bevonden fabrikantdemo;
|
||||
zie [de vergelijking](GUITION_FACTORY_REFERENCE.md). Er is geen lokale RGB-driver
|
||||
of periodiek herstel-script nodig. De GT911 gebruikt ongemirrorde coördinaten.
|
||||
|
||||
## Bestanden
|
||||
|
||||
@@ -25,8 +27,8 @@ geen `calibration.yaml` of XPT2046-correctie over.
|
||||
Zes tegels van **218 × 108 pixels** per pagina, 12px tussenruimte en een
|
||||
aparte navigatiestrook. Vanaf zeven tegels verschijnt pagina twee; tot zes
|
||||
verdwijnt de navigatie. Grotere letters, iconen, dimmers en kleurkeuzes; de
|
||||
climatekaart heeft een grotere temperatuurweergave. Een donkerblauwe
|
||||
achtergrond, gedempte uitgeschakelde tegels en lichte actieve tegels maken
|
||||
climatekaart heeft een grotere temperatuurweergave. Een egaal blauwgrijze
|
||||
achtergrond, duidelijk omlijnde blauwe uitgeschakelde tegels en lichte actieve tegels maken
|
||||
de status herkenbaar. Standby begint na tien minuten zonder aanraking.
|
||||
|
||||
De bestaande tegelacties, climatebediening en vacuumkaart zijn behouden.
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# Guition 4848S040: onafhankelijke fabrikanttest
|
||||
|
||||
Deze test onderscheidt onze ESPHome/UI van de oorspronkelijke paneelaansturing.
|
||||
Een passende demo is gevonden in het fabrikantpakket dat SpotPear aanbiedt:
|
||||
|
||||
- [Verkoper met downloadlink](https://spotpear.com/ESP32-S3-4-inch-LCD-Touchscreen-Display-SHT20-Temperature-Humidity-480x480-RS485-Relay-GC9503-ST7701-FT6336U-GT911-86-TVbox/forum-answer/357.html)
|
||||
- [Origineel archief](https://cdn.static.spotpear.com/uploads/picture/learn/ESP32/ESP32-S3-4inch/4.0inch_ESP32-4848S040.zip)
|
||||
- [Community-uitleg voor bouwen met LVGL 8/9](https://github.com/paulhamsh/LVGL_GUITION)
|
||||
|
||||
In het archief:
|
||||
|
||||
- `1-Demo/Demo_Arduino/1_2_4.0_LvglWidgets/4.0_LvglWidgets/`: broncode.
|
||||
- `1-Demo/Demo_Arduino/Libraries/Arduino_GFX-master/`: meegeleverde paneeldriver.
|
||||
- `8-Burn operation/Burn files/4.0_LvglWidgets.bin`: samengevoegde firmware,
|
||||
652640 bytes, flashadres 0. Bootloader op 0, partitietabel op 0x8000,
|
||||
applicatie op 0x10000.
|
||||
- SHA256 van die demo: `9662c193fc52407bba2ed1462c582d40148f7d8eedfc806db4e8fff7685abba1`.
|
||||
|
||||
Gebruik uitsluitend de Widgets-demo voor de displaytest. De andere meegeleverde
|
||||
voorbeelden zijn relay- en muziektoepassingen. De Widgets-bron gebruikt alleen
|
||||
paneel, GT911 en achtergrondverlichting en heeft geen HA-/wifi-configuratie.
|
||||
|
||||
## Opvallende referentie-instellingen
|
||||
|
||||
De oorspronkelijke bron gebruikt ArduinoGFX, `st7701_type1_init_operations`,
|
||||
16 MHz pixelklok, RGB-pinnen R=11/12/13/14/0, G=8/20/3/46/9/10,
|
||||
B=4/5/6/7/15. Horizontaal front/pulse/back=10/8/50; verticaal=10/8/20.
|
||||
De paneelmodus is 0x3A=0x60, RGB666 op een 16-bits bedrade bus, met 0xCD=0x00.
|
||||
Rotatie 0 schrijft C7=0 in registerbank 0x10 en MADCTL=0 in bank 0.
|
||||
De achtergrondverlichting staat via GPIO38 continu aan, zonder PWM.
|
||||
|
||||
De gamma- en spanningswaarden lijken op ESPHome's ST7701S-basis, maar de volgorde,
|
||||
porches en rotatiecommando's verschillen. Dat is aanleiding voor vergelijking,
|
||||
geen bewijs dat een specifieke wijziging strepen oplost.
|
||||
|
||||
## Back-up en terugkeer
|
||||
|
||||
Verifieer eerst de chip/MAC en de echte USB-poort. Een volledige flashback-up is
|
||||
het veiligst. Voor deze specifieke demo worden alleen sectoren binnen de eerste
|
||||
1 MiB overschreven. Een exacte back-up van dat bereik is voldoende om die
|
||||
overschrijving terug te draaien als de demo geen andere flashgebieden beschrijft.
|
||||
Bewaar daarnaast de eigen firmware/YAML. Flashback-ups bevatten persoonlijke
|
||||
sleutels: alleen lokaal opslaan, nooit in Git.
|
||||
|
||||
Gebruik geen erase-all. Herstel na de test de geback-upte sectoren en verifieer de
|
||||
ESPHome-identiteit, versie, voorkeuren en HA-koppeling. Leg het fysieke resultaat
|
||||
apart vast: een succesvolle upload zegt niets over het zichtbare beeld.
|
||||
|
||||
|
||||
## Uitgevoerde test op 12 september 2026
|
||||
|
||||
- Fabrikantarchief opgehaald en de Widgets-bron plus meegeleverde driver gelezen.
|
||||
- De eerste 1 MiB (alle door deze demo overschreven sectoren) via USB geback-upt;
|
||||
921600/460800 baud gaven communicatieproblemen, 115200 baud werkte.
|
||||
- Originele Widgets-binary ongewijzigd op adres 0 geschreven; hashverificatie geslaagd.
|
||||
- USB-bootlog meldt `LVGL Widgets Demo` en `Setup done`, vervolgens GT911-polling.
|
||||
Ook meldt de oorspronkelijke demo GPIO-fouten bij het opzetten; daarom blijft
|
||||
fysieke bevestiging nodig. De eigenaar bevestigt daarna: de fabrikantdemo is schoon, zonder strepen.
|
||||
Daarmee is goede beeldweergave op dit fysieke paneel aangetoond. Dit sluit
|
||||
niet iedere hardware-/voedingsfactor uit, maar maakt onze aansturing de
|
||||
eerste onderzoekslijn.
|
||||
|
||||
|
||||
## Native ESPHome-kandidaat 0.1.3
|
||||
|
||||
De standaard `st7701s`-component krijgt dezelfde 16 MHz-klok en horizontale
|
||||
10/8/50 en verticale 10/8/20 timing als de fabrikantdemo. SPI gebruikt MODE0;
|
||||
kleurvolgorde RGB, geen inversie of hardwarematige spiegeling. Na de ingebouwde
|
||||
initialisatie worden de 16-bits busconfiguratie CD=00 en de standaard registerbank
|
||||
expliciet gekozen, gevolgd door 3A=60 en de wachttijd na sleep-out. De GT911 blijft
|
||||
in dezelfde ongemirrorde oriëntatie. De ESPHome RGB-driver wordt niet gekopieerd
|
||||
of gepatcht; de eerdere extra SDK-cache-/restart-instellingen zijn verwijderd.
|
||||
|
||||
De eigenaar meldt dat deze kandidaat schoner is, maar nog enkele vaste verticale
|
||||
banden toont. Dit is dus geen afgeronde oplossing. De fabrikantdemo blijft de
|
||||
schone referentie. Verschillen zijn onder meer ESP-IDF/LVGL-versies, framebuffer-
|
||||
en bouncebuffergebruik, wifi/API, PWM en de extra initialisatiestappen van de
|
||||
standaarddriver (inclusief software-reset). Native betekent hier de ingebouwde
|
||||
ESPHome-driver, niet byte-voor-byte dezelfde uitvoering als de fabrikantdemo.
|
||||
|
||||
Daarna is alleen de Guition-interface licht vormgegeven: achtergrond F7F7F7,
|
||||
witte kaarten, rand DDDDDD, donkere tekst en blauwe accenten. Ook de detailkaarten
|
||||
gebruiken lichte bedieningselementen. Geometrie, paginering, touch, HA-indeling en
|
||||
opgeslagen instellingen blijven behouden. Deze stijlwijziging is geen strepenfix.
|
||||
|
||||
### Lichte interface: softwarecontrole
|
||||
|
||||
De Python-suite (33 tests), zeven C++-regressietests en packagegeneratorcontrole
|
||||
slagen. De eerste lichte firmware is via OTA geïnstalleerd; tien paginacontroles
|
||||
plus vijftig overlaywisselingen slagen zonder HA-acties. De schermopname toont de
|
||||
nieuwe lichte kaarten met de bestaande HA-indeling. Lange namen kregen daarna
|
||||
vaste regelhoogtes met afkapping, zodat titel en status niet overlappen.
|
||||
Een interne schermopname bewijst geen storingsvrije fysieke paneeluitvoer.
|
||||
+256
-198
File diff suppressed because it is too large
Load Diff
@@ -777,7 +777,7 @@ esphome:
|
||||
min_version: 2026.6.2
|
||||
project:
|
||||
name: maxgramser.esp_screen
|
||||
version: "0.1.2"
|
||||
version: "0.1.3"
|
||||
includes:
|
||||
- cyd_ui.h
|
||||
- light_controls.h
|
||||
@@ -1498,7 +1498,7 @@ text_sensor:
|
||||
- platform: template
|
||||
name: "Schermfirmware"
|
||||
entity_category: diagnostic
|
||||
lambda: 'return {"0.1.2"};'
|
||||
lambda: 'return {"0.1.3"};'
|
||||
update_interval: 60s
|
||||
- platform: template
|
||||
id: smartdisplay_action
|
||||
|
||||
+2
-2
@@ -781,7 +781,7 @@ esphome:
|
||||
min_version: 2026.6.2
|
||||
project:
|
||||
name: maxgramser.esp_screen
|
||||
version: "0.1.2"
|
||||
version: "0.1.3"
|
||||
includes:
|
||||
- <esphome/components/smart_display/cyd_ui.h>
|
||||
- <esphome/components/smart_display/light_controls.h>
|
||||
@@ -1451,7 +1451,7 @@ text_sensor:
|
||||
- platform: template
|
||||
name: "Schermfirmware"
|
||||
entity_category: diagnostic
|
||||
lambda: 'return {"0.1.2"};'
|
||||
lambda: 'return {"0.1.3"};'
|
||||
update_interval: 60s
|
||||
- platform: template
|
||||
id: smartdisplay_action
|
||||
|
||||
+256
-198
File diff suppressed because it is too large
Load Diff
+10
-4
@@ -13,14 +13,20 @@ VALUES=dict(re.findall(r'^ (\w+): "([^"]*)"',SOURCE,re.M))
|
||||
|
||||
class GuitionTests(unittest.TestCase):
|
||||
def test_hardware_is_s3_rgb_with_capacitive_touch(self):
|
||||
self.assertIn('model: GUITION-4848S040',SOURCE)
|
||||
self.assertIn('platform: st7701s',SOURCE)
|
||||
self.assertNotIn('platform: mipi_rgb',SOURCE)
|
||||
self.assertIn('platform: gt911',SOURCE)
|
||||
self.assertIn('mode: octal',SOURCE)
|
||||
self.assertNotIn('platform: xpt2046',SOURCE)
|
||||
self.assertNotIn('set_raw_correction',SOURCE)
|
||||
self.assertEqual(VALUES['TOUCH_MIRROR_X'],'true')
|
||||
self.assertEqual(VALUES['TOUCH_MIRROR_Y'],'true')
|
||||
self.assertEqual(VALUES['TOUCH_MIRROR_X'],'false')
|
||||
self.assertEqual(VALUES['TOUCH_MIRROR_Y'],'false')
|
||||
self.assertIn('pclk_frequency: 16MHz',SOURCE)
|
||||
self.assertIn('hsync_back_porch: 50',SOURCE)
|
||||
self.assertIn('vsync_back_porch: 20',SOURCE)
|
||||
self.assertIn('spi_mode: MODE0',SOURCE)
|
||||
self.assertIn('[0x3A, 0x60]',SOURCE)
|
||||
self.assertNotIn('CONFIG_LCD_RGB_RESTART_IN_VSYNC',SOURCE)
|
||||
self.assertIn('execute_from_psram: true',SOURCE)
|
||||
self.assertNotIn('id: output_red',SOURCE)
|
||||
self.assertEqual(VALUES['DISPLAY_W'],'480')
|
||||
@@ -46,7 +52,7 @@ class GuitionTests(unittest.TestCase):
|
||||
def test_all_tiles_guard_events_and_clip_long_titles(self):
|
||||
for i in range(1,11):
|
||||
self.assertEqual(SOURCE.count(f'cyd::touch_guard.accept(millis(), {i})'),2)
|
||||
self.assertRegex(SOURCE,rf'id: t{i}_title\n\s+width: 130\n\s+long_mode: DOT')
|
||||
self.assertRegex(SOURCE,rf'id: t{i}_title\n\s+height: 24\n\s+width: 130\n\s+long_mode: DOT')
|
||||
self.assertEqual(VALUES['AUTO_DIM_TIMEOUT'],'600')
|
||||
|
||||
def test_gt911_verification_accepts_pixels_and_rejects_wrong_orientation(self):
|
||||
|
||||
Reference in New Issue
Block a user