🚀 Browse our open source reference applications to accelerate your IoT project!

Search
Documentation Results
End of results
Community Results
End of results
Support
Blues.io
Notehub.io
Shop
Sign In
Search
Documentation Results
End of results
Community Results
End of results
Support
Blues.io
Notehub.io
Shop
×
HomeGuides & Tutorials
Welcome
Collecting Sensor Data
Routing Data to Cloud
Building Edge ML Applications
Twilio SMS Guide
Fleet Admin Guide
Using the Notehub API
Notecard Guides
Guide Listing
Asset Tracking
Attention Pin Guide
Connecting to a Wi-Fi Access Point
Debugging with the FTDI Debug Cable
Diagnosing Cellular Connectivity Issues
Encrypting Data With the Notecard
Minimizing Latency
Notecard Outboard Firmware Update
Remote Command and ControlSending Commands to DevicesReceiving Commands on a DeviceReceiving Commands on a Host
Serial-Over-I2C Protocol
Understanding Environment Variables
Understanding Notecard Penalty Boxes
Updating ESP32 Host Firmware
Using External SIM Cards
Using JSONata to Transform JSON
Rate this page  
  • ★
    ★
  • ★
    ★
  • ★
    ★
  • ★
    ★
  • ★
    ★
Can we improve this page? Send us feedbackRate this page
  • ★
    ★
  • ★
    ★
  • ★
    ★
  • ★
    ★
  • ★
    ★
© 2023 Blues Inc.Terms & ConditionsPrivacy
blues.ioTwitterLinkedInGitHubHackster.io
Disconnected
Notecard Disconnected
Having trouble connecting?

Try changing your Micro 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

Remote Command and Control

The Notecard's communication with its cloud backend, Notehub, is bidirectional. This means that in addition to sending local data from the Notecard to the cloud, you can also send data or commands in the opposite direction (cloud to device) using a pattern we call command and control.

Because the Notecard is a generic data pump, the commands you send to your devices can be as simple or as complex as you need them to be. For example you could tell a light to turn off, a robot to move left, or a machine to stop operating.

The Notecard allows you to send these commands remotely, giving you the ability to perform actions on devices located anywhere in cellular range. Let's look at how it works.

Sending Commands to Devices

The easiest way to send a command to a device is with the Notehub API's note.add request.

note

If you're new to the Notehub API, you'll want to read our Notehub API tutorial before continuing, as the tutorial shows you the basics of using the API, including how to generate a bearer token.

To use the note.add request you need to send a POST to the Notehub API's /projects/<projectUID>/devices/<deviceUID>/notes/<file> endpoint, where projectUID is your ProjectUID, deviceUID is the DeviceUID of a device within your Notehub project, and <file> is the name Notefile you'd like to use (e.g. data.qi).

The body of the note.add request can be any JSON object you'd like. For example, the curl command below shows how to send {"command": "on"} to a device.

curl -X POST
     -L 'https://api.notefile.net/v1/projects/<projectUID>/devices/<deviceUID>/notes/<file>'
     -H 'Authorization: Bearer <access_token>'
     -d '{"body": {"command": "on"}}'

Receiving Commands on a Device

Once you have Notes queued in Notehub, you next need to receive those Notes on your device. You can configure how often your device checks for inbound notes using the hub.set request's mode, inbound, and sync arguments.

For example, running the command below places a Notecard in continuous mode. Devices in continuous mode maintain a constant connection with Notehub, but also use considerably more battery to maintain the connection. Setting the request's sync argument to true ensures inbound notes sync as soon as they're detected on Notehub.

    {
      "req": "hub.set",
      "mode": "continuous",
      "sync": true
    }
    J *req = NoteNewRequest("hub.set");
    JAddStringToObject(req, "mode", "continuous");
    JAddBoolToObject(req, "sync", true);
    
    NoteRequest(req);
    req = {"req": "hub.set"}
    req["mode"] = "continuous"
    req["sync"] = True
    
    card.Transaction(req)
    note

    Check out our minimizing latency guide for additional information on sending low-latency commands.

    If your project is more battery-conscious, you may wish to instead place your device in periodic mode. Devices in periodic mode check for inbound Notes at a given interval, which you can specify with the inbound argument (in minutes).

    The request below tells the Notecard to check for inbound Notes every 60 minutes.

      {
        "req": "hub.set",
        "mode": "periodic",
        "inbound": 60
      }
      J *req = NoteNewRequest("hub.set");
      JAddStringToObject(req, "mode", "periodic");
      JAddNumberToObject(req, "inbound", 60);
      
      NoteRequest(req);
      req = {"req": "hub.set"}
      req["mode"] = "periodic"
      req["inbound"] = 60
      
      card.Transaction(req)
      note

      If you place your device in periodic mode, you can use the hub.sync request while prototyping, as it triggers a synchronization of Notes between your Notecard and Notehub, even if your device is in periodic mode.

      Regardless of the configuration you use, once your device has received Notes you can check if any are present by running a note.changes request.

      The note.changes request returns multiple Notes (if present), so you can use the request to process multiple commands at once.

        {
          "req": "note.changes",
          "file": "data.qi"
        }
        J *req = NoteNewRequest("note.changes");
        JAddStringToObject(req, "file", "data.qi");
        
        NoteRequest(req);
        req = {"req": "note.changes"}
        req["file"] = "data.qi"
        
        rsp = card.Transaction(req)

        Resulting in the following JSON response:

        {
           "notes":{
              "1:8572":{
                 "body":{
                    "command":"on"
                 },
                 "time":1667855195
              }
           },
           "total":1
        }

        If you want to work with one Note at a time, you can alternatively use the note.get request to retrieve the next Note waiting in the Notefile.

          {
            "req": "note.changes",
            "file": "data.qi",
            "delete": true
          }
          J *req = NoteNewRequest("note.changes");
          JAddStringToObject(req, "file", "data.qi");
          JAddBoolToObject(req, "delete", true);
          
          NoteRequest(req);
          req = {"req": "note.changes"}
          req["file"] = "data.qi"
          req["delete"] = True
          
          rsp = card.Transaction(req)

          Resulting in the following JSON response:

          {
             "body":{
                "command":"on"
             },
             "time":1667855195
          }

          If no notes are available the note.get request returns a {note-noexist} error.

          {"err":"no notes available {note-noexist}"}
          note

          Both the note.changes and note.get requests allow to pass a delete argument, which controls whether to delete Note(s) after you retrieve them from the Notefile.

          At this point you've now seen how to send commands to devices using the Notehub API, as well as how to receive those commands using the Notecard. To put everything together, let's look at an example of how you can use a host to receive commands from the Notecard, and then take action.

          Receiving Commands on a Host

          When implementing a command-and-control architecture you may want to receive commands on a host microcontroller or single-board computer. A host MCU makes it possible to receive commands and take action, for example using commands like {"command":"on"} and {"command":"off"} as a trigger for turning on and off a light, respectively.

          We provide Notecard libraries that allow you to communicate with the Notecard on a wide variety of hosts.

          In this section you'll see the steps you need to take using the Notecard libraries to implement a command-and-control architecture.

          As an example, we'll show how to use the Notecard Arduino library running on a Blues Wireless Swan, but you can use the same steps to implement this architecture with any Notecard library and virtually any MCU.

          Step 1: Configure Your Notecard

          As a first step, remember that you must configure your Notecard so that it can receive commands. You can do this either in the in-browser terminal using the configuration below (remembering to substitute YOUR_PRODUCTUID_HERE) with your own value.

          {
            "req": "hub.set",
            "product": "YOUR_PRODUCTUID_HERE",
            "mode": "continuous",
            "sync": true
          }

          Or you can set up your Notecard using one of the Notecard's libraries. For example, the code below shows how to set up a Notecard to immediately receive inbound Notes using the Notecard's Arduino SDK.

          J *req = notecard.newRequest("hub.set");
          JAddStringToObject(req, "product", "YOUR_PRODUCTUID_HERE");
          JAddStringToObject(req, "mode", "continuous");
          JAddBoolToObject(req, "sync", true);
          notecard.sendRequest(req);

          Step 2: Check for Inbound Notes

          Once you have your Notecard set up, you next need to check for inbound notes. The most common way to do this check is with the note.changes or note.get requests discussed in the previous section.

          As another option, you can also configure the Notecard to use an interrupt that allows you to use the ATTN pin to wake your host when you receive a new Note in a specified Notefile. If you're interested in that approach, check out Handling Notecard Interrupts.

          Regardless of the approach you take, you'll need some logic that can parse the command you need out of the Notecard's JSON response. The code below shows an Arduino example that parses the note.get request's JSON and returns the command. (For example, if note.get returns {"body:{"command":"on"}) this function returns "on").

          char* getLastCommand()
          {
            // To hold "on" and "off". Increase the size if you need to send longer commands.
            static char command[4];
          
            J *req = notecard.newRequest("note.get");
            JAddStringToObject(req, "file", "data.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));
            }
            
            notecard.deleteResponse(rsp);
            return command;
          }
          note

          If you're using note.changes you'll need some additional logic as the request can return multiple Notes in one response.

          Finally, if you're not using interrupts you need to check for inbound notes in a loop. For our Arduino example this is straightforward as Arduino provides a built-in loop function. The code below checks for inbound notes every second.

          void loop()
          {
            char* command = getLastCommand();
          
            // Use the command (which we'll do in the next step)
          
            // Wait one second before looking for changes again
            delay(1000);
          }

          Step 3: Take Action

          As a last step, now that you have your command you can take project-specific actions. For example, this is where you may want to turn on/off a light, move a robot in a given direction, or shut off a piece of hardware.

          As one example, the code below shows how to use {"command":"on"} to turn on the Swan MCU's built-in LED, and {"command":"off"} to turn that same light off.

          char* command = getLastCommand();
          
          if (!strncmp(command, "on", sizeof("on")))
          {
            notecard.logDebug("Turning light on");
            digitalWrite(LED_BUILTIN, HIGH);
          }
          if (!strncmp(command, "off", sizeof("off")))
          {
            notecard.logDebug("Turning light off");
            digitalWrite(LED_BUILTIN, LOW);
          }

          This example's full code is below for your reference. Remember that although this implementation uses Arduino and the Swan, you can perform the same steps using any of the Notecard's libraries, and you can run your logic on virtually any MCU.

          note

          Refer back to the section on sending commands to devices to learn how to send the necessary Notehub API requests to test this example.

          #include <Notecard.h>
          
          #define serialDebug Serial
          #define productUID "YOUR_PRODUCTUID_HERE"
          
          Notecard notecard;
          
          void setup()
          {
            while (!serialDebug);
            serialDebug.begin(115200);
            notecard.begin();
            notecard.setDebugOutputStream(serialDebug);
          
            // Configure the Notecard
            J *req = notecard.newRequest("hub.set");
            JAddStringToObject(req, "product", productUID);
            JAddStringToObject(req, "mode", "continuous");
            JAddBoolToObject(req, "sync", true);
            notecard.sendRequest(req);
          
            // Initialize digital pin LED_BUILTIN as an output,
            // and ensure the light starts off.
            pinMode(LED_BUILTIN, OUTPUT);
            digitalWrite(LED_BUILTIN, LOW);
          }
          
          char* getLastCommand()
          {
            // To hold "on" and "off". Increase the size if you need to send longer commands.
            static char command[4];
          
            J *req = notecard.newRequest("note.get");
            JAddStringToObject(req, "file", "data.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));
            }
            
            notecard.deleteResponse(rsp);
            return command;
          }
          
          void loop()
          {
            char* command = getLastCommand();
          
            if (!strncmp(command, "on", sizeof("on")))
            {
              notecard.logDebug("Turning light on");
              digitalWrite(LED_BUILTIN, HIGH);
            }
            if (!strncmp(command, "off", sizeof("off")))
            {
              notecard.logDebug("Turning light off");
              digitalWrite(LED_BUILTIN, LOW);
            }
          
            // Wait one second before looking for changes again
            delay(1000);
          }