Assignment requirements
Group assignment
- Compare as many tool options as possible
- Document your work on the group work page and reflect on your individual page what you learned
Individual assignment
- Write an application for the embedded board that you made, that interfaces a user with an input and/or output device(s)
Progress status
Compare tools and document your findings
Write and I/O application
Upload source files
1) Introduction
Improve new skills and fill knowledge gaps
- Input/Ouput devices
- Networking & commnication
- Design an application
2) Group assignment - Compare tools options and document them
For more details visit Fab Lab Peru Week 14 Group assignment
Problems
- We didn't know what to do
- New programs and applications to learn
- Shortage of time to test the procedures several times
Solutions
- Review previous assignments and repeat several times
- A lot of time in the computer is needed to learn and practice the new skills
// Arduino code for controlling an LED with Processing commands
#define LED_PIN D6
bool blinkMode = false;
bool ledState = false;
unsigned long lastBlinkTime = 0;
void setup() {
Serial.begin(115200);
Serial.setTimeout(20);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // apagado
}
void loop() {
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
if (command == "ON") {
blinkMode = false;
digitalWrite(LED_PIN, HIGH);
Serial.println("ON");
}
else if (command == "OFF") {
blinkMode = false;
digitalWrite(LED_PIN, LOW);
Serial.println("OFF");
}
else if (command == "BLINK") {
blinkMode = true;
Serial.println("BLINK");
}
}
if (blinkMode) {
if (millis() - lastBlinkTime > 300) {
lastBlinkTime = millis();
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
}
}
}
// Processing code to control the LED on the designed PCB
import processing.serial.*;
Serial myPort;
String status = "OFF";
void setup() {
size(430, 500);
smooth();
textAlign(CENTER, CENTER);
println(Serial.list());
myPort = new Serial(this, "COM3", 115200);
myPort.clear();
}
void draw() {
background(245);
fill(0);
textSize(28);
text("LED Control", width/2, 60);
fill(120);
textSize(14);
text("ON / OFF / BLINK", width/2, 90);
// STATUS
fill(255);
rect(50, 120, 330, 100, 20);
fill(0);
textSize(18);
text("Status", width/2, 150);
fill(status.equals("ON") ? color(0,200,100) :
status.equals("BLINK") ? color(0,120,255) :
color(150));
textSize(28);
text(status, width/2, 190);
// BOTONES
drawButton(60, 270, 90, 70, "ON");
drawButton(170, 270, 90, 70, "OFF");
drawButton(280, 270, 90, 70, "BLINK");
}
void drawButton(float x, float y, float w, float h, String label) {
boolean hover = mouseX > x && mouseX < x + w && mouseY > y && mouseY < y + h;
noStroke();
fill(hover ? color(80) : color(50));
rect(x, y, w, h, 15);
fill(255);
textSize(16);
text(label, x + w/2, y + h/2);
}
void mousePressed() {
if (mouseY > 270 && mouseY < 340) {
if (mouseX > 60 && mouseX < 150) {
send("ON");
status = "ON";
}
if (mouseX > 170 && mouseX < 260) {
send("OFF");
status = "OFF";
}
if (mouseX > 280 && mouseX < 370) {
send("BLINK");
status = "BLINK";
}
}
}
void send(String cmd) {
myPort.write(cmd + "\n");
println("Sent: " + cmd);
}
// Arduino code for HC-SR04 sensor and Putty serial communication
#define TRIG_PIN D5
#define ECHO_PIN D6
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
// Trigger the sensor
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Read the echo time
long duration = pulseIn(ECHO_PIN, HIGH);
// Calculate distance in cm
float distance = (duration / 2.0) * 0.0343;
// Send distance to serial monitor
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
delay(1000); // Wait before next reading
}
3) Individual assigment
Problems
- Define the project
- How to control Input/Output devices
- Not enough experience
Solutions
- Review previous materials
- Explore solutions at Web Resources
- Test & Error for hours
// Arduino code for DHT11 sensor and OLED display
#include
#include
#include
#define DHTPIN D2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
int currentMode = 0; // 0 = Hello, 1 = humidity, 2 = temp C, 3 = temp F
void showHello() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(22, 20, "DHT11 Ready");
u8g2.drawHLine(0, 25, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(10, 40, "0 - Hello Fab Lab");
u8g2.drawStr(10, 52, "1 - Humidity");
u8g2.drawStr(10, 64, "2 - Temp (C) 3 - Temp (F)");
u8g2.sendBuffer();
}
void showFabLab() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(18, 24, "Hello");
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(8, 54, "Fab Lab!");
u8g2.sendBuffer();
}
void showHumidity(float h) {
char valStr[10];
dtostrf(h, 4, 1, valStr);
strcat(valStr, " %");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Humidity");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 52, valStr);
u8g2.sendBuffer();
}
void showTempC(float t) {
char valStr[10];
dtostrf(t, 4, 1, valStr);
strcat(valStr, " C");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(18, 14, "Temperature");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(44, 32, "Celsius");
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 62, valStr);
u8g2.sendBuffer();
}
void showTempF(float t) {
float f = (t * 9.0 / 5.0) + 32.0;
char valStr[10];
dtostrf(f, 4, 1, valStr);
strcat(valStr, " F");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(18, 14, "Temperature");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(30, 32, "Fahrenheit");
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 62, valStr);
u8g2.sendBuffer();
}
void setup() {
Serial.begin(115200);
dht.begin();
u8g2.begin();
showHello();
Serial.println("DHT11 Monitor ready.");
Serial.println("Send 0 = Hello Fab Lab | 1 = Humidity | 2 = Temp C | 3 = Temp F");
}
void loop() {
if (Serial.available() > 0) {
char input = Serial.read();
if (input == '0') {
currentMode = 0;
showFabLab();
Serial.println("Mode: Hello Fab Lab");
} else if (input == '1') {
currentMode = 1;
Serial.println("Mode: Humidity");
} else if (input == '2') {
currentMode = 2;
Serial.println("Mode: Temperature (Celsius)");
} else if (input == '3') {
currentMode = 3;
Serial.println("Mode: Temperature (Fahrenheit)");
} else if (input != '\n' && input != '\r') {
Serial.println("Invalid. Send 0, 1, 2 or 3.");
}
}
// Sensor modes refresh every 2 seconds
if (currentMode == 1 || currentMode == 2 || currentMode == 3) {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("DHT11 read error!");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(10, 35, "Sensor error!");
u8g2.sendBuffer();
delay(2000);
return;
}
if (currentMode == 1) {
showHumidity(humidity);
Serial.print("Humidity: ");
Serial.print(humidity, 1);
Serial.println(" %");
} else if (currentMode == 2) {
showTempC(temperature);
Serial.print("Temperature: ");
Serial.print(temperature, 1);
Serial.println(" C");
} else if (currentMode == 3) {
showTempF(temperature);
float f = (temperature * 9.0 / 5.0) + 32.0;
Serial.print("Temperature: ");
Serial.print(f, 1);
Serial.println(" F");
}
delay(2000);
}
}
// Processing code for a DHT11 monitor with a custom UI
import processing.serial.*;
Serial myPort;
String serialMsg = "Waiting for data...";
int hoveredBtn = -1;
int activeBtn = -1;
String[] labels = {"Hello Fab Lab", "Humidity", "Celsius", "Fahrenheit"};
String[] icons = {"★", "~%", "C", "F"};
String[] sublabel = {"Welcome screen", "Relative humidity", "Temperature", "Temperature"};
color[] btnBase = {#534AB7, #0F6E56, #185FA5, #993C1D};
color[] btnLight = {#7F77DD, #1D9E75, #378ADD, #D85A30};
color[] btnDark = {#26215C, #04342C, #042C53, #4A1B0C};
PFont fontBold;
PFont fontRegular;
PFont fontSmall;
int COLS = 2;
int ROWS = 2;
int PAD = 24;
int BTN_W = 160;
int BTN_H = 110;
int GRID_X;
int GRID_Y = 140;
void setup() {
size(420, 520);
smooth();
GRID_X = (width - (COLS * BTN_W + PAD)) / 2;
fontBold = createFont("Arial Bold", 14, true);
fontRegular = createFont("Arial", 13, true);
fontSmall = createFont("Arial", 10, true);
try {
myPort = new Serial(this, "COM6", 115200);
myPort.bufferUntil('\n');
} catch (Exception e) {
println("Serial port error: " + e.getMessage());
}
}
void draw() {
background(24, 24, 28);
// Header background
noStroke();
fill(36, 36, 42);
rect(0, 0, width, 110);
// Title
textFont(fontBold);
fill(230);
textSize(22);
textAlign(CENTER, TOP);
text("DHT11 Monitor", width / 2, 22);
// Subtitle
textFont(fontRegular);
fill(130);
textSize(12);
text("XIAO ESP32C3 · COM6", width / 2, 54);
// Status pill
color pillC = (myPort != null) ? color(15, 110, 86) : color(153, 60, 29);
String pillT = (myPort != null) ? "● Connected" : "● Disconnected";
drawPill(width / 2, 80, pillT, pillC);
// Section label
textFont(fontSmall);
fill(110);
textSize(11);
textAlign(LEFT, TOP);
text("SELECT MODE", GRID_X, GRID_Y - 22);
// Grid buttons
hoveredBtn = -1;
for (int i = 0; i < 4; i++) {
int col = i % COLS;
int row = i / COLS;
int x = GRID_X + col * (BTN_W + PAD);
int y = GRID_Y + row * (BTN_H + PAD);
boolean hovered = (mouseX >= x && mouseX <= x + BTN_W &&
mouseY >= y && mouseY <= y + BTN_H);
if (hovered) { hoveredBtn = i; cursor(HAND); }
drawCard(x, y, BTN_W, BTN_H, i, hovered, activeBtn == i);
}
if (hoveredBtn == -1) cursor(ARROW);
drawSerialBox();
}
void drawCard(int x, int y, int w, int h, int i, boolean hovered, boolean active) {
color base = active ? btnLight[i] :
hovered ? btnLight[i] : btnBase[i];
color dark = btnDark[i];
// Shadow
noStroke();
fill(0, 60);
rect(x + 4, y + 6, w, h, 14);
// Card body
fill(base);
rect(x, y, w, h, 14);
// Top shine
fill(255, active ? 60 : hovered ? 45 : 25);
rect(x, y, w, h / 3, 14, 14, 0, 0);
// Active bottom bar
if (active) {
fill(255, 120);
rect(x + 20, y + h - 6, w - 40, 4, 2);
}
// Number badge
fill(dark);
ellipse(x + 22, y + 22, 26, 26);
textFont(fontBold);
fill(255, 200);
textSize(11);
textAlign(CENTER, CENTER);
text(str(i), x + 22, y + 22);
// Icon (top right)
textFont(fontBold);
fill(255, active ? 255 : 200);
textSize(active ? 22 : 20);
textAlign(RIGHT, TOP);
text(icons[i], x + w - 14, y + 12);
// Main label
textFont(fontBold);
fill(255);
textSize(14);
textAlign(LEFT, TOP);
text(labels[i], x + 12, y + 52);
// Sub label
textFont(fontRegular);
fill(255, 160);
textSize(10);
text(sublabel[i], x + 12, y + 72);
}
void drawPill(int cx, int cy, String label, color c) {
textFont(fontSmall);
textSize(11);
float tw = textWidth(label);
int pw = (int)tw + 24;
int ph = 22;
noStroke();
fill(c, 60);
rect(cx - pw / 2, cy - ph / 2, pw, ph, ph / 2);
fill(c);
rect(cx - pw / 2 + 1, cy - ph / 2 + 1, pw - 2, ph - 2, ph / 2);
fill(255);
textAlign(CENTER, CENTER);
text(label, cx, cy);
}
void drawSerialBox() {
int bx = PAD;
int by = GRID_Y + ROWS * (BTN_H + PAD) + 10;
int bw = width - PAD * 2;
int bh = 70;
noStroke();
fill(36, 36, 42);
rect(bx, by, bw, bh, 10);
// Left accent bar
fill(activeBtn >= 0 ? btnBase[activeBtn] : color(80));
rect(bx, by, 4, bh, 10, 0, 0, 10);
// Label
textFont(fontSmall);
fill(110);
textSize(10);
textAlign(LEFT, TOP);
text("SERIAL OUTPUT", bx + 16, by + 10);
// Message
textFont(fontRegular);
fill(210);
textSize(13);
text(serialMsg, bx + 16, by + 30);
}
void mousePressed() {
for (int i = 0; i < 4; i++) {
int col = i % COLS;
int row = i / COLS;
int x = GRID_X + col * (BTN_W + PAD);
int y = GRID_Y + row * (BTN_H + PAD);
if (mouseX >= x && mouseX <= x + BTN_W &&
mouseY >= y && mouseY <= y + BTN_H) {
sendCommand(i);
}
}
}
void sendCommand(int mode) {
activeBtn = mode;
if (myPort != null) {
myPort.write(str(mode));
println("Sent: " + mode);
}
switch (mode) {
case 0: serialMsg = "Sent 0 -> Hello Fab Lab"; break;
case 1: serialMsg = "Sent 1 -> Humidity"; break;
case 2: serialMsg = "Sent 2 -> Temperature (C)"; break;
case 3: serialMsg = "Sent 3 -> Temperature (F)"; break;
}
}
void serialEvent(Serial p) {
String incoming = p.readStringUntil('\n');
if (incoming != null) {
incoming = trim(incoming);
if (incoming.length() > 0) {
println("ESP32 >> " + incoming);
serialMsg = incoming;
}
}
}
// Arduino code for DHT11 sensor, OLED display, servo motor and ON/OFF switch monitor with a custom UI
#include
#include
#include
#include
#define DHTPIN D2
#define DHTTYPE DHT11
#define SERVO_PIN D9
DHT dht(DHTPIN, DHTTYPE);
Servo myServo;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
int currentMode = 0;
int servoAngle = 0;
bool sweeping = true;
bool servoEnabled = true;
unsigned long lastSensorRead = 0;
unsigned long lastServoMove = 0;
const unsigned long SENSOR_INTERVAL = 2000;
const unsigned long SERVO_INTERVAL = 15;
// ──────────────────────────────────────────
// OLED display functions
// ──────────────────────────────────────────
void showFabLab() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(18, 24, "Hello");
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(8, 54, "Fab Lab!");
u8g2.sendBuffer();
}
void showHumidity(float h) {
char valStr[10];
dtostrf(h, 4, 1, valStr);
strcat(valStr, " %");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Humidity");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 52, valStr);
u8g2.sendBuffer();
}
void showTempC(float t) {
char valStr[10];
dtostrf(t, 4, 1, valStr);
strcat(valStr, " C");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(18, 14, "Temperature");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(44, 32, "Celsius");
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 62, valStr);
u8g2.sendBuffer();
}
void showTempF(float t) {
float f = (t * 9.0 / 5.0) + 32.0;
char valStr[10];
dtostrf(f, 4, 1, valStr);
strcat(valStr, " F");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(18, 14, "Temperature");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(30, 32, "Fahrenheit");
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 62, valStr);
u8g2.sendBuffer();
}
void showServoOff() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Servo Status");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(22, 48, "STOPPED");
u8g2.sendBuffer();
}
void showServoOn() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Servo Status");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(18, 48, "RUNNING");
u8g2.sendBuffer();
}
// ──────────────────────────────────────────
// Sensor read + display
// ──────────────────────────────────────────
void readAndDisplay() {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("DHT11 read error!");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(10, 35, "Sensor error!");
u8g2.sendBuffer();
return;
}
if (currentMode == 1) {
showHumidity(humidity);
Serial.print("Humidity: ");
Serial.print(humidity, 1);
Serial.println(" %");
} else if (currentMode == 2) {
showTempC(temperature);
Serial.print("Temperature: ");
Serial.print(temperature, 1);
Serial.println(" C");
} else if (currentMode == 3) {
showTempF(temperature);
float f = (temperature * 9.0 / 5.0) + 32.0;
Serial.print("Temperature: ");
Serial.print(f, 1);
Serial.println(" F");
}
}
// ──────────────────────────────────────────
// Servo sweep
// ──────────────────────────────────────────
void updateServo() {
if (!servoEnabled) return;
if (millis() - lastServoMove < SERVO_INTERVAL) return;
lastServoMove = millis();
myServo.write(servoAngle);
if (sweeping) {
servoAngle++;
if (servoAngle >= 180) sweeping = false;
} else {
servoAngle--;
if (servoAngle <= 0) sweeping = true;
}
}
// ──────────────────────────────────────────
// Setup
// ──────────────────────────────────────────
void setup() {
Serial.begin(115200);
dht.begin();
u8g2.begin();
myServo.setPeriodHertz(50);
myServo.attach(SERVO_PIN, 500, 2400);
myServo.write(0);
showFabLab();
Serial.println("DHT11 Monitor ready.");
Serial.println("0 = Hello Fab Lab | 1 = Humidity | 2 = Temp C | 3 = Temp F");
Serial.println("5 = Servo OFF | 6 = Servo ON");
}
// ──────────────────────────────────────────
// Loop
// ──────────────────────────────────────────
void loop() {
updateServo();
if (Serial.available() > 0) {
char input = Serial.read();
if (input == '0') {
currentMode = 0;
showFabLab();
Serial.println("Mode: Hello Fab Lab");
} else if (input == '1') {
currentMode = 1;
Serial.println("Mode: Humidity");
readAndDisplay();
lastSensorRead = millis();
} else if (input == '2') {
currentMode = 2;
Serial.println("Mode: Temperature (Celsius)");
readAndDisplay();
lastSensorRead = millis();
} else if (input == '3') {
currentMode = 3;
Serial.println("Mode: Temperature (Fahrenheit)");
readAndDisplay();
lastSensorRead = millis();
} else if (input == '5') {
servoEnabled = false;
myServo.write(0); // return to rest
delay(500); // wait to reach position
myServo.detach(); // cut signal — no jitter
servoAngle = 0;
sweeping = true;
showServoOff();
Serial.println("Servo: OFF");
} else if (input == '6') {
servoEnabled = true;
servoAngle = 0;
sweeping = true;
myServo.attach(SERVO_PIN, 500, 2400);
myServo.write(0);
delay(300);
showServoOn();
Serial.println("Servo: ON");
} else if (input != '\n' && input != '\r') {
Serial.println("Invalid. Send 0, 1, 2, 3, 5 or 6.");
}
}
// Auto-refresh sensor display every 2 seconds
if (currentMode >= 1 && currentMode <= 3 &&
millis() - lastSensorRead >= SENSOR_INTERVAL) {
lastSensorRead = millis();
readAndDisplay();
}
}
// Processing code for a DHT11, 1.3 OLED IIC, Micro Servo 9 gram, and ON/OFF switch monitor with a custom UI
import processing.serial.*;
Serial myPort;
// ── Serial data ──────────────────────────
String serialMsg = "Waiting for data...";
float tempC = 0;
float tempF = 0;
float humidity = 0;
boolean hasData = false;
// ── Graph history ────────────────────────
int MAX_POINTS = 60;
float[] histTempC = new float[MAX_POINTS];
float[] histHumid = new float[MAX_POINTS];
int histIndex = 0;
boolean graphFull = false;
// ── UI state ─────────────────────────────
int activeBtn = -1;
int hoveredBtn = -1;
boolean servoOn = false;
boolean swHovered = false;
// ── Fonts ────────────────────────────────
PFont fontBold;
PFont fontRegular;
PFont fontSmall;
// ── Layout constants ─────────────────────
int W = 440;
int H = 720;
int PAD = 20;
int CARD_W = (W - PAD * 2 - 12) / 2;
int CARD_H = 90;
int GRID_X = PAD;
int GRID_Y = 390;
// Toggle
int SW_W = 60;
int SW_H = 30;
int SW_X;
int SW_Y = 560;
// Colors
color BG = color(24, 24, 28);
color PANEL = color(36, 36, 42);
color TEXT1 = color(230, 230, 230);
color TEXT2 = color(140, 140, 148);
color TEXT3 = color(90, 90, 100);
color BLUE = color(55, 138, 221);
color TEAL = color(29, 158, 117);
color[] CBASES = {color(83,74,183), color(15,110,86), color(24,95,165), color(153,60,29)};
color[] CLIGHTS = {color(127,119,221), color(29,158,117), color(55,138,221), color(216,90,48)};
color[] CDARKS = {color(38,33,92), color(4,52,44), color(4,44,83), color(74,27,12)};
// ─────────────────────────────────────────
void setup() {
size(440, 720);
smooth();
SW_X = (W - SW_W) / 2;
fontBold = createFont("Arial Bold", 14, true);
fontRegular = createFont("Arial", 13, true);
fontSmall = createFont("Arial", 10, true);
for (int i = 0; i < MAX_POINTS; i++) {
histTempC[i] = 0;
histHumid[i] = 0;
}
try {
myPort = new Serial(this, "COM6", 115200);
myPort.bufferUntil('\n');
} catch (Exception e) {
println("Serial error: " + e.getMessage());
}
}
// ─────────────────────────────────────────
void draw() {
background(BG);
drawHeader();
drawLiveCards();
drawGraph();
drawModeButtons();
drawServoSection();
drawSerialBox();
}
// ── Header ───────────────────────────────
void drawHeader() {
fill(PANEL);
noStroke();
rect(PAD, 14, W - PAD * 2, 80, 10);
textFont(fontBold);
fill(TEXT1);
textSize(20);
textAlign(CENTER, TOP);
text("DHT11 Monitor", W / 2, 24);
textFont(fontRegular);
fill(TEXT2);
textSize(11);
text("XIAO ESP32C3 · COM6", W / 2, 50);
// Status pill
color pc = (myPort != null) ? color(15,110,86) : color(153,60,29);
String pt = (myPort != null) ? " Connected" : " Disconnected";
drawPill(W / 2, 76, pt, pc);
}
// ── Live cards ───────────────────────────
void drawLiveCards() {
textFont(fontSmall);
fill(TEXT3);
textSize(10);
textAlign(LEFT, TOP);
text("LIVE READINGS", PAD, 108);
int cw = (W - PAD * 2 - 16) / 3;
int cy = 122;
int ch = 62;
drawLiveCard(PAD, cy, cw, ch,
hasData ? nf(tempC, 1, 1) + "C" : "--",
"Temperature", BLUE);
drawLiveCard(PAD + cw + 8, cy, cw, ch,
hasData ? nf(tempF, 1, 1) + "F" : "--",
"Temperature", BLUE);
drawLiveCard(PAD + (cw+8)*2, cy, cw, ch,
hasData ? nf(humidity, 1, 1) + "%" : "--",
"Humidity", TEAL);
}
void drawLiveCard(int x, int y, int w, int h, String val, String lbl, color c) {
fill(PANEL);
noStroke();
rect(x, y, w, h, 8);
fill(c);
textFont(fontBold);
textSize(18);
textAlign(LEFT, TOP);
text(val, x + 10, y + 12);
fill(TEXT3);
textFont(fontSmall);
textSize(10);
text(lbl, x + 10, y + 38);
}
// ── Graph ────────────────────────────────
void drawGraph() {
textFont(fontSmall);
fill(TEXT3);
textSize(10);
textAlign(LEFT, TOP);
text("HISTORY GRAPH", PAD, 198);
int gx = PAD;
int gy = 212;
int gw = W - PAD * 2;
int gh = 80;
fill(PANEL);
noStroke();
rect(gx, gy, gw, gh + 20, 8);
// Grid lines
stroke(50, 50, 58);
strokeWeight(0.5);
for (int i = 1; i < 4; i++) {
float ly = gy + (gh / 4.0) * i;
line(gx + 8, ly, gx + gw - 8, ly);
}
// Temp line
int points = graphFull ? MAX_POINTS : histIndex;
if (points > 1) {
float minT = 0, maxT = 50;
float minH = 0, maxH = 100;
noFill();
stroke(BLUE);
strokeWeight(1.5);
beginShape();
for (int i = 0; i < points; i++) {
int idx = graphFull ? (histIndex + i) % MAX_POINTS : i;
float x = map(i, 0, MAX_POINTS - 1, gx + 8, gx + gw - 8);
float y = map(histTempC[idx], minT, maxT, gy + gh - 4, gy + 4);
vertex(x, y);
}
endShape();
// Humidity line dashed
stroke(TEAL);
strokeWeight(1.5);
for (int i = 0; i < points - 1; i++) {
if (i % 3 == 0) {
int idx0 = graphFull ? (histIndex + i) % MAX_POINTS : i;
int idx1 = graphFull ? (histIndex + i + 1) % MAX_POINTS : i + 1;
float x0 = map(i, 0, MAX_POINTS - 1, gx + 8, gx + gw - 8);
float x1 = map(i + 1, 0, MAX_POINTS - 1, gx + 8, gx + gw - 8);
float y0 = map(histHumid[idx0], minH, maxH, gy + gh - 4, gy + 4);
float y1 = map(histHumid[idx1], minH, maxH, gy + gh - 4, gy + 4);
line(x0, y0, x1, y1);
}
}
}
// Legend
noStroke();
fill(BLUE);
rect(gx + 10, gy + gh + 7, 18, 2, 1);
fill(TEXT2);
textFont(fontSmall);
textSize(10);
textAlign(LEFT, CENTER);
text("Temp", gx + 32, gy + gh + 8);
fill(TEAL);
rect(gx + 80, gy + gh + 7, 18, 2, 1);
fill(TEXT2);
text("Humidity", gx + 102, gy + gh + 8);
fill(TEXT3);
textAlign(RIGHT, CENTER);
text("last 60s", gx + gw - 8, gy + gh + 8);
}
// ── Mode buttons ─────────────────────────
void drawModeButtons() {
textFont(fontSmall);
fill(TEXT3);
textSize(10);
textAlign(LEFT, TOP);
text("SELECT MODE", PAD, GRID_Y - 18);
String[] labels = {"Hello Fab Lab", "Humidity", "Celsius", "Fahrenheit"};
String[] sublbls = {"Welcome screen", "Rel. humidity", "Temperature", "Temperature"};
String[] icons = {"*", "%", "C", "F"};
hoveredBtn = -1;
for (int i = 0; i < 4; i++) {
int col = i % 2;
int row = i / 2;
int x = GRID_X + col * (CARD_W + 12);
int y = GRID_Y + row * (CARD_H + 10);
boolean hov = (mouseX >= x && mouseX <= x + CARD_W &&
mouseY >= y && mouseY <= y + CARD_H);
boolean act = (activeBtn == i);
if (hov) { hoveredBtn = i; cursor(HAND); }
drawCard(x, y, CARD_W, CARD_H, i,
labels[i], sublbls[i], icons[i], hov, act);
}
if (hoveredBtn == -1 && !swHovered) cursor(ARROW);
}
void drawCard(int x, int y, int w, int h, int i,
String lbl, String sub, String icon,
boolean hov, boolean act) {
color base = (hov || act) ? CLIGHTS[i] : CBASES[i];
color dark = CDARKS[i];
noStroke();
fill(base);
rect(x, y, w, h, 10);
fill(255, act ? 55 : hov ? 40 : 20);
rect(x, y, w, h / 3, 10, 10, 0, 0);
if (act) {
fill(255, 100);
rect(x + 18, y + h - 5, w - 36, 3, 2);
}
fill(dark);
ellipse(x + 20, y + 20, 24, 24);
textFont(fontSmall);
fill(255, 180);
textSize(10);
textAlign(CENTER, CENTER);
text(str(i), x + 20, y + 20);
textFont(fontBold);
fill(255, act ? 255 : 200);
textSize(16);
textAlign(RIGHT, TOP);
text(icon, x + w - 12, y + 8);
textFont(fontBold);
fill(255);
textSize(13);
textAlign(LEFT, TOP);
text(lbl, x + 10, y + 48);
textFont(fontRegular);
fill(255, 150);
textSize(10);
text(sub, x + 10, y + 66);
}
// ── Servo section ────────────────────────
void drawServoSection() {
textFont(fontSmall);
fill(TEXT3);
textSize(10);
textAlign(LEFT, TOP);
text("SERVO CONTROL", PAD, SW_Y - 18);
fill(PANEL);
noStroke();
rect(PAD, SW_Y - 2, W - PAD * 2, 60, 10);
// Label
textFont(fontBold);
fill(TEXT1);
textSize(13);
textAlign(LEFT, CENTER);
text("SG90 Servo", PAD + 14, SW_Y + 16);
// Status text
textFont(fontRegular);
textSize(11);
fill(servoOn ? TEAL : TEXT3);
text(servoOn ? "RUNNING" : "STOPPED", PAD + 14, SW_Y + 36);
// Toggle switch
int tx = W - PAD - SW_W - 14;
int ty = SW_Y + 14;
swHovered = (mouseX >= tx - 6 && mouseX <= tx + SW_W + 6 &&
mouseY >= ty - 6 && mouseY <= ty + SW_H + 6);
if (swHovered) cursor(HAND);
drawToggle(tx, ty, SW_W, SW_H, servoOn, swHovered);
}
void drawToggle(int x, int y, int w, int h, boolean on, boolean hov) {
int r = h / 2;
color track = on ? (hov ? color(29,158,117) : color(15,110,86))
: (hov ? color(70,70,80) : color(50,50,60));
noStroke();
fill(track);
rect(x, y, w, h, r);
fill(255, 18);
rect(x, y, w, h / 2, r, r, 0, 0);
textFont(fontSmall);
textSize(9);
fill(255, on ? 180 : 50);
textAlign(LEFT, CENTER);
text("ON", x + 9, y + h / 2);
fill(255, on ? 50 : 180);
textAlign(RIGHT, CENTER);
text("OFF", x + w - 9, y + h / 2);
int kd = h - 6;
int kx = on ? x + w - kd - 3 : x + 3;
int ky = y + 3;
fill(235);
ellipse(kx + kd / 2, ky + kd / 2, kd, kd);
fill(255, 160);
ellipse(kx + kd / 2 - 2, ky + kd / 2 - 3, kd / 3, kd / 3);
}
// ── Serial box ───────────────────────────
void drawSerialBox() {
int bx = PAD;
int by = SW_Y + 72;
int bw = W - PAD * 2;
int bh = 56;
fill(PANEL);
noStroke();
rect(bx, by, bw, bh, 10);
color accent = activeBtn >= 0 ? CBASES[activeBtn] : color(80);
fill(accent);
rect(bx, by, 4, bh, 10, 0, 0, 10);
textFont(fontSmall);
fill(TEXT3);
textSize(10);
textAlign(LEFT, TOP);
text("SERIAL OUTPUT", bx + 14, by + 10);
textFont(fontRegular);
fill(TEXT1);
textSize(12);
text(serialMsg, bx + 14, by + 28);
}
// ── Pill ─────────────────────────────────
void drawPill(int cx, int cy, String lbl, color c) {
textFont(fontSmall);
textSize(11);
float tw = textWidth(lbl);
int pw = (int)tw + 24;
int ph = 20;
noStroke();
fill(red(c), green(c), blue(c), 55);
rect(cx - pw/2, cy - ph/2, pw, ph, ph/2);
fill(c);
rect(cx - pw/2 + 1, cy - ph/2 + 1, pw - 2, ph - 2, ph/2);
fill(255);
textAlign(CENTER, CENTER);
text(lbl, cx, cy);
}
// ── Mouse ────────────────────────────────
void mousePressed() {
// Mode buttons
for (int i = 0; i < 4; i++) {
int col = i % 2;
int row = i / 2;
int x = GRID_X + col * (CARD_W + 12);
int y = GRID_Y + row * (CARD_H + 10);
if (mouseX >= x && mouseX <= x + CARD_W &&
mouseY >= y && mouseY <= y + CARD_H) {
activeBtn = i;
sendCmd(str(i));
switch (i) {
case 0: serialMsg = "Sent 0 -> Hello Fab Lab"; break;
case 1: serialMsg = "Sent 1 -> Humidity"; break;
case 2: serialMsg = "Sent 2 -> Temperature (C)"; break;
case 3: serialMsg = "Sent 3 -> Temperature (F)"; break;
}
return;
}
}
// Toggle switch
int tx = W - PAD - SW_W - 14;
int ty = SW_Y + 14;
if (mouseX >= tx - 6 && mouseX <= tx + SW_W + 6 &&
mouseY >= ty - 6 && mouseY <= ty + SW_H + 6) {
servoOn = !servoOn;
if (servoOn) {
sendCmd("6");
serialMsg = "Sent 6 -> Servo ON";
} else {
sendCmd("5");
serialMsg = "Sent 5 -> Servo OFF";
}
}
}
void sendCmd(String cmd) {
if (myPort != null) myPort.write(cmd);
println("Sent: " + cmd);
}
// ── Serial event ─────────────────────────
void serialEvent(Serial p) {
String raw = p.readStringUntil('\n');
if (raw == null) return;
raw = trim(raw);
if (raw.length() == 0) return;
println("ESP32 >> " + raw);
serialMsg = raw;
// Parse "Humidity: 58.2 %"
if (raw.startsWith("Humidity:")) {
String[] t = splitTokens(raw, ": %");
if (t.length >= 2) {
humidity = float(t[1]);
hasData = true;
addHistory();
}
}
// Parse "Temperature: 26.4 C" or "Temperature: 79.5 F"
if (raw.startsWith("Temperature:")) {
String[] t = splitTokens(raw, ": ");
if (t.length >= 3) {
float val = float(t[1]);
if (t[2].equals("C")) {
tempC = val;
tempF = val * 9.0 / 5.0 + 32.0;
hasData = true;
addHistory();
} else if (t[2].equals("F")) {
tempF = val;
tempC = (val - 32.0) * 5.0 / 9.0;
hasData = true;
addHistory();
}
}
}
}
void addHistory() {
histTempC[histIndex] = tempC;
histHumid[histIndex] = humidity;
histIndex++;
if (histIndex >= MAX_POINTS) {
histIndex = 0;
graphFull = true;
}
}
// Arduino code for a DHT11, 1.3 OLED IIC, Micro Servo 9 gram, and ON/OFF switch monitor
// Open - servo 180° and close - servo 0° with a custom UI
#include
#include
#include
#include
#define DHTPIN D2
#define DHTTYPE DHT11
#define SERVO_PIN D9
DHT dht(DHTPIN, DHTTYPE);
Servo myServo;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
int currentMode = 0;
int servoAngle = 0;
bool sweeping = true;
bool servoEnabled = false;
unsigned long lastSensorRead = 0;
unsigned long lastServoMove = 0;
const unsigned long SENSOR_INTERVAL = 2000;
const unsigned long SERVO_INTERVAL = 15;
// ──────────────────────────────────────────
// OLED display functions
// ──────────────────────────────────────────
void showFabLab() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(18, 24, "Hello");
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(8, 54, "Fab Lab!");
u8g2.sendBuffer();
}
void showHumidity(float h) {
char valStr[10];
dtostrf(h, 4, 1, valStr);
strcat(valStr, " %");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Humidity");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 52, valStr);
u8g2.sendBuffer();
}
void showTempC(float t) {
char valStr[10];
dtostrf(t, 4, 1, valStr);
strcat(valStr, " C");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(18, 14, "Temperature");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(44, 32, "Celsius");
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 62, valStr);
u8g2.sendBuffer();
}
void showTempF(float t) {
float f = (t * 9.0 / 5.0) + 32.0;
char valStr[10];
dtostrf(f, 4, 1, valStr);
strcat(valStr, " F");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(18, 14, "Temperature");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(30, 32, "Fahrenheit");
u8g2.setFont(u8g2_font_ncenB24_tr);
u8g2.drawStr(14, 62, valStr);
u8g2.sendBuffer();
}
void showServoOff() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Servo Status");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(22, 48, "STOPPED");
u8g2.sendBuffer();
}
void showServoOn() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(28, 14, "Servo Status");
u8g2.drawHLine(0, 18, 128);
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(18, 48, "RUNNING");
u8g2.sendBuffer();
}
void showServoAngle(int angle) {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB10_tr);
u8g2.drawStr(22, 14, "Servo Position");
u8g2.drawHLine(0, 18, 128);
char angStr[10];
sprintf(angStr, "%d deg", angle);
u8g2.setFont(u8g2_font_ncenB18_tr);
u8g2.drawStr(10, 48, angStr);
u8g2.sendBuffer();
}
// ──────────────────────────────────────────
// Sensor read + display
// ──────────────────────────────────────────
void readAndDisplay() {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("DHT11 read error!");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(10, 35, "Sensor error!");
u8g2.sendBuffer();
return;
}
if (currentMode == 1) {
showHumidity(humidity);
Serial.print("Humidity: ");
Serial.print(humidity, 1);
Serial.println(" %");
} else if (currentMode == 2) {
showTempC(temperature);
Serial.print("Temperature: ");
Serial.print(temperature, 1);
Serial.println(" C");
} else if (currentMode == 3) {
showTempF(temperature);
float f = (temperature * 9.0 / 5.0) + 32.0;
Serial.print("Temperature: ");
Serial.print(f, 1);
Serial.println(" F");
}
}
// ──────────────────────────────────────────
// Servo continuous sweep
// ──────────────────────────────────────────
void updateServo() {
if (!servoEnabled) return;
if (millis() - lastServoMove < SERVO_INTERVAL) return;
lastServoMove = millis();
myServo.write(servoAngle);
if (sweeping) {
servoAngle++;
if (servoAngle >= 180) sweeping = false;
} else {
servoAngle--;
if (servoAngle <= 0) sweeping = true;
}
}
// ──────────────────────────────────────────
// Servo move to target and stop
// ──────────────────────────────────────────
void moveServoTo(int target) {
servoEnabled = false;
if (!myServo.attached()) {
myServo.attach(SERVO_PIN, 500, 2400);
}
int step = (target > servoAngle) ? 1 : -1;
while (servoAngle != target) {
servoAngle += step;
myServo.write(servoAngle);
if (servoAngle % 10 == 0) {
showServoAngle(servoAngle);
}
delay(15);
}
showServoAngle(servoAngle);
Serial.print("Servo at: ");
Serial.print(servoAngle);
Serial.println(" deg -- stopped.");
delay(400);
myServo.detach();
}
// ──────────────────────────────────────────
// Setup
// ──────────────────────────────────────────
void setup() {
Serial.begin(115200);
dht.begin();
u8g2.begin();
myServo.setPeriodHertz(50);
myServo.attach(SERVO_PIN, 500, 2400);
myServo.write(0);
servoAngle = 0;
sweeping = true;
servoEnabled = false;
delay(300);
myServo.detach();
showFabLab();
Serial.println("DHT11 Monitor ready.");
Serial.println("0=FabLab | 1=Humidity | 2=Temp C | 3=Temp F");
Serial.println("5=Servo OFF | 6=Servo ON sweep");
Serial.println("8=Open-Move to 180 and stop | 9=Close-Move to 0 and stop");
}
// ──────────────────────────────────────────
// Loop
// ──────────────────────────────────────────
void loop() {
updateServo();
if (Serial.available() > 0) {
char input = Serial.read();
if (input == '0') {
currentMode = 0;
showFabLab();
Serial.println("Mode: Hello Fab Lab");
} else if (input == '1') {
currentMode = 1;
Serial.println("Mode: Humidity");
readAndDisplay();
lastSensorRead = millis();
} else if (input == '2') {
currentMode = 2;
Serial.println("Mode: Temperature (Celsius)");
readAndDisplay();
lastSensorRead = millis();
} else if (input == '3') {
currentMode = 3;
Serial.println("Mode: Temperature (Fahrenheit)");
readAndDisplay();
lastSensorRead = millis();
} else if (input == '5') {
servoEnabled = false;
if (myServo.attached()) {
myServo.write(0);
delay(500);
myServo.detach();
}
servoAngle = 0;
sweeping = true;
showServoOff();
Serial.println("Servo: OFF");
} else if (input == '6') {
servoEnabled = true;
sweeping = true;
myServo.attach(SERVO_PIN, 500, 2400);
myServo.write(servoAngle);
delay(300);
showServoOn();
Serial.println("Servo: ON -- sweeping");
} else if (input == '8') {
Serial.println("Open-Moving to 180 deg...");
moveServoTo(180);
} else if (input == '9') {
Serial.println("Close-Moving to 0 deg...");
moveServoTo(0);
} else if (input != '\n' && input != '\r') {
Serial.println("Invalid. Send 0,1,2,3,5,6,8 or 9.");
}
}
// Auto-refresh sensor display every 2 seconds
if (currentMode >= 1 && currentMode <= 3 &&
millis() - lastSensorRead >= SENSOR_INTERVAL) {
lastSensorRead = millis();
readAndDisplay();
}
}
// ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
// Code for Processing with 8-Open - 180° Servo control and 9-Close - 0° Servo Control (Processing 4)
// Line formats:
// H:,TC:,TF:
// SERVO:ANGLE:
// SERVO:ON / SERVO:OFF
// MODE:
// ERROR:sensor
// READY
// ─────────────────────────────────────────
import processing.serial.*;
Serial port;
// ── Data ──────────────────────────────────
float humidity = 0;
float tempC = 0;
float tempF = 0;
int servoAngle = 0;
float displayAngle = 0;
boolean servoOn = false;
String mode = "FabLab";
boolean hasData = false;
boolean connected = false;
String portName = "–";
// ── Buttons ───────────────────────────────
Button[] buttons;
// ── Palette ───────────────────────────────
final color BG = color(18, 18, 20);
final color CARD = color(28, 28, 32);
final color BORDER = color(55, 55, 65);
final color TEAL = color(29, 158, 117);
final color AMBER = color(186, 117, 23);
final color PURPLE = color(83, 74, 183);
final color BLUE = color(55, 138, 221);
final color PINK = color(212, 83, 126);
final color MUTED = color(130, 130, 140);
final color WHITE = color(230, 228, 222);
final color RED = color(226, 75, 74);
final color GREEN = color(99, 153, 34);
PFont mono;
PFont sans;
// ──────────────────────────────────────────
void setup() {
size(680, 580);
smooth(4);
mono = createFont("Monospaced", 12);
sans = createFont("SansSerif", 13);
// Define all 8 buttons: label, command char, color, x, y, w, h
buttons = new Button[] {
new Button("FabLab", '0', PURPLE, 20, 468, 138, 44),
new Button("Humidity", '1', BLUE, 172, 468, 138, 44),
new Button("Temp \u00b0C", '2', TEAL, 324, 468, 138, 44),
new Button("Temp \u00b0F", '3', TEAL, 476, 468, 138, 44),
new Button("Servo sweep", '4', AMBER, 20, 524, 138, 44),
new Button("Servo stop", '5', MUTED, 172, 524, 138, 44),
new Button("Open 180\u00b0",'6', PINK, 324, 524, 138, 44),
new Button("Close 0\u00b0", '7', PINK, 476, 524, 138, 44),
};
println("Available ports:");
printArray(Serial.list());
// ⚠ Change [0] if your board is on a different port
// Mac: look for /dev/cu.usbmodem...
// Win: look for COM3 / COM4 etc.
try {
portName = Serial.list()[0];
port = new Serial(this, portName, 115200);
port.bufferUntil('\n');
connected = true;
}
catch (Exception e) {
connected = false;
portName = "No port — demo mode";
// Seed demo values so UI is visible without a board
humidity = 58.0; tempC = 24.5; tempF = 76.1;
servoAngle = 45; hasData = true;
}
}
// ── Serial ────────────────────────────────
void serialEvent(Serial p) {
String raw = trim(p.readStringUntil('\n'));
if (raw == null || raw.length() == 0) return;
if (raw.startsWith("H:")) {
String[] pts = split(raw, ',');
try {
humidity = float(pts[0].substring(2));
tempC = float(pts[1].substring(3));
tempF = float(pts[2].substring(3));
hasData = true;
} catch (Exception e) {}
} else if (raw.startsWith("SERVO:ANGLE:")) {
servoAngle = int(raw.substring(12));
} else if (raw.equals("SERVO:ON")) {
servoOn = true;
} else if (raw.equals("SERVO:OFF")) {
servoOn = false;
} else if (raw.startsWith("MODE:")) {
mode = raw.substring(5);
}
}
// ── Send command ──────────────────────────
void sendCmd(char c) {
if (connected && port != null) {
port.write(c);
} else {
// Demo simulation — no board needed
switch(c) {
case '0': mode = "FabLab"; break;
case '1': humidity = random(35,85); hasData = true; mode = "Humidity"; break;
case '2': tempC = random(18,38); tempF = tempC*9/5+32; hasData = true; mode = "TempC"; break;
case '3': tempC = random(18,38); tempF = tempC*9/5+32; hasData = true; mode = "TempF"; break;
case '4': servoOn = true; mode = "Servo"; break;
case '5': servoOn = false; servoAngle = 0; mode = "Servo"; break;
case '6': servoAngle = 180; servoOn = false; mode = "Servo"; break;
case '7': servoAngle = 0; servoOn = false; mode = "Servo"; break;
}
}
}
// ── Click ─────────────────────────────────
void mousePressed() {
for (Button b : buttons) {
if (b.contains(mouseX, mouseY)) {
b.pressed = true;
sendCmd(b.cmd);
}
}
}
void mouseReleased() {
for (Button b : buttons) b.pressed = false;
}
// ── Draw ──────────────────────────────────
void draw() {
background(BG);
displayAngle = lerp(displayAngle, servoAngle, 0.1);
drawHeader();
drawSensorCards();
drawServoCard();
drawOledCard();
drawButtons();
}
// ── Header ────────────────────────────────
void drawHeader() {
fill(CARD); noStroke();
rect(0, 0, width, 56);
fill(TEAL); rect(0, 0, 5, 56);
fill(WHITE); textSize(18); textAlign(LEFT, CENTER);
text("Fab Lab — DHT11 + Servo + OLED", 20, 28);
fill(connected ? GREEN : AMBER);
noStroke(); ellipse(width - 18, 28, 10, 10);
fill(MUTED); textSize(10); textAlign(RIGHT, CENTER);
text(portName, width - 32, 28);
textAlign(LEFT, TOP);
}
// ── Card base ──────────────────────────────
void cardBase(int x, int y, int w, int h, color accent) {
fill(CARD); stroke(BORDER); strokeWeight(0.5);
rect(x, y, w, h, 10);
fill(accent); noStroke();
rect(x, y + 8, 4, h - 16, 2);
}
void cardTitle(int x, int y, String label, color c) {
fill(c); textFont(mono); textSize(10); textAlign(LEFT, TOP);
text(label.toUpperCase(), x, y);
}
// ── Sensor cards ──────────────────────────
void drawSensorCards() {
drawValueCard(22, 102, 188, 180, "Humidity",
hasData ? nf(humidity,1,1) : "--", "%", BLUE,
humidity > 70 ? "HIGH" : (humidity < 30 ? "DRY" : "OK"),
humidity > 70 ? RED : (humidity < 30 ? AMBER : GREEN));
drawValueCard(222, 102, 188, 180, "Temperature",
hasData ? nf(tempC,1,1) : "--", "\u00b0C", TEAL,
tempC > 35 ? "HOT" : (tempC < 15 ? "COLD" : "OK"),
tempC > 35 ? RED : (tempC < 15 ? BLUE : GREEN));
drawValueCard(422, 102, 232, 180, "Temperature",
hasData ? nf(tempF,1,1) : "--", "\u00b0F", PURPLE,
tempF > 95 ? "HOT" : (tempF < 59 ? "COLD" : "OK"),
tempF > 95 ? RED : (tempF < 59 ? BLUE : GREEN));
}
void drawValueCard(int x, int y, int w, int h,
String label, String val, String unit,
color accent, String status, color statusCol) {
fill(CARD); stroke(BORDER); strokeWeight(0.5);
rect(x, y, w, h, 10);
fill(accent); noStroke();
rect(x, y+8, 4, h-16, 2);
fill(MUTED); textSize(10); textAlign(CENTER, TOP);
text(label, x+w/2, y+12);
fill(WHITE); textSize(40); textAlign(CENTER, CENTER);
text(val, x+w/2, y+h/2 - 8);
fill(accent); textSize(13); textAlign(CENTER, TOP);
text(unit, x+w/2, y+h/2+26);
fill(statusCol); noStroke();
rect(x+w/2-28, y+h-26, 56, 18, 9);
fill(BG); textSize(10); textAlign(CENTER, CENTER);
text(status, x+w/2, y+h-17);
textAlign(LEFT, TOP);
}
// ── Servo card ────────────────────────────
void drawServoCard() {
int x = 22, y = 294, w = 300, h = 160;
fill(CARD); stroke(BORDER); strokeWeight(0.5);
rect(x, y, w, h, 10);
fill(AMBER); noStroke();
rect(x, y+8, 4, h-16, 2);
fill(MUTED); textSize(10); textAlign(CENTER, TOP);
text("Servo — D9", x+w/2, y+12);
int cx = x+w/2, cy = y+118, r = 60;
// Track arc
stroke(BORDER); strokeWeight(2); noFill();
arc(cx, cy, r*2, r*2, PI, TWO_PI);
// Progress arc
stroke(AMBER); strokeWeight(4);
float endRad = map(displayAngle, 0, 180, PI, TWO_PI);
arc(cx, cy, r*2, r*2, PI, endRad);
// Needle
float rad = map(displayAngle, 0, 180, PI, TWO_PI);
stroke(WHITE); strokeWeight(2.5);
line(cx, cy, cx+cos(rad)*r, cy+sin(rad)*r);
fill(AMBER); noStroke(); ellipse(cx, cy, 9, 9);
// Angle labels
fill(MUTED); textSize(9); textAlign(CENTER, TOP);
text("0\u00b0", cx-r-4, cy+6);
text("180\u00b0", cx+r-8, cy+6);
// Degree readout
fill(WHITE); textFont(mono); textSize(22); textAlign(CENTER, TOP);
text(int(displayAngle)+"\u00b0", cx, cy+10);
// Status pill
color pc = servoOn ? GREEN : MUTED;
fill(pc); noStroke();
rect(cx-38, y+h-28, 76, 20, 10);
fill(BG); textSize(10); textAlign(CENTER, CENTER);
text(servoOn ? "SWEEPING" : "STOPPED", cx, y+h-18);
textAlign(LEFT, TOP);
}
// ── OLED preview ──────────────────────────
void drawOledCard() {
int x = 334, y = 294, w = 320, h = 160;
fill(CARD); stroke(BORDER); strokeWeight(0.5);
rect(x, y, w, h, 10);
fill(PURPLE); noStroke();
rect(x, y+8, 4, h-16, 2);
fill(MUTED); textSize(10); textAlign(CENTER, TOP);
text("OLED display preview", x+w/2, y+12);
// Screen
fill(8); stroke(PURPLE); strokeWeight(1);
rect(x+20, y+30, w-40, 76, 4);
noStroke();
// Screen content
fill(255); textFont(mono); textAlign(LEFT, TOP);
if (mode.equals("FabLab")) {
textSize(12); text("Hello", x+34, y+40);
textSize(16); text("Fab Lab!", x+28, y+60);
} else if (mode.equals("Humidity")) {
textSize(9); text("Humidity", x+52, y+34);
textSize(18); text(nf(humidity,1,1)+" %", x+28, y+58);
} else if (mode.equals("TempC")) {
textSize(9); text("Temperature · Celsius", x+28, y+34);
textSize(18); text(nf(tempC,1,1)+" C", x+28, y+56);
} else if (mode.equals("TempF")) {
textSize(9); text("Temperature · Fahrenheit", x+22, y+34);
textSize(18); text(nf(tempF,1,1)+" F", x+28, y+56);
} else if (mode.equals("Servo")) {
textSize(9); text("Servo Status", x+38, y+34);
textSize(16); text(servoOn ? "RUNNING" : "STOPPED", x+26, y+58);
}
// Mode badge
fill(PURPLE); noStroke();
rect(x+20, y+114, w-40, 18, 6);
fill(BG); textSize(9); textAlign(CENTER, CENTER);
text("MODE: " + mode.toUpperCase(), x+w/2, y+123);
textAlign(LEFT, TOP);
}
// ── Button row ────────────────────────────
void drawButtons() {
fill(MUTED); textFont(mono); textSize(10); textAlign(LEFT, CENTER);
text("CONTROLS", 22, 458);
for (Button b : buttons) b.draw();
}
// ── Button class ──────────────────────────
class Button {
String label;
char cmd;
color col;
int x, y, w, h;
boolean pressed = false;
Button(String label, char cmd, color col, int x, int y, int w, int h) {
this.label = label; this.cmd = cmd; this.col = col;
this.x = x; this.y = y; this.w = w; this.h = h;
}
boolean contains(int mx, int my) {
return mx >= x && mx <= x+w && my >= y && my <= y+h;
}
void draw() {
color fc = pressed ? lerpColor(col, WHITE, 0.3) : col;
fill(fc); noStroke();
rect(x, y, w, h, 8);
fill(0, 40); noStroke(); // bottom depth edge
rect(x, y+h-6, w, 6, 0, 0, 8, 8);
fill(BG); textFont(mono); textSize(12); textAlign(CENTER, CENTER);
text(label, x+w/2, y+h/2);
textAlign(LEFT, TOP);
}
}
Video demonstration
4.2) Additional individual assignment
Considerations:
- Purpose and functionality of the application
- UI and user interaction flow
- Communication between the application and the embedded board
- Block diagram with system architecture and data flow
- Communication protocol used
- Important parts of application and embedded code
- Wiring/connections between board and peripherals
- Real-time interaction, testing results, and final output
- Debugging process, challenges faced, and solutions
- Final reflection, learning outcomes, and future improvements
6. Real time interaction:
5) Final project advances
Devices
3D Print body boxes
Review the prototype and considering sharp dimensions
Review acrilic windows
Review waterproof boxes
6) Final results
- Linked to the group assignment page
- Documented your process
- Explained the UI that you made and how you did it
- Expalined hoy your application communicates with your embedded microcontroller board
- Explained any problems you encountered and how you solved them
- Include original source code (or a screenshot of the app code if that's not poosible)
- Include a hero shot of your application running & communicating with your board
7) References files
We learn how to Interface and Application Programming