Hi all ![]()
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:
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.
Header-only, zero dependencies, C++17/20/23 (later standards unlock more compile-time checks).
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.
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).
Your memory, your rules — arena (zero heap), HeapResetPool, plainmalloc,std::pmr, or a custom allocator; the typed API is identical across all of them.
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.
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! ![]()