feat(brand): AP SSID WeVisto-XXXX + logo placeholder + 4-step copy

Rename the AP broadcast SSID from PictureFrame-XXXX to WeVisto-XXXX
(operation.h:ap_ssid_from_mac + main.cpp:enter_provisioning). Tests
updated to match.

Setup screens (both panels):
- Top-right header chip replaced with a draw_logo_placeholder() box —
  a 'WeVisto' text mark with a 'PLACEHOLDER' subtitle. When the real
  brand asset lands, swap the function for a paste of the file at the
  same coordinates; no layout change needed.
- Step list rewritten to Matt's spec (4 steps, not 5):
    1. Turn on your WeVisto
    2. Unlock your phone
    3. Scan QR 1  — This will connect your phone to the WeVisto
    4. Scan QR 2  — This will open the WeVisto setup page
  Step 5 (type WiFi password) lived only in the on-panel guide; the
  user does that on the phone via the captive portal, where the
  prompt is already explicit.
- Regenerated both panels' setup_bg / ap_bg / ap_bg_retry assets via
  the gen_screens scripts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-14 22:02:53 -04:00
parent 3358ec86ad
commit 9829d1af37
17 changed files with 82 additions and 45 deletions
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

+34 -20
View File
@@ -111,6 +111,32 @@ def leave_qr_white(draw, qr_x, qr_y, qr_px):
"""Blank the QR overlay region so firmware can write the real QR."""
draw.rectangle([qr_x, qr_y, qr_x+qr_px-1, qr_y+qr_px-1], fill=WH)
# ── Logo placeholder ─────────────────────────────────────────────────────────
# Top-right brand placeholder for both setup screens. When the real logo
# lands, replace draw_logo_placeholder() with a paste of assets/logo.png
# (or similar) at the same coordinates so the layout stays stable.
LOGO_W = 200
LOGO_H = 40
LOGO_X = 800 - LOGO_W - 16
LOGO_Y = (52 - LOGO_H) // 2 # BAR_H=52
def draw_logo_placeholder(img):
draw = ImageDraw.Draw(img)
draw.rectangle([LOGO_X, LOGO_Y, LOGO_X + LOGO_W - 1, LOGO_Y + LOGO_H - 1], fill=WH)
draw.rectangle([LOGO_X, LOGO_Y, LOGO_X + LOGO_W - 1, LOGO_Y + LOGO_H - 1],
outline=BK, width=2)
f_logo = ttf("DejaVuSans-Bold.ttf", 18)
bb = draw.textbbox((0, 0), "WeVisto", font=f_logo)
tw = bb[2] - bb[0]
draw.text((LOGO_X + (LOGO_W - tw) // 2, LOGO_Y + 4), "WeVisto",
font=f_logo, fill=BK)
f_hint = ttf("DejaVuSans-Bold.ttf", 8)
bb = draw.textbbox((0, 0), "PLACEHOLDER", font=f_hint)
pw = bb[2] - bb[0]
draw.text((LOGO_X + (LOGO_W - pw) // 2, LOGO_Y + LOGO_H - 12),
"PLACEHOLDER", font=f_hint, fill=BK)
def text_center(draw, cx, y, text, font, fill):
bb = draw.textbbox((0,0), text, font=font)
tw = bb[2]-bb[0]
@@ -200,14 +226,8 @@ def gen_ap(accent=YL, header="SETUP MODE — STEP 1 OF 2", qr_label="SCAN TO C
draw.rectangle([0, 0, W-1, BAR_H-1], fill=accent)
draw.text((24, 18), header, font=F_BAR, fill=BK)
# Right chip: black box with device SSID
chip_x, chip_y = 498, 11
chip_text = "PictureFrame-91F8"
bb = draw.textbbox((0,0), chip_text, font=F_CHIP)
chip_w = bb[2]-bb[0] + 22
chip_x2 = chip_x + chip_w
draw.rectangle([chip_x, chip_y, chip_x2, BAR_H-12], fill=BK)
draw.text((chip_x+11, chip_y+7), chip_text, font=F_CHIP, fill=accent)
# Logo placeholder top-right (replaces per-device SSID chip)
draw_logo_placeholder(img)
# ── Panel dividers ────────────────────────────────────────────
draw.rectangle([DIV1_X, BODY_Y, DIV1_X+1, H-1], fill=BK)
@@ -230,11 +250,10 @@ def gen_ap(accent=YL, header="SETUP MODE — STEP 1 OF 2", qr_label="SCAN TO C
# NEW WORDING 2026-05-09 — beta tester called the prior copy
# "Chinglish." Tighter, plainer, no Safari-specific reference.
steps = [
("Plug in the frame", ""),
("Unlock your phone", ""),
("Scan QR 1", "joins your phone to PictureFrame"),
("Scan QR 2", "opens the setup page"),
("Type your home WiFi password", "and tap Connect"),
("Turn on your WeVisto", ""),
("Unlock your phone", ""),
("Scan QR 1", "This will connect your phone to the WeVisto"),
("Scan QR 2", "This will open the WeVisto setup page"),
]
sy = BODY_Y + 95
step_pitch = 32
@@ -345,13 +364,8 @@ def gen_setup():
draw.rectangle([bx + i*8, BAR_H//2 - bh//2, bx+i*8+5, BAR_H//2 + bh//2], fill=WH)
draw.text((bx+38, 18), "WIFI CONNECTED — STEP 2 OF 2", font=F_BAR, fill=WH)
# Right IP chip
ip_text = "192.168.x.x"
bb = draw.textbbox((0,0), ip_text, font=F_CHIP)
chip_w = bb[2]-bb[0] + 22
chip_x = W - chip_w - 20
draw.rectangle([chip_x, 11, chip_x+chip_w, BAR_H-12], fill=WH)
draw.text((chip_x+11, 18), ip_text, font=F_CHIP, fill=GR)
# Logo placeholder top-right (replaces IP chip)
draw_logo_placeholder(img)
# ── Panel dividers ────────────────────────────────────────────
draw.rectangle([DIV1_X, BODY_Y, DIV1_X+1, H-1], fill=BK)
+41 -18
View File
@@ -120,17 +120,42 @@ def draw_qr_frame(draw, qx, qy, qp, accent):
draw.rectangle([qx - 4, qy - 4, qx + qp + 3, qy + qp + 3], outline=BK, width=4)
def draw_header(draw, accent, header_text, ssid_text):
"""Yellow/red band along the top with a section title + SSID chip."""
def draw_header(draw, accent, header_text):
"""Coloured band along the top with section title on the left. Logo
placeholder is rendered separately by draw_logo_placeholder() so the
brand mark sits in the top right of every setup screen."""
draw.rectangle([0, 0, W - 1, HEADER_H - 1], fill=accent)
draw.text((LEFT_PAD, 40), header_text, font=F_BAR, fill=BK)
if ssid_text:
bb = draw.textbbox((0, 0), ssid_text, font=F_CHIP)
chip_w = bb[2] - bb[0] + 36
chip_x = W - chip_w - LEFT_PAD
draw.rectangle([chip_x, 25, chip_x + chip_w, HEADER_H - 25], fill=BK)
draw.text((chip_x + 18, 38), ssid_text, font=F_CHIP, fill=accent)
# ── Logo placeholder ─────────────────────────────────────────────────────────
# Box dimensions for the top-right placeholder. When the real brand mark
# lands, replace draw_logo_placeholder() with a paste of assets/logo.png
# (or similar) at these same coordinates so the layout stays stable.
LOGO_W = 300
LOGO_H = 92
LOGO_X = W - LOGO_W - LEFT_PAD # 864
LOGO_Y = (HEADER_H - LOGO_H) // 2 # 19
def draw_logo_placeholder(img):
"""White rounded-look box with 'WeVisto' brand text in the top right of
the header. Stand-in for the real logo — same position will be reused."""
draw = ImageDraw.Draw(img)
draw.rectangle([LOGO_X, LOGO_Y, LOGO_X + LOGO_W - 1, LOGO_Y + LOGO_H - 1], fill=WH)
draw.rectangle([LOGO_X, LOGO_Y, LOGO_X + LOGO_W - 1, LOGO_Y + LOGO_H - 1],
outline=BK, width=4)
f_logo = ttf("DejaVuSans-Bold.ttf", 44)
bb = draw.textbbox((0, 0), "WeVisto", font=f_logo)
tw = bb[2] - bb[0]
draw.text((LOGO_X + (LOGO_W - tw) // 2, LOGO_Y + 12), "WeVisto",
font=f_logo, fill=BK)
f_hint = ttf("DejaVuSans-Bold.ttf", 14)
bb = draw.textbbox((0, 0), "PLACEHOLDER", font=f_hint)
pw = bb[2] - bb[0]
draw.text((LOGO_X + (LOGO_W - pw) // 2, LOGO_Y + LOGO_H - 22),
"PLACEHOLDER", font=f_hint, fill=BK)
def draw_divider(draw):
@@ -256,10 +281,8 @@ def gen_ap(accent=YL,
img = Image.new("RGB", (W, H), WH)
draw = ImageDraw.Draw(img)
# Universal brand chip — firmware doesn't write text into static .bin
# assets, so leaving a per-device SSID placeholder here would lie on
# every other unit. Same image for every frame.
draw_header(draw, accent, header_text, "PICTUREFRAME")
draw_header(draw, accent, header_text)
draw_logo_placeholder(img)
draw_divider(draw)
# ── LEFT COLUMN ──────────────────────────────────────────────────────────
@@ -275,11 +298,10 @@ def gen_ap(accent=YL,
# 5 numbered steps — same instructions as the 7.3" but with the larger
# type that fits comfortably on a 13.3" portrait body.
steps = [
("Plug in the frame", ""),
("Unlock your phone", ""),
("Scan QR 1", "joins your phone to PictureFrame"),
("Scan QR 2", "opens the setup page"),
("Type your home WiFi", "password and tap Connect"),
("Turn on your WeVisto", ""),
("Unlock your phone", ""),
("Scan QR 1", "This will connect your phone to the WeVisto"),
("Scan QR 2", "This will open the WeVisto setup page"),
]
step_y0 = head_y + 240
step_pitch = 92
@@ -375,7 +397,8 @@ def gen_setup():
img = Image.new("RGB", (W, H), WH)
draw = ImageDraw.Draw(img)
draw_header(draw, GR, "WIFI CONNECTED — STEP 2 OF 2", "192.168.x.x")
draw_header(draw, GR, "WIFI CONNECTED — STEP 2 OF 2")
draw_logo_placeholder(img)
# Centered heading
text_center(draw, W // 2, BODY_Y + 30, "Almost ready", F_HEAD, BK)
+1 -1
View File
@@ -205,7 +205,7 @@ static void enter_provisioning(const String& mac, bool retry = false) {
suffix.replace(":", "");
suffix = suffix.substring(suffix.length() - 4);
suffix.toUpperCase();
String apSsid = "PictureFrame-" + suffix;
String apSsid = "WeVisto-" + suffix;
Serial.println(retry ? "AP (retry): " + apSsid : "AP: " + apSsid);
+1 -1
View File
@@ -72,7 +72,7 @@ inline String ap_ssid_from_mac(const String& mac) {
++p;
}
std::string suffix = cleaned.substr(cleaned.size() - 4);
return String(("PictureFrame-" + suffix).c_str());
return String(("WeVisto-" + suffix).c_str());
}
// ── WiFi connection attempt ───────────────────────────────────────────────────
+2 -2
View File
@@ -646,12 +646,12 @@ void test_fw_draw_pending_header_absent_when_no_draw_needed() {
// FW-12/13: AP SSID derivation via ap_ssid_from_mac()
void test_fw12_ap_ssid_from_mac_aabbcc() {
String ssid = ap_ssid_from_mac(String("AA:BB:CC:DD:EE:FF"));
TEST_ASSERT_EQUAL_STRING("PictureFrame-EEFF", ssid.c_str());
TEST_ASSERT_EQUAL_STRING("WeVisto-EEFF", ssid.c_str());
}
void test_fw13_ap_ssid_from_real_mac() {
String ssid = ap_ssid_from_mac(String("1C:C3:AB:D1:91:F8"));
TEST_ASSERT_EQUAL_STRING("PictureFrame-91F8", ssid.c_str());
TEST_ASSERT_EQUAL_STRING("WeVisto-91F8", ssid.c_str());
}
int main(int argc, char** argv) {