# OxidESPark OxidESPark is a Rust library for the [Rust ESP Board](https://github.com/esp-rs/esp-rust-board) embedding an ESP32-C3 microcontroller (RISC-V). It uses the [ESP-IDF framework](https://docs.espressif.com/projects/esp-idf/en/v5.1.1/esp32c3/get-started/index.html) and provides tools to easily build applications that interact with the physical world. Its two main goals are: - Interfacing various I2C sensors through a simple TOML configuration file - Allowing control of various devices # Setup See the [ESP-IDF template](https://github.com/esp-rs/esp-idf-template) for a detailed guide on how to setup a project. A complete example can be found in the [`examples`](https://gitlab.com/cyril-marpaud/oxide-spark/-/tree/main/examples) folder of this repository. # Configuration file OxidESPark is configured through a TOML configuration file. A [full configuration example](https://gitlab.com/cyril-marpaud/oxide-spark/-/blob/main/examples/full_configuration.toml) can be found in the [`examples`](https://gitlab.com/cyril-marpaud/oxide-spark/-/tree/main/examples) folder of this repository. # Initialization As no file system is available on a microcontroller, OxidESPark requires a `&'static str` to embed the configuration file inside the binary. The `include_str` macro can be used to that end: ```Rust use oxide_spark::utils::init::Init; Init::init(include_str!("OxideSparkConfig.toml"))?; ``` That `init()` call also initializes the logging facilities (see the [Logging](#logging) section below). # Logging The [log crate](https://docs.rs/log/latest/log/) can be used with OxidESPark. Logging facilities are initialized with the library, the only requirement is to set the `log_level` field in the configuration file: ```toml [esp] uuid = "esp1" log_level = "Info" ``` ```Rust use log::info; use oxide_spark::utils::config::CONFIG; info!("Hello, world!"); info!("Configuration:\n{:#?}", *CONFIG); warn!("This is a warning!"); error!("This is an error!"); ``` # I2c sensors Any number of sensors can be declared in the configuration file through the optional `sensors` section: ```TOML [[sensors]] freq = 5 id = "sensor1" kind = "Shtc3" metrics = { "Temperature" = "t","Humidity" = "h" } ``` After that, one must configure the I2C bus and call the `init()` function to initialize the sensors and start measuring: ```Rust use esp_idf_hal::peripherals::Peripherals; use oxide_spark::{network::i2c::I2c, models::sensor::Metric, sensors::Sensors}; let peripherals = Peripherals::take().unwrap(); let i2c = I2c::init( peripherals.i2c0, peripherals.pins.gpio8, peripherals.pins.gpio10, ).unwrap(); let channel_size = 10; let (data_sender, data_receiver) = sync_channel::(channel_size); Sensors::init(i2c, &data_sender, None).unwrap(); ``` ## Supported internal sensors (embedded on the board) - [SHTC3](https://www.sensirion.com/products/catalog/SHTC3): temperature and humidity ```toml [[sensors]] freq = 5 id = "sensor1" kind = "Shtc3" metrics = { "Temperature" = "t","Humidity" = "h" } ``` Coming soon: - [ICM-42670-P](https://www.invensense.com/products/motion-tracking/6-axis/icm-42670-p/): accelerometer and gyroscope ## Supported external sensors Each external sensor must be connected to the board's I2C bus (SCL and SDA pins are respectively GPIO 8 and 10). - [TSL2561](https://ams.com/tsl2561): visible and infrared light ```toml [[sensors]] freq = 3 id = "sensor2" kind = "Tsl2561" metrics = { "InfraredLight" = "il", "VisibleInfraredLight" = "vil" } ``` Coming soon: - [BME280](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/): temperature, humidity and pressure - [MPU9250](https://www.invensense.com/products/motion-tracking/9-axis/mpu-9250/): accelerometer, gyroscope and magnetometer # Supported devices - [WS2812B](https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf): RGB LED strips (including the embedded "1-LED strip" on GPIO 2) ```Rust use oxide_spark::models::led_strip::LedStripBuilder; use oxide_spark_utils::{color::Color::{Chartreuse, Red}, command::led_strip_mode::LedStripMode}; let rgb_led = LedStripBuilder::new() .channel(0) .gpio(2) .length(1) .mode(LedStripMode::Full(Red)) .build() .unwrap() .init() .unwrap(); rgb_led.send(LedStripMode::Full(Chartreuse)).unwrap(); ``` # Connectivity ## Wifi Wifi connection is available (though optional) through the configuration file: ```toml [wifi] auth_method = "WPA2Enterprise" pwd = "wifi_password" ssid = "wifi_ssid" timeout = 8 ``` See [AuthMethod](https://docs.rs/embedded-svc/latest/embedded_svc/wifi/enum.AuthMethod.html) for a list of available authentication methods. ```Rust use esp_idf_hal::peripherals::Peripherals; use oxide_spark::network::wifi::Wifi; let peripherals = Peripherals::take().unwrap(); Wifi::init(peripherals.modem).unwrap(); ``` After the `init()` call, the Wifi connection is established. If a timeout occurs, the device automatically reboots. ## MQTT MQTT connection is also available (and optional). It requires a Wifi connection to be established first and a broker must of course be running at the given IP and port: ```toml [mqtt] channel_size = 10 ip = "1.2.3.4" port = 1883 ``` ```Rust use oxide_spark::network::mqtt::Mqtt; let (data_sender, cmd_receiver) = Mqtt::init().unwrap(); ``` `data_sender` is the sending half of a sync channel used to send data (namely, sensor measures) while `cmd_receiver` is the receiving half of a sync channel used to receive remote commands.