Environment Variable Not Updating on Notecard

Hi Blues team,

I’m having trouble getting an environment variable to update on my Notecard. II’ve tried the following:

  • Ensured the variable is set correctly in my Notehub project (under “Device environment variables”).
  • Included sync: true in my hub.set request.
  • Restarted the Notecard using card.restart.

However, when I send an env.get request for the variable, I consistently get an empty {} response, indicating that the variable is not being found (?)

Here’s the relevant part of my code:

#include <Wire.h>
#include <Notecard.h>
#include <NotecardPseudoSensor.h>

int getSensorInterval();

// Define the serial port for debugging output
#define USB_SERIAL Serial

// Replace with your Notehub project's ProductUID
#define NOTE_PRODUCT_UID "com.gmail.e.danesh:methaneguard_002"

using namespace blues;

// Create a Notecard object
Notecard notecard;
NotecardPseudoSensor sensor(notecard);

// This function assumes you’ll set the reading_interval environment variable to
// a positive integer. If the variable is not set, set to 0, or set to an invalid
// type, this function returns a default value of 60.
int getSensorInterval() {
  int sensorIntervalSeconds = 30; // Default value

  J *req = notecard.newRequest("env.get");
  if (req != NULL) {
    JAddStringToObject(req, "name", "reading_interval");
    J *rsp = notecard.requestAndResponse(req);

    // Check for errors and the correct type
    if (rsp != NULL) {
      if (JHasObjectItem(rsp, "err")) {
        USB_SERIAL.print("[ERROR] env.get: ");
        USB_SERIAL.println(JGetString(rsp, "err"));
      } else if (JIsNumber(JGetObjectItem(rsp, "text"))) {  
        // Successfully retrieved the variable as a number
        sensorIntervalSeconds = JGetNumber(rsp, "text");
      } else if (JIsString(JGetObjectItem(rsp, "text"))) { 
        // Handle the case where the variable is a string
        USB_SERIAL.println("[WARNING] env.get: 'reading_interval' is a string, not a number.");
      } else {
        USB_SERIAL.println("[WARNING] env.get: 'text' is not a number or string.");
      }

      // Print the response for debugging
      USB_SERIAL.print("env.get response: ");
      USB_SERIAL.println(JConvertToJSONString(rsp));

      notecard.deleteResponse(rsp);
    } else {
      USB_SERIAL.println("[ERROR] env.get: No response received.");
    }
  } else {
    USB_SERIAL.println("[ERROR] env.get: Could not create request.");
  }

  USB_SERIAL.print("sensorIntervalSeconds: ");
  USB_SERIAL.println(sensorIntervalSeconds);

  return sensorIntervalSeconds;
}

void setup() {

  // Begin serial communication for debugging
  USB_SERIAL.begin(115200);
  while (!USB_SERIAL); // Wait for serial port to connect
  USB_SERIAL.println("Starting...");

  // Begin I2C communication with the Notecard
  Wire.begin();
  notecard.begin();
  // notecard.begin(NOTE_I2C_ADDR_DEFAULT, 0, Wire);

  // Link the debug output to the USB serial port
  notecard.setDebugOutputStream(USB_SERIAL);

  // --- Configure Notehub with Error Handling ---
  USB_SERIAL.println("Configuring Notehub...");
  J *req = notecard.newRequest("hub.set");
  if (req != NULL) {
    JAddStringToObject(req, "product", NOTE_PRODUCT_UID);
    JAddStringToObject(req, "mode", "continuous");
    JAddBoolToObject(req, "sync", true); // for immediate inbound sync from notehub
    // JAddNumberToObject(req, "inbound", 1); // Enable inbound sync
    // JAddNumberToObject(req, "outbound", 1); // Enable outbound sync
    notecard.sendRequest(req);
  }

  // Create new template
  req = notecard.newRequest("note.template");
  if (req != NULL) {
    JAddStringToObject(req, "file", "sensors.qo");
    JAddNumberToObject(req, "port", 1); // Added port number
    // JAddBoolToObject(req, "sync", true);
    J *body = JCreateObject();
    if (body != NULL) {
    JAddNumberToObject(body, "temp", 14.1);
    JAddNumberToObject(body, "humidity", 14.1);
    JAddItemToObject(req, "body", body);
    notecard.sendRequest(req);
    }
  }

  // delay(1000);
  // USB_SERIAL.println("Veryfing template...");
  // verifyTemplate();

}

void loop() {

  float temperature = sensor.temp();
  float humidity = sensor.humidity();

  USB_SERIAL.print("Temperature = ");
  USB_SERIAL.print(temperature);
  USB_SERIAL.println(" *C");
  USB_SERIAL.print("Humidity = ");
  USB_SERIAL.print(humidity);
  USB_SERIAL.println(" %");

  J *req = notecard.newRequest("note.add");
  if (req != NULL) {
    JAddStringToObject(req, "file", "sensors.qo");
    // JAddNumberToObject(req, "port", 1);
    JAddBoolToObject(req, "sync", true);
    J *body = JAddObjectToObject(req, "body");
    if (body) {
      JAddNumberToObject(body, "temp", temperature);
      JAddNumberToObject(body, "humidity", humidity);
    }
    notecard.sendRequest(req);
  }
  
  // delay(60000); // Wait for 60 seconds
  int sensorIntervalSeconds = getSensorInterval();
  USB_SERIAL.print("Delaying ");
  USB_SERIAL.print(sensorIntervalSeconds);
  USB_SERIAL.println(" seconds");
  delay(sensorIntervalSeconds * 1000);

}

I even tried forced hub.sync and card.restart with up to 10 sec delays with no success. I also include a screenshot of my device Environment:

Please advise if you know where the issue is.

Thanks.

Of course, I first tried the original code in Collecting Sensor Data guide page:

int getSensorInterval() {
  int sensorIntervalSeconds = 60;
  J *req = notecard.newRequest("env.get");
  if (req != NULL) {
    JAddStringToObject(req, "name", "reading_interval");
    J* rsp = notecard.requestAndResponse(req);
    int readingIntervalEnvVar = atoi(JGetString(rsp, "text"));
    if (readingIntervalEnvVar > 0) {
      sensorIntervalSeconds = readingIntervalEnvVar;
    }
    notecard.deleteResponse(rsp);
  }
  return sensorIntervalSeconds;
}

but the result is the same - empty env.get response {}. Serial output attached:

Hey @e669danesh,

And welcome to the Blues community! Everything you have in here seems reasonable, so this is odd.

A couple of thoughts:

  • Ensure the ProductUID in your firmware matches the ProductUID of your Notehub project.

  • If you’re using a Notecard for LoRa you need to use the env.template request to create a template for the environment variable (see env Requests - API Reference - Blues Developers).

Let me know if either of those help. If not I’ll give this another look and see if I notice anything else.

Thanks,
TJ VanToll

Thank you, @tjvantoll .

  • The ProductUID was correct
  • In fact I am using LoRa and I didn’t know about the requirement for env.template. Thanks for the tip (I suggets you add this to the guide " Collecting Sensor Data.

However, even after adding this line of code to my void setup():

  // --- Define the environment variable template ---
  Serial.println("Defining environment variable template...");
  req = notecard.newRequest("env.template");
  if (req != NULL) {
    J *body = JCreateObject(); // Create the body object
    if (body != NULL) {
      JAddNumberToObject(body, "reading_interval", 21); // Define the variable within the body - 21 - for a 1 byte unsigned integer (e.g. 0 to 255)
      JAddItemToObject(req, "body", body);              // Add the body to the request
      notecard.sendRequest(req);
    }
  }

I still cannot update the “reading_interval” from default 60 to the value set in notehub device>Environment.

am I missing something?

Hey @e669danesh,

The code you have is correct, and I just tried it out in a new project and it worked fine for me. The trick is that the hub.set request’s sync flag doesn’t work with Notecard for LoRa, so your device will only pick up on the updated environment variable after your inbound interval, or after an explicit hub.sync request.

Appreciate you reaching out with this. Our sensor tutorial was written with Notecard Cellular and Wi-Fi-based Notecards in mind, and it’s clear we need to do more work to make sure it’s possible to complete with a Notecard for LoRa. I’m adding this to my short list for this week.

Sorry you ran into these issues.

TJ

thank you. I confirm that including a forced sync:

J *req = notecard.newRequest("hub.sync");
  notecard.sendRequest(req);

inside loop() solves the issue.

Curiously, if I don’t include this, Notecard does not sync with the hub even when inbound is set to 1 (presumably, one minute). I checked the status of the card and it reads:

> {"req":"card.status"}}
{
 "time": 1735906990,
 "usb": true,
 "set": true,
 "inbound": 1,
 "outbound": 1
}

So it seems that inbound setting is correct (and at minimum length). But Environment variable only gets updated during the forced/explicit hub.sync.

I wanted to know your opinion on this, and also your advice on how to minimise the power consumption: which one use more power: hub.sync or inbound?

Hey @e669danesh,

Sorry for the late reply here. I was at an event last week and I’m catching back up.

It looks like you’ve found a bug here. You shouldn’t need to perform a hub.sync to get inbound environment variable updates, but I just confirmed that you do in the latest firmware. We’re looking into this and I’ll let you know what we find. Thanks for reporting this!

Thanks,
TJ