← 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
}
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 normallywinsnumberExample: game score outputlossesnumberExample: game loss countGood 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
Snake
Non-blocking game loop using bh_poll_button(), speed scaling
RF Replay
NVS persistence, scrollable list UI, RF capture + replay
Weather Station
HTTP GET, JSON parsing, WiFi connect/disconnect pattern
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