Interface and Application programming

Group Assignment

  • Compare as many tool options as possible
Group Assignment here

Individual Assignment

  • Write an application that interfaces a user with an input &/or output device that you made.

Introduction

For this week’s assignment, my task was to create a GUI (Graphical User Interface) that the user can interact with, after sending the PC via USB cable readings from my input device, aka temperature sensor DS18B20 (I decided to take the code I did in final code draft - week 11 progress, clean it and simplfy the logic). For my electronics, please check out Week 8 - Electronics Production and Week 9 - Input Devices documentation! Based on my instructor's recommendation, I downloaded Processing 4. software to visualise my data in a GUI. Processing is a beginner-friendly Java-based environment for coding interactive graphics and hardware interfaces. To prepare myself, I reviewed the basics: how to open a serial port and send/receive data using the Serial library, how to remap raw sensor readings into a fixed range with the map() function (you can also check out Medium tutorial), and how to build a simple GUI (toggles and buttons) using ControlP5 library by following the ControlP5 guide (you can also check out the Processing.py ten-lessons to understand ControlP5 callbacks). Overall, the processing official site's Documentation reference list was my go to reading reference to understand different functions and be able to create my code with the help of ChatGPT. One last thing I remembered to consider in my prompt was the sensor's library. Since I want to avoid using library other than the one I found from my last test, I had to explicitly specify it to make sure I do not receive any other library.

Prompt

"Hi! I’m working on Fab Academy’s Interface & Application Programming week and I need two matched programs—one for my Raspberry Pi Pico W in the Arduino IDE and one in Processing 4. I am new to Processing, so please keep everything clear and fully commented.
    PART 1 – Arduino-IDE sketch for the Pico
  • Board: Raspberry Pi Pico W (RP2040).
  • Sensors: two DS18B20 sensors on GPIO 26 and GPIO 27.
  • LED: GPIO 22.
Important – do not change libraries. Use #include MicroDS18B20<26> sensor1; and MicroDS18B20<27> sensor2; exactly as written; do not switch to DallasTemperature.
    Firmware requirements:
  • every second start a 12-bit conversion, read both sensors, and compute their mean
  • send exactly one CSV line per second in the format mean;t1;t2\n (two decimals, no extra text)
  • light the LED automatically when the mean ≥ 23 °C unless overridden
  • listen for a single-byte command from the computer: '1' forces LED ON, '0' forces LED OFF, the override stays until the next byte
  • baud rate must be 9600 to match Processing;
  • no banners or debug prints—only the CSV line.
PART 2 – Processing 4 sketch Serial handling: open the Pico’s port at 9600 baud (show where to change the COM-index) and use bufferUntil('\n') so each callback receives a complete CSV line. Keep a 60-element circular buffer (one sample per second → one-minute history).
    >Visualisation: draw
  • a dial gauge for the mean temperature, scale 20 °C (left) → 30 °C (right), sweep 225° → –45°, color-fade blue → green → red as the value rises, and display the numeric value
  • a scrolling strip-chart under the gauge, 10 pixels per second so 60 samples fit the window.
    GUI with ControlP5:
  • a toggle switch labelled Stream that, when OFF, pauses or hides the visuals but continues receiving data; when ON, resumes drawing
  • a push-button that flips the LED—first click sends '1', second click sends '0', and the caption toggles between “LED ON” and “LED OFF”.
Beginner extras: include the import lines processing.serial.* and controlP5.*; use the standard setup() / draw() skeleton; add a short comment to every important line.
    Deliverables
  • A complete Arduino sketch (.ino) that compiles unchanged with microDS18B20.
  • A complete Processing 4 sketch (.pde) that runs immediately after ControlP5 is installed through the Library Manager.
Please place each code file in its own fenced code block, keep every specification above intact, and make no library substitutions. Thank you!"

ArduinoIDE Programming

Before uploading the sketch to the Pi Pico W, I faced into the same issue I previously ran into (check Reflection and Struggles - Week 11); the port disconnecting and getting stuck in the boot mode UF2. This time, I decided to download the flash_nuke.uf2 file from Raspberry Pi, reboot the board while holding BOOTSEL, and drag-and-drop that UF2 to reinstall the bootloader. Finally, I managed to see the COM7 port and uploaded the code I wrote with ChatGPT.

ArduinoIDE Code: ChatGPT version

This code uses the microDS18B20 library I already tested two weeks ago and read two temperature values every second, computes their mean value, and then prints out a single CSV line in the format mean;t1;t2\n at 9600 baud for the Processing code to pick up. It also overrides the automatic LED logic: when it receives 1 > LED is ON, and when it receives 0 > LED is OFF. Outside of override mode, the code drives the LED based on whether the mean temperature is above the threshold = 23°C.



                                #include              // Include the microDS18B20 library
                                    MicroDS18B20<26> sensor1;              // DS18B20 sensor on GPIO 26
                                    MicroDS18B20<27> sensor2;              // DS18B20 sensor on GPIO 27
                                    
                                    const int ledPin = 22;                 // LED on GPIO 22
                                    bool overrideActive = false;           // Flag: are we in override mode?
                                    bool overrideState = LOW;              // Forced LED state when overridden
                                    
                                    void setup() {
                                      Serial.begin(9600);                  // Start serial at 9600 baud (no banners)
                                      pinMode(ledPin, OUTPUT);             // Configure LED pin as output
                                    }
                                    
                                    void loop() {
                                      // 1) Start a new temperature conversion on both sensors
                                      sensor1.requestTemp();               
                                      sensor2.requestTemp();               
                                    
                                      // 2) Wait for conversion to complete (12-bit ≈750 ms; wait 1 s to be sure)
                                      delay(1000);                         
                                    
                                      // 3) Read temperatures (in °C) from the sensors
                                      float t1 = sensor1.getTemp();        
                                      float t2 = sensor2.getTemp();        
                                    
                                      // 4) Compute the mean of the two readings
                                      float meanTemp = (t1 + t2) / 2.0;    
                                    
                                      // 5) Check for an incoming override command ('1' or '0')
                                      if (Serial.available() > 0) {
                                        char cmd = Serial.read();          
                                        if (cmd == '1') {                  
                                          overrideActive = true;           
                                          overrideState = HIGH;            
                                        } 
                                        else if (cmd == '0') {
                                          overrideActive = true;           
                                          overrideState = LOW;             
                                        }
                                      }
                                    
                                      // 6) Control the LED: override if active, else auto on mean ≥23 °C
                                      if (overrideActive) {
                                        digitalWrite(ledPin, overrideState);
                                      } else {
                                        if (meanTemp >= 23.0) digitalWrite(ledPin, HIGH);
                                        else                  digitalWrite(ledPin, LOW);
                                      }
                                    
                                      // 7) Send one CSV line: mean;t1;t2\n (two decimals, no extra text)
                                      Serial.print(meanTemp, 2);
                                      Serial.print(';');
                                      Serial.print(t1,       2);
                                      Serial.print(';');
                                      Serial.print(t2,       2);
                                      Serial.print('\n');
                                    }
                                    

                            
                        

Processing Code: ChatGPT Version

Processing software has a very similar GUI to ArduinoIDE. Hence, navigating through it for the first time was not difficult. In order to be able to run the sketch, you need to close the ArduinIDE sketch first. Moreover, you can't open two sketches in parallel in Processing; it will show you Port busy error. Hence, run only one sketch at a time! First, I had to download the ControlP5 library from the library manager to be able to run the code. Then, I pasted the code I acquired from ChatGPT. In this code, COM ports were listed in the setup(), then the Pico’s port was opened with bufferUntil('\n'), at a baudrate of 9600 (to match the baud rate from the Arduino code). Furthermore, it generates a Stream toggle and LED button via ControlP5 library. Then, the draw() funcion starts by clearing the screen. If the Streamswitch is on, the sketch does two things:
  • Draws a simple dial that shows the mean temperature between 20 °C and 30 °C. For styling, the needle moves around the arc and changes color from blue to green to red as the temperature increase, and the value is printed underneath
  • .
  • Draws a line chart of the last 60 temperature records
  • . Lastly, when the Stream switch is toggled or the LED button is clicked, all events go through one function: controlEvent(). This function receives with button has been pressed by the user, updates the internal on/off state, sends the 1 or 0 character over serial accordingly, and updates the button label.
    DownloadControlp
    
                                    import processing.serial.*;   // import serial library
    import controlP5.*;           // import ControlP5 for GUI
    
    Serial myPort;                // The serial port object
    ControlP5 cp5;                // ControlP5 instance
    Toggle streamToggle;          // Toggle to pause/resume drawing
    Button ledButton;             // Button to flip the Pico's LED
    boolean ledState = false;     // Track current LED state (false=off)
    
    int totalSamples = 60;        // buffer length for 1-minute history
    float[] data = new float[totalSamples];
    int dataIndex = 0;
    boolean dataFull = false;
    float currentMean = 0;        // Latest mean value
    
    void setup() {
      size(600, 600);                           // Window size
    
      // Serial setup
      println(Serial.list());                   // List available ports
      String[] ports = Serial.list();
      int portIndex = 0;                        // ← change this to your Pico's index
      myPort = new Serial(this, ports[portIndex], 9600);
      myPort.bufferUntil('\n');                 // Deliver full lines
    
      // GUI setup 
      cp5 = new ControlP5(this);
      streamToggle = cp5.addToggle("stream")
        .setPosition(20, 20)
        .setSize(50, 20)
        .setLabel("Stream")
        .setValue(true);
      ledButton = cp5.addButton("ledButton")
        .setPosition(100, 20)
        .setSize(80, 20)
        .setLabel("LED ON");
    }
    
    void draw() {
      background(255);                          // White background
    
      if (streamToggle.getState()) {            // Only draw when streaming
        drawGauge();
        drawStripChart();
      }
    }
    
    // Called when a full CSV line arrives
    void serialEvent(Serial p) {
      String line = p.readStringUntil('\n');
      if (line != null) {
        line = trim(line);
        String[] parts = split(line, ';');
        if (parts.length == 3) {
          float mean = float(parts[0]);
          // Add to circular buffer
          data[dataIndex] = mean;
          dataIndex = (dataIndex + 1) % totalSamples;
          if (dataIndex == 0) dataFull = true;
          currentMean = mean;
        }
      }
    }
    
    // Draw the dial gauge for currentMean
    void drawGauge() {
      float cx = width/2;
      float cy = height/3;
      float radius = 150;
    
      // Gauge arc
      stroke(0);
      noFill();
      arc(cx, cy, radius*2, radius*2, radians(225), radians(-45));
    
      // Compute needle angle (20→30 °C maps 225°→-45°)
      float angle = map(currentMean, 20, 30, radians(225), radians(-45));
    
      // Color fade: blue→green→red
      color c;
      if      (currentMean <= 20) c = color(0, 0, 255);
      else if (currentMean >= 30) c = color(255, 0, 0);
      else if (currentMean <= 25) c = lerpColor(color(0, 0, 255), color(0, 255, 0), map(currentMean, 20, 25, 0, 1));
      else                        c = lerpColor(color(0, 255, 0), color(255, 0, 0), map(currentMean, 25, 30, 0, 1));
    
      // Draw needle
      pushMatrix();
      translate(cx, cy);
      stroke(c);
      strokeWeight(3);
      float nx = radius * cos(angle - HALF_PI);
      float ny = radius * sin(angle - HALF_PI);
      line(0, 0, nx, ny);
      popMatrix();
    
      // Numeric readout
      fill(0);
      textAlign(CENTER, CENTER);
      text(nf(currentMean, 0, 2) + " °C", cx, cy + radius + 20);
    }
    
    // Draw the scrolling strip-chart
    void drawStripChart() {
      float chartY = height * 2/3;
      float chartH = height/3 - 40;
    
      // Border
      noFill();
      stroke(0);
      rect(10, chartY, width - 20, chartH);
    
      // Data polyline
      noFill();
      beginShape();
      int count = dataFull ? totalSamples : dataIndex;
      for (int i = 0; i < count; i++) {
        int idx = (dataIndex + i) % totalSamples;
        float x = map(i, 0, totalSamples - 1, 10, width - 10);
        float y = map(data[idx], 20, 30, chartY + chartH, chartY);
        vertex(x, y);
      }
      endShape();
    }
    
    // Handle LED button clicks
    void controlEvent(ControlEvent e) {
      if (e.getController().getName().equals("ledButton")) {
        if (ledState) {
          myPort.write('0');                   // Turn LED OFF on Pico
          ledState = false;
          e.getController().setLabel("LED ON");
        } else {
          myPort.write('1');                   // Turn LED ON on Pico
          ledState = true;
          e.getController().setLabel("LED OFF");
        }
      }
    }
    
                                
                            

    Arduino Code Modified

    After testing, I decided to slightly adjust the Arduino code better reliability. First, I wrote few comments at the beginning to intruduce briefly what the code does. Then, I added error checks on each readTemp() for debugging. Afterwards, I defined the constant tempThreshold. Lastly, I simplified the override logic for controlling the LED, so that incoming 0s/1s commands are processed immediately in one block at the bedginning of loop() (by removing nested if-statements and using only one condition to set the LED state > behavior becomes more predictable).
    
    
                            /*
     - Raspberry Pi Pico W + two DS18B20 sensors + status LED
      • Built-in error check on readTemp() → GUI only sees valid data
      • When overrideActive==true → tempThreshold logic is bypassed
      • Outputs every 1 s: mean;t1;t2\n
      • Accepts single-byte commands: '1'→LED ON, '0'→LED OFF
     */
                
    #include        // DS18B20  MicroMicro library
    
    // Pins Definition
    MicroDS18B20<26> sensor1;       // DS18B20 on GPIO 26
    MicroDS18B20<27> sensor2;       // DS18B20 on GPIO 27
    #define LED_PIN 22              // status LED 
    
    // Temperature Threshold
    const float tempThreshold = 23.0;   // auto-LED ON above this mean °C
    
    // Set-up 
    void setup() {
      Serial.begin(9600);           // baudrate should match the Processing sketch
      pinMode(LED_PIN, OUTPUT);
    }
    // Global variables
    bool overrideActive = false; //initially OFF
    bool overrideState  = false;
    
    void loop() {
      // Process any incoming 1s/0s commands immediately 
      while (Serial.available()) {
        char c = Serial.read();
        if (c == '1') {
          overrideActive = true;
          overrideState  = true;
        }
        else if (c == '0') {
          overrideActive = true;
          overrideState  = false;
        }
        // ignore anything else
      }
    
      // Kick off conversions 
      sensor1.requestTemp();
      sensor2.requestTemp();
      delay(1000);                // wait for the DS18B20 sensor
    
      // Read temperature values and compute mean 
      bool ok1 = sensor1.readTemp();
      bool ok2 = sensor2.readTemp();
      if (ok1 && ok2) {
        float t1 = sensor1.getTemp();
        float t2 = sensor2.getTemp();
        float meanT = 0.5 * (t1 + t2);
    
        // apply LED logic with override 
        if (overrideActive) {
          digitalWrite(LED_PIN, overrideState ? HIGH : LOW);
        } else {
          digitalWrite(LED_PIN, meanT >= tempThreshold ? HIGH : LOW);
        }
    
        // send CSV line 
        Serial.print(meanT, 2); Serial.print(';');
        Serial.print(t1,     2); Serial.print(';');
        Serial.println(t2,   2);
      }
    
      // loop back and wait for next command!
    }
    
    
    The code works as expected. Nevertheless, the gauge lacks ticks or a digital readout, and the strip chart only shows the mean value line, which makes it hard to differential between the two sensors readings. Moreover, toggling buttons of the stream and the LED is quite confusing, since they lack the labels.

    Processing Code Modified

    Since I wasn't satisfied with the appearance of my GUI, I decided to modify the code. First, after watching the youtube video tutorial I attached at the end, I decided to download the Meter library. Second, I went through the library examples on Github, specifically SetAllValues example to understand how I can tweak the styling of the gauge for temperature readings (titles, ticks, arc thickness, needle,). Moreover, I reviewed the code example from Electronic Clinic gauge tutorial to understand how I can map raw sensor values onto an arc and smoothly fade the dial color (blue > green > red). This led me to replace the arcs with tempGauge.set…() calls, replace fixed values with constants MIN_T and MAX_T, and enable a digital readout. Lastly, I upgraded the strip chart, so each DS18B20 sensor has its own color, with axes and a legend for better visualisation (you can check out Double Sensor Graphs example).
    Downloadmeter
    
                                    /*
     -  Pi Pico 2 + two temperature sensors DS18B20 + LED 
     -  Libraries used: Serial (built-in)  |  ControlP5 | Meter
     */
     
    // Import Libraries
    import processing.serial.*;   // built-in serial commmunication
    import controlP5.*;           // ControlP5 GUI widgets
    import meter.*;               // external Meter library
    
    // Declare global objects
    Serial    pico;               // serial port to Pico
    ControlP5 cp5;                // ControlP5 controller
    Meter     tempGauge;          // Meter gauge object
    
    // History buffers for each sensor
    float[] hist1  = new float[60];  // buffer for sensor 1
    float[] hist2  = new float[60];  // buffer for sensor 2
    
    // State variables
    int       dataIndex      = 0;       // current write index into dataIndex
    boolean   stream    = true;    // true = draw visuals, false = paused
    boolean   ledOn     = false;   // track LED override state
    float     currentT  = 0;       // latest mean temperature 
    
    // Gauge range constants
    final float MIN_T = 20;        // lower bound on gauge
    final float MAX_T = 30;        // upper bound on gauge
    
    // Trace colors
    color col1 = color(  0, 200, 255);  // cyan for sensor 1
    color col2 = color(255, 100, 100);  // salmon for sensor 2
    
    void setup() {
      size(900, 600);                        // set canvas to 900×600 pixels
      surface.setTitle("Temperature Readings"); // window title bar text
    
      // Serial Port Setup
      println("Ports:", Serial.list());      // print available COM ports in console
      pico = new Serial(this, Serial.list()[0], 9600); // open first port @ 9600 baudrate
      pico.bufferUntil('\n');                // call serialEvent() on each newline
    
      // ControlP5 setup
      cp5 = new ControlP5(this);             // create GUI controller
    
      // Stream toggle
      cp5.addToggle("stream")                // auto-calls stream(boolean)
         .setPosition(20, 20)                // place at x=20, y=20
         .setSize(60, 25)                    // width=60, height=25
         .setMode(ControlP5.SWITCH)          // render as on/off switch
         .setValue(true)                     // default state = ON
         .getCaptionLabel()
           .set("Stream");                   // label the switch “Stream”
    
      // LED button
      cp5.addButton("LED")                   // auto-calls LED() on click
         .setPosition(100, 20)               // place to the right of toggle
         .setSize(80, 25)                    // width=80, height=25
         .setCaptionLabel("LED OFF");        // initial button text
    
      // Meter gauge setup
      tempGauge = new Meter(this, width/2 - 150, 20); // position gauge
    
      tempGauge.setTitleFontName("Arial Bold");  // set gauge title font
      tempGauge.setTitleFontSize(20);            // set title font size
      tempGauge.setTitle("Mean Temp (°C)");      // set title text
    
      // Clamp gauge input to [MIN_T,MAX_T]
      tempGauge.setMinInputSignal((int)MIN_T);   // min physical reading
      tempGauge.setMaxInputSignal((int)MAX_T);   // max physical reading
      tempGauge.setMinScaleValue((int)MIN_T);    // min tick label
      tempGauge.setMaxScaleValue((int)MAX_T);    // max tick label
    
      // Build tick labels at 2 °C intervals
      String[] labels = new String[(int)((MAX_T - MIN_T) / 2) + 1];
      for (int i = 0; i < labels.length; i++) {
        labels[i] = nf(MIN_T + i*2, 0, 0);       // format “20”, “22”, …, “30”
      }
      tempGauge.setScaleLabels(labels);          // apply tick labels
    
      // Visual styling for the gauge
      tempGauge.setArcColor(color(60));          // track (rim) color
      tempGauge.setArcThickness(15);             // track arc thickness
      tempGauge.setNeedleThickness(4);           // set pointer thickness
      tempGauge.setDisplayDigitalMeterValue(true);// show digital number
    }
    
    void draw() {
      background(0);                         // set screen to black
    
      // Draw dial gauge or paused message
      if (stream) {
        tempGauge.updateMeter(int(currentT)); // update gauge reading
      } else {
        fill(255);                           // white text (range from 0 to 255 → black to white)
        textSize(18);                        // font size
        textAlign(CENTER, CENTER);           // center alignment
        text("Stream OFF", width/2, 140);    // draw paused label
      }
    
      // Draw the strip-chart below
      drawPlot();                            // call custom plot function
    }
    
    
    // called by ControlP5 when the toggle changes
    public void stream(boolean active) {
      stream = active;                       // store new state
    }
    
    // called by ControlP5 when the "LED" button is clicked
    public void LED(int theValue) {        // callback signature (e.g. user interaction with a button) must accept an integer (click count)
      ledOn = !ledOn;                      // flip local LED state flag
      pico.write(ledOn ? '1' : '0');       // send '1' if ledOn true, else '0'
      cp5.get(Button.class, "LED")         // retrieve the Button named "LED"
         .setCaptionLabel(ledOn ?         // set its label to match the new state
           "LED ON" : "LED OFF");          
      println("LED() callback, ledOn = " + ledOn); // debug print to confirm it fired
    }                                       // end of LED callback
    
    // called whenever a full line arrives on serial
    void serialEvent(Serial s) {            // serialEvent triggered on '\n'
      String line = trim(                   // read up to newline
        s.readStringUntil('\n'));           // trim whitespace
      if (line == null || line.isEmpty())   // if nothing valid was read
        return;                             // exit the handler
    
      String[] parts = split(line, ';');    // split the CSV "mean;t1;t2" by semicolons
    
      float m  = parseFloat(parts[0]);      // parse mean temperature
      float t1 = parseFloat(parts[1]);      // parse sensor 1 reading
      float t2 = parseFloat(parts[2]);      // parse sensor 2 reading
    
      currentT    = m;                      // store mean for gauge update
      hist1[dataIndex] = t1;                     // push sensor1 into its circular buffer
      hist2[dataIndex] = t2;                     // push sensor2 into its circular buffer
    
      dataIndex = (dataIndex + 1) % hist1.length;     // advance buffer index, wrapping at 60
    }                                       // end of serialEvent handler
    
    void drawPlot() {  
      // compute plotting bounds and spacing  
      int plotTop    = 300;                 // y-pixel position of the top edge of the chart area  
      int plotBottom = height - 40;         // y-pixel position of the bottom edge of the chart area  
      int marginLeft = 60;                  // x-pixel offset from the left where the y-axis is drawn  
      // horizontal spacing so 60 samples fill from marginLeft → (width - 20)  
      float spacing  = float(width - marginLeft - 20) / (hist1.length - 1);  
    
      // draw sensor #1 trace in cyan  
      stroke(col1);                         // set stroke color to col1 (cyan)  
      strokeWeight(2);                      // set line thickness to 2 pixels  
      noFill();                             // disable filling any shapes  
      beginShape();                         // start recording vertices for a continuous line  
      for (int i = 0; i < hist1.length; i++) {  
        int p = (dataIndex + i) % hist1.length;  // wrap buffer index to get oldest → newest sample  
        float x = marginLeft + i * spacing; // compute x-position of this sample  
        float y = map(hist1[p], MIN_T, MAX_T, plotBottom, plotTop); // map temp → vertical pixel  
        vertex(x, y);                       // add this point to the shape  
      }  
      endShape();                           // draw the connected line  
    
      // draw sensor #2 trace in salmon, nudged +0.5°C for visibility (since they are essentially recording identical temperatures) 
      stroke(col2);                         // set stroke color to col2 (salmon)  
      strokeWeight(2);                      // set line thickness to 2 pixels  
      noFill();                             // disable fill  
      beginShape();                         // begin new shape for sensor 2  
      for (int i = 0; i < hist2.length; i++) {  
        int p = (dataIndex + i) % hist2.length;  // wrap buffer index for sensor 2  
        float x = marginLeft + i * spacing; // compute x-position for this sample  
        // temporary offset (+0.5°C) so the two traces don’t overlap exactly  
        float y = map(hist2[p] + 0.5, MIN_T, MAX_T, plotBottom, plotTop);  
        vertex(x, y);                       // add point to the second shape  
      }  
      endShape();                           // draw the second connected line  
    
      // draw the y-axis line and its min/max labels  
      stroke(180);                          // set stroke to light gray for axis  
      strokeWeight(1);                      // set axis line thickness to 1 pixel  
      line(marginLeft, plotTop, marginLeft, plotBottom); // draw vertical axis  
      noStroke();                           // disable stroke for text  
      fill(200);                            // set fill color for labels  
      textAlign(RIGHT, CENTER);             // right-align labels horizontally, center vertically  
      text(MIN_T + "°", marginLeft - 5, plotBottom); // draw minimum temp label just left of axis bottom  
      text(MAX_T + "°", marginLeft - 5, plotTop);    // draw maximum temp label just left of axis top  
    
      // draw legend entries for each sensor trace  
      textAlign(LEFT, CENTER);              // left-align legend text  
      fill(col1);                           // set fill to sensor 1 color  
      text("Sensor 1", marginLeft + 5, plotTop + 10);  // label for sensor 1  
      fill(col2);                           // set fill to sensor 2 color  
      text("Sensor 2", marginLeft + 5, plotTop + 30);  // label for sensor 2  
    }
    
                                
                            
    To see the changes in the needle color, I turned on a lighter right infront of the DS18B20 sensor so the temperature increases fast and changes can be visible faster.
    lightertempsensor
    In the video on theleft, we can see modified code, which looks much more polished. The tick marks are clearly labeled on the gauge, the live temperature values beneath it, and the dual-color strip chart with its own axes and legend to represent values from both DS18B20 sensors. Whereas in the video on the right, we can confirm that the LED button is fully functional: each click sends either 1 or 0 over serial, and the button label toggles between LED ON and LED OFF accordingly. This visual response confirms that the override logic is working perfectly fine on the Pico W.

    Conclusion and Reflection

    This week’s task was about turning raw temperature readings into a interactable GUI. I achieved this by reusing my week 11 draft code, but immediately faced the same issue with the port. Therefore, I flash the bootloader with flash_nuke.uf2 file in BOOTSEL mode to bring COM7 port back and upload the code. Once that was solved, I used ChatGPT to write both the Arduino and Processing sketches. Nevertheless, the outcome was not matching my expectations, hence, I did some more readings on Processing Serial guide, ControlP5 callback guides, and the Meter library’s examples to enhance my GUI I achieved with ChatGPT. Last result was more or less good for a first timer: dial gauge with ticks and a live digital curve with legends and axes labels. Overall, Processing is a powerful and beginner-friendly software. It has clear syntax, good documentation, and various library examples that one can start off with to build a well-designed GUI!

    YouTube Tutorials:

    • The Coding Train, 2015, 0.0: Introduction - Processing Tutorial
    • The Thinker Teacher, 2023, Programming in Processing (JAVA) for Beginners - Part 1
    • Digitale Profis, 2023, DIESER CHATGPT PROMPT IST DER WAHNSINN
    • Electronics Clinic, 2022, Arduino Sensor Values on Gauges designed in Processing Software, Sensors Dashboard

    Files