Compare commits

..

30 Commits

Author SHA1 Message Date
8f60e9c38c publication temp int + etat online 2026-03-14 11:51:44 +01:00
67e6d1cfaa webserver (crashes & dumps) 2026-03-13 18:57:27 +01:00
77e8116d54 bg
(cherry picked from commit a84b935d41b012d8f4349df37f5e37f4e2de47be)
2026-03-06 07:24:23 +01:00
0de95c5386 dump to flash + poisoning 2026-03-06 07:22:00 +01:00
f871b76ca2 fix compat linux 2026-03-01 21:09:32 +01:00
9d31148d21 Merge branch 'OTA' 2026-03-01 20:33:14 +01:00
9293b5fdc6 Merge branch 'chgt_style_dateheure' 2026-03-01 16:56:00 +01:00
bce9f03eb4 format date 2026-03-01 16:50:11 +01:00
9217397d7d OTA: 1ere version 2026-03-01 15:58:43 +01:00
b7552e15ce notif sonore et fin (1ere version) 2026-02-28 21:06:58 +01:00
434ede2480 amélioration ihm (boutons) 2026-02-26 23:56:19 +01:00
8e868da692 linux compat 2026-02-26 23:55:50 +01:00
e1640f4ad9 machine : affichage durée depuis départ 2026-02-26 23:20:05 +01:00
a41945bcef Merge branch 'fix/etat_machine_logs' 2026-02-26 07:54:12 +01:00
7316561482 1ere implem son fin machine 2026-02-26 07:44:35 +01:00
ae99b85932 compat linux 2026-02-24 17:06:30 +01:00
5ac20b78fa adjust dtHToString 2026-02-24 16:46:13 +01:00
fc5f46d3fd ajout heure meteo ecran home 2026-02-24 16:35:19 +01:00
f5419e85aa reactivation volets 2026-02-24 16:30:24 +01:00
4658da4adb ajout temp intérieure 2026-02-24 15:25:10 +01:00
f32cad2987 ajout temp ext 2026-02-24 14:39:36 +01:00
1d91bac9e9 Merge branch 'etat_machine' 2026-02-24 13:26:31 +01:00
c87cc69b9e corrections meteo + timecb 2026-02-24 12:52:45 +01:00
6f338020ab meteo colors 2026-02-23 20:43:39 +01:00
d9ac74a595 fix meteo (images...) 2026-02-23 18:16:34 +01:00
5bd2ef288a affichage EtatMachine 2026-02-23 15:15:03 +01:00
28c5870ca6 meilleure gestion meteo 2026-02-23 13:59:02 +01:00
2da4a8f94b Gestion etat machine. Manque affichage 2026-02-23 13:55:49 +01:00
f29fee752f modif defaults 2026-02-21 11:33:31 +01:00
3a791daa47 Merge commit '56b28be7581052c9cf7ab0dbc67a2467ad603a2c' 2026-02-21 11:11:31 +01:00
289 changed files with 157776 additions and 12571 deletions

13
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,13 @@
ARG DOCKER_TAG=latest
FROM espressif/idf:${DOCKER_TAG}
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN apt-get update -y && apt-get install udev -y
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD ["/bin/bash", "-c"]

View File

@ -0,0 +1,21 @@
{
"name": "ESP-IDF QEMU",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"idf.espIdfPath": "/opt/esp/idf",
"idf.toolsPath": "/opt/esp",
"idf.gitPath": "/usr/bin/git"
},
"extensions": [
"espressif.esp-idf-extension",
"espressif.esp-idf-web"
]
}
},
"runArgs": ["--privileged"]
}

7
.gitignore vendored
View File

@ -1,2 +1,9 @@
build/
managed_components/
build_slave/
CMakeFiles/
esp-idf/
gdbinit/
sdkconfig
sdkconfig.old
components/domotic_display/test_host/sdkconfig

View File

@ -2,7 +2,7 @@
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "${config:idf.toolsPath}/tools/riscv32-esp-elf/esp-14.2.0_20240906/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
"compilerPath": "/home/marc/.espressif/tools/riscv32-esp-elf/esp-14.2.0_20251107/riscv32-esp-elf/bin/riscv32-esp-elf-gcc",
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
"includePath": [
"${config:idf.espIdfPath}/components/**",

131
.vscode/launch.json vendored
View File

@ -16,7 +16,7 @@
"name": "Debug LVGL demo with gdb",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/rgb_lcd",
"program": "${workspaceFolder}/build/rgb_lcd",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
@ -32,6 +32,133 @@
"miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe"
}
},
{
"name": "Debug ihm with gdb",
"type": "cppdbg",
"request": "launch",
"preLaunchTask": "Build - Build IHM",
"program": "${workspaceFolder}/components/domotic_display/test_host/build/host_test.elf",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
/*
"setupCommands": [
{
"description": "Load LVGL GDB helpers",
"text": "source /home/marc/domotic/components/domotic_display/test_host/managed_components/lvgl__lvgl/scripts/gdb/gdbinit.py"
}
],*/
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe"
}
},
{
"name": "Debug meteofrance with gdb",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/components/meteofrance/testHost/build/my_custom_app.elf",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
/*
"setupCommands": [
{
"description": "Load LVGL GDB helpers",
"text": "source /home/marc/domotic/components/domotic_display/test_host/managed_components/lvgl__lvgl/scripts/gdb/gdbinit.py"
}
],*/
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe"
}
},
{
"name": "Debug main with gdb",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/rgb_lcd.elf",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
/*
"setupCommands": [
{
"description": "Load LVGL GDB helpers",
"text": "source /home/marc/domotic/components/domotic_display/test_host/managed_components/lvgl__lvgl/scripts/gdb/gdbinit.py"
}
],*/
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe"
}
},
{
"name": "Debug remindme with gdb",
"type": "cppdbg",
"request": "launch",
"preLaunchTask": "Build - Build IHM",
"program": "${workspaceFolder}/components/RemindMe/test/build/remindme_host_test.elf",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"setupCommands": [
{
"description": "Load LVGL GDB helpers",
"text": "source /home/marc/domotic/components/domotic_display/test_host/managed_components/lvgl__lvgl/scripts/gdb/gdbinit.py"
}
],
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGw\\bin\\gdb.exe"
}
},
{
"name": "Debug comp2 (Linux)",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/components/domotic_display/test_host/build/comp2_test",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Enable pretty printing",
"text": "-enable-pretty-printing"
}
]
}
]
}

18
.vscode/settings.json vendored
View File

@ -1,11 +1,11 @@
{
"C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPath": "/home/marc/esp/master/esp-idf",
"idf.pythonBinPath": "/home/marc/.espressif/python_env/idf5.3_py3.10_env/bin/python",
"idf.espIdfPath": "/home/marc/esp/esp-idf",
"idf.pythonBinPath": "/home/marc/.espressif/tools/python/v5.5.2/venv/bin/python3",
"idf.toolsPath": "/home/marc/.espressif",
"idf.customExtraPaths": "/home/marc/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin:/home/marc/.espressif/tools/riscv32-esp-elf-gdb/14.2_20240403/riscv32-esp-elf-gdb/bin:/home/marc/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20240530/xtensa-esp-elf/bin:/home/marc/.espressif/tools/riscv32-esp-elf/esp-13.2.0_20240530/riscv32-esp-elf/bin:/home/marc/.espressif/tools/esp32ulp-elf/2.38_20240113/esp32ulp-elf/bin:/home/marc/.espressif/tools/cmake/3.24.0/bin:/home/marc/.espressif/tools/openocd-esp32/v0.12.0-esp32-20240318/openocd-esp32/bin:/home/marc/.espressif/tools/ninja/1.11.1:/home/marc/.espressif/tools/esp-rom-elfs/20240305",
"idf.customExtraVars": {
"OPENOCD_SCRIPTS": "/home/marc/.espressif/tools/openocd-esp32/v0.12.0-esp32-20240318/openocd-esp32/share/openocd/scripts",
"OPENOCD_SCRIPTS": "/home/marc/.espressif/tools/openocd-esp32/v0.12.0-esp32-20251215/openocd-esp32/share/openocd/scripts",
"ESP_ROM_ELF_DIR": "/home/marc/.espressif/tools/esp-rom-elfs/20240305/",
"IDF_TARGET": "esp32p4"
},
@ -105,7 +105,15 @@
"bsp_board_extra.h": "c",
"display.h": "c",
"statemanagement.h": "c",
"communication.h": "c"
"communication.h": "c",
"mqtt_client.h": "c"
},
"idf.pythonInstallPath": "/usr/bin/python3"
"idf.pythonInstallPath": "/usr/bin/python3",
"clangd.path": "/home/marc/.espressif/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/clangd",
"clangd.arguments": [
"--background-index",
"--query-driver=/home/marc/.espressif/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
"--compile-commands-dir=/home/marc/domotic/build"
],
"idf.currentSetup": "/home/marc/.espressif/v5.5.2/esp-idf"
}

43
.vscode/tasks.json vendored
View File

@ -33,7 +33,7 @@
"isDefault": true
},
"dependsOn": "Build"
}
},
{
"label": "Build - Build project",
"type": "shell",
@ -73,6 +73,47 @@
"isDefault": true
}
},
{
"label": "Build - Build IHM",
"type": "shell",
"command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py build",
"windows": {
"command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py build",
"options": {
"env": {
"PATH": "${env:PATH};${config:idf.customExtraPaths}"
}
}
},
"options": {
"cwd": "${workspaceFolder}/components/domotic_display/test_host/",
"env": {
"IDF_TARGET": "linux",
"PATH": "${env:PATH}:${config:idf.customExtraPaths}"
}
},
"problemMatcher": [
{
"owner": "cpp",
"fileLocation": [
"autoDetect",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Set ESP-IDF Target",
"type": "shell",

View File

@ -1,28 +1,155 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# --------------------------------------------------
# 1. Version de base (version.txt)
# --------------------------------------------------
file(READ "${CMAKE_SOURCE_DIR}/version.txt" FW_VERSION)
string(STRIP "${FW_VERSION}" FW_VERSION)
# "Trim" the build. Include the minimal set of components, main and anything it depends on.
set(COMPONENTS main)
# --------------------------------------------------
# 2. Détection git + branche
# --------------------------------------------------
find_package(Git)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(GIT_BRANCH "")
set(IS_GIT_REPO OFF)
if(${IDF_TARGET} STREQUAL "esp32p4")
set(EXTRA_COMPONENT_DIRS
/home/marc/esp-dev-kits/examples/esp32-p4-function-ev-board/examples/common_components
$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
)
else()
# PROJECT_PLATFORM_LINUX
# PROJECT_PLATFORM_ESP32
add_compile_definitions(PROJECT_PLATFORM_LINUX)
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
set(IS_GIT_REPO ON)
set(EXTRA_COMPONENT_DIRS
$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
${CMAKE_CURRENT_SOURCE_DIR}/FreeRTOS
"/home/marc/esp-protocols/common_components/linux_compat"
"/home/marc/esp-protocols/components/mdns/tests/host_test/components"
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
endif()
project(rgb_lcd)
# --------------------------------------------------
# 3. Mode dev ou release
# --------------------------------------------------
# Convention simple :
# - branche main / master => release
# - le reste => dev
set(IS_DEV_BUILD OFF)
if(IS_GIT_REPO AND NOT GIT_BRANCH STREQUAL "main" AND NOT GIT_BRANCH STREQUAL "master")
set(IS_DEV_BUILD ON)
endif()
# --------------------------------------------------
# 4. Nettoyage nom de branche
# --------------------------------------------------
if(IS_DEV_BUILD)
# remplace / par -
string(REPLACE "/" "-" GIT_BRANCH_CLEAN "${GIT_BRANCH}")
set(FW_VERSION "${FW_VERSION}-${GIT_BRANCH_CLEAN}")
endif()
message(STATUS "Firmware version: ${FW_VERSION}")
# --------------------------------------------------
cmake_minimum_required(VERSION 3.16)
option(SIMULATION_QEMU "Build for QEMU simulation" OFF)
message(STATUS "ROOT:: SIMULATION_QEMU = ${SIMULATION_QEMU}")
# -------------------------------------------------
# CONFIGURATION AVANT project() : uniquement CMake pur
# -------------------------------------------------
if(SIMULATION_QEMU)
message(STATUS "SIMULATION_QEMU = ON")
option(SIMULATION_QEMU "Build for QEMU simulation" ON)
set(COMPONENTS
components/meteofrance
components/domotic_display
managed_components/lvgl_lvgl
main
esp-timer
$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
)
else()
message(STATUS "SIMULATION_QEMU = OFF")
option(SIMULATION_QEMU "Build for QEMU simulation" OFF)
# set(COMPONENTS
# components/meteofrance
# components/domotic_display
# managed_components/lvgl_lvgl
# main
# $ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
# )
endif()
#list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/esp_timer")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(domotic)
# -------------------------------------------------
# APRÈS project() : maintenant CONFIG_SIMULATION_QEMU existe
# -------------------------------------------------
if(CONFIG_SIMULATION_QEMU)
message(STATUS "Compilation IHM (simulation)")
add_compile_definitions(CONFIG_SIMULATION_QEMU=1)
#add_custom_target(run_ihm
# COMMAND ${CMAKE_COMMAND} -E echo "Building and launching IHM native..."
# COMMAND ${CMAKE_COMMAND} --build ${CMAKE_SOURCE_DIR}/components/ihm --target all
# COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR}/components/ihm ./ihm_simulator
#)
else()
message(STATUS "Compilation standard")
#add_link_options("-Wl,--disable-non-contiguous-regions")
add_compile_options(
-fsanitize=address
-fno-omit-frame-pointer
-O0
-g
)
add_link_options(-fsanitize=address)
endif()
# --- Paramètres OTA ---
set(OTA_DIR "${CMAKE_SOURCE_DIR}/../ota/fw")
set(DEVICE "esp32p4")
# --- Nom final du binaire ---
set(OTA_BIN_NAME "${PROJECT_NAME}-v${FW_VERSION}.bin")
set(BUILD_BIN "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin")
set(BUILD_ELF "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.elf")
message(STATUS "Firmware version: ${FW_VERSION}")
# --- Target OTA ---
add_custom_target(ota_push ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${OTA_DIR}
COMMAND ${CMAKE_COMMAND} -E copy
${BUILD_BIN}
${OTA_DIR}/${OTA_BIN_NAME}
COMMAND ${CMAKE_COMMAND} -E copy
${BUILD_ELF}
${OTA_DIR}/latest.elf
COMMENT "📦 Copy firmware to OTA server directory"
DEPENDS app
)
add_custom_target(ota_latest
COMMAND ${CMAKE_COMMAND} -E echo
"{ \"version\":\"${FW_VERSION}\", \
\"bin\":\"${OTA_BIN_NAME}\" }"
> ${OTA_DIR}/latest.json
DEPENDS ota_push
)
add_custom_target(ota_to_mqtt
COMMAND podman run --rm eclipse-mosquitto:alpine
mosquitto_pub
-h 192.168.0.10
-t devices/esp32p4_01/ota/update
-m '{"version":"${FW_VERSION}","url":"https://192.168.0.9:8443/${OTA_BIN_NAME}","sha256":"","force":true}'
)

View File

@ -0,0 +1,15 @@
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 130 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024 ) )
#define configMAX_TASK_NAME_LEN 10
#define configUSE_16_BIT_TICKS 0
#endif /* FREERTOS_CONFIG_H */

7
Kconfig.projbuild Normal file
View File

@ -0,0 +1,7 @@
menu "Simulation options"
config SIMULATION_QEMU
bool "Build with QEMU simulation stubs"
default n
endmenu

View File

@ -1,3 +1,7 @@
docker run -v $PWD:/app -w /app lvfontconv lv_font_conv --bpp 4 --size 24 --no-compress --font Montserrat-Medium.ttf --symbols "0123456789.°èéêûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz :-%," --format lvgl -o montserrat_medium_24.c --font fa-solid-900.ttf --range 61461,0xf0c2,0xf575
docker run -v $PWD:/app -w /app lvfontconv lv_font_conv --bpp 4 --size 18 --no-compress --font Montserrat-Medium.ttf --symbols "0123456789.°èéêûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz :-%," --format lvgl -o montserrat_medium_18.c --font fa-solid-900.ttf --range 61461,0xf0c2,0xf575
docker run -v $PWD:/app -w /app lvfontconv lv_font_conv --bpp 4 --size 12 --no-compress --font Montserrat-Medium.ttf --symbols "0123456789.°èéêûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz :-%," --format lvgl -o montserrat_medium_12.c --font fa-solid-900.ttf --range 61461,0xf0c2,0xf575
Pour lancer avec qemu:
idf.py qemu --graphics --qemu-extra-args "-m 8M -global driver=ssi_psram,property=is_octal,value=true" monitor

8647
compile_commands.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.16)
idf_component_register(SRCS "RemindMe.c"
INCLUDE_DIRS "include"
REQUIRES json spiffs)

View File

@ -0,0 +1,216 @@
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "cJSON.h"
#include "esp_spiffs.h"
#include "RemindMe.h"
#include <time.h>
static const char *TAG = "JSON_READER";
static void copy_json_string(cJSON *item,
const char *key,
char *dst,
size_t dst_size)
{
cJSON *v = cJSON_GetObjectItem(item, key);
if (cJSON_IsString(v) && v->valuestring)
{
strncpy(dst, v->valuestring, dst_size - 1);
dst[dst_size - 1] = '\0';
}
}
static RemindMeEvent *get_events_from_file(const char *filepath, int *count)
{
*count = 0;
FILE *f = fopen(filepath, "r");
if (!f)
{
ESP_LOGE(TAG, "Impossible d'ouvrir le fichier");
return NULL;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char *json_string = malloc(size + 1);
if (!json_string)
{
fclose(f);
return NULL;
}
fread(json_string, 1, size, f);
fclose(f);
json_string[size] = 0;
cJSON *json = cJSON_Parse(json_string);
free(json_string);
if (!cJSON_IsArray(json))
{
cJSON_Delete(json);
return NULL;
}
int n = cJSON_GetArraySize(json);
if (n == 0)
{
cJSON_Delete(json);
return NULL;
}
RemindMeEvent *events = calloc(n, sizeof(RemindMeEvent));
if (!events)
{
cJSON_Delete(json);
return NULL;
}
for (int i = 0; i < n; i++)
{
cJSON *item = cJSON_GetArrayItem(json, i);
copy_json_string(item, "evenement", events[i].evenement, sizeof(events[i].evenement));
copy_json_string(item, "affichage", events[i].affichage, sizeof(events[i].affichage));
copy_json_string(item, "date", events[i].date, sizeof(events[i].date));
copy_json_string(item, "type", events[i].type, sizeof(events[i].type));
}
cJSON_Delete(json);
*count = n;
return events;
}
static void read_json_file(const char *filepath, cJSON **root)
{
FILE *f = fopen(filepath, "r");
if (!f)
{
ESP_LOGE(TAG, "Impossible d'ouvrir le fichier");
return;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char *json_string = malloc(size + 1);
if (!json_string)
{
fclose(f);
return;
}
fread(json_string, 1, size, f);
fclose(f);
json_string[size] = 0;
*root = cJSON_Parse(json_string);
free(json_string);
}
/**
* Parse une date au format "YYYY-MM-DD" et retourne le timestamp
*/
time_t parse_date(const char *date_str)
{
struct tm tm = {0};
// Parser la date (format: YYYY-MM-DD)
sscanf(date_str, "%d-%d-%d",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday);
tm.tm_year -= 1900; // Années depuis 1900
tm.tm_mon -= 1; // Mois de 0 à 11
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
return mktime(&tm);
}
/**
* Calcule le nombre de jours entre maintenant et la date donnée
* Retourne un nombre négatif si la date est passée
*/
int days_until(const char *date_str)
{
// Obtenir l'heure actuelle
time_t now;
time(&now);
// Parser la date cible
time_t target = parse_date(date_str);
// Calculer la différence en secondes
double diff_seconds = difftime(target, now);
// Convertir en jours (arrondi)
int days = (int)(diff_seconds / (60 * 60 * 24));
return days;
}
RemindMeEvent *get_events(int *count)
{
RemindMeEvent *evts = get_events_from_file(
"/spiffs/events.json",
count);
for (size_t i = 0; i < *count; i++)
{
sprintf(evts[i].affichage, evts[i].affichage, days_until(evts[i].date));
}
return evts;
}
esp_err_t events_save_atomic(char *eventsJson)
{
FILE *f = fopen("/spiffs/events.tmp", "w");
if (!f)
goto error;
fwrite(eventsJson, 1, strlen(eventsJson), f);
fclose(f);
rename("/spiffs/events.json", "/spiffs/events.bak");
rename("/spiffs/events.tmp", "/spiffs/events.json");
//unlink("/spiffs/events.bak");
free(eventsJson);
return ESP_OK;
error:
free(eventsJson);
return ESP_FAIL;
}
void add_event(RemindMeEvent e){
int count=0;
cJSON *root = cJSON_CreateObject();
read_json_file("/spiffs/events.json", &root);
printf("%s","####################### AVANT\n");
//printf("%s\n",cJSON_Print(root));
if (!cJSON_IsArray(root))
{
ESP_LOGE(TAG, "'root' n'est pas un tableau");
return;
}else{
cJSON *new_event = cJSON_CreateObject();
if (!new_event)
return;
cJSON_AddStringToObject(new_event, "evenement", e.evenement);
cJSON_AddStringToObject(new_event, "affichage", e.affichage);
cJSON_AddStringToObject(new_event, "date", e.date);
cJSON_AddStringToObject(new_event, "type", e.type);
cJSON_AddItemToArray(root, new_event);
}
printf("%s", "####################### APRES\n");
//printf("%s\n", cJSON_Print(root));
char *eventsJson=cJSON_Print(root);
events_save_atomic(eventsJson);
}

View File

@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: '>=4.1.0'

View File

@ -0,0 +1,19 @@
#pragma once
typedef struct
{
char evenement[64];
char affichage[128];
char date[32];
char type[40];
} RemindMeEvent;
/**
* Charge les événements depuis le fichier JSON
* @param count (out) nombre d'événements chargés
* @return pointeur vers tableau d'événements ou NULL en cas d'erreur
*
* L'appelant doit libérer la mémoire avec free()
*/
RemindMeEvent *get_events(int *count);
void add_event();

View File

@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
list(APPEND EXTRA_COMPONENT_DIRS
../../RemindMe
)
project(remindme_host_test)

View File

@ -0,0 +1,10 @@
dependencies:
idf:
source:
type: idf
version: 5.5.1
direct_dependencies:
- idf
manifest_hash: 2fc18f414627b3fc737adcef5ecbfa3a4f7cff55fd5f96a20734c8d5302b79ed
target: linux
version: 2.0.0

View File

@ -0,0 +1,4 @@
idf_component_register(
SRCS "main.c"
REQUIRES RemindMe
)

View File

@ -0,0 +1,28 @@
#include "RemindMe.h"
#include "esp_log.h"
int app_main(int argc, char *argv[])
{
int count=0;
RemindMeEvent *events= get_events(&count);
if (!events)
{
ESP_LOGE("test", "Aucun événement chargé");
return 0;
} // Parcourir tous les événements
for (int i = 0; i < count; i++)
{
ESP_LOGI("test", "%s", events[i].affichage);
}
RemindMeEvent e = {
.affichage = "Test dans %d jours",
.date="2026-12-31",
.type="remaining_days",
.evenement="test"
};
add_event(e);
return 0;
}

View File

@ -0,0 +1,9 @@
#include "unity.h"
#include "RemindMe.h"
TEST_CASE("Test lecture JSON", "[RemindMe]")
{
Event event = {0};
esp_err_t ret = read_json_file("/spiffs/test.json", &event);
TEST_ASSERT_EQUAL(ESP_OK, ret);
}

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "audio.c"
INCLUDE_DIRS "include"
REQUIRES esp32_p4_function_ev_board)

224
components/audio/audio.c Normal file
View File

@ -0,0 +1,224 @@
#include <stdio.h>
#include "audio.h"
#include <stdio.h>
#include <inttypes.h>
#include <sdkconfig.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "bsp/esp-bsp.h"
/* Buffer for reading/writing to I2S driver. Same length as SPIFFS buffer and I2S buffer, for optimal read/write performance.
External SPI Flash -> SPIFFS buffer -> App buffer (RAM) -> I2S buffer (DMA) -> I2S peripheral.
*/
#define BUFFER_SIZE (1024)
#define DEFAULT_VOLUME (50)
/* Globals */
static const char *TAG = "audio";
TaskHandle_t audio_task_handle;
// Very simple WAV header, ignores most fields
typedef struct __attribute__((packed))
{
uint8_t ignore_0[22];
uint16_t num_channels;
uint32_t sample_rate;
uint8_t ignore_1[6];
uint16_t bits_per_sample;
uint8_t ignore_2[4];
uint32_t data_size;
uint8_t data[];
} dumb_wav_header_t;
typedef struct {
FILE *f;
uint32_t data_offset;
uint32_t data_size;
} wav_ctx_t;
#define AUDIO_CHUNK_SIZE 4096
bool wav_open(wav_ctx_t *ctx, const char *path)
{
ctx->f = fopen(path, "rb");
if (!ctx->f) return false;
/* Skip RIFF header */
fseek(ctx->f, 12, SEEK_SET);
uint32_t chunk_id, chunk_size;
while (fread(&chunk_id, 4, 1, ctx->f))
{
fread(&chunk_size, 4, 1, ctx->f);
if (chunk_id == 0x61746164) { // "data"
ctx->data_offset = ftell(ctx->f);
ctx->data_size = chunk_size;
return true;
}
fseek(ctx->f, chunk_size, SEEK_CUR);
}
fclose(ctx->f);
return false;
}
void rewind_wav(wav_ctx_t *ctx)
{
fseek(ctx->f, ctx->data_offset, SEEK_SET);
}
#define AUDIO_CHUNK_SIZE 4096
static void audio_task(void *arg)
{
ESP_LOGI(TAG,"Audio task");
esp_codec_dev_handle_t spk_codec_dev = bsp_audio_codec_speaker_init();
assert(spk_codec_dev);
esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);
esp_codec_dev_set_out_mute(spk_codec_dev, false); // 🔑 CRITIQUE
const char *play_filename = "/littlefs/sounds/mixkit-clear-announce-tones-2861.wav";
uint8_t *wav_bytes = malloc(BUFFER_SIZE);
assert(wav_bytes != NULL);
for (;;)
{
/* ⏸️ Attend PLAY */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
bool stop_requested = false;
while (!stop_requested) {
ESP_LOGI(TAG,"On joue !");
FILE *play_file = fopen(play_filename, "rb");
if (!play_file) {
ESP_LOGE(TAG,"File not found");
break;
}
dumb_wav_header_t wav_header;
if (fread(&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
ESP_LOGE(TAG,"Header read failed");
fclose(play_file);
break;
}
esp_codec_dev_sample_info_t fs = {
.sample_rate = wav_header.sample_rate,
.channel = wav_header.num_channels,
.bits_per_sample = wav_header.bits_per_sample,
};
ESP_ERROR_CHECK(esp_codec_dev_open(spk_codec_dev, &fs));
uint32_t bytes_sent = 0;
while (bytes_sent < wav_header.data_size) {
size_t bytes_read = fread(wav_bytes, 1, BUFFER_SIZE, play_file);
if (bytes_read == 0) break;
esp_codec_dev_write(spk_codec_dev, wav_bytes, bytes_read);
bytes_sent += bytes_read;
vTaskDelay(1); // watchdog + scheduler
}
esp_codec_dev_close(spk_codec_dev);
fclose(play_file);
ESP_LOGI(TAG,"Fin du fichier");
if (ulTaskNotifyTake(pdTRUE, 0) > 0) {
stop_requested = true;
}
}
}
free(wav_bytes);
}
static void audio_task__(void *arg)
{
ESP_LOGE(TAG,"Audio task");
esp_codec_dev_handle_t spk_codec_dev = bsp_audio_codec_speaker_init();
assert(spk_codec_dev);
esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);
/* Pointer to a file that is going to be played */
const char music_filename[] = "/littlefs/sounds/mixkit-clear-announce-tones-2861.wav";
const char *play_filename = music_filename;
int16_t *wav_bytes = malloc(BUFFER_SIZE);
assert(wav_bytes != NULL);
bool stop_requested = false;
while (!stop_requested){
ESP_LOGE(TAG,"On joue !");
/* Open WAV file */
ESP_LOGI(TAG, "Playing file %s", play_filename);
FILE *play_file = fopen(play_filename, "rb");
if (play_file == NULL) {
ESP_LOGW(TAG, "%s file does not exist!", play_filename);
break;
}
/* Read WAV header file */
dumb_wav_header_t wav_header;
if (fread((void *)&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
ESP_LOGW(TAG, "Error in reading file");
break;
}
//ESP_LOGI(TAG, "Number of channels: %" PRIu16 "", wav_header.num_channels);
//ESP_LOGI(TAG, "Bits per sample: %" PRIu16 "", wav_header.bits_per_sample);
//ESP_LOGI(TAG, "Sample rate: %" PRIu32 "", wav_header.sample_rate);
//ESP_LOGI(TAG, "Data size: %" PRIu32 "", wav_header.data_size);
esp_codec_dev_sample_info_t fs = {
.sample_rate = wav_header.sample_rate,
.channel = wav_header.num_channels,
.bits_per_sample = wav_header.bits_per_sample,
};
esp_codec_dev_open(spk_codec_dev, &fs);
uint32_t bytes_send_to_i2s = 0;
while (bytes_send_to_i2s < wav_header.data_size) {
/* Get data from SPIFFS and send it to codec */
size_t bytes_read_from_spiffs = fread(wav_bytes, 1, BUFFER_SIZE, play_file);
esp_codec_dev_write(spk_codec_dev, wav_bytes, bytes_read_from_spiffs);
bytes_send_to_i2s += bytes_read_from_spiffs;
/* ⭐ LIGNE CRITIQUE ⭐ */
vTaskDelay(1); // laisse respirer IDLE + watchdog
}
ESP_LOGE(TAG,"On a fini le fichier");
fclose(play_file);
esp_codec_dev_close(spk_codec_dev);
if(ulTaskNotifyTake(pdTRUE, 0)>0){
stop_requested=true;
break;
};
}
free(wav_bytes);
vTaskSuspend(NULL);
}
void playSound(void)
{
if(audio_task_handle==NULL){
BaseType_t ret = xTaskCreate(audio_task, "audio_task", 4096, NULL, 6, &audio_task_handle);
assert(ret == pdPASS);
}
xTaskNotifyGive(audio_task_handle);
}
void stopSound(void){
if (audio_task_handle) {
xTaskNotifyGive(audio_task_handle);
}
}

View File

@ -0,0 +1,4 @@
void playSound(void);
void stopSound(void);

View File

@ -0,0 +1,37 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "${config:idf.toolsPath}/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
"compileCommands": [
"${config:idf.buildPath}/compile_commands.json"
],
"includePath": [
"${config:idf.espIdfPath}/components/**",
"${config:idf.espIdfPathWin}/components/**",
"${workspaceFolder}/**"
],
"defines": ["LV_CONF_SKIP"],
"browse": {
"path": [
"${config:idf.espIdfPath}/components",
"${config:idf.espIdfPathWin}/components",
"${workspaceFolder}"
],
"limitSymbolsToIncludedHeaders": true
}
},
{
"name": "linux-host",
"includePath": [
"${workspaceFolder}/**"
],
"defines": ["LV_CONF_SKIP"],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

View File

@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "cppdbg",
"request": "launch",
"name": "Eclipse CDT GDB Adapter",
"program": "${workspaceFolder}/test_host/build/nvs_host_test.elf",
"cwd": "${workspaceFolder}/test_host",
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
}
],
}

View File

@ -0,0 +1,9 @@
{
"idf.pythonInstallPath": "/usr/bin/python3",
"files.associations": {
"model.h": "c",
"lvgl.h": "c",
"lv_init.h": "c",
"lv_conf_internal.h": "c"
}
}

View File

@ -0,0 +1,49 @@
include(${CMAKE_CURRENT_LIST_DIR}/fonts_symbols.cmake)
string(JOIN "," LVGL_SYMBOLS ${LVGL_SYMBOLS_CLASSIQUES})
message(STATUS "LVGL SYMBOL RANGE = ${LVGL_SYMBOLS}")
function (make_font fontName fileName fontSize)
execute_process(COMMAND podman run -v ${PROJECT_DIR}/components/domotic_display/fonts:/app -w /app lvfontconv lv_font_conv --bpp 4 --size ${fontSize} --no-compress --font ${fontName}.ttf --symbols "0123456789.°àéèêëûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz %,'!? ():/-" --format lvgl -o ${fileName}_${fontSize}.c --font fa-solid-900.ttf --range ${LVGL_SYMBOLS})
endfunction()
make_font(Montserrat-Medium montserrat_medium 12 )
make_font(Montserrat-Medium montserrat_medium 18)
make_font(Montserrat-Medium montserrat_medium 24)
make_font(Roboto-Medium roboto_medium 36)
make_font(Roboto-Medium roboto_medium 72)
make_font(Super_Malibu super_malibu 80)
#execute_process(COMMAND podman run -v /home/marc/rgb_lcd/components/domotic_display/fonts:/app -w /app lvfontconv lv_font_conv --bpp 4 --size 36 --no-compress --font Roboto-Medium.ttf --symbols "0123456789.°àéèûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz %,'():ê/-" --format lvgl -o roboto_medium_36.c --font fa-solid-900.ttf --range 61461,0xf0c2,0xf575)
#execute_process(COMMAND podman run -v /home/marc/rgb_lcd/components/domotic_display/fonts:/app -w /app lvfontconv lv_font_conv --bpp 4 --size 72 --no-compress --font Roboto-Medium.ttf --symbols "0123456789.°àéèûCABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz %,'():ê/-" --format lvgl -o roboto_medium_72.c --font fa-solid-900.ttf --range 61461,0xf0c2,0xf575)
SET(comps meteofrance eventsManager lvgl RemindMe washingMachineState)
if(${IDF_TARGET} STREQUAL "esp32p4" OR ${IDF_TARGET} STREQUAL "esp32s3")
#esp32_p4_function_ev_board
idf_component_register(SRC_DIRS . fonts
INCLUDE_DIRS "include"
REQUIRES ${comps} esp_lvgl_port esp32_p4_function_ev_board )
target_compile_options(${COMPONENT_LIB} PUBLIC -DLV_LVGL_H_INCLUDE_SIMPLE)
lvgl_port_create_c_image("images/wifi_ok.png" "images/" "ARGB8888" "NONE")
lvgl_port_create_c_image("images/wifi_ko.png" "images/" "ARGB8888" "NONE")
lvgl_port_create_c_image("images/mqtt_ok.png" "images/" "AUTO" "NONE")
lvgl_port_create_c_image("images/mqtt_ko.png" "images/" "ARGB8888" "NONE")
lvgl_port_add_images(${COMPONENT_LIB} "images/")
elseif(${IDF_TARGET} STREQUAL "linux")
idf_component_register(SRC_DIRS . fonts images
INCLUDE_DIRS "include"
REQUIRES ${comps})
message("Including SDL2 support")
find_package(SDL2 REQUIRED)
target_link_libraries(${COMPONENT_LIB} PUBLIC
-Wl,--no-as-needed
SDL2
-Wl,--as-needed
)
target_compile_options(${COMPONENT_LIB} PUBLIC -DLV_LVGL_H_INCLUDE_SIMPLE)
endif()

View File

@ -0,0 +1,7 @@
#include <stdio.h>
#include "domotic_display.h"
void func(void)
{
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
# Symboles perso
# --- Weather ---
set(MY_SYMBOL_CLOUD 0xf0c2) # cloud | UTF-8: "\xEF\x83\x82"
set(MY_SYMBOL_CLOUD_SUN 0xf575) # cloud-sun | UTF-8: "\xEF\x95\xB5"
# --- Navigation ---
set(MY_SYMBOL_UP 0xf077) # chevron-up | UTF-8: "\xEF\x81\xB7"
set(MY_SYMBOL_DOWN 0xf078) # chevron-down | UTF-8: "\xEF\x81\xB8"
# --- Sensors ---
set(MY_SYMBOL_THERMOMETER 0xf2ca) # thermometer | UTF-8: "\xEF\x89\xBA"
set(MY_SYMBOL_MESSAGE 0xf27a) # message | UTF-8: "\xEF\x89\xBA"
# --- Location / House ---
set(MY_THERMOMETER_IN_HOUSE 0xe1b0) # house-user | UTF-8: "\xEE\x86\xB0"
set(MY_THERMOMETER_OUT_HOUSE 0xe1b0) # house-user | UTF-8: "\xEE\x86\xB0"
# ======================================
# LVGL symbols (FontAwesome solid mapped)
# ======================================
# --- Base UI ---
set(LV_SYMBOL_OK 0xf00c) # check
set(LV_SYMBOL_CLOSE 0xf00d) # times
set(LV_SYMBOL_POWER 0xf011) # power-off
set(LV_SYMBOL_SETTINGS 0xf013) # gear
set(LV_SYMBOL_HOME 0xf015) # home
set(LV_SYMBOL_DOWNLOAD 0xf019) # download
set(LV_SYMBOL_REFRESH 0xf021) # refresh
set(LV_SYMBOL_LOCK 0xf023) # lock
set(LV_SYMBOL_WIFI 0xf1eb) # wifi
set(LV_SYMBOL_BELL 0xf0f3) # bell
set(LV_SYMBOL_BATTERY_FULL 0xf240) # battery-full
set(LV_SYMBOL_BATTERY_3 0xf241) # battery-3/4
set(LV_SYMBOL_BATTERY_2 0xf242) # battery-1/2
set(LV_SYMBOL_BATTERY_1 0xf243) # battery-1/4
set(LV_SYMBOL_BATTERY_EMPTY 0xf244) # battery-empty
# --- Navigation ---
set(LV_SYMBOL_LEFT 0xf060) # arrow-left
set(LV_SYMBOL_RIGHT 0xf061) # arrow-right
set(LV_SYMBOL_UP 0xf062) # arrow-up
set(LV_SYMBOL_DOWN 0xf063) # arrow-down
set(LV_SYMBOL_NEXT 0xf061) # alias RIGHT
set(LV_SYMBOL_PREV 0xf060) # alias LEFT
# --- Media / Actions ---
set(LV_SYMBOL_PLAY 0xf04b) # play
set(LV_SYMBOL_PAUSE 0xf04c) # pause
set(LV_SYMBOL_STOP 0xf04d) # stop
set(LV_SYMBOL_EJECT 0xf052) # eject
set(LV_SYMBOL_VOLUME_UP 0xf028)
set(LV_SYMBOL_VOLUME_DOWN 0xf027)
set(LV_SYMBOL_MUTE 0xf026)
# --- Information ---
set(LV_SYMBOL_EYE_OPEN 0xf06e)
set(LV_SYMBOL_EYE_CLOSE 0xf070)
set(LV_SYMBOL_WARNING 0xf071)
set(LV_SYMBOL_INFO 0xf05a)
set(LV_SYMBOL_QUESTION 0xf128)
# --- Time / Status ---
set(LV_SYMBOL_CLOCK 0xf017)
set(LV_SYMBOL_CALENDAR 0xf073)
# --- List of symbols used for font generation ---
set(LVGL_SYMBOLS_CLASSIQUES
${LV_SYMBOL_OK}
${LV_SYMBOL_CLOSE}
${LV_SYMBOL_POWER}
${LV_SYMBOL_SETTINGS}
${LV_SYMBOL_HOME}
${LV_SYMBOL_DOWNLOAD}
${LV_SYMBOL_REFRESH}
${LV_SYMBOL_LOCK}
${LV_SYMBOL_WIFI}
${LV_SYMBOL_BELL}
${LV_SYMBOL_BATTERY_FULL}
${LV_SYMBOL_BATTERY_3}
${LV_SYMBOL_BATTERY_2}
${LV_SYMBOL_BATTERY_1}
${LV_SYMBOL_BATTERY_EMPTY}
${LV_SYMBOL_LEFT}
${LV_SYMBOL_RIGHT}
${LV_SYMBOL_UP}
${LV_SYMBOL_DOWN}
${LV_SYMBOL_PLAY}
${LV_SYMBOL_PAUSE}
${LV_SYMBOL_STOP}
${LV_SYMBOL_VOLUME_UP}
${LV_SYMBOL_VOLUME_DOWN}
${LV_SYMBOL_MUTE}
${LV_SYMBOL_EYE_OPEN}
${LV_SYMBOL_EYE_CLOSE}
${LV_SYMBOL_WARNING}
${LV_SYMBOL_INFO}
${LV_SYMBOL_QUESTION}
${LV_SYMBOL_CLOCK}
${LV_SYMBOL_CALENDAR}
${MY_SYMBOL_CLOUD}
${MY_SYMBOL_CLOUD_SUN}
${MY_SYMBOL_UP}
${MY_SYMBOL_DOWN}
${MY_SYMBOL_THERMOMETER}
${MY_SYMBOL_MESSAGE}
${MY_THERMOMETER_IN_HOUSE}
)

View File

@ -0,0 +1,28 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: '>=4.1.0'
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true
espressif/esp_lvgl_port:
rules:
- if: target in ["esp32p4","esp32, "esp32s3"]
version: ^2.7.0
lvgl/lvgl:
rules:
- if: target in ["linux"]
version: 9.4.0
espressif/esp_lcd_qemu_rgb:
rules:
- if: target in ["esp32, "esp32s3"]
version: ^1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
// ihm_gateway.c
#include "ihm_gateway.h"
#include "ihm.h"
#include <stdio.h>
#include <stdlib.h>
#include "platform_detect.h"
#include "cJSON.h"
#include "esp_log.h"
#include "washingMachineState.h"
static const char *TAG = "IHM_GW";
static QueueHandle_t xIHMEventQueue = NULL;
QueueHandle_t getIHMQueueHandle(void) {
return xIHMEventQueue;
}
void ihm_gateway_init(void) {
if (!xIHMEventQueue) {
xIHMEventQueue = xQueueCreate(32, sizeof(xIHMEvent_t *));
}
}
void ihm_gateway_post_event(xIHMEvent_t *evt) {
if (!xIHMEventQueue) return;
if (platform_is_pc()) {
xQueueSend(xIHMEventQueue, &evt, 0); // non bloquant sur PC
} else {
xQueueSend(xIHMEventQueue, &evt, portMAX_DELAY); // bloquant ESP32
}
}
extern lv_subject_t wifiStatus;
static xIHMEvent_t *evt = NULL;
void ihm_gateway_process_queue(void) {
if (!xIHMEventQueue) return;
#if CONFIG_IDF_TARGET_LINUX
while (xQueueReceive(xIHMEventQueue, &evt, pdMS_TO_TICKS(0)) == pdTRUE)
#else
while (xQueueReceive(xIHMEventQueue, &evt, pdMS_TO_TICKS(10)) == pdTRUE)
#endif
{
if (!evt) return;
UBaseType_t pending = uxQueueMessagesWaiting(xIHMEventQueue);
ESP_LOGV(TAG,"Evt recu %d. La queue comporte %d éléments à traiter", evt->eEventType, pending);
lv_async_call(traiteEvt, evt);
}
}
void traiteEvt(void *arg)
{
xIHMEvent_t *evt = (xIHMEvent_t *)arg;
switch (evt->eEventType)
{
case IHM_EVT_WIFI_STATUS:
lv_subject_set_int(&wifiStatus, *(bool *)evt->pvData);
break;
case IHM_EVT_TIME_SETTED:
draw_time(evt->pvData);
evt->bNeedToFreeData=false;
break;
case IHM_EVT_OTA_STARTED:
app_ota_display();
break;
case IHM_EVT_HUMID_TEMP:
draw_temp((char *)evt->pvData);
evt->bNeedToFreeData=false;
break;
case IHM_EVT_TEMP_RECUE:
draw_tempExt((char *)evt->pvData);
evt->bNeedToFreeData=false;
break;
case IHM_EVT_PUISSANCE_EMISE:
{
int val = *(int *)evt->pvData;
// if(val == 0) lv_chart_set_next_value(myChart, ser, LV_CHART_POINT_NONE);
// else lv_chart_set_next_value(myChart, ser, val);
break;
}
case IHM_EVT_ETAT_MACHINE:
{
char *etatMachine = evt->pvData;
WashingMachineState wms = traiteMessage(etatMachine);
char etat[80];
getEtatMachineStr(wms, etat,80);
ESP_LOGI(TAG,"Etat machine : %s", etat);
draw_minuteur(etat);
// lv_label_set_text(lblEtatMachine, etatFormate);
break;
}
case IHM_EVT_MACHINE_TERMINEE:
{
draw_minuteurStop();
}
case IHM_EVT_HAUTEUR_CUVE:
{
float hauteur = *(float *)evt->pvData;
// lv_label_set_text_fmt(lblHauteurCuve, "%.0f cm", hauteur);
break;
}
case IHM_EVT_METEO_RECUE:{
//(void *)evt->pvData; // Pointeur sur tableau
//(void *)evt->pvData
ESP_LOGI(TAG, "Reception evt MF");
// On ne veut liberer la memoire que lorsque l'evenement aura été traité!
evt->bNeedToFreeData=false;
meteo_event_payload_t *datas = (meteo_event_payload_t *) evt->pvData;
for (size_t i = 0; i < 3; i++)
{
ESP_LOGI(TAG,"Type: %s - Valide : %d - %s", datas->daily[i].type, datas->daily[i].isValid, datas->daily[i].previsions.desc);
}
for (size_t i = 0; i < 3; i++)
{
ESP_LOGI(TAG,"Type: %s - Valide : %d - %s - %s - %f", datas->forecast[i].type, datas->forecast[i].isValid, datas->forecast[i].previsions.desc, datas->forecast[i].previsions.icon, datas->forecast[i].previsions.value);
}
draw_meteo(datas);
//lv_subject_set_int(&meteoStatus, 0);
//display_unlock("weather_data_retreived");
ESP_LOGI(TAG, "Fin Reception evt MF");
break;
}
default:
ESP_LOGE(TAG, "Evt inconnu");
break;
}
// Nettoyage mémoire sécurisé
if (evt->bNeedToFreeData && evt->pvData){
//ESP_LOGE(TAG, "Libération mémoire");
free(evt->pvData);
}
free(evt);
ESP_LOGV(TAG, "Evt traité");
}

View File

Before

Width:  |  Height:  |  Size: 654 B

After

Width:  |  Height:  |  Size: 654 B

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 483 B

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 372 B

After

Width:  |  Height:  |  Size: 372 B

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Some files were not shown because too many files have changed in this diff Show More