I am trying to take data from the serial port and use Processing to save it as a CSV
import processing.serial.*;
Serial myPort;
float[] sensorData= {0, 0, 0};
void setup() {
size(1043, 152);
background(255);
myPort = new Serial(this, "COM4", 9600);
myPort.bufferUntil('\n');
}
void draw() {
fill(0);
rect(10, 2, inStr[0], 46);
rect(10, 52, inStr[1], 46);
rect(10, 102, inStr[2], 46);
fill(255);
rect(390, 14, 265, 21);
fill(0);
textAlign(CENTER);
textSize(14);
text("Temperature: " + sensorData[0] + " Humidity: " + sensorData[1] + " Moisture: " + sensorData[2], width/2, 30);
}
void serialEvent(Serial myPort) {
if (myPort.available() > 0) {
String serialData= myPort.readStringUntil('\n');
if (serialData!= null) {
serialData = trim(serialData);
sensorData = float(split(serialData, ','));
print(sensorData);
}
}
}
The data however comes once every 15 minutes. Processing continues to check for data and throws an out of bounds exception when there is no data.
How can I make it so it will only run when new data comes through the serial port?
First off, where does inStr[] come from ? Perhaps left over from prototyping/testing ? if not required, it should be deleted, otherwise changed to use an existing variable.
Because you use myPort.bufferUntil('\n') you should be able to use myPort.readString() instead of myPort.readStringUntil('\n');.
You're on the right track by checking if serialData is not null and trimming whitespace.
You might experience variable shadowing: float[] sensorData declared at the top has the same name as String serialData (serialEvent())
Additionally you can check if float(split(serialData, ',')) has the expected number of elements (e.g. if something goes wrong with serial communication and bytes are lost).
This probably won't change much, but you can choose to use 3 float variables instead of an array where you assign values from the float[] parsed from strings. e.g.
import processing.serial.*;
Serial myPort;
float temperature, humidity, moisture;
void setup() {
size(1043, 152);
textSize(14);
try{
myPort = new Serial(this, "COM4", 9600);
myPort.bufferUntil('\n');
}catch(Exception e){
println("Error opening Serial port!\nDouble check the Serial port is connected via USB, the port name is correct and the port istn't already open in Serial Monitor");
e.printStackTrace();
}
}
void draw() {
background(255);
String sensorText = String.format("Temperature: %.2f Humidity: %.2f Moisture: %.2f", temperature, humidity, moisture);
float textWidth = textWidth(sensorText);
float textX = (width - textWidth) / 2;
fill(255);
rect(textX - 10, 14, textWidth + 20, 21);
fill(0);
text(sensorText, textX, 30);
}
void serialEvent(Serial myPort) {
if (myPort.available() > 0) {
String serialDataString = myPort.readString();
if (serialDataString != null) {
serialDataString = trim(serialDataString);
float[] sensorData = float(split(serialDataString, ','));
print(sensorData);
// check if 3 values are received
if(sensorData.length == 3){
temperature = sensorData[0];
humidity = sensorData[1];
moisture = sensorData[2];
}else{
println("received <3 values");
}
}
}
}
One last think about is how many bytes are being sent.
If you have a large number of floating point digits, each will take a character (byte).
If you display only 2 floating values, you can choose to format that format that data on the Arduino side first.
Additionally you can choose pack the data as bytes instead (e.g. keep the sensor values as 0-1023 values from analogRead() which use 4 bytes each (2 16-bit words): this should result in 12 bytes for the data and 1 byte for the terminator character (\n / 10).The 0-1023 values can then be converted in Processing to floating point values.
Ideally you'd put together a basic byte based serial protocol that is more roboust (e.g. byte header with packet length, checksum, data payload), but this may not be beginner friendly. It would avoid pitfalls such as using \n as both the terminator character, but also part of the data (and Processing not knowing the difference between a a byte which should mean the value 10 from a sensor and the \n character). (Although it will a tiny bit of overhead on the Arduino side, it's worth looking into the PacketSerial Arduino library if you want to avoid making your own binary serial protocol. (In the past I've managed to use PacketSerial with SLIP encoding to parse data as easy to parse OSC messages by sacrificing a bit of Arduino RAM))
Update
Regarding CSV you can make use of Processing's Table class:
instantiate a table (and optionally its columns)
when new data arrives, make a new TableRow, populate it with the 3 values and add it to the table
when required (e.g. exiting sketch / pressing 's'), saveTable()
Here's a modified version of the above, saving in TSV (tab separated values) format, just in case there's a conflict between commas in each value and separating table values with the same text character:
import processing.serial.*;
Serial myPort;
float temperature, humidity, moisture;
// table to store sensor data into
Table sensorDataTable;
void setup() {
size(1043, 152);
textSize(14);
try{
myPort = new Serial(this, "COM4", 9600);
myPort.bufferUntil('\n');
}catch(Exception e){
println("Error opening Serial port!\nDouble check the Serial port is connected via USB, the port name is correct and the port istn't already open in Serial Monitor");
e.printStackTrace();
}
// init table
sensorDataTable = new Table();
// nice to have: table column names
sensorDataTable.addColumn("temperature");
sensorDataTable.addColumn("humidity");
sensorDataTable.addColumn("moisture");
}
void draw() {
background(255);
String sensorText = String.format("Temperature: %.2f Humidity: %.2f Moisture: %.2f", temperature, humidity, moisture);
float textWidth = textWidth(sensorText);
float textX = (width - textWidth) / 2;
fill(255);
rect(textX - 10, 14, textWidth + 20, 21);
fill(0);
text(sensorText, textX, 30);
}
void serialEvent(Serial myPort) {
if (myPort.available() > 0) {
String serialDataString = myPort.readString();
if (serialDataString != null) {
serialDataString = trim(serialDataString);
float[] sensorData = float(split(serialDataString, ','));
print(sensorData);
// check if 3 values are received
if(sensorData.length == 3){
temperature = sensorData[0];
humidity = sensorData[1];
moisture = sensorData[2];
// add data to table (using column names)
TableRow newRow = sensorDataTable.addRow();
newRow.setFloat("temperature", temperature);
newRow.setFloat("humidity" , humidity);
newRow.setFloat("moisture" , moisture);
}else{
println("received <3 values");
}
}
}
}
// save on 's'
void keyPressed(){
if(key == 's'){
// save table to disk as .TSV instead of .CSV
// potentially avoiding .CSV and float values conflicts (depending on sys.language)
saveTable(sensorDataTable, "data/sensorData.tsv");
}
}
// save on exit
void exit(){
saveTable(sensorDataTable, "data/sensorData.tsv");
super.exit();
}
Related
I am trying to run this Processing code taken from this website to create a wavelength meter.
/***************************************************************************
Created by dbc0301
***************************************************************************/
import processing.serial.*;
Serial port;
PFont myFont;
int tmp;
//int begin='$';//begin
int end='\r';//end
char rev[] = new char[15];//datas
int revFlag=0;
int[] data=new int[10];//F1,F2,F3,F4,F5,F6,F7,F8,Clear,NIR
//int F1,F2,F3,F4,F5,F6,F7,F8,Clear,NIR;
//Stimulus Function
float[] Fx={0.07763, 0.34806, 0.09564, 0.02910, 0.51205, 1.02630, 0.64240, 0.04677};
float[] Fy={0.00218, 0.02980, 0.13902, 0.60820, 1.00000, 0.75700, 0.26500, 0.01700};
float[] Fz={0.37130, 1.78260, 0.81295, 0.11170, 0.00575, 0.00110, 0.00005, 0.00000};
int textHight=25;
float rt=1;//Length scaling
void receiveDatas(){
for(int i=0;port.available()>0;i++){
tmp=port.read();
if(tmp!=end){
rev=char(tmp);
}else{
rev=char(tmp);
revFlag=1;
tmp=port.read();
break;
}
}
}
void setup(){
//size(1074,241);
size(1250,301);
background(0);//white255 black0
noStroke();
myFont = createFont("Microsoft YaHei", 20);
textFont(myFont);
println(Serial.list()[0]);
port = new Serial(this,Serial.list()[0],115200);
}
void draw(){
receiveDatas();
if(revFlag==1){
String[] m=match(new String(rev), "(.*?):(.*?)\r");//Regular Expression Matching
//printArray(m);
try{
if(m[1].equals("F1")){
data[0]=int(m[2]);
}else if(m[1].equals("F2")){
data[1]=int(m[2]);
}else if(m[1].equals("F3")){
data[2]=int(m[2]);
}else if(m[1].equals("F4")){
data[3]=int(m[2]);
}else if(m[1].equals("F5")){
data[4]=int(m[2]);
}else if(m[1].equals("F6")){
data[5]=int(m[2]);
}else if(m[1].equals("F7")){
data[6]=int(m[2]);
}else if(m[1].equals("F8")){
data[7]=int(m[2]);
}else if(m[1].equals("Clear")){
data[8]=int(m[2]);
}else if(m[1].equals("NIR")){
data[9]=int(m[2]);
}else{
print("Wrong datas!");
}
}catch(NullPointerException e){
println(rev);
printArray(m);
}finally{}
revFlag=0;
//printArray(data);
//delay(10);
}
/*Display*/
//rectMode(CORNER);
background(0);
textSize(20);
fill(#8b3dc5);
rect(0,0,data[0]*rt,30);//F1
text(data[0], data[0]*rt, 0+textHight);//textHeight: veritcal height of text
fill(#00528e);
rect(0,30,data[1]*rt,30);//F2
text(data[1], data[1]*rt, 30+textHight);
fill(#00b1ed);
rect(0,60,data[2]*rt,30);//F3
text(data[2], data[2]*rt, 60+textHight);
fill(#01ffcd);
rect(0,90,data[3]*rt,30);//F4
text(data[3], data[3]*rt, 90+textHight);
fill(#00af50);
rect(0,120,data[4]*rt,30);//F5
text(data[4], data[4]*rt, 120+textHight);
fill(#ffff01);
rect(0,150,data[5]*rt,30);//F6
text(data[5], data[5]*rt, 150+textHight);
fill(#ffc000);
rect(0,180,data[6]*rt,30);//F7
text(data[6], data[6]*rt, 180+textHight);
fill(#c10005);
rect(0,210,data[7]*rt,30);//F8
text(data[7], data[7]*rt, 210+textHight);
fill(#ffffff);
rect(0,240,data[8]*rt,30);//Clear
text(data[8], data[8]*rt, 240+textHight);
fill(#888888);
rect(0,270,data[9]*rt,30);//F8
text(data[9], data[9]*rt, 270+textHight);
//delay(1);
/*Color Temperaure*/
float X,Y,Z,x,y,n,temp;
X=(data[0]*Fx[0] + data[1]*Fx[1] + data[2]*Fx[2] + data[3]*Fx[3] + data[4]*Fx[4] + data[5]*Fx[5] + data[6]*Fx[6] + data[7]*Fx[7]);//20/1000;//20 is the interval of integration. 1000 is used to converted the value into a real number between 0~1
Y=(data[0]*Fy[0] + data[1]*Fy[1] + data[2]*Fy[2] + data[3]*Fy[3] + data[4]*Fy[4] + data[5]*Fy[5] + data[6]*Fy[6] + data[7]*Fy[7]);//20/1000;//But it is meaningless to multiply this number here since it will be reduced in the next step
Z=(data[0]*Fz[0] + data[1]*Fz[1] + data[2]*Fz[2] + data[3]*Fz[3] + data[4]*Fz[4] + data[5]*Fz[5] + data[6]*Fz[6] + data[7]*Fz[7]);//20/1000;
x=X/(X+Y+Z);
y=Y/(X+Y+Z);
n=(x-0.3320)/(0.1858-y);
temp=437*n*n*n+3601*n*n+6831*n+5517;
print(temp);
println("K\n");
}
It is giving me this error on line 24 and 26:
Type mismatch, “char” does not match with “char[]”
The problem is that rev is an array. If you want to put tmp in rev, do something like rev[0] = char(tmp). I don't understand well your code, but if you want every letter you press to be added to tmp, you could make a variable to take count of how much letters were pressed, and do rev[typed] = char(tmp) where typed is the variable in question. Also, this code will probably confuse most of the community, go to discourse.processing.org to ask Processing questions. Hope i could help, though!
I have a project where I have data come in via the serial port every 15 minutes. I am using processing to read this data and save it as a CSV.
I would like for a new file to be created every 12 hours. However, when the file switches from AM to PM the entire row gets saved in the PM file (all the previous AM values)
How can I reset the table and start saving to a new file?
saveTable(dataTable, fileName());
dataTable.clearRows();
I tried this but it just clears the CSV file.
String fileName() {
String fileName = "";
String month = "";
String day = "";
int m = month();
int d = day();
if (d < 10) {
day = str(d);
day = "-0" + day;
} else {
day = "-" + str(d);
}
switch(m) {
case 1:
month = "-JAN";
break;
case 2:
month = "-FEB";
break;
case 3:
month = "-MAR";
break;
case 4:
month = "-APR";
break;
case 5:
month = "-MAY";
break;
case 6:
month = "-JUN";
break;
case 7:
month = "-JUL";
break;
case 8:
month = "-AUG";
break;
case 9:
month = "-SEP";
break;
case 10:
month = "-OCT";
break;
case 11:
month = "-NOV";
break;
case 12:
month = "-DEC";
break;
}
if (hour() >= 12) {
hour = "-PM";
} else {
hour = "-AM";
}
fileName = "SensorData_" + str(year()) + month + day + hour + ".csv";
return fileName;
}
Update: Code for collecting and saving data
void serialEvent(Serial myPort) {
if (myPort.available() > 0) {
String serialDataString = myPort.readString();
if (serialDataString != null) {
serialDataString = trim(serialDataString);
float[] sensorData = float(split(serialDataString, ','));
TableRow newRow = dataTable.addRow();
if (sensorData.length == 4) {
temperature = sensorData[0];
humidity = sensorData[1];
moisture = sensorData[2];
int packet = int(sensorData[3]);
if (packet < 10) {
packets = "00" + str(packet);
} else if (packet < 100) {
packets = "0" + str(packet);
}
String time = str(hour()) + ":" + str(minute()) + ":" + str(second());
String date = str(month()) + "/" + str(day());
newRow.setFloat("Temperature", temperature);
newRow.setFloat("Humidity", humidity);
newRow.setFloat("Moisture", moisture);
newRow.setString("Time", time);
newRow.setString("Date", date);
}
saveTable(dataTable, fileName());
}
}
}
In comments you've mentioned
Clearing after a save does not work as expected,
To clarify, what I meant is, if you call clearRows(), previous data will be erased. Saving before clearRows() should save previous data only, saving after clearRows() should only save current data.
I wrote a basic sketch and to me it looks that this works as expected:
void setup() {
// make new table, add 3 cols
Table dataTable = new Table();
dataTable.addColumn();
dataTable.addColumn();
dataTable.addColumn();
// add 1, 2, 3
TableRow newRow = dataTable.addRow();
newRow.setInt(0, 1);
newRow.setInt(1, 2);
newRow.setInt(2, 3);
// save to disk (expecting 1, 2, 3)
saveTable(dataTable,"test1.csv");
// print (expecting 1, 2, 3)
dataTable.print();
// completely clear table
dataTable.clearRows();
// add 4, 5, 6
newRow = dataTable.addRow();
newRow.setInt(0, 4);
newRow.setInt(1, 5);
newRow.setInt(2, 6);
// save again (expecting 4, 5, 6)
saveTable(dataTable,"test2.csv");
// print (expecting, 4, 5, 6)
dataTable.print();
}
(It's also nice that saveTable() appends data (and doesn't overwrite data) in this case.)
This is how I understand how/when data flows in your setup:
Arduino sends data over serial every 15 minutes. You haven't specified if the Arduino has a real time clock (RTC) and the code there uses it to only output data every 15 minutes on the clock (e.g. at :00, :15, :30, :45 past the hour, every hour). The assumption is there is no realtime clock and you're either using delay() or millis() so the actual time data gets sent out is relative to when the Arduino was powered.
When Processing sketch starts, it reads this serial data (meaning any prior data is loest). The assumption is there is no time sync between Arduino and Processing. The first row of data from Arduino comes at Arduino's next 15 minute (not Processing's) after the sketch was started.
The issue you might be experiencing based on your short snippet,
saveTable(dataTable, fileName());
dataTable.clearRows();
if it gets called in serialEvent() is that you'll loose data.
(Confusingly, it doesn't like you're calling clearRows() from serialEvent() ?)
One idea I can think is having some sort of event when the switch from AM/PM to then (first save any accumated data with the previous filename), then clear the the table and update the filename, otherwise (in serial event, save the data with the same filename).
A hacky approach is, once the AM/PM suffixed timestamp is generated to check if this suffix changes and only update filename/clear rows when this change occurs (e.g. manually "debouncing").
Here's a rough sketch to illustrate the idea:
Serial myPort;
float temperature, humidity, moisture;
Table dataTable = new Table();
String packets;
int packet;
boolean isAM,wasAM;
String tableFileName;
public void setup() {
textSize(14);
try{
myPort = new Serial(this, "COM4", 9600);
myPort.bufferUntil('\n');
}catch(Exception e){
println("Error opening Serial port!\nDouble check the Serial port is connected via USB, the port name is correct and the port istn't already open in Serial Monitor");
e.printStackTrace();
}
tableFileName = "SensorData_" + getDateStampString() + ".csv";
}
public void draw() {
background(255);
String sensorText = String.format("Temperature: %.2f Humidity: %.2f Moisture: %.2f", temperature, humidity, moisture);
float textWidth = textWidth(sensorText);
float textX = (width - textWidth) / 2;
fill(255);
rect(textX - 10, 14, textWidth + 20, 21);
fill(0);
text(sensorText, textX, 30);
// get an update date string
String dateStamp = getDateStampString();
// check AM/PM switch and update
isAM = dateStamp.endsWith("AM");
if(!wasAM && isAM){
println("changed PM to AM");
updateTableAMPM(dateStamp);
// update previous state for debouncing
wasAM = true;
}
if(wasAM && !isAM){
println("changed AM to PM");
updateTableAMPM(dateStamp);
wasAM = true;
}
}
public void updateTableAMPM(String dateStamp){
// saves current table (old filename): we're vaing data before the AM/PM switch
saveDataTable();
// clear rows so next 12 cycle starts fresh
dataTable.clearRows();
// update filename (for next save (serialEvent) to use)
tableFileName = "SensorData_" + dateStamp + ".csv";
}
public String getDateStampString(){
return new SimpleDateFormat("yyyy-MMM-dd-aa").format(new Date());
}
public void saveDataTable(){
saveTable(dataTable, tableFileName);
println("saved",tableFileName);
}
public void serialEvent(Serial myPort) {
if (myPort.available() > 0) {
String serialDataString = myPort.readString();
if (serialDataString != null) {
serialDataString = trim(serialDataString);
float[] sensorData = PApplet.parseFloat(split(serialDataString, ','));
TableRow newRow = dataTable.addRow();
if (sensorData.length == 4) {
temperature = sensorData[0];
humidity = sensorData[1];
moisture = sensorData[2];
int packet = PApplet.parseInt(sensorData[3]);
if (packet < 10) {
packets = "00" + str(packet);
} else if (packet < 100) {
packets = "0" + str(packet);
}
String time = str(hour()) + ":" + str(minute()) + ":" + str(second());
String date = str(month()) + "/" + str(day());
newRow.setFloat("Temperature", temperature);
newRow.setFloat("Humidity", humidity);
newRow.setFloat("Moisture", moisture);
newRow.setString("Time", time);
newRow.setString("Date", date);
}
// save data, but don't change the filename
saveDataTable();
}
}
}
Note the above isn't tested (so might contain errors), but hopefully it illustrates the ideas aforementioned.
(One minor note on packets (which I'm unsure where it's used): you can use nf() to easily pad a number with zeros (There are similar functions like nfc(), nfp(), nfs())).
Another option (similar to what I've mentioned in comments) is to use java utilities to call a function after a set time (e.g. the difference in time since the start of the sketch until either noon or midnight, whichever comes first), to then repeat at 12 hour intervals. You can check out TimerTask, or if your familiar with setTimeout in JS you can try this Thread based WIP setTimeout Processing workaround.
so I am new to Processing and basically I am doing a program that when it runs, it opens a window with 4 different images, each of the image have description underneath. In the methods below, I created two random methods, one for the reviews number and the other for the review comments, I would like the comments to not be generated all the time for every film - more like popping up randomly, because it cause too much chaos trying to read them all. Also to check weather I can add arrays together of string and integer for the average value of the review number.
Below is the code, would appreciate your help. thanks.
import g4p_controls.*;
import ddf.minim.*;
PFont font;
PImage img1,img2; // background images for two different windows
PImage fimg1, fimg2, fimg3, fimg4, fimg5, fimg6; //images of movies
int rectX,rectY;
GButton btn;
GWindow window;
Minim minim;
AudioPlayer player;
String[] rev_film1 = {"The Best Wolverine Movie","Logan is another level","Disappointment","Such a sad farewell"}; //Logan
String[] rev_film2 = {"A scary movie that isn't scary.","Terrifyingly brilliant.","The perfect blend of comedy and horror","The IT Factor"}; //IT
String[] rev_film3 = {"Soul-less,Confused,Loud.","Devastatingly Disappointed","A technical masterpiece","A visual wonder that lacks depth"}; //Dunkirk
String[] rev_film4 = {"Disgrace", "Worst Star Wars movie", "TERRIBLE","A Betrayal to the Legacy"}; //Starwars
int[] rat_film1 = {9,8,2,2};
float r;
void setup()
{
size(1150,600,JAVA2D);
surface.setTitle(" - The Theatre of Dreams Database - ");
font = loadFont("BerlinSansFB-Reg-48.vlw");
img1 = loadImage("film2.jpg");
background(img1);
btn = new GButton(this,900,350,100,50, "Enter Website");
minim = new Minim(this);
player = minim.loadFile("sound.mp3");
player.play();
}
void draw()
{
fill(255);
textFont(font,32);
text("Welcome to", 850, 85);
text("The Theatre of Dreams", 760, 175);
text("Database", 870, 220);
}
void handleButtonEvents(GButton button, GEvent event)
{
if (button == btn && event == GEvent.CLICKED)
{
createWindow();
btn.setEnabled(false);
}
}
void createWindow() // creating new window with mouse click
{
window = GWindow.getWindow(this, " - Top 4 Movies in 2017 - ", 100, 50, 1150, 600, JAVA2D);
window.addDrawHandler(this, "windowDraw");
window.addOnCloseHandler(this, "windowClosing");
window.setActionOnClose(GWindow.CLOSE_WINDOW);
}
void windowDraw(PApplet app, GWinData data)
{
img2 = loadImage("film3.jpg");
app.background(img2);
app.text(" - Top 4 Movies in 2017 - ",440,85);
app.fill(255);
app.textFont(font,25);
fimg1 = loadImage("logan.jpg");
fimg2 = loadImage("it.jpg");
fimg3 = loadImage("dunkirk.jpg");
fimg4 = loadImage("starwars.jpg");
//////////Film 1 - LOGAN
app.image(fimg1,5,140,180,170);
app.text("Rating: 8.1 / 10",5,340); //fixed rating
app.text("Genres: Action | Drama", 5, 365);
app.text("| Sci-Fi | Thriller",5,390);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(0, 6);
}
String user = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user, 5,430);
// the random function of the comments
int index = int(random(rev_film1.length));
String user11 = "Reviews: " + "\n" + rev_film1[index];
app.text(user11, 5,460);
////////////////////Film 2 - IT
app.image(fimg2,960,360,180,170);
app.text("Rating: 7.6 / 10", 700,400);
app.text("Genres: Drama | Horror",700,430);
app.text("| Thriller",700,460);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(5, 10);
}
String user2 = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user2, 700,500);
int index2 = int(random(rev_film2.length)); // the random function of the comments
String user22 = "Reviews: " + "\n" + rev_film2[index2];
app.text(user22, 700,540);
/////////Film 3 - DUNKIRK
app.image(fimg3,320,250,180,170);
app.text("Rating: 8.1 / 10",320,445); //fixed rating
app.text("Genres: Action | Drama", 320, 470);
app.text("| History | Thriller | War",320,495);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(0, 5);
}
String user3 = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user3, 320,530);
int index3 = int(random(rev_film3.length)); // the random function of the comments
String user33 = "Reviews: " + "\n" + rev_film3[index3];
app.text(user33, 320,560);
/////////////Film 4 - STAR WARS
app.image(fimg4,570,120,180,170);
app.text("Rating: 7.6 / 10", 760,140); //fixed rating
app.text("Genres: Action | Adventure | Fantasy ", 760,168);
app.text("| Sci-Fi", 760,195);
//Ratings that are constantly changing using the random function
for (int i = 0; i < 50; i++)
{
r = random(0, 2);
}
String user4 = "Ratings by users: " + nf(r,0,1) + " / 10";
app.text(user4, 760,220);
int index4 = int(random(rev_film4.length)); // the random function of the comments
String user44 = "Reviews: " + "\n" + rev_film4[index4];
app.text(user44, 760,250);
}
public void windowClosing(GWindow w)
{
btn.setEnabled(false);
player.close();
minim.stop();
exit();
}
Please try to post a MCVE instead of your full program. For example, try creating a simple sketch that shows a circle every X seconds. That way we can focus on your problem instead of all the extra stuff that has nothing to do with your question.
But to answer your question, you can use the millis() function or the frameCount variable to check how much time has gone by, then do something every X seconds or every X frames.
Related posts:
How to make a delay in processing project?
How can I draw only every x frames?
Removing element from ArrayList every 500 frames
Timing based events in Processing
How to add +1 to variable every 10 seconds in Processing?
How to create something happen when time = x
making a “poke back” program in processing
Processing: How do i create an object every “x” time
Timer using frameRate and frame counter reliable?
Please also consult the Processing reference for more information.
If you still can't get it working, please post a MCVE (not your full project!) in a new question and we'll go from there. Good luck.
step by step what I did so far
1) micro controller used CC3200 from Texas instruments ( wifi builted micro controller)
2) Conductive rubber cord stretch sensor - connected to Microcontroller's analog pin
**Sensor's behaviour = ( resistance increases upon stretching the conductive rubber)
So now, following is the code fo reference which I debugged in to the microcontroller to run the sensor(Using energia tool-IDE).
The code is nothing but written for the web server( which I gave- available wifi ssid and password-which you can see in the following programm "iPhone and the passowrd"), where the sensor's code is also wrote in to,
And this webserver reads and generates IP address of the microcontroller and also values of the stretch sensor.
Webserver code :
#include <SPI.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
// which analog pin to connect
#define RUBBERPIN A3
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// the value of the 'other' resistor
#define SERIESRESISTOR 10000
int samples[NUMSAMPLES];
// your network name also called SSID
char ssid[] = "iPhone";
// your network password
char password[] = "123456789";
// your network key Index number (needed only for WEP)
int keyIndex = 0;
WiFiServer server(3000);
void setup() {
Serial.begin(115200); // initialize serial communication
analogReference(EXTERNAL);
pinMode(RED_LED, OUTPUT); // set the LED pin mode
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to Network named: ");
// print the network name (SSID);
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP
network:
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED) {
// print dots while we wait to connect
Serial.print(".");
delay(300);
}
Serial.println("\nYou're connected to the network");
Serial.println("Waiting for an ip address");
while (WiFi.localIP() == INADDR_NONE) {
// print dots while we wait for an ip addresss
Serial.print(".");
delay(300);
}
// you're connected now, so print out the status
printWifiStatus();
Serial.println("Starting dataerver on port 3000");
server.begin(); // start the web server on port
80
Serial.println("Dataserver started!");
}
void loop() {
// listen for incoming clients
WiFiClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
uint8_t i;
float average;
// take N samples in a row, with a slight delay
for (i=0; i< NUMSAMPLES; i++) {
samples[i] = analogRead(RUBBERPIN);
delay(10);
}
// average all the samples out
average = 0;
for (i=0; i< NUMSAMPLES; i++) {
average += samples[i];
}
average /= NUMSAMPLES;
Serial.println(average);
client.println(average);
delay(10);
}
delay(1);
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("Network Name: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
After running this programm it generates IP address and sensor's values(
221.40
221.20
221.20
*********here = value missing were a noise is visible on graph
221.00
221.20
221.40
221.00
221.20
221.40
221.00
221.40
221.20
221.40
221.20
221.00
221.00
221.60
221.00
221.20
*********here = value missing were a noise is visible on graph
221.20
221.00
Now,
I wrote the generated IP address in to a client programm (In the tool- named processing.org )
Here is my client code
import processing.net.*;
Client c;
String input;
int data[];
int posx;
void setup()
{
size(1000, 500);
background(204);
stroke(0);
frameRate(5); // Slow it down a little
// Connect to the server's IP address and port
c = new Client(this, "192.168.23.2", 3000); // Replace with your server's IP
and port
posx =2;
data = new int[3];
}
void draw()
{
posx++;
// Receive data from server
if (c.available() > 0) {
input = c.readString();
input = input.substring(0, input.indexOf("\n")); // Only up to the newline
println(input);
data[0]=data[1];
data[1] = int(input); // Split values into an array
// Draw line using received coords
stroke(0);
line(posx-1, data[0]+10, posx, data[1]+10);
}
}
My results after running the following programm:
Server sending the data and client receiving the data wirelessly- its all fine
I am able to see the output signal which I am expecting. i.e., when my sensor is in rest position the output must be straight line and if I stretch my sensor the voltage signal must increase- Iam able to see all these. But,
here is a small problem
There is a noise coming out from the output signal (please have a look in to the following picture.)
Noise
So my problem is even when the sensor is in rest position- with out any stretch- there is peak coming out.
please help me
I am new in MQL5 and I am trying to capture the values of Open, High, Low and Close of each new candle.
For now I am using a one minute TimeFRAME for each candle.
I read the documentation and have not figured out how can I do it.
My only clue was the CopyOpen() functions, but I am still stuck.
Let's split the task:
How to read OHLC-values?
How to detect (each) new candle?
A1: MQL4/MQL5 syntax reports OHLCV-values straight in Open[], High[], Low[], Close[], Volume[] time-series arrays. As a rule of thumb, these arrays are time-series, reverse-stepping indexed, so that the most recent cell ( The Current Bar ( candle ) ) always has cell-index == 0. So Open[1], High[1], Low[1], Close[1] are values for the "current instrument" ( _Symbol ), retrieved from the "current TimeFRAME" for a candle, that was already closed right before the "current Candle" has started. Complex? Well, just on the first few reads. You will get acquainted with this.
If your code does not want to rely on "current" implicit contexts, the syntax allows one to use explicit, indirect, specifications:
/* iVolume( ||| ... )
iTime( ||| ... )
iClose( ||| ... )
iLow( ||| ... )
iHigh( vvv ... ) */
iOpen( aTradingSymbolNameSTRING, // Broker specific names, "DE-30.." may surprise
PERIOD_M1, // explicit reference to use M1 TimeFRAME
1 // a Cell-index [1] last, closed Candle
)
A2: There is neat way how to detect a new Candle, indirectly, the same trick allows one to thus detect a moment, when the previous Candle stops evolving ( values do not change anymore ) which thus makes sense to report "already frozen" OHLCV-values to be reported anywhere else.
Remeber, the "current" OHLCV-registers-[0] are always "hot" == continuously changing throughout the time of the "current" TimeFRAME Candle duration, so one has to wait till a new Candle starts ( indirectly meaning the "now-previous" Candle [0] has ended and has thus got a reverse-stepping index "re-indexed" to become [1], a frozen one ).
For detecting a new candle it is enough to monitor changes of a system register int Bars, resp. an indirect, context aware, int iBars( ... ).
One may realise, that there are some "theoretical" Candles, that do not happen and are thus not "visible" / "accessible" in data of time-series -- whence a market was not active during such period of time and no PriceDOMAIN change has happened during such administratively-framed epoch in time -- for such situations, as there was no price-change, there was no QUOTE and thus such candle did not happen and is "missing" both in linear counting and in data-cells. The first next QUOTE arrival is thus painted right "besides" a candle, that was principally "older" than a "previous"-neighbour ( the missing candles are not depicted, so due care ought be taken in processing ). This typically happens even on major instruments near the Friday EoB/EoWk market closing times and around midnights UTC +0000 during the 24/5-cycles.
In case you become too frustrated, here is a script that will export selected chart contents the second a new candle appears. Just choose the pair you want and attach this to the chart and you will get exported a .csv file on each new candle.
//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>
//+------------------------------------------------------------------+
//| Input Parameters Definition |
//+------------------------------------------------------------------+
extern int BarCount = 500;
extern string Pairs = "EURAUD,EURCAD,EURCHF,EURGBP,EURNZD,EURUSD,EURJPY,AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDUSD,GBPAUD,GBPCAD,GBPCHF,GBPJPY,GBPNZD,GBPUSD,CADCHF,CADJPY,USDCAD,USDCHF,USDJPY,NZDCAD,NZDCHF,NZDJPY,NZDUSD,CHFJPY";
extern string delimiter = ",";
//+------------------------------------------------------------------+
//| Local Parameters Definition |
//+------------------------------------------------------------------+
datetime lastExport[];
string pairs[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//------------------------------------------------------------------
Split(Pairs, pairs, ",");
//------------------------------------------------------------------
if (ArraySize(pairs) == 0 || StringTrimLeft(StringTrimRight(pairs[0])) == "")
{
Alert("Pairs are not entered correctly please check it...");
return (0);
}
//------------------------------------------------------------------
ArrayResize(lastExport, ArraySize(pairs));
ArrayInitialize(lastExport, 0);
//------------------------------------------------------------------
Comment("quote exporter is active :)");
//------------------------------------------------------------------
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//------------------------------------------------------------------
Comment("");
//------------------------------------------------------------------
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
//------------------------------------------------------------------
if (ArraySize(pairs) == 0 || StringTrimLeft(StringTrimRight(pairs[0])) == "") return (0);
//------------------------------------------------------------------
BarCount = MathMin(Bars, BarCount);
//------------------------------------------------------------------
for (int j = 0; j < ArraySize(pairs); j++)
{
if (lastExport[j] == Time[0]) continue;
lastExport[j] = Time[0];
if (StringTrimLeft(StringTrimRight(pairs[j])) == "") continue;
if (MarketInfo(pairs[j], MODE_BID) == 0) { Alert("symbol " + pairs[j] + " is not loaded!!!"); continue; }
//------------------------------------------------------------------
string file = pairs[j] + "_" + GetTimeFrameName(0) + ".csv";
int log = FileOpen(file, FILE_CSV|FILE_WRITE, "~");
if (log < 0) { Alert("can not create/overwrite csv file " + file + "!!!"); continue; }
string buffer;
buffer = "Date"+delimiter+"Time"+delimiter+"Open"+delimiter+"High"+delimiter+"Low"+delimiter+"Close"+delimiter+"Volume";
FileWrite(log, buffer);
int digits = MarketInfo(pairs[j], MODE_DIGITS);
for (int i = BarCount; i >= 1; i--)
{
buffer = TimeToStr(Time[i], TIME_DATE)+delimiter+TimeToStr(Time[i], TIME_MINUTES)+delimiter+DoubleToStr(iOpen(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iHigh(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iLow(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iClose(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iVolume(pairs[j], 0, i), 0);
FileWrite(log, buffer);
}
buffer = "0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0";
FileWrite(log, buffer);
FileClose(log);
}
//------------------------------------------------------------------
return(0);
}
//+------------------------------------------------------------------+
string GetTimeFrameName(int TimeFrame)
{
switch (TimeFrame)
{
case PERIOD_M1: return("M1");
case PERIOD_M5: return("M5");
case PERIOD_M15: return("M15");
case PERIOD_M30: return("M30");
case PERIOD_H1: return("H1");
case PERIOD_H4: return("H4");
case PERIOD_D1: return("D1");
case PERIOD_W1: return("W1");
case PERIOD_MN1: return("MN1");
case 0: return(GetTimeFrameName(Period()));
}
}
//+------------------------------------------------------------------+
void Split(string buffer, string &splitted[], string separator)
{
string value = "";
int index = 0;
ArrayResize(splitted, 0);
if (StringSubstr(buffer, StringLen(buffer) - 1) != separator) buffer = buffer + separator;
for (int i = 0; i < StringLen(buffer); i++)
if (StringSubstr(buffer, i, 1) == separator)
{
ArrayResize(splitted, index + 1);
splitted[index] = value;
index ++;
value = "";
}
else
value = value + StringSubstr(buffer, i, 1);
}
//+------------------------------------------------------------------+