Files
homeassistant_espscreen/tests/test_cyd_ui.cpp
T
Max Gramser 3e959b3df9 Put ESP Screens in English and keep layouts when entity IDs change (0.2.40)
Everything a user sees or reads is now English: both boards' labels,
status replies and logs, the ESP Screens editor and Alerts cheatsheet,
and the README and guides (docs/TILES.md, CALIBRATING.md, ACCEPTANCE.md
and TROUBLESHOOTING.md replace the Dutch file names). Labels follow
Home Assistant's own English names (Heat/Cool modes, Heating/Cooling
actions, Away, Returning to dock, weather conditions), dates use English
abbreviations and the top bar writes numbers the English way. Docs use
HA 2026.9's menu names (Settings -> Apps, App store, Settings -> Tools).
Unused legacy files (home-like.yaml, buttons.yaml, a.out) are removed.

Firmware 0.2.34 names its entities in English. Home Assistant registers
a renamed ESPHome entity under a new entity ID, so the inbox
text.<screen>_tegelinstellingen becomes text.<screen>_tile_settings and
the layout stored under the old ID would be lost. The manager now
recognises the screen by its device, during a run or after a restart,
and moves its layout and update history along; the Update button and
the nightly round follow the screen through the rename. Screens that
still run 0.2.33 or older keep working: both languages are matched.

Main is the only release branch from now on.

Tested on a Home Assistant Yellow (HA 2026.9.1) with both bench boards:
see docs/TEST_RESULTS_0240.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 02:08:43 +02:00

140 lines
7.6 KiB
C++

#include "../cyd_ui.h"
#include <cassert>
#include <limits>
int main() {
using cyd::quantize_temperature;
// Fan and swing mode chips read the n-th name of a JSON list attribute.
assert(cyd::list_item("[\"auto\",\"low\",\"high\"]", 0) == "auto");
assert(cyd::list_item("[\"auto\",\"low\",\"high\"]", 2) == "high");
assert(cyd::list_item("[\"auto\",\"low\",\"high\"]", 3).empty());
assert(cyd::list_item("", 0).empty());
assert(cyd::list_item("[\"broken", 0).empty());
assert(quantize_temperature(223, 160, 300, 5) == 225);
assert(quantize_temperature(221, 160, 300, 5) == 220);
assert(quantize_temperature(-1, 160, 300, 5) == 160);
assert(quantize_temperature(999, 160, 299, 5) == 299);
assert(quantize_temperature(201, 160, 300, 0) == 201);
// -/+ keys: quick successive taps on the same key all count; bounce within 150 ms does not.
cyd::TouchGuard r;
r.begin(1000); assert(r.accept_repeat(1060, 7)); assert(!r.accept_repeat(1070, 7)); // one contact, one step
r.begin(1200); assert(r.accept_repeat(1260, 7)); // 200 ms later: accepted
r.begin(1300); assert(!r.accept_repeat(1340, 7)); // 80 ms after the last: bounce
r.begin(1300); r.update(40, 0); assert(!r.accept_repeat(1500, 7)); // a swipe is never a step
r.begin(1600); assert(r.accept_repeat(1660, 8)); // the other key right away
cyd::TouchGuard g;
g.begin(100);
assert(!g.accept(120, 1)); // resistive noise pulse
assert(g.accept(180, 1));
assert(!g.accept(800, 1)); // same physical gesture cannot fire twice
g.begin(200);
assert(!g.accept(280, 1)); // contact bounce cannot repeat the action
g.begin(300);
assert(g.accept(380, 2)); // another tile is still responsive
g.begin(1000);
assert(g.accept(1080, 2));
cyd::TouchGuard moving;
moving.begin(100, 50, 50);
moving.update(52, 48);
assert(moving.accept(180, 1)); // small resistive jitter remains usable
moving.begin(1000, 50, 50);
moving.update(51, 50); moving.update(50, 51); moving.update(50, 50); // reference settled
moving.update(50, 80); // 30 px beyond the default 18 px
moving.update(50, 50);
assert(!moving.accept(1200, 2)); // excursion stays cancelled, even on return
assert(moving.accept_slider(1200, 202)); // captured drag is a valid slider gesture
assert(!moving.accept(1201, 2)); // no parent action after slider release
assert(!moving.accept_slider(1202, 202)); // one send per contact
moving.begin(1250);
assert(!moving.accept_slider(1260, 202)); // noise remains rejected
assert(!moving.accept_slider(1350, 202)); // same-control bounce remains rejected
// Per-board limits (0.2.23): a centimetre of drift on the Guition is still a tap, and the
// reference settles over the first samples, so the landing wobble does not count.
cyd::TouchGuard wide;
wide.configure(67, 20);
assert(wide.move_limit() == 67 && wide.min_press() == 20);
wide.begin(100, 200, 200, 3);
wide.update(206, 203, 3); wide.update(210, 205, 3); wide.update(212, 206, 3); // finger flattens
wide.update(262, 206, 3); // 55 px from the settled point
assert(wide.distance() > 45 && wide.distance() <= 67);
assert(wide.accept(180, 1)); // under one centimetre: still a tap
wide.begin(1000, 200, 200, 3);
wide.update(275, 200, 3); wide.update(300, 200, 3); wide.update(340, 200, 3); // a real swipe: the reference
wide.update(380, 200, 3); // settles, the finger keeps going
assert(!wide.accept(1100, 1));
assert(wide.reason().rfind("moved", 0) == 0);
wide.begin(2000, 200, 200, 3);
wide.update(400, 400, 5); // a second finger elsewhere
assert(wide.accept(2050, 1)); // ignored: only contact 3 is followed; 50 ms is long enough here
wide.begin(3000, 200, 200, 3);
assert(!wide.accept(3010, 2)); // 10 ms is below the capacitive minimum
assert(wide.reason().rfind("too short", 0) == 0);
wide.begin(3100, 200, 200, 3);
assert(wide.accept(3160, 2));
assert(wide.reason().empty());
assert(!wide.accept(3170, 2));
assert(wide.reason() == "already handled in this contact");
wide.begin(3200, 200, 200, 3);
assert(!wide.accept(3260, 2)); // same tile within 600 ms
assert(wide.reason() == "same button within the debounce window");
// No movement limit (0): a capacitive board leaves the drift decision to LVGL's press-lost.
cyd::TouchGuard free;
free.configure(0, 20);
free.begin(100, 200, 200, 3);
free.update(205, 200, 3); free.update(205, 200, 3); free.update(205, 200, 3); // settled
free.update(400, 260, 3);
assert(free.distance() > 200);
assert(free.accept(180, 1)); // 200 px of drift, still a tap
free.begin(1000, 200, 200, 3);
free.update(205, 200, 3); free.update(205, 200, 3); free.update(205, 200, 3);
free.update(400, 200, 3);
assert(free.accept_repeat(1060, 7)); // -/+ keys follow the same rule
cyd::TouchGuard resistive;
resistive.configure(56, 60);
resistive.begin(100, 50, 50);
resistive.update(80, 50); resistive.update(50, 50); // the CYD's jump of 30 px is fine now
assert(resistive.accept(180, 1));
resistive.begin(1000, 50, 50);
resistive.update(50, 120); resistive.update(50, 130); resistive.update(50, 140);
resistive.update(50, 180); // 70 px past the settled point: a swipe
assert(!resistive.accept(1100, 1));
assert(!resistive.accept_repeat(1100, 1));
// Edge swipe (0.2.24, back on the touchscreen triggers since 0.2.29): only a touch that
// starts in the side band flips a page, from the right edge leftwards "next", from the left
// edge rightwards "previous", once per touch, slow or fast, more sideways than vertical,
// never from the middle. Rotation follows ESPHome's pointer mapping; end() disarms.
cyd::EdgeSwipe edge;
edge.configure(480, 480, 32, 40);
edge.begin(6, 240);
assert(edge.armed());
assert(edge.update(30, 242) == 0); // not far enough yet
assert(edge.update(48, 245) == -1); // 42 px inward from the left edge: previous page
assert(edge.update(90, 245) == 0); // once per touch
assert(!edge.armed());
edge.begin(474, 100);
assert(edge.update(430, 104) == 1); // from the right edge: next page
edge.begin(240, 240);
assert(!edge.armed());
assert(edge.update(300, 240) == 0); // started in the middle: never a page swipe
edge.begin(6, 240);
assert(edge.update(50, 300) == 0); // steeper than 45 degrees: 44 px sideways against 60 down
assert(edge.update(-10, 240) == 0); // moving outward: nothing
assert(edge.update(60, 270) == -1); // 54 sideways against 30 down: a slanted thumb swipe counts
edge.begin(6, 240);
edge.update(20, 250);
assert(edge.inward() == 14 && edge.sideways() == 10); // what the log reports for a swipe that ended early
edge.end();
assert(!edge.armed());
assert(edge.update(300, 250) == 0); // the next touch's first update, before begin(): nothing
edge.begin(240, 6, 90);
assert(edge.update(240, 60) == -1); // rotated 90: the user's left edge is the panel's top
edge.begin(240, 6, 270);
assert(edge.update(240, 60) == 1); // rotated 270: that same edge is the user's right
edge.begin(6, 240, 180);
assert(edge.update(60, 240) == 1); // upside down: the panel's left is the user's right
cyd::TouchGuard rollover;
rollover.begin(std::numeric_limits<uint32_t>::max() - 30);
assert(rollover.accept(50, 1)); // millis wraps after 49 days
rollover.begin(60);
assert(!rollover.accept(130, 1));
}