chronos-esp32 Library

repository·main·Indexed 41 days ago

https://github.com/fbiego/chronos-esp32

A wrapper library for ESP32 that enables the development of smartwatch-like devices. It facilitates BLE communication with the Chronos companion app to synchronize time, receive notifications and weather data, monitor phone status, and control music, volume, and the camera. It includes support for health data transmission, alarm management, and navigation data.

Tokens
4.7K
Snippets
11
Records
25
Agent score
2%

What's inside chronos-esp32

  1. Overview of chronos-esp32

    main

    chronos-esp32 is a wrapper library for the ESP32 designed to facilitate the development of smartwatch-like projects. It enables an ESP32 device to act as a smartwatch by connecting to the Chronos companion app via Bluetooth Low Energy (BLE).

    Key capabilities include:

    • Time Sync: Automatic time synchronization via BLE.
    • Notifications: Receiving notifications from the connected smartphone.
    • Weather: Receiving weather information.
    • Controls: Controlling music, finding the phone, and controlling the camera.
    • Phone Status: Monitoring phone battery level and charging state (requires Chronos app v3.5.1+).
    • Navigation: Navigation support (requires Chronos app v3.7.5+).
    • Additional Features: Support for contacts and QR codes.
  2. Important lifecycle and usage notes

    main

    To ensure the ChronosESP32 library functions correctly, follow these operational requirements:

    • Initialization Order: Call setName() and setScreen() before calling begin().
    • Callbacks: Register any callbacks before calling begin().
    • Main Loop: You must continuously call watch.loop(). This is critical as several outgoing updates and timeouts depend on it.
    • Address Retrieval: The getAddress() method is only populated after begin() has been called.
    • Data Storage: The library stores notifications, weather, alarms, contacts, QR links, and navigation state in RAM.
    • Index Safety: Several indexed getters use modulo arithmetic, meaning out-of-range indices will not cause a failure.
    • Disconnection Behavior: When a disconnect occurs, advertising restarts and the camera state is reset to inactive.
  3. Setup ChronosESP32 in an Arduino project

    main

    To use ChronosESP32, include the header and instantiate a ChronosESP32 object. You must call begin() in your setup() function and loop() in your main loop. You can also set callbacks for connections, notifications, and configuration updates.

    Important Pairing Note: Do not pair the device via phone Bluetooth settings. Instead, use the Chronos companion app: Chronos app > Watches tab > Watches button > Pair New Devices > Search > select your board.

    #include <ChronosESP32.h>
    
    ChronosESP32 watch;
    
    void setup() {
      Serial.begin(115200);
    
      // Optional: Set callbacks
      watch.setConnectionCallback(connectionCallback);
      watch.setNotificationCallback(notificationCallback);
      watch.setConfigurationCallback(configCallback);
    
      watch.begin();
      watch.setBattery(80);
    }
    
    void loop() {
      watch.loop();
    }
  4. Configure the notification buffer size

    main

    The default notification ring buffer size is defined by CS_NOTIF_SIZE (default: 10). You can override this by defining the constant before including the header, or by using a PlatformIO build flag.

    Using C++ define:

    #define CS_NOTIF_SIZE 20
    #include <ChronosESP32.h>

    Using PlatformIO (platformio.ini):

    build_flags = -D CS_NOTIF_SIZE=20
  5. Common usage patterns for ChronosESP32

    main

    The following patterns demonstrate how to interact with the watch object for common tasks like checking connectivity, displaying time, controlling music, capturing photos, and reading data from the watch.

    ### Show Connection State
    ```cpp
    digitalWrite(LED_PIN, watch.isConnected());

    Display Time

    String time = String(watch.getHourC()) + watch.getTime(":%M ") + watch.getAmPmC();
    Serial.println(time);

    Send Music Control

    watch.musicControl(MUSIC_TOGGLE);
    watch.musicControl(MUSIC_NEXT);
    watch.setVolume(50);

    Capture Photo

    if (watch.capturePhoto()) {
      Serial.println("Capture command sent");
    } else {
      Serial.println("Camera not ready");
    }

    Read Notifications

    int count = watch.getNotificationCount();
    for (int i = 0; i < count; i++) {
      Notification &n = watch.getNotificationAt(i);
      Serial.println(n.title);
      Serial.println(n.message);
    }

    Read Weather

    int count = watch.getWeatherCount();
    for (int i = 0; i < count; i++) {
      Weather &w = watch.getWeatherAt(i);
      Serial.printf("Day %d: %d C\n", w.day, w.temp);
    }

    Read Navigation

    Navigation &nav = watch.getNavigation();
    if (nav.active) {
      Serial.println(nav.title);
      Serial.println(nav.directions);
      Serial.println(nav.distance);
      Serial.println(nav.duration);
    }

    Draw Navigation Icon

    Navigation &nav = watch.getNavigation();
    
    for (int y = 0; y < 48; y++) {
      for (int x = 0; x < 48; x++) {
        int byteIndex = (y * 48 + x) / 8;
        int bitPos = 7 - (x % 8);
        bool pixelOn = (nav.icon[byteIndex] >> bitPos) & 0x01;
        // tft.drawPixel(x, y, pixelOn ? TFT_WHITE : TFT_BLACK);
      }
    }
  6. Access weather and forecast data

    main

    Weather data is provided via specific getter methods. Indices wrap around based on defined buffer sizes (CS_WEATHER_SIZE and CS_FORECAST_SIZE).

    • getWeatherCount(): Returns the number of weather items.
    • getWeatherAt(int index): Returns a Weather object.
    • getForecastHour(int hour): Returns an HourlyForecast object for the specified hour.
    • getWeatherLocation(): Returns the current WeatherLocation.
    • getWeatherCity() / getWeatherTime(): Returns the city name and time string.
  7. Initialize and manage the ChronosESP32 lifecycle

    main

    The ChronosESP32 class is the primary interface for the library. Use the constructor to set the device name and screen type, then call begin() to start operations.

    Key Lifecycle Methods:

    • begin(): Starts the library. Call setName() and setScreen() before this.
    • loop(): Must be called continuously in your main loop. It handles internal tasks like delayed info sync, battery sync, and find-phone timeouts.
    • stop(bool clearAll): Stops the library and deinitializes the BLE device. If clearAll is true, it clears all resources.
    • setChunkedTransfer(bool chunked): Enables splitting outgoing packets larger than 20 bytes. This is useful if the companion app is configured for chunked transfers.
    ChronosESP32 chronos("MyWatch", CF_ESP32_240x240);
    
    void setup() {
      chronos.begin();
    }
    
    void loop() {
      chronos.loop();
    }
  8. Send health and activity data

    main

    You can send both real-time and historical health data to the companion app. Real-time methods should typically be called in response to setHealthRequestCallback().

    Real-time Methods:

    • sendRealtimeSteps(uint32_t steps, uint32_t calories)
    • sendRealtimeHeartRate(uint8_t heartRate)
    • sendRealtimeBloodPressure(uint8_t systolic, uint8_t diastolic)
    • sendRealtimeBloodOxygen(uint8_t bloodOxygen)
    • sendRealtimeHealthData(uint8_t heartRate, uint8_t bloodOxygen, uint8_t systolic, uint8_t diastolic)

    Historical Records (using DateTime or individual components):

    • sendStepsRecord(...)
    • sendHeartRateRecord(...)
    • sendBloodPressureRecord(...)
    • sendBloodOxygenRecord(...)
    • sendSleepRecord(...)
    • sendTemperatureRecord(...)
  9. Accessing Notifications

    main

    Notifications are stored in a ring buffer of size CS_NOTIF_SIZE. Use getNotificationAt(index) to retrieve a notification. Index 0 returns the most recent notification.

    Notification Structure:

    • int icon: Icon identifier
    • String app: Source application name
    • String time: Timestamp string
    • String title: Notification title
    • String message: Notification body text
  10. Handle notifications

    main

    Notifications are stored in a buffer. Index 0 represents the latest notification.

    • getNotificationCount(): Returns the number of pending notifications.
    • getNotificationAt(int index): Retrieves the Notification object at the specified index.
    • clearNotifications(): Resets the count to zero. Note that old buffer data remains until overwritten.