Управление светодиодом ESP32 через веб-страницу
Мы создадим простую конечную точку API, которая принимает логическое значение и управляет состоянием светодиода. Кроме того, будет отдаваться страница «index.html» с двумя кнопками: одна включает светодиод, другая выключает его.
При нажатии одной из кнопок на конечную точку «/led» будет отправлен запрос с таким JSON-телом:
{ "is_on": true }— включить светодиод{ "is_on": false }— выключить светодиод
В зависимости от значения поля «is_on» обновляется переменная «LED_STATE» модуля led. Затем «led_task» соответственно включает или выключает светодиод.
Маршрутизация
В функции «build_app» настраиваются веб-маршруты приложения. Корневой путь («/») отдаёт содержимое «index.html», поэтому этот файл нужно поместить в папку «src/». Путь «/led» принимает POST-запросы, которые обрабатывает «led_handler».
#![allow(unused)]
fn main() {
pub struct Application;
impl AppBuilder for Application {
type PathRouter = impl routing::PathRouter;
fn build_app(self) -> picoserve::Router<Self::PathRouter> {
picoserve::Router::new()
.route(
"/",
routing::get_service(File::html(include_str!("index.html"))),
)
.route("/led", routing::post(led_handler))
}
}
}
Обработчик светодиода
Мы определим две структуры: одну для входящих данных и одну для ответа. Структура LedRequest получит derive Deserialize, чтобы разбирать входящий JSON и представлять его в виде экземпляра структуры. Структура LedResponse получит derive Serialize, чтобы преобразовывать экземпляр структуры и отправлять его как JSON-ответ.
#![allow(unused)]
fn main() {
#[derive(serde::Deserialize)]
struct LedRequest {
is_on: bool,
}
#[derive(serde::Serialize)]
struct LedResponse {
success: bool,
}
}
В функции led_handler структура LedRequest извлекается как параметр. Значение «is_on» можно сразу сохранить в LED_STATE, так как оба значения логические. Наконец, обработчик возвращает JSON-ответ с LedResponse, в котором указывается успешное выполнение.
#![allow(unused)]
fn main() {
async fn led_handler(input: picoserve::extract::Json<LedRequest>) -> impl IntoResponse {
crate::led::LED_STATE.store(input.0.is_on, Ordering::Relaxed);
picoserve::response::Json(LedResponse { success: true })
}
}
Содержимое веб-страницы
Файл index.html можно скачать здесь и поместить в папку «src/», либо создать собственное содержимое, которое отправляет JSON-запросы.
Примечание:
Нужно заменить URL «http://192.168.0.50/led» на IP-адрес вашего ESP32. Для простоты я прописал адрес прямо в коде; иначе пришлось бы использовать заглушку, которую заменяли бы динамически, или подход на основе шаблонов.
<div class="button-container">
<button class="btn-on" onclick="sendRequest(true)">Turn on LED</button>
<button class="btn-off" onclick="sendRequest(false)">Turn off LED</button>
</div>
<script>
function sendRequest(is_on) {
const url = 'http://192.168.0.50/led'; // Замените на статический IP-адрес ESP32
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ is_on })
})
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok');
})
.then(data => {
console.log('Success:', data);
//alert(LED turned ${action});
})
.catch(error => {
console.error('Error:', error);
alert('Failed to send the request');
});
}
</script>
Клонирование существующего проекта
Вы также можете клонировать (или посмотреть) созданный мной проект и перейти в папку wifi-led.
git clone https://github.com/ImplFerris/esp32-projects
cd esp32-projects/wifi-led
Как запустить?
Передайте имя Wi-Fi, пароль, статический IP-адрес и IP-адрес шлюза как переменные окружения, а затем прошейте ESP32
SSID=YOUR_WIFI_NAME PASSWORD=YOUR_WIFI_PASSWORD STATIC_IP=ASSIGN_ESP32_IP/24 GATEWAY_IP=WIFI_GATEWAY_IP cargo run --release