Community
OpenEnergyMonitor

Community

Arduino Yun with TX shield updates only once each time it boots

Tags: #<Tag:0x00007f8de8ee42b0>

I don’t know and I’m not familiar enough with CPP to know any more.

You could dig into the EmonESP code and see what is done there for the URL. However, I think that may use a GET method rather than curl.

From my point of view, I’m content the EmonCMS side is fine as long as it is sent the right string.

rotfllmao

Thanks for digging deeper.

Ok thanks. There’s also a possibility that the problem is when the output is passed to the Linux side of the Yun, so it may not be the same as an Arduino that doesn’t do that.

Anyway, at least we could confirm Emoncms was acting as expected. I switched “fulljson” in the string back to “data” and it works perfectly.

Looking at the serial print

20:50:04.036 -> curl --data "node=Seeed&fulljson={"Temperature":-196.60,"ct1.apparentPower":2.20,"ct2.apparentPower":2.46,"ct3.apparentPower":3.00,"ct4.apparentPower":3.07}&apikey=nnnnnnnnnnnnnnnnnnnnnnnnnnn" "http://192.168.1.116/input/post"

It would appear you have a nested quotes issue. The leading and trailing double quotes in the --data string change the way the other double quotes are interpreted eg the double quote immediately before “Temperture” is seen as a closing double quote to “node=Seeed&fulljson={” rather than an opening double quote to “Temperature”, and so on through the string.

Offhand I can think of 2 potential fixes you could try, I don’t know for sure either will work but hopefully it will point you in the right direction.

  1. Use single quotes to wrap the --data string rather than escaping the doubles (if curl permits use of single quotes) ie

      String url = "curl --data 'node=Seeed&fulljson=";
      url += dataString;
      url += "}&";
      url += apiString;
      url += "' \"http://192.168.1.116/input/post\"";
    

    so that the printed string becomes

    20:50:04.036 -> curl --data 'node=Seeed&fulljson={"Temperature":-196.60,"ct1.apparentPower":2.20,"ct2.apparentPower":2.46,"ct3.apparentPower":3.00,"ct4.apparentPower":3.07}&apikey=nnnnnnnnnnnnnnnnnnnnnnnnnnn' "http://192.168.1.116/input/post"
    

    (notice the shift in the forums colour coding in the displayed code block?) and if that works ok I would also change the escaped double quotes that wrap the url to single quotes too perhaps for neatness?

  2. Double escape the double quotes within the string, I assume a double backslash (aka an escaped backslash “\\” ) might be needed before the escaped double quotes, eg

      dataString = "{\\\"Temperature\\\":";
    

    etc for each key, so the output becomes

    20:50:04.036 -> curl --data "node=Seeed&fulljson={\"Temperature\":-196.60,\"ct1.apparentPower\":2.20,\"ct2.apparentPower\":2.46,\"ct3.apparentPower\":3.00,\"ct4.apparentPower\":3.07}&apikey=nnnnnnnnnnnnnnnnnnnnnnnnnnn" "http://192.168.1.116/input/post"
    

    (again note the colour coding change) so that curl knows what’s what. You may need to amend the escaping depending on OS and/or curl, I just took a guess.

Personally I prefer the first method but I do not know if the single quotes are permitted. I hope this helps.

1 Like

Thanks Paul, #1, single quotes around the data does preserve the double quotes around the variable names and works!

I also got the watchdog timer working, and experimented to find out where resets were needed. That’s not relevant to this thread, but is an update in the code below compared to the code above. Once again, here’s the working code for reference:
To get an Arduino Yun with the EmonTX shield to POST(not GET) to emoncms in fulljson:

// based on http://forum.arduino.cc/index.php?topic=201925.0
#include <EmonLib.h> //for energy monitoring
#include <Process.h> //for Yun
#include <Bridge.h> //for Yun linux to Arduino connection
#include <OneWire.h> //for thermometer
#include <DallasTemperature.h> //for thermometer
#include <FileIO.h> //for writing to SD card
#include <avr/wdt.h> //watchdog timer

#define DEBUG 1
#ifdef DEBUG
  #define DEBUG_PRINTLN(x)  Serial.println(x)
#else
  #define DEBUG_PRINTLN(x)
#endif

// Create  instances for each CT channel
EnergyMonitor ct1; //ct1 is 71 HPWH on Yun, dryer on Seeed (15A, 120V)("30A, 220V when used with NEMA adapter" why 4x the power with the adapter!?)
EnergyMonitor ct2; //ct2 is 73 HPWH on Yun, washer on Seeed (12A draw, 20A breaker recommended, 240V)
EnergyMonitor ct3; //ct3 is 71 ASHP on Yun, laundry room heat on Seeed (specs?)
EnergyMonitor ct4; //ct4 is 73 ASHP on Yun, not used on Seeed

// On-board emonTx LED
const int LEDpin = 9;

//Setup thermometer
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

const unsigned long postingInterval = 60000; //one minute
unsigned long lastRequest = 0;
String Timestamp = "";
String dataString =  "";
String APIKEY = "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn";

void setup() {

  DEBUG_PRINTLN("Finished initialization, entering setup");

  // Initialize Bridge
  Bridge.begin();

  // Start serial port
  Serial.begin(9600);

  // Start file system for SD card logging
  FileSystem.begin();

  // Start up the thermometer library
  sensors.begin();

  // 1st arg: pin number
  // 2nd arg: Calibration factor = CT ratio / burden resistance = (100A / 0.05A) / 33 Ohms = 60.606
  ct1.current(1, 20);
  ct2.current(2, 20);
  ct3.current(3, 25);
  ct4.current(4, 25);

  // (ADC input, calibration, phase_shift)
  ct1.voltage(0, 130, 1.7);
  ct2.voltage(0, 130, 1.7);
  ct3.voltage(0, 130, 1.7);
  ct4.voltage(0, 130, 1.7);

  // Setup indicator LED
  pinMode(LEDpin, OUTPUT);

  DEBUG_PRINTLN("Finished setup, entering delay to wait for wifi");

  // Hoping a delay allows the wifi connection to establish for more reliable operation
  delay(15000);

  wdt_enable(WDTO_8S);
}

void loop() {

  DEBUG_PRINTLN("Entering loop");

  long now = millis();

  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  sensors.requestTemperatures(); // Send the command to get temperatures

  // Calculate all. No.of crossings, //time-out
wdt_reset();
  ct1.calcVI(20, 2000);
  ct2.calcVI(20, 2000);
wdt_reset();            // these calculations must be slow because the WDT(8s) will act if this reset is not here
  ct3.calcVI(20, 2000);
  ct4.calcVI(20, 2000);
wdt_reset();            // if one or both the resets before/after aren't present, it will post, reset, post, reset around every 85-90s instead of 60s
  
  if (now - lastRequest >= postingInterval) {
    updateData();
    sendData();
    writeToCard(); // only for the Yun, the Seeeduino doesn't have an sdcard
    lastRequest = now;
  }
}

void updateData() {
  // convert the readings to a String to send it:
  digitalWrite(LEDpin, HIGH);
//Timestamp moved to the write to card portion only because that has no other timestamp and the Emon server doesn't like the timestamp format
  dataString = "{\"Temperature\":"; //need to add a comma in front, and switch to += if I turn the timestamp back on
  dataString += sensors.getTempFByIndex(0);
  dataString += ",\"ct1.apparentPower\":";
  dataString += 2*ct1.apparentPower;//these have 2x because the CTs are around 240v circuits while the voltage sensor is plugged into 120v
  dataString += ",\"ct2.apparentPower\":";
  dataString += 2*ct2.apparentPower;
  dataString += ",\"ct3.apparentPower\":";
  dataString += 2*ct3.apparentPower;
  dataString += ",\"ct4.apparentPower\":";
  dataString += 2*ct4.apparentPower;
  digitalWrite(LEDpin, LOW); 
  DEBUG_PRINTLN("updateData: ");
  DEBUG_PRINTLN(dataString);
  DEBUG_PRINTLN("Finished updateData");
}

// this method makes a HTTP connection to the server:
void sendData() {
  String apiString = "apikey=";
  apiString += APIKEY;

  // form the string for the URL parameter:
  // specify the server address
  String url = "curl --data 'node=Seeed&fulljson=";
  url += dataString;
  url += "}&";
  url += apiString;
  url += "' \"http://192.168.1.116/input/post\"";

  Process p;  // Yun's special libraries that pass code between the Arduino and Linux sides
  DEBUG_PRINTLN("\n\nSending data... ");
  p.runShellCommand(url); // run some code on the Linux side
  DEBUG_PRINTLN("Wrote to EmonCMS ");
  DEBUG_PRINTLN(url);

  while (p.running()); //wait for the process to finish
  // If there's incoming data from the net connection,
  // send it out the Serial:
  while (p.available()>0) {
    char c = p.read();
    Serial.print(c);  //print the entire server response as one line
  }
}

void writeToCard() {
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  // The FileSystem card is mounted at the following "/mnt/FileSystema1"
  File dataFile = FileSystem.open("/mnt/sd/arduino/emon/datalog.csv", FILE_APPEND);

  Timestamp = getTimeStamp(); 
  dataString += ",Timestamp:";  dataString += "}";
  dataString += Timestamp;

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  
  // if the file isn't open, pop up an error:
  else {
    DEBUG_PRINTLN("error opening datalog.csv");
  }
  DEBUG_PRINTLN("Finished writeToCard");
}

// This function return a string with the time stamp
// from the bottom of this Yun specific tutorial https://www.arduino.cc/en/Tutorial/YunDatalogger
String getTimeStamp() {
  String result;
  Process time;
  // date is a command line utility to get the date and the time
  // in different formats depending on the additional parameter
  time.begin("date");
  time.addParameter("+%D-%T");  
  // parameters: D for the complete date mm/dd/yy
  // T for the time hh:mm:ss
  time.run();  // run the command

  // read the output of the command
  while (time.available() > 0) {
    char c = time.read();
    if (c != '\n')
      result += c;
  }
  return result;
  DEBUG_PRINTLN("Got TimeStamp");
}

When setting up my second Yun+TX shield, it had the same one post per boot problem! And so did my first one, after I had finalized the sketch: setting the node, adding notes, etc. As I played around them and tshark, it seemed that almost no matter what combination of single or double quotes, json, fulljson, or data tag I used, one post worked and none after that. Tshark showed that they weren’t making it to the server, so it wasn’t the server rejecting them. The serial monitor showed identical strings being created, so why weren’t the second and later strings getting to the server?

I started to suspect the “while” statements after the curl shell command, and I realized that the working sketches in this thread don’t use the console; while the first one I posted and the ones I was using for installation did - the original sketch I copied has it, and I added it back for installation so I could get serial monitor type output over ssh. But that must either hang or interact with the while, like if the console has started, the while waits for input?

Anyway, removing the console statements is what solves the one post per boot problem. In testing, commenting console.begin() in and out, the Bridge/communication with the Linux side seems to hang whether or not console.write() is used.

1 Like