Skip to content

Commit aa6e255

Browse files
committed
added 5v2 examples
1 parent b65d952 commit aa6e255

File tree

25 files changed

+2909
-8
lines changed

25 files changed

+2909
-8
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/**
2+
**************************************************
3+
*
4+
* @file BluetoothSerial.ino
5+
* @brief Example showing how to use Bluetooth Serial on Inkplate 5V2
6+
* with an LVGL-based UI that safely renders incoming text.
7+
*
8+
* HOW TO USE
9+
* - Upload this example to Inkplate 5V2.
10+
* - Pair your phone with the device in Bluetooth settings (device name: "Inkplate6").
11+
* - Open a Serial Bluetooth Terminal app (or similar) and connect to "Inkplate6".
12+
* - Anything you type in the app will be shown on the Inkplate screen.
13+
* - Anything you type in the Arduino Serial Monitor will be sent to the phone.
14+
*
15+
*
16+
* For setup instructions and more information about Inkplate 5V2, visit:
17+
* https://soldered.com/documentation/inkplate/5v2/overview/
18+
*
19+
* @authors Soldered
20+
* @date November 2025
21+
**************************************************
22+
*/
23+
24+
#if !defined(ARDUINO_ESP32_DEV) && !defined(ARDUINO_INKPLATE6V2)
25+
#error "Wrong board selection for this example, please select e-radionica Inkplate6 or Soldered Inkplate6 in the boards menu."
26+
#endif
27+
28+
#include <Inkplate-LVGL.h>
29+
#include <BluetoothSerial.h>
30+
31+
static const char *btDeviceName = "Inkplate6";
32+
33+
Inkplate inkplate(INKPLATE_1BIT);
34+
BluetoothSerial SerialBT;
35+
36+
// ---------- Font helpers (use LV_FONT_DEFAULT only) ----------
37+
static const lv_font_t* font_big() { return LV_FONT_DEFAULT; }
38+
static const lv_font_t* font_small() { return LV_FONT_DEFAULT; }
39+
40+
// ---------- LVGL helpers ----------
41+
static inline int dispW() {
42+
lv_display_t *d = lv_display_get_default();
43+
return lv_display_get_horizontal_resolution(d);
44+
}
45+
static inline int dispH() {
46+
lv_display_t *d = lv_display_get_default();
47+
return lv_display_get_vertical_resolution(d);
48+
}
49+
50+
static int lineHeight(const lv_font_t *f) {
51+
#if LVGL_VERSION_MAJOR >= 9
52+
return lv_font_get_line_height(f);
53+
#else
54+
// Approximate default font line height for LVGL v8 if API is unavailable
55+
return 18;
56+
#endif
57+
}
58+
59+
static void make_opaque(lv_obj_t *obj) {
60+
lv_obj_set_style_bg_color(obj, lv_color_hex(0xFFFFFF), 0);
61+
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
62+
lv_obj_set_style_border_width(obj, 0, 0);
63+
}
64+
65+
// ---------- UI elements ----------
66+
static lv_obj_t *label_title = nullptr;
67+
static lv_obj_t *label_info = nullptr;
68+
static lv_obj_t *panel_log = nullptr;
69+
static lv_obj_t *label_log = nullptr;
70+
71+
// Spacing
72+
static const int INFO_LINE_SPACE = 4;
73+
static const int LOG_LINE_SPACE = 6;
74+
static const int topMargin = 8;
75+
static const int leftMargin = 8;
76+
static const int rightMargin = 8;
77+
78+
// Log state
79+
static String logText;
80+
static int maxLines = 0;
81+
static int usedLines = 0;
82+
83+
static void ui_create() {
84+
// Screen background
85+
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0xFFFFFF), LV_PART_MAIN);
86+
87+
// Title
88+
label_title = lv_label_create(lv_screen_active());
89+
lv_obj_set_style_text_color(label_title, lv_color_hex(0x000000), 0);
90+
lv_obj_set_style_text_font(label_title, font_big(), 0);
91+
lv_label_set_text(label_title, "Bluetooth Serial Example");
92+
lv_obj_set_pos(label_title, leftMargin, topMargin);
93+
make_opaque(label_title);
94+
95+
// Instructions
96+
label_info = lv_label_create(lv_screen_active());
97+
lv_obj_set_style_text_color(label_info, lv_color_hex(0x000000), 0);
98+
lv_obj_set_style_text_font(label_info, font_small(), 0);
99+
lv_label_set_long_mode(label_info, LV_LABEL_LONG_WRAP);
100+
lv_obj_set_style_text_line_space(label_info, INFO_LINE_SPACE, 0);
101+
int infoY = topMargin + lineHeight(font_big()) + 8;
102+
lv_obj_set_pos(label_info, leftMargin, infoY);
103+
lv_obj_set_width(label_info, dispW() - leftMargin - rightMargin);
104+
lv_label_set_text(label_info,
105+
"Pair your phone and open a Serial Bluetooth Terminal.\n"
106+
"Messages from phone appear below.\n"
107+
"USB Serial -> phone is also forwarded.\n");
108+
make_opaque(label_info);
109+
110+
// Ensure layout is computed before measuring info height
111+
lv_timer_handler();
112+
#if LVGL_VERSION_MAJOR >= 9
113+
lv_obj_update_layout(label_info);
114+
#endif
115+
int infoBottom = lv_obj_get_y(label_info) + lv_obj_get_height(label_info);
116+
117+
// Opaque log panel below the instructions
118+
panel_log = lv_obj_create(lv_screen_active());
119+
make_opaque(panel_log);
120+
lv_obj_set_style_pad_all(panel_log, 0, 0);
121+
lv_obj_set_style_border_width(panel_log, 0, 0);
122+
int panelX = leftMargin;
123+
int panelY = infoBottom + 10;
124+
int panelW = dispW() - leftMargin - rightMargin;
125+
int panelH = dispH() - panelY - topMargin;
126+
lv_obj_set_pos(panel_log, panelX, panelY);
127+
lv_obj_set_size(panel_log, panelW, panelH);
128+
129+
// Log label inside the panel
130+
label_log = lv_label_create(panel_log);
131+
lv_obj_set_style_text_color(label_log, lv_color_hex(0x000000), 0);
132+
lv_obj_set_style_text_font(label_log, font_small(), 0);
133+
lv_label_set_long_mode(label_log, LV_LABEL_LONG_WRAP);
134+
lv_obj_set_style_text_line_space(label_log, LOG_LINE_SPACE, 0);
135+
lv_obj_set_pos(label_log, 0, 0);
136+
lv_obj_set_width(label_log, panelW);
137+
138+
// Compute how many lines fit into the panel
139+
int effLineH = lineHeight(font_small()) + LOG_LINE_SPACE;
140+
maxLines = (effLineH > 0) ? (panelH / effLineH) : 0;
141+
if (maxLines < 3) maxLines = 3; // safety minimum
142+
}
143+
144+
static void ui_reset_log_full_refresh() {
145+
// Rebuild the entire UI and perform a full refresh (avoids ghosting)
146+
lv_obj_clean(lv_screen_active());
147+
logText = "";
148+
usedLines = 0;
149+
ui_create();
150+
151+
lv_tick_inc(10);
152+
lv_timer_handler();
153+
inkplate.display(); // FULL
154+
}
155+
156+
static void log_append_char(char c) {
157+
if (c == '\r') return;
158+
159+
if (c == '\n') {
160+
logText += '\n';
161+
usedLines++;
162+
} else {
163+
logText += c;
164+
}
165+
166+
if (usedLines >= maxLines) {
167+
ui_reset_log_full_refresh();
168+
return;
169+
}
170+
171+
lv_label_set_text(label_log, logText.c_str());
172+
173+
// Partial refresh for faster updates; opaque panel removes old pixels
174+
lv_tick_inc(5);
175+
lv_timer_handler();
176+
inkplate.partialUpdate();
177+
}
178+
179+
void setup() {
180+
Serial.begin(115200);
181+
inkplate.begin(LV_DISP_RENDER_MODE_PARTIAL);
182+
183+
ui_create();
184+
185+
// Initial full refresh to clear any boot artifacts
186+
lv_tick_inc(20);
187+
lv_timer_handler();
188+
inkplate.display();
189+
190+
// Start Bluetooth
191+
if (!SerialBT.begin(btDeviceName)) {
192+
const char *err = "Bluetooth init ERROR";
193+
for (const char *p = err; *p; ++p) log_append_char(*p);
194+
log_append_char('\n');
195+
} else {
196+
const char *ok1 = "BT ready. Pair and connect.";
197+
for (const char *p = ok1; *p; ++p) log_append_char(*p);
198+
log_append_char('\n');
199+
log_append_char('\n'); // extra spacing before user messages
200+
}
201+
}
202+
203+
void loop() {
204+
// USB Serial -> Bluetooth
205+
while (Serial.available()) {
206+
char c = (char)Serial.read();
207+
SerialBT.write((uint8_t)c);
208+
}
209+
210+
// Bluetooth -> screen + echo to USB Serial
211+
while (SerialBT.available()) {
212+
char c = (char)SerialBT.read();
213+
Serial.write((uint8_t)c);
214+
log_append_char(c);
215+
}
216+
217+
lv_tick_inc(5);
218+
lv_timer_handler();
219+
delay(20);
220+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
**************************************************
3+
*
4+
* @file Qwiic.ino
5+
* @brief Example demonstrating easyC/Qwiic (I2C) communication between Inkplate 5V2 and
6+
* a Soldered BME280 or BME680 environmental sensor, using the LVGL library
7+
* for display rendering.
8+
*
9+
* This example reads temperature, humidity, and pressure data from a
10+
* Soldered BME280 sensor connected via the easyC interface and displays
11+
* it on the Inkplate 5V2 e-paper screen using LVGL elements.
12+
*
13+
* Note: Both BME280 and BME680 sensors are supported by the same
14+
* Soldered BME280/BME680 library. In this example, the BME280 is used,
15+
* as defined in the code. The sensor communicates over easyC (I2C)
16+
* using the default 0x76 address.
17+
*
18+
* For setup instructions and more information about Inkplate 5V2, visit:
19+
* https://soldered.com/documentation/inkplate/5v2/overview/
20+
*
21+
* @hardware Inkplate 5V2 (ESP32-based e-paper display)
22+
* @sensors Soldered BME280 (or BME680) via easyC connector
23+
* @library Soldered BME280/BME680 Gas Sensor Arduino Library
24+
* https://github.com/SolderedElectronics/Soldered-BME280-BME680-Gas-Sensor-Arduino-Library
25+
*
26+
* @authors Soldered
27+
* @date November 2025
28+
**************************************************
29+
*/
30+
31+
32+
#if !defined(ARDUINO_ESP32_DEV) && !defined(ARDUINO_INKPLATE6V2)
33+
#error "Wrong board selection for this example, please select e-radionica Inkplate6 or Soldered Inkplate6 in the boards menu."
34+
#endif
35+
36+
#include <Inkplate-LVGL.h>
37+
#include <BME280-SOLDERED.h> // Soldered BME280/BME680 library (easyC/I2C)
38+
39+
// Inkplate in 1-bit mode (fast partial updates)
40+
Inkplate inkplate(INKPLATE_1BIT);
41+
BME280 bme280; // easyC/I2C (Soldered uses 0x76)
42+
43+
// Optional temperature calibration offset
44+
const float TEMPERATURE_OFFSET = 0.0f;
45+
46+
// UI elements
47+
static lv_obj_t *panel_data;
48+
static lv_obj_t *lbl_title;
49+
static lv_obj_t *lbl_temp;
50+
static lv_obj_t *lbl_hum;
51+
static lv_obj_t *lbl_press;
52+
static lv_obj_t *lbl_warn;
53+
54+
// Refresh policy (do a FULL every ~20 partials)
55+
static int partialCount = 0;
56+
static const int FULL_REFRESH_EVERY = 20;
57+
58+
// Helpers
59+
static inline int dispW() { auto *d = lv_display_get_default(); return lv_display_get_horizontal_resolution(d); }
60+
static inline int dispH() { auto *d = lv_display_get_default(); return lv_display_get_vertical_resolution(d); }
61+
62+
static void make_opaque(lv_obj_t *obj) {
63+
lv_obj_set_style_bg_color(obj, lv_color_hex(0xFFFFFF), 0);
64+
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
65+
lv_obj_set_style_border_width(obj, 0, 0);
66+
}
67+
68+
// Minimal LVGL UI (no GFX icons to keep it LVGL-only)
69+
static void ui_create() {
70+
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0xFFFFFF), LV_PART_MAIN);
71+
72+
lbl_title = lv_label_create(lv_screen_active());
73+
lv_label_set_text(lbl_title, "easyC • BME280");
74+
lv_obj_set_style_text_color(lbl_title, lv_color_hex(0x000000), 0);
75+
lv_obj_set_pos(lbl_title, 8, 8);
76+
make_opaque(lbl_title);
77+
78+
panel_data = lv_obj_create(lv_screen_active());
79+
make_opaque(panel_data);
80+
lv_obj_set_style_pad_all(panel_data, 0, 0);
81+
lv_obj_set_style_border_width(panel_data, 0, 0);
82+
lv_obj_set_pos(panel_data, 0, 40);
83+
lv_obj_set_size(panel_data, dispW(), dispH() - 80);
84+
85+
lbl_temp = lv_label_create(panel_data);
86+
lv_obj_set_style_text_color(lbl_temp, lv_color_hex(0x000000), 0);
87+
lv_obj_set_pos(lbl_temp, 24, 40);
88+
89+
lbl_hum = lv_label_create(panel_data);
90+
lv_obj_set_style_text_color(lbl_hum, lv_color_hex(0x000000), 0);
91+
lv_obj_set_pos(lbl_hum, 24, 140);
92+
93+
lbl_press = lv_label_create(panel_data);
94+
lv_obj_set_style_text_color(lbl_press, lv_color_hex(0x000000), 0);
95+
lv_obj_set_pos(lbl_press, 24, 240);
96+
97+
lbl_warn = lv_label_create(panel_data); // shown only if sensor looks unresponsive
98+
lv_obj_set_style_text_color(lbl_warn, lv_color_hex(0x000000), 0);
99+
lv_obj_set_pos(lbl_warn, 24, 320);
100+
lv_label_set_text(lbl_warn, "");
101+
}
102+
103+
static void update_readings() {
104+
// Read sensor
105+
float tC = bme280.readTemperature() + TEMPERATURE_OFFSET; // °C
106+
float hum = bme280.readHumidity() / 10.0f; // library returns x10
107+
float hPa = bme280.readPressure() * 10.0f; // hPa (original style)
108+
109+
// Basic sanity check (some libs return 0 or extreme values if not connected)
110+
bool looks_bad = (hPa <= 0.0f) || (hum < 0.0f || hum > 100.0f) || (tC < -40.0f || tC > 85.0f);
111+
112+
char bufT[32], bufH[32], bufP[32];
113+
snprintf(bufT, sizeof(bufT), "Temperature: %.1f *C", tC);
114+
snprintf(bufH, sizeof(bufH), "Humidity: %.0f %%", hum);
115+
snprintf(bufP, sizeof(bufP), "Pressure: %.0f hPa", hPa);
116+
117+
lv_label_set_text(lbl_temp, bufT);
118+
lv_label_set_text(lbl_hum, bufH);
119+
lv_label_set_text(lbl_press, bufP);
120+
121+
if (looks_bad) {
122+
lv_label_set_text(lbl_warn, "Warning: sensor readings look invalid.\nCheck easyC cable and sensor power.");
123+
} else {
124+
lv_label_set_text(lbl_warn, "");
125+
}
126+
}
127+
128+
void setup() {
129+
Serial.begin(115200);
130+
131+
// LVGL + Inkplate in PARTIAL mode
132+
inkplate.begin(LV_DISP_RENDER_MODE_PARTIAL);
133+
inkplate.selectDisplayMode(INKPLATE_1BIT);
134+
135+
// Init BME280 (void return in this library)
136+
bme280.begin();
137+
138+
ui_create();
139+
update_readings();
140+
141+
// Initial FULL refresh
142+
lv_tick_inc(20);
143+
lv_timer_handler();
144+
inkplate.display();
145+
}
146+
147+
void loop() {
148+
update_readings();
149+
150+
lv_tick_inc(10);
151+
lv_timer_handler();
152+
153+
if (partialCount >= FULL_REFRESH_EVERY) {
154+
inkplate.display(); // FULL
155+
partialCount = 0;
156+
} else {
157+
inkplate.partialUpdate();
158+
partialCount++;
159+
}
160+
161+
delay(10000); // ~10 s between readings
162+
}

0 commit comments

Comments
 (0)