Compare commits
4
Commits
624d90f3c9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38f849e323
|
||
|
|
233a0944c7 | ||
|
|
0ed1871042
|
||
|
|
bf6ccc6df1
|
No files matched your search
@@ -9,6 +9,8 @@ mqtt:
|
|||||||
rooms:
|
rooms:
|
||||||
- "!iFCnqQcvrVIeehrjQO:chat.labolyon.fr"
|
- "!iFCnqQcvrVIeehrjQO:chat.labolyon.fr"
|
||||||
|
|
||||||
|
debounce_delay: 10 # seconds
|
||||||
|
|
||||||
# username / password login
|
# username / password login
|
||||||
# /!\ will create a new device every time the bot starts
|
# /!\ will create a new device every time the bot starts
|
||||||
username: "login"
|
username: "login"
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ pub enum AuthConfig {
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub mqtt: MQTTConfig,
|
pub mqtt: MQTTConfig,
|
||||||
pub rooms: Vec<String>,
|
pub rooms: Vec<String>,
|
||||||
|
pub debounce_delay: u64,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub auth: AuthConfig,
|
pub auth: AuthConfig,
|
||||||
pub homeserver_uri: String
|
pub homeserver_uri: String
|
||||||
|
|||||||
+71
-15
@@ -24,7 +24,8 @@ mod matrix;
|
|||||||
mod mqtt;
|
mod mqtt;
|
||||||
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::{Notify, broadcast},
|
sync::{Notify, broadcast, mpsc},
|
||||||
|
time::{sleep, Duration},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,11 +49,16 @@ struct Args {
|
|||||||
config: String,
|
config: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||||
enum LolOpenerStatus {
|
enum DoorSensorStatus {
|
||||||
Open,
|
Open,
|
||||||
Closed,
|
Closed,
|
||||||
}
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct LolOpenerState {
|
||||||
|
sensor_status: Option<DoorSensorStatus>,
|
||||||
|
pending: Option<(DoorSensorStatus, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
@@ -80,25 +86,75 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
matrix_ready.notified().await;
|
matrix_ready.notified().await;
|
||||||
info!("Matrix is ready");
|
info!("Matrix is ready");
|
||||||
|
|
||||||
let current_status = Arc::new(Mutex::new(None));
|
let current_state = Arc::new(Mutex::new(LolOpenerState {
|
||||||
let current_status = Arc::clone(¤t_status);
|
sensor_status: None,
|
||||||
|
pending: None
|
||||||
|
}));
|
||||||
|
let current_state = Arc::clone(¤t_state);
|
||||||
|
|
||||||
|
let (debounce_tx, mut debounce_rx) = mpsc::unbounded_channel::<(DoorSensorStatus, String)>();
|
||||||
|
let debounce_delay = config.debounce_delay;
|
||||||
|
let rooms = config.rooms.clone();
|
||||||
|
let handle = tokio::spawn(async move {
|
||||||
|
|
||||||
|
while let Some((new_status, msg)) = debounce_rx.recv().await {
|
||||||
|
let should_wait = {
|
||||||
|
//XXX: Panic if the lock is poisoned
|
||||||
|
let mut state = current_state.lock().unwrap();
|
||||||
|
let should_wait = state.pending.is_none();
|
||||||
|
|
||||||
|
state.pending = Some((new_status, msg));
|
||||||
|
should_wait
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_wait {
|
||||||
|
let tx = bcast_tx.clone();
|
||||||
|
let rooms = rooms.clone();
|
||||||
|
let state = current_state.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
sleep(Duration::from_secs(debounce_delay)).await;
|
||||||
|
|
||||||
|
let msg = {
|
||||||
|
//XXX: Panic if the lock is poisoned
|
||||||
|
let mut state = state.lock().unwrap();
|
||||||
|
let pending = state.pending.take();
|
||||||
|
|
||||||
|
match pending {
|
||||||
|
Some((status, msg))
|
||||||
|
if state.sensor_status.as_ref() != Some(&status) => {
|
||||||
|
state.sensor_status = Some(status);
|
||||||
|
Some(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(msg) = msg {
|
||||||
|
debug!("Sending msg {}", msg);
|
||||||
|
//XXX: Panic if the matrix module can't get the message
|
||||||
|
tx.send((msg, rooms)).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mut mqtt = MQTT::new(config.mqtt.clone()).await;
|
let mut mqtt = MQTT::new(config.mqtt.clone()).await;
|
||||||
mqtt.subscribe(move |status: StatusMessage| {
|
mqtt.subscribe(move |status: StatusMessage| {
|
||||||
let (new_status, msg) = match status {
|
let (new_status, msg) = match status {
|
||||||
StatusMessage { contact: true, .. } => (Some(LolOpenerStatus::Closed), "🔴 Le LOL est fermé :("),
|
StatusMessage { contact: true, .. } => (DoorSensorStatus::Closed, "🔴 Le LOL est fermé :("),
|
||||||
StatusMessage { contact: false, .. } => (Some(LolOpenerStatus::Open), "🟢 Le LOL est ouvert :)"),
|
StatusMessage { contact: false, .. } => (DoorSensorStatus::Open, "🟢 Le LOL est ouvert :)"),
|
||||||
};
|
};
|
||||||
|
|
||||||
//XXX: Panic if the lock is poisoned (why would that happen?)
|
//XXX: Panic if the channel is closed
|
||||||
let mut current_status = current_status.lock().unwrap();
|
debounce_tx.send((new_status, String::from(msg))).unwrap();
|
||||||
if new_status != *current_status {
|
|
||||||
debug!("Sending msg {}", msg);
|
|
||||||
//XXX: Panic if the matrix module can't get the message
|
|
||||||
bcast_tx.send((msg.into(), config.rooms.clone())).unwrap();
|
|
||||||
*current_status = new_status;
|
|
||||||
}
|
|
||||||
}).await.unwrap(); //XXX: Panic if the mqtt broker fails
|
}).await.unwrap(); //XXX: Panic if the mqtt broker fails
|
||||||
|
|
||||||
|
handle.abort();
|
||||||
|
handle.await.unwrap();
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -133,7 +133,9 @@ async fn login(
|
|||||||
match auth_config {
|
match auth_config {
|
||||||
AuthConfig::PasswordAuthConfig{username, password} => {
|
AuthConfig::PasswordAuthConfig{username, password} => {
|
||||||
matrix_auth.login_username(username, password)
|
matrix_auth.login_username(username, password)
|
||||||
.initial_device_display_name("bender v0.2.0").await?;
|
.initial_device_display_name(
|
||||||
|
format!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")).as_str()
|
||||||
|
).await?;
|
||||||
},
|
},
|
||||||
AuthConfig::TokenAuthConfig{user_id, device_id, access_token} => {
|
AuthConfig::TokenAuthConfig{user_id, device_id, access_token} => {
|
||||||
matrix_auth.restore_session(
|
matrix_auth.restore_session(
|
||||||
|
|||||||
Reference in new issue
Block a user