#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <IRremote.h> // Include the IRremote library
// Initialize the LCD with the I2C address and dimensions
LiquidCrystal_I2C lcd(0x27, 16, 2); // 16 columns, 2 rows
const char* ssid = "Wokwi-GUEST";
const char* password = "";
int apiKeyIndex = 0; // API key index
String Gemini_Token = ""; // Current API key
int Gemini_Max_Tokens = 100; // Max tokens
String res = "";
// Define the IR Receiver pin
#define IR_RECEIVE_PIN 23
// Button hex codes and their functionalities
#define BUTTON_POWER 0x5DA2FF00 // Power button - LCD Backlight toggle
#define BUTTON_VOL_UP 0xFD02FF00 // Volume Up - Increase Max Tokens
#define BUTTON_VOL_DOWN 0x6798FF00 // Volume Down - Decrease Max Tokens
#define BUTTON_TEST 0xDD22FF00 // Play/Pause - Ask predefined question
#define BUTTON_NEXT 0x3DC2FF00 // Next - Wi-Fi reconnect
#define BUTTON_OK 0xFFE01F // OK button - Display Wi-Fi status
#define BUTTON_UP 0xFFA857 // Up - System restart
#define BUTTON_C 0x1DE2FF00 // Down - Display IP address
#define BUTTON_5 0xC738FF00 // Button "5" - Change API key
// Array of 5 API keys (insert your API keys here)
String apiKeys[] = {
"AIzaSyDcZCwcKgmtcRPkiH3E5ejkWfN97BkkzNs",
"AIzaSyCTIY_A8KLsG_A5cijWNix9ID0Dgnj1WVA",
"AIzaSyAWpBK4FaGCBfuAOSvyqVnzC2hoNFw3y0Q",
"AIzaSyAd-D8JJNf0Bowl7XdEIadHo8WBiksFxVE",
"AIzaSyA9DTf8BfUGI0u0TTDz7SW1RH0XWHnZ-P4"
};
const int numApiKeys = sizeof(apiKeys) / sizeof(apiKeys[0]);
// Predefined question for BUTTON_TEST
String predefinedQuestion = "Tell me a joke.";
void setup() {
Serial.begin(115200);
// Initialize the LCD
lcd.init();
lcd.backlight();
// Display startup message
lcd.setCursor(0, 0);
lcd.print("Connecting to");
lcd.setCursor(0, 1);
lcd.print(ssid);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
// Wait for Wi-Fi connection
WiFi.begin(ssid, password);
Serial.print("Connecting to ");
Serial.println(ssid);
int count = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
lcd.setCursor(count % 16, 1); // Create a loading effect
lcd.print(".");
count++;
}
Serial.println("\nConnected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Display IP address on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Connected");
lcd.setCursor(0, 1);
lcd.print("IP:");
lcd.print(WiFi.localIP());
delay(2000); // Pause to display IP
lcd.clear();
// Initialize IR receiver
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); // Initialize IR receiver
// Set the initial API key
Gemini_Token = apiKeys[apiKeyIndex];
}
void loop() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Press Remote");
Serial.println("\nWaiting for IR input...");
// Wait for IR input
while (!IrReceiver.decode()) {
delay(100);
}
uint32_t code = IrReceiver.decodedIRData.decodedRawData;
IrReceiver.resume(); // Ready to receive the next value
// Take action based on button code
if (code == BUTTON_POWER) {
// Toggle LCD backlight
static bool backlightOn = true;
backlightOn = !backlightOn;
if (backlightOn) {
lcd.backlight();
} else {
lcd.noBacklight();
}
Serial.println("LCD Backlight toggled.");
}
else if (code == BUTTON_VOL_UP) {
// Increase Max Tokens
Gemini_Max_Tokens += 10;
if (Gemini_Max_Tokens > 4000) Gemini_Max_Tokens = 4000; // Max limit
Serial.print("Max Tokens increased to: ");
Serial.println(Gemini_Max_Tokens);
lcd.clear();
lcd.print("Max Tokens: ");
lcd.print(Gemini_Max_Tokens);
delay(2000);
}
else if (code == BUTTON_VOL_DOWN) {
// Decrease Max Tokens
Gemini_Max_Tokens -= 10;
if (Gemini_Max_Tokens < 10) Gemini_Max_Tokens = 10; // Min limit
Serial.print("Max Tokens decreased to: ");
Serial.println(Gemini_Max_Tokens);
lcd.clear();
lcd.print("Max Tokens: ");
lcd.print(Gemini_Max_Tokens);
delay(2000);
}
else if (code == BUTTON_TEST) {
// Ask predefined question
askQuestion(predefinedQuestion);
}
else if (code == BUTTON_NEXT) {
// Reconnect to Wi-Fi
WiFi.disconnect();
WiFi.begin(ssid, password);
Serial.println("Reconnecting to Wi-Fi...");
lcd.clear();
lcd.print("Reconnecting WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
lcd.print(".");
}
Serial.println("\nReconnected");
lcd.clear();
lcd.print("WiFi Reconnected");
delay(2000);
}
else if (code == BUTTON_OK) {
// Display Wi-Fi status
lcd.clear();
lcd.print("WiFi Status:");
lcd.setCursor(0, 1);
if (WiFi.status() == WL_CONNECTED) {
lcd.print("Connected");
} else {
lcd.print("Disconnected");
}
delay(2000);
}
else if (code == BUTTON_UP) {
// Restart system
Serial.println("Restarting system...");
lcd.clear();
lcd.print("Restarting...");
delay(2000);
ESP.restart();
}
else if (code == BUTTON_C) {
// Display IP address
lcd.clear();
lcd.print("IP Address:");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
delay(3000);
}
else if (code == BUTTON_5) {
// Change API key
apiKeyIndex = (apiKeyIndex + 1) % numApiKeys;
Gemini_Token = apiKeys[apiKeyIndex];
Serial.print("API Key changed to index: ");
Serial.println(apiKeyIndex);
lcd.clear();
lcd.print("API Key Changed");
delay(2000);
}
else {
// Unknown code
Serial.print("Unknown IR code received: 0x");
Serial.println(code, HEX);
lcd.clear();
lcd.print("Unknown code");
delay(2000);
}
}
void askQuestion(String question) {
res = "\"" + question + "\"";
Serial.println("\nAsking Question: ");
Serial.println(question);
// Display sending status on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Sending...");
lcd.setCursor(0, 1);
if (question.length() <= 16) {
lcd.print(question);
} else {
lcd.print(question.substring(0, 16));
}
HTTPClient https;
if (https.begin("https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=" + Gemini_Token)) {
https.addHeader("Content-Type", "application/json");
String payload = String("{\"contents\": [{\"parts\":[{\"text\":" + res + "}]}],\"generationConfig\": {\"maxOutputTokens\": " + String(Gemini_Max_Tokens) + "}}");
int httpCode = https.POST(payload);
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String response = https.getString();
DynamicJsonDocument doc(8192); // Adjust JSON document size as needed
deserializeJson(doc, response);
String Answer = doc["candidates"][0]["content"]["parts"][0]["text"];
Answer.trim();
Serial.println("\nHere is your Answer: ");
Serial.println(Answer);
// Display the answer on the LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Answer:");
// Scroll the answer if it's too long
if (Answer.length() <= 16) {
lcd.setCursor(0, 1);
lcd.print(Answer);
} else {
for (int i = 0; i <= Answer.length() - 16; i++) {
lcd.setCursor(0, 1);
lcd.print(Answer.substring(i, i + 16));
delay(300); // Adjust scrolling speed
}
delay(2000);
}
} else {
Serial.printf("[HTTPS] POST... failed, error: %s\n", https.errorToString(httpCode).c_str());
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error:");
lcd.setCursor(0, 1);
lcd.print(https.errorToString(httpCode).c_str());
delay(2000);
}
https.end();
} else {
Serial.println("[HTTPS] Unable to connect");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Unable to");
lcd.setCursor(0, 1);
lcd.print("connect");
delay(2000);
}
res = "";
delay(1000);
}