Can one dashboard connect to many devices?

I will have 5 or more identical machines that will use the same dashboard layout. Is there a way I could have one dashboard where maybe a value widget could be changed to Machine 1, machine 2, etc and the dashboard would switch to another machine and display info from the new selected machine?
Or will I have to make an identical Thing and dashboard for each machine and link variables to individual identical things? I hope you get the concept of what I mean.

I want to use one dashboard to control multiple machines each of which are the same.

Hi!
Absolutely yes. The granularity in the widgets is per variable.
This means that, in the same dashboard, you can add widgets associated to variables from different things.

1 Like

Yes, I understand that on one dashboard I can display variables from many devices. I could have one large dashboard and have sections showing the values from multiple devices. Each section would have a similar set of widgets, just linked to different devices.

What I would like to do is have one dashboard that displays the values from device A, change one of the widget values, (for example a value widget called Device), change it to "B" using the dashboard, and then the same set of widgets would display the values from device B. Did I explain it better this time?

Ah, ok. I got it now.
Unfortunately not directly as every widget is linked to one specific variable and that can't be changed in real time.

Anyway, I think there is one workaround you could try with a little bit of coding leveraging device-to-device communication.
You can have one Thing responsible of publishing the data to the widgets.
This Thing will have a set of variables synced with the rest of the Things. For instance, imagine that you create this variables:

  • Thing # 1: temp, humidity
  • Thing # 2: temp, humidity
  • ...
  • Thing # N: temp, humidity
  • Thing Master
    • widget_temp, widget_humidity, widget_thing_selector
    • temp1 (synced with Thing #1/temp), humidity1 (linked to Thing #1/humidity)
    • temp2 (synced with Thing #2/temp), humidity2 (synced with Thing #2/humidity)
    • ...
    • tempN (synced with Thing #N/temp), humidityN (synced with Thing #N/humidity)

In the dashboard, you visualise widget_temp and widget_humidity using your preferred widgets (chart, value, ...).
And you add another widget linked to the variable widget_thing_selector.
In the code in Thing Master, you must set the value of widget_temp and widget_humidity to the value of the synced variable corresponding to tempX and humidtyX (where X is the number of the selected Thing with widget_thing_selector). That can be done in the callback functions of tempX and humidityX.

It's a little bit tricky and tedious but it will work.

I think I understand the concept. Are you thinking that Thing Master would be another physical device that would act as a broker and essentially listen to all of the other things variables and control the Single dashboard. The dashboard user would enter a value in the thing_selector widget, and the master would then populate the other dashboard widgets with the correct values.
Would the master thing have to have a set of thing variables from each of the other Things? So as you added a new Thing #N, you would have to change the code in the Thing Master?

Or are you thinking a separate physical Thing Master would not be needed?

Either way, the IoT cloud can't handle that many variables. I have a reproducible minimum code example currently in to tech support, that causes the program to freeze (main loop stops) when the 13th Thing variable is added. If I go back to 12, and it runs again. Tech support sent me a sketch that had 15 int Thing variables in it that ran fine, but mine had a mix of bool, String, int which won't work past 12 Thing variables. I haven't had any response from them in a few days so I may have been forgotten. I'm not even able to get one dashboard to work. I had big hopes for the IoT cloud at first.

Both can be correct. If you can use a spare additional device it is fine. If not, any of the existing devices can serve as that broker.

That's pretty weird. I do have projects with many variables working perfectly fine. Can you share the sketch that is not working so that I can try to reproduce the effect?

You wrote:

"That's pretty weird. I do have projects with many variables working perfectly fine. Can you share the sketch that is not working so that I can try to reproduce the effect?"

Yes, please try to help me make this work. Is there a way I can do the Thing variable updating myself in code rather than having it be done in the background? Maybe with the ArduinoIoTCloud library? I need to be able to send SMS messages from within my cloud application, so I need to pause the Thing variable updates, send the SMS, and resume.

Here are my Thing variables. If I add one more Thing variable, the cloud stuff locks up, my main Loop executes three times before the lockup. Then it is almost impossible to reprogram the MKR NB 1500 again because the watchdog goes off in the middle of the upload process. I have a total of 21 Thing variables I want to use.

Here is the code. I am running a new clean build of Win10 because i wanted to be sure it wasn't some windows thing. I had the exact same results using a different computer. Note, I had all of the Thing variables linked to widgets on dashboards too.

Depending on how interested you are in getting to the bottom of this problem, and want to work with me at the same time,let me know your time zone and what time you would be available, and I will be here to work live with you. This is very important to me as I have the potential to lose lots of money if I can't get this to work. Thanks in advance!

Oh, I commented out the callback code and had the same problem either way.

Tom

/*
Sketch generated by the Arduino IoT Cloud Thing "GreenWater2"
[https://create.arduino.cc/cloud/things/3b7bb899-d59e-4d1e-ae90-07da76eee3c0](https://create.arduino.cc/cloud/things/3b7bb899-d59e-4d1e-ae90-07da76eee3c0)

Arduino IoT Cloud Variables description

The following variables are automatically generated and updated when changes are made to the Thing

String status;
String testValue;
int area1;
int area2;
int area3;
int boardO3analog;
int number1;
int number2;
int number3;
int potentiometer;
int seconds;
bool led;

Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"

int i = 0;
unsigned long starttime = millis();

void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
Serial.println("Serial working");

// Defined in thingProperties.h
initProperties();

/*
Invoking `addCallback` on the ArduinoCloud object allows you to subscribe
to any of the available events and decide which functions to call when they are fired.

The functions `doThisOnConnect`, `doThisOnSync`, `doThisOnDisconnect`
are custom functions and can be named to your likings and for this example
they are defined/implemented at the bottom of the Sketch
*/
// I have tried with and without these callbacks and program fails the same way
ArduinoCloud.addCallback(ArduinoIoTCloudEvent::CONNECT, doThisOnConnect);
ArduinoCloud.addCallback(ArduinoIoTCloudEvent::SYNC, doThisOnSync);
ArduinoCloud.addCallback(ArduinoIoTCloudEvent::DISCONNECT, doThisOnDisconnect);

// Connect to Arduino IoT Cloud
// If watchdog is on and program fails to connect to the cloud it is almost
// impossible to upload a new sketch because the watchdog fires during the upload process
ArduinoCloud.begin(ArduinoIoTPreferredConnection, false); // false = no watchdog

/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(4);
ArduinoCloud.printDebugInfo();
}

// ====================== Main Loop =========================
void loop() {
ArduinoCloud.update();
// Your code here
Serial.print("\n(");
Serial.print(i++);
Serial.print(") CloudCon = ");
Serial.println(ArduinoCloud.connected());
//seconds = (millis()-starttime) / 1000; //seconds
//potentiometer = analogRead(A0);
delay(1000); // much shorter than watchdog ~ 16 sec

}
// ====================== END Main Loop ====================

/*
Since Status is READ_WRITE variable, onStatusChange() is
executed every time a new value is received from IoT Cloud.
*/
void onStatusChange() {
// Add your code here to act upon Status change via dashboard
Serial.print("Status=");
Serial.println(status);

}
/*
Since TestValue is READ_WRITE variable, onTestValueChange() is
executed every time a new value is received from IoT Cloud.
*/
void onTestValueChange() {
// Add your code here to act upon TestValue change
}
/*
Since Area1 is READ_WRITE variable, onArea1Change() is
executed every time a new value is received from IoT Cloud.
*/
void onArea1Change() {
// Add your code here to act upon Area1 change
Serial.print("Area1=");
Serial.println(area1);
}
/*
Since Area2 is READ_WRITE variable, onArea2Change() is
executed every time a new value is received from IoT Cloud.
*/
void onArea2Change() {
// Add your code here to act upon Area2 change
}
/*
Since Area3 is READ_WRITE variable, onArea3Change() is
executed every time a new value is received from IoT Cloud.
*/
void onArea3Change() {
// Add your code here to act upon Area3 change
}
/*
Since BoardO3Analog is READ_WRITE variable, onBoardO3AnalogChange() is
executed every time a new value is received from IoT Cloud.
*/
void onBoardO3AnalogChange() {
// Add your code here to act upon BoardO3Analog change
}
/*
Since Number1 is READ_WRITE variable, onNumber1Change() is
executed every time a new value is received from IoT Cloud.
*/
void onNumber1Change() {
// Add your code here to act upon Number1 change
}
/*
Since Number2 is READ_WRITE variable, onNumber2Change() is
executed every time a new value is received from IoT Cloud.
*/
void onNumber2Change() {
// Add your code here to act upon Number2 change
}
/*
Since Number3 is READ_WRITE variable, onNumber3Change() is
executed every time a new value is received from IoT Cloud.
*/
void onNumber3Change() {
// Add your code here to act upon Number3 change
}
/*
Since Potentiometer is READ_WRITE variable, onPotentiometerChange() is
executed every time a new value is received from IoT Cloud.
*/
void onPotentiometerChange() {
// Add your code here to act upon Potentiometer change
}
/*
Since Seconds is READ_WRITE variable, onSecondsChange() is
executed every time a new value is received from IoT Cloud.
*/
void onSecondsChange() {
// Add your code here to act upon Seconds change
}
/*
Since Led is READ_WRITE variable, onLedChange() is
executed every time a new value is received from IoT Cloud.
*/
void onLedChange() {
// Add your code here to act upon Led change
digitalWrite(5,led);
testValue = ("Led = " + String(led));
Serial.print("Led changed");
}

void doThisOnConnect() {
/* add your custom code here */
Serial.print("Board successfully connected to Arduino IoT Cloud - ");
Serial.println((millis() - starttime) / 1000);
}
void doThisOnSync() {
/* add your custom code here */
Serial.print("Thing Properties synchronised - ");
Serial.println((millis() - starttime) / 1000);
}
void doThisOnDisconnect() {
/* add your custom code here */
Serial.print("Board disconnected from Arduino IoT Cloud - ");
Serial.println((millis() - starttime) / 1000);
}

I would suggest removing the delay() in the loop(). Even if it is a short one.
You can follow this approach

unsigned long last_ts = 0;

void loop() {
  ArduinoCloud.update();
  
  ...
  unsigned long now = millis();
  if (now - last_ts > 1000) {
    last_ts = now;
     ... periodic code here ...
  }
  ...  
}

Instead of SMS, you could send emails using the Trigger feature

If that's not a good option for you, you could use webhooks to connect with IFTTT or Zapier. Then you can find in those platforms any services that can send SMS.

I had tried that at one time and it didn't seem to make any difference as long as I didn't exceed about 15 seconds for the watchdog timer. I am familiar with this issue and I will try as you suggested.

The only reason for the delay was so I could read the output and not have the serial buffer overwrite itself giving scrambled output since the loop runs so fast.

Part of the problem may be that the loop starts before the background connection stuff has finished. The loop rund about three seconds before the Connected message prints. That is about when my more than 12 Thing variable program hangs. Could be a coincidence.

Did you get my code to run? Even with the delay(1000) removed?

Thanks so much for helping with this, it is really important to me.

Tom

My client want texts to be sent to his phone. I would like to know about the "trigger feature" I have not heard of that.

It was recently announced :wink:

Hi! I have just tested your code (as it is and with one additional variable) and it works for me :man_shrugging:
It is a pretty simple code, so I don't actually see any reasons why it shouldn't work... :sweat_smile:

I can see some potential uses for Triggers, nice to have that feature. I tried to do more testing, but the cloud editor can't upload a sketch today. error is "No Device found on com3". It shows it as connected at the top of the cloud IDE. I reinstalled the create agent. No luck. The IDE works fine on other sketches.

I managed to download the test sketch to the IDE and it compiled with errors about the SECRET_OPTIONAL_APN was not declared in this scope (same for the other SECRET_...). I think that is something the cloud editor does for you that the IDE doesn't. Sigh... I'll hard code them in and try that.

Wouldn't let me change the code gave read only error. I did get it to work. I had to close all instances of the IDE, then the cloud editor worked OK. I guess the IDE and the cloud editor are mutually exclusive.
I will run some tests.

Ran into a problem. In cloud editor I loaded my second test program a different Thing I guess. It gave me an error "No device is currently associated to this Thing, hence the Connection Handler code could not be generated".

It also put a Comment box in the .h code saying essentially the same. and telling me to associate an existing device or manually create your own instance of Connection Handler.
I wouldn't know how to manually do that so I used the cloud to disconnect the device (there is only one device) and then connected it to the appropriate thing.

I get the same error "No device...". Meanwhile the serial monitor shows the first test program is still running happily. I reset the device and it of course rebooted connected and ran the first test program as expected.
So at this point I am stuck. Bug or feature? I will use the IDE to program the board with the "Blink" program to stop the device from connecting to the cloud, then go back to the cloud editor and try the other cloud test program. fairly sure if this will work, will update soon.

Update:
Success! I found that I had a similar problem in that the IDE gave the same error "No device..." until I closed the browser, then the IDE saw the device and downloaded "Blink".

Then I closed the IDE. Opened up the browser, restored the previous tabs, and the cloud editor uploaded the second test sketch with no problems and it ran!

Is this a bug or a feature? Long time to test a different cloud program.
I also tried a different program I had that used the MKR 1500 without the Arduino cloud and had the same problem trying to upload the sketch with the cloud editor. It seems when the MKR board is connected either to the Arduino cloud or just the cellular network, the web editor reports that "No device is found on com3..." Not really too helpful. At least it is a workaround, albeit time consuming.

This second test program (with 12 variables) had a tiny amount of code that would print out the value of a dashboard Value widget when it was changed.

I changed the value, and about 30 seconds later I saw the value change on the serial monitor. I changed the dashboard value several times and it varied, but usually in about 15 seconds I saw the change print on the serial monitor. Very slow today for some reason.

I added one int variable, ran it and it hung after second loop. here is the serial monitor output:

GPRS.attachGPRS(): 4
Connected to GPRS Network

(1) CloudCon = 0
TimeServiceClass::sync  Drift: -8 RTC value: 1689345826

(2) CloudCon = 0

no other changes to the code. I will send the whole code if you wish, but don't want waste space here if not needed. Here is what the variables look like now from the .h file. I added an "int prefix1".

void onStatusChange();
void onTestValueChange();
void onArea1Change();
void onArea2Change();
void onArea3Change();
void onBoardO3AnalogChange();
void onNumber1Change();
void onNumber2Change();
void onNumber3Change();
void onPotentiometerChange();
void onPrefix1Change();
void onSecondsChange();
void onLedChange();

I then decided to take out the thing variable and recompile. It said that there was no board connected. After trying many ideas I found that having ArduinoCloud.begin(ArduinoIoTPreferredConnection, false); in the program is a bad thing. When the program hangs, the USB port does not respond and isn't recognized by the web editor/IDE. The Create Agent gets confused because the physical USB port is there but doesn't respond properly. I ended up with about 6 instances of create agent showing in the task thingy. I deleted all of them, restarted Create agent - no work. Finally I closed down the browser removed any instances of Create Agent, launched the IDE, and tried to upload "Blink". Didn't work, port still hosed by the hung program still running on the MKR. Finally after many tries and resetting the MKR the "Blink" program downloaded and ran.

That tookme about an hour, but MKR was now running something that didn't use the IoT cloud.
I closed the IDE, fired up the web editor made sure the variable count was 12. Recompiled and downloaded it and it ran OK. Note in the output how many times through the loop it takes to fully get the cloud part up and running and that "ArduinoCloud.connected()" can't be used to control when your loop code should be run. It appears that you must use the call backs and wait for the "doThisOnSync()" callback to fire, then run your loop code.

The problem is that when the 13 Thing variable program crashes is before all of that, and the program never runs...

So if i can get past the program locking up issue with more than 12 variables figured out...
(Yes the first test program with 15 int Thing variables runs OK, Mine with a mix of variable types doesn't. At least this is a reproducible problem.

I think the issue is not in the program, but in the cloud stuff that runs in the background.
I hope we can get this resolved.

Here is the serial monitor output:

GPRS.attachGPRS(): 4
Connected to GPRS Network

(1) CloudCon = 0
TimeServiceClass::sync  Drift: -316 RTC value: 1689356376

(2) CloudCon = 0

(3) CloudCon = 1

(4) CloudCon = 1

(5) CloudCon = 1

(6) CloudCon = 1

(7) CloudCon = 1

(8) CloudCon = 1

(9) CloudCon = 1
Connected to Arduino IoT Cloud
Thing ID: 3b7bb899-d59e-4d1e-ae90-07da76eee3c0
Board successfully connected to Arduino IoT Cloud - 25

(10) CloudCon = 1

(11) CloudCon = 1

(12) CloudCon = 1
Area1=555
Led changedStatus=Tommy 123
TimeServiceClass::setTimeZoneData offset: -14400 dst_unitl 1699164000
Thing Properties synchronised - 29

(13) CloudCon = 1

(14) CloudCon = 1

(15) CloudCon = 1

(16) CloudCon = 1


Update FYI:
I cleaned up my test code (12 vars) to wait to fully connect and sync. That part of the code seems to work. My loop code now doesn't run until all variables are synced.

/*
  Sketch generated by the Arduino IoT Cloud Thing "GreenWater2"
  https://create.arduino.cc/cloud/things/3b7bb899-d59e-4d1e-ae90-07da76eee3c0

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  String status;
  String testValue;
  int area1;
  int area2;
  int area3;
  int boardO3analog;
  int number1;
  int number2;
  int number3;
  int potentiometer;
  int seconds;
  bool led;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"

unsigned long i = 0;
unsigned long last_ts = 0;    //loop timer
unsigned long starttime = millis();
bool actuallyConnected = false;

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500);
  Serial.println("Serial working");

  // Defined in thingProperties.h
  initProperties();

  /*
      Invoking `addCallback` on the ArduinoCloud object allows you to subscribe
      to any of the available events and decide which functions to call when they are fired.

      The functions `doThisOnConnect`, `doThisOnSync`, `doThisOnDisconnect`
      are custom functions and can be named to your likings and for this example
      they are defined/implemented at the bottom of the Sketch
  */
  // I have tried with and without these callbacks and program fails the same way
  ArduinoCloud.addCallback(ArduinoIoTCloudEvent::CONNECT, doThisOnConnect);
  ArduinoCloud.addCallback(ArduinoIoTCloudEvent::SYNC, doThisOnSync);
  ArduinoCloud.addCallback(ArduinoIoTCloudEvent::DISCONNECT, doThisOnDisconnect);

  // Connect to Arduino IoT Cloud
  // If watchdog is on and program fails to connect to the cloud it is almost
  // impossible to upload a new sketch because the watchdog fires during the upload process
  ArduinoCloud.begin(ArduinoIoTPreferredConnection, true);  // false = no watchdog

  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
  */
  setDebugMessageLevel(4);
  ArduinoCloud.printDebugInfo();
}

// ====================== Main Loop =========================
void loop() {
  ArduinoCloud.update();
  
  // Your code here
  unsigned long now = millis();
  if (now - last_ts > 1000UL) {
    last_ts = now;
    
    // periodic code goes here executed once per second
    // wait to be completely connected 
    // ---> Problem is code won't run unless connected, in my case the program needs to run anyway even if connection doesn't happen
    if (actuallyConnected == true) {
      i++;
      Serial.print("\n(");
      Serial.print(String(i) + ") ");
      //Serial.print(") CloudConnected = ");
      //Serial.println(ArduinoCloud.connected());

    }
  }
}
// ====================== END Main Loop ====================

/*
  Since Status is READ_WRITE variable, onStatusChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onStatusChange()  {
  // Add your code here to act upon Status change via dashboard  // tests communication FROM the cloud
  Serial.print("\nStatus Changed to: ");
  Serial.println(status);

}
/*
  Since TestValue is READ_WRITE variable, onTestValueChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onTestValueChange()  {
  // Add your code here to act upon TestValue change
}
/*
  Since Area1 is READ_WRITE variable, onArea1Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onArea1Change()  {
  // Add your code here to act upon Area1 change  // tests communication FROM the cloud
  Serial.print("\nArea1 Change =");
  Serial.println(area1);
}
/*
  Since Area2 is READ_WRITE variable, onArea2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onArea2Change()  {
  // Add your code here to act upon Area2 change
}
/*
  Since Area3 is READ_WRITE variable, onArea3Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onArea3Change()  {
  // Add your code here to act upon Area3 change
}
/*
  Since BoardO3Analog is READ_WRITE variable, onBoardO3AnalogChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onBoardO3AnalogChange()  {
  // Add your code here to act upon BoardO3Analog change
}
/*
  Since Number1 is READ_WRITE variable, onNumber1Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onNumber1Change()  {
  // Add your code here to act upon Number1 change
}
/*
  Since Number2 is READ_WRITE variable, onNumber2Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onNumber2Change()  {
  // Add your code here to act upon Number2 change
}
/*
  Since Number3 is READ_WRITE variable, onNumber3Change() is
  executed every time a new value is received from IoT Cloud.
*/
void onNumber3Change()  {
  // Add your code here to act upon Number3 change
}
/*
  Since Potentiometer is READ_WRITE variable, onPotentiometerChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onPotentiometerChange()  {
  // Add your code here to act upon Potentiometer change
}
/*
  Since Seconds is READ_WRITE variable, onSecondsChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onSecondsChange()  {
  // Add your code here to act upon Seconds change
}
/*
  Since Led is READ_WRITE variable, onLedChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onLedChange()  {
  // Add your code here to act upon Led change
  digitalWrite(5, led);
  testValue = ("Led = " + String(led));  // tests communication TO the cloud
  Serial.print("Led changed");
}

// Callback functions
void doThisOnConnect() {
  /* add your custom code here */
  Serial.print("\nBoard successfully connected to Arduino IoT Cloud - ");
  Serial.print((millis() - starttime) / 1000);
  Serial.println(" Seconds");
}
void doThisOnSync() {
  /* add your custom code here */
  actuallyConnected = true;
  Serial.print("\nThing Properties synchronised - ");
  Serial.print((millis() - starttime) / 1000);
  Serial.println(" Seconds");
}
void doThisOnDisconnect() {
  /* add your custom code here */
  actuallyConnected = false;
  Serial.print("\nBoard disconnected from Arduino IoT Cloud - ");
  Serial.print((millis() - starttime) / 1000 );
  Serial.println(" Seconds");
}

You can see from the output it is well behaved:

Connected to Arduino IoT Cloud
Thing ID: 3b7bb899-d59e-4d1e-ae90-07da76eee3c0

Board successfully connected to Arduino IoT Cloud - 16 Seconds

Area1 Change =555
Led changed
Status Changed to: Tommy 123
TimeServiceClass::setTimeZoneData offset: -14400 dst_unitl 1699164000

Thing Properties synchronised - 19 Seconds

(1) 
(2) 
(3) 
(4) 
(5) 
(6) 
(7) 
(8) 
(9) 
(10) 
(11) 
(12) 
(13) 
(14) 
(15) 
(16) 
(17) 
(18) 
(19) 
(20) 
(21) 
(22) 
(23) 
(24) 
(25) 
(26) 
(27) 
(28) 
(29) 
(30) 
(31) 
(32) 
(33) 
(34) 
(35) 
(36) 
(37) 
Status Changed to: Testing 123

(38) 
(39) 
(40) 

Next, I will now add back the 13th variable and see how it works.