Note-cpp — a type-safe C++ library for the Notecard (community project)

Hi all :waving_hand:

I’ve been building note-cpp, a header-only C++ library for the Blues Notecard, and I’d love to share it with the community and get your feedback.

The goal was a Notecard API that feels natural in modern C++ — typed requests and responses, no macros-everywhere, and the same code from an ATmega328P all the way up to an ESP32 or a desktop host.

A quick taste:

#include <note.hpp>

Notecard nc;
nc.begin(Serial1, 9600);          // or nc.begin(Wire) for I2C

nc.hub.set()
    .product("com.example.app")
    .mode("periodic")
    .execute();

auto rsp = nc.card.version().execute();
if (rsp) {
    Serial.println(rsp.version);  // typed fields
} else {
    Serial.println(rsp.error());
}

A few things I think make it nice to use:

  • :puzzle_piece: Fully typed API for all 74 Notecard requests — fluent (nc.hub.set().product(...)) or plain assignment, with typed response fields instead of digging through JSON.
  • :feather: Header-only, zero dependencies, C++17/20/23 (later standards unlock more compile-time checks).
  • :chart_decreasing: Scales from tiny to large — the same API runs on an Arduino Uno (ATmega328P) all the way up through ESP32, Cortex-M, and Linux/macOS. On the Uno the fully-typed build lands around 80% of flash with zero heap — roughly flash-parity with hand-written note-c, and lighter on RAM — and if you need headroom, leaner call styles drop the same app to ~36% of flash. You dial memory and flash use without changing your call sites.
  • :shield: Catches mistakes at compile time — on C++20 it validates string constants like mode/triggers, and can constrain the API to your hardware variant + firmware version, and gives each request intent its own type (setting a field that doesn’t apply is a compile error).
  • :wrench: Your memory, your rules — arena (zero heap), HeapResetPool, plain malloc, std::pmr, or a custom allocator; the typed API is identical across all of them.
  • :electric_plug: Serial + I2C built in with CRC auto-detection, retries, segmentation, and binary transfer (card.binary.put/get) — plus an optional compact JSONB wire format for constrained targets.
  • :white_check_mark: Well tested — the same test cases run on host compilers and on real Notecard hardware over serial/I2C, with high coverage.

Your own structs work as note bodies for send, receive, and note.template registration:

struct Readings {
    float temperature;
    int16_t humidity;
    NOTE_FIELDS(temperature, humidity)   // optional on C++20+
};

nc.note.add().file("sensors.qo").body(Readings{22.5f, 60}).execute();

A note on scope: this is an independent community project — not affiliated with or supported by Blues, and “Notecard” is their trademark. It assumes you’re already comfortable with the Notecard and its API.

Repo, docs, and examples: GitHub - m-mcgowan/note-cpp: Type-safe C++ API for the Blues Notecard. Header-only, zero dependencies. C++17/20/23. · GitHub

I’d genuinely welcome feedback, bug reports, or “I tried it on X board” reports. Thanks for taking a look! :folded_hands:

3 Likes