#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ArduinoJson.h>
#include <Adafruit_NeoPixel.h>
#define BUTTON_PIN 2
#define LED_PIN 13
#define LED_COUNT 1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
volatile bool buttonPressed = false;
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* csvUrl = "https://gist.githubusercontent.com/rloucks/a4ff97fc6f7964a43b82019882f18a36/raw/bebabbd1c922afad30fee522390c1861b70772b5/gistfile1.txt";
String cachedCSVData;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
void buttonISR() {
buttonPressed = true;
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
Serial.begin(9600);
connectToWiFi();
cacheCSVData();
}
void loop() {
display8Ball();
delay(100);
displayShakeAnimation();
waitForButtonPress();
display8Ball();
fetchAndDisplayData();
}
void connectToWiFi() {
Serial.println("Connecting to WiFi...");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.print("Connecting.");
display.display();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(".");
display.print(".");
display.display();
}
Serial.println("WiFi connected!");
}
void cacheCSVData() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.print("Filling the ball with sweet data");
display.display();
HTTPClient http;
http.begin(csvUrl);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
cachedCSVData = http.getString();
Serial.println("CSV data cached successfully.");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.print("All totes mcgoats!");
display.display();
delay(500);
} else {
Serial.println("Failed to cache CSV data.");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.print("Failed, Sadly");
display.display();
}
http.end();
}
void displayShakeAnimation() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 20);
display.println("Shake the 8Ball");
display.display();
rainbowCycle();
}
void waitForButtonPress() {
while (!buttonPressed) {
delay(10);
}
buttonPressed = false; // Reset flag
delay(100);
}
void fetchAndDisplayData() {
// Use the cached CSV data instead of fetching it from the server
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, cachedCSVData);
if (error) {
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str()); // Print error message to Serial Monitor
return;
}
JsonArray array = doc.as<JsonArray>();
int rowCount = array.size();
int randomIndex = random(0, rowCount);
JsonObject row = array[randomIndex];
String voice = row["Voice"].as<String>();
String mood = row["Mood"].as<String>();
String response = row["Response"].as<String>();
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 10);
display.println(voice);
display.println("Says:");
display.display();
delay(500);
if (mood == "Positive") {
fadePositive();
}
if (mood == "Negative") {
fadeNegative();
}
if (mood == "Neutral") {
fadeNeutral();
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(response);
display.display();
delay(15000);
}
void rainbowCycle() {
uint16_t i, j;
for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(10);
}
}
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
void fadeNegative() {
for (int i = 0; i <= 255; i++) {
uint32_t color = strip.Color(i, i / 2, 0); // Red to Orange gradient
strip.setPixelColor(0, color);
strip.show();
delay(10);
}
for (int i = 255; i >= 0; i--) {
uint32_t color = strip.Color(i, i / 2, 0); // Red to Orange gradient
strip.setPixelColor(0, color);
strip.show();
delay(10);
}
}
void fadePositive() {
for (int i = 0; i <= 255; i++) {
uint32_t color = strip.Color(0, i, 255 - i); // Green to Blue gradient
strip.setPixelColor(0, color);
strip.show();
delay(10);
}
for (int i = 255; i >= 0; i--) {
uint32_t color = strip.Color(0, i, 255 - i); // Green to Blue gradient
strip.setPixelColor(0, color);
strip.show();
delay(10);
}
}
void fadeNeutral() {
for (int i = 0; i <= 255; i++) {
uint32_t color = strip.Color(255, 255, i); // Yellow to Purple gradient
strip.setPixelColor(0, color);
strip.show();
delay(10);
}
for (int i = 255; i >= 0; i--) {
uint32_t color = strip.Color(255, 255, i); // Yellow to Purple gradient
strip.setPixelColor(0, color);
strip.show();
delay(10);
}
}
void display8Ball() { // Number of times to shake the 8ball
int shakeIterations = 5;
for (int i = 0; i < shakeIterations; i++) {
// Clear the display
display.clearDisplay();
// Draw the white circle representing the 8ball at different positions
display.fillCircle(SCREEN_WIDTH / 2 - 10, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / 2 - 2, SSD1306_WHITE);
// Draw a smaller black circle in the center
display.fillCircle(SCREEN_WIDTH / 2 - 10, SCREEN_HEIGHT / 2, (SCREEN_HEIGHT / 2) / 2, SSD1306_BLACK);
// Set the font size and color for the number 8
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
// Draw the number 8 in the center of the black circle
display.setCursor(SCREEN_WIDTH / 2 - 18, SCREEN_HEIGHT / 2 - 8);
display.print("8");
// Display the content
display.display();
// Delay to see the 8ball
delay(100);
// Clear the display
display.clearDisplay();
// Draw the white circle representing the 8ball at different positions
display.fillCircle(SCREEN_WIDTH / 2 + 10, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / 2 - 2, SSD1306_WHITE);
// Draw a smaller black circle in the center
display.fillCircle(SCREEN_WIDTH / 2 + 10, SCREEN_HEIGHT / 2, (SCREEN_HEIGHT / 2) / 2, SSD1306_BLACK);
// Set the font size and color for the number 8
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
// Draw the number 8 in the center of the black circle
display.setCursor(SCREEN_WIDTH / 2 - 2, SCREEN_HEIGHT / 2 - 8);
display.print("8");
// Display the content
display.display();
// Delay to see the 8ball
delay(100);
}
}