Всем КУ. Мой первый пост, прошу не судить строго.

Возникла по работе необходимость считывать визуально состояние оборудования и, при необходимости, производить перезапуск криокомпрессора удаленно. Под рукой была Arduino UNO, к ней приобретены датчик освещенности, пока что 2 реле и 2 соленоида на 12 В(не суть важно). В дальнейшем то дело обрастет датчиками температуры, влажности и давления, но пока того нет в готовом виде.

Причина написания поста — это то, что в интернете нашлось очень мало информации по возможностям Processing 3, особенно в русскоязычной его части. Надеюсь, что таким же чайникам, как я, то когда-то пригодится, чтобы не тупить как я последнюю неделю.

Скетч для Ардуино простой, как три рубля: при получении определенных значений из ком порта дунька устанавливает значение на пинах и пишет об том ответ в ком порт, а так же замеряет освещенность и, так же, отчитывается об том. В дальнейшем он будет расширен.

Скетч Ардуино:

#include <Wire.h>
#include <BH1750.h>
int val;
BH1750 lightMeter;

void setup() {
  Serial.begin(9600);
  lightMeter.begin();
  Serial.println("Running...");
  pinMode (7, OUTPUT);
  pinMode(6, OUTPUT);
  digitalWrite(7, HIGH);
  digitalWrite(6, HIGH);
}
void loop() {
  uint16_t lux = lightMeter.readLightLevel();
   if (Serial.available()) {
    val = Serial.read();
    if (val == '0') {
      digitalWrite(7, HIGH);
      digitalWrite(6, HIGH);
      Serial.println("Оба реле ВЫКЛЮЧЕНЫ");
    }
    if (val == '1') {
      digitalWrite(7, HIGH);
      digitalWrite(6, LOW);
      Serial.println("Реле 1 включено");
    }
    if (val == '2') {
      digitalWrite(7, LOW);
      digitalWrite(6, HIGH);
      Serial.println("Включено реле 2");
    }
    if (val == '3') {
      digitalWrite(7, LOW);
      digitalWrite(6, LOW);
      Serial.println("ВКЛЮЧЕНЫ оба реле");
    }
    if (val == '4') {                                                
      if (lux >= 800) {                                           
        Serial.print("Light: ");                                
        Serial.print(lux);                                        
        Serial.println(" lx  Все отлично ");            
      }                                                                  
      else {                                                          
        Serial.print("Light: ");                                
        Serial.print(lux);                                        
        Serial.println(" lx    Мне ТЕМНО!!!!!!!");   
      }                                                                 
    }                                                                   
  }
 }

Это, думаю, и ежу понятно, но в связи с тем, что функционалом моей приблуды в дальнейшем будут пользоваться другие люди, то захотелось написать простенькое, но понятное GUI. Выбор пал на Processing, так как я был ранее знаком с Arduino IDE, которая, в свою очередь, построена на основе Processing.

В апплете использована библиотека ControlP5 для отрисовки элементов управления.

Лично для меня возникли проблемы с реализацией и поиском информации относительно следующих вещей — 1) запуск второго окна из приложения, 2) закрывание 2-го окна, но чтобы при том основное окно продолжало работать, 3) ради прикола — установка картинок в качестве фона и кнопок, полупрозрачность кнопок.

Итак, скетч Processing:

Листинг кода
import processing.serial.*;
import controlP5.*;
import java.util.Date;

Serial port;
Textfield recived;
Textfield recived1;
Textfield recived2;
Textfield recived3;
Textfield recived4;
Textfield recived5;
String val;
String data;
String DateTab;
String Dat;
int data2=0;
String time;
Button vyvod;
PrintWriter output;                                                    
Table table2;
int i=0;
ControlP5 cp5;
ControlP5 ax;
PFont font;
PFont font2;
String[] args = {"YourSketchNameHere"};
SecondApplet sa; 
PImage fon;
PImage fon2;
PImage titlebaricon;     // Объявление переменных и классов

void setup() {
  titlebaricon = loadImage("data/myicon.png");
  surface.setIcon(titlebaricon);
  surface.setTitle("Контроль МРТ"); //Установил свою иконку и название приложения))) 
  printArray(Serial.list());
  port = new Serial(this, "/dev/ttyUSB0", 9600); //инициализирую com порт (под Ubuntu, для Windows указываем //com port)
  cp5 = new ControlP5(this);
  font = createFont("Arial", 20);  //устанавливаю шрифт  
  fon = loadImage("data/phil.bmp");  //моя картинка в качестве фона
  fon2 = loadImage("data/fon2.bmp"); /* размер картинки должен соответствовать размерам окна из void settings()*/
              PImage img;
             img = loadImage("data/image1.bmp");     //кнопки - собранные мной в папку "data" рисунки
             image(img, 0, 0);
             tint(0, 255, 0, 126);   //Прозрачность кнопки - 50% и окрашивает в зеленый цвет
             image(img, 50, 0);                       
             
              PImage img2;
             img2 = loadImage("data/image2.bmp");
             image(img2, 0, 0);
             image(img2, 50, 0);  //делаю то же для всех моих кнопок
                                              //только tint() должна вызываться один раз в моем примере.
              PImage img3;         // цвет и прозрачность всех кнопок будет одинакова.
             img3 = loadImage("data/image3.bmp");
             image(img3, 0, 0);
             image(img3, 50, 0);
             
              PImage img4;
             img4 = loadImage("data/image4.bmp");
             image(img4, 0, 0);
             image(img4, 50, 0);
             
              PImage img5;
             img5 = loadImage("data/imagezapros.bmp");
             image(img5, 0, 0);
             image(img5, 50, 0);
             
              PImage img6;
             img6 = loadImage("data/temper.bmp");
             image(img6, 0, 0);
             image(img6, 50, 0);              
             
   cp5.addButton("Relay_1")
    .setSize (100, 50)
    .setPosition(50, 50)
    .setFont(font)
    .setImage(img)
    .setLabel("Реле 1");
           
   cp5.addButton("Relay_2")
    .setSize (100, 50)
    .setPosition(250, 50)
    .setFont(font)
    .setImage(img2)
    .setLabel("Реле 2");
        
   cp5.addButton("Relay_ON")
    .setSize (300, 50)
    .setPosition(50, 120)
    .setFont(font)
    .setLabel("Реле ВКЛ")
    .setImage(img3);
        
   cp5.addButton("Relay_OFF")
    .setSize (300, 50)
    .setPosition(50, 190)
    .setFont(font)
    .setLabel("Реле ВЫКЛ")
    .setImage(img4);
    
   cp5.addButton("Zapros_sostoyaniya")
    .setSize (300, 50)
    .setPosition(50, 260)
    .setFont(font)
    .setLabel("Запрос состояния")
    .setImage(img5);
   
   recived=cp5.addTextfield(" ")
    .setSize(380,100)
    .setPosition(10, 340)
    .setColorValueLabel(0)
    .setFont(font)
    .setColorBackground(color(255, 255, 255));
    
  cp5.addButton("temps")
    .setSize (380, 50)
    .setPosition(10, 500)
    .setColorBackground(color(70, 100, 0))
    .setColorForeground(color(0, 0, 0))
    .setFont(font)
    .setLabel("Температура")
    .setImage(img6);
  }
 
void settings(){
  size(400, 560);
}

void draw() {
 background(fon);
 fill(0, 0, 0);
 textFont(font);
 text("Контроль МРТ", 135, 30);
    int s = second();
    int m = minute();
    int h = hour();
    int d = day();
    int mo = month();
    int y = year();
    DateTab = str(d)+ "." + str(mo) + "." +  str(y) + (" ") +  str(h) + (":") + str(m) + (":") + str(s);
    
  if ( port.available() > 0){
    val = port.readString();
    if(data2==0){                  // до сих пор все должно быть понятно - обрабатываю события кнопок, 
    recived.setText(val);      // пишу-читаю com порт, сохраняю дату-время и значение датчика.
 }                                         /* data2 - переменная, чтобы считанные в Second Applet показания не отображались   в textfield основного окна программы. */
  }  
 sa = new SecondApplet();
}

void Relay_1(){
   port.write("1");
}   

void Relay_2(){
  port.write("2");
}  

void Relay_ON(){
  port.write("3");
}  

void Relay_OFF(){
  port.write("0");
}  

void Zapros_sostoyaniya(){
  data2=0;
  port.write("4");
}  
 
void save123(){            // Веду журнал в виде электронной таблицы
   data2=1;
    port.write("4");
        delay(600);
        port.available();
        Dat=DateTab + "      " + val;
          table2 = loadTable("data/Journaltemp.ods");  // открываю файл
          table2.setString(0, 0, "t"); //устанавливаю некое значение в ячейку 0.0
          table2.removeColumn(0); /*удаляю столбец 0, иначе каждый раз создается новый столбец и таблица растет вширь*/
          TableRow newRow = table2.addRow();  //создаю новую строку
          newRow.setString(0, Dat);    /*пишу в 0 столбец новой строки дату и показания датчика (пока освещенности)*/            
          saveTable(table2, "data/Journaltemp.ods");     //сохраняю значения в таблице
          data2=0;
 }
 
void temps(){
PApplet.runSketch(args, sa);  //Запускаю окно Second Applet
}

public class SecondApplet extends PApplet {
  
public void setup(){
  surface.setTitle("Контроль Температуры");
  surface.setIcon(titlebaricon);
   font2 = createFont("Arial", 20);   /*можно установить свой шрифт, кнопки, текстовые поля  и т.д.*/
     ax = new ControlP5(this);
     ax.addButton("test1")
      .setSize(159, 70)
      .setPosition(1, 300)
      .setFont(font2)
      .setLabel("Измерить");
      
     ax.addButton("test2") 
       .setSize(158, 70)
       .setPosition(161, 300)
       .setFont(font2)
       .setLabel("Измерить");
     
     ax.addButton("test3") 
       .setSize(159, 70)
       .setPosition(320, 300)
       .setFont(font2)
       .setLabel("Измерить");
       
     ax.addButton("test4") 
       .setSize(159, 70)
       .setPosition(480, 300)
       .setFont(font2)
       .setLabel("Измерить");
      
     ax.addButton("test5") 
       .setSize(159, 70)
       .setPosition(640, 300)
       .setFont(font2)
       .setLabel("Измерить");  
       
     ax.addButton("obj")
      .setSize (790, 50)
      .setPosition(5, 540)
      .setColorBackground(color(70, 100, 0))
      .setColorForeground(color(0, 0, 0))
      .setFont(font)
      .setLabel("Журнал"); 
      
      recived1 = ax.addTextfield(" ")
       .setSize(157, 70)
       .setPosition(2, 370)
       .setColorValueLabel(0)
       .setFont(font)
       .setColorBackground(color(255, 255, 255));
       
     recived2=ax.addTextfield("  ")
       .setSize(156, 70)
       .setPosition(162, 370)
       .setColorValueLabel(0)
       .setFont(font)
       .setColorBackground(color(255, 255, 255));
       
     recived3=ax.addTextfield("   ")
       .setSize(157, 70)
       .setPosition(321, 370)
       .setColorValueLabel(0)
       .setFont(font)
       .setColorBackground(color(255, 255, 255)); 
       
     recived4=ax.addTextfield("    ")
       .setSize(157, 70)
       .setPosition(481, 370)
       .setColorValueLabel(0)
       .setFont(font)
       .setColorBackground(color(255, 255, 255));  
       
     recived5=ax.addTextfield("     ")
       .setSize(157, 70)
       .setPosition(641, 370)
       .setColorValueLabel(0)
       .setFont(font)
       .setColorBackground(color(255, 255, 255)); 
       
     }

public void settings() {
    size(800, 600);   // а здесь размер
  }

public void draw() {
    background(fon2);  //а здесь фон))
    textFont(font2);
  }

public void test1(){
  recived1.setText("        11111");
}

public void test2(){
  recived2.setText("       22222");
} 

public void test3(){
  recived3.setText("       33333");  //обрабатываю события кнопок окна Second Applet
} 

public void test4(){
  recived4.setText("       44444");
} 

public void test5(){
  recived5.setText("       55555");
} 

public void obj(){
       save123();  /* для ведения журнала в виде электронной таблицы отсылаю к коду в теле основной программы*/
     }

public void exitActual(){}   //функция выхода из окна по кнопке [X] в верхнем поле окна.
}       // при том первое окно продолжит работу, пока в нем не будет нажато [X]. 


Полученная мной программа:

Раз
Два

Прошу сильно не пинать — мой первый проект на Processing, надеюсь кому нибудь помоет разобраться с такими простейшими, как оказалось вещами. А если кто подскажет, как оптимизировать мой г… код — буду рад.