Sending multiple numbers to Arduino via Serial

Hello,

For the project i am doing, i am trying to grab weather data from multiple cities that i will then use to drive some NeoPixles on an Arduino with. The Processing sketch i have at the moment uses 3 cities, and takes 3 weather variables (temp, humidity, and wind speed). I want to then take each of these variables (temp, humid, speed) and send them to the Arduino so as to use them for RGB values for the Neopixels. For example, temp1, humidity1, and speed1 from the first city would make up the RGB values for the first Noepixel and temp2, humidity2, and speed2 would make up the RGB for Neopixel #2, etc. etc.

For now, i am trying to just send the temp1, humidity1, and speed1 over to my Arduino, have the Arduino read it, and then “tell” Processing what it just recieved.

At the moment, i am having trouble with sending the data from Processing to Arduino in a way that 1) makes sense, and 2) doesnt create “garbage” numbers. (Later, i am going to try to figure out a way to sort of "store the three number so as to assign them as the rgb values, but for now, one step at a time)

When i see it in the Processing monitor, the data being sent back from the Arduino makes sense, for a few seconds, but then starts sending nonsense numbers back.

Processing:

import processing.serial.*;
Serial myPort;  // Create object from Serial class


JSONObject json, main1, main2, main3, wind1, wind2, wind3 ;
String APIKEY = "";

int temp1, temp2, temp3, humidity1, humidity2, humidity3, speed1, speed2, speed3;
int angle = 0;
int increment1 = 0;
void setup() {

  String portName = Serial.list()[2]; //change the 0 to a 1 or 2 etc. to match your port
  myPort = new Serial(this, portName, 9600);

  size(640, 500);
  background(102);
  noStroke();
  fill(0, 102);
}

int time_to_fetch;
int time_between_fetches = 10000; // Ten seconds.

void draw() {
  if ( millis() > time_to_fetch ) {
    loadData();
  }
  myPort.clear(); 
  myPort.write(temp1 + ";" + humidity1 + ";" + speed1 + ";" + increment1 + ";");
  //myPort.write('\r'); //send an ASCII character 10 (value)
  //myPort.write(Integer.toString(humidity1));
  //myPort.write(Integer.toString(speed1));
  myPort.write('e');
  //delay (1000);
}


void loadData() {
  time_to_fetch = millis() + time_between_fetches;
  json = loadJSONObject("http://api.openweathermap.org/data/2.5/group?id=5964347,1266510,2347078&units=imperial&APPID="+APIKEY);

  increment1++;

  JSONArray weatherArr = json.getJSONArray("list");
  //println(weatherArr);

  ///////////////////////////////////////////////////////////////////////

  JSONObject weatherObj1 = weatherArr.getJSONObject(0);
  //println("Weather Object:\n" + weatherObj, ENTER);

  main1 = weatherObj1.getJSONObject("main");
  wind1 = weatherObj1.getJSONObject("wind");
  speed1 = wind1.getInt("speed");
  humidity1 = main1.getInt("humidity");
  temp1 = main1.getInt("temp");

  ///////////////////////////////////////////////////////////////////////
  JSONObject weatherObj2 = weatherArr.getJSONObject(1);
  //println("Weather Object:\n" + weatherObj, ENTER);

  main2 = weatherObj2.getJSONObject("main");
  wind2 = weatherObj2.getJSONObject("wind");
  speed2 = wind2.getInt("speed");
  humidity2 = main2.getInt("humidity");
  temp2 = main2.getInt("temp");

  ///////////////////////////////////////////////////////////////////////

  JSONObject weatherObj3 = weatherArr.getJSONObject(2);
  //println("Weather Object:\n" + weatherObj, ENTER);

  main3 = weatherObj3.getJSONObject("main");
  wind3 = weatherObj3.getJSONObject("wind");
  speed3 = wind3.getInt("speed");
  humidity3 = main3.getInt("humidity");
  temp3 = main3.getInt("temp");

  ///////////////////////////////////////////////////////////////////////

  //println(temp1);
  //println(humidity1);
  //println(speed1);
  //println(temp2);
  //println(humidity2);
  //println(speed2);
  //println(temp3);
  //println(humidity3);
  //println(speed3);
  //println(increment1);
  drawData();

  //exit();
}
void drawData() {
  background(102);
  textSize(18);
  text("Temp1: " + nfc(temp1) + 
    "\nHumidity1: " + nfc(humidity1) +
    "\nSpeed1: " + speed1 +
    "\n "  +
    "\nTemp2: " + temp2 +
    "\nHumidity2: " + humidity2 +
    "\nSpeed2: " + speed2 +
    "\n "  +
    "\nTemp3: " + temp3 +
    "\nHumidity3: " + humidity3 +
    "\nSpeed3: " + speed3 + 
  "\n "  +
  "\nIncrement: " + increment1, 10, 50);
}

void serialEvent(Serial p) {
  try {
    // get message till line break (ASCII > 13)
    String message = p.readStringUntil(13);
    // just if there is data
    if (message != null) {
      println("message received: "+trim(message));
    }
  }
  catch (Exception e) {
  }
}

Arduino:

const long BAUD_RATE = 9600;
int x, y, z, a;
void setup() {
  Serial.begin(BAUD_RATE);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  x = 0;
  y = 0;
  z = 0;
  a = 0;
}

void loop() {
  receiveData();

  if ( a <= 4 ) {
    digitalWrite(13, HIGH);
  } else {
    digitalWrite(13, LOW);
  }


  Serial.println(x);
  //  delay(5000);
  Serial.println(y);
  //  delay(5000);
  Serial.println(z);
  //  delay(5000);
  Serial.println(a);
  delay(500);
}

void receiveData() {


  if (Serial.available() >= 3) {
    for (int i = 0; i < 3; i++) {

      x = Serial.parseInt();
      y = Serial.parseInt();
      z = Serial.parseInt();
      a = Serial.parseInt();

      Serial.read();
    }
  }
}
1 Like

looks like you have a timer to get new data ( 10 sec )
but that data you then send every draw loop ( possibly 60 times per sec ) to arduino
( move the } down )

for the sending on both sides i recommend a CSV type of Lines
1023,1023,1023,1023CR ( arduino might send CR LF ( catched by your trim() )
so pls use ‘,’ and writeline and no delay() at all, ( instead ‘;’ and ‘e’ )
as the original sender is processing there is the timer (10 sec ),
arduino send back a CSV line with the already understood values…

on the processing side use
https://processing.org/reference/libraries/serial/serialEvent_.html
and split on ‘,’

on arduino side that command serialEvent is board depending.
use
https://www.arduino.cc/reference/en/language/functions/communication/serial/readstringuntil/
to catch the line and then split it or try use your parseInt()

Thank you, kll

So, i have implemented at least some of your advice. Unfortunately, Im still very new with Processing, so im not sure i truly understand all of what youre trying to impart on me.

One thing that im confused by is moving the curly brackets…you mentioned moving them down…and i have…but when i do, the info that i should be reading in the Processing monitor from the arduino just results in “0”, instead of the numbers i would expect to get back.

That all said, I’ve adjusted both sets of code, and well…it works…at least i think it does. That is, the numbers im getting in the Processing monitor are correct, and they are stable and are doing exactly what i want them to do. Im not so sure its elegant, (in fact, my code seems rather “brutish” and clumsy, if you will), but it works. (Again, im a noob, so some of the stuff you mentioned are confusing to me)

import processing.serial.*;
Serial myPort;  // Create object from Serial class
JSONObject json, main1, main2, main3, wind1, wind2, wind3 ;

String APIKEY = "";

int temp1, temp2, temp3, humidity1, humidity2, humidity3, speed1, speed2, speed3;
int increment1 = 0;
int time_to_fetch;
int time_between_fetches = 10000; // Ten seconds.

void setup() {
  String portName = Serial.list()[2]; //change the 0 to a 1 or 2 etc. to match your port
  myPort = new Serial(this, portName, 9600);
  delay(5000);
  size(640, 500);
  background(102);
  noStroke();
  fill(0, 102);
}

void draw() {
  if ( millis() > time_to_fetch ) {
    loadData();
  }

  myPort.write(temp1 + ";" + humidity1 + ";" + speed1 +  ";" + temp2 + ";" + humidity2 + ";" + speed2 + ";" + ";" + increment1 + 'e' + ";");
  //myPort.write(temp2 + ";" + humidity2 + ";" + speed2 + ";" + 'e' + ";");
  //myPort.write(increment1 + ";");
  //myPort.write(humidity1 + ":");
  //myPort.write(speed1 + ":");
  //myPort.write('\r'); //send an ASCII character 10 (value)
  //myPort.write(Integer.toString(humidity1));
  //myPort.write(Integer.toString(speed1));
  //myPort.write('e');

  myPort.clear();
}


void loadData() {

  increment1++;
  
  time_to_fetch = millis() + time_between_fetches;
  json = loadJSONObject("http://api.openweathermap.org/data/2.5/group?id=5964347,1266510,2347078&units=imperial&APPID="+APIKEY);

  JSONArray weatherArr = json.getJSONArray("list");
  //println(weatherArr);

  ///////////////////////////////////////////////////////////////////////

  JSONObject weatherObj1 = weatherArr.getJSONObject(0);
  //println("Weather Object:\n" + weatherObj, ENTER);

  main1 = weatherObj1.getJSONObject("main");
  wind1 = weatherObj1.getJSONObject("wind");
  speed1 = wind1.getInt("speed");
  humidity1 = main1.getInt("humidity");
  temp1 = main1.getInt("temp");

  ///////////////////////////////////////////////////////////////////////
  JSONObject weatherObj2 = weatherArr.getJSONObject(1);
  //println("Weather Object:\n" + weatherObj, ENTER);

  main2 = weatherObj2.getJSONObject("main");
  wind2 = weatherObj2.getJSONObject("wind");
  speed2 = wind2.getInt("speed");
  humidity2 = main2.getInt("humidity");
  temp2 = main2.getInt("temp");

  ///////////////////////////////////////////////////////////////////////

  JSONObject weatherObj3 = weatherArr.getJSONObject(2);
  //println("Weather Object:\n" + weatherObj, ENTER);

  main3 = weatherObj3.getJSONObject("main");
  wind3 = weatherObj3.getJSONObject("wind");
  speed3 = wind3.getInt("speed");
  humidity3 = main3.getInt("humidity");
  temp3 = main3.getInt("temp");

  ///////////////////////////////////////////////////////////////////////

  //println(temp1);
  //println(humidity1);
  //println(speed1);
  //println(temp2);
  //println(humidity2);
  //println(speed2);
  //println(temp3);
  //println(humidity3);
  //println(speed3);
  //println(increment1);
  drawData();

  //exit();
}

void drawData() {
  background(102);
  textSize(18);
  text("Temp1: " + nfc(temp1) + 
    "\nHumidity1: " + nfc(humidity1) +
    "\nSpeed1: " + speed1 +
    "\n "  +
    "\nTemp2: " + temp2 +
    "\nHumidity2: " + humidity2 +
    "\nSpeed2: " + speed2 +
    "\n "  +
    "\nTemp3: " + temp3 +
    "\nHumidity3: " + humidity3 +
    "\nSpeed3: " + speed3 + 
    "\n "  +
    "\nIncrement: " + increment1, 10, 50);
}

void serialEvent(Serial p) {
  try {
    // get message till line break (ASCII > 13)
    String message = p.readStringUntil(13);
    // just if there is data
    if (message != null) {
      println("message received: "+trim(message));
    }
  }
  catch (Exception e) {
  }
}

const long BAUD_RATE = 9600;
int x1, y1, z1, x2, y2, z2, x3, y3, z3;
int a;
char c;
long v = 0;
//buffer [];
void setup() {
  Serial.begin(BAUD_RATE);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  x1 = 0;
  y1 = 0;
  z1 = 0;

  x2 = 0;
  y2 = 0;
  z2 = 0;

  x3 = 0;
  y3 = 0;
  z3 = 0;

  a = 0;
}

void loop() {
  receiveData();

  if ( a <= 4 || a >= 7) {
    digitalWrite(13, HIGH);
  } else {
    digitalWrite(13, LOW);
  }


  Serial.println(x1);
  //  delay(5000);
  Serial.println(y1);
  //  delay(5000);
  Serial.println(z1);
  //  delay(5000);
  Serial.println(x2);
  Serial.println(y2);
  Serial.println(z2);
  Serial.println(a);
  delay(500);
}

void receiveData() {


  if (Serial.available() >= 4) {
    for (int i = 0; i < 4; i++) {
      Serial.readStringUntil('e');
      x1 = Serial.parseInt();
      y1 = Serial.parseInt();
      z1 = Serial.parseInt();
      x2 = Serial.parseInt();
      y2 = Serial.parseInt();
      z2 = Serial.parseInt();
      a = Serial.parseInt();
    }
  }
}
//    if (c == 'e') {
//      Serial.println(v);
//      v = 0;
//    }
//  }
//}



sorry, my idea was ( UNTESTED )

final int LINE_FEED=10;


void draw() {
  if ( millis() > time_to_fetch ) {
    loadData();
    String send = temp1 + ',' + humidity1 + ',' + speed1 +  ',' + temp2 + ',' + humidity2 + ',' + speed2 + ','  + increment1 + ',' ;
    myPort.write(send + LINE_FEED);
    println(send);
  }
}

so you send one line every 10 sec
and not 60 lines per sec

for better understanding put in your code a

println(increment1);