#BLUEHASH
← Docs

Guide

Writing a Community Program

Programs are full-screen apps that run on BLUEHASH. Write one, submit it, and every user gets it in their editor library.

The rules

Every program must follow these rules to be accepted. The firmware sandbox depends on them.

1
Only use bh_* functions
Never call Arduino APIs directly (no digitalRead, Serial, delay, etc). The HAL provides everything you need.
2
Always check bh_exit_requested()
Your main loop MUST check this every iteration. Failing to do so means the user cannot exit your program.
3
Always call bh_program_exit()
Call this before returning from your entry function. It resets the exit flag so the device flow resumes normally.
4
Prefix your globals
Name all static variables and helpers with a unique prefix (e.g. _myprog_) to avoid name collisions with other programs included in the same firmware.
5
Use bh_delay() not delay()
Always use bh_delay(ms) instead of the Arduino delay(). They are equivalent but bh_delay ensures consistency across HAL versions.
6
Clean up before exit
If your program uses WiFi, BLE, or SD — disconnect/stop them before calling bh_program_exit().
7
Never use blocking loops without bh_exit_requested()
Any while(true) loop that does not check bh_exit_requested() will trap the user inside your program forever.

Program template

Start from this template. Fill in the metadata and write your logic in the marked sections. See HAL API reference for all available functions.

/* * ╔══════════════════════════════════════════════════════╗ * ║ BLUEHASH COMMUNITY PROGRAM TEMPLATE ║ * ║ ║ * ║ 1. Fill in the metadata below ║ * ║ 2. Write your logic in the functions provided ║ * ║ 3. Only use bh_* functions — never Arduino directly ║ * ║ 4. Submit via /library ║ * ╚══════════════════════════════════════════════════════╝ */ #pragma once #include "../../hal/bh_hal.h" // ═══════════════════════════════════════════════════════ // METADATA // ═══════════════════════════════════════════════════════ #define PROGRAM_ID "my-program" // unique slug, lowercase-kebab #define PROGRAM_NAME "My Program" // display name in editor #define PROGRAM_AUTHOR "your-name" #define PROGRAM_VERSION "1.0.0" #define PROGRAM_DESCRIPTION "What your program does in one line" #define PROGRAM_CATEGORY "game" // game | tool | utility | rf | ble | network // ═══════════════════════════════════════════════════════ // BUTTON MAP (document what your buttons do) // ═══════════════════════════════════════════════════════ // OK = // UP = // DOWN = // BACK = // BACK (hold 1.5s) = Exit ← MANDATORY, do not override // ═══════════════════════════════════════════════════════ // YOUR HELPERS & STATE // ═══════════════════════════════════════════════════════ // Prefix everything with _prog_ (or your own prefix) // to avoid collisions with other included programs. // static int _prog_score = 0; // ═══════════════════════════════════════════════════════ // ENTRY POINT // Called by the device flow when the Program node fires. // ═══════════════════════════════════════════════════════ void bh_program_my_program_main() { // ── One-time setup ────────────────────────────────── bh_display_clear(); bh_display_font(BH_FONT_SMALL); bh_display_print_center(20, PROGRAM_NAME); bh_display_print_center(34, "OK to start"); bh_display_show(); bh_beep(440, 80); int _start = bh_wait_button(); if (_start == BH_BTN_BACK || _start == BH_BTN_EXIT) { bh_program_exit(); // ← MANDATORY return; } // ── Main loop ─────────────────────────────────────── while (!bh_exit_requested()) { // ← MANDATORY check int btn = bh_wait_button(); if (btn == BH_BTN_EXIT) break; // ← MANDATORY if (btn == BH_BTN_OK) { // your logic here } if (btn == BH_BTN_UP) { // your logic here } if (btn == BH_BTN_DOWN) { // your logic here } } // ── Cleanup ───────────────────────────────────────── // bh_wifi_disconnect(); // if you used WiFi // bh_ble_stop(); // if you used BLE bh_program_exit(); // ← MANDATORY }
↓ Download template.hHAL reference →

Output ports

Programs can declare output ports that appear in the editor — other nodes can wire to them. Declare them in your submission metadata.

PortTypeDescription
donetriggerFired when the program finishes normally
winsnumberExample: game score output
lossesnumberExample: game loss count

Good examples

Study these working programs before writing your own. They show the full pattern including exit handling, NVS high scores, and display layouts.

Rock Paper Scissors
Full game loop, random CPU, score display, NVS high score
rps.h
Snake
Non-blocking game loop using bh_poll_button(), speed scaling
snake.h
RF Replay
NVS persistence, scrollable list UI, RF capture + replay
rf_replay.h
Weather Station
HTTP GET, JSON parsing, WiFi connect/disconnect pattern
weather_station.h

How to submit

Once your program works locally, submit it to the community library.

1
Write your program using the template above
2
Test it locally by adding it to bluehash-firmware/programs/examples/ and registering in main.ino
3
Fill in all METADATA fields — especially PROGRAM_ID (must be unique) and PROGRAM_CATEGORY
4
Document your button map in the comments
5
Submit via the Library page — paste your source and fill the form
6
Once approved it appears in the editor Library browser for all users
Go to Library →