jakkra / ZSWatch

ZSWatch - the Open Source Zephyr™ based Smartwatch, including both HW and FW.
https://forms.gle/G48Sm5zDe9aCaYtT9
GNU General Public License v3.0
2.3k stars 197 forks source link

Add support for watchfaces from esp32-lvgl-watchface #254

Closed Kampi closed 5 months ago

Kampi commented 5 months ago

Link https://github.com/fbiego/esp32-lvgl-watchface

Modified repo https://github.com/Kampi/esp32-lvgl-watchface/tree/ZSWatch_Port

ToDo

Bugs

Notes

fbiego commented 5 months ago

It appears I may have misinterpreted your concern on https://github.com/fbiego/esp32-lvgl-watchface/issues/1.

I noticed that you mentioned Color Swap and BGR support in your to-do list. Could you provide further clarification on the issue? From what I understand, BGR doesn't seem related to color swapping.

Kampi commented 5 months ago

Hi @fbiego,

thanks for your support! I prepare a branch of the ZSWatch firmware and the watchface repository to test it more properly :)

jakkra commented 5 months ago

@fbiego I think we figured it out, @Kampi tested the code in our Linux environment and there we had wrong display color settings. Will try tomorrow with updated config on our side.

@fbiego BTW really like your project and app!

Kampi commented 5 months ago

So we don´t need BGR and color swap must be enabled because we also use it (the old POSIX configuration causes some issues). This means your implementation should work out of the box after I change the macro name for the swap in the template code.

fbiego commented 5 months ago

awesome, it would be great to see how it turns out

thanks @jakkra btw Chronos app also uses Nordic UART service but the data is structured differently. https://github.com/fbiego/dt78/blob/master/DT78_COMMANDS.md

I would check how I can configure support, I have implemented a library for ESP32.

This is how incoming data is parsed https://github.com/fbiego/chronos-esp32/blob/e521f703cf9ffe12e6d58ec6b929d4d18727f093/ChronosESP32.cpp#L604

https://github.com/fbiego/chronos-esp32/blob/e521f703cf9ffe12e6d58ec6b929d4d18727f093/ChronosESP32.cpp#L662

jakkra commented 5 months ago

@fbiego thanks for the reference, I think it should be fairly easy to add support from Chronos app as we have separated the layer between feeding stuff like weather, time, notifications etc. into the watch from different transport methods already. (We support either Gadgetbride, or iOS (native iOS services for time, notifications etc.). So it would be a matter of adding another.

This is what we use right now: https://www.espruino.com/Gadgetbridge#how-it-works-internally

I think since Chronos also use Nordic NUS, we can just add some check here which protocol the payload matches, and then feed it into a new ble_chronos_input(...) instead when it is of this binary type instead of json. https://github.com/jakkra/ZSWatch/blob/050facf1fac6fde1857f2420c69afeebebd02ec4/app/src/ble/ble_comm.c#L352

Created a skeleton here: https://github.com/jakkra/ZSWatch/tree/jakkra_ble_chronos_app

Kampi commented 5 months ago

This Chronos app looks really nice. Jakob and I thought about a app which provides better support for the watch :) Would be cool to integrate the ZSWatch into this app and vice versa.

Kampi commented 5 months ago

Edit:

It works :)

image

Kampi commented 5 months ago

The first version with ZSWatch capable code is available. The Kotlin template generator was modified to output the code in the format needed for ZSWatch watch face API.

image

Example:


// File generated by bin2lvgl
// developed by fbiego.
// https://github.com/fbiego
// modified by Daniel Kampert. 
// https://github.com/kampi
// Watchface: 748_2_dial

#include <lvgl.h>

#include <zephyr/logging/log.h>

#include "ui/zsw_ui.h"
#include "applications/watchface/watchface_app.h"

LOG_MODULE_REGISTER(watchface_748_2_dial, LOG_LEVEL_WRN);

static lv_obj_t *face_748_2_dial;
static lv_obj_t *face_748_2_dial = NULL;
static watchface_app_evt_listener ui_748_2_dial_evt_cb;

static lv_obj_t *face_748_2_dial_0_424;
...

ZSW_LV_IMG_DECLARE(face_748_2_dial_dial_img_0_424_0);
...

#if CONFIG_LV_COLOR_DEPTH_16 != 1
#error "CONFIG_LV_COLOR_DEPTH_16 should be 16 bit for watchfaces"
#endif
#if CONFIG_LV_COLOR_16_SWAP != 1
#error "CONFIG_LV_COLOR_16_SWAP should be 1 for watchfaces"
#endif

const lv_img_dsc_t *face_748_2_dial_dial_img_2_94526_group[] = {
    &face_748_2_dial_dial_img_2_94526_0,
    &face_748_2_dial_dial_img_2_94526_1,
    &face_748_2_dial_dial_img_2_94526_2,
    &face_748_2_dial_dial_img_2_94526_3,
    &face_748_2_dial_dial_img_2_94526_4,
    &face_748_2_dial_dial_img_2_94526_5,
    &face_748_2_dial_dial_img_2_94526_6,
};
const lv_img_dsc_t *face_748_2_dial_dial_img_3_101560_group[] = {
    &face_748_2_dial_dial_img_3_101560_0,
    &face_748_2_dial_dial_img_3_101560_1,
    &face_748_2_dial_dial_img_3_101560_2,
    &face_748_2_dial_dial_img_3_101560_3,
    &face_748_2_dial_dial_img_3_101560_4,
    &face_748_2_dial_dial_img_3_101560_5,
    &face_748_2_dial_dial_img_3_101560_6,
};
const lv_img_dsc_t *face_748_2_dial_dial_img_4_60206_group[] = {
    &face_748_2_dial_dial_img_4_60206_0,
    &face_748_2_dial_dial_img_4_60206_1,
    &face_748_2_dial_dial_img_4_60206_2,
    &face_748_2_dial_dial_img_4_60206_3,
    &face_748_2_dial_dial_img_4_60206_4,
    &face_748_2_dial_dial_img_4_60206_5,
    &face_748_2_dial_dial_img_4_60206_6,
    &face_748_2_dial_dial_img_4_60206_7,
    &face_748_2_dial_dial_img_4_60206_8,
    &face_748_2_dial_dial_img_4_60206_9,
    &face_748_2_dial_dial_img_4_60206_10,
    &face_748_2_dial_dial_img_4_60206_11,
};
const lv_img_dsc_t *face_748_2_dial_dial_img_5_72552_group[] = {
    &face_748_2_dial_dial_img_5_72552_0,
    &face_748_2_dial_dial_img_5_72552_1,
    &face_748_2_dial_dial_img_5_72552_2,
    &face_748_2_dial_dial_img_5_72552_3,
    &face_748_2_dial_dial_img_5_72552_4,
    &face_748_2_dial_dial_img_5_72552_5,
    &face_748_2_dial_dial_img_5_72552_6,
    &face_748_2_dial_dial_img_5_72552_7,
    &face_748_2_dial_dial_img_5_72552_8,
    &face_748_2_dial_dial_img_5_72552_9,
    &face_748_2_dial_dial_img_5_72552_10,
    &face_748_2_dial_dial_img_5_72552_11,
};
const lv_img_dsc_t *face_748_2_dial_dial_img_6_58522_group[] = {
    &face_748_2_dial_dial_img_6_58522_0,
    &face_748_2_dial_dial_img_6_58522_1,
    &face_748_2_dial_dial_img_6_58522_2,
    &face_748_2_dial_dial_img_6_58522_3,
    &face_748_2_dial_dial_img_6_58522_4,
    &face_748_2_dial_dial_img_6_58522_5,
    &face_748_2_dial_dial_img_6_58522_6,
    &face_748_2_dial_dial_img_6_58522_7,
    &face_748_2_dial_dial_img_6_58522_8,
    &face_748_2_dial_dial_img_6_58522_9,
};
const lv_img_dsc_t *face_748_2_dial_dial_img_15_82792_group[] = {
    &face_748_2_dial_dial_img_15_82792_0,
    &face_748_2_dial_dial_img_15_82792_1,
    &face_748_2_dial_dial_img_15_82792_2,
    &face_748_2_dial_dial_img_15_82792_3,
    &face_748_2_dial_dial_img_15_82792_4,
    &face_748_2_dial_dial_img_15_82792_5,
    &face_748_2_dial_dial_img_15_82792_6,
    &face_748_2_dial_dial_img_15_82792_7,
    &face_748_2_dial_dial_img_15_82792_8,
    &face_748_2_dial_dial_img_15_82792_9,
};
const lv_img_dsc_t *face_748_2_dial_dial_img_19_80958_group[] = {
    &face_748_2_dial_dial_img_19_80958_0,
    &face_748_2_dial_dial_img_19_80958_1,
    &face_748_2_dial_dial_img_19_80958_2,
    &face_748_2_dial_dial_img_19_80958_3,
    &face_748_2_dial_dial_img_19_80958_4,
    &face_748_2_dial_dial_img_19_80958_5,
    &face_748_2_dial_dial_img_19_80958_6,
    &face_748_2_dial_dial_img_19_80958_7,
    &face_748_2_dial_dial_img_19_80958_8,
    &face_748_2_dial_dial_img_19_80958_9,
};

static void watchface_748_2_dial_remove(void)
{
    if (!face_748_2_dial) {
        return;
    }
    lv_obj_del(face_748_2_dial);
    face_748_2_dial = NULL;
}

static void watchface_748_2_dial_invalidate_cached(void)
{
}

static void watchface_748_2_dial_set_datetime(int day_of_week, int date, int day, int month, int year, int weekday, int32_t hour,
                                   int32_t minute, int32_t second, uint32_t usec)
{
    if (!face_748_2_dial) {
        return;
    }

    lv_img_set_src(face_748_2_dial_3_101560, face_748_2_dial_dial_img_3_101560_group[((weekday + 6) / 1) % 7]);
    lv_img_set_src(face_748_2_dial_5_72552, face_748_2_dial_dial_img_5_72552_group[(month / 1) % 12]);
    lv_img_set_src(face_748_2_dial_15_82792, face_748_2_dial_dial_img_15_82792_group[(hour / 1) % 10]);
    lv_img_set_src(face_748_2_dial_16_82792, face_748_2_dial_dial_img_15_82792_group[(hour / 10) % 10]);
    lv_img_set_src(face_748_2_dial_17_82792, face_748_2_dial_dial_img_15_82792_group[(minute / 1) % 10]);
    lv_img_set_src(face_748_2_dial_18_82792, face_748_2_dial_dial_img_15_82792_group[(minute / 10) % 10]);
    lv_img_set_src(face_748_2_dial_19_80958, face_748_2_dial_dial_img_19_80958_group[(day / 1) % 10]);
    lv_img_set_src(face_748_2_dial_20_80958, face_748_2_dial_dial_img_19_80958_group[(day / 10) % 10]);

}

static void watchface_748_2_dial_set_step(int32_t steps, int32_t distance, int32_t kcal)
{
    if (!face_748_2_dial) {
        return;
    }

    lv_img_set_src(face_748_2_dial_9_58522, face_748_2_dial_dial_img_6_58522_group[(steps / 1) % 10]);
    lv_img_set_src(face_748_2_dial_10_58522, face_748_2_dial_dial_img_6_58522_group[(steps / 10) % 10]);
    lv_img_set_src(face_748_2_dial_11_58522, face_748_2_dial_dial_img_6_58522_group[(steps / 100) % 10]);
    lv_img_set_src(face_748_2_dial_12_58522, face_748_2_dial_dial_img_6_58522_group[(steps / 1000) % 10]);
    lv_img_set_src(face_748_2_dial_13_58522, face_748_2_dial_dial_img_6_58522_group[(steps / 10000) % 10]);

}

static void watchface_748_2_dial_set_hrm(int32_t bpm, int32_t oxygen)
{
    if (!face_748_2_dial) {
        return;
    }

    lv_img_set_src(face_748_2_dial_6_58522, face_748_2_dial_dial_img_6_58522_group[(bpm / 1) % 10]);
    lv_img_set_src(face_748_2_dial_7_58522, face_748_2_dial_dial_img_6_58522_group[(bpm / 10) % 10]);
    lv_img_set_src(face_748_2_dial_8_58522, face_748_2_dial_dial_img_6_58522_group[(bpm / 100) % 10]);

}

static void watchface_748_2_dial_set_weather(int8_t temperature, int weather_code)
{
    if (!face_748_2_dial) {
        return;
    }

}

static void watchface_748_2_dial_set_ble_connected(bool connected)
{
    if (!face_748_2_dial) {
        return;
    }

}

static void watchface_748_2_dial_set_battery_percent(int32_t percent, int32_t battery)
{
    if (!face_748_2_dial) {
        return;
    }

}

static void watchface_748_2_dial_set_num_notifcations(int32_t number)
{
    if (!face_748_2_dial) {
        return;
    }

}

static void watchface_748_2_dial_set_watch_env_sensors(int temperature, int humidity, int pressure, float iaq, float co2)
{
    if (!face_748_2_dial) {
        return;
    }

}

void watchface_748_2_dial_show(watchface_app_evt_listener evt_cb, zsw_settings_watchface_t *settings) {
    ui_748_2_dial_evt_cb = evt_cb;

    lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);
    face_748_2_dial = lv_obj_create(lv_scr_act());
    watchface_748_2_dial_invalidate_cached();

    lv_obj_clear_flag(face_748_2_dial, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_scrollbar_mode(face_748_2_dial, LV_SCROLLBAR_MODE_OFF);
    lv_obj_set_style_bg_opa(face_748_2_dial, LV_OPA_TRANSP, LV_PART_MAIN);

    lv_obj_set_style_border_width(face_748_2_dial, 0, LV_PART_MAIN);
    lv_obj_set_size(face_748_2_dial, 240, 240);
    lv_obj_clear_flag(face_748_2_dial, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_style_bg_color(face_748_2_dial, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(face_748_2_dial, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(face_748_2_dial, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_left(face_748_2_dial, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_right(face_748_2_dial, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_top(face_748_2_dial, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_bottom(face_748_2_dial, 0, LV_PART_MAIN | LV_STATE_DEFAULT);

    face_748_2_dial_0_424 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_0_424, &face_748_2_dial_dial_img_0_424_0);
    lv_obj_set_width(face_748_2_dial_0_424, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_0_424, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_0_424, 0);
    lv_obj_set_y(face_748_2_dial_0_424, 0);
    lv_obj_add_flag(face_748_2_dial_0_424, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_0_424, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_1_65535 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_1_65535, &face_748_2_dial_dial_img_1_65535_0);
    lv_obj_set_width(face_748_2_dial_1_65535, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_1_65535, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_1_65535, 177);
    lv_obj_set_y(face_748_2_dial_1_65535, 91);
    lv_obj_add_flag(face_748_2_dial_1_65535, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_1_65535, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_3_101560 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_3_101560, &face_748_2_dial_dial_img_3_101560_0);
    lv_obj_set_width(face_748_2_dial_3_101560, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_3_101560, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_3_101560, 116);
    lv_obj_set_y(face_748_2_dial_3_101560, 157);
    lv_obj_add_flag(face_748_2_dial_3_101560, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_3_101560, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_5_72552 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_5_72552, &face_748_2_dial_dial_img_5_72552_0);
    lv_obj_set_width(face_748_2_dial_5_72552, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_5_72552, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_5_72552, 130);
    lv_obj_set_y(face_748_2_dial_5_72552, 82);
    lv_obj_add_flag(face_748_2_dial_5_72552, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_5_72552, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_6_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_6_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_6_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_6_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_6_58522, 153);
    lv_obj_set_y(face_748_2_dial_6_58522, 40);
    lv_obj_add_flag(face_748_2_dial_6_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_6_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_7_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_7_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_7_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_7_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_7_58522, 142);
    lv_obj_set_y(face_748_2_dial_7_58522, 40);
    lv_obj_add_flag(face_748_2_dial_7_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_7_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_8_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_8_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_8_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_8_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_8_58522, 131);
    lv_obj_set_y(face_748_2_dial_8_58522, 40);
    lv_obj_add_flag(face_748_2_dial_8_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_8_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_9_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_9_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_9_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_9_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_9_58522, 170);
    lv_obj_set_y(face_748_2_dial_9_58522, 191);
    lv_obj_add_flag(face_748_2_dial_9_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_9_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_10_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_10_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_10_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_10_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_10_58522, 159);
    lv_obj_set_y(face_748_2_dial_10_58522, 191);
    lv_obj_add_flag(face_748_2_dial_10_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_10_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_11_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_11_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_11_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_11_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_11_58522, 148);
    lv_obj_set_y(face_748_2_dial_11_58522, 191);
    lv_obj_add_flag(face_748_2_dial_11_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_11_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_12_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_12_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_12_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_12_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_12_58522, 137);
    lv_obj_set_y(face_748_2_dial_12_58522, 191);
    lv_obj_add_flag(face_748_2_dial_12_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_12_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_13_58522 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_13_58522, &face_748_2_dial_dial_img_6_58522_0);
    lv_obj_set_width(face_748_2_dial_13_58522, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_13_58522, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_13_58522, 126);
    lv_obj_set_y(face_748_2_dial_13_58522, 191);
    lv_obj_add_flag(face_748_2_dial_13_58522, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_13_58522, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_14_80686 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_14_80686, &face_748_2_dial_dial_img_14_80686_0);
    lv_obj_set_width(face_748_2_dial_14_80686, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_14_80686, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_14_80686, 166);
    lv_obj_set_y(face_748_2_dial_14_80686, 117);
    lv_obj_add_flag(face_748_2_dial_14_80686, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_14_80686, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_15_82792 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_15_82792, &face_748_2_dial_dial_img_15_82792_0);
    lv_obj_set_width(face_748_2_dial_15_82792, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_15_82792, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_15_82792, 138);
    lv_obj_set_y(face_748_2_dial_15_82792, 102);
    lv_obj_add_flag(face_748_2_dial_15_82792, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_15_82792, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_16_82792 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_16_82792, &face_748_2_dial_dial_img_15_82792_0);
    lv_obj_set_width(face_748_2_dial_16_82792, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_16_82792, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_16_82792, 110);
    lv_obj_set_y(face_748_2_dial_16_82792, 102);
    lv_obj_add_flag(face_748_2_dial_16_82792, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_16_82792, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_17_82792 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_17_82792, &face_748_2_dial_dial_img_15_82792_0);
    lv_obj_set_width(face_748_2_dial_17_82792, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_17_82792, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_17_82792, 204);
    lv_obj_set_y(face_748_2_dial_17_82792, 102);
    lv_obj_add_flag(face_748_2_dial_17_82792, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_17_82792, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_18_82792 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_18_82792, &face_748_2_dial_dial_img_15_82792_0);
    lv_obj_set_width(face_748_2_dial_18_82792, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_18_82792, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_18_82792, 176);
    lv_obj_set_y(face_748_2_dial_18_82792, 102);
    lv_obj_add_flag(face_748_2_dial_18_82792, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_18_82792, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_19_80958 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_19_80958, &face_748_2_dial_dial_img_19_80958_0);
    lv_obj_set_width(face_748_2_dial_19_80958, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_19_80958, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_19_80958, 199);
    lv_obj_set_y(face_748_2_dial_19_80958, 82);
    lv_obj_add_flag(face_748_2_dial_19_80958, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_19_80958, LV_OBJ_FLAG_SCROLLABLE);

    face_748_2_dial_20_80958 = lv_img_create(face_748_2_dial);
    lv_img_set_src(face_748_2_dial_20_80958, &face_748_2_dial_dial_img_19_80958_0);
    lv_obj_set_width(face_748_2_dial_20_80958, LV_SIZE_CONTENT);
    lv_obj_set_height(face_748_2_dial_20_80958, LV_SIZE_CONTENT);
    lv_obj_set_x(face_748_2_dial_20_80958, 189);
    lv_obj_set_y(face_748_2_dial_20_80958, 82);
    lv_obj_add_flag(face_748_2_dial_20_80958, LV_OBJ_FLAG_ADV_HITTEST);
    lv_obj_clear_flag(face_748_2_dial_20_80958, LV_OBJ_FLAG_SCROLLABLE);

}

static watchface_ui_api_t ui_api = {
    .show = watchface_748_2_dial_show,
    .remove = watchface_748_2_dial_remove,
    .set_battery_percent = watchface_748_2_dial_set_battery_percent,
    .set_hrm = watchface_748_2_dial_set_hrm,
    .set_step = watchface_748_2_dial_set_step,
    .set_ble_connected = watchface_748_2_dial_set_ble_connected,
    .set_num_notifcations = watchface_748_2_dial_set_num_notifcations,
    .set_weather = watchface_748_2_dial_set_weather,
    .set_datetime = watchface_748_2_dial_set_datetime,
    .set_watch_env_sensors = watchface_748_2_dial_set_watch_env_sensors,
    .ui_invalidate_cached = watchface_748_2_dial_invalidate_cached,
};

static int watchface_748_2_dial_init(void)
{
    watchface_app_register_ui(&ui_api);

    return 0;
}

SYS_INIT(watchface_748_2_dial_init, APPLICATION, WATCHFACE_UI_INIT_PRIO);
Kampi commented 5 months ago

PXL_20240418_040847675

Working on HW too :)

Needs a quick fix because I haven´t placed the images in the external flash (open point) but it looks good

fbiego commented 5 months ago

@Kampi there was no documentation on the watchface format so most of it was identifying patterns in the structure https://github.com/Kampi/esp32-lvgl-watchface/pull/1 btw, X5 Pro dials are 360x360 and may not be suitable however i have been working on a resize script that reduces the size to 240x240. I will add that to the repo soon

Kampi commented 5 months ago

@fbiego we want to reduce the redrawing load for the CPU by adding a check for a needed reload. Unfortunately I can not add it to the Kotlin code because I don´t know the code and Kotlin well. Can you do it?

This should like the following (for every variable like time, weather, etc.):

static int32_t last_hour = -1;

static void watchface_79_2_dial_invalidate_cached(void)
{
    last_hour = -1;
}

static void watchface_79_2_dial_set_datetime(int day_of_week, int date, int day, int month, int year, int weekday, int32_t hour,
                                   int32_t minute, int32_t second, uint32_t usec, bool am, bool mode)
{
    if (!face_79_2_dial) {
        return;
    }

    if (last_hour != hour) {
        last_hour = hour;
        lv_img_set_src(face_79_2_dial_1_59582, face_79_2_dial_dial_img_1_59582_group[(hour / 1) % 10]);
        lv_img_set_src(face_79_2_dial_2_59582, face_79_2_dial_dial_img_1_59582_group[(hour / 10) % 10]);
    }

   ...
} 

Maybe it´s possible to split it up a bit more to the single decimal places.

Edit: @fbiego I tried it on my own (check the latest commits). Maybe you can improve it :)

Kampi commented 5 months ago

@fbiego these splitted if-statements from my implementation doesn´t work because the first condition is blocking the second condition. So it´s important to move both update renderings into one if...

So my approach is wrong :D

fbiego commented 5 months ago

@Kampi i just noticed that too

fbiego commented 5 months ago

Implementing grouped if block may not be feasible given the structure of the watchfaces may be unpredictable.

Probably it would be suitable to implement checking and updating only the place value of the variable. This would require additional functions to get the place value and set the place value. You can run and try this code online https://www.programiz.com/cpp-programming/online-compiler/

// Online C++ compiler to run C++ program online
#include <iostream>

int32_t getPlaceValue(int32_t num, int32_t place) {
    int32_t divisor = 1;
    for (uint32_t i = 1; i < place; i++)
        divisor *= 10;
    return (num / divisor) % 10;
}

int32_t setPlaceValue(int32_t num, int32_t place, int32_t newValue) {
    int32_t divisor = 1;
    for (uint32_t i = 1; i < place; i++)
        divisor *= 10;
    return num - ((num / divisor) % 10 * divisor) + (newValue * divisor);
}

int main() {
    // Write C++ code here

    int32_t last_hour = 12;
    int32_t hour = 13;

    if (getPlaceValue(last_hour, 1) != getPlaceValue(hour, 1)) {
        last_hour = setPlaceValue(last_hour, 1, getPlaceValue(hour, 1));
        // lv_img_set_src(face_79_2_dial_1_59582, face_79_2_dial_dial_img_1_59582_group[(hour / 1) % 10]);
        printf("Digit 1 updated to : %u\n", getPlaceValue(hour, 1));
    }

    if (getPlaceValue(last_hour, 2) != getPlaceValue(hour, 2)) {
        last_hour = setPlaceValue(last_hour, 2, getPlaceValue(hour, 2));
//      lv_img_set_src(face_79_2_dial_2_59582, face_79_2_dial_dial_img_1_59582_group[(hour / 10) % 10]);
        printf("Digit 2 updated to: %u\n", getPlaceValue(hour, 2));
    }

    printf("Final Update Last hour: %u\n", last_hour);

    return 0;
}
Kampi commented 5 months ago

mmh looks like a good approach. A bit more code but it shouldn´t care that much. But @fbiego how we can integrate it into the Kotlin script?

@jakkra what do you think about it?

fbiego commented 5 months ago

I have created a pr https://github.com/Kampi/esp32-lvgl-watchface/pull/2

jakkra commented 5 months ago

@fbiego really awesome thanks! I got an update (not using those new changes) that now watchfaces run nicely.

Thanks for the support @fbiego !

Had some bugs when external flash partitions grew, but sorted now, so now running pretty smoothly! Just have a bug that rotating images that are in external flash isn't working hence the analog watchface isn't working. But will debug this at some point.

https://github.com/jakkra/ZSWatch/assets/4318648/9341b8a9-d3d0-420f-9fa7-92224f2275f5

Kampi commented 5 months ago

I have created a pr Kampi/esp32-lvgl-watchface#2

Cool! Thank you very much!

fbiego commented 5 months ago

Thanks @Kampi for the coffee, much appreciated

Kampi commented 5 months ago

@fbiego we figured out some issues with the latest version of the converter and with the upload of the images.