WebControlPanel
network
network/WebControlPanel.h
network
beta
beta
Tool: WebControlPanel Abstraction haut niveau au-dessus d'un serveur HTTP + WebSocket pour créer très simplement un petit tableau de bord web permettant de piloter un montage (moteur, LED, relais...) depuis un navigateur, sans avoir à écrire une seule ligne de HTML/JS/JSON.
Méthodes publiques
| Méthode | Description | Paramètres | Retour |
|---|---|---|---|
|
WebControlPanel()
WebControlPanel(const String& title = "Panneau CREPP",
uint16_t httpPort = 80,
uint16_t wsPort = 81);
|
|||
|
connectToWiFi()
connectToWiFi(const String& ssid, const String& password,
unsigned long timeoutMs = 15000);
|
|||
|
startAP()
startAP(const String& ssid, const String& password = "", int channel = 1);
|
Démarre un point d'accès WiFi autonome (la carte crée son propre réseau, pratique pour un atelier sans WiFi disponible). / | ssid: Nom du réseau créé. password: Mot de passe (8 caractères minimum), vide = réseau ouvert. channel: Canal WiFi utilisé. / |
|
|
getIP()
getIP() const;
|
Adresse IP à saisir dans le navigateur pour accéder au panneau. / | ||
|
begin()
begin();
|
Démarre les serveurs HTTP et WebSocket. A appeler une fois dans setup(), après avoir ajouté les widgets et connecté le WiFi. / | ||
|
loop()
loop();
|
A appeler à chaque tour de loop() : traite les nouvelles connexions HTTP et les messages WebSocket entrants. / | ||
|
addLed()
addLed(const String& id, const String& label,
const String& color = "#4CAF50");
|
|||
|
addLabel()
addLabel(const String& id, const String& label,
const String& initialValue = "");
|
|||
|
addChart()
addChart(const String& id, const String& label,
float minValue, float maxValue, uint16_t maxPoints = 30);
|
|||
|
setLed()
setLed(const String& id, bool state);
|
|||
|
setLabel()
setLabel(const String& id, const String& value);
|
|||
|
setSliderValue()
setSliderValue(const String& id, int value);
|
|||
|
setTextInput()
setTextInput(const String& id, const String& value);
|
|||
|
setCheckbox()
setCheckbox(const String& id, bool checked);
|
|||
|
setRadioSelection()
setRadioSelection(const String& id, int index);
|
|||
|
setColor()
setColor(const String& id, const String& hexColor);
|
|||
|
pushChartValue()
pushChartValue(const String& id, float value);
|
Ajoute un nouveau point à un widget CHART déjà ajouté avec addChart() : mis à jour en temps réel sur tous les navigateurs connectés, et le point le plus ancien est supprimé si le nombre maximal de points (maxPoints) est dépassé. / | ||
|
hexToRgb()
hexToRgb(const String& hexColor, uint8_t& r, uint8_t& g, uint8_t& b);
|
Convertit une couleur "#rrggbb" (telle que reçue par un COLOR_PICKER) en composantes rouge/vert/bleu (0-255), pratique pour piloter directement une LED RGB (ex: analogWrite). (r/g/b ne sont alors pas modifiés). / | truetrue si hexColor est bien au format "#rrggbb", false sinon (r/g/b ne sont alors pas modifiés). / |
|
|
getStatus()
getStatus() const {
|
Méthodes privées
findWidget(const String& id);;
generateCss() const;;
generateJs() const;;
renderButtonHtml(const PanelWidget& w) const;;
renderSliderHtml(const PanelWidget& w) const;;
renderLedHtml(const PanelWidget& w) const;;
renderLabelHtml(const PanelWidget& w) const;;
renderDPadHtml(const PanelWidget& w) const;;
renderTextInputHtml(const PanelWidget& w) const;;
renderCheckboxHtml(const PanelWidget& w) const;;
renderRadioGroupHtml(const PanelWidget& w) const;;
renderColorPickerHtml(const PanelWidget& w) const;;
renderChartHtml(const PanelWidget& w) const;;
handleWsMessage(const String& msg);;
stopAllDPads();;
pushUpdate(const String& type, const String& id, const String& extraJsonFields);;
escapeJson(const String& text);;
escapeHtmlAttr(const String& text);;
panel("Robot CREPP");;
begin(115200);;
begin(MOTOR_IN1, MOTOR_IN2, MOTOR_EN);;
startAP("Robot-CREPP", "robotique56");;
addButton("avance", "Avancer", [](){;
setSpeed(80);;
addButton("recule", "Reculer", [](){;
setSpeed(-80);;
addButton("stop", "Stop", [](){;
stop();;
addSlider("vitesse", "Vitesse", -100, 100, 0,
[](int v){;
addDPad("pad",
// [](){;
setSpeed(80);;
setSpeed(-80);;
setSpeed(-40);;
setSpeed(40);;
stop();;
addLed("actif", "Moteur en marche");;
addLabel("info", "Vitesse actuelle", "0");;
addTextInput("nom", "Nom du robot", "R2D2",
[](const String& v){;
println("Nom : " + v);;
addCheckbox("phares", "Phares allumés", false,
[](bool on){;
digitalWrite(LED_BUILTIN, on);;
addRadioGroup("mode", "Mode de conduite",
{"Normal", "Sport", "Economie"}, 0,
[](int index){;
addColorPicker("couleur_led", "Couleur LED RGB", "#4CAF50",
[](const String& hex){;
analogWrite(PIN_R, r);;
analogWrite(PIN_G, g);;
analogWrite(PIN_B, b);;
begin();;
loop();;
readSpeed(speed);;
setLed("actif", speed != 0);;
Variables membres
String id;
String label;
PanelWidgetType type;
String textValue;
return _status;
String _title;
int8_t speed;
Code source
// WebControlPanel.h
#pragma once
#include <Arduino.h>
#include <WiFi.h>
#include <WebSocketsServer.h>
#include <vector>
#include <functional>
#include "../StatusDevice.h"
#include "WebSocketAppBase.h"
namespace crepp::network {
/**
* @brief Type d'un widget affiché sur le panneau web.
*/
enum class PanelWidgetType : uint8_t {
BUTTON, ///< Bouton cliquable -> déclenche un callback sans argument
SLIDER, ///< Curseur -> déclenche un callback avec la valeur (int)
LED, ///< Voyant de statut (allumé / éteint, couleur configurable)
LABEL, ///< Simple texte affiché, mis à jour depuis le programme
DPAD, ///< Croix directionnelle façon joystick (haut/bas/gauche/droite)
TEXT_INPUT, ///< Champ de saisie de texte libre
CHECKBOX, ///< Case à cocher (on/off)
RADIO_GROUP, ///< Choix unique parmi une liste d'options
COLOR_PICKER, ///< Sélecteur de couleur (palette RGB native du navigateur)
CHART ///< Courbe temps réel (historique de valeurs numériques)
};
/**
* @brief Représente un élément de l'interface (bouton, slider, LED ou texte).
*
* @note Les utilisateurs de la bibliothèque n'ont normalement pas besoin de
* manipuler cette structure directement : elle est créée et gérée en
* interne par WebControlPanel::addButton() / addSlider() / addLed() /
* addLabel().
*/
struct PanelWidget {
String id; ///< Identifiant unique (utilisé aussi en HTML/JS)
String label; ///< Texte affiché à côté du widget
PanelWidgetType type;
std::function<void()> onClick; ///< Callback appelé pour un BUTTON
std::function<void(int)> onChange; ///< Callback appelé pour un SLIDER
int sliderMin = 0;
int sliderMax = 100;
int sliderValue = 0;
bool ledState = false;
String ledColor = "#4CAF50";
String textValue; ///< Valeur affichée pour un LABEL
// DPAD : un callback par direction, appelé tant que le bouton reste
// appuyé (voir le protocole "press:"/"release:" dans le .cpp), plus un
// callback optionnel appelé au relâchement (typiquement motor.stop()).
std::function<void()> onUp;
std::function<void()> onDown;
std::function<void()> onLeft;
std::function<void()> onRight;
std::function<void()> onStop;
// TEXT_INPUT / COLOR_PICKER : callback appelé avec la nouvelle valeur
// texte (chaîne libre pour TEXT_INPUT, couleur hexadécimale "#rrggbb"
// pour COLOR_PICKER). textValue (ci-dessus) sert de valeur courante
// pour TEXT_INPUT ; colorValue ci-dessous pour COLOR_PICKER.
std::function<void(const String&)> onTextChange;
String colorValue = "#ffffff";
// CHECKBOX
std::function<void(bool)> onToggle;
bool checkboxState = false;
// RADIO_GROUP : réutilise onChange(int) (même signature que SLIDER) pour
// signaler l'index sélectionné.
std::vector<String> options;
int selectedIndex = 0;
// CHART : historique borné de valeurs numériques (voir addChart() /
// pushChartValue()). Pas de callback : widget d'affichage seul.
std::vector<float> chartData;
float chartMin = 0.0f;
float chartMax = 100.0f;
uint16_t chartMaxPoints = 30;
};
/*
* =========================
* Guide d'extension : ajouter un nouveau type de widget
* -------------------------
* Toute la logique d'un type de widget est volontairement regroupée à
* quelques endroits bien identifiés, pour qu'ajouter ou modifier un type
* (ex: un champ de texte, un choix multiple...) reste rapide :
*
* 1. PanelWidgetType : ajouter la nouvelle valeur d'enum.
* 2. PanelWidget : ajouter les champs de données nécessaires
* (comme sliderMin/sliderMax pour SLIDER).
* 3. addXxx() : méthode publique de construction du widget
* (voir addButton/addSlider/addLed/addLabel).
* 4. renderXxxHtml() : génère le HTML du widget + l'appelle depuis
* generateHtmlPage() (un cas de switch, une ligne).
* 5. generateJs() : ajouter une entrée dans la table `handlers` du
* JavaScript pour appliquer les mises à jour
* temps réel reçues du Pico (un objet, une clé).
* 6. setXxx() : si le programme doit pouvoir mettre à jour ce
* widget depuis loop(), utiliser pushUpdate() en
* suivant setLed()/setLabel()/setSliderValue().
*
* Rien d'autre à toucher : begin(), loop(), le HTTP et le WebSocket restent
* génériques et n'ont pas besoin d'être modifiés.
* =========================
*/
/*
* =========================
* Tool: WebControlPanel
* -------------------------
* Abstraction haut niveau au-dessus d'un serveur HTTP + WebSocket pour créer
* très simplement un petit tableau de bord web permettant de piloter un
* montage (moteur, LED, relais...) depuis un navigateur, sans avoir à écrire
* une seule ligne de HTML/JS/JSON.
*
* @badge network
* @badge beta
*
* Fonctionnalités :
* - Connexion WiFi (station) ou point d'accès autonome
* - Génération automatique d'une page HTML responsive
* - Boutons, curseurs (sliders), voyants (LED) et étiquettes de texte
* - Communication bidirectionnelle en temps réel via WebSocket
* - Callbacks C++ (lambdas) appelés directement quand l'utilisateur clique
* ou déplace un curseur : aucune notion de HTTP/WebSocket/JSON à connaître
*
* @note Pensé pour un usage pédagogique/débutant (ateliers CREPP) : un seul
* objet, quelques appels à addButton()/addSlider()/addLed()/addLabel()
* dans setup(), puis begin() et loop(). Pour un serveur HTTP "brut"
* avec vos propres routes, voir PicoWebServer. Pour un terminal de
* debug avec historique de logs, voir PicoWebTerminal.
* =========================
*/
class WebControlPanel : public WebSocketAppBase {
public:
/**
* @brief Construit le panneau (ne démarre rien tant que begin() n'est
* pas appelé).
* @param title Titre affiché en haut de la page web.
* @param httpPort Port du serveur HTTP (page web), 80 par défaut.
* @param wsPort Port du serveur WebSocket (temps réel), 81 par défaut.
*/
explicit WebControlPanel(const String& title = "Panneau CREPP",
uint16_t httpPort = 80,
uint16_t wsPort = 81);
/*
* =========================
* Réseau
* =========================
*/
/**
* @brief Connecte la carte à un réseau WiFi existant (mode station).
* Appel bloquant : attend la connexion jusqu'à timeoutMs.
* @param ssid Nom du réseau WiFi.
* @param password Mot de passe du réseau.
* @param timeoutMs Délai maximum d'attente en millisecondes.
* @return true si la connexion a réussi.
*/
bool connectToWiFi(const String& ssid, const String& password,
unsigned long timeoutMs = 15000);
/**
* @brief Démarre un point d'accès WiFi autonome (la carte crée son
* propre réseau, pratique pour un atelier sans WiFi disponible).
* @param ssid Nom du réseau créé.
* @param password Mot de passe (8 caractères minimum), vide = réseau ouvert.
* @param channel Canal WiFi utilisé.
*/
void startAP(const String& ssid, const String& password = "", int channel = 1);
/**
* @brief Adresse IP à saisir dans le navigateur pour accéder au panneau.
*/
String getIP() const;
/*
* =========================
* Cycle de vie
* =========================
*/
/**
* @brief Démarre les serveurs HTTP et WebSocket.
* A appeler une fois dans setup(), après avoir ajouté les widgets
* et connecté le WiFi.
*/
void begin();
/**
* @brief A appeler à chaque tour de loop() : traite les nouvelles
* connexions HTTP et les messages WebSocket entrants.
*/
void loop();
/*
* =========================
* Construction de l'interface
* -------------------------
* A appeler dans setup(), avant begin().
* =========================
*/
/**
* @brief Ajoute un bouton à l'interface.
* @param id Identifiant unique du bouton.
* @param label Texte affiché sur le bouton.
* @param onClick Fonction appelée (sans argument) à chaque clic.
*/
void addButton(const String& id, const String& label,
std::function<void()> onClick);
/**
* @brief Ajoute un curseur (slider) à l'interface.
* @param id Identifiant unique du curseur.
* @param label Texte affiché au-dessus du curseur.
* @param minValue Valeur minimale.
* @param maxValue Valeur maximale.
* @param initialValue Valeur affichée au chargement de la page.
* @param onChange Fonction appelée avec la nouvelle valeur (int)
* dès que l'utilisateur déplace le curseur.
*/
void addSlider(const String& id, const String& label,
int minValue, int maxValue, int initialValue,
std::function<void(int)> onChange);
/**
* @brief Ajoute un voyant de statut (LED) à l'interface.
* @param id Identifiant unique du voyant.
* @param label Texte affiché à côté du voyant.
* @param color Couleur CSS utilisée quand le voyant est allumé.
*/
void addLed(const String& id, const String& label,
const String& color = "#4CAF50");
/**
* @brief Ajoute une étiquette de texte (valeur en lecture seule côté
* utilisateur, mise à jour depuis le programme via setLabel()).
* @param id Identifiant unique de l'étiquette.
* @param label Texte descriptif (ex: "Température").
* @param initialValue Valeur affichée au départ (ex: "-- °C").
*/
void addLabel(const String& id, const String& label,
const String& initialValue = "");
/**
* @brief Ajoute une croix directionnelle façon joystick (4 boutons en
* croix : haut/bas/gauche/droite), pratique pour piloter un
* moteur ou un robot. Chaque direction appelle son callback tant
* que le bouton reste appuyé (utile pour "avancer tant que
* j'appuie"), et onStop est appelé au relâchement, quelle que
* soit la direction relâchée.
* @param id Identifiant unique de la croix.
* @param onUp Callback appelé pendant l'appui sur le bouton haut.
* @param onDown Callback appelé pendant l'appui sur le bouton bas.
* @param onLeft Callback appelé pendant l'appui sur le bouton gauche.
* @param onRight Callback appelé pendant l'appui sur le bouton droite.
* @param onStop Callback appelé au relâchement (ex: motor.stop()).
* Optionnel : peut être laissé vide (nullptr).
*/
void addDPad(const String& id,
std::function<void()> onUp,
std::function<void()> onDown,
std::function<void()> onLeft,
std::function<void()> onRight,
std::function<void()> onStop = nullptr);
/**
* @brief Ajoute un champ de saisie de texte libre.
* @param id Identifiant unique du champ.
* @param label Texte descriptif affiché au-dessus.
* @param initialValue Valeur affichée au chargement de la page.
* @param onChange Fonction appelée avec le texte saisi, une fois
* la saisie validée (Entrée ou perte de focus).
*/
void addTextInput(const String& id, const String& label,
const String& initialValue,
std::function<void(const String&)> onChange);
/**
* @brief Ajoute une case à cocher.
* @param id Identifiant unique de la case.
* @param label Texte affiché à côté de la case.
* @param initialChecked Etat initial (cochée ou non).
* @param onChange Fonction appelée avec le nouvel état à chaque clic.
*/
void addCheckbox(const String& id, const String& label, bool initialChecked,
std::function<void(bool)> onChange);
/**
* @brief Ajoute un groupe de boutons radio (un seul choix possible).
* @param id Identifiant unique du groupe.
* @param label Texte descriptif affiché au-dessus des options.
* @param options Liste des libellés des options, dans l'ordre.
* @param initialIndex Index (0 = première option) sélectionné au départ.
* @param onChange Fonction appelée avec l'index choisi à chaque
* changement de sélection.
*/
void addRadioGroup(const String& id, const String& label,
const std::vector<String>& options, int initialIndex,
std::function<void(int)> onChange);
/**
* @brief Ajoute un sélecteur de couleur (palette RGB native du
* navigateur : l'utilisateur choisit une couleur, le programme
* reçoit un code hexadécimal "#rrggbb"). Pratique pour piloter
* une LED RGB. Voir aussi WebControlPanel::hexToRgb() pour
* convertir la valeur reçue en composantes r/g/b.
* @param id Identifiant unique du sélecteur.
* @param label Texte descriptif affiché au-dessus.
* @param initialColor Couleur affichée au départ, au format "#rrggbb".
* @param onChange Fonction appelée avec la couleur choisie
* ("#rrggbb") à chaque validation du sélecteur.
*/
void addColorPicker(const String& id, const String& label,
const String& initialColor,
std::function<void(const String&)> onChange);
/**
* @brief Ajoute une courbe temps réel (widget d'affichage seul, sans
* interaction utilisateur), pratique pour visualiser l'évolution
* d'une température, d'une distance, d'une vitesse...
* @param id Identifiant unique de la courbe.
* @param label Texte descriptif affiché au-dessus.
* @param minValue Valeur minimale de l'échelle verticale.
* @param maxValue Valeur maximale de l'échelle verticale.
* @param maxPoints Nombre de points conservés (les plus anciens sont
* supprimés au-delà), 30 par défaut.
*/
void addChart(const String& id, const String& label,
float minValue, float maxValue, uint16_t maxPoints = 30);
/*
* =========================
* Mise à jour depuis le programme principal
* -------------------------
* A appeler dans loop(), pour refléter l'état réel du montage sur
* l'interface web (tous les clients connectés sont mis à jour en
* temps réel).
* =========================
*/
/// Allume ou éteint un widget LED déjà ajouté avec addLed().
void setLed(const String& id, bool state);
/// Modifie le texte affiché pour un widget LABEL déjà ajouté avec addLabel().
void setLabel(const String& id, const String& value);
/// Force la valeur affichée d'un widget SLIDER (ex: resynchronisation).
void setSliderValue(const String& id, int value);
/// Modifie le texte affiché dans un widget TEXT_INPUT déjà ajouté avec addTextInput().
void setTextInput(const String& id, const String& value);
/// Force l'état d'un widget CHECKBOX déjà ajouté avec addCheckbox().
void setCheckbox(const String& id, bool checked);
/// Force l'option sélectionnée d'un widget RADIO_GROUP (index, 0 = première option).
void setRadioSelection(const String& id, int index);
/// Force la couleur affichée d'un widget COLOR_PICKER ("#rrggbb").
void setColor(const String& id, const String& hexColor);
/**
* @brief Ajoute un nouveau point à un widget CHART déjà ajouté avec
* addChart() : mis à jour en temps réel sur tous les navigateurs
* connectés, et le point le plus ancien est supprimé si le
* nombre maximal de points (maxPoints) est dépassé.
*/
void pushChartValue(const String& id, float value);
/**
* @brief Convertit une couleur "#rrggbb" (telle que reçue par un
* COLOR_PICKER) en composantes rouge/vert/bleu (0-255), pratique
* pour piloter directement une LED RGB (ex: analogWrite).
* @return true si hexColor est bien au format "#rrggbb", false sinon
* (r/g/b ne sont alors pas modifiés).
*/
static bool hexToRgb(const String& hexColor, uint8_t& r, uint8_t& g, uint8_t& b);
/// Etat du périphérique (OK une fois begin() appelé avec succès).
StatusDevice getStatus() const { return _status; }
private:
String _title;
std::vector<PanelWidget> _widgets;
StatusDevice _status = StatusDevice::DEVICE_ERROR_INIT;
PanelWidget* findWidget(const String& id);
// Génération de la page HTML : le service HTTP lui-même (accepter les
// clients, envoyer la réponse) est géré par WebSocketAppBase::loopServers().
String generateHtmlPage() override;
String generateCss() const;
String generateJs() const;
// Rendu HTML d'un widget, un point d'entrée par type (voir le guide
// d'extension ci-dessus). Chacune ne connaît que son propre widget.
String renderButtonHtml(const PanelWidget& w) const;
String renderSliderHtml(const PanelWidget& w) const;
String renderLedHtml(const PanelWidget& w) const;
String renderLabelHtml(const PanelWidget& w) const;
String renderDPadHtml(const PanelWidget& w) const;
String renderTextInputHtml(const PanelWidget& w) const;
String renderCheckboxHtml(const PanelWidget& w) const;
String renderRadioGroupHtml(const PanelWidget& w) const;
String renderColorPickerHtml(const PanelWidget& w) const;
String renderChartHtml(const PanelWidget& w) const;
// WebSocket : messages entrants du navigateur ("click:id", "slide:id:val")
void handleWsMessage(const String& msg);
// Sécurité : appelle onStop() de tous les widgets DPAD (voir begin(),
// déclenché sur WStype_DISCONNECTED).
void stopAllDPads();
// Construit puis diffuse (broadcast) un message de mise à jour au format
// {"type":"<type>","id":"<id>" <extraJsonFields>}. extraJsonFields doit
// commencer par une virgule, ex: ",\"state\":true". Ne fait rien si
// aucun navigateur n'est connecté. Toutes les méthodes setXxx() passent
// par ici : ajouter un nouveau setXxx() se résume à un appel à
// pushUpdate() (voir setLed/setLabel/setSliderValue).
void pushUpdate(const String& type, const String& id, const String& extraJsonFields);
// Petite fonction utilitaire d'échappement pour les valeurs textuelles
// insérées dans les messages JSON envoyés au navigateur.
static String escapeJson(const String& text);
// Echappement pour les valeurs textuelles insérées dans un attribut HTML
// (ex: value='...') : évite qu'une apostrophe tapée dans un TEXT_INPUT
// ne casse la page générée.
static String escapeHtmlAttr(const String& text);
// Types de message JSON envoyés au navigateur (Pico -> navigateur) et
// préfixes des messages reçus (navigateur -> Pico). Centralisés ici pour
// qu'il n'y ait qu'un seul endroit à modifier si le protocole évolue :
// ces constantes sont utilisées à la fois par le C++ (pushUpdate,
// handleWsMessage) et recopiées dans le JavaScript généré (generateJs).
static constexpr const char* kMsgLed = "led";
static constexpr const char* kMsgLabel = "label";
static constexpr const char* kMsgSlider = "slider";
static constexpr const char* kMsgText = "text";
static constexpr const char* kMsgCheck = "check";
static constexpr const char* kMsgRadio = "radio";
static constexpr const char* kMsgColor = "color";
static constexpr const char* kMsgChart = "chart";
static constexpr const char* kCmdClick = "click:";
static constexpr const char* kCmdSlide = "slide:";
static constexpr const char* kCmdPress = "press:"; ///< "press:<id>:<up|down|left|right>"
static constexpr const char* kCmdRelease = "release:"; ///< "release:<id>"
static constexpr const char* kCmdText = "text:"; ///< "text:<id>:<valeur>"
static constexpr const char* kCmdCheck = "check:"; ///< "check:<id>:<0|1>"
static constexpr const char* kCmdRadio = "radio:"; ///< "radio:<id>:<index>"
static constexpr const char* kCmdColor = "color:"; ///< "color:<id>:<#rrggbb>"
};
} // namespace crepp::network
/*
@example
@include
#include <crepp/network/WebControlPanel.h>
#include <crepp/tools/Motor.h>
@end_include
@macro
#define MOTOR_IN1 6
#define MOTOR_IN2 7
#define MOTOR_EN 8
@end_macro
@instance
crepp::network::WebControlPanel panel("Robot CREPP");
crepp::tools::Motor motor;
@end_instance
@setup
Serial.begin(115200);
motor.begin(MOTOR_IN1, MOTOR_IN2, MOTOR_EN);
// Pas de WiFi à disposition dans l'atelier : on crée un point d'accès.
panel.startAP("Robot-CREPP", "robotique56");
panel.addButton("avance", "Avancer", [](){ motor.setSpeed(80); });
panel.addButton("recule", "Reculer", [](){ motor.setSpeed(-80); });
panel.addButton("stop", "Stop", [](){ motor.stop(); });
panel.addSlider("vitesse", "Vitesse", -100, 100, 0,
[](int v){ motor.setSpeed((int8_t)v); });
// Alternative aux 3 boutons ci-dessus : une croix directionnelle.
// panel.addDPad("pad",
// [](){ motor.setSpeed(80); }, // haut -> avance
// [](){ motor.setSpeed(-80); }, // bas -> recule
// [](){ motor.setSpeed(-40); }, // gauche -> pivote (exemple)
// [](){ motor.setSpeed(40); }, // droite -> pivote (exemple)
// [](){ motor.stop(); }); // relâchement -> stop
panel.addLed("actif", "Moteur en marche");
panel.addLabel("info", "Vitesse actuelle", "0");
// Nouveaux widgets disponibles :
panel.addTextInput("nom", "Nom du robot", "R2D2",
[](const String& v){ Serial.println("Nom : " + v); });
panel.addCheckbox("phares", "Phares allumés", false,
[](bool on){ digitalWrite(LED_BUILTIN, on); });
panel.addRadioGroup("mode", "Mode de conduite",
{"Normal", "Sport", "Economie"}, 0,
[](int index){ Serial.println("Mode choisi : " + String(index)); });
panel.addColorPicker("couleur_led", "Couleur LED RGB", "#4CAF50",
[](const String& hex){
uint8_t r, g, b;
if (crepp::network::WebControlPanel::hexToRgb(hex, r, g, b)) {
// analogWrite(PIN_R, r); analogWrite(PIN_G, g); analogWrite(PIN_B, b);
}
});
panel.begin();
Serial.println("Connectez-vous a http://" + panel.getIP());
@end_setup
@loop
panel.loop();
int8_t speed;
motor.readSpeed(speed);
panel.setLed("actif", speed != 0);
panel.setLabel("info", String(speed));
@end_loop
@end_example
*/