Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
399686857f | |||
5c8e216809 | |||
e90f1e0ebb | |||
6e6e35021b | |||
59d21b3fe4 | |||
736808931a | |||
643295b388 | |||
19c682219c |
10 changed files with 1376 additions and 712 deletions
1923
Cargo.lock
generated
1923
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
31
Cargo.toml
31
Cargo.toml
|
@ -1,35 +1,34 @@
|
||||||
[package]
|
[package]
|
||||||
name = "hassliebe"
|
name = "hassliebe"
|
||||||
version = "1.0.0"
|
version = "1.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "BlueOak-1.0.0"
|
license = "BlueOak-1.0.0"
|
||||||
authors = ["Moritz Ruth <dev@moritzruth.de>"]
|
authors = ["Moritz Ruth <dev@moritzruth.de>"]
|
||||||
homepage = "https://git.moritzruth.de/moritzruth/Hassliebe"
|
|
||||||
repository = "https://git.moritzruth.de/moritzruth/Hassliebe"
|
repository = "https://git.moritzruth.de/moritzruth/Hassliebe"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
dry_run = [] # will prevent some actions like shutting down
|
dry_run = [] # will prevent some actions like shutting down
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.69"
|
anyhow = "1.0.88"
|
||||||
base64 = "0.21.0"
|
base64 = "0.22.1"
|
||||||
battery = "0.7.8"
|
env_logger = "0.11.5"
|
||||||
env_logger = "0.10.0"
|
|
||||||
exitcode = "1.1.2"
|
exitcode = "1.1.2"
|
||||||
image = "0.24.5"
|
image = "0.25.2"
|
||||||
json = "0.12.4"
|
json = "0.12.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
notify-rust = { version = "4.8.0", features = ["images"] }
|
notify-rust = { version = "4.11.3", features = ["images"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
regex = "1.7.1"
|
regex = "1.7.1"
|
||||||
rumqttc = "0.20.0"
|
rumqttc = "0.24.0"
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = "1.0.93"
|
serde_json = "1.0.128"
|
||||||
sysinfo = { version = "0.28.2", default-features = false }
|
sysinfo = { version = "0.31.4", default-features = false, features = ["system"] }
|
||||||
tokio = { version = "1.25.0", features = ["full"] }
|
tokio = { version = "1.25.0", features = ["full"] }
|
||||||
toml = "0.7.2"
|
toml = "0.8.19"
|
||||||
users = "0.11.0"
|
users = "0.11.0"
|
||||||
validator = { version = "0.16.0", features = ["derive"] }
|
validator = { version = "0.18.1", features = ["derive"] }
|
||||||
void = "1.0.2"
|
|
||||||
zbus = { version = "3.10.0", default-features = false, features = ["tokio"] }
|
[profile.release]
|
||||||
|
strip = true # Automatically strip symbols from the binary.
|
||||||
|
|
36
README.md
36
README.md
|
@ -2,27 +2,31 @@
|
||||||
|
|
||||||
> Integrates any Linux machine into your Home Assistant ecosystem.
|
> Integrates any Linux machine into your Home Assistant ecosystem.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [x] Command buttons
|
- [x] Command buttons
|
||||||
- [x] Notifications
|
- [x] Notifications
|
||||||
- [x] Actions
|
- [x] Actions
|
||||||
- [x] System information reporting (CPU usage, battery status, …)
|
- [x] System information reporting (CPU usage, RAM usage, battery status)
|
||||||
- [ ] Media control (MPRIS)
|
|
||||||
|
The following sound like interesting ideas but as I don’t have a use case for them at the moment, I haven’t implemented them yet.
|
||||||
|
Feel free to [open an issue and describe your use-case](https://git.moritzruth.de/moritzruth/Hassliebe/issues/new).
|
||||||
|
|
||||||
- [ ] PipeWire control
|
- [ ] PipeWire control
|
||||||
- [ ] File watcher
|
- [ ] Exposing file contents as sensors
|
||||||
|
|
||||||
Ideas:
|
|
||||||
|
|
||||||
- Camera video stream
|
|
||||||
- Idle time (→ libseat)
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
Hassliebe is a [single executable](https://git.moritzruth.de/moritzruth/Hassliebe/releases). Copy it somewhere and execute it.
|
||||||
|
|
||||||
|
For systemd users, a unit file is provided.
|
||||||
|
|
||||||
### As a systemd _system_ service
|
### As a systemd _system_ service
|
||||||
|
|
||||||
- Download [the latest binary](https://git.moritzruth.de/moritzruth/Hassliebe/releases) and put it into `/usr/bin`.
|
- Download [the latest binary](https://git.moritzruth.de/moritzruth/Hassliebe/releases) and put it into `/usr/bin`.
|
||||||
- Download [the unit file](distrib/systemd/system/hassliebe.service) and put it into `/etc/systemd/system`.
|
- Download [the unit file](contrib/systemd/system/hassliebe.service) and put it into `/etc/systemd/system`.
|
||||||
- Create the configuration file (see below) at `/etc/hassliebe/config.toml`.
|
- Create the configuration file (see below) at `/etc/hassliebe/config.toml`.
|
||||||
- Enable and start the unit:
|
- Enable and start the unit:
|
||||||
|
|
||||||
|
@ -30,10 +34,11 @@ Ideas:
|
||||||
systemctl enable hassliebe && systemctl start hassliebe
|
systemctl enable hassliebe && systemctl start hassliebe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### As a systemd _user_ service
|
### As a systemd _user_ service
|
||||||
|
|
||||||
- Download [the latest binary](https://git.moritzruth.de/moritzruth/Hassliebe/releases) and put it into `~/.local/bin`.
|
- Download [the latest binary](https://git.moritzruth.de/moritzruth/Hassliebe/releases) and put it into `~/.local/bin`.
|
||||||
- Download [the unit file](distrib/systemd/user/hassliebe.service) and put it into `~/.local/share/systemd/user`.
|
- Download [the unit file](contrib/systemd/user/hassliebe.service) and put it into `~/.local/share/systemd/user`.
|
||||||
- Create the configuration file (see below) at `$XDG_CONFIG_HOME/hassliebe/config.toml`.
|
- Create the configuration file (see below) at `$XDG_CONFIG_HOME/hassliebe/config.toml`.
|
||||||
- Enable and start the unit:
|
- Enable and start the unit:
|
||||||
|
|
||||||
|
@ -41,11 +46,13 @@ systemctl enable hassliebe && systemctl start hassliebe
|
||||||
systemctl --user enable hassliebe && systemctl --user start hassliebe
|
systemctl --user enable hassliebe && systemctl --user start hassliebe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Depending on whether Hassliebe is run as root or as a regular user, the configuration is read from
|
Depending on whether Hassliebe is run as root or as a regular user, the configuration is read from
|
||||||
`/etc/hassliebe/config.toml` or `$XDG_CONFIG_HOME/hassliebe/config.toml`.
|
`/etc/hassliebe/config.toml` or `$XDG_CONFIG_HOME/hassliebe/config.toml`.
|
||||||
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
@ -56,6 +63,9 @@ display_name = "My PC"
|
||||||
host = "127.0.0.1" # You probably need to change this
|
host = "127.0.0.1" # You probably need to change this
|
||||||
port = 1883
|
port = 1883
|
||||||
|
|
||||||
|
# You can remove the following line if your MQTT broker allows unauthenticated access
|
||||||
|
credentials = { user = "user", password = "password" }
|
||||||
|
|
||||||
[modules.buttons]
|
[modules.buttons]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
||||||
|
@ -74,6 +84,7 @@ battery = 60
|
||||||
enabled = true
|
enabled = true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Machine identification
|
### Machine identification
|
||||||
|
|
||||||
Hassliebe needs a way to uniquely identify a machine.
|
Hassliebe needs a way to uniquely identify a machine.
|
||||||
|
@ -83,6 +94,7 @@ If `/etc/machine-id` exists (as is the case with systemd-based systems), it will
|
||||||
Otherwise, a random ID will be generated on the first run and stored in `[data]/machine_id`.
|
Otherwise, a random ID will be generated on the first run and stored in `[data]/machine_id`.
|
||||||
The latter always takes precedence.
|
The latter always takes precedence.
|
||||||
|
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
### Buttons
|
### Buttons
|
||||||
|
@ -99,6 +111,7 @@ run_in_shell = true # defaults to false
|
||||||
|
|
||||||
When `run_in_shell` is set to `true`, the command will be run with `/bin/sh`.
|
When `run_in_shell` is set to `true`, the command will be run with `/bin/sh`.
|
||||||
|
|
||||||
|
|
||||||
### Info
|
### Info
|
||||||
|
|
||||||
Hassliebe currently supports reporting the following system stats:
|
Hassliebe currently supports reporting the following system stats:
|
||||||
|
@ -117,6 +130,7 @@ ram_usage = 0 # disabled
|
||||||
battery = 60 # updates every 60 seconds
|
battery = 60 # updates every 60 seconds
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Notifications
|
### Notifications
|
||||||
|
|
||||||
**Not available when running as a system service.**
|
**Not available when running as a system service.**
|
||||||
|
@ -152,6 +166,7 @@ Complex messages have these properties:
|
||||||
- `encoded_image` (optional) — Padded Base64-encoded image attached to the notification.
|
- `encoded_image` (optional) — Padded Base64-encoded image attached to the notification.
|
||||||
- `actions` (optional) — Object with the keys being IDs and the values being labels.
|
- `actions` (optional) — Object with the keys being IDs and the values being labels.
|
||||||
|
|
||||||
|
|
||||||
#### Actions
|
#### Actions
|
||||||
|
|
||||||
When a notification action is invoked, the ID of the action is sent to the MQTT topic with the following name:
|
When a notification action is invoked, the ID of the action is sent to the MQTT topic with the following name:
|
||||||
|
@ -159,6 +174,7 @@ When a notification action is invoked, the ID of the action is sent to the MQTT
|
||||||
|
|
||||||
When a notification is dismissed, `closed` is sent into the topic.
|
When a notification is dismissed, `closed` is sent into the topic.
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Hassliebe is licensed under the [Blue Oak Model License 1.0.0](./LICENSE.md).
|
This project is available under the permissive [Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0).
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub struct Mqtt {
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[validate]
|
#[validate(nested)]
|
||||||
pub credentials: Option<MqttCredentials>,
|
pub credentials: Option<MqttCredentials>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,16 +33,16 @@ pub struct Internal {
|
||||||
|
|
||||||
#[derive(Deserialize, Validate)]
|
#[derive(Deserialize, Validate)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[validate(custom = "crate::util::validate_hass_id")]
|
#[validate(custom(function = "crate::util::validate_hass_id"))]
|
||||||
pub friendly_id: String,
|
pub friendly_id: String,
|
||||||
|
|
||||||
#[validate(length(min = 1))]
|
#[validate(length(min = 1))]
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
|
||||||
#[validate]
|
#[validate(nested)]
|
||||||
pub mqtt: Mqtt,
|
pub mqtt: Mqtt,
|
||||||
|
|
||||||
#[validate]
|
#[validate(nested)]
|
||||||
pub modules: modules::Config,
|
pub modules: modules::Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ pub fn load(config_file_path: &Path) -> Result<Option<Config>> {
|
||||||
file.read_to_string(&mut string_content).context("while reading the configuration file")?;
|
file.read_to_string(&mut string_content).context("while reading the configuration file")?;
|
||||||
|
|
||||||
let parsed = toml::from_str::<Config>(string_content.as_str()).context("while parsing the configuration file")?;
|
let parsed = toml::from_str::<Config>(string_content.as_str()).context("while parsing the configuration file")?;
|
||||||
parsed.validate().context("while validating the configuration file")?;
|
Validate::validate(&parsed).context("while validating the configuration file")?;
|
||||||
|
|
||||||
Ok(Some(parsed))
|
Ok(Some(parsed))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ const BUTTON_TRIGGER_TEXT: &str = "press";
|
||||||
|
|
||||||
#[derive(Deserialize, Validate, Clone)]
|
#[derive(Deserialize, Validate, Clone)]
|
||||||
pub struct ButtonConfig {
|
pub struct ButtonConfig {
|
||||||
#[validate(custom = "crate::util::validate_hass_id")]
|
#[validate(custom(function = "crate::util::validate_hass_id"))]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
||||||
#[validate(length(min = 1))]
|
#[validate(length(min = 1))]
|
||||||
|
|
|
@ -3,10 +3,10 @@ use std::time::Duration;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use rumqttc::QoS;
|
use rumqttc::QoS;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sysinfo::{CpuExt, System, SystemExt};
|
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
use tokio::time::MissedTickBehavior;
|
use tokio::time::MissedTickBehavior;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
use sysinfo::System;
|
||||||
|
|
||||||
use crate::modules::InitializationContext;
|
use crate::modules::InitializationContext;
|
||||||
|
|
||||||
|
@ -43,14 +43,16 @@ pub async fn init(context: &mut InitializationContext) -> Result<()> {
|
||||||
sub_id: "ram_usage",
|
sub_id: "ram_usage",
|
||||||
display_name: "RAM Usage",
|
display_name: "RAM Usage",
|
||||||
icon: "mdi:memory",
|
icon: "mdi:memory",
|
||||||
suggested_precision: 0,
|
suggested_precision: Some(0),
|
||||||
unit: Some("%"),
|
unit: Some("%"),
|
||||||
|
force_update: true,
|
||||||
|
device_class: None
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
config.ram_usage,
|
config.ram_usage,
|
||||||
move || {
|
move || {
|
||||||
sys.refresh_memory();
|
sys.refresh_memory();
|
||||||
Ok(format!("{:.2}", (sys.available_memory() as f64) / (sys.total_memory() as f64) * 100.0))
|
Ok(format!("{:.2}", (sys.used_memory() as f64) / (sys.total_memory() as f64) * 100.0))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -63,14 +65,16 @@ pub async fn init(context: &mut InitializationContext) -> Result<()> {
|
||||||
sub_id: "cpu_usage",
|
sub_id: "cpu_usage",
|
||||||
display_name: "CPU Usage",
|
display_name: "CPU Usage",
|
||||||
icon: "mdi:memory",
|
icon: "mdi:memory",
|
||||||
suggested_precision: 0,
|
suggested_precision: Some(0),
|
||||||
unit: Some("%"),
|
unit: Some("%"),
|
||||||
|
force_update: true,
|
||||||
|
device_class: None
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
config.cpu_usage,
|
config.cpu_usage,
|
||||||
move || {
|
move || {
|
||||||
sys.refresh_cpu();
|
sys.refresh_cpu_usage();
|
||||||
Ok(format!("{:.2}", sys.global_cpu_info().cpu_usage()))
|
Ok(format!("{:.2}", sys.global_cpu_usage()))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -86,8 +90,7 @@ pub async fn init(context: &mut InitializationContext) -> Result<()> {
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
})
|
})
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(dir) = battery_dirs.first() {
|
if let Some(dir) = battery_dirs.first() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
|
@ -106,8 +109,10 @@ pub async fn init(context: &mut InitializationContext) -> Result<()> {
|
||||||
sub_id: "battery_level",
|
sub_id: "battery_level",
|
||||||
display_name: "Battery Level",
|
display_name: "Battery Level",
|
||||||
icon: "mdi:battery",
|
icon: "mdi:battery",
|
||||||
suggested_precision: 0,
|
suggested_precision: Some(0),
|
||||||
unit: Some("%"),
|
unit: Some("%"),
|
||||||
|
force_update: true,
|
||||||
|
device_class: Some("battery")
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
config.battery,
|
config.battery,
|
||||||
|
@ -120,8 +125,10 @@ pub async fn init(context: &mut InitializationContext) -> Result<()> {
|
||||||
sub_id: "battery_state",
|
sub_id: "battery_state",
|
||||||
display_name: "Battery State",
|
display_name: "Battery State",
|
||||||
icon: "mdi:battery",
|
icon: "mdi:battery",
|
||||||
suggested_precision: 0,
|
suggested_precision: None,
|
||||||
unit: None,
|
unit: None,
|
||||||
|
force_update: false,
|
||||||
|
device_class: Some("enum")
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
config.battery,
|
config.battery,
|
||||||
|
@ -140,8 +147,10 @@ struct InfoEntityOptions<'a> {
|
||||||
sub_id: &'a str,
|
sub_id: &'a str,
|
||||||
display_name: &'a str,
|
display_name: &'a str,
|
||||||
icon: &'a str,
|
icon: &'a str,
|
||||||
suggested_precision: u64,
|
suggested_precision: Option<u64>,
|
||||||
unit: Option<&'a str>,
|
unit: Option<&'a str>,
|
||||||
|
force_update: bool,
|
||||||
|
device_class: Option<&'a str>
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_info_value(
|
async fn init_info_value(
|
||||||
|
@ -167,10 +176,10 @@ async fn init_info_value(
|
||||||
let mut object = json::object! {
|
let mut object = json::object! {
|
||||||
"availability_topic": context.full.mqtt.availability_topic.clone(),
|
"availability_topic": context.full.mqtt.availability_topic.clone(),
|
||||||
"device": context.full.mqtt.discovery_device_object.clone(),
|
"device": context.full.mqtt.discovery_device_object.clone(),
|
||||||
"force_update": true,
|
"device_class": options.device_class,
|
||||||
|
"force_update": options.force_update,
|
||||||
"icon": options.icon,
|
"icon": options.icon,
|
||||||
"name": options.display_name,
|
"name": options.display_name,
|
||||||
"suggested_display_precision": options.suggested_precision,
|
|
||||||
"state_class": "measurement",
|
"state_class": "measurement",
|
||||||
"state_topic": state_topic.as_str(),
|
"state_topic": state_topic.as_str(),
|
||||||
"object_id": entity_id.as_str(),
|
"object_id": entity_id.as_str(),
|
||||||
|
@ -181,6 +190,10 @@ async fn init_info_value(
|
||||||
object.insert("unit_of_measurement", unit).unwrap();
|
object.insert("unit_of_measurement", unit).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(suggested_precision) = options.suggested_precision {
|
||||||
|
object.insert("suggested_display_precision", suggested_precision).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,13 +13,13 @@ mod notifications;
|
||||||
|
|
||||||
#[derive(Deserialize, Validate, Default)]
|
#[derive(Deserialize, Validate, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[validate]
|
#[validate(nested)]
|
||||||
pub buttons: Option<buttons::Config>,
|
pub buttons: Option<buttons::Config>,
|
||||||
|
|
||||||
#[validate]
|
#[validate(nested)]
|
||||||
pub info: Option<info::Config>,
|
pub info: Option<info::Config>,
|
||||||
|
|
||||||
#[validate]
|
#[validate(nested)]
|
||||||
pub notifications: Option<notifications::Config>,
|
pub notifications: Option<notifications::Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
41
src/mqtt.rs
41
src/mqtt.rs
|
@ -28,9 +28,9 @@ pub async fn create_client(config: &config::Config, machine_id: &str, availabili
|
||||||
usize::MAX,
|
usize::MAX,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (mqtt_client, event_loop) = MqttClient::new(options, 100);
|
config.mqtt.credentials.as_ref().map(|c| options.set_credentials(c.user.clone(), c.password.clone()));
|
||||||
mqtt_client.publish(availability_topic, QoS::AtLeastOnce, true, "online").await?;
|
|
||||||
|
|
||||||
|
let (mqtt_client, event_loop) = MqttClient::new(options, 30);
|
||||||
Ok((mqtt_client, event_loop))
|
Ok((mqtt_client, event_loop))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,20 +111,6 @@ pub async fn start_communication(context: &InitializationContext, mut event_loop
|
||||||
context.full.config.mqtt.port
|
context.full.config.mqtt.port
|
||||||
);
|
);
|
||||||
|
|
||||||
if !context.message_handler_by_mqtt_topic.is_empty() {
|
|
||||||
context
|
|
||||||
.full
|
|
||||||
.mqtt
|
|
||||||
.client
|
|
||||||
.subscribe_many(
|
|
||||||
context
|
|
||||||
.message_handler_by_mqtt_topic
|
|
||||||
.keys()
|
|
||||||
.map(|k| SubscribeFilter::new(k.to_owned(), QoS::AtLeastOnce)),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut connection_state = ConnectionState::NotConnected;
|
let mut connection_state = ConnectionState::NotConnected;
|
||||||
let mut owned_topics_service = Some(owned_topics_service);
|
let mut owned_topics_service = Some(owned_topics_service);
|
||||||
|
|
||||||
|
@ -177,9 +163,30 @@ pub async fn start_communication(context: &InitializationContext, mut event_loop
|
||||||
if connection_state == ConnectionState::NotConnected {
|
if connection_state == ConnectionState::NotConnected {
|
||||||
log::info!("Connection established")
|
log::info!("Connection established")
|
||||||
} else {
|
} else {
|
||||||
log::info!("Connection restored")
|
log::info!("Connection restored");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !context.message_handler_by_mqtt_topic.is_empty() {
|
||||||
|
context
|
||||||
|
.full
|
||||||
|
.mqtt
|
||||||
|
.client
|
||||||
|
.subscribe_many(
|
||||||
|
context
|
||||||
|
.message_handler_by_mqtt_topic
|
||||||
|
.keys()
|
||||||
|
.map(|k| SubscribeFilter::new(k.to_owned(), QoS::AtLeastOnce)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
context
|
||||||
|
.full
|
||||||
|
.mqtt
|
||||||
|
.client
|
||||||
|
.publish(&context.full.mqtt.availability_topic, QoS::AtLeastOnce, true, "online")
|
||||||
|
.await?;
|
||||||
|
|
||||||
if let Some(service) = owned_topics_service.take() {
|
if let Some(service) = owned_topics_service.take() {
|
||||||
service.clear_old_and_save_new(&context.full.mqtt.client, &context.owned_mqtt_topics).await?;
|
service.clear_old_and_save_new(&context.full.mqtt.client, &context.owned_mqtt_topics).await?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue