Setting the presence mqtt topic is now optional, if not set it will generate an appropriate value automatically
This commit is contained in:
parent
cbcbd05613
commit
27a63b1a79
|
@ -52,5 +52,4 @@ speakers = "10.0.0.182"
|
|||
[devices.hallway_frontdoor]
|
||||
type = "ContactSensor"
|
||||
topic = "zigbee2mqtt/hallway/frontdoor"
|
||||
# @TODO This should be automatically constructed from the identifier and presence topic
|
||||
presence = { topic = "automation_dev/presence/frontdoor", timeout = 10 }
|
||||
presence = { timeout = 10 }
|
||||
|
|
|
@ -28,7 +28,7 @@ pub struct OpenIDConfig {
|
|||
pub base_url: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct MqttConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
|
@ -96,32 +96,43 @@ pub struct HueBridgeConfig {
|
|||
pub flags: Flags,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct InfoConfig {
|
||||
pub name: String,
|
||||
pub room: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct MqttDeviceConfig {
|
||||
pub topic: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct KettleConfig {
|
||||
pub timeout: Option<u64>, // Timeout in seconds
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct PresenceDeviceConfig {
|
||||
#[serde(flatten)]
|
||||
pub mqtt: MqttDeviceConfig,
|
||||
pub mqtt: Option<MqttDeviceConfig>,
|
||||
// @TODO Maybe make this an option? That way if no timeout is set it will immediately turn the
|
||||
// device off again?
|
||||
pub timeout: u64 // Timeout in seconds
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
impl PresenceDeviceConfig {
|
||||
/// Set the mqtt topic to an appropriate value if it is not already set
|
||||
fn generate_topic(&mut self, identifier: &str, config: &Config) {
|
||||
if self.mqtt.is_none() {
|
||||
let topic = config.presence.topic.clone() + "/" + identifier;
|
||||
trace!("Setting presence mqtt topic: {topic}");
|
||||
self.mqtt = Some(MqttDeviceConfig { topic });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Device {
|
||||
IkeaOutlet {
|
||||
|
@ -182,7 +193,7 @@ impl Config {
|
|||
}
|
||||
|
||||
impl Device {
|
||||
pub fn into(self, identifier: String, client: AsyncClient) -> DeviceBox {
|
||||
pub fn into(self, identifier: String, config: &Config, client: AsyncClient) -> DeviceBox {
|
||||
match self {
|
||||
Device::IkeaOutlet { info, mqtt, kettle } => {
|
||||
trace!(id = identifier, "IkeaOutlet [{} in {:?}]", info.name, info.room);
|
||||
|
@ -196,8 +207,11 @@ impl Device {
|
|||
trace!(id = identifier, "AudioSetup [{}]", identifier);
|
||||
Box::new(AudioSetup::new(identifier, mqtt, mixer, speakers, client))
|
||||
},
|
||||
Device::ContactSensor { mqtt, presence } => {
|
||||
Device::ContactSensor { mqtt, mut presence } => {
|
||||
trace!(id = identifier, "ContactSensor [{}]", identifier);
|
||||
if let Some(presence) = &mut presence {
|
||||
presence.generate_topic(&identifier, &config);
|
||||
}
|
||||
Box::new(ContactSensor::new(identifier, mqtt, presence, client))
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
use pollster::FutureExt;
|
||||
use rumqttc::AsyncClient;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing::{error, debug};
|
||||
use tracing::{error, debug, warn};
|
||||
|
||||
use crate::{config::{MqttDeviceConfig, PresenceDeviceConfig}, mqtt::{OnMqtt, ContactMessage, PresenceMessage}};
|
||||
|
||||
|
@ -68,17 +68,25 @@ impl OnMqtt for ContactSensor {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let topic = match &presence.mqtt {
|
||||
Some(mqtt) => mqtt.topic.clone(),
|
||||
None => {
|
||||
warn!("Contact sensors is configured as a presence sensor, but no mqtt topic is specified");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if !is_closed {
|
||||
// Activate presence and stop any timeout once we open the door
|
||||
if let Some(handle) = self.handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
||||
self.client.publish(presence.mqtt.topic.clone(), rumqttc::QoS::AtLeastOnce, false, serde_json::to_string(&PresenceMessage::new(true)).unwrap()).block_on().unwrap();
|
||||
|
||||
self.client.publish(topic, rumqttc::QoS::AtLeastOnce, false, serde_json::to_string(&PresenceMessage::new(true)).unwrap()).block_on().unwrap();
|
||||
} else {
|
||||
// Once the door is closed again we start a timeout for removing the presence
|
||||
let client = self.client.clone();
|
||||
let topic = presence.mqtt.topic.clone();
|
||||
let id = self.identifier.clone();
|
||||
let timeout = Duration::from_secs(presence.timeout);
|
||||
self.handle = Some(
|
||||
|
|
29
src/main.rs
29
src/main.rs
|
@ -44,8 +44,9 @@ async fn main() {
|
|||
info!("Starting automation_rs...");
|
||||
|
||||
// Configure MQTT
|
||||
let mut mqttoptions = MqttOptions::new("rust-test", config.mqtt.host, config.mqtt.port);
|
||||
mqttoptions.set_credentials(config.mqtt.username, config.mqtt.password);
|
||||
let mqtt = config.mqtt.clone();
|
||||
let mut mqttoptions = MqttOptions::new("rust-test", mqtt.host, mqtt.port);
|
||||
mqttoptions.set_credentials(mqtt.username, mqtt.password);
|
||||
mqttoptions.set_keep_alive(Duration::from_secs(5));
|
||||
mqttoptions.set_transport(Transport::tls_with_default_config());
|
||||
|
||||
|
@ -57,6 +58,18 @@ async fn main() {
|
|||
let devices = Arc::new(RwLock::new(Devices::new()));
|
||||
mqtt.add_listener(Arc::downgrade(&devices));
|
||||
|
||||
// Turn the config into actual devices and add them
|
||||
config.devices.clone()
|
||||
.into_iter()
|
||||
.map(|(identifier, device_config)| {
|
||||
// This can technically block, but this only happens during start-up, so should not be
|
||||
// a problem
|
||||
device_config.into(identifier, &config, client.clone())
|
||||
})
|
||||
.for_each(|device| {
|
||||
devices.write().unwrap().add_device(device);
|
||||
});
|
||||
|
||||
// Setup presence system
|
||||
let mut presence = Presence::new(config.presence, client.clone());
|
||||
// Register devices as presence listener
|
||||
|
@ -82,18 +95,6 @@ async fn main() {
|
|||
// Start mqtt, this spawns a seperate async task
|
||||
mqtt.start();
|
||||
|
||||
// Turn the config into actual devices and add them
|
||||
config.devices
|
||||
.into_iter()
|
||||
.map(|(identifier, device_config)| {
|
||||
// This can technically block, but this only happens during start-up, so should not be
|
||||
// a problem
|
||||
device_config.into(identifier, client.clone())
|
||||
})
|
||||
.for_each(|device| {
|
||||
devices.write().unwrap().add_device(device);
|
||||
});
|
||||
|
||||
// Create google home fullfillment route
|
||||
let fullfillment = Router::new()
|
||||
.route("/google_home", post(async move |user: User, Json(payload): Json<Request>| {
|
||||
|
|
Loading…
Reference in New Issue
Block a user