feat: blink, voltage detection.

This commit is contained in:
Ivan Li 2022-08-21 14:12:55 +08:00
parent 5058005031
commit d20344fe5e
5 changed files with 220 additions and 13 deletions

View File

@ -17,8 +17,10 @@ pio = ["esp-idf-sys/pio"]
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
embedded-hal = "0.2.7"
embedded-svc = "0.22.0" embedded-svc = "0.22.0"
env_logger = "0.9.0" env_logger = "0.9.0"
esp-idf-hal = "0.38.0"
esp-idf-svc = "0.42.1" esp-idf-svc = "0.42.1"
esp-idf-sys = { version = "0.31.6", features = ["binstart"] } esp-idf-sys = { version = "0.31.6", features = ["binstart"] }
log = "0.4.17" log = "0.4.17"

47
src/blink.rs Normal file
View File

@ -0,0 +1,47 @@
use embedded_hal::digital::v2::OutputPin;
use std::thread;
use std::time::Duration;
pub struct Blink<T>
where
T: OutputPin,
{
state: bool,
pin: T,
stopped: bool,
}
impl<T> Blink<T>
where
T: OutputPin,
{
pub fn new(pin: T) -> Blink<T> {
return Blink {
state: false,
pin,
stopped: false,
};
}
pub fn toggle(&mut self) -> Result<(), T::Error> {
self.state = !self.state;
if self.state {
self.pin.set_high()
} else {
self.pin.set_low()
}
}
pub fn play(&mut self) where <T as embedded_hal::digital::v2::OutputPin>::Error: std::fmt::Debug {
loop {
if self.stopped {
break;
}
self.toggle().unwrap();
thread::sleep(Duration::from_millis(30));
self.toggle().unwrap();
thread::sleep(Duration::from_millis(1930));
}
}
}

View File

@ -1,13 +1,22 @@
use std::{env, thread::sleep, time::{Duration}};
use embedded_svc::mqtt::client::{Publish, QoS}; use embedded_svc::mqtt::client::{Publish, QoS};
use esp_idf_sys as _; use esp_idf_sys as _;
use log::*; use log::*;
use std::{
env,
thread::{self, sleep},
time::Duration,
};
mod blink;
mod message_queue; mod message_queue;
mod wifi;
mod time; mod time;
mod wifi;
mod voltage_detection;
use crate::{
message_queue::MessageQueue, time::Time, wifi::Internet, voltage_detection::VoltageDetection,
};
use crate::{message_queue::MessageQueue, wifi::Internet, time::Time};
fn main() { fn main() {
env::set_var("DEFMT_LOG", "trace"); env::set_var("DEFMT_LOG", "trace");
env::set_var("RUST_BACKTRACE", "1"); env::set_var("RUST_BACKTRACE", "1");
@ -18,7 +27,31 @@ fn main() {
// or else some patches to the runtime implemented by esp-idf-sys might not link properly. // or else some patches to the runtime implemented by esp-idf-sys might not link properly.
esp_idf_sys::link_patches(); esp_idf_sys::link_patches();
println!("Hello, world!"); info!("Hello, world!");
let peripherals = esp_idf_hal::peripherals::Peripherals::take().unwrap();
let blink_pin = peripherals.pins.gpio5;
let beep_pin = peripherals.pins.gpio6;
let ledc_timer0 = peripherals.ledc.timer0;
let ledc_channel0 = peripherals.ledc.channel0;
let dc_out_ctl_pin = peripherals.pins.gpio3;
let i2c0 = peripherals.i2c0;
let sda_pin = peripherals.pins.gpio4;
let scl_pin = peripherals.pins.gpio10;
thread::spawn(move || {
let mut blink = blink::Blink::new(
blink_pin
.into_output()
.expect("Failed to set GPIO5 as output"),
);
blink.play();
});
let mut voltage_detection = VoltageDetection::new();
voltage_detection.watching().expect("Can not watch voltages.");
let _wifi = Internet::new().unwrap(); let _wifi = Internet::new().unwrap();
@ -34,14 +67,15 @@ fn main() {
let timestamps = time.get_time().as_millis(); let timestamps = time.get_time().as_millis();
info!("timestamps {}", timestamps); info!("timestamps {}", timestamps);
mq_client.publish( mq_client
.publish(
"ups-0.2/heartbeat", "ups-0.2/heartbeat",
QoS::AtMostOnce, QoS::AtMostOnce,
false, false,
timestamps.to_string().as_bytes(), timestamps.to_string().as_bytes(),
).map_err(|err| { )
warn!("publish heartbeat failed {}", err) .map_err(|err| warn!("publish heartbeat failed {}", err))
}).unwrap(); .unwrap();
} }
} }
} }

View File

@ -24,7 +24,7 @@ impl MessageQueue {
}; };
let (mut client, mut connection) = let (mut client, mut connection) =
EspMqttClient::new_with_conn("mqtt://192.168.31.8:1883", &conf)?; EspMqttClient::new_with_conn("mqtt://192.168.31.11:1883", &conf)?;
info!("MQTT client started"); info!("MQTT client started");
thread::spawn(move || { thread::spawn(move || {

124
src/voltage_detection.rs Normal file
View File

@ -0,0 +1,124 @@
use std::{
sync::{Arc, Mutex},
time::Duration,
};
use embedded_hal::{adc::Channel, prelude::_embedded_hal_adc_OneShot, digital::v2::OutputPin};
use embedded_svc::timer::{PeriodicTimer, TimerService};
use esp_idf_hal::{
adc::{
config::{self},
Analog, PoweredAdc, ADC1,
},
gpio::{Gpio1, Gpio2, Gpio3, Input, Pull},
};
use esp_idf_svc::timer::{EspTimer, EspTimerService};
use log::{info, warn};
pub struct VoltageDetection {
pub worker: VoltageDetectionWorker,
watch_timer: Option<EspTimer>,
}
#[derive(Clone, Copy)]
pub struct VoltageDetectionWorker {
pub adapter_voltage: u16,
pub battery_voltage: u16,
pub output_voltage: u16,
}
impl VoltageDetection {
pub fn new() -> Self {
return Self {
worker: VoltageDetectionWorker::new(),
watch_timer: None,
};
}
pub fn watching(&mut self) -> anyhow::Result<()> {
let worker = Arc::new(Mutex::new(self.worker));
let mut timer = EspTimerService::new()?.timer(move || {
info!("One-shot timer triggered");
match worker.as_ref().lock().as_mut() {
Ok(worker) => {
if let Err(err) = worker.read_once() {
warn!("Read Failed. {}", err);
}
info!(
"Adapter: {},\tBattery: {},\t Output: {}",
worker.adapter_voltage, worker.battery_voltage, worker.output_voltage
);
}
Err(err) => {
warn!("Lock VoltageDetection Worker Failed. {}", err)
}
}
})?;
timer.every(Duration::from_secs(1))?;
self.watch_timer = Some(timer);
return anyhow::Ok(());
}
}
impl VoltageDetectionWorker {
pub fn new() -> Self {
return Self {
adapter_voltage: 0,
battery_voltage: 0,
output_voltage: 0,
};
}
pub fn read_once(&mut self) -> anyhow::Result<()> {
let adapter_pin = unsafe { Gpio1::<Input>::new() }
.into_analog_atten_11db()
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?;
match self.read_pin_once(adapter_pin) {
Ok(voltage) => {
self.adapter_voltage = voltage;
}
Err(err) => {
warn!("Adapter Voltage read failed: {:?}", err);
}
}
let battery_pin = unsafe { Gpio2::<Input>::new() }
.into_analog_atten_11db()
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?;
match self.read_pin_once(battery_pin) {
Ok(voltage) => {
self.battery_voltage = voltage;
}
Err(err) => {
warn!("Adapter Voltage read failed: {:?}", err);
}
}
let output_pin = unsafe { Gpio3::<Input>::new() }
.into_analog_atten_11db()
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?;
match self.read_pin_once(output_pin) {
Ok(voltage) => {
self.output_voltage = voltage;
}
Err(err) => {
warn!("Adapter Voltage read failed: {:?}", err);
}
}
return anyhow::Ok(());
}
pub fn read_pin_once<AN: Analog<ADC1>, PIN: Channel<AN, ID = u8>>(
&mut self,
mut pin: PIN,
) -> anyhow::Result<u16> {
let mut adc = PoweredAdc::new(unsafe { ADC1::new() }, config::Config::new())?;
let voltage = adc.read(&mut pin);
match voltage {
Ok(voltage) => anyhow::Ok((self.adapter_voltage + voltage * 10) / 11),
Err(err) => {
anyhow::bail!("Adapter Voltage read failed: {:?}", err)
}
}
}
}