{"id":20316084,"url":"https://github.com/lupyuen/remote-pinetime-bot","last_synced_at":"2025-10-26T11:45:01.373Z","repository":{"id":87767163,"uuid":"296701534","full_name":"lupyuen/remote-pinetime-bot","owner":"lupyuen","description":"Telegram Bot to flash and test PineTime firmware remotely","archived":false,"fork":false,"pushed_at":"2020-11-23T10:38:36.000Z","size":325,"stargazers_count":25,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-04T01:16:33.754Z","etag":null,"topics":["bootloader","firmware","flash","flash-mcuboot-bootloader","pinetime","rust","telegram-bot"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lupyuen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-18T18:34:13.000Z","updated_at":"2024-07-11T15:18:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"9002e988-c425-4f4b-865a-1bf6e3c1c4eb","html_url":"https://github.com/lupyuen/remote-pinetime-bot","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/lupyuen/remote-pinetime-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fremote-pinetime-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fremote-pinetime-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fremote-pinetime-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fremote-pinetime-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lupyuen","download_url":"https://codeload.github.com/lupyuen/remote-pinetime-bot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fremote-pinetime-bot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281099966,"owners_count":26443537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-26T02:00:06.575Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bootloader","firmware","flash","flash-mcuboot-bootloader","pinetime","rust","telegram-bot"],"created_at":"2024-11-14T18:24:14.847Z","updated_at":"2025-10-26T11:45:01.324Z","avatar_url":"https://github.com/lupyuen.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Remote PineTime Live Stream](https://lupyuen.github.io/images/remote-pinetime-youtube.png)\n\n# Remote PineTime: Flash and Test a PineTime Smart Watch remotely\n\n__Remote PineTime is no longer in operation. Thanks everyone for testing Remote PineTime!__\n\n![Telegram Bot to flash and test PineTime firmware remotely](https://lupyuen.github.io/images/remote-pinetime-arch.jpg)\n\nRemote PineTime is a [PineTime Smart Watch](https://wiki.pine64.org/index.php/PineTime) in Singapore that's configured to allow anyone in the world to flash and test firmware remotely.\n\nThe Remote PineTime Bot (created in Rust) watches a Telegram group for flashing commands and flashes the firmware to PineTime. \n\nThe display on PineTime is streamed live to YouTube, so you can watch your firmware running live on my PineTime.\n\nTo flash your own firmware and test PineTime, join the \"Remote PineTime\" Telegram group: https://t.me/remotepinetime\n\nThe flashing log (from OpenOCD) and debug message log (from Arm Semihosting) will be shown in the \"Remote PineTime Log\" Telegram Channel here: https://t.me/remotepinetimelog\n\n[Watch the Demo Video on YouTube](https://youtu.be/mMLWgzJSAGI)\n\n## Telegram Commands\n\nTo flash a firmware binary file `https://.../firmware.bin` to PineTime at address `0x0`...\n\n```\n/flash 0x0 https://.../firmware.bin\n```\n\nThis works for any URL that is not login protected.\n\nDon't pass URLs for artifacts created by GitHub Actions. They require login and the Telegram Bot will be blocked.\n\nInstead, copy the artifacts and upload them under \"Releases\", which is not protected by login.\n\nSome flavours of PineTime firmware require a Bootloader, like MCUBoot or SoftDevice. Flash the Bootloader to address `0x0` first, then flash the firmware.\n\nMCUBoot-Compatible Firmware should be flashed to address `0x8000`\n\n## Sample Firmware\n\n### Breakout\n\nTo flash [Breakout on PineTime](https://github.com/TT-392/TT-time)...\n\n```\n/flash 0x0 http://tt-392.space/breakout.hex\n```\n\n[Demo Video of Breakout on PineTime](https://www.youtube.com/watch?v=5rt6C1FeglM)\n\n### Hand-Drawn Watch Face\n\n\u003cimg height=250 src=\"https://lupyuen.github.io/images/handdrawn-title.png\" /\u003e\n\nTo flash [Hand-Drawn Watch Face](https://lupyuen.github.io/pinetime-rust-mynewt/articles/handdrawn)...\n\n```\n/flash 0x0 https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v5.0.4/mynewt.elf.bin\n\n/flash 0x8000 https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v7.0.1/my_sensor_app.img\n```\n\n[More about Hand-Drawn Watch Face](https://lupyuen.github.io/pinetime-rust-mynewt/articles/handdrawn)\n\n### InfiniTime\n\nTo flash a modified \"MIND BLOWN\" [InfiniTime Firmware](https://github.com/JF002/Pinetime) that never sleeps...\n\n```\n/flash 0x0 https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v5.0.4/mynewt.elf.bin\n\n/flash 0x8000 https://github.com/AntonMadness/Pinetime/releases/download/v0.1.1/pinetime-mcuboot-app-img.bin\n```\n\nThis was modified by editing [`src/DisplayApp/DisplayApp.cpp`](https://github.com/AntonMadness/Pinetime/blob/master/src/DisplayApp/DisplayApp.cpp) to remove all calls to `case Messages::GoToSleep:`\n\n### Rust on Mynewt\n\nTo flash [Rust on Mynewt Firmware](https://github.com/lupyuen/pinetime-rust-mynewt) that emits Semihosting Debug Messages...\n\n```\n/flash 0x0 https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v5.0.4/mynewt.elf.bin\n\n/flash 0x8000 https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v5.0.7/my_sensor_app.img\n```\n\n### Rust on RIOT\n\n\u003cimg height=250 src=\"https://lupyuen.github.io/images/remote-pinetime-youtube.png\" /\u003e\n\nTo flash [Rust on RIOT](https://github.com/lupyuen/pinetime-rust-riot)...\n\n```\n/flash 0x0 https://github.com/lupyuen/pinetime-rust-riot/releases/download/v1.0.3/PineTime.bin\n```\n\n### MCUBoot Bootloader\n\nTo flash [MCUBoot Bootloader](https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot) 5.0.4...\n\n```\n/flash 0x0 https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v5.0.4/mynewt.elf.bin\n```\n\nSometimes PineTime will get locked up due to firmware errors. Flashing the above MCUBoot Booloader should fix the locking.\n\nTo build your own firmware in a web browser (without installing any IDE or toolchain) check out the articles...\n\n1. [Build PineTime Firmware in the Cloud with GitHub Actions](https://lupyuen.github.io/pinetime-rust-mynewt/articles/cloud)\n\n1. [Preview PineTime Watch Faces in your Web Browser with WebAssembly](https://lupyuen.github.io/pinetime-rust-mynewt/articles/simulator)\n\nHow the flashing looks in Telegram...\n\n[Watch the Demo Video on YouTube](https://youtu.be/mMLWgzJSAGI)\n\n![Flashing Remote PineTime with Telegram](https://lupyuen.github.io/images/remote-pinetime.png)\n\nGot questions on PineTime? Chat with the PineTime Community on Matrix / Discord / Telegram / IRC...\n\nhttps://wiki.pine64.org/index.php/PineTime#Community\n\n[Check out my PineTime articles](https://lupyuen.github.io)\n\n## Why was Remote PineTime created?\n\nBecause it's difficult and expensive to ship real hardware around the world during the pandemic... And remote firmware testing could be the solution.\n\nRemote PineTime was created to allow people to learn and experiment with smartwatch coding without having a real smartwatch.\n\nCheck out my video presentation...\n\n[RIOT Summit 2020 - Safer \u0026 Simpler Embedded Programs with Rust on RIOT](https://youtu.be/LvfCSnOM1Hs)\n\n## What is Arm Semihosting?\n\n[Arm Semihosting](https://www.keil.com/support/man/docs/armcc/armcc_pge1358787046598.htm) enables our firmware to emit debugging messages by invoking the Arm Cortex-M Instruction `bkpt`.\n\nCheck out this implementation of Arm Semihosting from [`pinetime-rust-mynewt`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/libs/semihosting_console/src/semihosting_console.c#L52-L73)...\n\n```c\n/// Send an ARM Semihosting command to the debugger, e.g. to print a message.\n/// To see the message you need to run opencd:\n/// openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -f scripts/debug.ocd\nstatic int __semihost(int command, void* message) {\n    //  Warning: This code will trigger a breakpoint and hang unless a debugger is connected.\n    //  That's how ARM Semihosting sends a command to the debugger to print a message.\n    //  This code MUST be disabled on production devices.\n    __asm( \n        \"mov r0, %[cmd] \\n\"\n        \"mov r1, %[msg] \\n\" \n        \"bkpt #0xAB \\n\"\n\t:  //  Output operand list: (nothing)\n\t:  //  Input operand list:\n        [cmd] \"r\" (command), \n        [msg] \"r\" (message)\n\t:  //  Clobbered register list:\n        \"r0\", \"r1\", \"memory\"\n\t);\n\treturn 0;\n}\n```\n\nWe call `__semihost()` like so: [`semihosting_console.c`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/libs/semihosting_console/src/semihosting_console.c#L77-L113)\n\n```c\n/// ARM Semihosting Command\n#define SYS_WRITE  (0x5)\n\n/// Write \"length\" number of bytes from \"buffer\" to the debugger's file handle fh.\n/// We set fh=2 to write to the debugger's stderr output.\nstatic int semihost_write(uint32_t fh, const unsigned char *buffer, unsigned int length) {\n    //  If debugger is not connected, quit.\n    if (!debugger_connected()) { return 0; }\n    if (length == 0) { return 0; }\n    uint32_t args[3];\n    args[0] = (uint32_t) fh;\n    args[1] = (uint32_t) buffer;\n    args[2] = (uint32_t) length;\n    return __semihost(SYS_WRITE, args);\n}\n\n/// Return non-zero if debugger is connected. From repos/apache-mynewt-core/hw/mcu/ambiq/apollo2/src/hal_system.c\nstatic int debugger_connected(void) {\n    return CoreDebug-\u003eDHCSR \u0026 CoreDebug_DHCSR_C_DEBUGEN_Msk;\n}\n```\n\nWhen we call...\n\n```c\n/// Write \"hello\\n\" (6 characters) to the debugger's stderr output.\n#define SEMIHOST_HANDLE 2\nsemihost_write(SEMIHOST_HANDLE, (const unsigned char *) \"hello\\n\", 6);\n```\n\nWe'll see the the message `hello` appear in OpenOCD and the Remote PineTime Log. (Messages must end with a newline or they won't appear)\n\nArm Semihosting needs to be enabled in OpenOCD. Here's how Remote PineTime enables Arm Semihosting: [`flash-log.ocd`](https://github.com/lupyuen/pinetime-updater/blob/master/scripts/flash-log.ocd)\n\n```\n# Arm Semihosting is used to show debug console output and may only be enabled after the init event.\n# We wait for the event and enable Arm Semihosting.\n$_TARGETNAME configure -event reset-init {\n    echo \"Enabled ARM Semihosting to show debug output\"\n    arm semihosting enable\n}\n```\n\nArm Semihosting can be slow... The entire microcontroller freezes while the debug message is transmitted character by character to OpenOCD via the SWD port.\n\nWe recommend using a static array to buffer the outgoing messages in memory.\n\nIn the [`pinetime-rust-mynewt`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/libs/semihosting_console/src/semihosting_console.c#L137-L155) implementation of Arm Semihosting, we use [Mynewt Mbufs](https://mynewt.apache.org/latest/os/core_os/mbuf/mbuf.html) to buffer the messages efficiently.\n\nDon't use Arm Semihosting when Bluetooth LE processing is ongoing... Messages will be dropped and Bluetooth LE clients will automatically disconnect.\n\nArm Semihosting should be disabled in production firmware. Also, Arm Semihosting may hang when a JLink debugger is connected. For `pinetime-rust-mynewt` we disable Arm Semihosting with the GCC flag `-DDISABLE_SEMIHOSTING` in [`targets/nrf52_boot/pkg.yml`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/targets/nrf52_boot/pkg.yml) (for the MCUBoot Bootloader) and in [`targets/nrf52_my_sensor/pkg.yml`](https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/targets/nrf52_my_sensor/pkg.yml) (for the Application Firmware).\n\n## Start Telegram Bot\n\nTo create your own Telegram Bot...\n\n1. Chat with BotFather, create a bot named `PineTime Bot`\n\n1. Enter `/mybots`, select `PineTime Bot`\n\n1. Select `Edit Commands`, enter `flash - flash 0x0 https://.../firmware.bin`\n\nTo run your own Telegram Bot: Clone this repo and run this in a shell script...\n\n```bash\n#  Set your Telegram Bot Token\nexport TELEGRAM_BOT_TOKEN=???\n#  This is needed to fix the h2 / indexmap build error \"ids: IndexMap\u003cStreamId, SlabIndex\u003e expected 3 type arguments\"\nexport CARGO_FEATURE_STD=1\n#  Show Rust stack trace\nexport RUST_BACKTRACE=1\n\ncd ~/remote-pinetime-bot\nfor (( ; ; ))\ndo\n    git pull\n    pkill openocd\n    cargo run\n    echo \"---------ERROR--------\"\n    sleep 30\ndone\n```\n\nThe Telegram Bot calls [PineTime Updater](https://github.com/lupyuen/pinetime-updater/blob/master/README.md) and [xPack OpenOCD](https://xpack.github.io/openocd/install/) to flash firmware to PineTime via SWD.\n\nTo download xPack OpenOCD (for Mac) or OpenOCD SPI (for Raspberry Pi), look at [`pinetime-updater/run.sh`](https://github.com/lupyuen/pinetime-updater/blob/master/run.sh)\n\nThe Telegram Bot is currently running on Raspberry Pi with xPack OpenOCD (instead of OpenOCD SPI). xPack OpenOCD for 32-bit Raspbian was [downloaded from here](https://github.com/xpack-dev-tools/openocd-xpack/releases/download/v0.10.0-14/xpack-openocd-0.10.0-14-linux-arm.tar.gz)\n\nThe USB driver for ST-Link was configured on Raspbian like so...\n\n```bash\n#  For Linux Only: Install UDEV Rules according to https://xpack.github.io/openocd/install/#udev\nsudo cp xpack-openocd/contrib/60-openocd.rules /etc/udev/rules.d/\nsudo udevadm control --reload-rules\n```\n\n## Live Video Stream\n\nTo live stream your Raspberry Pi camera to YouTube: Run this in a shell script...\n\n```bash\nfor (( ; ; ))\ndo\n    raspivid -n -o - -t 0 -vf -hf -fps 30 -b 6000000 | \\\n        ffmpeg -re -ar 44100 -ac 2 \\\n        -acodec pcm_s16le -f s16le -ac 2 \\\n        -i /dev/zero -f h264 -i - -vcodec copy -acodec aac -ab 128k -g 50 -strict experimental \\\n        -f flv rtmp://a.rtmp.youtube.com/live2/YOUR_YOUTUBE_STREAM_KEY\n    sleep 1\ndone\n```\n\nBased on https://www.makeuseof.com/tag/live-stream-youtube-raspberry-pi/\n\nUse a Wired Network Connection instead of WiFi... Because switching on your Microwave Oven will disrupt the 2.4 GHz WiFi Network and terminate your YouTube Live Stream. (And your YouTube Live Stream URL will change)\n\nHere is the live streaming setup with (left to right) Raspberry Pi 4, Raspberry Pi v2 Camera Module (8 MP), Two Magnifying Glasses, PineTime with [Pogo Pins (sharp tip)](https://youtu.be/K5GgUlv-1SI) and [ST-Link v2](https://www.aliexpress.com/wholesale?catId=0\u0026initiative_id=SB_20180924134644\u0026SearchText=st-link+v2\u0026switch_new_app=y)...\n\n![Raspberry Pi Live Stream](https://lupyuen.github.io/images/remote-pinetime-stream.jpg)\n\nCover with a Papier-Mâché Enclosure to block the reflection on the Magnifying Glasses (like a telescope)...\n\n![Remote PineTime Enclosure](https://lupyuen.github.io/images/remote-pinetime-enclosure.jpg)\n\nHow to make the Papier-Mâché Enclosure...\n\n1. Position the Raspberry Pi, Camera Module, Two Magnifying Glasses and PineTime\n\n1. Build a Scaffold by resting an Envelope on the Raspberry Pi, Camera Module and Magnifying Glasses\n\n1. Complete the Scaffold by laying a folded piece of A4-size paper\n\n1. Paste strips of Paper Towel on the Scaffold, be sure to cover Raspbery Pi. I created the paste by mixing half-cup of Flour with half-cup of Water.\n\n1. Let the Papier-Mâché dry overnight to form the shape of the enclosure. Trim the Papier-Mâché with scissors. Microwave the Papier-Mâché to dry it.\n\n1. Paste a second layer of Paper Towel strips, in an orderly fashion.\n\n1. Microwave the Papier-Mâché for one minute, let it cool. Use overturned bowls to support the structure. Repeat 3 times until the Papier-Mâché is dry.\n\n1. Trim the Papier-Mâché Enclosure with scissors.\n\n![Making the Remote PineTime Enclosure](https://lupyuen.github.io/images/remote-pinetime-enclosure2.jpg)\n\n## Security Issues\n\nAre there any security issues exposing a Telegram Bot to the world for flashing and testing?\n\nWe mitigate the security risks as much as possible...\n\n1. Our Telegram Bot is built with Rust, a secure systems programming language.\n\n   Check out the Rust source code at [`src/main.rs`](src/main.rs)\n\n1. No remote access to the host is allowed. The Telegram Bot only polls for `/flash` commands and executes them.\n\n1. Temporary files are automatically deleted after use with the [`tempfile`](https://crates.io/crates/tempfile) library. So we reduce the exposure of files with malware.\n\nBut there is one concern... Our PineTime may be flashed with malware that attacks other Bluetooth devices nearby.\n\nFor the sake of IoT Education... I'll allow it! :-) \n\nI'm fully aware of the risks when I operate this free service. And if you choose to operate your own Remote PineTime, you should be aware of the risks too.\n\n## Semihosting Security\n\nThere is one serious security issue concerning Semihosting support: The Semihosting API supports [reading, writing and executing files](https://www.keil.com/support/man/docs/armcc/armcc_pge1358787059782.htm) on the OpenOCD host (Raspberry Pi).\n\nThis security issue has not been resolved. The workaround is to disable Semihosting support in OpenOCD, which would also disable debugging messages.\n\n## Completed Features\n\n1. Write Semihosting Debug Log to a separate Telegram Channel\n\n1. Throttle the number of Semihosting messages that will be logged to the Telegram Channel (aggregates and transmits the messages as a single Telegram request every 5 seconds)\n\n1. Allow Semihosting Debug Log and Firmware Flashing to coexist (they both use OpenOCD)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flupyuen%2Fremote-pinetime-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flupyuen%2Fremote-pinetime-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flupyuen%2Fremote-pinetime-bot/lists"}