Browse documentation

🧭 Start Here

Blackcap Overview ✨ Blackcap Feature Catalog Installation First Run

🚀 Deploy Blackcap

Platform Stacks and Raspberry Pi Hardware Raspberry Pi Deployment Raspberry Pi Client Services GCP Deployment Application Updates Environment Variables and Secrets Reverse Proxy and TLS Background Jobs and Schedules

🛠️ Administer Blackcap

Organizations Users, Permissions, and Authentication Configuration Workspace Backups and Restore Database Administration Regression Testing Performance and Job Status Audit, Access Activity, and Logging GeoIP and Access Location Data Retention and Purge Support Requests API Tester and Postman Instance Reporting

🍽️ Use Recipes

Recipes and the Recipe Library Recipe Import and Discovery Recipe Editing and Cache Artifacts Recipe Sharing Social Recipe Import AI Recipe Image Generation

📅 Plan Meals

Meal Planner

🛒 Use Shopping Lists

Shopping Lists and Shop a List External and Household Shopping 🧩 Chrome Extension Shop With

🧺 Manage Kitchen Inventory

🧺 Kitchen Inventory

🖥️ Use Displays

Displays and Connections Assigning and Scheduling Display Content Remote Pi Client E-Ink Rendering Menu Refresh and Rendering Noun Project Footer Images

🧑‍🍳 Cook with Let’s Cook

🧑‍🍳 Let’s Cook 🧑‍🍳 Let’s Cook Controls and Timers

🤖 Use and Administer AI

🤖 AI in Blackcap 🤖 AI Providers and Connections 🤖 AI Seeds and Usage

🧩 Use the Chrome Extension

🧩 Blackcap Chrome Extension 🧩 Chrome Extension Recipe Capture 🧩 Chrome Extension Shop With 🧩 Chrome Extension Release and Privacy

🎮 Play Games

🎮 Games and Trivia

🔌 Integrations

Email Integration Cloud Storage Integrations Voice Assistants Shop With Integrations Authentication Providers

⚙️ Develop Blackcap

Application Architecture Database Service and Data Access SQLite and PostgreSQL Database Migrations Background Job Architecture Testing API Architecture Security and Organization Scoping UI, Icons, and Documentation Assets Blackcap-Safe Emoji Documentation Standards Terminology

⚠️ Troubleshoot Blackcap

⚠️ Troubleshooting Deployment Troubleshooting Display Troubleshooting Recipe Import Troubleshooting 🤖 AI Troubleshooting Backup Troubleshooting Database Troubleshooting Diagnostic Organization Clones Support Requests

🧑‍🍳 Let’s Cook

Audience: User, Org Admin, Developer, Support Related: Controls And Timers · Overview · Voice Assistants · Displays

Let’s Cook is Blackcap’s guided-cooking mode. A session presents preparation, ingredients, instructions, progress, timers, step completion, and session controls across Admin, Mobile, Hosted/Kiosk, voice, and display-only e-ink surfaces.

Sessions can show the full recipe before the current step, include a preparation step, track current-step ingredients, restore the display’s default content on completion, and record bounded session history for diagnostics and review.

Let’s Cook is Blackcap’s active cooking mode. It shares one durable cooking session across Admin, Mobile, Kiosk, hosted display receivers, and the attached e-ink renderer. The session tracks recipe steps, used ingredients, active timers, side reminders from the meal plan, restore behavior, and compact cooking history.

The current production design intentionally favors reliability over partial-refresh cleverness. The attached Waveshare 13.3" HAT (K) display uses full refresh only for Let’s Cook.

Surfaces

Let’s Cook is available from:

  • Admin — full session control, timers, auto-mark controls, recent session history, and debugging visibility.
  • Mobile — compact cooking controller with timers and ingredient/step controls. Mobile does not expose recent session history.
  • Kiosk — tokenized display mini-app support for starting/continuing cooking sessions, including compact side reminders when a session is started from a meal-plan slot.
  • Attached e-ink — passive cooking display: recipe, ingredients, steps, static timer indicator, and side reminders. E-ink does not expose timer-start controls.
  • Remote Raspberry Pi client — GCP renders the Let’s Cook preview directly for the destination profile, a paired Pi pulls the changed preview, and the attached Type K panel performs one full four-level grayscale refresh.

True multi-recipe cooking remains future work. Today, Let’s Cook cooks one recipe at a time while optionally showing side reminders from the same meal-plan slot.

Attached e-ink refresh policy

Repeated partial refreshes proved unreliable on the Waveshare 13.3" HAT (K) panel: text could lighten, region replacement could garble, and timer countdown digits were especially poor. Let’s Cook therefore uses the safe model:

Controller state changes immediately
        ↓
Durable session state is saved
        ↓
Display refresh is marked pending
        ↓
Pi local panel: 10-second full-refresh coalescing
GCP remote client: immediate server preview generation
        ↓
Remote client polls every 5 seconds during Let’s Cook
        ↓
Physical e-ink refreshes only when the preview version changes

For both the attached local_eink preset and the remote_pi_client Type K preset, the Let’s Cook renderer resolves the display profile before drawing. It creates a 960 × 680 Pillow L canvas and publishes only the final four-gray PNG (0, 128, 192, 255). Hosted and kiosk targets continue to render RGB assets.

Attached e-ink refresh rules:

  • ingredient complete/incomplete → queued full refresh
  • step complete/incomplete → queued full refresh
  • auto-used ingredients from step completion → queued full refresh
  • timer start/pause/resume/cancel/complete → queued full refresh
  • active timer countdown ticks → no e-ink refresh
  • ending a session → release cooking state and restore the display’s default content

A locally attached Pi panel retains the roughly ten-second server-side coalescing window for normal session updates. For a GCP-hosted remote_pi_client, every durable Let’s Cook action renders the remote preview immediately with no server-side debounce, while the retry watcher remains available for failures or concurrent-state races. The client temporarily advertises a five-second pull interval instead of the normal 30 seconds.

The Waveshare full refresh remains the dominant delay, typically about 23–24 seconds. Changes made while that waveform is running are naturally coalesced into the newest server artifact. After each Let’s Cook physical refresh, the client polls the server immediately rather than waiting another five seconds, then resumes the five-second interval when no newer preview exists.

Ending a normal Let’s Cook session explicitly returns the display to its configured default content. Assigning another content type remains an intentional takeover: the session ends without restoring first because the newly assigned content immediately replaces it.

Required service

The display refresh loop is handled by:

blackcap_lets_cook_timer_refresh.service

Despite the historical name, this service now does more than timer refresh. It is the Let’s Cook watcher for:

  • coalescing pending full e-ink refreshes;
  • retrying pending_display_retry states after the display was busy;
  • updating completed timers in session state;
  • avoiding live e-ink countdown pushes.

Install and enable it through the scheduled-operations installer. The same service name uses a host-appropriate scope:

  • full-server Pi: attached local e-ink only, 10-second cadence;
  • GCP: remote Raspberry Pi client previews only, 2-second cadence;
  • client-only Pi: not installed.

For a Raspberry Pi with an attached local e-ink display:

sudo cp /home/pi/Blackcap-Pi/systemd/blackcap_lets_cook_timer_refresh.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now blackcap_lets_cook_timer_refresh.service
sudo systemctl restart inky_admin.service

The Pi service runs:

/home/pi/inky_env/bin/python3 /home/pi/Blackcap-Pi/run_lets_cook_timer_refresh.py --watch --interval 10 --quiet

The GCP scheduled-operations installer creates the same service with:

/opt/blackcap_env/bin/python3 /opt/Blackcap/run_lets_cook_timer_refresh.py --watch --interval 2 --remote-clients --quiet

It is intentionally separate from Gunicorn. The web request stays quick and durable; preview and hardware work happen in the watcher/client processes.

Removed partial-refresh worker

The persistent partial-refresh worker is no longer required and should not be installed:

blackcap_lets_cook_display_worker.service
run_lets_cook_display_worker.py

If a device tested earlier partial-refresh builds, remove the old worker:

sudo systemctl disable --now blackcap_lets_cook_display_worker.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/blackcap_lets_cook_display_worker.service
rm -f /home/pi/Blackcap-Pi/systemd/blackcap_lets_cook_display_worker.service
rm -f /home/pi/Blackcap-Pi/run_lets_cook_display_worker.py
rm -rf /tmp/blackcap_lets_cook_display_queue
rm -f /tmp/blackcap_eink_partial_state.json
sudo systemctl daemon-reload
sudo systemctl reset-failed

push_eink_image.py remains at the project root and is still used for full attached e-ink pushes:

/home/pi/Blackcap-Pi/push_eink_image.py

All e-ink hardware access must continue to use the shared display lock.

Display lock and retry behavior

Let’s Cook uses the same shared display lock file as menu, recipe render, display restore, and deep clean operations:

/tmp/inky_menu_display.lock

If an attached e-ink push finds an existing lock, the helper checks the stored PID:

  • live PID → another display operation is active; do not disturb it;
  • dead PID → stale lock; remove and retry safely.

If the display is legitimately busy, the API still saves the Let’s Cook state and rendered preview. The display state is marked pending_display_retry; the blackcap_lets_cook_timer_refresh.service watcher retries later.

Meal-plan and implicit start behavior

Let’s Cook has two different start modes:

  • Explicit recipe start — Admin/Mobile recipe search and recipe-page controls pass a recipe id, so Let’s Cook starts that recipe directly.
  • Implicit display start — Kiosk and future voice-assistant starts do not identify a recipe directly, so Blackcap chooses the next applicable recipe-backed meal-plan item.

Implicit starts use lets_cook_selection_service.choose_next_meal_plan_recipe() and must not fall back to a saved recipe. If there is no upcoming meal-plan recipe, no session starts. This prevents the old unsafe behavior where a kiosk-style start could fall back to the first saved recipe.

Selection order for implicit starts:

  1. currently active timed meal slot containing a recipe-backed item;
  2. next upcoming timed meal slot containing a recipe-backed item;
  3. untimed meal-plan slots ordered by date, slot order, and entry order;
  4. no session if no recipe-backed item exists in the 7-day window.

When a meal-plan slot has additional recipe-backed entries, Let’s Cook can include them through the existing meal-plan slot recipe context rather than choosing a random recipe.

Timer behavior

Admin and Mobile are the live timer surfaces. They show the actual countdown and play the completion alarm.

Attached e-ink displays only show a static timer indicator, for example:

Active timer: Orzo simmer (12 min)

Timer behavior:

  • starting a timer queues a full e-ink refresh with the static active timer indicator;
  • countdown seconds do not refresh the e-ink display;
  • pausing, resuming, cancelling, completing, or auto-completing queues a full e-ink refresh;
  • when a web/mobile timer reaches zero, the controller sounds a repeating alarm until the cook stops/cancels it with 🛑 or extends/restarts it with +1, +5, or 🔁.

Timer controls on Admin and Mobile use compact icon buttons:

  • ⏸️ pause while running
  • ▶️ resume while paused
  • ✅ mark done while running or paused
  • 🔁 restart
  • 🛑 stop/cancel
  • +1 / +5 appear only after a timer is done, where they restart for one or five additional minutes

Timer controls are not rendered on the attached e-ink cooking display.

Voice timer start behavior

Voice-assistant start timer uses lets_cook_service.start_timer_for_current_incomplete_step(). It intentionally looks only at the first incomplete recipe step and starts the first timer candidate in that step that has not already completed or been cancelled. It does not skip ahead to a later recipe step just because a later step has a timer.

If the current incomplete step has no timer, Blackcap responds:

I don't see a timer in the current step.

If an active/paused timer already exists in the current step, Blackcap reports that a timer is already running for this step rather than starting a duplicate.

Voice end-session keyword

The clear voice keyword for ending a cooking session is:

end Let’s Cook

Accepted equivalents should map to END_LETS_COOK, including end the Let’s Cook session, end cooking with Blackcap, and finish cooking with Blackcap. Bare stop should not end the session because stop timer is a timer command.

Ingredient auto-completion

Admin and Mobile include an Auto-mark ingredients control near the cooking display selector:

  • On · obvious matches is the default. When a completed instruction has high-confidence ingredient matches, Blackcap marks those ingredients used and shows a notice such as Marked 3 ingredients used.
  • Off · manual only disables automatic ingredient marking from step completion on that controller.

The setting is intentionally controller-local and stored in browser localStorage.

Meal-side reminders

When Let’s Cook is started from a meal-plan slot that includes other planned entries, Blackcap keeps the session focused on one recipe and shows the other entries as compact side reminders.

Example:

Spaghetti & Meatballs w/ Bread and Salad

The Let’s Cook header shows:

Sides: Bread · Salad

Side reminders appear in Admin, Mobile, Kiosk, and the attached e-ink recipe header. They are reminders only; they do not create additional recipe tabs or multi-recipe state.

Kiosk starts that automatically choose the current/next meal-plan recipe preserve the meal-plan entry id, so side reminders are available there too. Starting a saved recipe directly from kiosk search is recipe-only unless a meal-plan entry is supplied.

Session history

When a Let’s Cook session ends, Blackcap writes a compact history row to:

lets_cook_session_history

The history summary records:

  • recipe cooked and recipe id;
  • display used, or Here for local/admin sessions;
  • source surface such as Admin, Mobile, Kiosk, or Meal Planner;
  • started/ended timestamps and duration;
  • completed step count;
  • used ingredient count;
  • timer started/completed/cancelled counts;
  • a compact JSON summary for short-term debugging.

Admin Let’s Cook shows Recent cooking sessions below active sessions. The panel is collapsed by default and uses the same compact collapse-button styling as other Let’s Cook panels. Mobile does not expose session history.

History endpoints:

GET /api/lets-cook/history?limit=20
GET /api/lets-cook/history/<session_id>

Session history is separate from the Made It/rating/photo flow. Photos, ratings, and notes remain in the existing recipe-made-it experience.

Purge behavior

Let’s Cook uses two purge retention tiers:

purge.lets_cook_session_data.enabled = true
purge.lets_cook_session_data.after_days = 7

purge.lets_cook_session_history.enabled = true
purge.lets_cook_session_history.after_days = 30

When a session is completed, cancelled, or failed, its operational session graph is eligible after 7 days by default:

  • lets_cook_timers
  • lets_cook_session_ingredients
  • lets_cook_session_steps
  • lets_cook_session_recipes
  • lets_cook_display_state
  • lets_cook_scheduled_content_deferrals
  • lets_cook_sessions

The compact summary in lets_cook_session_history is retained separately for 30 days by default. Migration 069_lets_cook_purge_retention_split.sql removes the history table’s session foreign key so the summary can survive after operational rows are purged.

Database Admin resources

The Database Admin page exposes all Let’s Cook resources under the Let’s Cook category:

  • lets_cook_sessions
  • lets_cook_session_history
  • lets_cook_session_recipes
  • lets_cook_session_steps
  • lets_cook_session_ingredients
  • lets_cook_timers
  • lets_cook_display_state
  • lets_cook_scheduled_content_deferrals

Use these resources for inspection/debugging. Purge should still go through the domain-aware Data Cleanup workflow, not raw row deletion.

Manual testing checklist

After deployment, verify:

  1. Starting a session renders the recipe on the controller and queues a full e-ink refresh.
  2. Checking several ingredients quickly results in one coalesced e-ink full refresh after roughly 10 seconds.
  3. Completing a step optionally auto-marks high-confidence ingredients and shows controller feedback.
  4. Starting a timer shows a static active timer indicator on e-ink while Mobile/Admin continue live countdown.
  5. Timer completion alarm repeats until 🛑, +1, +5, or 🔁.
  6. Ending from Admin, Mobile, Kiosk, or the session close X restores default display content.
  7. Starting from a meal-plan slot with sides shows compact side reminders on Admin, Mobile, Kiosk, and e-ink.
  8. Ending a session creates Admin-only recent session history.
  9. Data Cleanup shows separate Let’s Cook Session Data and Let’s Cook Session History retention groups.
  10. blackcap_lets_cook_display_worker.service is not installed/running.

Useful commands:

sudo systemctl status inky_admin.service
sudo systemctl status blackcap_lets_cook_timer_refresh.service

sudo journalctl -u inky_admin.service -n 120 --no-pager
sudo journalctl -u blackcap_lets_cook_timer_refresh.service -n 120 --no-pager

Useful log lines:

Let’s Cook display update queued for debounced full refresh
pending_display_retry
Let’s Cook local e-ink partial refresh disabled; using full refresh
Attached e-ink push complete
BASE_OK / LOCK_ACQUIRED / LOCK_RELEASED
active_timer_static_no_eink_refresh

Future work

The next major feature is true multi-recipe cooking, where one Let’s Cook session can coordinate multiple recipe-backed entries in the same meal. Until then, side reminders provide the lightweight reminder use case without introducing multi-recipe scheduling, assignment, or display orchestration complexity.

Current-step display mode

Displays can choose whether Let’s Cook sessions use the compact current-step layout by setting Let’s Cook Current Step Display Mode in the display rendering settings:

  • Off keeps the existing full Let’s Cook layout and is the default.
  • Only show current step for voice-initiated Let’s Cook shows all session ingredients above the current step only when the session is started by a voice assistant.
  • Only show current step for all Let’s Cook sessions uses the same ingredients plus current-step layout for any session rendered on that display.

Current-step mode applies from the beginning of the session on the configured render surface and uses the existing session step order, including any meal-plan side/additional recipe context that is already present in the Let’s Cook session data. Admin and Mobile remain control surfaces and continue to show the full step list even when the selected display is rendering one step at a time.

Current-step display deliberately shows all session ingredients above the active step so the cook can see the full ingredient context. Ingredient auto-checking still uses the matching service described below; the renderer does not yet hide the ingredient list down to only the current step's matched ingredients because one ingredient can legitimately belong to multiple steps and collective phrases such as sauce ingredients need special handling.

Interactive takeover is one-way for this phase. If a session is in current-step mode, Admin, Mobile, Kiosk, and touch-enabled hosted receiver surfaces can show 📖 Show Entire Recipe. Pressing it switches only the active session to full-recipe rendering, preserves completed steps/ingredients/timers/current step, and does not change the display default for future sessions.

Ingredient auto-check matching and diagnostics

Let’s Cook links ingredients to steps before a session starts so completing a step can automatically check off ingredients when the match is clear. The matcher is intentionally conservative:

  • Quantity and unit terms are ignored.
  • Section headers are ignored.
  • Ingredients marked or worded as divided/reserved are not auto-checked.
  • Distinctive ingredient terms are preferred over generic context words.
  • Generic words such as sauce, oil, cheese, salt, pepper, flour, sugar, broth, and cream are used as supporting context when a more specific term is present.
  • If a distinctive term is mentioned in any step, generic context words are not allowed to add unrelated extra matches.
  • If no distinctive term is mentioned in the steps, the matcher falls back to generic context so directions that say only cheese, salt, or flour still check off ingredients like cheddar cheese, kosher salt, or all-purpose flour.
  • Collective step phrases such as sauce ingredients, marinade ingredients, dressing ingredients, seasoning mixture, dry ingredients, wet ingredients, filling ingredients, and topping ingredients can match likely members of that group even when the step does not repeat every ingredient by name.
  • Collective phrases also include a gap-fill fallback: if an ingredient has no direct step mention and a collective instruction exists, Blackcap can infer that the otherwise-unmentioned ingredient belongs to that collective instruction. This mirrors how a cook interprets add sauce ingredients after noticing that garlic, ginger, or sugar are listed but never named in the directions.
  • Ordered ingredient group phrases such as first five ingredients, first 5 ingredients, and remaining ingredients except zucchini are resolved from the ingredient list order. This helps baking recipes that intentionally avoid repeating every dry or wet ingredient by name in the directions.
  • Product descriptors for ingredients such as rice vinegar and pineapple juice are guarded so they do not match unrelated rice or pineapple steps by themselves.

For example, 1 tbsp. Worcestershire sauce primarily matches steps containing Worcestershire; the word sauce should not cause that ingredient to match unrelated tomato/pasta sauce steps. Conversely, 1 c. shredded cheddar cheese can fall back to a step that only says cheese when cheddar is not mentioned in the directions. A sauce step that says Add sauce ingredients to pan can now match explicitly sauce-like components such as soy sauce, vinegar, barbecue sauce, pineapple juice, garlic, brown sugar, or ginger, and can also gap-fill another otherwise-unmentioned ingredient into that sauce step when there is no direct text match. A baking step that says Whisk together first five ingredients. In a separate bowl, whisk remaining ingredients except zucchini can match the first five ingredient-list entries to the first phrase, the later ingredients to the remaining phrase, and keep zucchini tied to its direct Add zucchini usage.

Admin Let’s Cook history now includes an Ingredient Auto-Check Review when detailed session rows are still retained. Open a completed cooking session in Recent cooking sessions to see:

  • auto-checked, manually checked, unmatched, waiting, and possible-overmatch counts;
  • each notable ingredient’s matched steps;
  • whether the ingredient was waiting for another matched step;
  • whether the session used older broader matching than the current matcher would use;
  • cases where all matched steps were complete but the ingredient was not checked.

The review is read-only and recomputed from the stored session detail rows. Once detailed Let’s Cook rows are purged, only the compact history summary remains and the diagnostic review is unavailable for that session.

Session-only setup / mise en place step

Blackcap can generate a session-only Setup · Step 0 before the first real recipe step. Current-step displays generate Step 0 automatically when setup items exist. Full-recipe Let’s Cook displays generate Step 0 only when the display’s Show Setup Step in Full Let’s Cook setting is enabled. This setup step is not written back to the recipe and does not change the recipe instructions.

The setup step scans the scaled session ingredients for prep cues such as diced, chopped, minced, sliced, grated, shredded, zested, peeled, crushed, cubed, chiffonade, melted, softened, room temperature, drained, rinsed, thawed, toasted, divided, separated, beaten, or whisked. Straight measurements such as 1 cup flour do not create setup work, while ingredients such as 3 cloves garlic diced, 1/2 cup chopped onion, or basil, chiffonade become setup instructions like Dice 3 garlic cloves, Chop 1/2 cup onion, and Chiffonade basil.

Setup uses the Let’s Cook session multiplier. For example, starting a 2x session from 3 cloves garlic diced produces Dice 6 garlic cloves.

Setup behavior intentionally stays lightweight:

  • Step 0 appears only when there is at least one detected prep item.
  • Step 0 appears before Step 1 and must be advanced before the first real cooking step is shown.
  • Step 0 is displayed as Step 0 of N, where N is the real recipe step count.
  • Step 0 is not counted in the real recipe step total.
  • Setup items are rendered as a compact command list without numeric sub-step prefixes, so the prep text does not look like additional recipe step numbers.
  • Completing Step 0 does not check off ingredients, because the ingredients have only been prepared, not used.
  • Timer behavior remains tied to the current real/incomplete step. Setup normally has no timer candidates.
  • Alexa read-aloud uses Step 0 first when read-aloud is enabled, then reads Step 1 after the user advances.

The display setting is stored as show_setup_step_in_full_lets_cook and defaults to false to preserve the existing full-recipe layout and font fitting. Enabling it adds the same generated Step 0 to full-recipe Let’s Cook sessions on that display while leaving saved recipe rendering unchanged.

Full-recipe review before step-by-step cooking

Organizations can enable Show full recipe before step-by-step cooking on the Organization page near Preferred Recipe Units. The setting is stored as lets_cook.show_full_recipe_review_before_current_step, defaults to true, and applies when the target display will render the session in current-step mode.

When enabled, a current-step Let’s Cook session begins in an intentional pre-cook review phase:

  1. the render surface shows the full recipe without generated Step 0;
  2. the cook can read the complete ingredients and instructions first;
  3. saying next or pressing ▶ Start Step-by-Step switches the same active session into current-step mode;
  4. the first current-step screen is generated Step 0 when setup items exist, otherwise Step 1.

The review phase does not complete any steps, check off ingredients, start timers, or edit the saved recipe. It is only a session render phase. Admin and Mobile remain control surfaces and can start step-by-step mode for a non-touch display; Kiosk and touch-enabled hosted receiver surfaces show the same ▶ Start Step-by-Step control when they are allowed to control the active session.

When Alexa starts a current-step session and review is enabled, Blackcap responds: I sent the full recipe to your display. Say next when you’re ready to start cooking. The next voice command leaves review mode and reads Setup/Step 0 or Step 1 when Alexa read-aloud is enabled.

Current-step ingredient emphasis and touch advancement

Single-step mode keeps ingredients in their original recipe order and emphasizes ingredients confidently associated with the current step in place. This preserves visual verification for phrases such as “first five ingredients” and “remaining ingredients.” Relevance to the current step is separate from whether the ingredient becomes complete after that step.

On interactive hosted, kiosk, and touchscreen receivers, tapping the current step advances through the existing next-step behavior. The request includes the expected step and session version, ignores text selection and nested controls, and prevents duplicate taps. Static image/e-ink output remains non-interactive.

More information

On this page