ESP32-C3 Chronos— Program SmartGlasses BLE Ultra-Efisien
Program ini mengubah ESP32-C3 SuperMini + OLED 0.91" menjadi smartglasses Android yang full-featured menggunakan Chronos app (BLE). Fokus…
ESP32-C3 Chronos— Program SmartGlasses BLE Ultra-Efisien
Program ini mengubah ESP32-C3 SuperMini + OLED 0.91" menjadi smartglasses Android yang full-featured menggunakan Chronos app (BLE). Fokus utama: stabilitas koneksi, navigasi real-time, dan UI minimalis untuk layar kecil.


Fitur Utama

✅ Notifikasi push real-time (WhatsApp, SMS, etc)
✅ Incoming call display + caller ID
✅ Auto-reconnect BLE (stabilitas C3)
✅ Scroll text untuk navigasi panjang
✅ Battery sync dari HP
✅ Weather sync otomatis
watch.loop(); // Prioritas #1 - 1ms/block
displayInterval = 50; // 20 FPS, bukan 60fps berat
non-blocking ISR // No delay() di interrupt
setChunkedTransfer(true) // v1.9.0 large data fix
- String operations minimized
- Framebuffer OLED efficient (clrScr+update)
- No WiFi (pure BLE)
- ISR atomic access
- 20fps vs 60fps = 66% power saving
// ❌ LAMA (blocking)
if (buttonPressed) { delay(50); ... }
// ✅ BARU (non-blocking)
if (buttonPressedRaw && millis()-buttonPressTime > debounceDelay)
ESP32-C3 SuperMini
OLED SSD1306 128x32 (0.91")
1x Button (GPIO9)
1x LED (GPIO8)
I2C: SDA=20, SCL=21
Power: 3.3V stable

Library Dependencies
ChronosESP32 v1.9.0 ✓
OLED_I2C (SSD1306)
graphics.h (fonts)
Arduino-ESP32 core 3.0+
Kode Full Yang Sudah Di Optimasi
#include <OLED_I2C.h>
#include <ChronosESP32.h>
#include "graphics.h"
#define BUILTINLED 8
#define BUTTON_PIN 9
OLED myOLED(20, 21);
ChronosESP32 watch("ESP32-C3 Watch");
extern uint8_t SmallFont[], MediumNumbers[];
// State
unsigned long notifyTimer = 0;
const unsigned long notifyDuration = 8000;
bool showNotify = false;
int currentPage = 0;
const int maxPages = 4; // Hapus Controls = 4 pages
String msgHeader = "", msgBody = "";
volatile bool buttonPressedRaw = false;
unsigned long buttonPressTime = 0, lastDisplayUpdate = 0, navScrollOffset = 0;
const unsigned long debounceDelay = 50, displayInterval = 50;
bool isConnected = false;
bool navActive = false;
String navDirections = "", navDistance = "", navDuration = "", navSpeed = "";
unsigned long lastScrollUpdate = 0;
const unsigned long scrollSpeed = 150;
void IRAM_ATTR buttonISR() {
buttonPressedRaw = true;
buttonPressTime = millis();
}
void connectionCallback(bool connected) {
isConnected = connected;
digitalWrite(BUILTINLED, connected);
}
void notificationCallback(Notification notification) {
msgHeader = notification.app;
msgBody = notification.message;
showNotify = true;
notifyTimer = millis();
}
void ringerCallback(String caller, bool state) {
if (state) {
msgHeader = "TELPON";
msgBody = caller;
showNotify = true;
notifyTimer = millis() + 5000;
} else showNotify = false;
}
void configCallback(Config config, uint32_t a, uint32_t b) {
if (config == CF_NAV_DATA) {
navActive = (a == 1);
if (navActive) {
Navigation nav = watch.getNavigation();
navDirections = nav.directions;
navDistance = String(nav.distance);
navDuration = nav.duration;
navSpeed = nav.speed;
navScrollOffset = 0; // Reset scroll
}
}
}
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(BUILTINLED, OUTPUT);
if (!myOLED.begin(SSD1306_128X32)) while(1);
myOLED.setFont(SmallFont);
myOLED.clrScr();
myOLED.print("CHRONOS C3", CENTER, 10);
myOLED.print("CLEAN UI", CENTER, 22);
myOLED.update();
watch.setNotificationCallback(notificationCallback);
watch.setRingerCallback(ringerCallback);
watch.setConnectionCallback(connectionCallback);
watch.setConfigurationCallback(configCallback);
watch.setChunkedTransfer(true);
watch.begin();
watch.set24Hour(true);
attachInterrupt(BUTTON_PIN, buttonISR, FALLING);
}
void loop() {
watch.loop();
if (buttonPressedRaw && (millis() - buttonPressTime > debounceDelay)) {
noInterrupts();
bool pressed = buttonPressedRaw;
buttonPressedRaw = false;
interrupts();
if (pressed) {
if (showNotify) showNotify = false;
else currentPage = (currentPage + 1) % maxPages;
}
}
// Nav scroll update
if (navActive && currentPage == 3 && millis() - lastScrollUpdate > scrollSpeed) {
navScrollOffset += 2;
if (navScrollOffset > navDirections.length() * 8) navScrollOffset = 0;
lastScrollUpdate = millis();
}
if (millis() - lastDisplayUpdate < displayInterval) return;
lastDisplayUpdate = millis();
myOLED.clrScr();
if (showNotify && (millis() - notifyTimer < notifyDuration)) {
displayNotification();
} else {
showNotify = false;
switch (currentPage) {
case 0: displayTime(); break;
case 1: displayWeather(); break;
case 2: displayBattery(); break;
case 3: displayNavigation(); break;
}
}
myOLED.update();
}
void displayNotification() {
myOLED.setFont(SmallFont);
myOLED.print(msgHeader.substring(0, 20), LEFT, 0);
myOLED.print(msgBody.substring(0, 20), LEFT, 12);
if (msgBody.length() > 20) {
myOLED.print(msgBody.substring(20, 40), LEFT, 22);
}
}
void displayTime() {
myOLED.setFont(MediumNumbers);
myOLED.print(watch.getHourZ() + ":" + watch.getTime("%M"), CENTER, 0);
myOLED.setFont(SmallFont);
myOLED.print(watch.getTime("%a %d"), CENTER, 22);
}
void displayWeather() {
myOLED.setFont(SmallFont);
myOLED.print("WEATHER", CENTER, 0);
if (watch.getWeatherCount() > 0) {
Weather w = watch.getWeatherAt(0);
String city = watch.getWeatherCity();
if (city.length() > 12) city = city.substring(0, 12);
myOLED.print(city, CENTER, 12); // LOKASI SAJA
myOLED.print(String(w.temp) + "C", CENTER, 22); // SUHU SAJA
} else {
myOLED.print("Medan", CENTER, 12);
myOLED.print("28C", CENTER, 22);
}
}
void displayBattery() {
myOLED.setFont(SmallFont);
myOLED.print("BATTERY", CENTER, 0);
int bat = watch.getPhoneBattery();
String batStr = String(bat); // ANGKA POLOS SAJA
myOLED.setFont(MediumNumbers);
myOLED.print(batStr, CENTER, 17); // TENGAH VERTIKAL
}
void displayNavigation() {
myOLED.setFont(SmallFont);
myOLED.print("NAVIGATION", CENTER, 0);
if (!isConnected) {
myOLED.print("No Connection", CENTER, 16);
return;
}
if (navActive) {
// KIRI ATAS: Direction (scrolling)
String scrollDir = navDirections.substring(navScrollOffset / 8);
if (scrollDir.length() > 16) scrollDir = scrollDir.substring(0, 16);
myOLED.print(scrollDir, LEFT, 10);
// KIRI BAWAH: Distance
myOLED.print(navDistance, LEFT, 22);
// KANAN ATAS: Duration
myOLED.print(navDuration, RIGHT, 10);
// KANAN BAWAH: Speed
myOLED.print(navSpeed, RIGHT, 22);
} else {
myOLED.print("Maps Share", CENTER, 12);
myOLED.print("Chronos", CENTER, 22);
}
} 메타데이터
- post_id
- a73c1e8b49ea
- slug
- esp32-c3-chronos-program-smartglasses-ble-ultra-efisien-a73c1e8b49ea
- url
- https://medium.com/@rvaldi26/esp32-c3-chronos-program-smartglasses-ble-ultra-efisien-a73c1e8b49ea
- canonical_url
- https://medium.com/@rvaldi26/esp32-c3-chronos-program-smartglasses-ble-ultra-efisien-a73c1e8b49ea
- author_url
- https://medium.com/@rvaldi26
- status
- ok
- fetched_at
- 2026-06-27 10:07:59