No Towers? No Problem: Join Our Satellite IoT Webinar on September 29th

Blues Developers
What’s New
Resources
Blog
Technical articles for developers
Connected Product Guidebook
In-depth guides for connected product development
Developer Certification
Get certified on wireless connectivity with Blues
Newsletter
The monthly Blues developer newsletter
Terminal
Connect to a Notecard in your browser
Webinars
Listing of Blues technical webinars
Blues.comNotehub.io
Shop
Docs
Button IconHelp
Support DocsNotehub StatusSecurity AdvisoriesVisit our Forum
Button IconSign In
Docs Home
What’s New
Resources
Blog
Technical articles for developers
Connected Product Guidebook
In-depth guides for connected product development
Developer Certification
Get certified on wireless connectivity with Blues
Newsletter
The monthly Blues developer newsletter
Terminal
Connect to a Notecard in your browser
Webinars
Listing of Blues technical webinars
Blues.comNotehub.io
Shop
Docs
Guides & Tutorials
Host Wiring Guide
Writing Host Firmware
Routing Data to Cloud
Best Practices for Production-Ready Projects
Fleet Admin Guide
Using the Notehub API
Notecard Guides
Asset Tracking with GPS
Attention Pin Guide
Connecting to a WiFi Access Point
Debugging with the FTDI Debug Cable
Encrypting and Decrypting Data with the Notecard
Feather MCU Low Power Management
Minimizing Latency
Notecard Communication Without a Library
Remote Command and Control
Scaling Your Notecard Firmware Design
Sending and Receiving Large Binary Objects
Sending Large Binary ObjectsReceiving Large Binary ObjectsBinary Uploads with Web APIsFaster Binary Transfers over AUX UART
Serial-Over-I2C Protocol
Storing Device State with DB Notefiles
Understanding Environment Variables
Using a Serial Terminal with Notecard
Using External SIM Cards
Using JSONata to Transform JSON in Notehub
homechevron_rightDocschevron_rightGuides & Tutorialschevron_rightNotecard Guideschevron_rightSending and Receiving Large Binary Objects

Sending and Receiving Large Binary Objects

While Notecard is designed to be a low-bandwidth wireless device, it is also possible to sync large binary payloads with the cloud.

This is accomplished by storing raw binary data in a reserved area on the Notecard, and then having Notecard send that large block directly to Notehub. Likewise, Notecard and Notehub can work together to get a binary payload from a remote endpoint and save it to the reserved area on the Notecard.

note

Important Considerations When Syncing Large Binary Objects

  1. In your app design, it's safe to assume the maximum space available for data in the binary storage area on the Notecard is 100KB. The exact available space (in bytes) is returned in the max field in response to a card.binary request.

    If the total size of the binary data you are sending is > than max, you will need to "flush" the storage with the appropriate web.post request each time that limit is reached (see examples below), and then reassemble the binary data after it has been routed to your cloud.

  2. Notehub charges one event credit for each megabyte of data uploaded via web transactions.

  3. The card.binary and card.binary.put APIs are not supported on Notecard for LoRa, which does not include a binary storage area.

tip

Let AI write your firmware. Blues Expert MCP connects your AI coding assistant (Claude Code, GitHub Copilot, Cursor) directly to our API docs, providing live request validation and firmware best practices for Arduino, C, Zephyr, and Python. Install the Blues Expert MCP →

Sending Large Binary Objects

Sending a large binary object from the Notecard involves two steps:

  1. Storing the binary payload in Notecard's reserved binary buffer.
  2. Syncing that buffer with Notehub so it can be routed to your cloud endpoint.

These two steps are independent, so you can mix and match any storing method with any syncing method. Most applications pair the SDK helpers with a web.post request.

Storing Binary Data on Notecard

You have two paths to choose from when populating Notecard's binary buffer. They both build on the card.binary and card.binary.put APIs, but note-c provides helper functions that ease the process. note-arduino includes note-c, so Arduino sketches can call them directly.

  1. Storing Binary Data with the note-arduino SDK (Recommended)
  2. Storing Binary Data with the card.binary APIs

Storing Binary Data with the note-arduino SDK

Due to the complexities of using the card.binary APIs directly, the recommended path is to use the helper functions provided by note-c, the core C library that also powers the note-arduino SDK.

note

The following Arduino examples demonstrate storing binary data with note-arduino: basic binary data example and sending a large binary payload in chunks.

Storing a Single Binary Fragment

For small binary payloads (e.g. <= 8 KB), you can store the entire payload in a single fragment without the need to split and reassemble it on your cloud endpoint.

  1. Define the binary data and use the NoteBinaryStoreTransmit() function to store the data in the reserved binary space on the Notecard. The fourth argument is the offset into the Notecard's binary area where the data should be written (0 for a single-fragment upload).

    char buff[25] = "Hello World";
    NoteBinaryStoreTransmit((uint8_t *) buff, strlen(buff), sizeof(buff), 0);
  2. Once the buffer is populated, continue on to Syncing Binary Data to Notehub.

Storing Multiple Binary Fragments

For larger binary payloads, you may need to split the payload into multiple smaller fragments and reassemble them on your cloud endpoint.

  1. Define the size of the binary payload fragments to send to the Notecard.

    #define CHUNK_SIZE 4096
    uint8_t temp_buffer[CHUNK_SIZE + 128];
  2. Specify the binary array and length of the binary array from your binary object and send the binary payload to the Notecard in CHUNK_SIZE fragments.

    note

    The binary buffer requires additional overhead, so the buffer can be encoded in place. If you wish to know the exact requirements of your binary payload, you may use NoteBinaryCodecMaxEncodedLength(). In this example, an arbitrary overhead was specified.

    const uint8_t * img_map = big_img_map;
    const size_t img_len = big_img_len;
    
    int i = 0;
    size_t bytes_left = img_len;
    while (bytes_left) {
      notecard.logDebugf("\nSending chunk %d, offset: %d...\n", i, i * CHUNK_SIZE);
      size_t bytes_to_send = bytes_left >= CHUNK_SIZE ? CHUNK_SIZE : bytes_left;
      memcpy(temp_buffer, img_map + i * CHUNK_SIZE, bytes_to_send);
    
      const char *err = NoteBinaryStoreTransmit((uint8_t *)temp_buffer, bytes_to_send, sizeof(temp_buffer), i * CHUNK_SIZE);
         
      if (!err) {
        bytes_left -= bytes_to_send;
        i++;
      }
    }
  3. Once the buffer is populated, continue on to Syncing Binary Data to Notehub.

Storing Binary Data with the card.binary APIs

As an alternative to using the SDK helpers, you can populate the binary buffer directly with the card.binary and card.binary.put APIs. This path requires you to handle COBS encoding and MD5 verification yourself.

  1. Issue a card.binary request to the Notecard to verify the available space (max) is larger than the size of the binary payload you want to store.

    >
    {"req":"card.binary"}
    {"max":130554}
  2. Calculate the MD5 checksum of the binary payload.

  3. COBS-encode the binary payload. The note-c library (the core C library that also powers note-arduino) includes a NoteBinaryCodecEncode function to simplify this process.

  4. Calculate the length of the new COBS-encoded payload.

  5. Append a newline character to the COBS-encoded payload (\n).

  6. Send a card.binary.put request to the Notecard with the MD5 checksum in the status argument and the length of the payload in the cobs argument.

    Use the offset argument if you are supplying multiple payloads in succession, where the current offset is the index location of where the previous ended.

    {
      "req": "card.binary.put",
      "cobs": 5,
      "status": "ce6fdef565eeecf14ab38d83643b922d"
    }
  7. At this point, the Notecard is in a state where it expects the next input to be binary data, not a JSON-formatted API request. Send it the COBS-encoded payload.

    000011110110100101100101011010000111100100001010
  8. Next, you can optionally send a card.binary request to check for errors and verify the binary data was properly saved to the Notecard by checking the MD5 checksum:

    >
    {"req":"card.binary"}
    {
     "connected": true,
     "max": 130554,
     "status": "ce6fdef565eeecf14ab38d83643b922d",
     "length": 4,
     "cobs": 5
    }

    If an error occurs on the transfer it will appear in the err field:

    {"err":"md5 mismatch","max":130554}
  9. Once the buffer is populated, continue on to Syncing Binary Data to Notehub.

Syncing Binary Data to Notehub

After storing binary data on the Notecard, you have two options for transmitting the buffer to Notehub:

  • web.post, which sends the buffer to a Proxy for Notecard Web Requests route.
  • note.add, which attaches the buffer to a Note and delivers it through a standard Notehub route.

Syncing Binary Data with web.post

  1. Issue a web.post request with the "binary":true and content (the appropriate MIME type) arguments supplied. This tells Notecard to send all the data in the binary buffer to the specified proxy route in Notehub.

    note

    Consult the Web Transactions docs for detailed information on using the web.post API and proxy routes (noting the Notecard must be connected and in continuous mode).

    >
    {
      "req": "web.post",
      "route": "PostBinaryDataRoute",
      "binary": true,
      "verify": true,
      "content": "application/octet-stream"
    }
    {"result":200}

    Here is the equivalent request in C using the note-arduino SDK:

    if (J *req = NoteNewRequest("web.post")) {
      JAddStringToObject(req, "route", "PostImageRoute");
      JAddStringToObject(req, "content", "images/jpeg");
      JAddBoolToObject(req, "binary", true);
      JAddBoolToObject(req, "verify", true);
    
      if (!NoteRequest(req)) {
        NoteDebug("Error sending image\n");
        delay(15000);
      }
    }
  2. After the web.post is complete, reset the binary buffer on Notecard by sending a card.binary request with the "delete":true argument:

    >
    {
      "req": "card.binary",
      "delete": true
    }
    {"max":130554}

    Or, with the note-arduino SDK, call NoteBinaryStoreReset():

    NoteBinaryStoreReset();

Syncing Binary Data with note.add

As an alternative to web.post, you can transmit the contents of the binary buffer by attaching it to a Note using a note.add request with the "binary":true and "live":true arguments. This allows the binary payload to flow through a standard Notefile sync and Notehub route.

note

When using "binary":true with note.add, the "live":true argument is required. The live argument tells Notecard to bypass saving the Note to flash, since the binary buffer itself is not stored in the Notefile on the Notecard.

  1. Issue a note.add request with "binary":true and "live":true, specifying the Notefile (for example, binary.qo) that your Notehub route is configured to filter on.

    >
    {
      "req": "note.add",
      "file": "binary.qo",
      "binary": true,
      "live": true
    }
    {"total":1}

    Here is the equivalent request in C using the note-arduino SDK:

    if (J *req = NoteNewRequest("note.add")) {
      JAddStringToObject(req, "file", "binary.qo");
      JAddBoolToObject(req, "binary", true);
      JAddBoolToObject(req, "live", true);
      NoteRequest(req);
    }
  2. When Notecard next syncs with Notehub, the contents of the binary buffer will be delivered as the payload of the resulting event on the specified Notefile. After the sync has completed, reset the binary buffer on the Notecard before storing the next payload by sending a card.binary request with the "delete":true argument:

    >
    {
      "req": "card.binary",
      "delete": true
    }
    {"max":130554}

    Or, with the note-arduino SDK, call NoteBinaryStoreReset():

    NoteBinaryStoreReset();
warning

If you plan to route binary payloads to external services, be aware that Notehub removes any payload larger than 256 bytes from the stored event after the event has been successfully routed.

After that point, the stored event in Notehub no longer includes the original payload. If you need to access these payloads later, make sure your route persists them when it first receives them.

Receiving Large Binary Objects

Receiving a large binary object on Notecard involves two steps:

  1. Syncing the binary payload from Notehub into Notecard's reserved binary buffer.
  2. Reading that buffer from your host microcontroller.

These two steps are independent, so you can choose how to read the buffer regardless of how it was populated. Most applications pair a web.get request with the SDK helpers.

Syncing Binary Data from Notehub

Before reading, you first need to get the binary payload into the Notecard's binary buffer by issuing a web.get request with the "binary":true argument.

  1. Issue a card.binary request to the Notecard to verify the available space (max) is larger than the size of the binary payload you expect to download.

    >
    {"req":"card.binary"}
    {"max":130554}
  2. Send a web.get request to the specified Notehub proxy route with the "binary":true and content (the appropriate MIME type) arguments supplied, which requests that the response be placed in the Notecard's binary buffer.

    note

    Consult the Web Transactions docs for detailed information on using the web.get API and proxy routes (noting the Notecard must be connected and in continuous mode).

    >
    {
      "req": "web.get",
      "route": "GetBinaryDataRoute",
      "binary": true,
      "content": "application/octet-stream"
    }
    {
     "result": 200,
     "length": 78179,
     "cobs": 78194,
     "body": {}
    }

    Here is the equivalent request in C using the note-arduino SDK:

    if (J *req = NoteNewRequest("web.get")) {
      JAddStringToObject(req, "route", "GetImageRoute");
      JAddStringToObject(req, "content", "images/jpeg");
      JAddBoolToObject(req, "binary", true);
    
      if (!NoteRequest(req)) {
        NoteDebug("Error receiving image\n");
      }
    }
  3. Next, you can send a card.binary request to verify the binary data was properly saved to the Notecard, noting the MD5 checksum returned in the status field is computed before COBS-encoding, and therefore does not include the \n.

    >
    {"req":"card.binary"}
    {
     "connected": true,
     "max": 130554,
     "status": "c381abe19c96870db6d73fb4d670ef25",
     "length": 78179,
     "cobs": 78194
    }

Reading Binary Data from Notecard

You have two paths to choose from when reading the binary buffer on your host. They both use the card.binary and card.binary.get APIs, but note-c provides helper functions that ease the process. note-arduino includes note-c, so Arduino sketches can call them directly.

  1. Reading Binary Data with the note-arduino SDK (Recommended)
  2. Reading Binary Data with the card.binary APIs

Reading Binary Data with the note-arduino SDK

Due to the complexities of using the card.binary APIs directly, the recommended path is to use the helper functions provided by note-c, the core C library that also powers note-arduino.

note

The following Arduino examples demonstrate receiving binary data with note-arduino: basic binary data example and receiving a large binary payload in chunks.

  1. Get the decoded length of the downloaded binary data via a call to NoteBinaryStoreDecodedLength():

    uint32_t buffer_len = 0;
    NoteBinaryStoreDecodedLength(&buffer_len);
  2. Call NoteBinaryStoreReceive() to verify and decode the binary data. The third and fourth arguments are the decoded-byte offset and decoded length to retrieve — pass 0 and the full buffer_len to fetch the entire payload.

    Size the buffer for the encoded data, not the decoded length. NoteBinaryStoreReceive() reads the COBS-encoded bytes off the wire and decodes them in place, and rejects a buffer that is only as large as the decoded payload with an insufficient buffer size error.

    uint32_t encoded_len = NoteBinaryCodecMaxEncodedLength(buffer_len) + 1;
    uint8_t * my_binary_data = (uint8_t *)malloc(encoded_len);
    NoteBinaryStoreReceive(my_binary_data, encoded_len, 0, buffer_len);
  3. Clear the binary buffer on the Notecard after the host has handled the binary data.

    NoteBinaryStoreReset();

Reading Binary Data with the card.binary APIs

As an alternative to using the SDK helpers, you can read from the binary buffer directly with the card.binary.get API. This path requires you to handle COBS decoding yourself.

  1. Send a card.binary.get request to Notecard to fetch the binary data:

    >
    {"req":"card.binary.get"}
    {"status":"39f66921b9fb84a0400a1579e3dd3210"}

    Binary data will immediately follow this response. It can be fetched by reading until the \n character is encountered.

  2. COBS-decode the binary data. If you're working in C or C++, the note-c library (the core C library that also powers note-arduino) includes a NoteBinaryCodecDecode function to simplify this process.

  3. After successfully retrieving the binary data, clear the binary buffer on the Notecard.

    >
    {"req":"card.binary", "delete":true}
    {"max":130554}

    Or call note-c's NoteBinaryStoreReset():

    NoteBinaryStoreReset();

Binary Uploads with Web APIs

Using Notecard's binary storage area is the recommended path for most binary uploads. As an alternative, the web.post API accepts base64-encoded payload fragments that Notehub reassembles before invoking your route, delivering a single payload to your cloud endpoint.

You may opt to utilize this alternative binary data upload path when your payload exceeds the binary buffer on the Notecard. The card.binary path is capped at the Notecard's reserved binary area (i.e. max in the card.binary response, typically ~100KB). Larger payloads require multiple buffer flushes and reassembly on your cloud endpoint, while fragment uploads let Notehub handle reassembly before routing.

note

There are some tradeoffs to be aware of when using this method:

  • Base64 encoding adds ~33% bandwidth overhead per fragment compared to the raw binary sent by the card.binary path.
  • Your host must manage fragment sizing, offsets, and per-fragment MD5s manually.
  • This is a synchronous path as the Notecard must be connected and in continuous mode, the same as the other web.* approaches.
  • The maximum recommended size of each fragment depends on the type and quality of your network connection. A safe range for most scenarios is 4–8 KB.

Sending Binary Fragments

Your host will split the binary payload into fragments and send them in successive web.post requests. Each request must set the "content": "application/octet-stream" argument and include the following additional arguments so Notehub can verify each fragment and place it correctly in the reassembled payload:

  • total - The total size of the reassembled payload, in raw (pre-base64) bytes.
  • offset - The byte offset of this fragment within the reassembled payload, in raw (pre-base64) bytes.
  • status - A 32-character hex-encoded MD5 sum of the fragment's bytes, used by Notehub to verify each fragment on receipt.
  • verify - Set to true to request verification from Notehub once the fragment is received. Automatically set to true when status is supplied.
  1. Send the first fragment of your payload with offset: 0. The example below shows the first fragment of an 8191-byte payload:

    {
      "req": "web.post",
      "route": "SensorService",
      "content": "application/octet-stream",
      "payload": "<base64-encoded first 600 raw bytes>",
      "status": "<hex-encoded md5 of those 600 bytes>",
      "offset": 0,
      "total": 8191
    }
    J *req = NoteNewRequest("web.post");
    JAddStringToObject(req, "route", "SensorService");
    JAddStringToObject(req, "content", "application/octet-stream");
    JAddStringToObject(req, "payload", "<base64-encoded first 600 raw bytes>");
    JAddStringToObject(req, "status", "<hex-encoded md5 of those 600 bytes>");
    JAddNumberToObject(req, "offset", 0);
    JAddNumberToObject(req, "total", 8191);
    
    NoteRequest(req);
    req = {"req": "web.post"}
    req["route"] = "SensorService"
    req["content"] = "application/octet-stream"
    req["payload"] = "<base64-encoded first 600 raw bytes>"
    req["status"] = "<hex-encoded md5 of those 600 bytes>"
    req["offset"] = 0
    req["total"] = 8191
    
    rsp = card.Transaction(req)
  2. Send each subsequent fragment, advancing offset by the raw byte count of the prior fragment. For example, after sending 600 bytes, the next fragment uses offset: 600:

    {
      "req": "web.post",
      "route": "SensorService",
      "content": "application/octet-stream",
      "payload": "<base64-encoded next 600 raw bytes>",
      "status": "<hex-encoded md5 of those 600 bytes>",
      "offset": 600,
      "total": 8191
    }
    J *req = NoteNewRequest("web.post");
    JAddStringToObject(req, "route", "SensorService");
    JAddStringToObject(req, "content", "application/octet-stream");
    JAddStringToObject(req, "payload", "<base64-encoded next 600 raw bytes>");
    JAddStringToObject(req, "status", "<hex-encoded md5 of those 600 bytes>");
    JAddNumberToObject(req, "offset", 600);
    JAddNumberToObject(req, "total", 8191);
    
    NoteRequest(req);
    req = {"req": "web.post"}
    req["route"] = "SensorService"
    req["content"] = "application/octet-stream"
    req["payload"] = "<base64-encoded next 600 raw bytes>"
    req["status"] = "<hex-encoded md5 of those 600 bytes>"
    req["offset"] = 600
    req["total"] = 8191
    
    rsp = card.Transaction(req)
  3. Continue sending fragments until the sum of fragment sizes reaches total. When the final fragment arrives, Notehub reassembles the complete payload, invokes the proxy route, and returns the route's HTTP response to the Notecard:

    >
    {
      "req": "web.post",
      "route": "SensorService",
      "content": "application/octet-stream",
      "payload": "<base64-encoded final fragment>",
      "status": "<hex-encoded md5 of final fragment>",
      "offset": 7800,
      "total": 8191
    }
    {"result":200}

    If a fragment fails MD5 verification, Notehub returns an err field in the response so the host can retransmit that fragment.

Faster Binary Transfers over AUX UART

Storing a large payload in Notecard's binary buffer is often the slowest part of a binary data transfer workflow, and the interface you choose for your host firmware sets the ceiling:

  • I2C runs the Serial-Over-I2C protocol at roughly 100kHz, and each chunk costs an additional query/read round trip on top of the data itself.
  • Serial UART (N_RX/N_TX) is fixed at 9600/8-N-1 and is slower still.

Notecard's AUX UART (AUX_RX/AUX_TX/AUX_EN) implements the same JSON request/response protocol as the other interfaces, but unlike them its baud rate is configurable with the rate argument of card.aux.serial. That makes it possible to leave your host on I2C for everyday requests, temporarily move to AUX UART for the duration of a card.binary transfer, and then switch back.

warning

This is an advanced technique. AUX UART is not the recommended primary host interface for a production design (see Choosing Your Interface). It requires up to three additional physical connections (how many depends on your Notecarrier), it must be explicitly enabled with AUX_EN, and Notecard cannot reach its lowest-power modes while AUX_EN is asserted. Use it as a temporary, high-throughput side channel for bulk transfers, not as a replacement for I2C or Serial UART.

How the Switch Works

Only one Notecard interface is active in your host library at a time. In note-c, NoteSetFnSerial() makes serial the active interface and NoteSetFnI2C() makes I2C the active interface; in note-arduino, notecard.begin() does this for you. Switching interfaces is therefore a matter of configuring the Notecard side over your current interface, then re-pointing the library at the new one:

  1. While still on I2C, send a card.aux.serial request with "mode":"req", the rate you want, and flow control settings.
  2. Pull AUX_EN high to enable the AUX interface.
  3. Re-point your host library at the AUX UART port at the new baud rate.
  4. Verify the Notecard is reachable at the new rate.
  5. Perform the card.binary transfer.
  6. Re-point the library back at I2C and drop AUX_EN.

What You Need

AUX UART needs three signals connected between the Notecard and your host:

Notecard PinConnect ToNotes
AUX_RXHost UART TXNotecard receives host transmissions here.
AUX_TXHost UART RXHost receives Notecard responses here.
AUX_ENA host GPIOMust be driven high (to VIO) to enable.

How much of this you have to wire yourself depends on your Notecarrier. Some carriers already route the AUX data lines to the host header, either permanently or through a DIP switch:

  • Notecarrier F v1.3 and earlier connects AUX_RX/AUX_TX to the Feather's F_TX/F_RX pins — that is, to the Feather's hardware Serial1. On v1.0 this routing is DIP-selectable; on v1.3 it is dedicated. AUX_EN is not routed, so it still needs a jumper to a spare GPIO.
  • Notecarrier F v1.5 does not wire the AUX lines to the Feather. Notecard Outboard Firmware Update moved to the dedicated ALT_DFU pins on this revision, so AUX_RX, AUX_TX, and AUX_EN are broken out to the Notecarrier header only. Jumper all three to your host yourself.
  • Notecarrier Pi routes AUX_RX/AUX_TX to Raspberry Pi GPIO 14 and 15 (header pins 8 and 10) when the SERIAL TXRX DIP switch is ON.
  • Notecarrier A, B, and the X series expose the AUX signals on their headers without routing them anywhere, so all three connections are yours to make.

Confirm the routing for your specific carrier and revision in the Notecarrier Datasheet before wiring anything — the shared-pin tables and DIP switch descriptions there are authoritative, and they differ between board revisions.

The examples below assume a Feather host on a Notecarrier F v1.3, using Serial1 for AUX and digital pin D5 for AUX_EN. Adjust both to match your own hardware.

note

If you are designing your own carrier board, provide appropriate termination resistance on the AUX transmission lines. The Notecarrier reference designs use two 100Ω resistors for this purpose. See the Notecard Carrier Board Design Guide for details.

Step 1: Enable AUX Request Mode

Send this request over your current interface (I2C, in this example), not over AUX. Set mode, rate, and the flow control arguments in a single request.

{
  "req": "card.aux.serial",
  "mode": "req",
  "rate": 115200,
  "max": 63,
  "ms": 1
}
// Match these to your host, wiring, and Arduino core. See the warning below
// on determining HOST_RX_BUFFER_SIZE for your board.
#define AUX_EN_PIN           D5
#define AUX_BAUD_RATE        115200
#define HOST_RX_BUFFER_SIZE  64

// Enable the AUX interface before configuring it.
pinMode(AUX_EN_PIN, OUTPUT);
digitalWrite(AUX_EN_PIN, HIGH);

J *req = NoteNewRequest("card.aux.serial");
JAddStringToObject(req, "mode", "req");
JAddNumberToObject(req, "rate", AUX_BAUD_RATE);
JAddNumberToObject(req, "max", HOST_RX_BUFFER_SIZE - 1);
JAddNumberToObject(req, "ms", 1);

J *rsp = NoteRequestResponseWithRetry(req, 10);

// Confirm the Notecard actually accepted the configuration before switching.
bool configured = (rsp != NULL)
               && !NoteResponseError(rsp)
               && (strcmp(JGetString(rsp, "mode"), "req") == 0)
               && (JGetNumber(rsp, "rate") == AUX_BAUD_RATE);
NoteDeleteResponse(rsp);

if (!configured) {
    // Stay on I2C. Switching now would leave the host unable to communicate.
    return;
}
req = {"req": "card.aux.serial"}
req["mode"] = "req"
req["rate"] = 115200
req["max"] = 63
req["ms"] = 1

rsp = card.Transaction(req)

# Confirm the Notecard actually accepted the configuration before switching.
if "err" in rsp or rsp.get("mode") != "req" or rsp.get("rate") != 115200:
    raise RuntimeError(f"Notecard rejected AUX configuration: {rsp}")

Check the response before you switch. It must come back without an err field and must echo back both "mode":"req" and the rate you asked for. If it doesn't, the Notecard did not accept the configuration, and re-pointing your library at AUX will leave you unable to communicate with it at all. The examples above bail out and stay on I2C in that case.

warning

Flow control is mandatory on AUX UART.

The max and ms arguments tell the Notecard how much data it may send before pausing to let your host drain its receive buffer. max must be set to the size of your host's serial receive buffer minus 1.

Without flow control, Notecard responses longer than your receive buffer are silently truncated at the buffer boundary. During a card.binary transfer this typically surfaces as an MD5 or CRC mismatch rather than an obvious overflow, which makes it easy to misdiagnose as a data corruption problem.

There is no portable Arduino constant for this size, so define your own and set it from your core's documentation or headers. The macro and its default differ by core — SERIAL_RX_BUFFER_SIZE (64 bytes) on AVR and STM32, SERIAL_BUFFER_SIZE (350 bytes) on Adafruit SAMD, and different names again elsewhere. Several cores also let you override the size with a build flag. When in doubt, err low: a max smaller than your real buffer costs a little throughput, while one larger than it corrupts responses.

If you need to adjust flow control on its own (without changing the mode or baud rate) note-c provides a helper. It applies the - 1 for you, so just pass the full buffer size:

// Sends {"req":"card.aux.serial","max":<bufSize - 1>,"ms":<delayMs>}
NoteAuxSerialFlowControl(HOST_RX_BUFFER_SIZE, 1);

Step 2: Move the Host Library to AUX UART

Changing interfaces takes three calls, in this order:

notecard.end();                          // tear down the I2C interface
NoteSetFnDisabled();                     // release the active interface
notecard.begin(Serial1, AUX_BAUD_RATE);  // bring up AUX UART at the new rate

notecard.end() tears down the transport instance. note-arduino holds one serial instance and one I2C instance internally, and only constructs each if it does not already exist. On your first I2C-to-AUX switch no serial instance exists, so begin() builds one and opens Serial1 on its own. On later switches one already exists, and begin() reuses it without reopening the port, so a changed baud rate is silently ignored. Calling end() first avoids that, and it closes the port you are leaving: Serial.end() on the serial side, and Wire.end() on the I2C side for cores that define WIRE_HAS_END.

NoteSetFnDisabled() releases the active interface, which end() leaves set. note-c tracks one active interface at a time and end() clears the I2C callbacks.

notecard.begin() then constructs the new instance, opens the port at your baud rate, and claims the interface the previous call released.

Use all three every time, in both directions, rather than tracking which instance exists with which settings on a given pass. The sequence is safe to repeat and stays correct when you loop over several transfers or change baud rates between them.

Step 3: Verify the Switch Took

Before streaming a payload, confirm the Notecard is actually reachable at the new baud rate. note-c's NotePing() is purpose-built for this as it sends a single echo request with a random nonce, uses a short fixed timeout, performs no retries, and does not trigger a Notecard reset on failure. On serial it also drains the host UART input buffer first, discarding any residual bytes left over from a previous attempt at a different baud rate.

if (!NotePing()) {
    // The Notecard is not responding at this rate. Fall back to I2C.
}
note

NotePing() requires note-c v2.6.1 or later.

As of note-arduino v1.8.5, the vendored copy of note-c is v2.5.6, which does not include NotePing(). If you are using note-arduino, verify the switch with an ordinary request round trip instead:

J *rsp = notecard.requestAndResponse(notecard.newRequest("card.version"));
bool reachable = (rsp != NULL) && !notecard.responseError(rsp);
notecard.deleteResponse(rsp);

Step 4: Perform the Binary Transfer

From here, the transfer is identical to Storing Binary Data with the note-arduino SDK — the only difference is which interface the requests travel over. Reset the binary buffer first, then transmit your fragments.

NoteBinaryStoreReset();

const char *err = NoteBinaryStoreTransmit((uint8_t *)temp_buffer, bytes_to_send,
                                          sizeof(temp_buffer), offset);

Once the buffer is populated, you can issue the web.post or note.add request that syncs it to Notehub over AUX as well, or switch back to I2C first — the sync itself is not bandwidth-bound on the host interface.

Step 5: Switch Back to I2C

Return to your primary interface as soon as the transfer completes.

notecard.end();                       // tear down the AUX UART interface
NoteSetFnDisabled();                  // release the active interface
notecard.begin();                     // back to I2C at the default address

digitalWrite(AUX_EN_PIN, LOW);        // disable the AUX interface

The same three-call sequence applies in this direction, and for the same reason — here it is NoteSetFnSerial(nullptr, ...) inside end() that leaves serial marked active, blocking begin() from claiming I2C.

warning

Don't leave AUX_EN asserted.

Notecard cannot enter its lowest-power modes while the AUX interface is enabled via AUX_EN. On a battery- or solar-powered device, leaving AUX enabled between transfers can cost far more energy than the transfer itself saved in time.

Choosing a Baud Rate

The AUX UART default is 115200, which makes it the natural starting point.

Other rates are accepted by the rate argument, but we publish no throughput or qualification data for any AUX rate, and the answer is hardware-specific regardless: throughput depends on your host MCU, its UART buffer size, your flow control settings, and your wiring. Rather than assuming a speedup, measure the transfer time for a representative payload on your own hardware at a few rates, and verify with card.binary that the MD5 still matches at whichever rate you settle on. Treat any rate above 115200 as something you have qualified yourself.

Troubleshooting

SymptomLikely Cause
No response at all after switchingAUX_EN not pulled high, AUX_RX/AUX_TX swapped, or the end() / NoteSetFnDisabled() / begin() sequence not followed in full.
MD5 or CRC mismatch on an otherwise valid payloadFlow control (max/ms) not set, or max larger than the host receive buffer minus 1.
Responses arrive garbled at the new rateHost UART never reopened at the new baud rate — see the interface-switch warning in Step 2.
card.aux.serial response doesn't echo your rateThe Notecard rejected the configuration. Stay on I2C and check the err field.

Additional Resources

  • card.binary APIs
  • Notecard Web Transactions
  • card.aux.serial API
  • Working with the Notecard AUX Pins
  • Serial-Over-I2C Protocol
Can we improve this page? Send us feedback
© 2026 Blues Inc.
© 2026 Blues Inc.
AboutDocsAPI ReferenceTermsPrivacy