Files
matrix-lolopener/src/config.rs
T
mirsal 38f849e323 Implement sensor status debouncing
This introduces a configurable debouncing delay before which no update
is sent to matrix, which avoids flooding the matrix room with updates
when the door is opened and closed in quick succession. It also allows
to quickly open and close the door without sending notifications.

The debouncing window can be configured in config.yml, see example.
2026-10-07 20:17:49 +00:00

102 lines
2.5 KiB
Rust

/*!
* matrix-lolopener v0.1.0
*
* Copyright (C) 2026 The 1312 Media Collective
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use serde::Deserialize;
use std::{fs, io, fmt};
#[derive(Deserialize, Debug, Clone)]
pub struct MQTTConfig {
pub id: String,
pub host: String,
pub port: u16,
pub topic: String,
}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub enum AuthConfig {
PasswordAuthConfig {
username: String,
password: String,
},
TokenAuthConfig {
user_id: String,
device_id: String,
access_token: String,
}
}
#[derive(Deserialize, Debug)]
pub struct Config {
pub mqtt: MQTTConfig,
pub rooms: Vec<String>,
pub debounce_delay: u64,
#[serde(flatten)]
pub auth: AuthConfig,
pub homeserver_uri: String
}
impl Config {
pub fn load(config_file: &str) -> Result<Self> {
let serialized_config = fs::read_to_string(config_file).map_err(|e| {
match e.kind() {
io::ErrorKind::NotFound => Error::FileNotFound(config_file.into()),
io::ErrorKind::PermissionDenied => Error::PermissionDenied(),
_ => e.into(),
}
})?;
let config: Config = serde_yaml::from_str(&serialized_config)?;
Ok(config)
}
}
#[derive(Debug)]
#[allow(dead_code)] // we use Debug, so inner fields are never read
pub enum Error {
FileNotFound(String),
PermissionDenied(),
InvalidFormat(serde_yaml::Error),
Io(io::Error),
}
impl From<serde_yaml::Error> for Error {
fn from(e: serde_yaml::Error) -> Self {
Self::InvalidFormat(e)
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Self::Io(e)
}
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
write!(fmt, "{self:?}")
}
}
pub type Result<T> = std::result::Result<T, Error>;