← - Guide et exemples Arduino. | Sommaire | Suivant: Composant ESPHome →
Guide et exemples ESP-IDF
Bibliothèque universelle de variateurs pour ESP32. Guide et exemples pour ESP-IDF framework C.
Avant de commencer, veuillez consulter l'aperçu de la bibliothèque : Bibliothèque universelle pour ESP32
Exigences et compatibilité
- Version minimale d'ESP-IDF : 5.3
- Puces supportées : ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6
- La bibliothèque utilise
Kconfigstandard pour la configuration de compilation (renommé deKconfig.txten v2.0.0)
Nouveautés dans v2.0.0
La version 2.0.0 est une réécriture majeure interne. L'API publique est entièrement rétro-compatible — aucune modification de votre code d'application n'est requise.
Améliorations internes :
- Architecture modulaire — le code est divisé en 7 modules internes (moteur de phase, gestionnaire de canaux, tables de courbes, noyau ISR, etc.). Le seul en-tête public
rbdimmerESP32.hreste le seul include dont vous avez besoin. - Tous les ISR utilisent
IRAM_ATTRet les minuteurs utilisent la distributionESP_TIMER_ISRpour un timing déterministe sub-microseconde. - Porte de bruit de zéro-crossing — une fenêtre de rebond configurable rejette le bruit électrique et les faux déclenchements sur l'entrée de zéro-crossing. Par défaut : 3000 us.
- ISR à deux passages pour la synchronisation multi-canaux — lorsque plusieurs canaux partagent une phase, l'ISR les pré-trie par délai et déclenche les impulsions TRIAC en un seul passage consolidé, éliminant la gigue de timing entre les canaux.
- Configuration de compilation
Kconfig— le fichier est maintenant nomméKconfig(convention ESP-IDF standard ; auparavantKconfig.txt).
Nouveaux paramètres Kconfig :
| Paramètre | Par défaut | Description |
|---|---|---|
CONFIG_RBDIMMER_ZC_DEBOUNCE_US |
3000 | Fenêtre de rebond de zéro-crossing en microsecondes |
CONFIG_RBDIMMER_MIN_DELAY_US |
100 | Délai minimal de déclenchement TRIAC en microsecondes |
CONFIG_RBDIMMER_LEVEL_MIN |
3 | Niveau d'atténuation minimal (%). Les valeurs ci-dessous sont traitées comme OFF |
CONFIG_RBDIMMER_LEVEL_MAX |
99 | Niveau d'atténuation maximal (%) |
Installation
Utilisation de CMake avec ESP-IDF
- Téléchargez la bibliothèque
rbdimmerESP32depuis le référentiel GitHub :
git clone https://github.com/your-username/rbdimmerESP32 components/rbdimmer- Configure your project's
CMakeLists.txtto include the library:
# Main project CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(your_project_name)- Add component dependency in your application's
CMakeLists.txt:
# App CMakeLists.txt
idf_component_register(
SRCS "main.c"
INCLUDE_DIRS "."
REQUIRES rbdimmer
)- The library's
CMakeLists.txtandKconfigare included automatically when placed incomponents/rbdimmer/. The componentCMakeLists.txtregisters sources, includes, and dependencies:
# components/rbdimmer/CMakeLists.txt
idf_component_register(
SRCS "rbdimmerESP32.c"
INCLUDE_DIRS "include"
REQUIRES driver esp_timer freertos
)Kconfig (convention ESP-IDF standard). Si vous effectuez une mise à niveau à partir d'une version antérieure qui utilisait Kconfig.txt, renommez-le en Kconfig.Configuration Kconfig
La bibliothèque expose les paramètres de réglage via le système menuconfig d'ESP-IDF. Pour les ajuster :
idf.py menuconfig
# Navigate to: Component config → RBDimmer ConfigurationOptions disponibles :
- Rebond de zéro-crossing (us) —
CONFIG_RBDIMMER_ZC_DEBOUNCE_US(par défaut 3000). Augmentez si vous observez de faux déclenchements de zéro-crossing dus au bruit électrique. - Délai minimal TRIAC (us) —
CONFIG_RBDIMMER_MIN_DELAY_US(par défaut 100). Empêche le TRIAC de se déclencher trop proche du zéro-crossing, ce qui peut causer un scintillement à haute luminosité. - Niveau Min (%) —
CONFIG_RBDIMMER_LEVEL_MIN(par défaut 3). Les niveaux en dessous de ce seuil sont traités comme OFF pour éviter un comportement instable du TRIAC. - Niveau Max (%) —
CONFIG_RBDIMMER_LEVEL_MAX(par défaut 99). Limite l'angle de déclenchement maximal.
Connexion matérielle
Instructions pour connecter le variateur au microcontrôleur et à la charge AC :
- Connectez la Broche de zéro-crossing à n'importe quel GPIO ayant des capacités ISR. Consultez la documentation de votre puce ESP32
- Connectez la Broche de variateur à n'importe quel GPIO
- VCC à 3.3V (pour ESP32, VCC = 3.3V)
- GND à GND
Exemple basique (ESP-IDF / C)
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "rbdimmerESP32.h"
static const char *TAG = "DIMMER_EXAMPLE";
// Pins
#define ZERO_CROSS_PIN 18 // Zero-Cross pin
#define DIMMER_PIN 19 // Dimming control pin
#define PHASE_NUM 0 // Phase N (0 for single phase)
// Global variables. Dimmer object
rbdimmer_channel_t* dimmer_channel = NULL;
void app_main(void)
{
ESP_LOGI(TAG, "AC Dimmer Test");
// Dimmer lib init
if (rbdimmer_init() != RBDIMMER_OK) {
ESP_LOGE(TAG, "Failed to initialize AC Dimmer library");
return;
}
// Zero-cross detector and phase registry
if (rbdimmer_register_zero_cross(ZERO_CROSS_PIN, PHASE_NUM, 0) != RBDIMMER_OK) {
ESP_LOGE(TAG, "Failed to register zero-cross detector");
return;
}
// Dimmer channel. Configuration data structure.
rbdimmer_config_t config_channel = {
.gpio_pin = DIMMER_PIN,
.phase = PHASE_NUM,
.initial_level = 50, // Initial dimming level 50%
.curve_type = RBDIMMER_CURVE_RMS // Level Curve Selection. RMS-curve
};
if (rbdimmer_create_channel(&config_channel, &dimmer_channel) != RBDIMMER_OK) {
ESP_LOGE(TAG, "Failed to create dimmer channel");
return;
}
ESP_LOGI(TAG, "AC Dimmer initialized successfully");
// Main loop
while (1) {
// dimming from 10% to 90% with step 10
for (int brightness = 10; brightness <= 90; brightness += 10) {
ESP_LOGI(TAG, "Setting brightness to %d%%", brightness);
rbdimmer_set_level(dimmer_channel, brightness);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
// Smooth transition from current level to 0 level in 5 sec
ESP_LOGI(TAG, "Smooth transition to 0%%");
rbdimmer_set_level_transition(dimmer_channel, 0, 5000);
vTaskDelay(6000 / portTICK_PERIOD_MS); // delay 6 sec
// Smooth transition from current level (0) to 100 level in 5 sec
ESP_LOGI(TAG, "Smooth transition to 100%%");
rbdimmer_set_level_transition(dimmer_channel, 100, 5000);
vTaskDelay(6000 / portTICK_PERIOD_MS); // delay 6 sec
}
} Référence API
Opération de la bibliothèque
Préparation :
- Initialisez la bibliothèque à l'aide de
rbdimmer_init() - Enregistrez le détecteur de passage à zéro en utilisant
rbdimmer_register_zero_cross() - Créez un canal de variateur en utilisant
rbdimmer_create_channel()
Contrôle de l'atténuation :
- Définissez le niveau d'atténuation avec
rbdimmer_set_level(). Le niveau d'atténuation est défini dans la plage 0(OFF) ~ 100(ON) - Transition en douceur du niveau d'atténuation avec
rbdimmer_set_level_transition(). Transition en douceur du niveau actuel au niveau défini sur une période de temps (en millisecondes, 1s=1000ms)
Structures de données
rbdimmer_config_t
typedef struct {
uint8_t gpio_pin; // Dimmer GPIO
uint8_t phase; // Phase number
uint8_t initial_level; // Initial dimming level
rbdimmer_curve_t curve_type; // Level Curve type
} rbdimmer_config_t;Énumérations
rbdimmer_curve_t
Types de courbes de niveau :
typedef enum {
RBDIMMER_CURVE_LINEAR, // Linear curve
RBDIMMER_CURVE_RMS, // RMS-compensated curve (for incandescent bulbs)
RBDIMMER_CURVE_LOGARITHMIC // Logarithmic curve (for dimmable LED)
} rbdimmer_curve_t;rbdimmer_err_t
Réponses des fonctions de la bibliothèque :
typedef enum {
RBDIMMER_OK = 0, // Successful execution
RBDIMMER_ERR_INVALID_ARG, // Invalid argument
RBDIMMER_ERR_NO_MEMORY, // Not enough memory
RBDIMMER_ERR_NOT_FOUND, // Object not found
RBDIMMER_ERR_ALREADY_EXIST, // Object already exists
RBDIMMER_ERR_TIMER_FAILED, // Timer initialization error
RBDIMMER_ERR_GPIO_FAILED // GPIO initialization error
} rbdimmer_err_t;Constantes et macros
En v2.0.0, la plupart des paramètres de réglage ont été déplacés vers Kconfig (voir Configuration Kconfig ci-dessus). Les constantes suivantes restent dans rbdimmerESP32.h :
#define RBDIMMER_MAX_PHASES 4 // Maximum number of phases
#define RBDIMMER_MAX_CHANNELS 8 // Maximum number of channels
#define RBDIMMER_DEFAULT_PULSE_WIDTH_US 50 // Pulse width (us)Les éléments suivants sont maintenant configurables via idf.py menuconfig :
// Kconfig defaults (override via menuconfig):
// CONFIG_RBDIMMER_ZC_DEBOUNCE_US = 3000 // Zero-cross debounce (us)
// CONFIG_RBDIMMER_MIN_DELAY_US = 100 // Minimum TRIAC delay (us)
// CONFIG_RBDIMMER_LEVEL_MIN = 3 // Minimum level (%)
// CONFIG_RBDIMMER_LEVEL_MAX = 99 // Maximum level (%)RBDIMMER_DEFAULT_PULSE_WIDTH_US, car cela concerne les caractéristiques matérielles du variateur.Fonctions
Initialisation et configuration
// Initialize the library
rbdimmer_err_t rbdimmer_init(void);
// Register a zero-cross detector
rbdimmer_err_t rbdimmer_register_zero_cross(uint8_t pin, uint8_t phase, uint16_t frequency);
// Create a dimmer channel
rbdimmer_err_t rbdimmer_create_channel(rbdimmer_config_t* config, rbdimmer_channel_t** channel);
// Set callback function for zero-cross events
rbdimmer_err_t rbdimmer_set_callback(uint8_t phase, void (*callback)(void*), void* user_data);Contrôle de l'atténuation
// Set dimming level
rbdimmer_err_t rbdimmer_set_level(rbdimmer_channel_t* channel, uint8_t level_percent);
// Set brightness with smooth transition
rbdimmer_err_t rbdimmer_set_level_transition(rbdimmer_channel_t* channel, uint8_t level_percent, uint32_t transition_ms);
// Set brightness curve type
rbdimmer_err_t rbdimmer_set_curve(rbdimmer_channel_t* channel, rbdimmer_curve_t curve_type);
// Activate/deactivate channel
rbdimmer_err_t rbdimmer_set_active(rbdimmer_channel_t* channel, bool active);Requêtes d'information
// Get current channel brightness
uint8_t rbdimmer_get_level(rbdimmer_channel_t* channel);
// Get measured mains frequency for the specified phase
uint16_t rbdimmer_get_frequency(uint8_t phase);
// Check if channel is active
bool rbdimmer_is_active(rbdimmer_channel_t* channel);
// Get channel curve type
rbdimmer_curve_t rbdimmer_get_curve(rbdimmer_channel_t* channel);
// Get current channel delay
uint32_t rbdimmer_get_delay(rbdimmer_channel_t* channel);Guide étape par étape
Structure du projet
your_project/
├── CMakeLists.txt
├── main/
│ ├── CMakeLists.txt
│ └── main.c
└── components/
└── rbdimmer/
├── CMakeLists.txt
├── Kconfig
├── include/
│ └── rbdimmer.h
└── rbdimmerESP32.cÉtapes d'implémentation
- Définissez la bibliothèque et les broches dans votre fichier
main.c:
#include "rbdimmer.h"
// Pins
#define ZERO_CROSS_PIN 18 // Zero-Cross pin
#define DIMMER_PIN 19 // Dimming control pin
#define PHASE_NUM 0 // Phase N (0 for single phase)- Créez l'objet de variateur (un pour chaque variateur) :
rbdimmer_channel_t* dimmer_channel = NULL;- Initialisez la bibliothèque de variateur :
rbdimmer_init();- Enregistrez le détecteur de zéro-crossing et la phase :
rbdimmer_register_zero_cross(ZERO_CROSS_PIN, PHASE_NUM, 0);- Configurez le canal de variateur et créez-le :
rbdimmer_config_t config_channel = {
.gpio_pin = DIMMER_PIN,
.phase = PHASE_NUM,
.initial_level = 50, // Initial dimming level 50%
.curve_type = RBDIMMER_CURVE_RMS // Level Curve Selection. RMS-curve
};
rbdimmer_create_channel(&config_channel, &dimmer_channel);- Contrôlez l'atténuation :
// Set specific level
rbdimmer_set_level(dimmer_channel, level);
// Smooth transition
rbdimmer_set_level_transition(dimmer_channel, 0, 5000);Exemples avancés
Systèmes de variateurs multi-canaux
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "rbdimmer.h"
#define ZERO_CROSS_PIN 18
#define DIMMER_PIN_1 19
#define DIMMER_PIN_2 21
#define PHASE_NUM 0
static const char *TAG = "DIMMER_EXAMPLE";
rbdimmer_channel_t* channel1 = NULL;
rbdimmer_channel_t* channel2 = NULL;
void app_main(void)
{
// Initialize library
rbdimmer_init();
// Register zero-cross detector (one per phase)
rbdimmer_register_zero_cross(ZERO_CROSS_PIN, PHASE_NUM, 0);
// Create first channel (incandescent bulbs)
rbdimmer_config_t config1 = {
.gpio_pin = DIMMER_PIN_1,
.phase = PHASE_NUM,
.initial_level = 50,
.curve_type = RBDIMMER_CURVE_RMS
};
rbdimmer_create_channel(&config1, &channel1);
// Create second channel (dimmable LED lighting)
rbdimmer_config_t config2 = {
.gpio_pin = DIMMER_PIN_2,
.phase = PHASE_NUM,
.initial_level = 50,
.curve_type = RBDIMMER_CURVE_LOGARITHMIC
};
rbdimmer_create_channel(&config2, &channel2);
// Main control loop
while (1) {
// Control channels independently
rbdimmer_set_level(channel1, 75);
rbdimmer_set_level(channel2, 25);
vTaskDelay(2000 / portTICK_PERIOD_MS);
rbdimmer_set_level(channel1, 25);
rbdimmer_set_level(channel2, 75);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
} Utilisation de fonctions de rappel d'interruption de zéro-crossing
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "rbdimmer.h"
#define ZERO_CROSS_PIN 18
#define DIMMER_PIN 19
#define LED_PIN 2 // Built-in LED for zero-cross visualization
#define PHASE_NUM 0
static const char *TAG = "DIMMER_CALLBACK";
rbdimmer_channel_t* dimmer = NULL;
QueueHandle_t zero_cross_queue;
// Simple message for our queue
typedef struct {
uint32_t timestamp;
} ZeroCrossEvent_t;
// Callback function for zero-cross events
void zero_cross_callback(void* arg)
{
ZeroCrossEvent_t event;
event.timestamp = esp_timer_get_time() / 1000; // Current time in ms
// Send to queue from ISR
BaseType_t higher_priority_task_woken = pdFALSE;
xQueueSendFromISR(zero_cross_queue, &event, &higher_priority_task_woken);
if (higher_priority_task_woken) {
portYIELD_FROM_ISR();
}
}
// Task to process zero-cross events
void zero_cross_processing_task(void *pvParameters)
{
ZeroCrossEvent_t event;
while (1) {
if (xQueueReceive(zero_cross_queue, &event, portMAX_DELAY)) {
// Toggle LED to visualize zero-crossing
gpio_set_level(LED_PIN, !gpio_get_level(LED_PIN));
// Additional processing can be done here safely
ESP_LOGI(TAG, "Zero-cross event at time: %lu ms", event.timestamp);
}
}
}
void app_main(void)
{
// Setup LED
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
// Create the queue
zero_cross_queue = xQueueCreate(10, sizeof(ZeroCrossEvent_t));
if (zero_cross_queue == NULL) {
ESP_LOGE(TAG, "Failed to create queue");
return;
}
// Create the task to process zero-cross events
BaseType_t task_created = xTaskCreate(
zero_cross_processing_task,
"ZeroCrossTask",
2048,
NULL,
5,
NULL
);
if (task_created != pdPASS) {
ESP_LOGE(TAG, "Failed to create task");
return;
}
// Initialize dimmer
rbdimmer_init();
rbdimmer_register_zero_cross(ZERO_CROSS_PIN, PHASE_NUM, 0);
// Register callback
rbdimmer_set_callback(PHASE_NUM, zero_cross_callback, NULL);
// Create dimmer channel
rbdimmer_config_t config = {
.gpio_pin = DIMMER_PIN,
.phase = PHASE_NUM,
.initial_level = 60,
.curve_type = RBDIMMER_CURVE_RMS
};
rbdimmer_create_channel(&config, &dimmer);
ESP_LOGI(TAG, "Dimmer with callback initialized");
// Main loop - print frequency information
while (1) {
uint16_t frequency = rbdimmer_get_frequency(PHASE_NUM);
ESP_LOGI(TAG, "Detected frequency: %u Hz", frequency);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
} Systèmes multi-phases
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "rbdimmer.h"
#define ZERO_CROSS_PIN_PHASE_A 18
#define ZERO_CROSS_PIN_PHASE_B 19
#define ZERO_CROSS_PIN_PHASE_C 21
#define DIMMER_PIN_PHASE_A 22
#define DIMMER_PIN_PHASE_B 23
#define DIMMER_PIN_PHASE_C 25
#define PHASE_A 0
#define PHASE_B 1
#define PHASE_C 2
static const char *TAG = "DIMMER_MULTIPHASE";
rbdimmer_channel_t* channel_a = NULL;
rbdimmer_channel_t* channel_b = NULL;
rbdimmer_channel_t* channel_c = NULL;
void app_main(void)
{
// Initialize library
rbdimmer_init();
// Register zero-cross detectors for each phase
rbdimmer_register_zero_cross(ZERO_CROSS_PIN_PHASE_A, PHASE_A, 0);
rbdimmer_register_zero_cross(ZERO_CROSS_PIN_PHASE_B, PHASE_B, 0);
rbdimmer_register_zero_cross(ZERO_CROSS_PIN_PHASE_C, PHASE_C, 0);
// Create channels for each phase
rbdimmer_config_t config_a = {
.gpio_pin = DIMMER_PIN_PHASE_A,
.phase = PHASE_A,
.initial_level = 50,
.curve_type = RBDIMMER_CURVE_RMS
};
rbdimmer_create_channel(&config_a, &channel_a);
rbdimmer_config_t config_b = {
.gpio_pin = DIMMER_PIN_PHASE_B,
.phase = PHASE_B,
.initial_level = 50,
.curve_type = RBDIMMER_CURVE_RMS
};
rbdimmer_create_channel(&config_b, &channel_b);
rbdimmer_config_t config_c = {
.gpio_pin = DIMMER_PIN_PHASE_C,
.phase = PHASE_C,
.initial_level = 50,
.curve_type = RBDIMMER_CURVE_RMS
};
rbdimmer_create_channel(&config_c, &channel_c);
ESP_LOGI(TAG, "Multi-phase dimmer system initialized");
// Main control loop
while (1) {
// Control phases with different levels
ESP_LOGI(TAG, "Setting phase A: 75%%, phase B: 50%%, phase C: 25%%");
rbdimmer_set_level(channel_a, 75);
rbdimmer_set_level(channel_b, 50);
rbdimmer_set_level(channel_c, 25);
vTaskDelay(3000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Setting phase A: 25%%, phase B: 50%%, phase C: 75%%");
rbdimmer_set_level(channel_a, 25);
rbdimmer_set_level(channel_b, 50);
rbdimmer_set_level(channel_c, 75);
vTaskDelay(3000 / portTICK_PERIOD_MS);
}
} Surveillance de l'opération et débogage
void print_dimmer_status(rbdimmer_channel_t* channel, uint8_t phase)
{
ESP_LOGI(TAG, "=== Dimmer Status ===");
ESP_LOGI(TAG, "Mains frequency: %d Hz", rbdimmer_get_frequency(phase));
ESP_LOGI(TAG, "Brightness: %d%%", rbdimmer_get_level(channel));
ESP_LOGI(TAG, "Active: %s", rbdimmer_is_active(channel) ? "Yes" : "No");
ESP_LOGI(TAG, "Curve type: %d", rbdimmer_get_curve(channel));
ESP_LOGI(TAG, "Delay: %d us", rbdimmer_get_delay(channel));
ESP_LOGI(TAG, "====================");
}Dépannage
Général
- If the dimmer doesn't work correctly, check your hardware connections, especially the zero-cross detector
- Assurez-vous que la broche de zéro-crossing est connectée à un GPIO qui supporte les interruptions
- Utilisez les fonctions
ESP_LOGpour surveiller l'opération en temps réel - Pour les systèmes multi-canaux, assurez-vous que chaque canal de variateur dispose d'une broche GPIO séparée
- La bibliothèque supporte la détection automatique de fréquence. Si vous connaissez la fréquence du secteur de votre région (généralement 50Hz ou 60Hz), vous pouvez la définir explicitement pour une meilleure performance initiale
Problèmes de scintillement et de stabilité (corrections en v2.0.0)
Scintillement aléatoire ou faux déclenchements : La porte de bruit de zéro-crossing (CONFIG_RBDIMMER_ZC_DEBOUNCE_US, par défaut 3000 us) filtre le bruit électrique sur la ligne de zéro-crossing. Si vous observez toujours un scintillement aléatoire, essayez d'augmenter la valeur de rebond via idf.py menuconfig.
Scintillement à 100% (luminosité maximale) : Le délai minimal TRIAC (CONFIG_RBDIMMER_MIN_DELAY_US, par défaut 100 us) empêche le TRIAC de se déclencher trop proche du bord du zéro-crossing. La valeur par défaut de 100 us en v2.0.0 résout le scintillement qui s'était produit avec la valeur par défaut antérieure de 50 us.
Comportement instable en dessous de 3% : Les niveaux en dessous de CONFIG_RBDIMMER_LEVEL_MIN (par défaut 3%) sont maintenant traités comme OFF. Le TRIAC ne peut pas maintenir de manière fiable la conduction à des angles de déclenchement très bas, donc la bibliothèque limite à off plutôt que de produire une sortie erratique.
Gigue multi-canaux : Lorsque plusieurs canaux partagent la même phase, v2.0.0 utilise un ISR à deux passages qui pré-trie les canaux par délai et les déclenche en séquence dans une seule interruption. Cela élimine la gigue de timing qui pourrait survenir lorsque les canaux avaient des valeurs de délai similaires dans les versions antérieures.
Intégration continue
La bibliothèque est testée dans l'IC par rapport à la matrice suivante :
- Versions d'ESP-IDF : v5.3, v5.4, v5.5
- Puces cibles : ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6
Cela garantit que chaque commit se compile correctement sur l'ensemble des configurations supportées.
Historique des modifications
Pour une liste complète des modifications, voir CHANGELOG.md.
← - Guide et exemples Arduino. | Sommaire | Suivant: Composant ESPHome →