Blues provides an ecosystem of hardware and software to simplify wireless connectivity for IoT devices. Voltaic uses Blues’ Notecard and Notecarrier in our battery health monitoring module for our solar powered systems and we have customers using our solar panels to power their IoT applications. 

This is an introduction to create a simple, solar powered, cellular connected device. In this post, we:

  • Explain the Blues ecosystem (The Blues Developer Center is also an invaluable resource)
  • Show you how to program a device in the Arduino IDE to measure and report temperature then go to sleep
  • Measure the power consumption with a Qoitech Otii Ace and size a solar system to support it
  • Display that data to a Qubitro dashboard

The Blues Notecard

Blues’ core hardware product is the Blues Notecard, a “device-to-cloud data pump” that connects physical devices to cloud applications via low-power cellular, Wi-Fi, or LoRa.

      Notecards

There are available starter kits and the basic  Blues Starter Kit includes a Notecarrier F Development board and Notecard with a low power cellular and GPS module and on-board temperature sensor. The Notecard also ships with an embedded SIM and 10 years + 500 MB of data. No SIM setup is required. 

To configure the Notecard firmware (including the cellular modem) you use JSON commands. No AT commands are needed.

This is the request to get information about your card:

{"req":"card.version"}

The request will return something similar to the following response:

{
  "body":{
    "org":"Blues Wireless",
    "product":"Notecard",
    "version":"notecard-1.5.6",
    "ver_major":1,
    "ver_minor":5,
    "ver_patch":6,
    "ver_build":13807,
    "built":"Oct  7 2021 14:32:14"
  },
  "version":"notecard-1.5.6.13807",
  "device":"dev:864475040543182",
  "name":"Blues Wireless Notecard",
  "sku":"NOTE-NBGL-500",
  "board":"1.11",
  "api":1
}

To get location data you issue the following JSON command:

{“req”:”card.location”}

In a C/C++ environment you make your JSON requests like this:

J *req= NoteNewRequest(“card.location”);

And to parse the request’s response in C/C++ you can use statements like these::

J *rsp= NoteRequestResponse(req);
J *status=JGetString(rsp, “status”);
J *mode=JGetString(rsp, “mode”);

All interaction between the Notecard and a host microcontroller or microprocessor occurs using this JSON protocol. It is important to note that to send a subsequent request to the Notecard, you must wait to receive the response from the previous request as it is unsafe to send a second request without waiting for the first to complete.

Notecards are connected to Notecarriers through I2C.  The I2C interface is available at address 0x17 and can be reconfigured using a card.io request.

The Blues Notecarrier

Notecarriers are development boards. The Notecarrier F which comes in the Blues Starter Kit works with any feather compatible MCU, while the Notecarrier R is compatible with the Arduino MKR and Pro boards.

Notecarriers A and F ship with low-profile cellular and GPS antennas and allow for connections to solar panels and Lithium Ion batteries.

Notecarriers A and F

The Blues Notehub

The Blues Notehub is a cloud-based software as a service (SaaS) platform found at Notehub.io and is the central hub for device management, data routing, and cloud integration. Notehub is where you can view your Notecard’s event data and securely route that data to third-party cloud applications, like AWS, Azure, or Qubitro

third-party cloud applications

Notehub also provides functionality for managing Notecard and host firmware and allows users to create and manage their projects, fleets, and teams. 

A Note

A Note is a JSON object containing your content, and is the primary means of sending data to/from a Notecard.

Notecard overview

https://dev.blues.io/notecard/notecard-walkthrough/overview/

 

Getting Started with Blues

The low power consumption of the notecard makes it ideal for low power applications including those powered by solar panels. Here is an outline of the basic steps to follow to set up your IoT device:

  1. Setup the hardware
  2. Register your Blues Wireless device in Notehub
  3. Assign your Notecard to a Cloud Project 
  4. Validate your ProductUID and Connection
  5. Develop your IoT application
    1. Queue Notes to Your Notecard
    2. Set up a microcontroller
    3. Integrate a Notecard into your code
    4. Power your device
    5. Size your system
    6. Route data to the cloud
    7. Use JSONata to get your data in the format that suits your needs

    Hardware for a Low Power Solar Device with Blues

    This device will read and report temperature. It is powered by a pair of 0.3 watt solar panels and an LIC (lithium Ion Capacitor)

    Software

    URLS

     

    1. Setup Hardware

    You’ve ordered the Starter Kit and now it’s time to put it to use.

    1. Remove the screw with a Phillips head screwdriver from the Notecarrier:
      Notecard setup

      https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/

       

    2. Place the Notecard into the M.2 slot on the Notecarrier. Once inserted, press gently until the Notecard is inserted and the screw receptacle hole is completely visible. Re-insert the screw, being sure NOT to over tighten the screw:
      Notecard and Notecarrier

      https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/

       

    3. Push the cable end from the antenna labeled LTE firmly onto the MAIN socket on the Notecard. When seated properly, you will feel it “click” into place. NOTE: If you are using the Molex 213353 antenna, the LTE and GPS labels may be absent. Use the center wire (the wire on the left) for LTE.
      Notecarrier and antenna

      https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/

       

    4. Push the cable end from the antenna labeled GPS onto the GPS socket on the Notecard.

      Notecarrier and GPS

      https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/

    2. Register Your Blues Wireless device in Notehub.

    To set up your first simple solar powered IoT device, you need to create a ProductUID and then configure your Notecard to connect to a cloud project on Notehub. You need to do this in order to sync data. 

      1. Navigate your browser to Notehub.io and sign in or sign up:Blues Sign up
      2. Blues Projects provide a way to organize fleets of devices, distribute firmware, organize teams, and provide controls for team access. Click on the +Create Project button to get started: Create Project Button
      3. A Project is composed of one or more identifiers called ProductUIDs. Each Project is created with an initial ProductUID, enabling you to associate your Notecard(s) with your Project as soon as it is created. Complete the fields in the popup and click on the +Create Project button:First Project In order to help ensure your ProductUID is unique, every ProductUID is prepended with the reverse domain name notation of your account email. For example, I signed up with [email protected], so my product takes the form of com.voltaicsystems.liz:your_product_uid.
      4. Copy/take note of your ProductUID because this identifier will be used by Notehub to associate your Notecard to your project.In my case the ProductUID is: com.voltaicsystems.liz:my_first_project
        Add a New Device

    3. Assign Your Notecard to a Cloud Project

    You need to tell the Notecard about your Notehub project so it knows where to send your data. To associate the Notecard with your project in Notehub you assign the ProductUID to your Notecard. Note that while a Notecard can easily be moved between projects over time, it can only belong to one project at a time.

    1. Connect a microUSB cable from the Notecarrier’s USB port to your computer’s USB port.
    2. Open the In-Browser Terminal.
    3. Within the In-Browser Terminal, click the USB Notecard button. A browser prompt might appear asking for permission to connect to a USB serial device. If it appears click on Connect:In-Browser Terminal
      usbmodem
    4. All requests and responses to/from the Notecard are in JSON format and are structured with the command as the value of a req key. Additional arguments are written as additional key-value pairs. You issue commands at the command prompt:
      JSON
      To get started, paste either this line at the command prompt:
      {"req":"card.version"}

      The first request returns metadata about your Notecard. Something similar to this:

      {
       "version": "notecard-7.4.2.16888",
       "device": "dev:351077454527113",
       "name": "Blues Wireless Notecard",
       "sku": "NOTE-WBGLW",
       "ordering_code": "HB0YT1N0AEAU",
       "board": "5.13",
       "wifi": true,
       "cell": true,
       "gps": true,
       "api": 7,
       "body": {
        "org": "Blues Wireless",
        "product": "Notecard",
        "target": "u5",
        "version": "notecard-u5-7.4.2",
        "ver_major": 7,
        "ver_minor": 4,
        "ver_patch": 2,
        "ver_build": 16888,
        "built": "Aug 27 2024 19:08:01"
       }
      }
      
    5. The next step is to set the ProductUID. You’ll start by sending a hub.set JSON request to your Notecard. Once the Notecard has finished processing your request, it will send a JSON response back to your computer to let you know that the request is complete.The JSON object hub.set consists of two key-value pairs. The first provides the name of the request, denoted with the key req and a value of hub.set. The second (product) is one of the arguments for the hub.set request.
    6. Copy and paste the following Notecard request, making sure to replace com.your-company.your-name:your_product with your ProductUID:{“req”: “hub.set” “product”:”com.your-company.your-name:your_product”}hub.setAn empty JSON object ({}) from the Notecard indicates a successful request. If an error occurs, the Notecard will return a JSON object with an err key and a string describing the error that occurred.
      Error described

    4. Validate ProductUID and Connection

    You now need to validate the Notecard configuration. To do this you’ll perform a manual sync with Notehub and then request sync status updates from the Notecard.

    1. Initiate a synchronization between the Notecard and Notehub with a hub.sync request, as shown below:{“req”:”hub.sync”}hub command
    2. Once a sync has started, you can monitor the state of the sync by watching the status bar at the top of the in-browser terminal.Before Sync
      Sync Update
    3. As soon as you see “Successful Notehub sync [x]s ago”, the sync is complete. If you’re having trouble connecting, enter {“req”:”hub.sync.status”} and check if your status includes “no project was found” or “can’t open Notehub” errors.If you’re having problems:
      You may have a typo, or you may have passed a project name to your hub.set request’s product instead of a ProductUID. If this is the case, run another hub.set request with the correct ProductUID, and then issue another hub.sync request.If your ProductUID seems correct and you’re still having no luck, you may have a connectivity issue. In this case consult the Blues guide on Diagnosing Cellular Connectivity Issues.
    4. Return to Notehub and refresh the Devices page. You should see that a device has been added to your project:
      Devices

    5. Develop your IoT Application

    You can continue to use the terminal for simple projects, like this GPS reindeer  tracker application, or you can program a compatible microcontroller.

    In either case you will work with the Notecard, Notecarrier, and Notehub by queueing and adding Notes  with data to your Notecard.

    Let’s assume you have connected a sensor like the DHT22 to read temperature and humidity data to a MCU like the Blues Swan. To add a Note, you will use the Notecard’s note.add API that includes a body argument which accepts any arbitrary JSON data.

    In its simplest form, adding a Note could look like this:

    JSON:

    {"req":"note.add","body":{"temp":35.5,"humid":56.23}}

    C/C++:

    {
       J *req = notecard.newRequest("note.add");
       if (req != NULL) {
         JAddStringToObject(req, "file", "sensors.qo");
         JAddBoolToObject(req, "sync", true);
         J *body = JAddObjectToObject(req, "body");
         if (body != NULL) {
    	JAddNumberToObject(body, "temperature", temperature);
           JAddNumberToObject(body, "humidity", humidity);
         }
         notecard.sendRequest(req);
       }
     }
  1. To view the data navigate to Notehub.io:First Project
  2. Click on the “card” with your Project. The device dashboard for your Project will load and you’ll see your Notecard in the Devices list.Devices
  3. Click Events in the left-side navigation. In the Events list, you should see your Note in the list with the sensor data in the body. EventsYou don’t necessarily need to have a MCU, but having one allows you to create more sophisticated applications..

6. Setting up a microcontroller

The Starter Kit comes with the Blues Swan, a feather compatible MCU. The Swan can be programmed in the Arduino IDE, with a programmer like the STLINK-V3MINIE ST-LINK V3 PROG FOR STM32. Blues sells a clone, the SWD Programmer & Debugger, but I ran into some difficulties with it not consistently recognizing my USB ports.

Download and install STM32CubeCLT, which is a toolset that allows third-party IDEs to work with STM32-based host MCUs.

  1. Open up Arduino and add the following URL to the Additional Boards URL in Preferences: https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
    Arduino Board Manager
  2. Restart Arduino IDE.
  3. Go to the Tools > Boards > Boards Manager… menu option.  Search for “STM32 MCU based boards”, and install or update to version 2.8.1 or greater.STM32 boards
  4. Under Tools > Board, select “STM32 MCU based boards”, and then “Blues boards”
  5. Under Tools > Board Part Number, select “Swan R5.”Swan
  6. Under Tools > USB support (if available), select “CDC (generic ‘Serial’ supersede U(S)ART)usbmodem
  7.  Under Tools > Upload method, select “STM32CubeProgrammer (SWD).”
  8. Plug the STLINK-V3MINI into your computer over USB.
  9. Plug the Cortex-Debug connector from the STLINK-V3MINI into the Swan.
  10. You can plug the Swan into a power source (e.g. a LiIon cell), but if you want to see Serial output from the Swan, you’ll need to either use a USB cable as the power source or customize your sketch to use the STLINK-V3MINI for Serial output.STLINK-V3MINI
  11. Test your setup with a simple sketch:
    1. In the Arduino IDE, use File > New to create a new sketch.
    2. Overwrite the provided boilerplate code with the following to cause the onboard LED to blink repeatedly:
      // the setup function runs once when you press reset or power the board
      void setup() {
       // initialize digital pin LED_BUILTIN as an output.
       pinMode(LED_BUILTIN, OUTPUT);
      }
      
      // the loop function runs over and over again forever
      void loop() {
       digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
       delay(1000);                       // wait for a second
       digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
       delay(1000);                       // wait for a second
      }
    3. Select the port connected to the STLINK.
    4. Upload the sketch.
    5. If all goes well, the Swan’s LED will blink. 

    The next step is to create a program that incorporates the Notecard.

    7. Integrating a Notecard into an Arduino Program

    To communicate with the Notecard over I2C, you need to install the note-arduino library

    1. Add the Blues Wireless Notecard library to the Arduino IDE.
      Arduino IDE
    2. Create a new sketch and add the library to your sketch by selecting Sketch > Include Library > Contributed Libraries > Blues Wireless Notecard menu option:Blues Notecard
    3. Follow these steps to set up the Notecard in your program:
      • Configure a Serial interface:
        #define usbSerial Serial

        USBSerial

      • Add a definition for your ProductUID using the value you created in  Notehub:
        #define productUID "com.your-company.your-name:your_product"

        ProductUID

      • Declare a global object to represent the Notecard: 

        Notecard notecard;

        Declare Notecard

      • In setup(), initialize the usbSerial object and tell the Notecard library to use this serial object for sending debug output.
        delay(2500);
        usbSerial.begin(115200);

        setup

      • Initialize an instance of the Notecard class and initialize an I2C connection to the Notecard using the notecard.begin() function.
        notecard.begin();
      • Use setDebugOutputStream() to link the debug output to usbSerial with the following code:
        notecard.setDebugOutputStream(usbSerial);
      • Create a hub.set request, to associate the Notecard with the ProductUID of your project . Set the Notecard to operate in continuous mode. This mode indicates that the device should immediately make a connection to Notehub and keep it active.
        {
         	J *req = notecard.newRequest("hub.set");
         	JAddStringToObject(req, "product", productUID);
         	JAddStringToObject(req, "mode", "continuous");
         	notecard.sendRequest(req);
        }
      •  Click the Upload button (right arrow icon) to flash the firmware to your device. You need to use the USB connected to the STLINK-V3MINI to upload.Open a new sketch and connect the port to the other USB port. You can now use a Serial Monitor on the USB Port connected to the Swan to view the device output. Here is the basic starter code:
        #include <Notecard.h> 
        #define usbSerial Serial
        #define productUID "[your ProductUID]"
        
        Notecard notecard;
        
        void setup() {
         // put your setup code here, to run once:
         delay(2500);
         usbSerial.begin(115200);
         notecard.begin();
         notecard.setDebugOutputStream(usbSerial);
        	{
         	J *req = notecard.newRequest("hub.set");
         	JAddStringToObject(req, "product", productUID);
         	JAddStringToObject(req, "mode", "continuous");
         	notecard.sendRequest(req);
            }
        }
        void loop() {
         // put your main code here, to run repeatedly:
        }
        
    4. The next step is to connect to Notehub. Once you start capturing readings, your Notecard will initiate a connection to Notehub and will start transferring Notes. To follow along, add a DHT22 temperature sensor:
    5. Connect the data line to pin D5
    6. Install the following libraries
    7. Create a new sketch.
    8. Add the following Include statements:
      #include "DHT.h"
      #include <Notecard.h>
      #include "STM32LowPower.h"
    9. Add the following definitions:
      #define usbSerial Serial
      #define DHTPIN 5  // Digital pin connected to the DHT sensor
      
      // Uncomment whatever type you're using!
      //#define DHTTYPE DHT11   // DHT 11
      #define DHTTYPE DHT22  // DHT 22  (AM2302), AM2321
      //#define DHTTYPE DHT21   // DHT 21 (AM2301)
      
      // This is the unique Product Identifier for your device
      #define productUID "[your productUID]" 
      
    10.  Initialize the sensor:
      // Initialize DHT sensor.
      DHT dht(DHTPIN, DHTTYPE);
    11. Create variables. The notecard will be the global object that  represents the Notecard: 
      Notecard notecard;
      static bool registerNotefileTemplate();
      static const size_t PERIOD_S = 60;
    12. Define the registerNotefileTemplate() function. This function will create a template.  Templates allow you to optimize data storage and transmission and are an important feature of the ecosystem.Templates serve two main purposes:
      1. Optimize storage space on the Notecard
      2. Reduce bandwidth usage when syncing data to Notehub

      Templates act as a schema or structure for Notes added to a specific Notefile. When you create a template, you’re essentially telling the Notecard how future Notes in that Notefile will be structured.

      To create a template, you use the file argument to specify the Notefile to which the template should be applied. You use the body argument to specify a template body, similar to the way you’d make a note.add request. That body must contain the name of each field expected in each note.add request, and a value that serves as the hint indicating the data type to the Notecard. Each field can be a boolean, integer, float, or string:

      static bool registerNotefileTemplate() {
       // Create the request
       J *req = notecard.newRequest("note.template");
       if (req == NULL) {
         Serial.println("Could not create fall template request");
         return false;
       }
       // Create the body
       J *body = JCreateObject();
       if (body == NULL) {
         Serial.println("Could not create fall template body");
         JDelete(req);
         return false;
       }
      
      
       // Setup name and parameters for template
       JAddStringToObject(req, "file", "sensors.qo");
       JAddStringToObject(req, "format", "compact");
       JAddNumberToObject(body, "temperature", TFLOAT64);
       JAddNumberToObject(body, "humidity", TFLOAT64);
       JAddNumberToObject(body, "heat_index_F", TFLOAT64);
       JAddNumberToObject(body, "heat_index_C", TFLOAT64);
       JAddNumberToObject(body, "voltage", TFLOAT64);
       JAddNumberToObject(body, "time", TUINT32);
      
      
       // Attach the body to the request, and send it to the gateway
       JAddItemToObject(req, "body", body);
      
      
       Serial.println("Template created");
       if (!NoteRequest(req)) {
         Serial.println("Could not send  template request");
         return false;
       }
       return true;
      }
    13. Navigate to setup(), and add the following to setup the Serial connection:
      #ifdef usbSerial
       // If you open Arduino's serial terminal window, you'll be able to watch
       // JSON objects being transferred to and from the Notecard for each request.
       usbSerial.begin(115200);
       const size_t usb_timeout_ms = 3000;
       for (const size_t start_ms = millis(); !usbSerial && (millis() - start_ms) < usb_timeout_ms;)
         ;
      
      
         // For low-memory platforms, don't turn on internal Notecard logs.
      #ifndef NOTE_C_LOW_MEM
       notecard.setDebugOutputStream(usbSerial);
      #else
      #pragma message("INFO: Notecard debug logs disabled. (non-fatal)")
      #endif  // !NOTE_C_LOW_MEM
      #endif  // usbSerial
      
      
       // Initialize the physical I/O channel to the Notecard
      #ifdef txRxPinsSerial
       notecard.begin(txRxPinsSerial, 9600);
      #else
       notecard.begin();
      #endif
       usbSerial.begin(115200);
      
      
       usbSerial.println("Setup Start");
    14. Configure LowPower so that you can put the Swan into deep sleep:
      // Configure low power
       LowPower.begin();
      
    15. Configure the sensor:
      dht.begin();
    16. Instead of using the In-Browser Terminal, we’re going to call hub.set() from within the Arduino IDE. The following connects the Notecard to the project and sets up how the Notecard will communicate. In this case it is in continuous mode as long as the Notecard is connected to USB. Once the power source switches to battery, the mode switches to periodic in order to save power. In the code snippet below, the voutbound syncs every 10 minutes if the device is powered by USB, every 60 minutes if the battery level is high, every 360 minutes if the battery is not high or low, every 720 minutes if the voltage level is low, and stops syncing if the battery is dead. It is the  uperiodic argument in the hub.set request that configures the Notecard to use periodic mode when the USB/line power is disconnected.:
      {
         J *req = NoteNewRequest("hub.set");
         JAddStringToObject(req, "product", productUID);
         JAddStringToObject(req, "mode", "continuous");
         JAddBoolToObject(req, "sync", true);
          JAddStringToObject(req, "voutbound", "usb:10;high:60;normal:360;low:720;dead:0");
         JAddStringToObject(req, "vinbound", "usb:60;high:120;normal:720;low:1440;dead:0");
         JAddBoolToObject(req, "uperiodic", true);
         notecard.sendRequest(req);
       }
    17. Now add code to tell the Notecard that we will be powering it by a lic. This is used for comparing voltage thresholds:
      {
      //Lithium-ion capacitors. Equivalent to "usb:4.6;high:3.8;normal:3.1;low:0"
         J *req = notecard.newRequest("card.voltage");
         JAddStringToObject(req, "mode", "lic");
         notecard.sendRequest(req);
       }
      
    18. Next we add error checking to make sure our template was created:
      if (!registerNotefileTemplate()) {
         usbSerial.println("Notefile Template setup failed");
         while (1) {};
       }
      
    19. Add a call to a function to add a new note:
      addNote();
    20. For debugging add a print statement that informs you that your setup is complete:
      usbSerial.println("Setup End");
    21. Define the addNote() function. It’s important that your Note matches your template. If there is a mismatch, you will get an error. At the end of the function, we’ll call sleep() to conserve power. We’ll change the duration of this function after testing.
      static void addNote() {
      
       int currentTime = getTime();
      // Do the same to retrieve the voltage that is detected by the Notecard on
       // its `V+` pin.
       //get voltage
       float voltage = getVoltage();
       float t = dht.readTemperature();
       float h = dht.readHumidity();
       float f = dht.readTemperature(true);
      
      // Check if any reads failed and exit early (to try again).
       if (isnan(h) || isnan(t) || isnan(f)) {
         Serial.println(F("Failed to read from DHT sensor!"));
         return;
       }
      
       // Compute heat index in Fahrenheit (the default)
       float hif = dht.computeHeatIndex(f, h);
       // Compute heat index in Celsius (isFahreheit = false)
       float hic = dht.computeHeatIndex(t, h, false);
      Serial.print(F("Humidity: "));
       Serial.print(h);
       Serial.print(F("%  Temperature: "));
       Serial.print(t);
       Serial.print(F("°C "));
       Serial.print(f);
       Serial.print(F("°F  Heat index: "));
       Serial.print(hic);
       Serial.print(F("°C "));
       Serial.print(hif);
       Serial.println(F("°F"));
       {
         J *req = notecard.newRequest("note.add");
         if (req != NULL) {
           JAddStringToObject(req, "file", "sensors.qo");
           JAddBoolToObject(req, "sync", true);
           J *body = JAddObjectToObject(req, "body");
           if (body != NULL) {
            
             JAddNumberToObject(body, "temperature", t);
             JAddNumberToObject(body, "humidity", h);
             JAddNumberToObject(body, "heat_index_F", hif);
             JAddNumberToObject(body, "heat_index_C", hic);
             JAddNumberToObject(body, "voltage", voltage);
             JAddNumberToObject(body, "time", currentTime);
           }
           notecard.sendRequest(req);
         }
       }
       usbSerial.println("note added");
       LowPower.deepSleep(60 *1000);
      }
      
    22. Define the getVoltage() function to poll the voltage level on the Notecard:
      float getVoltage() {
       // retrieve the voltage that is detected by the Notecard on
       // its `V+` pin.
       float v = 0;
       J *rsp = notecard.requestAndResponse(notecard.newRequest("card.voltage"));
       if (rsp != NULL) {
         v = JGetNumber(rsp, "value");
         notecard.deleteResponse(rsp);
       }
       return v;
      }
      
    23. Define the getTime() function which  returns the time expressed as a Unix epoch value:
      int getTime() {
       int t = 0;
       J *rsp = notecard.requestAndResponse(notecard.newRequest("card.time"));
       if (rsp != NULL) {
         t = JGetInt(rsp, "time");
         usbSerial.println(t);
         notecard.deleteResponse(rsp);
       }
       return t;
      }
    24. Navigate to the loop() function and add a call to addNote():
      addNote();
    25. Here is the complete program:
      #include "DHT.h"
      #include <Notecard.h>
      #include "STM32LowPower.h"
      
      // #define txRxPinsSerial Serial1
      #define usbSerial Serial
      #define DHTPIN 5  // Digital pin connected to the DHT sensor
      
      // Uncomment whatever type you're using!
      //#define DHTTYPE DHT11   // DHT 11
      #define DHTTYPE DHT22  // DHT 22  (AM2302), AM2321
      //#define DHTTYPE DHT21   // DHT 21 (AM2301)
      
      // This is the unique Product Identifier for your device
      #define productUID "com.voltaicsystems.liz:c117_example"  // "com.my-company.my-name:my-project"
      
      // Initialize DHT sensor.
      DHT dht(DHTPIN, DHTTYPE);
      
      Notecard notecard;
      
      static bool registerNotefileTemplate();
      static const size_t PERIOD_S = 60;
      
      // Register the notefile template for our data
      static bool registerNotefileTemplate() {
       // Create the request
      
      
       J *req = notecard.newRequest("note.template");
        if (req == NULL) {
         Serial.println("Could not create fall template request");
         return false;
       }
      
      
       // Create the body
       J *body = JCreateObject();
       if (body == NULL) {
         Serial.println("Could not create fall template body");
         JDelete(req);
         return false;
       }
      
      
       // Setup name and parameters for template
       JAddStringToObject(req, "file", "sensors.qo");
       JAddStringToObject(req, "format", "compact");
       JAddNumberToObject(body, "temperature", TFLOAT64);
       JAddNumberToObject(body, "humidity", TFLOAT64);
       JAddNumberToObject(body, "heat_index_F", TFLOAT64);
       JAddNumberToObject(body, "heat_index_C", TFLOAT64);
       JAddNumberToObject(body, "voltage", TFLOAT64);
       JAddNumberToObject(body, "time", TUINT32);
      
      
       // Attach the body to the request, and send it to the gateway
       JAddItemToObject(req, "body", body);
      
      
       Serial.println("Template created");
       if (!NoteRequest(req)) {
         Serial.println("Could not send  template request");
         return false;
       }
       return true;
      }
      
      
      void setup() {
      pinMode(LED_BUILTIN, OUTPUT);
      digitalWrite(LED_BUILTIN, HIGH);
       // Set up for debug output (if available).
      #ifdef usbSerial
       // If you open Arduino's serial terminal window, you'll be able to watch
       // JSON objects being transferred to and from the Notecard for each request.
       usbSerial.begin(115200);
       const size_t usb_timeout_ms = 3000;
       for (const size_t start_ms = millis(); !usbSerial &amp;&amp; (millis() - start_ms) &lt; usb_timeout_ms;)
         ;
      
      
         // For low-memory platforms, don't turn on internal Notecard logs.
      #ifndef NOTE_C_LOW_MEM
       notecard.setDebugOutputStream(usbSerial);
      #else
      #pragma message("INFO: Notecard debug logs disabled. (non-fatal)")
      #endif  // !NOTE_C_LOW_MEM
      #endif  // usbSerial
      
      
       // Initialize the physical I/O channel to the Notecard
      #ifdef txRxPinsSerial
       notecard.begin(txRxPinsSerial, 9600);
      #else
       notecard.begin();
      #endif
       usbSerial.begin(115200);
      
      
       usbSerial.println("Setup Start");
       // Configure low power
       LowPower.begin();
       notecard.begin();
       dht.begin();
      
      
       {
         J * req = notecard.newRequest("hub.set");
         JAddStringToObject(req, "product", productUID);
         JAddStringToObject(req, "mode", "periodic");
         JAddStringToObject(req, "vinbound", "usb:60;high:120;normal:240;low:480;dead:0");
         JAddStringToObject(req, "voutbound", "usb:1;high:40;normal:60;low:120;dead:0");
         notecard.sendRequest(req);
       }
      
      
       {
         J *req = notecard.newRequest("card.voltage");
         JAddStringToObject(req, "mode", "lic");
         notecard.sendRequest(req);
       }
      
      
      
      
       if (!registerNotefileTemplate()) {
         usbSerial.println("Notefile Template setup failed");
         while (1) {};
       }
      
      
       addNote();
       usbSerial.println("Setup End");
       digitalWrite(LED_BUILTIN, LOW);
      }
      float getVoltage() {
       //Retrieve the voltage that is detected by the Notecard on
       // its `V+` pin.
       float v = 0;
       J *rsp = notecard.requestAndResponse(notecard.newRequest("card.voltage"));
       if (rsp != NULL) {
         v = JGetNumber(rsp, "value");
         notecard.deleteResponse(rsp);
       }
       return v;
      }
      
      
      int getTime() {
       int t = 0;
       J *rsp = notecard.requestAndResponse(notecard.newRequest("card.time"));
       if (rsp != NULL) {
      
      
         t = JGetInt(rsp, "time");
         usbSerial.println(t);
         notecard.deleteResponse(rsp);
       }
       return t;
      }
      
      
      static void addNote() {
       digitalWrite(LED_BUILTIN, HIGH);
       int currentTime = getTime();
       // Do the same to retrieve the voltage that is detected by the Notecard on
       // its `V+` pin.
       //get voltage
       float voltage = getVoltage();
       float t = dht.readTemperature();
       float h = dht.readHumidity();
       float f = dht.readTemperature(true);
      // Check if any reads failed and exit early (to try again).
       if (isnan(h) || isnan(t) || isnan(f)) {
         Serial.println(F("Failed to read from DHT sensor!"));
         return;
       }
      
      
       // Compute heat index in Fahrenheit (the default)
       float hif = dht.computeHeatIndex(f, h);
       // Compute heat index in Celsius (isFahreheit = false)
       float hic = dht.computeHeatIndex(t, h, false);
      Serial.print(F("Humidity: "));
       Serial.print(h);
       Serial.print(F("%  Temperature: "));
       Serial.print(t);
       Serial.print(F("°C "));
       Serial.print(f);
       Serial.print(F("°F  Heat index: "));
       Serial.print(hic);
       Serial.print(F("°C "));
       Serial.print(hif);
       Serial.println(F("°F"));
       {
         J *req = notecard.newRequest("note.add");
         if (req != NULL) {
           JAddStringToObject(req, "file", "sensors.qo");
           JAddBoolToObject(req, "sync", true);
           J *body = JAddObjectToObject(req, "body");
           if (body != NULL) {
             // JAddStringToObject(body, "status", temperature > 26.67 ? "hot" : "normal");  // 80F
             JAddNumberToObject(body, "temperature", t);
             JAddNumberToObject(body, "humidity", h);
             JAddNumberToObject(body, "heat_index_F", hif);
             JAddNumberToObject(body, "heat_index_C", hic);
             JAddNumberToObject(body, "voltage", voltage);
             JAddNumberToObject(body, "time", currentTime);
           }
      
      
           notecard.sendRequest(req);
         }
       }
      
      
       usbSerial.println("note added");
       digitalWrite(LED_BUILTIN, LOW);
       LowPower.deepSleep(60 *1000);
      }
      void loop() {
       addNote();
      }
      
    26. Upload the program.
    27. If everything is working you can adjust the sleep duration. You can keep reprogramming the Swan to adjust the sleep interval, or you could add an ENV variable to control the interval and then modify that variable in Notehub to change the duration.
    28. Return to your Notehub project, go to the Devices page, and double click your device. You should see a screen that looks like this.Devices Page
    29. Click the Environment tab:
      Environment Tab
    30. Under the Device header, click on Go to project environment.
    31. Define a new environment variable named sleep_interval and set its value to 60. Click on Apply Changes.
      Apply Changes
    32. Back in the Arduino sketch go to setup() and adjust your existing hub.set configuration to set the sync argument to true. When sync is true, the Notecard synchronizes inbound environment variable changes as soon as they’re made in Notehub. Add the following line before notecard.sendRequest(req);
      JAddBoolToObject(req, "sync", true); // ADD THIS LINE
    33. Add this line after the #include lines at the top of the file:
      int getSleepInterval();
    34. Change the the call to LowPower.deepSleep() in the addNote() function to the following:
      int sleep_interval = getSleepInterval();
       LowPower.deepSleep(sleep_interval * 1000);
    35. Add a new function at the bottom of your sketch:
      int getSleepInterval(){
      int sleepIntervalSeconds = 60;
       J *req = notecard.newRequest("env.get");
       if (req != NULL) {
           JAddStringToObject(req, "name", "sleep_interval");
           JAddBoolToObject(req, "sync", true);
           J *rsp = notecard.requestAndResponse(req);
           int sleepingIntervalEnvVar = atoi(JGetString(rsp, "text"));
           if (sleepingIntervalEnvVar &gt; 0) {
             sleepIntervalSeconds = sleepingIntervalEnvVar;
           }
           notecard.deleteResponse(rsp);
       }
       return sleepIntervalSeconds;
      }
    36. Upload the modified program.
    37. With those modifications,  you can change the sleep interval from your web browser by modifying the variable under Environment>Device.Update variable

    8. Powering the Device

    To power the Blues Notecard you can use:

    1. A single-cell 3.7V LiIon cell with a 2-pin JST PH connector.
    2. A  solar cell (must be accompanied by LiIon cell). Note that there is an internal  solar charging circuit that is designed for use with 4.5-7V solar panels. You could use a single-cell 3.7 LiIon cell with the following Voltaic solar panels:
    3. You can also power the device by applying 2.5-5.5VDC to the V+ pin.
    4. You could also power the board with a solar-powered lithium-ion capacitor (LIC).

     

    9. Sizing your system

    Depending on signal strength and coverage in your area, it may take a few minutes for your Notecard to connect to Notehub and transfer data. But let’s say that everything is working as expected. Let’s disconnect the Notecard and Swan from the computer and use a single-cell 3.7V LiIon cell with a 2-pin JST PH connector to provide power.

    Theoretically, you should be able to find the power consumption of your IoT device with two multimeters: one set to read current and the other set to read voltage. You would then multiply the amps by the voltage to get the watts and then you would multiply the watts by 24 to get your device’s daily consumption in watt hours.

    The multimeter reading voltage should be connected to the positive and negative terminals of the power source. In this case a single-cell 3.7V LiPo or Lithium Ion Battery. You would also connect the red power cable to the V+  or VBAT pin on the Notecarrier.

     

    The GND cable of the multimeter measuring current should be connected to the ground connection of the battery and GND cable of the voltage multimeter. The red cable should be connected to the GND pin of the Notecarrier.Measuring

    Why this doesn’t work well is because the current mostly falls below what the multimeter can display. This is a good thing. It’s actually great. It means that the device is low powered and a perfect candidate for being powered by solar.

    In this case we need to use an Qoitech Otii Ace to get an accurate measurement.

    First we need to look at the Notecard’s DC Characteristics:

    DC Characteristics
    Then we set up the Otii Ace with the following settings:

    Label Value
    Voltage 3.3V
    General Settings Power Box
    OC protection 2A
    Channels Main current, Main power, Main voltage
    Baudrate 115200

    Qoitech Settings
    After starting the Qoitech Otii Ace by clicking on the power button on the screen, we record our values over a period of time:
    Qoitech ResultsAfter capturing an hour of data, we can determine our power consumption. The Qoitech Otii Ace shows that with a 20 minute sleep cycle (I set my ENV sleep_interval variable to 1200), my device’s  daily consumption is 0.0204wh * 24 or  about 0.48Wh per day.

    0.00112A during sleep 
    1.97A during transmitting
    0.06 during sensing

    Based on this information we can select a solar system to power the device.

    We look for a solar panel that can, on average, produce at least 1.5 times the device’s daily power consumption. A larger panel will help maintain uptime.

    Power ratio=Power Available /Power Consumed

    Power Available = Panel Power * Equivalent Sunlight Hours 

    Power Consumed = System Power * 24 hours

    To find average sunlight hours per day for the month of December (the month with the least sun in the Northern Hemisphere):

     

    1. Open JRC Photovoltaic Geographical Information System (PVGIS) tool.
    2. Find your location:Location
    3. Set the following fields to the following values.
      Field name Field value
      Installed peak PV power [Wp] * 1.0
      Battery capacity [Wh]* 0.01
      Discharge cutoff limit [%] * 0.01
      Consumption per day [Wh] * 0.01
      Slope [°] * 55
      Azimuth [°] * 0

      The numbers we enter sets a panel to 1W and battery storage to 0. This allows us to capture the Watt hours per day:Entered fields for calculation

    4. Click on Visualize results:Results
    5. Click on December. The Energy not captured is the value we’re looking for. In my case it is 2.28Wh. Since the panel was set to 1W, watts are canceled out and we are left with hours

    For my location, my result is 2.28 hours of equivalent full per day on average.  If we use a single 0.3 watt panel, we fall below the 1.5 threshold.

    0.3W x 2.28h (sun in NY in December)/0.48=1.42

    If we use two panels in parallel, we fall above the 1.5 threshold:

    2*0.3W x 2.28h (sun in NY in December)/0.48= 2.85 

    We’re going to connect our circuit to the C117 Lithium Ion Capacitor with two panels in parallel (0.6 Watt 3.3 Volt Solar Power System), connecting the black lead to GND and the red to the V+ pin. The LIC (Lithium Ion Capacitor) is admittedly too small here, most IoT devices should be designed with a minimum of 5 days of storage capacity with no solar and this example is closer to 1 day.
    In case

    10. Routing Data to the Cloud: General HTTP/HTTPS

    A feature of Notehub is that it allows you to forward your data from Notehub. (Notehub operates under a “pay-as-you-go” model with Consumption Credits. A Consumption Credit is only used upon event egress (e.g. when events are routed out of Notehub)).

    A Route is an external API, or server location, where Notes can be forwarded upon receipt.

    Routes are defined in Notehub for a Project and can target Notes from one or more Fleets or Devices. A Project can have multiple routes defined and active at any one time.

    1. Make sure the data you want to route is available in Notehub by navigating to the Events view:Events View
    2. Navigate to webhook.site. When the page loads, you’ll be presented with a unique URL that you can use as a Route destination. Copy that URL:Routes
    3. Navigate to the Notehub.io project.
    4. Click on Routes.
    5. Click on Create Route:Create Route
    6. Select the General HTTP/HTTPS Request/Response route type:Select Route
    7. Give the route a name (for example, “Weather”).Name Route
    8. For the Route URL, use the unique URL you obtained from webhook.site webhook.site
    9. Under Filters, choose Select Notefiles and enter the name of the Notefile to monitor. For example, we used sensors.qo in our program:sensors.qo
    10. Make sure the Enabled switch remains selected, and click Create Route:Create Routes
    11. Return to webhook.site. This page will update automatically with data from your Notecard as it is received in Notehub. The data from your sensor is contained within the body attribute. Notice that Notehub provides you with a lot of information, by default. webhook.site data

    9. Use JSONata to Transform JSON data

    To help simplify what you see, you can use JSONata.

    1. Navigate to the Routes page in Notehub and click View next to the Route you wish to edit.Edit Weather Route
    2. In the Transform Data drop-down, select JSONata Expression:JSONata
    3. In the JSONata expression text area, add the following query to select the values you want to track. JSONata allows you to manipulate your data, like formatting your numbers or creating a location field by concatenating the tower_location and tower_country fields:
      {
      "Heat_index_C": $number($formatNumber(body.heat_index_C, "#0.00;(#0.00)")),
         	"Humidity": $number($formatNumber(body.humidity, "#0.00;(#0.00)")),
          	"Temperature (F)": (body.temperature *9)/5+32,
          	"Time": body.time,
          	"Voltage": body.voltage,
          	"Location": tower_location &amp; ', ' &amp; tower_country
      }
    4. Click Apply Changes and Confirm. Then, navigate back to your webhook.site url. As requests come in, you’ll see your custom, JSONata-transformed payload in the Raw Content section:Raw Content
    5. To explore JSONata further, visit the Blues JSON Fundamentals guide

     

    10. Qubitro

      1. Create an account or log into Qubitro.
      2. Create a new project. Enter a name and a description:New Qubitro Project
      3. Click on the project then click on Browse Data Sources:Browse Data Sources
      4. Click on Notehub:Data Sources
      5. Back in Notehub, edit the Route.
      6. Copy the URL from Qubitro and paste into the URL field of Notehub.
      7. In Notehub click on Additional Headers. Set the following key-value pairs:
        note-device: weather

        projectId: [projectId from Qubitro]
        webhookSigningKey: [webhookSigningKey from Qubitro]

      8. Apply Changes
      9. In Qubitro open Functions Tab and select Create…:
        Functions Tab
      10. Select Blank template, then select Transformation function:
        Transformation Function
      11. Create your JSONata expressions:JSONata in Qubitro
        Some JSONata possibilities:
{
 "Heat_index_C": Heat_index_C,
 "Humidity": Humidity,
 "Location": Location,
 "Temperature_F":$number($formatNumber(Temperature_F, "#0.00;(#0.00)")),
 "Date": $fromMillis(Time*1000, '[M01]/[D01]/[Y0001]'),
 "Time": $fromMillis(Time*1000, '[h#1]:[m01][P]'),
 "Date/Time": $fromMillis(Time*1000, '[M01]/[D01]/[Y0001] [h#1]:[m01][P]'),
 "Voltage": $number($formatNumber(Voltage, "#0.00;(#0.00)")),
 "EST":$fromMillis(Time*1000, '[H01]:[m01]', '-0400'),
 "Raw Time":Time

}
  • Click on Save and complete.
  • Name your function.
  • Create your dashboard

Qubitro Dashboard

Running the device for several weeks showed that the C117 Lithium Ion Capacitor was providing insufficient capacity. I could see this in notehub.io dashboard.

I could also see in the dashboard that the system was dying at night without the sun and recovering when exposed to the sunlight the next  day.

With this information, I can change my sleep environmental variable on the dashboard from 1200 to 3600 seconds without having to gather my device and connect it to my computer.

Notehub.io Dashboard

Notehub.io Dashboard

Now that you know how to interact with the Blues ecosystem, you can start to build more advanced applications that can be powered by solar. What will you build?

Sign Up for a Consultation

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.