Skip to content

Commit ba4a93a

Browse files
committed
Merge branch 'dev'
2 parents 7694c29 + 658f018 commit ba4a93a

File tree

28 files changed

+7912
-2
lines changed

28 files changed

+7912
-2
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
Inkplate10 OpenAI Image slideshow
3+
Compatible with Soldered Inkplate 10
4+
5+
For this example you will need only USB cable and Inkplate 10.
6+
Select "Soldered Inkplate10" from Tools -> Board menu.
7+
Don't have "Soldered Inkplate10" option? Follow our tutorial and add it:https://soldered.com/documentation/inkplate/10/quick-start-guide/
8+
9+
Overview:
10+
This example demonstrates how to send a prompt to the GPT DALL-E API in order to generate an image which will be displayed on the Inkplate
11+
It generates an image every 30mins, after which it goes to deep sleep.
12+
13+
Before You Start:
14+
- Enter your WiFi credentials carefully (they are case-sensitive).
15+
- After creating an OpenAI API key, enter it in the openai_key variable
16+
*/
17+
18+
#include <WiFiClientSecure.h> // Enables secure (HTTPS) communication over WiFi
19+
#include <ArduinoJson.h> // Library for JSON parsing and creation
20+
#include "Inkplate.h" // Driver for the Inkplate e-paper display
21+
22+
// Time in minutes the device will sleep between updates (30 mins in this case)
23+
#define SLEEP_DURATION_IN_MINS 30*60
24+
25+
// Format of the image to be downloaded and displayed (PNG is recommended for best compatibility)
26+
Image::Format imageFormat = Image::PNG;
27+
28+
// WiFi credentials (replace with your own SSID and password)
29+
const char* ssid = "YOUR_SSID_HERE";
30+
const char* password = "YOUR_PASSWORD_HERE";
31+
32+
// OpenAI API key (replace with your OpenAI API key)
33+
const char* openai_key = "YOUR_API_KEY_HERE";
34+
35+
36+
// Create a secure WiFi client to communicate with OpenAI over HTTPS
37+
WiFiClientSecure client;
38+
39+
// Create an Inkplate display object (1-bit mode = faster, lower-power updates)
40+
Inkplate display(INKPLATE_1BIT);
41+
42+
// Set the image prompt to send to OpenAI
43+
String imagePrompt = "Generate a cyberpunk city with a lot of vertical layers";
44+
45+
void setup() {
46+
display.begin(); // Initialize the Inkplate hardware and begin communication
47+
48+
Serial.begin(115200); // Start serial communication for debugging
49+
50+
display.setTextSize(3); // Set text size for on-screen messages
51+
52+
// Display message while attempting to connect to WiFi
53+
display.print("Connecting to WiFi...");
54+
WiFi.begin(ssid, password);
55+
while (WiFi.status() != WL_CONNECTED) {
56+
delay(500); // Wait and retry
57+
display.print("."); // Show progress
58+
display.partialUpdate(); // Update only the changed part of the screen for speed
59+
}
60+
61+
// WiFi connection successful
62+
display.println("\nConnected!");
63+
display.display(); // Push display buffer to screen
64+
display.clearDisplay(); // Clear the screen for next display content
65+
66+
// Notify the user on the display
67+
display.println("Generating prompt...");
68+
display.partialUpdate(); // Show message quickly
69+
70+
// Call function to get image URL from OpenAI based on the prompt
71+
String imageUrl = getImageUrlFromPrompt(imagePrompt);
72+
73+
display.println("Prompt generated!");
74+
display.partialUpdate(); // Update message after URL is fetched
75+
76+
// Switch display to 3-bit grayscale mode for higher image quality
77+
// WARNING: Partial updates are not supported in this mode!
78+
display.setDisplayMode(INKPLATE_3BIT);
79+
display.setTextColor(BLACK);
80+
display.println("Downloading and displaying image (May take a while...)");
81+
display.display(); // Show status
82+
display.clearDisplay(); // Clear screen before showing the image
83+
84+
if (imageUrl != "") {
85+
Serial.println("Image URL: " + imageUrl);
86+
87+
// Draw the image centered on the screen
88+
// Image assumed to be 1024x1024; offset to center it
89+
bool result = display.drawImage(imageUrl, imageFormat, display.width()/2 - 512, display.height()/2 - 512, true, false);
90+
91+
if(result == 0) {
92+
// Show an error if image decoding fails
93+
display.println("Image decode error.");
94+
}
95+
96+
display.display(); // Push image to display
97+
}
98+
else {
99+
// Show an error message if the image URL wasn't retrieved
100+
display.println("Failed to get image URL.");
101+
display.display();
102+
}
103+
104+
// Schedule the next wakeup time using the real-time clock
105+
display.rtcSetAlarmEpoch(display.rtcGetEpoch() + SLEEP_DURATION_IN_MINS, RTC_ALARM_MATCH_DHHMMSS);
106+
107+
// Enable external wakeup on GPIO 39 (typically tied to RTC alarm)
108+
esp_sleep_enable_ext0_wakeup(GPIO_NUM_39, 0);
109+
110+
// Enter deep sleep mode to conserve power
111+
esp_deep_sleep_start();
112+
}
113+
114+
void loop() {
115+
// This loop will never run because device goes into deep sleep after setup()
116+
}
117+
118+
// Sends the image prompt to OpenAI's DALL·E endpoint and extracts the image URL
119+
String getImageUrlFromPrompt(String prompt)
120+
{
121+
client.setInsecure(); // Disable certificate validation (OK for dev/test, not secure for prod)
122+
123+
// Attempt to connect to OpenAI's server
124+
if (!client.connect("api.openai.com", 443)) {
125+
Serial.println("Connection to OpenAI for image failed!");
126+
return "";
127+
}
128+
129+
// Create JSON request body
130+
DynamicJsonDocument doc(1024);
131+
doc["model"] = "dall-e-3"; //GPT model we are using, delete this line to use DALL-E 2
132+
doc["prompt"] = prompt;
133+
doc["style"] = "vivid";
134+
doc["n"] = 1;
135+
doc["size"] = "1024x1024"; // or 1792x1024, 1024x1792
136+
137+
String requestBody;
138+
serializeJson(doc, requestBody); // Convert JSON object to string
139+
140+
// Compose and send HTTPS POST request
141+
client.println("POST /v1/images/generations HTTP/1.1");
142+
client.println("Host: api.openai.com");
143+
client.println("Authorization: Bearer " + String(openai_key)); // Add API key to header
144+
client.println("Content-Type: application/json");
145+
client.print("Content-Length: ");
146+
client.println(requestBody.length());
147+
client.println("Connection: close");
148+
client.println();
149+
client.println(requestBody);
150+
151+
// Wait up to 40 seconds for a response
152+
unsigned long timeout = millis();
153+
while (!client.available() && millis() - timeout < 40000) {
154+
delay(100);
155+
}
156+
157+
// Timeout handling
158+
if (!client.available()) {
159+
Serial.println("OpenAI image request timed out.");
160+
return "";
161+
}
162+
163+
// Skip over HTTP response headers
164+
while (client.connected()) {
165+
String line = client.readStringUntil('\n');
166+
if (line == "\r") break; // End of headers
167+
}
168+
169+
// Read the HTTP response body
170+
String response = client.readString();
171+
Serial.println("Response:");
172+
Serial.println(response);
173+
174+
// Parse JSON response to extract image URL
175+
DynamicJsonDocument resDoc(4096);
176+
DeserializationError err = deserializeJson(resDoc, response);
177+
if (err) {
178+
Serial.print("Image JSON parse failed: ");
179+
Serial.println(err.c_str());
180+
return "";
181+
}
182+
183+
// Extract and return the first image URL from the response
184+
if (resDoc["data"] && resDoc["data"][0]["url"]) {
185+
String url = resDoc["data"][0]["url"].as<String>();
186+
return url;
187+
}
188+
189+
Serial.println("No image URL found in OpenAI response");
190+
return ""; // Return empty string if no image URL was found
191+
}

0 commit comments

Comments
 (0)