# Desktop simulator for the thermostat UI. Not part of the ESP-IDF build -- # `idf.py build` never looks in here, and this never builds firmware sources # that touch hardware. # # cmake -S sim -B sim/build -G Ninja && cmake --build sim/build # # See sim/README.md. cmake_minimum_required(VERSION 3.16) project(thermostat_sim C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(FW_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) set(LVGL_DIR ${FW_ROOT}/managed_components/lvgl__lvgl) # LVGL is pulled in by the IDF component manager, so it lives in a gitignored # directory that only exists after an IDF build. Using it anyway -- rather than # fetching a second copy -- guarantees the simulator and the firmware render # with the identical LVGL version. A simulator on a different version is a # simulator that lies. if(NOT EXISTS ${LVGL_DIR}/lvgl.h) message(FATAL_ERROR "LVGL not found at ${LVGL_DIR}\n" "It is fetched by the ESP-IDF component manager. Run once:\n" " . ~/esp/esp-idf/export.sh && idf.py reconfigure") endif() # Nothing here uses LVGL's bundled demos or examples, and they add real build # time. ThorVG is a C++ vector engine we do not use either. set(CONFIG_LV_BUILD_DEMOS OFF CACHE BOOL "" FORCE) set(CONFIG_LV_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(CONFIG_LV_USE_THORVG_INTERNAL OFF CACHE BOOL "" FORCE) # LVGL's desktop CMake picks up lv_conf.h from CMAKE_SOURCE_DIR, which is this # directory. add_subdirectory(${LVGL_DIR} ${CMAKE_BINARY_DIR}/lvgl) find_package(SDL2 REQUIRED) # cJSON comes from the ESP-IDF tree rather than the host's libcjson, so the # simulator parses Home Assistant replies with the exact same parser the # firmware uses. IDF_PATH is only needed for this one directory -- the rest of # the simulator builds with no ESP-IDF environment at all. if(DEFINED ENV{IDF_PATH}) set(IDF_ROOT $ENV{IDF_PATH}) else() set(IDF_ROOT $ENV{HOME}/esp/esp-idf) endif() set(CJSON_DIR ${IDF_ROOT}/components/json/cJSON) if(NOT EXISTS ${CJSON_DIR}/cJSON.c) message(FATAL_ERROR "cJSON not found at ${CJSON_DIR}\n" "Set IDF_PATH, or install ESP-IDF to ~/esp/esp-idf.") endif() add_executable(thermostat_sim sim_main.c lvgl_port_sim.c compat/esp_compat.c # The point of the exercise: real firmware sources, compiled unmodified. # Anything added here must stay free of hardware access -- drivers and # HTTP transport stay on the device side. ${FW_ROOT}/main/ui/ui_manager.c ${FW_ROOT}/main/api/ha_data.c ${CJSON_DIR}/cJSON.c ) target_include_directories(thermostat_sim PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/compat # ESP-IDF header stand-ins ${FW_ROOT}/main/ui # ui_manager.h, lvgl_port.h ${FW_ROOT}/main/api # ha_data.h, ha_config.h, ha_template.h ${CJSON_DIR} ${LVGL_DIR}/src/libs/lodepng # PNG encoder for --png mode ${SDL2_INCLUDE_DIRS} ) # SDL2_LIBRARIES can carry trailing whitespace from sdl2-config, which makes # the link line fail in confusing ways. string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES) target_link_libraries(thermostat_sim PRIVATE lvgl ${SDL2_LIBRARIES} m pthread) target_compile_options(thermostat_sim PRIVATE -Wall -Wextra -Wno-unused-parameter)