almost
This commit is contained in:
parent
a03e890349
commit
14d8f7f683
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -701,6 +701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e98f0f58453dd2ce08d99228fc8757fad39d05dfd26643665d1093b8844f42cc"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -792,6 +793,7 @@ dependencies = [
|
||||
"esp-println",
|
||||
"esp-wifi",
|
||||
"heapless 0.8.0",
|
||||
"log",
|
||||
"mqttrust",
|
||||
"rand",
|
||||
"rand_core",
|
||||
|
13
Cargo.toml
13
Cargo.toml
@ -8,7 +8,7 @@ authors = [ "Marvin Drescher <m@sparv.in>" ]
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.5.0", features = ["nightly", "integrated-timers", "arch-riscv32", "executor-thread"] }
|
||||
embassy-net = { version = "0.4.0", features = ["dhcpv4", "dhcpv4-hostname", "dns", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp"] }
|
||||
embassy-net = { version = "0.4.0", features = ["dhcpv4", "dhcpv4-hostname", "dns", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"] }
|
||||
embassy-sync = "0.5.0"
|
||||
embassy-time = { version = "0.3.0" }
|
||||
embedded-io-async = "0.6.1"
|
||||
@ -17,9 +17,10 @@ esp-alloc = "0.3.0"
|
||||
esp-backtrace = { version = "0.11.0", features = ["esp32c3", "exception-handler", "panic-handler", "println"] }
|
||||
esp-hal = { version = "0.16.1", features = ["embassy", "embassy-time-timg0", "esp32c3"] }
|
||||
esp-hal-smartled = { version = "0.9.0", features = ["esp32c3"] }
|
||||
esp-println = { version = "0.9.1", features = ["esp32c3", "uart"] }
|
||||
esp-println = { version = "0.9.1", features = ["esp32c3", "log", "uart"] }
|
||||
esp-wifi = { version = "0.4.0", features = ["embassy-net", "esp32c3", "wifi"] }
|
||||
heapless = { version = "0.8.0", features = ["portable-atomic", "portable-atomic-unsafe-assume-single-core"] }
|
||||
log = "0.4.21"
|
||||
mqttrust = "0.6.0"
|
||||
rand = { version = "0.8.5", default-features = false, features = ["std_rng"] }
|
||||
rand_core = "0.6.4"
|
||||
@ -28,4 +29,10 @@ smart-leds = "0.4.0"
|
||||
static_cell = { version = "2.0.0", features = ["nightly"] }
|
||||
|
||||
[profile.dev.package.esp-wifi]
|
||||
opt-level = 2
|
||||
opt-level = 3
|
||||
[profile.dev.package.embedded-tls]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
|
53
src/main.rs
53
src/main.rs
@ -33,10 +33,12 @@ use esp_hal::{adc::AdcConfig, clock::ClockControl};
|
||||
use esp_hal::{embassy, prelude::*, rmt, Rmt, Rng, Rtc, IO};
|
||||
use esp_hal_smartled::SmartLedsAdapter;
|
||||
use esp_hal_smartled::*;
|
||||
use esp_println::logger::init_logger;
|
||||
use esp_println::println;
|
||||
use esp_wifi::wifi::{get_random, ClientConfiguration, Configuration};
|
||||
use esp_wifi::wifi::{WifiController, WifiDevice, WifiEvent, WifiStaDevice, WifiState};
|
||||
use esp_wifi::{initialize as initialize_wifi, EspWifiInitFor};
|
||||
use log::{debug, error, info, trace};
|
||||
use smart_leds::{SmartLedsWrite, RGB8};
|
||||
use static_cell::{make_static, StaticCell};
|
||||
|
||||
@ -69,7 +71,7 @@ impl<TX: rmt::TxChannel, const BUFFER_SIZE: usize> MySmartLed
|
||||
{
|
||||
fn set_color(&mut self, color: RGB8) {
|
||||
if let Err(err) = self.write([color].into_iter()) {
|
||||
esp_println::println!("{err:?}");
|
||||
error!("{err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -80,7 +82,6 @@ pub static DATA: Mutex<CriticalSectionRawMutex, BTreeMap<Cow<'static, str>, Stri
|
||||
#[embassy_executor::task]
|
||||
async fn blink(mut led: Box<dyn MySmartLed>) {
|
||||
loop {
|
||||
esp_println::println!("Bing!");
|
||||
let scale = 4;
|
||||
for r in 0..(255 / scale) {
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
@ -100,17 +101,25 @@ async fn blink(mut led: Box<dyn MySmartLed>) {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! nb_await {
|
||||
($ex:expr, $interval:expr) => {
|
||||
loop {
|
||||
match $ex {
|
||||
Err(nb::Error::WouldBlock) => Timer::after($interval).await,
|
||||
Err(nb::Error::Other(e)) => break Err(e),
|
||||
Ok(val) => break Ok(val),
|
||||
}
|
||||
}
|
||||
};
|
||||
($ex:expr) => {
|
||||
$crate::nb_await!($ex, Duration::from_millis(10))
|
||||
};
|
||||
}
|
||||
async fn async_read<T, E>(
|
||||
mut fun: impl FnMut() -> nb::Result<T, E>,
|
||||
interval: Duration,
|
||||
) -> Result<T, E> {
|
||||
loop {
|
||||
match fun() {
|
||||
Err(nb::Error::WouldBlock) => Timer::after(interval).await,
|
||||
Err(nb::Error::Other(e)) => return Err(e),
|
||||
Ok(val) => return Ok(val),
|
||||
}
|
||||
}
|
||||
nb_await!(fun(), interval)
|
||||
}
|
||||
|
||||
/// https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32c3/api-reference/peripherals/adc.html
|
||||
@ -148,7 +157,7 @@ async fn moisture(
|
||||
let moisture = ((milli_volt.checked_sub(submerged_in_water).unwrap_or(0))
|
||||
<< 8 / (dry - submerged_in_water))
|
||||
>> 8;
|
||||
esp_println::println!("moisture: {moisture}%, v_s: {milli_volt}");
|
||||
info!("moisture: {moisture}%, v_s: {milli_volt}");
|
||||
{
|
||||
DATA.lock()
|
||||
.await
|
||||
@ -174,7 +183,7 @@ async fn battery_monitor(
|
||||
);
|
||||
// account for 50:50 voltage divider
|
||||
let v_bat = v_out * 2;
|
||||
println!("V_bat: {}", v_bat);
|
||||
info!("V_bat: {}", v_bat);
|
||||
{
|
||||
DATA.lock()
|
||||
.await
|
||||
@ -187,7 +196,7 @@ static EXECUTOR: StaticCell<Executor> = StaticCell::new();
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::println!("Init!");
|
||||
init_logger(log::LevelFilter::Info);
|
||||
init_heap();
|
||||
|
||||
let peripherals = Peripherals::take();
|
||||
@ -270,7 +279,7 @@ fn main() -> ! {
|
||||
spawner.spawn(net_task(&stack)).unwrap();
|
||||
spawner.spawn(ip_task(&stack)).unwrap();
|
||||
}
|
||||
spawner.spawn(blink(led)).unwrap();
|
||||
// spawner.spawn(blink(led)).unwrap();
|
||||
spawner
|
||||
.spawn(moisture(pin, adc1, moisture_sensor_suppy_pin.into()))
|
||||
.unwrap();
|
||||
@ -285,8 +294,8 @@ async fn wifi_connection(
|
||||
ssid: &'static str,
|
||||
psk: &'static str,
|
||||
) {
|
||||
println!("start connection task");
|
||||
println!("Device capabilities: {:?}", controller.get_capabilities());
|
||||
trace!("start wifi connection task");
|
||||
debug!("Device capabilities: {:?}", controller.get_capabilities());
|
||||
loop {
|
||||
match esp_wifi::wifi::get_wifi_state() {
|
||||
WifiState::StaConnected => {
|
||||
@ -303,16 +312,16 @@ async fn wifi_connection(
|
||||
..Default::default()
|
||||
});
|
||||
controller.set_configuration(&client_config).unwrap();
|
||||
println!("Starting wifi");
|
||||
trace!("starting wifi");
|
||||
controller.start().await.unwrap();
|
||||
println!("Wifi started!");
|
||||
trace!("Wifi started!");
|
||||
}
|
||||
println!("About to connect...");
|
||||
trace!("About to connect...");
|
||||
|
||||
match controller.connect().await {
|
||||
Ok(_) => println!("Wifi connected!"),
|
||||
Ok(_) => info!("Wifi connected!"),
|
||||
Err(e) => {
|
||||
println!("Failed to connect to wifi: {e:?}");
|
||||
error!("Failed to connect to wifi: {e:?}");
|
||||
Timer::after(Duration::from_millis(5000)).await
|
||||
}
|
||||
}
|
||||
@ -327,10 +336,10 @@ async fn ip_task(stack: NetworkStack) {
|
||||
}
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
println!("Waiting to get IP address...");
|
||||
debug!("Waiting to get IP address...");
|
||||
loop {
|
||||
if let Some(config) = stack.config_v4() {
|
||||
println!("Got IP: {}", config.address);
|
||||
info!("Got IP: {}", config.address);
|
||||
break;
|
||||
}
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
|
45
src/mqtt.rs
45
src/mqtt.rs
@ -1,8 +1,10 @@
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
use embassy_net::{dns::Error as DnsError, tcp::ConnectError};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::{with_timeout, Duration, TimeoutError, Timer};
|
||||
use embedded_tls::{Aes128GcmSha256, NoVerify, TlsConfig, TlsConnection, TlsContext, TlsError};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
use log::{debug, error, info, trace};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{CryptoRng, RngCore, SeedableRng};
|
||||
use rust_mqtt::client::client::MqttClient;
|
||||
@ -19,6 +21,7 @@ pub enum SendError {
|
||||
Tls(TlsError),
|
||||
Connect(ConnectError),
|
||||
MqttReason(ReasonCode),
|
||||
Timeout(TimeoutError),
|
||||
}
|
||||
|
||||
macro_rules! from_impl {
|
||||
@ -35,6 +38,7 @@ from_impl!(DnsError, Dns);
|
||||
from_impl!(TlsError, Tls);
|
||||
from_impl!(ConnectError, Connect);
|
||||
from_impl!(ReasonCode, MqttReason);
|
||||
from_impl!(TimeoutError, Timeout);
|
||||
|
||||
const MQTT_SERVER_HOSTNAME: &str = "mqtt.shimun.net";
|
||||
const MQTT_SERVER_PORT: u16 = 8883;
|
||||
@ -44,22 +48,31 @@ pub async fn send_message(
|
||||
mut messages: impl Iterator<Item = (&str, &[u8])>,
|
||||
mut rng: impl CryptoRng + RngCore,
|
||||
) -> core::result::Result<(), SendError> {
|
||||
async fn inner(
|
||||
stack: NetworkStack,
|
||||
mut messages: impl Iterator<Item = (&str, &[u8])>,
|
||||
mut rng: impl CryptoRng + RngCore,
|
||||
) -> core::result::Result<(), SendError> {
|
||||
let dns_resp = stack
|
||||
.dns_query(MQTT_SERVER_HOSTNAME, embassy_net::dns::DnsQueryType::A)
|
||||
.await
|
||||
.map_err(SendError::Dns)?;
|
||||
let mut rx_buffer = [0; 4096];
|
||||
let mut tx_buffer = [0; 4096];
|
||||
const TCP_BUFLEN: usize = 2048 << 2;
|
||||
let mut rx_buffer = [0; TCP_BUFLEN];
|
||||
let mut tx_buffer = [0; TCP_BUFLEN];
|
||||
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||
socket.set_timeout(Some(Duration::from_secs(10)));
|
||||
socket.set_timeout(Some(Duration::from_secs(30)));
|
||||
let socket_addr = dns_resp
|
||||
.into_iter()
|
||||
.map(|addr| (addr, MQTT_SERVER_PORT))
|
||||
.next()
|
||||
.ok_or(SendError::NXDomain(MQTT_SERVER_HOSTNAME))?;
|
||||
|
||||
debug!("got address {socket_addr:?}");
|
||||
|
||||
// establish TCP connection
|
||||
socket.connect(socket_addr).await?;
|
||||
trace!("connected");
|
||||
|
||||
// seed mqtt rng from rng
|
||||
let mut mqtt_config = ClientConfig::<5, _>::new(
|
||||
@ -73,13 +86,11 @@ pub async fn send_message(
|
||||
}
|
||||
|
||||
// TLS layer
|
||||
const TLS_BUF_LEN: usize = 1 << 12;
|
||||
const TLS_BUF_LEN: usize = 4096;
|
||||
let mut tls_read_record_buffer = [0; TLS_BUF_LEN];
|
||||
let mut tls_write_record_buffer = [0; TLS_BUF_LEN];
|
||||
let mut tls = {
|
||||
let config = TlsConfig::new()
|
||||
.with_server_name(MQTT_SERVER_HOSTNAME)
|
||||
.with_max_fragment_length(embedded_tls::MaxFragmentLength::Bits12);
|
||||
let config = TlsConfig::new();
|
||||
|
||||
let mut tls = TlsConnection::new(
|
||||
socket,
|
||||
@ -91,11 +102,14 @@ pub async fn send_message(
|
||||
.await?;
|
||||
tls
|
||||
};
|
||||
debug!("tls handshake succeeded");
|
||||
|
||||
const BUF_LEN: usize = 1 << 13;
|
||||
const BUF_LEN: usize = 1024;
|
||||
let mut recv_buffer = [0; BUF_LEN];
|
||||
let mut buffer = [0; BUF_LEN];
|
||||
|
||||
mqtt_config.add_client_id("esp32c3");
|
||||
mqtt_config.max_packet_size = (BUF_LEN - 128) as _;
|
||||
// MQTT Layer
|
||||
let mut mqtt_client = MqttClient::new(
|
||||
tls,
|
||||
@ -106,6 +120,7 @@ pub async fn send_message(
|
||||
mqtt_config,
|
||||
);
|
||||
mqtt_client.connect_to_broker().await?;
|
||||
info!("connected to broker");
|
||||
for (topic, message) in messages {
|
||||
mqtt_client
|
||||
.send_message(
|
||||
@ -117,13 +132,20 @@ pub async fn send_message(
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
with_timeout(Duration::from_secs(60), inner(stack, messages, rng)).await?
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn publish_data(stack: NetworkStack, rng_seed: [u8; 32], interval: Duration) {
|
||||
let mut rng = StdRng::from_seed(rng_seed);
|
||||
loop {
|
||||
Timer::after(interval).await;
|
||||
Timer::after(interval / 10).await;
|
||||
if stack.is_config_up() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
loop {
|
||||
let mut data = DATA.lock().await;
|
||||
let res = send_message(
|
||||
stack,
|
||||
@ -133,8 +155,9 @@ pub async fn publish_data(stack: NetworkStack, rng_seed: [u8; 32], interval: Dur
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = res {
|
||||
println!("Oh no: {e:?}");
|
||||
error!("Oh no: {e:?}");
|
||||
};
|
||||
data.clear();
|
||||
Timer::after(interval).await;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user