PLX-DAQ version 2 - now with 64 bit support! (and further new features)

Bride:
How can I auto save the spreadsheet when the time is equal to 07:00 AM.
How do you use the tick boxes, can they be used to do a auto save when selected?

Hi Bride,
the tick boxes can be used for whatever you want them to be used. But: it is only good for controlling your Arduino. Via Ardunio you can set the label of the boxes, check/uncheck each box and get the status of each box (is checked / is not checked). Therefore you could name a box e.g. "pause every 100 samples", and check its status via Arduino every 10 seconds to see if the user on the PC checked the box and in case yes use a counter on Arduino to count to 100 and do a pause.

For your purpose I would suggest to use the CustomDevPoints (have a look at the Beginners Guide please). Each time data is read by PLX DAQ the custom DevPoint is triggered. In there you could use some VBA code to save the workbook if the time is equal to 07:00 AM.
On the other hand you could also use the SAVEWORKBOOK command from Arduino (via Serial.println) but you won't have the current time on your Arduino (only milliseconds since start via millis() ...).

Better to go for the CustomDevPoint and some VBA code.

Hi NetDevil
I somehow somewhere can not figure out how this piece of code works?

Private Sub clearData()
    WStoUse.Range("A2:" & Split(WStoUse.UsedRange.Address, ":", , vbBinaryCompare)(1)).NumberFormat = "General"
    WStoUse.Range("A2:" & Split(WStoUse.UsedRange.Address, ":", , vbBinaryCompare)(1)).Value = Null
End Sub

My aim is to clear only colums A B C D (Data logging four channels),the count of columns determined in function ,
because I manualy fill in data in cells E2 F2 and H2 which I want to keep if I press Clear Columns.

However I can solve my problem when I search for the last row in the active sheet and then do a resize, but I guess this is not a proper solution?
I do understand the individual things like WStoUse , UsedRange and the Split function, but can not figure out how to alter the code to my needs.

Hi GijKieken,

I had to think about your question for a while and came up with three options:

  1. Rewrite the ClearData command: I would not recommend this since you would have to copy your changes to every new version (although there weren't so many new versions lately :zipper_mouth_face:

  2. Implement your own commmand: using CustomDevPoints this is possible, but it takes some knowhow and you still need to copy that code to every new version of PLX DAQ

  3. using the ClearRange command: this came to me this morning. If you know the data you want to remove you could just use the CLEARRANGE which is available out of the box. If you want to delete all content from columns A, B, C and D (without the headers) and you know the amount of data you pasted to PLX DAQ by Arduino this would be good for you: Serial.println((String) “CLEARRANGE,A,2,D,” + yourRowCounter);In case you don't know how many rows you pasted to the sheet ... well ... just delete 100.000 - that should be enough :smiley: Serial.println((String) “CLEARRANGE,A,2,D,100000");

I hope this works for you !?

Hi NetDevil,
For sure it makes more sence if one can examine the Arduino code.
The options you offer are indeed worthwhile and I will considder to alter the code.
Thanks anways for the ideas.

/*
 @ Purpose of this program is to Log two independent speeds and two
 @ Lambda values from a combustion engine
 @ Speed of the Engine measured with inductive clamp 0--12.000 Rpm
 @ 1 puls per revolution (12000rpm/60sec) 200Hz
 @ Speed of the Drum with photo-sensor 0--2500 Rpm
 @ 60 pulses per revolution (2500rpm*60[encoder-disc]/60sec) 2500Hz
 @ int0 (digitalpin 2)highest priority is used for Engine speed
 @ int1 (digitalpin 3)lower priority is used for Drum speed
 @ A0 & A1(alias input 14 & 15) connected via an impedance interface
 @ to measure 2-channel Lambda
 */

#include <TimerOne.h>
#define field_separator ","    //used for .csv file
volatile int revEngine=0;
volatile int revDrum=0;
byte lambdaSensorPin0 = A0;  //input for first Lamda measurement
byte lambdaSensorPin1 = A1;  //input for second Lambda measurement
int lambdaValue0 = 0;        //variable to store the value coming from Lambda sensor0
int lambdaValue1 = 0;        //variable to store the value coming from Lambda sensor1

void isrEngine() //interrupt service routine Engine
{
  revEngine++;
}                 //last curley bracket initiates a Return

void isrDrum()  //interrupt service routine Drum
{
  revDrum++; 
}               //last curley bracket initiates a Return

void plot()
{
  detachInterrupt(0);           // detaches the interrupt 0
  detachInterrupt(1);           // detaches the interrupt 1
  //Serial.println((String)"DATA," + revDrum + field_separator + revEngine + field_separator + millis());
  //Serial.println((String)"DATA," + revDrum + "," + revEngine + "," + lambdaValue0 + "," + lambdaValue1 );
  //Get rid off String object
  Serial.print("DATA,");
  Serial.print(revDrum);     
  Serial.print(field_separator);
  Serial.print(revEngine);   
  Serial.print(field_separator);
  Serial.print(lambdaValue0);
  Serial.print(field_separator);
  Serial.println(lambdaValue1);

  attachInterrupt(0,isrEngine,CHANGE);
  attachInterrupt(1,isrDrum,CHANGE);
}

void setup() 
{
  Serial.begin(9600);

  //Serial.println("CLEARDATA"); // clears sheet starting at row 2
  Serial.println("CLEARSHEET"); // clears sheet starting at row 1

  //define 5 columns named RevDrum,RevEngine,Lambda0,Lambda1,Date&Time
  Serial.println("LABEL,RevDrum,RevEngine,Lambda0,Lambda1,Date&Time");

  attachInterrupt(0,isrEngine,CHANGE);  // attaching interrupt Engine
  attachInterrupt(1,isrDrum,CHANGE);    // attaching interrupt Drum
  Timer1.initialize(250000);            // sample time 250ms
  Timer1.attachInterrupt(plot);         // attach the service routine here
  //post to specific cells on default sheet as well as named sheet
  //Serial.println("CELL,SET,G10,400 test 1 string"); // default sheet active in PLX DAQ Excel
  //Serial.println("CELL,SET,ONSHEET,Simple Data,G,11,400 test 2 string"); // named sheet available in PLX DAQ Excel
  Serial.println("CELL,SET,E2,DATE");   // default sheet active in Gij Kieken Excel
  Serial.println("CELL,SET,E3,TIME");   // default sheet active in Gij Kieken Excel
}
void loop()
{
  lambdaValue0 = analogRead(lambdaSensorPin0);  //read the first sensor
  lambdaValue1 = analogRead(lambdaSensorPin1);  //read the second sensor
  delay(2);  //give the A-D converters some time to settle  
}

Meanwhile I made this of it in Excel and that means I have to copy it in all later versions.

Private Sub clearData()

    'WStoUse.Range("A2:" & Split(WStoUse.UsedRange.Address, ":", , vbBinaryCompare)(1)).NumberFormat = "General"
    'WStoUse.Range("A2:" & Split(WStoUse.UsedRange.Address, ":", , vbBinaryCompare)(1)).Value = Null
    '------------------------------------------------------------------------------------------------------------
    'lastRow = WStoUse.Cells(Rows.Count, ColumnCount).End(xlUp).offset(1, 0).row
 
lastRow = WStoUse.Cells.Find("*", SearchOrder:=xlByRows, LookIn:=xlValues, SearchDirection:=xlPrevious).row
lastCol = WStoUse.Cells.Find("*", SearchOrder:=xlByColumns, LookIn:=xlValues, SearchDirection:=xlPrevious).column
'bij de lastCol formule is geen regelnummer opgegeven dus kiest Excel standaart row1
lastCol = lastCol - 1   'lastCol=5 door de Header Time&Date in row1, dus -1 voor de cellen met Data
Range(Cells(2, 1), Cells(lastRow, lastCol)) = Null  'enkel de Data in kolom A..D wissen,starten bij row2
WStoUse.Range("A1").Select

End Sub

The values I send are rawValues ,I do the calculations for conversion in Excel.
Sorry for the comments I have to translate them to make it more universal(my native language is dutch).

Addendum to my post above.
So in Excel Plx, via Arduino Setup (setup only runs once)
I place a header Time&Date in Cell E1
Date in Cell E2
Time in Cell E3
In Excel Cell F2 a title for the workbook (project) is placed which I tranfer to other sheets for printout of graphs
In Excel Cell H2 via an inputBox I provide a fileName_xx (xx is a counter to increment on each save) the fileName is also transfered to other sheets for printouts

That is the reason why I had to change the code for clearData an clearSheet.
So when I do a run on the Dyno I need to run stop (connect , disconnect) several times and does not want to fill in the title and fileName again.
I could uncheck but with a hit on my Date and Time (which I prefer to keep) is also gone.
Maybe this short info gives more explanation to the issue.

A snapshot of the Main page.

Is there an instability for running for too long?
After some time, some values start getting a little crazy (even though they seen okay on Direct Debug Window).

Is it because there're many cells being sent/written?

Should I lower the baudRate? Increase buffer?

OBS:

Robin2:
Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

The technique in the 3rd example will be the most reliable.
...R

On another topic about the Serial Data being reliable, they cited this 3rd example. Don't know if the idea of using start-marker and end-marker is the same of PLX-DAQ code.

Apparently solved after setting baudRate to 2400.

Tip for others having same problem: READ the begginer's guide made by NetDevil! I discovered my switch wasn't working because I was using Serial.readStringUntil(10).toFloat() and should be using Serial.readStringUntil(10).toInt() !

Thanks!

Hi, NetDevil, what is the License for this worksheet, sicne you got rid of selmaDAQ?

Thanks

Hi egsc,

please don't think I haven't seen your posts. I am particular busy at the moment but will try to post you an answer tomorrow ( 2am in Germany at the moment....)

Greetings!

OK I am a new with Arduino

I read the Beginners guide, look in this forum, installed Version 2.11, and everything seems fine. I can even read the Arduino data in the "Raw data logger:" but no data goes into the spreadsheet. I can even clear the existing data with the "Clear columns". Everything seems to be working exactly as it supposed to expect there is no data being written in the spreadsheet.

I am using Windows 10 and Excel 2016.

Any idea of what is going wrong and how to fix it?

Thanks

@GijKieken: don't you worry about your comments - at least for me. Because I'm German I could roughly guess / translate those :stuck_out_tongue:
On another piece of paper: I don't mind the UI being reworked for special needs - but keeping the credits in the title of the form would be nice (my nickname at least) :wink:

@egsc:

  • There actually is an issue when using a too high baud rate. Data will get mixed up pretty soon - my best guess is, that it depends on your computers speed. Nevertheless I found a general improvement of PLX DAQ v2 engine (see post for version 2.11 "Backlog for next version(s):") but haven't had the time to actually implement that. Therefore it is most suggested to run PLX DAQ on low baud rates like 9600.
  • I haven't had it running for longer times. Does it really get buggy? In case the data is received correctly in DirectDebugWindow it would imply and issue within Excel - most likely due to too many cells being used. That would be a pity but I guess hard to solve :-/
  • Regarding the licence: it is BEERWARE licence. That sounds a bit funny but is true. I have no meaning of earning money with it, therefore the software should be used as anyone wants. As the comments in the intro to the code say:
  • "THE BEER-WARE LICENSE" (Revision 42): *
  • Net^Devil wrote this file. As long as you retain *
  • this notice you can do whatever you want with *
  • this stuff. If we meet some day, and you think *
  • this stuff is worth it, you can buy me a beer *
  • in return -- Jonathan Arndt, Stuttgart, Germany *

The code is based on parts of Martin Hebel of Parallax Inc (Selma) (with regards to the command logic) and David Hitchner and Brendan Lambe (for COMM port communications 64bit). In a chat with Martin he said that "I have no financial interest in the software and would happy to see a solution for all". Of course I will follow that lead.
The software should be distributed for free and open source.
Please keep the names of all participants (as listed above) in the code.
And in case we ever meet in Germany or somewhere else ==> Prost ("cheers")

@TeoGr: could you please post your code? And by that please use the "[ code]" and "[/ code]" tags for better readability. My first guess is, that you didn't use the "DATA" command correctly. But we will have to see. Please also post a screenshot of PLX DAQ in action with the DirectDebugWindow visible. Thanks :slight_smile:

Sure, let see if can do it right.

#include <LiquidCrystal.h>
#include <PID_v1.h>
#include <Wire.h>
#include <Sodaq_SHT2x.h>
#include <Servo.h>

int pos = 45;// variable to store the servo position
int n = 1;
unsigned long previousMillis = 0; // to control the frequency of move
const unsigned long interval = 6000000; // intervals of movement
unsigned long previousMillisLCD = 0;
const unsigned long intervalLCD = 5000; // change LCD display every 3 seconds
double Temp, TempMax, Tempmin, Humi, HumiMax, Humimin;  //to display in the LCD
double T_Setpoint, H_Setpoint, T_Output, H_Output;  // for controlling via PID
double T_Kp = 10, T_Ki = 5, T_Kd = 1; //parameters for PID setting
double H_Kp = 10, H_Ki = 5, H_Kd = 1;

LiquidCrystal lcd(13, 12, 8, 7, 4, 2); //only digital pins, PWMs are for fan control and PID output
Servo myservo;
PID T_PID(&Temp, &T_Output, &T_Setpoint, T_Kp, T_Ki, T_Kd, DIRECT);
PID H_PID(&Humi, &H_Output, &H_Setpoint, H_Kp, H_Ki, H_Kd, DIRECT);
#define T_pinout 6  //PID output, must be a PWM
#define H_pinout 10  // PID output, must be PWM

void setup() {
  lcd.begin(16, 2);
  lcd.print("fxt 2000");
  delay(1500);
  Wire.begin();
  Serial.begin(9600);
  myservo.attach(3);  // attaches the servo on pin 3 to the servo object
  myservo.write(pos);
  Temp = SHT2x.GetTemperature();  // reads Temperature in Celsious degrees
  Humi = SHT2x.GetHumidity();  // reads humidity in %
  T_Setpoint = 35;  //temperature setpoint for the PID
  H_Setpoint = 65;  // Humidity setpoint for PID
  Tempmin = Temp;
  Humimin = Humi;
  T_PID.SetMode(AUTOMATIC);
  H_PID.SetMode(AUTOMATIC);
  analogWrite(9,150);  //PWM controlled fan

  Serial.println("CLEARDATA");
  Serial.println("CLEARSHEET");
  Serial.println("Temp,Humidty,T_out,H_out");
}

void loop() {
  Temp = SHT2x.GetTemperature();
  Humi = SHT2x.GetHumidity();
  T_PID.Compute();
  analogWrite(T_pinout, T_Output);
  H_PID.Compute();
  analogWrite(H_pinout, H_Output);


  unsigned long currentTime = millis();
  if ((currentTime - previousMillis >= interval) and (pos <= 90)) {
    previousMillis += interval;
    for (pos = 45; pos <= 135; pos += 1) { // goes from XX degrees to XX degrees
      // in steps of 1 degree
      myservo.write(pos);              // tell servo to go to position in variable 'pos'
      delay(30);                       
    }
  }
  if ((currentTime - previousMillis >= interval) and (pos >= 90)) {
    previousMillis += interval;
    for (pos = 135; pos >= 45; pos -= 1) { // goes from xx degrees to xx degrees
      myservo.write(pos);              // tell servo to go to position in variable 'pos'
      delay(30);                       
    }
  }
  if (Temp >= TempMax) {
    TempMax = Temp;
  }
  if (Temp <= Tempmin) {
    Tempmin = Temp;
  }
  if (Humi >= HumiMax) {
    HumiMax = Humi;
  }
  if (Humi <= Humimin) {
    Humimin = Humi;
  }

  if ((currentTime - previousMillisLCD >= intervalLCD) and (n==1)) {
    previousMillisLCD += intervalLCD;
    n=2;
  }
  
  if ((currentTime - previousMillisLCD >= intervalLCD) and (n==2)) {
    previousMillisLCD += intervalLCD;
    n=1;
  }

  if (n==1){
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("T");
    lcd.setCursor(1, 0);
    lcd.print(Temp);
    lcd.setCursor(6, 0);
    lcd.print(" ");
    lcd.setCursor(7, 0);
    lcd.print(TempMax,1);
    lcd.setCursor(11, 0);
    lcd.print("/");
    lcd.setCursor(12, 0);
    lcd.print(Tempmin,1);
    lcd.setCursor(0, 1);
    lcd.print("H");
    lcd.setCursor(1, 1);
    lcd.print(Humi);
    lcd.setCursor(6, 1);
    lcd.print(" ");
    lcd.setCursor(7, 1);
    lcd.print(HumiMax,1);
    lcd.setCursor(11, 1);
    lcd.print("/");
    lcd.setCursor(12, 1);
    lcd.print(Humimin,1);
  }
  
  if (n==2) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print((int) currentTime/86400000);  // print the numbers of Days
    lcd.setCursor(3, 0);
    lcd.print("Days");
    lcd.setCursor(8, 0);
    lcd.print("Heat");
    lcd.setCursor(13, 0);
    if ((T_Output * 100) / 255>=100){
      lcd.print("99");
    }else{
    lcd.print((T_Output * 100) / 255);
    }
    lcd.setCursor(15, 0);
    lcd.print("%");
    lcd.setCursor(8, 1);
    lcd.print("Humi");
    lcd.setCursor(13, 1);
    if ((H_Output * 100) / 255>=100){
      lcd.print("99");
    }else{
    lcd.print((H_Output * 100) / 255);
    }
    lcd.setCursor(15, 1);
    lcd.print("%");  
 }

//  Serial.print(millis()/1000);
//  //Serial.print("  ");
//  Serial.print(Temp);
//  Serial.print("  ");
//  Serial.print(TempMax);
//  Serial.print("  ");
//  Serial.print(Tempmin);
//  Serial.print("  ");
//  Serial.print(Humi);
//  Serial.print("  ");
//  Serial.print(HumiMax);
//  Serial.print("  ");
//  Serial.print(Humimin);
//  Serial.print("  ");
//  Serial.print((T_Output * 100) / 255);
//  Serial.print("  ");
//  Serial.println((H_Output * 100) / 255);

Serial.print(Temp);
Serial.print(",");
Serial.print (Humi);
Serial.print(",");
Serial.print((T_Output * 100) / 255);
Serial.print(",");
Serial.println((H_Output * 100) / 255);
 
  delay(1000);


}

btw I just added the:
Serial.println("CLEARDATA");
Serial.println("CLEARSHEET");
Serial.println("Temp,Humidty,T_out,H_out");

the Spreadsheet clear as it should and I noticed the paste function in the excel is disable and the clipboard remains empty. Pausing data log does not stop the raw data log.

Thanks

OK hold on, I think I got it. I will add a line data,date,time and see if it works....

cheers

Damm it, why it is always some thing simple....

any way, problem solved!

Cheers

On my worksheet, with baudRate=9600, CELLGET fails (returns 0 or 2) after some time (100-400seconds after start), goes back to sending the right values, but eventually Excel crashes (can occur at 300-600 seconds after start).

I already added delay(200) before CELLGET, dind't solved, and other delay(200) before CELLSET, it keeps senging wrong values and eventually crashing (before 200s).

Thenk I tried to ""force"" reading the right values.

delay(200); //supposed to, but didn't solve the wrong values
Serial.println("CELL,GET,FROMSHEET,Control,AV,20"); //read AV20
valAD20 = Serial.readStringUntil(10).toFloat(); //(yes, valAD20 was declared as double before setup())
//verify if it was correctly read
while (setpoint == 0 || setpoint == 2) { //because 0 and 2 are wrong values that appear for me
                                          Serial.println("Wrong read, read again until get it right!");
                        delay(300); //even bigger delay
                        Serial.println("CELL,GET,FROMSHEET,PainelControle,AV,20");
                        valAD20= Serial.readStringUntil(10).toFloat(); 
                        Serial.println("PAUSELOGGING");
                        Serial.println("SAVEWORKBOOKAS,ReadWrongValAD20");
                        Serial.println("RESUMELOGGING"); 
                 }

This generates a CORRUPTED .xlsm (ReadWrongValAD20.xlsm), so I deleted the lines to create a new .xlsm. So the code is:

delay(200); //supposed to, but didn't solve the wrong values
Serial.println("CELL,GET,FROMSHEET,Control,AV,20"); //read AV20
valAD20 = Serial.readStringUntil(10).toFloat(); //(yes, valAD20 was declared as double before setup())
//verify if it was correctly read
while (setpoint == 0 || setpoint == 2) { //because 0 and 2 are wrong values that appear for me
                                          Serial.println("Wrong read, read again until get it right!");
                        delay(300); //even bigger delay
                        Serial.println("CELL,GET,FROMSHEET,PainelControle,AV,20");
                        valAD20= Serial.readStringUntil(10).toFloat(); 
                 }

========

WEIRD=> I disconnected PLX-DAQ and Excel crashed while it was disconnected. Maybe it isn't PLX-DAQ?
But it keeps crashing after ~150s.

Sometimes, after long running, this error occurs: it """"forgets""" to jump to row above and inserted the values on the next cells on the same row.

It also crashes somewhere 100-600s, like in this video.

===========
CORRECTION - Decreasing baudRate to 2400 really improved stability (26min running with no Excel crashes). However, mistakes still occured eventually on sending values to Excel.
And decreasing baudRate made the rows sent go from 1s period to 4-6 period.... Wish I could have stability + fast frequency :S. Where to change buffer size? Here? (Picture sent)

"DirectDebugWindow it would imply and issue within Excel - most likely due to too many cells being used. That would be a pity but I guess hard to solve :-/"
The error was present in DirectDebugWindow. It was a PID() library value (ATune_RunTim(), which is 0 if running autotune and 1 if completed). So it wasn't from CELLGET....

26min running

=====UPDATE
@SASv
I saw you got sucess on running at baudRate 115200.

SASv:
........
6. 10 trials at 115200 baud with 100 msec delays before the CELL,GET and CELL,GET,FROMSHEET commands: 0 complete successes!

Update: If tdelay is changed from byte to integer
Result: 10/10 complete successes
.....

Sorry, what? "tdelay changed from byte to integer", what do you mean?

SASv:
........
Finally, another clue to the puzzle might be what I observed in a program I am developing. The code involves 9600 baud communication and has several GETs and SETs in the infinite loop. After several iterations there is a final GET and SET (the infinite loop "ends" with a very long delay). The last SET failed until I increased the delay before it to 500 msec. At that time some of the loop GETs and SETs had 100 msec delays. However, when I decreased them to 3 msec, the final SET again failed. To return to success I had to increase its delay to 800 msec. So there seems to be a cummulative effect from prior GETs and SETs.

FURTHER UPDATE: Increasing the stop bits to 2 (Serial.begin(baudRate,SERIAL_8N2); ) might help a bit. It is no solution, but it seems to increase the frequency of correct results.
.....

I missed this answer on the long post! I'll try it and update here about my results!

Hi NetDevil,
For sure I put your nick name back,for me it was just a way of trying to understand what all the the pieces of code induvidualy are made for ,and how things works.
So are the lines of code for clear sheet and clear data a hard time for me to figure out how they work.
Also there is no intension do distribute the altered Excel anyways.

So you definitively get a couple of beers when we meet in Germany.

Hi to everyone,

I have read all post but I don't find any solution for my question.

PLX-DAQ works like a charm sendig data from Arduino to Excel. Every minute I send temperature sensor to excel.

Now I am trying to read from excel a entire column data to send to an arduino and draw a pixel in a X,Y position.

For example

Column A - Time
Column B - temperature
Column C - temperature

B2= 24,33
B3=25,03
.
.
.
B40=33,21
.
.
.
B100=""

with (CELL,GET,B3) I only read B3 value. I need to read all B column data.

My project is when I push a button, the screen turns black. Then read Bx value and using this value print a pixel in position (Bx,Y) until in Column B / Row X there's no data.

Thanks in Advanced

Thanks in advanced.

Hi kobayeshi,

there is no such functionality at the moment.
For your use case I can think of three solutions:

  • You could just store the measured data locally in an array and read from that array once the button is pushed
  • You could do an endless loop and query Excel via (CELL,GET,Bx) (whereby x should be a counter), read the result and in case it is empty break the loop. That way you would go down the full column. But it might take a while for each value to get queried and responded.
  • and of course you could use the CustomDevPoint to create an own command (e.g., READFULLCOLUMN(dim letter as char) to return an array or CSV list from PLX DAQ to Arduino. Therefore you need to know some things about VBA programming language of course

I hope this helps you to get started?

Hi, kobayeshi
Why not ,just use Excel to plot a simple graph, or am I missing the point of the story?

@NetDevil:

Second Option is that I want to do. How could I do?

@GijKieken:

Yes, I have plotted a graph in excel and in real time. This was my first goal and with PLX-DAQ is a piece of cake. But my project is more complex than I have explained here.

I need at any time an operator can see a graph of the data collected by a sensor outside the offices.

Thanks a lot for all the answers.