3.Rust嵌入式入门——Http服务

489 阅读3分钟

3.Rust嵌入式入门——Http服务

本节将结合前两节的知识,编写一个http服务供外部去调用。

安装依赖

serdeserde_json 是 Rust 编程语言中广泛使用的库,用于序列化和反序列化数据结构,特别是与 JSON 格式相关的数据。

cargo add serde serde-json -F serde/derive

serde官网

实现

首先我们新建bin/http_server.rs文件。

主要实现两个功能

  • /接收GET请求,返回html文件给浏览器。

  • /set-color接收POST请求,并解析携带的JSON Body,然后将颜色值发送给RMT控制灯光的颜色。

  • /shutdown接收GET请求,调用关灯方法。

实现JSON Body解析功能。

定义一个从请求中读取Body的方法

// 从HTTP请求中获取JSON负载的函数
fn get_json_body<'r, T: for<'b> Deserialize<'b>>(
    req: &mut Request<&mut EspHttpConnection<'r>>
) -> anyhow::Result<T> {
    // 获取请求的负载长度
    let len = req.content_len().ok_or(anyhow!("content_len is None"))? as usize;
    // 创建一个缓冲区用于存储负载
    let mut buf = vec![0; len];
    // 从请求中读取负载到缓冲区
    req.read_exact(&mut buf)?;
    // 从缓冲区中的数据解析JSON负载
    Ok(serde_json::from_slice(&buf)?)
}

定义数据结构

// 表示RGB颜色的结构体
#[derive(Debug, Serialize, Deserialize)]
struct Color {
    r: u8,
    g: u8,
    b: u8,
}

// 包含颜色参数的结构体
#[derive(Debug, Serialize, Deserialize)]
struct Params {
    color: Color,
}

// 从Color结构体到RGB8的转换
impl From<Color> for RGB8 {
    fn from(color: Color) -> Self {
        RGB8::new(color.r, color.g, color.b)
    }
}

然后在main函数中创建http服务,并注册服务。

在我的GitHub仓库中提供了前端UI界面,将src/bin/index.html拷贝到自己的项目中

use std::sync::{ Arc, Mutex };

use anyhow::anyhow;
use embedded_svc::http::Headers;
use esp_idf_svc::{
    http::{ server::{ Configuration, EspHttpConnection, Request }, Method },
    io::{ Read, Write },
};
use rgb::RGB8;
use rust_embedded_study::led::WS2812RMT;
use serde::{ Deserialize, Serialize };

// 配置结构体,包含WiFi的SSID和PSK
#[toml_cfg::toml_config]
pub struct Config {
    #[default("")]
    wifi_ssid: &'static str,
    #[default("")]
    wifi_psk: &'static str,
}

fn main() -> anyhow::Result<()> {
    // 初始化系统服务、外设和NVS
    // 初始化系统循环、外设和NVS闪存。
    let (sysloop, peripherals, nvs) = rust_embedded_study::init()?;

    // 连接到WiFi网络
    // 使用配置文件中的WiFi SSID和PSK连接到WiFi。
    let _wifi = rust_embedded_study::wifi::connect_wifi(
        CONFIG.wifi_ssid,
        &CONFIG.wifi_psk,
        peripherals.modem,
        sysloop,
        nvs
    )?;

    // 初始化HTTP服务器
    let mut server = esp_idf_svc::http::server::EspHttpServer::new(
        &(Configuration {
            stack_size: 10240,

            ..Default::default()
        })
    )?;

    // 初始化LED控制器
    let led = peripherals.pins.gpio8;
    let channel = peripherals.rmt.channel0;
    let ws2812_rmt = Arc::new(Mutex::new(WS2812RMT::new(led, channel)?));
    let ws2812_rmt_clone = ws2812_rmt.clone();
		
    server.fn_handler("/", Method::Get, |req| {
        let mut response = req.into_ok_response()?;
        response.write_all(include_bytes!("index.html"))?;
        Ok::<(), anyhow::Error>(())
    })?;

    // 注册处理设置LED颜色的HTTP请求的函数
    server.fn_handler("/set-color", Method::Post, move |mut req| {
        // 从请求中获取JSON数据并解析为颜色参数
        let params: Params = get_json_body(&mut req)?;
        let color = params.color;
        // 设置LED颜色
        ws2812_rmt_clone.lock().unwrap().set_pixel(RGB8::new(color.r, color.g, color.b))?;
        log::info!("color: {:?}", color);

        // 构建并返回成功的HTTP响应
        let mut response = req.into_response(
            200,
            Some("ok"),
            &[
                ("Access-Control-Allow-Origin", "*"),
                ("Access-Control-Allow-Methods", "all"),
            ]
        )?;
        response.write_all(b"OK")?;
        Ok::<(), anyhow::Error>(())
    })?;

    // 注册处理关闭LED的HTTP请求的函数
    server.fn_handler("/shutdown", Method::Get, move |req| {
        // 关闭LED控制器
        ws2812_rmt.lock().unwrap().shutdown()?;
        let mut response = req.into_response(
            200,
            Some("ok"),
            &[
                ("Access-Control-Allow-Origin", "*"),
                ("Access-Control-Allow-Methods", "all"),
            ]
        )?;
        response.write_all(b"OK")?;
        Ok::<(), anyhow::Error>(())
    })?;

    // 保持程序运行
    loop {
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

最后写入开发板

cargo run --bin http_server

然后会在控制台中打印一些信息,请记住sta ip后面我们要用。

image-20240717100953352.png

验证

将sta ip输入到浏览器中,将会显示以下界面

image-20240717124213279.png

然后我们点击http就能调试灯光啦。连接到相同wifi的设备都能通过这个地址访问。

881721191482_.pic.jpg

如果不想使用前端UI可以使用Apifox进行调试。

image-20240717124636561.png

最后

🎉恭喜您成功实现了Http服务功能。您所探索的代码可以在GitHub仓库yexiyue/rust-embedded-study中找到。

如果您觉得不错,请点个关注或者收藏,感谢您的支持。