目的

パルダリウム用のタイマー式照明を普通に買うと高くつく → NTPとかで時刻同期を取って照明を管理するシステムを作ろう

部品

Rustを書く

リポジトリ: cordx56/paluda-man

  • nightlyしか使えない

esp_idf_svc とか embedded_svc とかのcrateを使う

use embedded_svc::ota::*;
use esp_idf_svc::{
    hal::{gpio::*, reset::restart},
    http::{
        server::{self, EspHttpServer},
        Method,
    },
    io::{Read, Write},
    nvs::*,
    ota::*,
    sntp::*,
    sys::EspError,
    wifi::EspWifi,
};

WiFiを繋ぐ

サンプルとかを見つつ適当に。ソースコードはこの辺

fn wifi() -> Result<EspWifi<'static>, EspError> {
    use esp_idf_svc::eventloop::*;
    use esp_idf_svc::hal::peripherals::Peripherals;
    use esp_idf_svc::wifi::*;
    let peripherals = Peripherals::take()?;
    let sys_loop = EspSystemEventLoop::take()?;
    let mut esp_wifi = EspWifi::new(peripherals.modem, sys_loop.clone(), None)?;
    let mut wifi = BlockingWifi::wrap(&mut esp_wifi, sys_loop.clone())?;
    wifi.set_configuration(&Configuration::Client(ClientConfiguration {
        ssid: SSID.try_into().unwrap(),
        password: PASS.try_into().unwrap(),
        ..Default::default()
    }))?;

    wifi.start()?;
    info!("WiFi started");

    wifi.connect()?;
    info!("WiFi connected");

    wifi.wait_netif_up()?;
    info!("WiFi netif up");

    Ok(esp_wifi)
}

HTTP server

EspのHTTPサーバを使う。 ソースコード

let mut server = EspHttpServer::new(&server::Configuration {
    stack_size: 10240,
    ..Default::default()
})?;
server.fn_handler("/", Method::Get, |req| {
    let on = nvs.get_i8(SCHEDULE_ON_TAG)?.unwrap_or(-1);
    let off = nvs.get_i8(SCHEDULE_OFF_TAG)?.unwrap_or(-1);
    req.into_ok_response()?
        .write_all(html(on, off).as_bytes())
        .map(|_| ())
})?;

OTA update

OTAアップデートをしたかったので、HTTPサーバにデータを送りつけたらアップデートするやつを実装した。

server.fn_handler("/ota", Method::Post, |mut req| {
	let mut ota = EspOta::new()?;
	let update = ota.initiate_update()?;
	info!("OTA initiate");
	info!("Start OTA update...");
	let updated = update.update(&mut req, |_, _| ());
	restart();
	req.into_ok_response()?
	    .write_all(format!("{:?}", updated).as_bytes())
	    .map(|_| ())
})?;

比較的簡単に実装できる。

こけたポイント

OTAアップデートにはパーティションをいじる必要がある

パーティションテーブルはこんな感じになった。

ESPのサーバのスタックサイズが足りない

デフォルトだと普通のHTMLを返すのでも厳しかった。

let mut server = EspHttpServer::new(&server::Configuration {
    stack_size: 10240,
    ..Default::default()
})?;

EspHttpServer を作る時に、 stack_size を大きめに取る。