Thermocouple-Mood-Reader/ThermoMood_Display.ino
2025-06-26 20:48:05 -04:00

182 lines
8.9 KiB
C++

// ThermoMood Display Integration (Circular Layout, Mood-Centric)
// Uses MAX6675 thermocouple and GC9A01A round TFT to display temperature-based moods
#include <max6675.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
// Thermocouple SPI pin definitions
#define SO_PIN D4
#define CS_PIN D5
#define SCK_PIN D6
MAX6675 thermocouple(SCK_PIN, CS_PIN, SO_PIN);
// TFT display pin definitions
#define TFT_DC D7
#define TFT_CS D10
#define TFT_RST D8
Adafruit_GC9A01A tft(TFT_CS, TFT_DC, TFT_RST);
// Track last displayed stable temperature
float lastDisplayedTemp = -999.0;
// Return background color based on mood content
uint16_t getMoodColor(const char* mood) {
if (strstr(mood, "alive") || strstr(mood, "Frozen")) return GC9A01A_NAVY;
if (strstr(mood, "spiraling") || strstr(mood, "low")) return GC9A01A_BLUE;
if (strstr(mood, "meh") || strstr(mood, "core")) return GC9A01A_DARKGREY;
if (strstr(mood, "deadline") || strstr(mood, "present")) return GC9A01A_ORANGE;
if (strstr(mood, "existential") || strstr(mood, "panic")) return GC9A01A_TEAL;
if (strstr(mood, "TIME FOR YOU") || strstr(mood, "martyr")) return GC9A01A_RED;
if (strstr(mood, "CRASHING OUT") || strstr(mood, "overheated")) return GC9A01A_MAROON;
return GC9A01A_PURPLE;
}
// Choose mood text based on input temperature (Fahrenheit)
const char* getMood(float tempF) {
if (tempF < 85) {
const char* moods[] = {
"Are you even alive?", "Frozen in apathy", "Intern from the underworld", "Just cold hands or cold heart?", "CRASHING OUT",
"Brain freeze, spiritually", "Free trial expired", "Skeletal operation mode", "Soul buffering...", "No warmth detected",
"Winter is inside me", "Heartbeat optional", "Frosty but functional", "Shivering in lowercase", "Glacial thoughts",
"Is this Antarctica?", "Sentient popsicle", "Emotionally glaciated", "Frozen screen vibes", "Zero serotonin detected",
"Warmth not found", "Arctic chill mode", "Cardiovascular snooze", "Tundra-core", "Respawning from cold storage"
};
return moods[random(0, 25)];
} else if (tempF < 88) {
const char* moods[] = {
"Quietly spiraling", "Coffee might help, but not really", "Low-power mode engaged", "Social battery: low", "Flatline on enthusiasm",
"Gray scale emotions", "Sad Mac beep", "Existence.exe lagging", "No spark, just static", "Barely breathing",
"Soft quitting reality", "Drained and dull", "Ghosting everyone (including self)", "Snooze mode IRL", "Dimly aware",
"Where is my will to vibe?", "Running on nostalgia", "Manual override failed", "Dark mode mind", "Internally buffering",
"Echo chamber of meh", "Empty inbox, empty heart", "Is this thing on?", "Caffeine = personality", "2% battery remaining"
};
return moods[random(0, 25)];
} else if (tempF < 90) {
const char* moods[] = {
"Classic cubicle-core", "Meh. Just meh.", "Functioning introvert mode", "Emotionally beige", "Dead inside, but on time",
"Mildly vibrating", "Calendar soul", "Background NPC energy", "Muted ambition", "Wednesday afternoon essence",
"Waiting for lunch", "Neutral and compliant", "Middle management mindset", "Auto-pilot enabled", "Email sent, soul left",
"One tab away from meltdown", "Performance review pending", "Just surviving", "At capacity", "Debugging existence",
"Snooze loop initiated", "Sleepwalking professionalism", "Deadpan default", "HR-safe chaos", "Corporate husk"
};
return moods[random(0, 25)];
} else if (tempF < 92) {
const char* moods[] = {
"One deadline away from losing it", "Focused panic detected", "Productivity-induced suffering", "Almost emotionally present", "Running on fumes",
"Stress-colored glasses on", "Thriving (but sarcastically)", "Too hot to handle deadlines", "Meetings are a fever dream", "Google Calendar warrior",
"Anxiously efficient", "Caffeinated dread", "Deadlines whispering", "Hyper-focus? Maybe.", "Did I send that email?",
"Frantically composed", "99 tabs open, 1 brain cell", "Ctrl+Alt+Stress", "Surviving on vibes & panic", "Deadline-driven drama",
"Multitasking disaster", "Red-alert mindstate", "Mental break loading...", "Rush hour upstairs", "Spicy brain activity"
};
return moods[random(0, 25)];
} else if (tempF < 94) {
const char* moods[] = {
"Buzzing with existential dread", "Running on caffeine and vibes", "Possibly unraveling", "Caffeinated and dangerous", "Deadline ninja",
"Thermally unhinged", "Mood: Keyboard smash", "Side questing thru life", "Out-of-office inside", "May implode soon",
"System overheating", "Productive chaos", "Brain jammed in 4th gear", "Screaming (internally)", "Manager ping anxiety",
"Ctrl+Z for life", "Power surge personality", "Ctrl+Shift+Survive", "Overclocking the soul", "Heavy emotional packet loss",
"Workload tsunami", "High temp, low chill", "Crashing in style", "This is fine.exe", "Stress-induced charisma"
};
return moods[random(0, 25)];
} else if (tempF < 96) {
const char* moods[] = {
"Overclocked human processor", "Might spontaneously combust", "TIME FOR YOU TO GO HOME", "Stop. Breathe. Panic again.", "Corporate martyr detected",
"Flame-retardant personality", "Data corrupted by stress", "Close to meltdown", "Break glass for emotional support", "Nearing brain boil",
"Meme-ing through pain", "Slack screaming", "Too hot to work", "Charcoal soul", "Emotional core dump",
"Danger zone entered", "Ping me never", "Deadlines are lava", "Executive dysfunction maxed", "Infernal to-do list",
"Crispy aura", "Drenched in digital sweat", "Mental fan spinning fast", "Update delayed due to fire", "Red-alert mode"
};
return moods[random(0, 25)];
} else {
const char* moods[] = {
"Go touch grass. Immediately.", "Check for open flames", "Thermally unstable coworker", "CRASHING OUT", "Return to sender (overheated)",
"Brain soup mode", "Sizzling regrets", "Ashes of motivation", "Permanent vacation (from logic)", "Doomscrolling the sun",
"Burnout bonanza", "Toxic heat signature", "Emotionally flambéed", "Sunburnt thoughts", "Smoking productivity",
"Human volcano", "Too late to chill", "Fahrenheit 404", "Internally toasted", "This meeting is a sauna",
"Excessive self-heating", "Crash cart required", "Too much vibe, not enough AC", "Flare-up in progress", "Hot mess express"
};
return moods[random(0, 25)];
}
}
void setup() {
Serial.begin(9600); // Start serial for debugging
delay(500);
tft.begin(); // Initialize TFT display
tft.setRotation(0);
tft.fillScreen(GC9A01A_BLACK); // Start with black screen
randomSeed(analogRead(A0)); // Seed RNG for mood randomness
}
void loop() {
static float lastStableTemp = -999;
static float tempSum = 0;
static int sampleCount = 0;
float tempF = thermocouple.readFahrenheit() - 7.0; // Read current temperature
tempSum += tempF;
sampleCount++;
// Average temp every 10 readings to reduce noise
if (sampleCount >= 10) {
float avgTemp = tempSum / sampleCount;
tempSum = 0;
sampleCount = 0;
// Only update display if temperature changes significantly
if (abs(avgTemp - lastStableTemp) >= 1.0) {
lastStableTemp = avgTemp;
const char* mood = getMood(avgTemp);
uint16_t moodColor = getMoodColor(mood);
Serial.print("Temp: "); Serial.print(avgTemp); Serial.print(" F | Mood: "); Serial.println(mood);
tft.fillScreen(moodColor); // Set background to mood color
tft.drawCircle(120, 120, 119, GC9A01A_BLACK); // Thin border ring
tft.drawCircle(120, 120, 118, GC9A01A_BLACK);
// Draw mood message, word-wrapped in center
tft.setTextColor(GC9A01A_WHITE);
tft.setTextSize(2);
int y = 100;
char buffer[128];
strncpy(buffer, mood, sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
char* line = strtok(buffer, " ");
String currentLine = "";
while (line != NULL) {
if (currentLine.length() + strlen(line) + 1 < 15) {
currentLine += line;
currentLine += " ";
} else {
int x = (240 - currentLine.length() * 12) / 2;
tft.setCursor(x, y);
tft.print(currentLine);
y += 20;
currentLine = String(line) + " ";
}
line = strtok(NULL, " ");
}
if (currentLine.length() > 0) {
int x = (240 - currentLine.length() * 12) / 2;
tft.setCursor(x, y);
tft.print(currentLine);
}
// Draw temperature at bottom
tft.setTextColor(GC9A01A_WHITE);
tft.setTextSize(2);
char tempStr[10];
sprintf(tempStr, "%d F", (int)avgTemp);
int tempWidth = strlen(tempStr) * 12;
int tempX = (240 - tempWidth) / 2;
tft.setCursor(tempX, 210);
tft.print(tempStr);
}
}
delay(500); // Sample delay
}