/*
ESP32 Chuck Norris Jokes
by R. Pelayo
Tutorial: https://www.teachmemicro.com/esp32-restful-api
V1.0 - 10/27/2020
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <ArduinoJson.hpp>
const char* ssid = "ATT2PQv2U8";
const char* password = "PASSWORD"; // fill in password
String response = ""; //String for storing server response
JsonDocument myDoc;
// ------------------ Start U8g2 library and constructor ---------------------------------
#include "U8g2lib.h"
// Constructor for U8g2lib
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0);
// ------------------ Start generated bitmaps from image2cpp ---------------------------------
// 'Sunrise_Sunset_Icon', 16x16px
const unsigned char Sunrise_Sunset_Icon[] PROGMEM = { // 'PROGMEM" places this variable in Flash (32k) memory as opposed to SRAM (2k)
0x88, 0x00, 0x72, 0x02, 0x8c, 0x01, 0x05, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x05, 0x45,
0x8c, 0xc1, 0x72, 0xc2, 0x88, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x7c, 0xc0, 0x3f, 0x00, 0x0f
};
// 'Dad_Jokes_Icon', 16x16px
const unsigned char Dad_Jokes_Icon[] PROGMEM = {
0xc0, 0x03, 0x30, 0x0c, 0x0c, 0x30, 0x04, 0x20, 0x72, 0x4e, 0x22, 0x44, 0x01, 0x80, 0x01, 0x80,
0x01, 0x80, 0x19, 0x98, 0xf2, 0x4f, 0xe2, 0x47, 0x84, 0x21, 0x0c, 0x30, 0x30, 0x0c, 0xc0, 0x03
};
// 'Useless_Facts_Icon', 16x16px
const unsigned char Useless_Facts_Icon[] PROGMEM = {
0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x07,
0x80, 0x03, 0x87, 0x03, 0xcf, 0x01, 0xde, 0x01, 0xfc, 0x00, 0xf8, 0x00, 0x70, 0x00, 0x20, 0x00
};
// 'Quote_Icon', 16x16px
const unsigned char Quote_Icon[] PROGMEM = {
0xcf, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xc3, 0x00, 0xc3, 0x00, 0x86, 0x01, 0x0c, 0x03, 0x00, 0x00,
0x00, 0x00, 0xc0, 0xf3, 0xc0, 0xf3, 0xc0, 0xf3, 0x00, 0xc3, 0x00, 0xc3, 0x80, 0x61, 0xc0, 0x30
};
// 'Chuck_Icon_new', 16x16px
const unsigned char Chuck_Icon[] PROGMEM = {
0x00, 0x00, 0x42, 0x42, 0xa2, 0x45, 0x16, 0x68, 0xfc, 0x3f, 0x08, 0x10, 0x68, 0x16, 0x08, 0x10,
0x08, 0x11, 0x88, 0x11, 0x08, 0x10, 0xc8, 0x13, 0x28, 0x14, 0x08, 0x10, 0x50, 0x0a, 0xa0, 0x05
};
// Array of all icon bitmaps.
const unsigned char* menu_icon[5] = {
Sunrise_Sunset_Icon,
Dad_Jokes_Icon,
Useless_Facts_Icon,
Quote_Icon,
Chuck_Icon
};
// 'Boarder', 128x20px
const unsigned char Boarder[] PROGMEM = {
0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01
};
// 'Scroll Bar', 8x64px
const unsigned char Scroll_Bar[] PROGMEM = {
0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40
};
// 2D array of strings for menu items
const int NUM_ITEMS = 5;
char menu_item[NUM_ITEMS][20] = {
{"Sunrise Sunset"},
{"Dad Jokes"},
{"Useless Facts"},
{"Quotes"},
{"Chuck Jokes"}
};
// ------------------ End generated bitmaps from image2cpp ---------------------------------
// ------------------ Start OLED menu variables ---------------------------------
int item_sel_previous; // menu item before selected
int item_selected = 0; // selected menu item
int item_sel_next; // menu item after selected
#define BUTTON_UP_PIN 27 // pin for UP button
#define BUTTON_DOWN_PIN 26 // pin for DOWN button
#define BUTTON_SELECT_PIN 25 // pin for SELECT button
int button_up_clicked = 0; // only perform action when button is clicked, and wait until another press
int button_select_clicked = 0; // same as above
int button_down_clicked = 0; // same as above
int current_screen = 0; // 0 = menu, 1 = screenshot, 2 = qr
// ------------------ End OLED menu variables ---------------------------------
/* ----------------------- Start scrolling text variables ----------------------------- */
u8g2_uint_t offset; // current offset for the scrolling text
u8g2_uint_t width; // pixel width of the scrolling text (must be lesser than 128 unless U8G2_16BIT is defined
const char *text = "\"We could never learn to be brave and patient if there were only joy in the world.\" ";
/* ----------------------- End scrolling text variables ----------------------------- */
void setup(void) {
Serial.begin(9600);
/* ----------------------- Start WiFi connection ----------------------------- */
/*
WiFi.mode(WIFI_STA);
WiFi.begin("Wokwi-GUEST", "", 6);
//WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("WiFi connected with IP: ");
Serial.println(WiFi.localIP());
*/
/* ----------------------- End WiFi connection ----------------------------- */
/* ----------------------- Start u8g2 setup ----------------------------- */
u8g2.begin();
u8g2.setBitmapMode(1);
u8g2.setColorIndex(1); // set the color to white
/* ---------- Used for scrolling text ---------- */
u8g2.setFont(u8g2_font_10x20_mr);
width = u8g2.getUTF8Width(text);
u8g2.setFontMode(0); // enable transparent mode, which is faster
/* ------------------------ End u8g2 setup ------------------------------ */
/* ---------------- Button setup ----------------- */
pinMode(BUTTON_UP_PIN, INPUT_PULLUP); // up button
pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); // down button
pinMode(BUTTON_SELECT_PIN, INPUT_PULLUP); // select button
}
void loop(void) {
/* ----------------------- Start API menu ----------------------------- */
u8g2_uint_t x;
if (current_screen == 0) { // MENU SCREEN
if ((digitalRead(BUTTON_UP_PIN) == LOW) && (button_up_clicked == 0)) { // up button pressed
item_selected = item_selected - 1; // select previous item
button_up_clicked = 1; // set button to clicked to only perform the action once
if (item_selected < 0) { // if first item was selected, jump to last item
item_selected = NUM_ITEMS - 1;
}
}
if ((digitalRead(BUTTON_DOWN_PIN) == LOW) && (button_down_clicked == 0)) { // down button pressed
item_selected = item_selected + 1; // select next item
button_down_clicked = 1; // set button to clicked to only perform the action once
if (item_selected >= NUM_ITEMS) { // last item was selected, jump to first menu item
item_selected = 0;
}
}
if ((digitalRead(BUTTON_UP_PIN) == HIGH) && (button_up_clicked == 1)) { // unclick
button_up_clicked = 0;
}
if ((digitalRead(BUTTON_DOWN_PIN) == HIGH) && (button_down_clicked == 1)) { // unclick
button_down_clicked = 0;
}
}
// This section toggles through enter button selections by changing variable 'current_screen' value to 0, 1 or 2
if ((digitalRead(BUTTON_SELECT_PIN) == LOW) && (button_select_clicked == 0)) { // select button clicked, jump between screens
button_select_clicked = 1; // set button to clicked to only perform the action once
if (current_screen == 0) {current_screen = 1;} // menu items screen --> screenshots screen
else if (current_screen == 1) {current_screen = 2;} // screenshots screen --> qr codes screen
else {current_screen = 0;} // qr codes screen --> menu items screen
}
if ((digitalRead(BUTTON_SELECT_PIN) == HIGH) && (button_select_clicked == 1)) { // unclick
button_select_clicked = 0;
}
// set correct values for the previous and next items
item_sel_previous = item_selected - 1; // = 0 - 1 or -1
if (item_sel_previous < 0) { // Yes, -1 is < 0
item_sel_previous = NUM_ITEMS - 1; // NUM_ITEMS(4) - 1 = 3
}
item_sel_next = item_selected + 1; // = 0 + 1 or 1
if (item_sel_next >= NUM_ITEMS) { // No, 1 is not > 4
item_sel_next = 0; // next item would be after last = make it the first
}
u8g2.firstPage(); // required for page drawing, mode 1
do {
if (current_screen == 0) { // MENU SCREEN
// selected menu item boarder
u8g2.drawXBMP( 0, 22, 128, 20, Boarder);
// draw previous item as icon + label
u8g2.setFont(u8g2_font_7x14_tf);
u8g2.drawStr(26, 15, menu_item[item_sel_previous]);
// From top left corner - over, down, horz size, vert size)
// u8g2.drawXBMP(, over, down, horz, vert);
u8g2.drawXBMP(4, 2, 16, 16, menu_icon[item_sel_previous]);
// draw selected item as icon + label in bold font
u8g2.setFont(u8g2_font_7x14B_tf);
u8g2.drawStr(25, 37, menu_item[item_selected]);
u8g2.drawXBMP(4, 24, 16, 16, menu_icon[item_selected]);
// draw next item as icon + label
u8g2.setFont(u8g2_font_7x14_tf);
u8g2.drawStr(26, 59, menu_item[item_sel_next]);
u8g2.drawXBMP(4, 46, 16, 16, menu_icon[item_sel_next]);
// draw scrollbar background
u8g2.drawXBMP(120, 0, 8, 64, Scroll_Bar);
// draw scrollbar handle
u8g2.drawBox(125, 64/NUM_ITEMS * item_selected, 3, 64/NUM_ITEMS);
}
// ---------- Run 'Scrolling Quote' Test ----------
else if (current_screen == 1) { // MENU OPEN SCREEN
u8g2.firstPage();
do {
// draw the scrolling text at current offset
x = offset;
u8g2.setFont(u8g2_font_10x20_mr); // set the target font
do { // repeated drawing of the scrolling text...
u8g2.drawUTF8(x, 30, text); // draw the scolling text
x += width; // add the pixel width of the scrolling text
} while( x < u8g2.getDisplayWidth() ); // draw again until the complete display is filled
u8g2.setFont(u8g2_font_10x20_mr); // draw the current pixel width
u8g2.setCursor(0, 58);
u8g2.print(width); // this value must be lesser than 128 unless U8G2_16BIT is set
} while ( u8g2.nextPage() );
offset-=10; // scroll by one pixel
if ( (u8g2_uint_t)offset < (u8g2_uint_t)-width )
offset = 0; // start over again
}
else if (current_screen == 2) { // SUB MENU OPEN SCREEN
// Do something - "Display second item"
}
} while ( u8g2.nextPage() ); // required for page drawing, mode 1
/*
// -------- Start http request and response ----------
HTTPClient http; //Initiate HTTP client
//The API URL
String request = "https://api.chucknorris.io/jokes/random";
http.begin(request); //Start the request
http.GET(); //Use HTTP GET request
response = http.getString(); //Response from server
//Parse JSON, read error if any
DeserializationError error = deserializeJson(myDoc, response); // DeserializationError converts to boolean
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
}
else {
Serial.print(F("deserializeJson() passed: "));
Serial.println(error.f_str());
}
// Serial.println(response);
String value = myDoc["value"];
Serial.println(value);
//Print parsed value on Serial Monitor
//Serial.println(response["value"].as<char*>());
//Close connection
http.end();
//Wait two seconds for next joke
// -------- End http request and response ----------
*/
delay(1000);
}