Skip to content

Commit 2b3175e

Browse files
committed
Added News_API example for Inkplate5
1 parent 7f6f70d commit 2b3175e

File tree

3 files changed

+392
-0
lines changed

3 files changed

+392
-0
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
Inkplate5_News_API example for Soldered Inkplate 5
3+
For this example you will need only a USB-C cable and Inkplate 5.
4+
Select "Soldered Inkplate5" from Tools -> Board menu.
5+
Don't have "Soldered Inkplate5" option? Follow our tutorial and add it:
6+
https://soldered.com/learn/add-inkplate-6-board-definition-to-arduino-ide/
7+
8+
This example will show you how you can use Inkplate 5 to display API data.
9+
Here we use News API to get headline news and short description and display
10+
them on the Inkplate screen. For this you will need an API key which you can obtain
11+
here: https://newsapi.org/
12+
On the Serial Monitor at 115200 baud rate, you can see what's happening.
13+
14+
IMPORTANT:
15+
Make sure to change your timezone and wifi credentials below.
16+
Also have ArduinoJson installed in your Arduino libraries, download here: https://arduinojson.org/
17+
18+
Want to learn more about Inkplate? Visit www.inkplate.io
19+
Looking to get support? Write on our forums: https://forum.soldered.com/
20+
29 March 2023 by Soldered
21+
*/
22+
23+
// Next 3 lines are a precaution, you can ignore those, and the example would also work without them
24+
#ifndef ARDUINO_INKPLATE5
25+
#error "Wrong board selection for this example, please select Soldered Inkplate5 in the boards menu."
26+
#endif
27+
28+
//---------- CHANGE HERE -------------:
29+
30+
// Put in your WiFi name (ssid) and password
31+
char ssid[] = "";
32+
char pass[] = "";
33+
char apiKey[] = ""; //You can obtain one here: https://newsapi.org/
34+
35+
// Delay between API calls in miliseconds (first 60 represents minutes so you can change to your need)
36+
// Here is set to 1 call per hour, but if you want to change it, have in mind that in the free plan there are only 100 free API calls
37+
#define DELAY_MS 60 * 60 * 1000
38+
39+
//-------------------------------------
40+
41+
// Include Inkplate library to the sketch
42+
#include "Inkplate.h"
43+
44+
// Our networking functions, declared in Network.cpp
45+
#include "Network.h"
46+
47+
// Include used fonts
48+
#include "Fonts/Inter12pt7b.h"
49+
#include "Fonts/GT_Pressura16pt7b.h"
50+
51+
// Create object with all networking functions
52+
Network network;
53+
54+
// Create display object
55+
Inkplate display(INKPLATE_1BIT);
56+
57+
void setup()
58+
{
59+
// Begin serial communitcation, sed for debugging
60+
Serial.begin(115200);
61+
62+
// Initial display settings
63+
display.begin(); // Init Inkplate library (you should call this function ONLY ONCE)
64+
display.setTextWrap(false);
65+
66+
// Our begin function
67+
network.begin(ssid, pass);
68+
69+
// Pointer to the struct that will hold all news data
70+
struct news *entities = NULL;
71+
72+
// Fetch news. If something went wrong the function returns NULL
73+
entities = network.getData(apiKey);
74+
if(entities == NULL)
75+
{
76+
Serial.println();
77+
Serial.println("Error fetching news");
78+
ESP.restart();
79+
}
80+
81+
// Draw the news and display it on the screen
82+
drawNews(entities);
83+
display.display();
84+
85+
// Go to sleep before checking again
86+
esp_sleep_enable_timer_wakeup(1000LL * DELAY_MS); // Set wakeup timer
87+
(void)esp_deep_sleep_start(); // Put ESP32 into deep sleep (this function returns nothing). Program stops here!
88+
}
89+
90+
void loop()
91+
{
92+
// Nothing! If you use deep sleep, whole program should be in setup() because each time the board restarts, not in a
93+
// loop()! loop() must be empty!
94+
}
95+
96+
// Function that draw the news
97+
void drawNews(struct news *entities)
98+
{
99+
uint8_t coll = 0; // For keeping track of columns
100+
uint16_t y = 32; // Y coordinate for drawing
101+
uint8_t rows = 0; // For keeping track of rows
102+
int i = 0; // For each piece of news
103+
104+
// Printing the news until we fill 3 columns
105+
// If an entire piece of news doesn't fit on the screen, don't print it
106+
while (coll < 2)
107+
{
108+
display.setCursor(10 + 320 * coll, y); // Set the cursor to the beginning of the current column
109+
display.setFont(&GT_Pressura16pt7b); // Set the font for the title
110+
uint16_t cnt = 0; // Index of each character in the title or description that is printing
111+
112+
// Let's print the title
113+
while (*(entities[i].title + cnt) != '\0')
114+
{
115+
// Go to the new line if needed
116+
if (display.getCursorX() > 320 * coll + 280 || (*(entities[i].title + cnt) == ' ' && display.getCursorX() > 320 * coll + 245))
117+
{
118+
*(entities[i].title + cnt) == ' ' ? cnt++ : 0;
119+
rows++;
120+
y += 32;
121+
display.setCursor(10 + 320 * coll, y);
122+
}
123+
124+
// Go to the next column if there is the end of the current one
125+
if (display.getCursorY() > E_INK_HEIGHT - 20)
126+
{
127+
coll++;
128+
y = 32;
129+
display.setCursor(10 + 320 * coll, y);
130+
}
131+
132+
// Print the text in the frame buffer in before calculated positions
133+
display.print(*(entities[i].title + cnt));
134+
cnt++;
135+
}
136+
137+
// Move the cursor a bit down and add indentation for the beginning of the sentence
138+
y = y + 40;
139+
display.setCursor(10 + 320 * coll, y);
140+
display.print(" ");
141+
142+
// Reset the counter
143+
cnt = 0;
144+
145+
// Set font for description and print description
146+
display.setFont(&Inter12pt7b);
147+
while (*(entities[i].description + cnt) != '\0')
148+
{
149+
// Go to the new line (row) if needed
150+
if (display.getCursorX() > 320 * coll + 280 || (*(entities[i].description + cnt) == ' ' && display.getCursorX() > 320 * coll + 255))
151+
{
152+
*(entities[i].description + cnt) == ' ' ? cnt++ : 0;
153+
rows++;
154+
y += 26;
155+
display.setCursor(10 + 320 * coll, y);
156+
}
157+
158+
// Go to the next column if there is the end of the current one
159+
if (display.getCursorY() > E_INK_HEIGHT - 20)
160+
{
161+
coll++;
162+
y = 32;
163+
display.setCursor(10 + 320 * coll, y);
164+
}
165+
166+
// Print the text in the frame buffer in before calculated positions
167+
display.print(*(entities[i].description + cnt));
168+
cnt++;
169+
}
170+
171+
// Add a bit of spacing between 2 news and go to the other piece of news
172+
y += 48;
173+
i++;
174+
}
175+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
Network.cpp
3+
Inkplate 5 Arduino library
4+
David Zovko, Borna Biro, Denis Vajak, Zvonimir Haramustek @ Soldered
5+
29 March 2023
6+
https://github.com/SolderedElectronics/Inkplate-Arduino-library
7+
8+
For support, please reach over forums: https://forum.soldered.com/
9+
For more info about the product, please check: www.inkplate.io
10+
11+
This code is released under the GNU Lesser General Public License v3.0: https://www.gnu.org/licenses/lgpl-3.0.en.html
12+
Please review the LICENSE file included with this example.
13+
If you have any questions about licensing, please contact [email protected]
14+
Distributed as-is; no warranty is given.
15+
*/
16+
17+
#include "Network.h"
18+
19+
// Connect Inkplate to the WiFi
20+
void Network::begin(char *ssid, char *pass)
21+
{
22+
// Initiating wifi, like in BasicHttpClient example
23+
WiFi.mode(WIFI_STA);
24+
WiFi.begin(ssid, pass);
25+
26+
int cnt = 0;
27+
Serial.print(F("Waiting for WiFi to connect..."));
28+
while ((WiFi.status() != WL_CONNECTED))
29+
{
30+
Serial.print(F("."));
31+
delay(1000);
32+
++cnt;
33+
34+
if (cnt == 20)
35+
{
36+
Serial.println("Can't connect to WIFI, restarting");
37+
delay(100);
38+
ESP.restart();
39+
}
40+
}
41+
Serial.println(F(" connected"));
42+
}
43+
44+
// Get data from the News API
45+
struct news* Network::getData(char *apiKey)
46+
{
47+
// Pointer to the struct where will be stored the news data
48+
struct news *ent = NULL;
49+
50+
// If not connected to wifi, reconnect wifi
51+
if (WiFi.status() != WL_CONNECTED)
52+
{
53+
WiFi.reconnect();
54+
delay(5000);
55+
56+
int cnt = 0;
57+
Serial.println(F("Waiting for WiFi to reconnect..."));
58+
while ((WiFi.status() != WL_CONNECTED))
59+
{
60+
// Prints a dot every second that wifi isn't connected
61+
Serial.print(F("."));
62+
delay(1000);
63+
++cnt;
64+
65+
// Restart after 7 times trying to reconnect
66+
if (cnt == 7)
67+
{
68+
Serial.println("Can't connect to WIFI, restart initiated.");
69+
delay(100);
70+
ESP.restart();
71+
}
72+
}
73+
}
74+
75+
// Allocate memory for data from API
76+
uint32_t n = 0;
77+
char *buf = (char *)ps_malloc(20000);
78+
if (buf == NULL)
79+
{
80+
Serial.println("Memory allocation failed");
81+
return NULL;
82+
}
83+
84+
// Making URL for GET request by adding the API key at the end
85+
char url[128];
86+
sprintf(url, "https://newsapi.org/v2/top-headlines?country=us&apiKey=%s", apiKey);
87+
88+
// Begin HTTP connection and send get request to the news api
89+
Serial.println("Loading buffer...");
90+
HTTPClient http;
91+
if (http.begin(url) && http.GET() > 0)
92+
{
93+
while (http.getStreamPtr()->available())
94+
{
95+
char c = http.getStreamPtr()->read();
96+
buf[n++] = c;
97+
}
98+
buf[n] = '\0';
99+
}
100+
Serial.println("The buffer is loaded completely");
101+
102+
// To proper deserialization, the buffer must start with {
103+
char *start = strstr(buf, "{");
104+
105+
// Dynamic Json from ArduinoJson library
106+
DynamicJsonDocument doc(20000);
107+
108+
// Deserialize JSON document
109+
DeserializationError error = deserializeJson(doc, start);
110+
111+
// Deserialize function takes data from the buffer so the buffer is no needed anymore
112+
free(buf);
113+
114+
// If there is no error and the status is ok, allocate memory for the news and store it
115+
if (!error && strcmp(doc["status"], "ok") == 0)
116+
{
117+
// Get the number of articles to fetch
118+
int n = doc["articles"].size();
119+
120+
// Allocate memory for n articles
121+
ent = (struct news*)ps_malloc(n * sizeof(struct news));
122+
if(ent == NULL)
123+
{
124+
// Return NULL to the main program if the memory isn't allocated successfully
125+
return NULL;
126+
}
127+
128+
// Go through each article and store information about it
129+
for(int i = 0; i < n; i++)
130+
{
131+
// Temporary pointers
132+
const char *temp_title = doc["articles"][i]["title"].as<const char*>();
133+
const char *temp_description = doc["articles"][i]["description"].as<const char*>();
134+
135+
// Copy values from temporary pointers to the main structure for news
136+
// If there is no title or description, store "\r\n"
137+
if (temp_title != NULL)
138+
{
139+
strcpy(ent[i].title, temp_title);
140+
}
141+
else
142+
{
143+
strcpy(ent[i].title, "\r\n");
144+
}
145+
146+
if (temp_description != NULL)
147+
{
148+
strcpy(ent[i].description, temp_description);
149+
}
150+
else
151+
{
152+
strcpy(ent[i].description, "\r\n");
153+
}
154+
}
155+
156+
// Print the message on the Serial Monitor
157+
Serial.print("Fetched ");
158+
Serial.print(n);
159+
Serial.println(" news");
160+
}
161+
else
162+
{
163+
// Print a message and return NULL if a deserialization error occurs
164+
Serial.println("Deserialization error");
165+
return NULL;
166+
}
167+
168+
// Clear the document and end http
169+
doc.clear();
170+
http.end();
171+
172+
// Return the pointer to the struct with the news
173+
return ent;
174+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Network.h
3+
Inkplate 5 Arduino library
4+
David Zovko, Borna Biro, Denis Vajak, Zvonimir Haramustek @ Soldered
5+
29 March 2023
6+
https://github.com/SolderedElectronics/Inkplate-Arduino-library
7+
8+
For support, please reach over forums: https://forum.soldered.com/
9+
For more info about the product, please check: www.inkplate.io
10+
11+
This code is released under the GNU Lesser General Public License v3.0: https://www.gnu.org/licenses/lgpl-3.0.en.html
12+
Please review the LICENSE file included with this example.
13+
If you have any questions about licensing, please contact [email protected]
14+
Distributed as-is; no warranty is given.
15+
*/
16+
17+
// Include needed libraries
18+
#include "Arduino.h"
19+
#include "ArduinoJson.h"
20+
#include "HTTPClient.h"
21+
#include "WiFi.h"
22+
#include "WiFiClientSecure.h"
23+
24+
// Struct for each piece of news
25+
struct news
26+
{
27+
char title[128];
28+
char description[1000];
29+
};
30+
31+
#ifndef NETWORK_H
32+
#define NETWORK_H
33+
34+
// All functions defined in Network.cpp
35+
class Network
36+
{
37+
public:
38+
// Functions we can access in main file
39+
void begin(char *ssid, char *pass);
40+
struct news* getData(char *apiKey);
41+
};
42+
43+
#endif

0 commit comments

Comments
 (0)