Scaling an IoT deployment? Join our webinar on May 28th where we dive into real-world scaling pain points and how to overcome them.

Blues Developers
What’s New
Resources
Blog
Technical articles for developers
Newsletter
The monthly Blues developer newsletter
Terminal
Connect to a Notecard in your browser
Developer Certification
Get certified on wireless connectivity with Blues
Webinars
Listing of Blues technical webinars
Blues.comNotehub.io
Shop
Docs
Button IconHelp
Notehub StatusVisit our Forum
Button IconSign In
Sign In
Sign In
Docs Home
What’s New
Resources
Blog
Technical articles for developers
Newsletter
The monthly Blues developer newsletter
Terminal
Connect to a Notecard in your browser
Developer Certification
Get certified on wireless connectivity with Blues
Webinars
Listing of Blues technical webinars
Blues.comNotehub.io
Shop
Docs
Example Apps
Accelerators
SDK Examples
Sample Apps
Sample Apps List
Continuous Asset Tracking with External GPS and Immediate Location Sync
Managing a Notecard's Wi-Fi Network Remotely
Putting a Host to Sleep Between Sensor Readings
Routing Data from Notehub to a Custom Cloud Endpoint
Sending Inbound Notes and Receiving Acknowledgment
IntroductionGeneral InformationSummaryTechnical ImplementationAdditional Resources
Using LEDs and NeoPixels to Monitor Notecard Status
Community Projects
homechevron_rightDocschevron_rightExample Appschevron_rightSample Appschevron_rightSending Inbound Notes and Receiving Acknowledgment

Sending Inbound Notes and Receiving Acknowledgment

Introduction

This sample app demonstrates a pattern for sending commands from the cloud to a Notecard-connected device, processing the command on the device, and then sending an acknowledgment back to the cloud.

By implementing this pattern you can implement more robust user interfaces for your devices.

An example of the acknowledgment pattern in a web app

Wireless Connectivity with Blues

This sample app is built around the Blues Notecard and Blues Notehub .

The Blues Notecard is the easiest way for developers to add secure, robust, and affordable pre-paid wireless connectivity to their microcontroller or single-board computer of choice. Notecard is a System-on-Module (SoM) that combines pre-paid data, low-power hardware (~8μA-12μA when idle), and secure communications. It acts as a device-to-cloud data pump to communicate with the Blues cloud service Notehub.

Notehub is the Blues cloud service for routing Notecard-provided data to third-party cloud applications, deploying OTA firmware updates, and securely managing fleets of Notecards. Notehub allows for secure communications between edge devices and the cloud without certificate management or manual provisioning of devices.

General Information

System Hardware

You can use any Notecard and any host microcontroller to implement this article's pattern. However, this example will demonstrate using the following hardware.

ComponentPurpose
Blues Notecard Cellular WBGLW Wireless connectivity module enabling device-to-cloud data syncing.
Blues Notecarrier F Carrier board for connecting Notecard to an MCU.
Blues Swan Example host MCU.

List of Acronyms

AcronymDefinition
MCUMicrocontroller
SoMSystem-on-Module

Summary

The Notecard is a wireless SoM that offers bidirectional connectivity between a device and cloud applications. This article focuses on data that you wish to send from the cloud to a device, which we refer to as inbound data. For example, a cloud application may wish to tell a device to turn off a connected LED by sending the following inbound Note:

{"command":"led-on"}

When building user interfaces for Notecard-based devices, the UI often needs to receive some indication that the requested action completed successfully. For example, after sending {"command":"led-on"} to a device, the UI may wish to display a pending indicator while the action is in progress, a completed indicator once the action has successfully completed, and an error if the action failed.

The following sections demonstrate how to write firmware and web applications that implement this pattern.

Requirements

  1. Host firmware that can:

    1. Turn on and off an LED (the host's onboard LED is fine).

    2. Receive inbound data.

    3. Send outbound acknowledgments as Notes.

  2. A web or mobile application that sends data to Notehub using the Notehub API.

Technical Implementation

The full source code for this example is available on GitHub .

Firmware

This section covers the most important aspects of writing firmware that sends out acknowledgments. The firmware for this example uses the Arduino Notecard library, although you can implement this pattern using any of the Notecard SDKs.

note

You may wish to bring up the full source file on GitHub while reading through this section.

hub.set

The hub.set request controls how a Notecard connects to Notehub. This example's firmware uses the following configuration.

J *req = notecard.newRequest("hub.set");
JAddStringToObject(req, "product", productUID);
JAddStringToObject(req, "mode", "continuous");
JAddBoolToObject(req, "sync", true);
if (!notecard.sendRequest(req)) {
  JDelete(req);
}
  • The "mode": "continuous" option places the Notecard in continuous mode, which has it maintain a constant network connection with Notehub.
  • The "sync": true option ensures inbound Notes sync as soon as they're detected on Notehub.

This configuration ensures the device will receive inbound data as soon as possible, which is ideal for any device that needs to quickly respond to commands. However, this configuration does mean the device will use considerably more battery to maintain the connection to Notehub than it would with a periodic connection.

You can receive commands and send acknowledgments from devices in periodic mode. However, when in periodic mode your Notecard will not send/receive instantly, and instead those intervals will be determined by your configured inbound and outbound options.

note.get

After running the hub.set request, the Notecard will perform a connection with Notehub and start listening for inbound data. To check whether data has come in, the firmware calls the note.get request in a loop.

void loop()
{
  // To hold "led-on" and "led-off". Increase the size if you need to send longer commands.
  char command[7];
  char id[10];

  J *req = notecard.newRequest("note.get");
  JAddStringToObject(req, "file", "commands.qi");
  JAddBoolToObject(req, "delete", true);

  J *rsp = notecard.requestAndResponse(req);
  if (notecard.responseError(rsp)) {
    notecard.logDebug("No notes available");
    command[0] = '\0';
  } else {
    J *body = JGetObject(rsp, "body");
    strncpy(command, JGetString(body, "command"), sizeof(command));
    strncpy(id, JGetString(body, "id"), sizeof(id));
  }
  notecard.deleteResponse(rsp);

  ...

  delay(1000);
}

The code above checks whether any inbound commands.qi Notes have been synchronized from Notehub. If it detects any, it extracts the "command" and "id" from the inbound Note and saves them in variables.

note.add

Now that the firmware has received a command it needs to take the requested action (turn the light on or off), and then acknowledge that action by sending an outbound Note.

The note.add request is the Notecard's main mechanism for working with outbound data. The firmware uses the function below to send outbound notes for a provided state (e.g. "on") and identifier.

void sendAck(char *state, char *id)
{
  J *req = notecard.newRequest("note.add");
  if (req != NULL)
  {
    JAddStringToObject(req, "file", "ack.qo");
    JAddBoolToObject(req, "sync", true);
    J *body = JAddObjectToObject(req, "body");
    if (body)
    {
      JAddStringToObject(body, "led-state", state);
      JAddStringToObject(body, "id", id);
    }
    notecard.sendRequest(req);
  }
}

The above request uses the note.add request's sync option, which tells the Notecard to immediately synchronize this Note to Notehub.

note

The Notecard uses the configured outbound interval to determine how often to to synchronize outbound data, even in continuous mode.

If you want to immediately synchronize data you can either use the note.add request's sync option (as shown above), or use the hub.sync request.

To put everything together, let's return to the firmware's loop(), and look at the new code at the bottom.

void loop()
{
  // To hold "led-on" and "led-off". Increase the size if you need to send longer commands.
  char command[7];
  char id[10];

  J *rsp = notecard.requestAndResponse(req);
  if (notecard.responseError(rsp)) {
    notecard.logDebug("No notes available");
    command[0] = '\0';
  } else {
    J *body = JGetObject(rsp, "body");
    strncpy(command, JGetString(body, "command"), sizeof(command));
    strncpy(id, JGetString(body, "id"), sizeof(id));
  }
  notecard.deleteResponse(rsp);

  // ⬇️ the new stuff ⬇️
  if (!strncmp(command, "led-on", sizeof("led-on")))
  {
    notecard.logDebug("Turning light on");
    digitalWrite(LED_BUILTIN, HIGH);
    sendAck("on", id);
  }
  if (!strncmp(command, "led-off", sizeof("led-off")))
  {
    notecard.logDebug("Turning light off");
    digitalWrite(LED_BUILTIN, LOW);
    sendAck("off", id);
  }

  // Wait one second before looking for changes again
  delay(1000);
}

After the Notecard receives a command from the note.get request, it checks whether the command is a known command ("led-on" or "led-off"). If it finds a known command it makes the appropriate change to the LED itself, and then uses the sendAck() function to send an acknowledgment Note.

Testing the Firmware

To test that the firmware is working correctly you'll need to send an inbound Note to your device. You can do this with the Notehub UI or API as shown here, or use the provided web application below.

If you do want to test with only Notehub API, try sending Notes to the command.qi Notefile in the following form:

{"command":"led-on","id":"abc123"}

You should see your microcontroller's LED turn on, and you should see a new ack.qo Note appear as an event in your Notehub project.

{"led-state":"on","id":"abc123"}

Web Application

This section covers the most important aspects of writing user interfaces that send commands and receive acknowledgments. The web application for this example uses Notehub JS.

note

You may wish to bring up the full source file on GitHub while reading through this section.

Sending Notes

The main task of the user interface is to allow the user to send commands to a device. To do so the example application uses a Switch component . When the Switch is toggled on the UI sends an "led-on" command to Notehub, and when the Switch is toggled off the UI sends an "led-off" command to Notehub.

<Switch
  onChange={updateLed}
  value={ledState}
  disabled={isPending}
  loading={isPending}
/>
const deviceApiInstance = new NotehubJs.DeviceApi();
const [lastId, setLastId] = React.useState("");
const [isPending, setIsPending] = React.useState(false);
const [ledState, setLedState] = React.useState(false);

const updateLed = (checked: boolean) => {
  setLedState(checked);
  setIsPending(true);

  const id = generateRandomString(10);
  setLastId(id);

  const note = new NotehubJs.Note();
  note.body = {
    command: checked ? "led-on" : "led-off",
    id,
  };
  deviceApiInstance
    .handleNoteAdd(projectUID, deviceUID, "commands.qi", note)
    .then(() => console.log("Successfully added note"))
    .catch(console.error);
};

This simple bit of code works, and you can use it to send commands to your device— which is cool!—but it also has one big limitation: there is nothing to stop the user from rapidly clicking the switch and getting it out of sync with the physical device.

This is where acknowledgments come in. With acknowledgment events the UI can disable the switch after sending a command, and wait to enable the switch until it detects a matching acknowledgment event. Let's see how it works.

Reading Notes

There are two primary techniques for receiving updates in a web application: WebSockets and polling. This application takes the simpler approach, polling, and uses Notehub JS to retrieve the latest acknowledgment event every few seconds.

Here is the function that performs the call itself. Notice how the code checks to ensure that the acknowledgment id matches before it calls setIsPending(false), which re-enables the switch.

const eventApiInstance = new NotehubJs.EventApi();

const [lastId, setLastId] = React.useState("");
const [isPending, setIsPending] = React.useState(false);
const [ledState, setLedState] = React.useState(false);

const getLatestValue = () => {
  eventApiInstance
    .getProjectEvents(projectUID, {
      deviceUID: [deviceUID],
      files: ["ack.qo"],
      pageSize: 1,
      sortBy: "captured",
      sortOrder: "desc",
    })
    .then((data: EventsResponse) => {
      if (!data || !data.events || data.events.length === 0) {
        return;
      }

      const state = data.events[0].body["led-state"];
      const id = data.events[0].body.id;
      if (lastId && id !== lastId) {
        return;
      }

      setLedState(state === "on");
      setIsPending(false);
    })
    .catch(console.error);
};

Finally, the code uses the browser's setInterval function to have the getLatestValue() run every POLL_INVERVAL_MS (5 seconds, by default).

React.useEffect(() => {
  const intervalId = setInterval(getLatestValue, POLL_INVERVAL_MS);
  return () => clearInterval(intervalId);
}, [lastId]);

Expected Results

And with that, you should be good to go! Try running the web application, and you should see the switch change to a disabled and pending state, and become reenabled seconds later when the UI receives acknowledgment when the action completed.

An example of the acknowledgment pattern in a web app

In your Notehub project you should see a pair of command.qi and ack.qo events every time you perform a command in the app.

A list of ack.qo and commands.qi events

Potential Issues

This example, while powerful, does have a few limitations.

Multiple Interfaces

The current implementation assumes that only a single interface is being used to send commands to the device. If you need your dashboard to stay accurate while being used by multiple devices simultaneously, you'll need to adjust the logic that loads events.

Specifically, you'll need to alter the event code to retrieve multiple acknowledgment events (in case other devices sent acknowledged commands), and cycle through them to determine the device's current state, and to ensure your interface's command was processed.

Error Handling

You may want to implement error handling in your firmware to transmit error codes when commands fail, and update your user interface to handle these error codes appropriately.

Additional Resources

  • Source code - The source code for this example.
  • Remote Command and Control - A guide to sending commands to a Notecard from the cloud.
  • Notehub JS - The official library for working with the Notehub API in JavaScript.
  • note-arduino - The official Arduino library for communicating with the Notecard over serial or I2C.
Can we improve this page? Send us feedback
© 2025 Blues Inc.
© 2025 Blues Inc.
TermsPrivacy
Notecard Disconnected
Having trouble connecting?

Try changing your USB cable as some cables do not support transferring data. If that does not solve your problem, contact us at support@blues.com and we will get you set up with another tool to communicate with the Notecard.

Advanced Usage

The help command gives more info.

Connect a Notecard
Use USB to connect and start issuing requests from the browser.
Try Notecard Simulator
Experiment with Notecard's latest firmware on a Simulator assigned to your free Notehub account.

Don't have an account? Sign up