### Install Plugin Example Source: https://docs.trmnl.com/go/plugin-marketplace/plugin-installation-flow Example of how to install a plugin using the client. This snippet demonstrates a GET request to the plugin marketplace. ```bash GET ``` -------------------------------- ### List Recipes API Request Example Source: https://docs.trmnl.com/go/llms-full.txt Example GET request to the /recipes.json endpoint to list recipes, sorted by install count. ```http GET /recipes.json?sort-by=install ``` -------------------------------- ### Get Devices API Example Source: https://docs.trmnl.com/go/llms-full.txt This example demonstrates how to retrieve a list of devices associated with your account. Ensure you are authenticated with a valid API key. ```javascript // GET https://trmnl.com/api/devices { "data": [ { "id": 123456, "name": "My TRMNL", "friendly_id": "A1B2C3", "mac_address": "AB:CD:EF:12:34:56", "battery_voltage": 3.9, "rssi": -41 } ] } ``` -------------------------------- ### Step 4: Installation Callback GET Source: https://docs.trmnl.com/go/llms-full.txt Redirect the user's browser to the 'installation_callback_url' received in Step 1 to complete the plugin connection in TRMNL. ```bash GET '' ``` -------------------------------- ### Navigate to Introduction Source: https://docs.trmnl.com/go/private-api/screens Provides a link to the Introduction section of the Private API documentation. Use this to get started with the API. ```html Previous Introduction ``` -------------------------------- ### Basic HTTP Request Example Source: https://docs.trmnl.com/go/private-api/introduction A simple example demonstrating how to make a GET request to a private API endpoint using Go's standard library. Ensure you have the necessary authentication headers. ```Go package main import ( "fmt" "net/http" ) func main() { url := "https://api.example.com/data" req, err := http.NewRequest("GET", url, nil) if err != nil { fmt.Printf("Error creating request: %s\n", err) return } // Add authentication headers if required // req.Header.Add("Authorization", "Bearer YOUR_API_TOKEN") client := &http.Client{} res, err := client.Do(req) if err != nil { fmt.Printf("Error making request: %s\n", err) return } defer res.Body.Close() fmt.Printf("Status Code: %d\n", res.StatusCode) // Process the response body here } ``` -------------------------------- ### Plugin Configuration Example Source: https://docs.trmnl.com/go/plugin-marketplace/introduction Example of a plugin's configuration file, showing how to set parameters. ```yaml plugin: id: com.example.plugin configuration: api_key: "YOUR_API_KEY" timeout: 30 ``` -------------------------------- ### Installing a Plugin Source: https://docs.trmnl.com/go/plugin-marketplace/introduction Command to install a plugin from the marketplace using the Trmnl CLI. ```bash trmnl plugin install com.example.plugin ``` -------------------------------- ### Step 1: Installation Request GET Source: https://docs.trmnl.com/go/llms-full.txt When a user installs your plugin, TRMNL redirects their browser to your installation_url with 'code' and 'installation_callback_url' as query parameters. ```bash GET 'https://your-server.com/your-installation-url?code=abc123&installation_callback_url=https%3A%2F%2Ftrmnl.com%2Fplugin_settings%2Fnew%3Fkeyname%3Dyour_plugin%26code%3Dabc123' ``` -------------------------------- ### Installation URL Parameters Source: https://docs.trmnl.com/go/plugin-marketplace/plugin-installation-flow When a user installs a plugin, TRMNL redirects their browser to your 'installation_url'. This is a GET request, so parameters are sent in the query string. ```text installation_url GET request parameters: - installation_code — a single-use installation code, unique to this user + plugin - installation_callback_url — the TRMNL URL you send the user back to once installation is complete ``` -------------------------------- ### Boot Framework Initialization Source: https://trmnl.com/framework The main function to initialize the framework. It installs parent terminalize guards, adds preview classes, generates a table of contents, updates sidebar links, and runs terminalize when examples are ready. Includes error handling for syntax highlighting. ```javascript function bootFramework() { installParentTerminalizeGuard(); addPreviewClassToScreens(document); // Initialize TOC generation generateTableOfContents(); // Update active state in left sidebar links updateActiveSidebarLinks(); runTerminalizeWhenExamplesReady(); // Syntax highlighting for code examples try { if (typeof Prism !== 'undefined') { const mainContent = document.getElementById('main-content'); if (mainContent) { Prism.highlightAllUnder(mainContent); } else { Prism.highlightAll(); } } } catch(e) {} } ``` -------------------------------- ### Get Current Example Position Source: https://trmnl.com/framework Calculates the position of the example iframe closest to the center of the viewport. Returns null if the user is near the top of the page or no examples are found. ```javascript window.getCurrentExamplePosition = function() { // If user is near the top of the page, don't restore scroll position const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const isNearTop = scrollTop < 200; // Within 200px of the top if (isNearTop) { return null; // Don't restore position when at top of page } const examples = document.querySelectorAll('iframe[data-trmnl-example]'); if (examples.length === 0) return null; const viewportHeight = window.innerHeight; const viewportCenter = scrollTop + (viewportHeight / 2); let closestExample = null; let closestDistance = Infinity; let exampleIndex = -1; // Find the example closest to the center of the viewport examples.forEach((example, index) => { const rect = example.getBoundingClientRect(); const exampleTop = scrollTop + rect.top; const exampleCenter = exampleTop + (rect.height / 2); const distance = Math.abs(exampleCenter - viewportCenter); if (distance < closestDistance) { closestDistance = distance; closestExample = example; exampleIndex = index; } }); if (!closestExample) return null; // Calculate the offset from the top of the viewport to the top of the example const exampleRect = closestExample.getBoundingClientRect(); const offsetFromViewportTop = exampleRect.top; return { index: exampleIndex, offsetFromTop: offsetFromViewportTop }; }; ``` -------------------------------- ### Plugin Installation Request Source: https://docs.trmnl.com/go/plugin-marketplace/plugin-installation-flow This snippet shows the required parameters for installing a plugin. The access token is the only required parameter, sent as a form-encoded body. ```http POST /v1/plugins/install Content-Type: application/x-www-form-urlencoded access_token=YOUR_ACCESS_TOKEN ``` -------------------------------- ### Setup Error Handling for ESP Web Install Button Source: https://trmnl.com/flash Monitors the esp-web-install-button for specific error messages indicating browser incompatibility. Displays an error message if detected. ```javascript function setupErrorHandling() { const installButton = document.querySelector("esp-web-install-button"); if (installButton) { customElements.whenDefined('esp-web-install-button').then(() => { const checkForError = () => { const shadowText = installButton.shadowRoot?.textContent?.trim(); if (shadowText?.includes('Your browser does not support')) { showError(shadowText); installButton.style.display = 'none'; return true; } return false; }; if (!checkForError()) { setTimeout(checkForError, 25); setTimeout(checkForError, 200); } }); } } ``` -------------------------------- ### Example xhrSelectSearch Responses Source: https://help.trmnl.com/en/articles/10513740-custom-plugin-form-builder Illustrates example responses from an `xhrSelectSearch` endpoint, showing results with and without a search query. ```json # https://trmnl.com/custom_plugin_example_xhr_select_search.json # query=null [ { 'id' => 'db-123', 'name' => 'Project Tasks' }, { 'id' => 'db-456', 'name' => 'Team Goals' }, { 'id' => 'db-789', 'name' => 'Family Goals' } ] # query=goa [ { 'id' => 'db-456', 'name' => 'Team Goals' }, { 'id' => 'db-789', 'name' => 'Family Goals' } ] ``` -------------------------------- ### API Response Body Example Source: https://docs.trmnl.com/go/private-api/introduction Illustrates the format of a typical response body from the API, showing an example 'image_url'. ```json { "image_url" => "https://trmnl.s3.us-east-2.amazonaws.com/path-to-img.bmp" } ``` -------------------------------- ### Example Response for Auto-Advance Content Source: https://docs.trmnl.com/go/private-api/screens This is an example JSON response from the auto-advance content endpoint. It includes the status, image URL, image name, and firmware update information. ```json { "status":0, # will be 202 if no user_id is attached to device "image_url":"https://trmnl.s3.us-east-2.amazonaws.com/path-to-img.png", "image_name":"plugin-YYYY-MM-DD-TXX-XX-XXZ-hash", "update_firmware":false, "firmware_url":null, "refresh_rate":"1800", "reset_firmware":false } ``` -------------------------------- ### Plugin Configuration Example Source: https://docs.trmnl.com/go/plugin-marketplace/plugin-creation Illustrates how to define and use configuration flags for your plugin commands. This allows users to customize plugin behavior. ```go package main import ( "fmt" "github.com/urfave/cli/v2" ) func main() { cli.VersionFlag.Action = func(c *cli.Context) error { fmt.Println("version") return nil } } var MyCommand = &cli.Command{ Name: "mycommand", Aliases: []string{"mc"}, Usage: "A sample command", Flags: []cli.Flag{ &cli.StringFlag{ Name: "message", Aliases: []string{"m"}, Usage: "The message to display", Value: "Hello", }, }, Action: func(c *cli.Context) error { message := c.String("message") fmt.Println(message) return nil }, } ``` -------------------------------- ### Get Current Example Position Source: https://trmnl.com/framework/format_value This function calculates the position of the current example relative to the viewport center. It's used to manage scroll restoration for interactive examples, returning null if the user is near the top of the page. ```javascript window.getCurrentExamplePosition = function() { // If user is near the top of the page, don't restore scroll position const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const isNearTop = scrollTop < 200; // Within 200px of the top if (isNearTop) { return null; // Don't restore position when at top of page } const examples = document.querySelectorAll('iframe[data-trmnl-example]'); if (examples.length === 0) return null; const viewportHeight = window.innerHeight; const viewportCenter = scrollTop + (viewportHeight / 2); let closestExample = null; let closestDistance = Infinity; let exampleIndex = -1; // Find the example closest to the center of the viewport examples.forEach((example, index) => { const rect = example.getBoundingClientRect(); const exampleTop = scrollTop + rect.top; const exampleCenter = exampleTop + (rect.height / 2); const distance = Math.abs(exampleCenter - viewportCenter); if (distance < closestDistance) { closestDistance = distance; closestExample = example; exampleIndex = index; } }); if (closestExample) { return { index: exampleIndex, top: closestExample.getBoundingClientRect().top + scrollTop }; } return null; }; ``` -------------------------------- ### Get Current Example Scroll Position Source: https://trmnl.com/framework/overflow Determines the scroll position of the example closest to the viewport center. Returns null if the user is near the top of the page or no examples are found. Used to maintain scroll state when navigating between pages. ```javascript window.getCurrentExamplePosition = function() { // If user is near the top of the page, don't restore scroll position const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const isNearTop = scrollTop < 200; // Within 200px of the top if (isNearTop) { return null; // Don't restore position when at top of page } const examples = document.querySelectorAll('iframe[data-trmnl-example]'); if (examples.length === 0) return null; const viewportHeight = window.innerHeight; const viewportCenter = scrollTop + (viewportHeight / 2); let closestExample = null; let closestDistance = Infinity; let exampleIndex = -1; // Find the example closest to the center of the viewport examples.forEach((example, index) => { const rect = example.getBoundingClientRect(); const exampleTop = scrollTop + rect.top; const exampleCenter = exampleTop + (rect.height / 2); const distance = Math.abs(exampleCenter - viewportCenter); if (distance < closestDistance) { closestDistance = distance; closestExample = example; exampleIndex = index; } }); if (!closestExample) return null; // Calculate the offset from the top of the viewport to the top of the example const exampleRect = closestExample.getBoundingClientRect(); const offsetFromViewportTop = exampleRect.top; return { index: exampleIndex, offsetFromTop: offsetFromViewportTop }; }; ``` -------------------------------- ### Install Parent Terminalize Execution Guard Source: https://trmnl.com/framework Installs a guard on the `executeTerminalize` and `terminalize` functions to prevent them from running under certain conditions on documentation or example pages. This ensures terminal execution is contextually appropriate. ```javascript function installParentTerminalizeGuard() { if (typeof window.executeTerminalize === 'function' && !window.executeTerminalize.__frameworkDocsGuard) { const originalExecuteTerminalize = window.executeTerminalize; window.executeTerminalize = function() { if (isDocsOrExamplesPage() && !shouldRunParentTerminalize()) return; return originalExecuteTerminalize.apply(this, arguments); }; window.executeTerminalize.__frameworkDocsGuard = true; } if (typeof window.terminalize === 'function' && !window.terminalize.__frameworkDocsGuard) { const originalTerminalize = window.terminalize; window.terminalize = function() { if (isDocsOrExamplesPage() && !shouldRunParentTerminalize()) return; return originalTerminalize.apply(this, arguments); }; window.terminalize.__frameworkDocsGuard = true; } } ``` -------------------------------- ### Starting the BYOS HTTP Server Source: https://docs.trmnl.com/go/diy/byos This Go snippet demonstrates how to start the HTTP server for your BYOS, making it accessible to receive requests. It listens on a specified port (e.g., 8080). ```Go // Start the HTTP server fmt.Println("Starting BYOS server on :8080...") http.ListenAndServe(":8080", nil) ``` -------------------------------- ### Get Single Recipe Response Source: https://docs.trmnl.com/go/llms-full.txt Example JSON response for a successful GET request to retrieve a single recipe by ID. This structure includes recipe details, author information, custom fields, and statistics. ```json { "data": { "id": 16382, "user_id": 934, "name": "Matrix", "published_at":"2025-02-10T11:33:00.000Z", "icon_url": "https://trmnl-public.s3.us-east-2.amazonaws.com/mtpxyr22spnwjheeh5kv1p7tpk6n", "screenshot_url": "https://trmnl.s3.us-east-2.amazonaws.com/jly9u094jtsc2bwmnhlnmwjnsokk?response-content-disposition=inline%3B%20filename%3D%22plugin-2025-04-10T12-47-23Z-776f51%22%3B%20filename%2A%3DUTF-8%27%27plugin-2025-04-10T12-47-23Z-776f51&response-content-type=image%2Fbmp&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA47CRUQUU4VKBBMOF%2F20251024%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20251024T210933Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host&X-Amz-Signature=828e75fc333464c3ba13654c70434d307a8ca48053cd102f4a10a55e953c3ce2", "author_bio": { "keyname": "doesnt_matter", "name": "About This Plugin", "field_type": "author_bio", "description": "Matrix brings the iconic digital rain from the movies to your screen. By default, it displays the current date in the classic style, but you can also customize it to show any message you want.", "category": "calendar,life" }, "custom_fields": [ { "keyname": "doesnt_matter", "name": "About This Plugin", "field_type": "author_bio", "description": "Matrix brings the iconic digital rain from the movies to your screen. By default, it displays the current date in the classic style, but you can also customize it to show any message you want.", "category": "calendar,life" }, { "keyname": "message", "field_type": "string", "name": "Message", "default": "%date", "help_text": "%date to display current date" } ], "stats": { "installs": 25, "forks": 176 } } } ``` -------------------------------- ### Plugin Settings Example Source: https://docs.trmnl.com/go/plugin-marketplace/plugin-screen-generation-flow Defines basic plugin settings including an instance name. This is a foundational configuration for a plugin. ```json { "plugin_settings": { "instance_name": "Upcoming Assignments" } } ``` -------------------------------- ### Test Headers with Authorization Token Source: https://help.trmnl.com/en/articles/9510536-custom-plugins Make a GET request to the example endpoint with this header value to receive a special response. ```text authorization=token qwerty ``` -------------------------------- ### Create apikey.txt for TRMNL Kindle Source: https://trmnl.com/guides/turn-your-amazon-kindle-into-a-trmnl If using the example from the repository, create an 'apikey.txt' file in the 'TRMNL_KINDLE' directory containing your TRMNL API Key. ```bash apikey.txt ``` -------------------------------- ### Initialize Model Picker Source: https://trmnl.com/flash Populates a dropdown menu with available firmware models based on fetched release data. Sets a default placeholder text. ```javascript function initModels() { var models = Array.from(Object.keys(firmwareReleases)); models.forEach((model) => { let opt = document.createElement('option'); opt.value = model; opt.innerText = firmwareReleases[model]['label']; model_picker.appendChild(opt); }) // let user know this dropdown is ready model_picker.options[0].innerText = 'Please select...'; } ``` -------------------------------- ### Setup BYOS Device Source: https://docs.trmnl.com/go/diy/byos Use this cURL command to set up your BYOS device. Ensure you replace `` with the actual MAC address of your device. ```shell curl "http://byos.local/api/setup" \ -H 'ID: ' \ -H 'Content-Type: application/json' ``` -------------------------------- ### Initialize Framework Transitions Source: https://trmnl.com/framework/overflow Initializes framework transitions by setting up event listeners for Turbo Drive. This code should be run once to enable smooth page transitions. ```javascript (() => { let disableMainTransitions = false; const beforeVisit = function() { if (disableMainTransitions) return; try { const main = document.getElementById('main-content'); if (!main) return; main.classList.add('opacity-0', 'translate-y-1'); main.classList.add('transition-all', 'duration-200', 'ease-out'); } catch (_) {} }; const beforeRender = function() { if (disableMainTransitions) return; try { const newMain = document.querySelector('#main-content'); if (newMain) { newMain.classList.add('opacity-0', 'translate-y-1'); newMain.classList.add('transition-all', 'duration-200', 'ease-out'); } } catch (_) {} try { window.scrollTo(0, 0); } catch (_) {} }; const render = function() { if (disableMainTransitions) return; try { const main = document.getElementById('main-content'); if (!main) return; requestAnimationFrame(() => { requestAnimationFrame(() => { main.classList.remove('opacity-0', 'translate-y-1'); }); }); } catch (_) {} }; frameworkDocsRuntime.transitions = { beforeVisit, beforeRender, render }; document.addEventListener('turbo:before-visit', beforeVisit, { passive: true }); document.addEventListener('turbo:before-render', beforeRender); document.addEventListener('turbo:render', render); })(); ``` -------------------------------- ### Find Closest Example and Offset Source: https://trmnl.com/framework/format_value Calculates the closest example element in the viewport and its offset from the top. Used to maintain scroll position when navigating between examples. ```javascript window.getClosestExampleAndOffset = function() { const examples = document.querySelectorAll('iframe[data-trmnl-example]'); if (examples.length === 0) return null; const viewportCenter = window.innerHeight / 2; let closestDistance = Infinity; let closestExample = null; let exampleIndex = -1; examples.forEach((example, index) => { const rect = example.getBoundingClientRect(); const exampleCenter = rect.top + (rect.height / 2); const distance = Math.abs(exampleCenter - viewportCenter); if (distance < closestDistance) { closestDistance = distance; closestExample = example; exampleIndex = index; } }); if (!closestExample) return null; const exampleRect = closestExample.getBoundingClientRect(); const offsetFromViewportTop = exampleRect.top; return { index: exampleIndex, offsetFromTop: offsetFromViewportTop }; }; ``` -------------------------------- ### Listing Installed Plugins Source: https://docs.trmnl.com/go/plugin-marketplace/introduction Command to list all plugins currently installed in Trmnl. ```bash trmnl plugin list ``` -------------------------------- ### Install Parent Terminalize Guard and Boot Framework Source: https://trmnl.com/framework/format_value Installs a guard for parent terminalization and sets up event listeners for booting the framework on DOMContentLoaded and turbo:load events. ```javascript if (frameworkDocsRuntime.bootFramework) { document.removeEventListener('DOMContentLoaded', frameworkDocsRuntime.bootFramework); document.removeEventListener('turbo:load', frameworkDocsRuntime.bootFramework); } installParentTerminalizeGuard(); frameworkDocsRuntime.bootFramework = bootFramework; document.addEventListener('DOMContentLoaded', frameworkDocsRuntime.bootFramework); document.addEventListener('turbo:load', frameworkDocsRuntime.bootFramework); ``` -------------------------------- ### BYOS API Setup Endpoint Source: https://docs.trmnl.com/go/llms-full.txt Use this cURL command to set up a BYOS device. Ensure you replace `` with the actual MAC address. ```shell curl "http://byos.local/api/setup" \ -H 'ID: ' \ -H 'Content-Type: application/json' ``` -------------------------------- ### JSON Data Structure Example Source: https://help.trmnl.com/en/articles/10671186-liquid-101 Example JSON data structure representing a task. ```json { "name": "Walk the dog", "date": "2025-02-24", "late": true, "location": { "city": "New York" } } ``` -------------------------------- ### API Request Example Source: https://docs.trmnl.com/go/private-api/introduction Demonstrates the structure of a request to the API, including necessary headers like 'ID' and 'Access-Token'. ```json { 'ID' => 'XX:XX:XX:XX', 'Access-Token' => '2r--SahjsAKCFksVcped2Q' } ``` -------------------------------- ### Framework Initialization and Terminalization Source: https://trmnl.com/framework/format_value Handles framework readiness marking and executes the terminalization pipeline. It ensures that the framework is ready before proceeding with terminalization tasks. ```javascript (!shouldRunParentTerminalize()) return; try { if (typeof markFrameworkReady === 'function') { markFrameworkReady(); } else { window.frameworkReady = true; } } catch(e) {} const runTerminalizePipeline = () => { try { if (typeof executeTerminalize === 'function') { executeTerminalize(); } else if (typeof terminalize === 'function') { terminalize(); } } catch(e) {} }; runTerminalizePipeline(); ``` -------------------------------- ### Framework Initialization Event Listeners Source: https://trmnl.com/framework Sets up event listeners for 'DOMContentLoaded' and 'turbo:load' to call the `bootFramework` function. It also ensures any previously attached listeners are removed to prevent duplicates. ```javascript if (frameworkDocsRuntime.bootFramework) { document.removeEventListener('DOMContentLoaded', frameworkDocsRuntime.bootFramework); document.removeEventListener('turbo:load', frameworkDocsRuntime.bootFramework); } installParentTerminalizeGuard(); frameworkDocsRuntime.bootFramework = bootFramework; document.addEventListener('DOMContentLoaded', frameworkDocsRuntime.bootFramework); document.addEventListener('turbo:load', ``` -------------------------------- ### Create Standard Firmware Manifest Source: https://trmnl.com/flash Generates a JSON manifest for the esp-web-install-button using selected model and version. Used for standard firmware installations. ```javascript function createManifest() { let manifest = { "name": "TRMNL Firmware", "version": version_picker.value, "new_install_prompt_erase": false, "builds": [ { "chipFamily": firmwareReleases[model_picker.value]['chipFamily'], "parts": [{ "path": `https://trmnl.com/firmware/${model_picker.value}/${version_picker.value}.bin`, "offset": "0x0" }] } ] } let json = JSON.stringify(manifest); let blob = new Blob([json], {type: "application/json"}); document.querySelector("esp-web-install-button").manifest = URL.createObjectURL(blob); } ``` -------------------------------- ### TRMNL Display API Request Example Source: https://docs.trmnl.com/go/llms-full.txt Example of request headers and response body for the TRMNL Display API. ```http GET /api/display # request headers example { 'ID' => 'XX:XX:XX:XX', 'Access-Token' => '2r--SahjsAKCFksVcped2Q' } # response body example { "image_url"=>"https://trmnl.s3.us-east-2.amazonaws.com/path-to-img.bmp", "filename"=>"2025-05-10-plugin-T00:00:00", "update_firmware"=>false } ```