182 lines
8.9 KiB
C++
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
|
|
}
|