Compare commits
3
Commits
master
..
3cc606da45
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cc606da45
|
||
|
|
903887a149
|
||
|
|
79ac49041d
|
@@ -1,28 +0,0 @@
|
|||||||
name: Audit
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- "**/Cargo.toml"
|
|
||||||
- "**/Cargo.lock"
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
audit:
|
|
||||||
name: cargo audit
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
- name: Install rust toolchain
|
|
||||||
uses: dtolnay/rust-toolchain@nightly
|
|
||||||
- name: Setup rust cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
- name: Audit check
|
|
||||||
uses: https://git.huizinga.dev/infra/rust-audit-check@v3.0.0
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
@@ -9,7 +9,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
uses: infra/workflows/.gitea/workflows/docker.yaml@2bb37b698effa4fba36040d668cfa95d4abc568e
|
uses: dreaded_x/workflows/.gitea/workflows/docker-kubernetes.yaml@ef78704b98c72e4a6b8340f9bff7b085a7bdd95c
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
push_manifests: false
|
push_manifests: false
|
||||||
|
|||||||
Generated
+673
-557
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -34,10 +34,10 @@ google_home = { path = "./google_home/google_home" }
|
|||||||
google_home_macro = { path = "./google_home/google_home_macro" }
|
google_home_macro = { path = "./google_home/google_home_macro" }
|
||||||
hostname = "0.4.2"
|
hostname = "0.4.2"
|
||||||
inventory = "0.3.24"
|
inventory = "0.3.24"
|
||||||
itertools = "0.15.0"
|
itertools = "0.14.0"
|
||||||
json_value_merge = "2.0.1"
|
json_value_merge = "2.0.1"
|
||||||
lua_typed = { git = "https://git.huizinga.dev/Dreaded_X/lua_typed" }
|
lua_typed = { git = "https://git.huizinga.dev/Dreaded_X/lua_typed" }
|
||||||
mlua = { version = "0.12.0", features = [
|
mlua = { version = "0.11.6", features = [
|
||||||
"lua54",
|
"lua54",
|
||||||
"vendored",
|
"vendored",
|
||||||
"macros",
|
"macros",
|
||||||
@@ -51,11 +51,11 @@ reqwest = { version = "0.13.3", features = [
|
|||||||
"json",
|
"json",
|
||||||
"rustls",
|
"rustls",
|
||||||
], default-features = false } # Use rustls, since the other packages also use rustls
|
], default-features = false } # Use rustls, since the other packages also use rustls
|
||||||
rumqttc-next = "0.34.0"
|
rumqttc = "0.25.1"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
serde_repr = "0.1.20"
|
serde_repr = "0.1.20"
|
||||||
syn = { version = "3.0.3" }
|
syn = { version = "2.0.117" }
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
tokio = { version = "1", features = ["rt-multi-thread"] }
|
tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||||
tokio-cron-scheduler = "0.15.1"
|
tokio-cron-scheduler = "0.15.1"
|
||||||
@@ -80,6 +80,7 @@ lua_typed = { workspace = true }
|
|||||||
inventory = { workspace = true }
|
inventory = { workspace = true }
|
||||||
mlua = { workspace = true }
|
mlua = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
|
rumqttc = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
@@ -87,7 +88,6 @@ tokio = { workspace = true }
|
|||||||
tokio-cron-scheduler = { workspace = true }
|
tokio-cron-scheduler = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
rumqttc-next = { workspace = true }
|
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
wakey = { git = "https://git.huizinga.dev/Dreaded_X/wakey" }
|
wakey = { git = "https://git.huizinga.dev/Dreaded_X/wakey" }
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
FROM rust:1.98-alpine3.24 AS base
|
FROM rust:1.95-alpine AS base
|
||||||
RUN cargo install cargo-chef --locked --version 0.1.71 && \
|
RUN cargo install cargo-chef --locked --version 0.1.71 && \
|
||||||
cargo install cargo-auditable --locked --version 0.6.6
|
cargo install cargo-auditable --locked --version 0.6.6
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -9,7 +9,7 @@ COPY . .
|
|||||||
RUN cargo chef prepare --recipe-path recipe.json
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
RUN apk add --no-cache g++=15.2.0-r5 cmake=4.2.3-r0 make=4.4.1-r4 openssl-dev=3.5.8-r0 openssl-libs-static=3.5.8-r0
|
RUN apk add --no-cache g++=15.2.0-r2 cmake=4.1.3-r0 make=4.4.1-r3 openssl-dev=3.5.7-r0 openssl-libs-static=3.5.7-r0
|
||||||
# HACK: Now we can use unstable feature while on stable rust!
|
# HACK: Now we can use unstable feature while on stable rust!
|
||||||
ENV RUSTC_BOOTSTRAP=1
|
ENV RUSTC_BOOTSTRAP=1
|
||||||
COPY --from=planner /app/recipe.json recipe.json
|
COPY --from=planner /app/recipe.json recipe.json
|
||||||
@@ -21,7 +21,7 @@ ENV RELEASE_VERSION=${RELEASE_VERSION}
|
|||||||
RUN cargo auditable build --release
|
RUN cargo auditable build --release
|
||||||
|
|
||||||
|
|
||||||
FROM gcr.io/distroless/static-debian13:nonroot AS runtime
|
FROM scratch AS runtime
|
||||||
COPY --from=builder /app/target/release/automation /app/automation
|
COPY --from=builder /app/target/release/automation /app/automation
|
||||||
ENV AUTOMATION__ENTRYPOINT=/app/config/config.lua
|
ENV AUTOMATION__ENTRYPOINT=/app/config/config.lua
|
||||||
ENV LUA_PATH="/app/?.lua;;"
|
ENV LUA_PATH="/app/?.lua;;"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ inventory = { workspace = true }
|
|||||||
lua_typed = { workspace = true }
|
lua_typed = { workspace = true }
|
||||||
mlua = { workspace = true }
|
mlua = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
rumqttc-next = { workspace = true }
|
rumqttc = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
serde_repr = { workspace = true }
|
serde_repr = { workspace = true }
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use bambulab::{Command, Message};
|
|||||||
use google_home::errors::{self};
|
use google_home::errors::{self};
|
||||||
use google_home::traits::OnOff;
|
use google_home::traits::OnOff;
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use tracing::{debug, trace};
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::{DebugWrap, LuaDeviceCreate};
|
use crate::{DebugWrap, LuaDeviceCreate};
|
||||||
|
|
||||||
@@ -104,7 +104,6 @@ impl LuaDeviceCreate for Bambu {
|
|||||||
bambu.config.callbacks.state.call(bambu.clone()).await;
|
bambu.config.callbacks.state.call(bambu.clone()).await;
|
||||||
}
|
}
|
||||||
Message::Connected => {
|
Message::Connected => {
|
||||||
debug!(id = bambu.config.device_id, "Connected");
|
|
||||||
client.publish(Command::PushAll).await.unwrap();
|
client.publish(Command::PushAll).await.unwrap();
|
||||||
|
|
||||||
bambu.config.callbacks.connected.call(bambu.clone()).await;
|
bambu.config.callbacks.connected.call(bambu.clone()).await;
|
||||||
|
|||||||
@@ -159,10 +159,7 @@ impl OpenClose for ContactSensor {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl OnMqtt for ContactSensor {
|
impl OnMqtt for ContactSensor {
|
||||||
async fn on_mqtt(&self, message: rumqttc::Publish) {
|
async fn on_mqtt(&self, message: rumqttc::Publish) {
|
||||||
if !rumqttc::matches(
|
if !rumqttc::matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,10 +98,7 @@ impl LuaDeviceCreate for HueSwitch {
|
|||||||
impl OnMqtt for HueSwitch {
|
impl OnMqtt for HueSwitch {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the device itself or from a remote
|
// Check if the message is from the device itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let message = match serde_json::from_slice::<State>(&message.payload) {
|
let message = match serde_json::from_slice::<State>(&message.payload) {
|
||||||
Ok(message) => message,
|
Ok(message) => message,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -70,10 +70,7 @@ impl LuaDeviceCreate for IkeaRemote {
|
|||||||
impl OnMqtt for IkeaRemote {
|
impl OnMqtt for IkeaRemote {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the deviec itself or from a remote
|
// Check if the message is from the deviec itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let message = match RemoteMessage::try_from(message) {
|
let message = match RemoteMessage::try_from(message) {
|
||||||
Ok(message) => message,
|
Ok(message) => message,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -85,10 +85,7 @@ impl Device for LightSensor {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl OnMqtt for LightSensor {
|
impl OnMqtt for LightSensor {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
if !rumqttc::matches(
|
if !rumqttc::matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,10 +105,7 @@ impl Device for Presence {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl OnMqtt for Presence {
|
impl OnMqtt for Presence {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
if !rumqttc::matches(
|
if !rumqttc::matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +116,7 @@ impl OnMqtt for Presence {
|
|||||||
.find('+')
|
.find('+')
|
||||||
.or(self.config.mqtt.topic.find('#'))
|
.or(self.config.mqtt.topic.find('#'))
|
||||||
.expect("Presence::create fails if it does not contain wildcards");
|
.expect("Presence::create fails if it does not contain wildcards");
|
||||||
let device_name: String = str::from_utf8(&message.topic[offset..])
|
let device_name = message.topic[offset..].into();
|
||||||
.expect("Topic should be valid")
|
|
||||||
.into();
|
|
||||||
|
|
||||||
if message.payload.is_empty() {
|
if message.payload.is_empty() {
|
||||||
// Remove the device from the map
|
// Remove the device from the map
|
||||||
|
|||||||
@@ -66,10 +66,7 @@ impl Device for WakeOnLAN {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl OnMqtt for WakeOnLAN {
|
impl OnMqtt for WakeOnLAN {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
if !rumqttc::matches(
|
if !rumqttc::matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,10 +89,7 @@ const HYSTERESIS: isize = 10;
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl OnMqtt for Washer {
|
impl OnMqtt for Washer {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
if !rumqttc::matches(
|
if !rumqttc::matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use core::str;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -17,7 +16,7 @@ use google_home::errors::ErrorCode;
|
|||||||
use google_home::traits::{Brightness, Color, ColorSetting, ColorTemperatureRange, OnOff};
|
use google_home::traits::{Brightness, Color, ColorSetting, ColorTemperatureRange, OnOff};
|
||||||
use google_home::types::Type;
|
use google_home::types::Type;
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use rumqttc::{Publish, PublishOptions, matches};
|
use rumqttc::{Publish, matches};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
@@ -178,10 +177,7 @@ where
|
|||||||
impl OnMqtt for LightOnOff {
|
impl OnMqtt for LightOnOff {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the device itself or from a remote
|
// Check if the message is from the device itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let state = match serde_json::from_slice::<StateOnOff>(&message.payload) {
|
let state = match serde_json::from_slice::<StateOnOff>(&message.payload) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -214,10 +210,7 @@ impl OnMqtt for LightOnOff {
|
|||||||
impl OnMqtt for LightBrightness {
|
impl OnMqtt for LightBrightness {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the deviec itself or from a remote
|
// Check if the message is from the deviec itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let state = match serde_json::from_slice::<StateBrightness>(&message.payload) {
|
let state = match serde_json::from_slice::<StateBrightness>(&message.payload) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -256,10 +249,7 @@ impl OnMqtt for LightBrightness {
|
|||||||
impl OnMqtt for LightColorTemperature {
|
impl OnMqtt for LightColorTemperature {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the deviec itself or from a remote
|
// Check if the message is from the deviec itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let state = match serde_json::from_slice::<StateColorTemperature>(&message.payload) {
|
let state = match serde_json::from_slice::<StateColorTemperature>(&message.payload) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -352,8 +342,9 @@ where
|
|||||||
.client
|
.client
|
||||||
.publish(
|
.publish(
|
||||||
&topic,
|
&topic,
|
||||||
|
rumqttc::QoS::AtLeastOnce,
|
||||||
|
false,
|
||||||
serde_json::to_string(&message).unwrap(),
|
serde_json::to_string(&message).unwrap(),
|
||||||
PublishOptions::at_least_once(),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
||||||
@@ -395,8 +386,9 @@ where
|
|||||||
.client
|
.client
|
||||||
.publish(
|
.publish(
|
||||||
&topic,
|
&topic,
|
||||||
|
rumqttc::QoS::AtLeastOnce,
|
||||||
|
false,
|
||||||
serde_json::to_string(&message).unwrap(),
|
serde_json::to_string(&message).unwrap(),
|
||||||
PublishOptions::at_least_once(),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
||||||
@@ -442,8 +434,9 @@ where
|
|||||||
.client
|
.client
|
||||||
.publish(
|
.publish(
|
||||||
&topic,
|
&topic,
|
||||||
|
rumqttc::QoS::AtLeastOnce,
|
||||||
|
false,
|
||||||
serde_json::to_string(&message).unwrap(),
|
serde_json::to_string(&message).unwrap(),
|
||||||
PublishOptions::at_least_once(),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use google_home::errors::ErrorCode;
|
|||||||
use google_home::traits::OnOff;
|
use google_home::traits::OnOff;
|
||||||
use google_home::types::Type;
|
use google_home::types::Type;
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use rumqttc::{Publish, PublishOptions, matches};
|
use rumqttc::{Publish, matches};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
@@ -162,10 +162,7 @@ where
|
|||||||
impl OnMqtt for OutletOnOff {
|
impl OnMqtt for OutletOnOff {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the device itself or from a remote
|
// Check if the message is from the device itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let state = match serde_json::from_slice::<StateOnOff>(&message.payload) {
|
let state = match serde_json::from_slice::<StateOnOff>(&message.payload) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -198,10 +195,7 @@ impl OnMqtt for OutletOnOff {
|
|||||||
impl OnMqtt for OutletPower {
|
impl OnMqtt for OutletPower {
|
||||||
async fn on_mqtt(&self, message: Publish) {
|
async fn on_mqtt(&self, message: Publish) {
|
||||||
// Check if the message is from the deviec itself or from a remote
|
// Check if the message is from the deviec itself or from a remote
|
||||||
if matches(
|
if matches(&message.topic, &self.config.mqtt.topic) {
|
||||||
str::from_utf8(&message.topic).expect("Topic should be valid"),
|
|
||||||
&self.config.mqtt.topic,
|
|
||||||
) {
|
|
||||||
let state = match serde_json::from_slice::<StatePower>(&message.payload) {
|
let state = match serde_json::from_slice::<StatePower>(&message.payload) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -290,8 +284,9 @@ where
|
|||||||
.client
|
.client
|
||||||
.publish(
|
.publish(
|
||||||
&topic,
|
&topic,
|
||||||
|
rumqttc::QoS::AtLeastOnce,
|
||||||
|
false,
|
||||||
serde_json::to_string(&message).unwrap(),
|
serde_json::to_string(&message).unwrap(),
|
||||||
PublishOptions::at_least_once(),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
.map_err(|err| warn!("Failed to update state on {topic}: {err}"))
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ hostname = { workspace = true }
|
|||||||
inventory = { workspace = true }
|
inventory = { workspace = true }
|
||||||
lua_typed = { workspace = true }
|
lua_typed = { workspace = true }
|
||||||
mlua = { workspace = true }
|
mlua = { workspace = true }
|
||||||
rumqttc-next = { workspace = true }
|
rumqttc = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use automation_macro::LuaDeviceConfig;
|
use automation_macro::LuaDeviceConfig;
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use mlua::FromLua;
|
use mlua::FromLua;
|
||||||
use rumqttc::{AsyncClient, Event, Incoming, MqttOptions, PublishOptions, Transport};
|
use rumqttc::{AsyncClient, Event, Incoming, MqttOptions, Transport};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
@@ -23,9 +24,9 @@ pub struct MqttConfig {
|
|||||||
|
|
||||||
impl From<MqttConfig> for MqttOptions {
|
impl From<MqttConfig> for MqttOptions {
|
||||||
fn from(value: MqttConfig) -> Self {
|
fn from(value: MqttConfig) -> Self {
|
||||||
let mut mqtt_options = MqttOptions::new(value.client_name, (value.host, value.port));
|
let mut mqtt_options = MqttOptions::new(value.client_name, value.host, value.port);
|
||||||
mqtt_options.set_credentials(value.username, value.password);
|
mqtt_options.set_credentials(value.username, value.password);
|
||||||
mqtt_options.set_keep_alive(5);
|
mqtt_options.set_keep_alive(Duration::from_secs(5));
|
||||||
|
|
||||||
if value.tls {
|
if value.tls {
|
||||||
mqtt_options.set_transport(Transport::tls_with_default_config());
|
mqtt_options.set_transport(Transport::tls_with_default_config());
|
||||||
@@ -91,7 +92,7 @@ impl mlua::UserData for WrappedAsyncClient {
|
|||||||
debug!("message = {message}");
|
debug!("message = {message}");
|
||||||
|
|
||||||
this.0
|
this.0
|
||||||
.publish(topic, message, PublishOptions::at_least_once().retained())
|
.publish(topic, rumqttc::QoS::AtLeastOnce, true, message)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ impl mlua::UserData for WrappedAsyncClient {
|
|||||||
|
|
||||||
pub fn start(config: MqttConfig, event_channel: &EventChannel) -> WrappedAsyncClient {
|
pub fn start(config: MqttConfig, event_channel: &EventChannel) -> WrappedAsyncClient {
|
||||||
let tx = event_channel.get_tx();
|
let tx = event_channel.get_tx();
|
||||||
let (client, mut eventloop) = AsyncClient::builder(config.into()).capacity(100).build();
|
let (client, mut eventloop) = AsyncClient::new(config.into(), 100);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
debug!("Listening for MQTT events");
|
debug!("Listening for MQTT events");
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ fn field_from_lua(field: &Field) -> TokenStream {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter_map(|arg| match arg {
|
.filter_map(|arg| match arg {
|
||||||
Argument::Flatten { .. } => Some(quote! {
|
Argument::Flatten { .. } => Some(quote! {
|
||||||
mlua::LuaSerdeExt::from_value_with(lua, value.clone(), mlua::serde::DeserializeOptions::new().deny_unsupported_types(false))?
|
mlua::LuaSerdeExt::from_value_with(lua, value.clone(), mlua::DeserializeOptions::new().deny_unsupported_types(false))?
|
||||||
}),
|
}),
|
||||||
Argument::FromLua { .. } => Some(quote! {
|
Argument::FromLua { .. } => Some(quote! {
|
||||||
if table.contains_key(#table_name)? {
|
if table.contains_key(#table_name)? {
|
||||||
|
|||||||
+2
-2
@@ -10,12 +10,12 @@ return {
|
|||||||
openid_url = "https://login.huizinga.dev/api/oidc",
|
openid_url = "https://login.huizinga.dev/api/oidc",
|
||||||
},
|
},
|
||||||
mqtt = {
|
mqtt = {
|
||||||
host = ((host == "zeus" or host == "hephaestus") and "olympus.huizinga.lan") or "mosquitto",
|
host = ((host == "zeus" or host == "hephaestus") and "olympus.lan.huizinga.dev") or "mosquitto",
|
||||||
port = 8883,
|
port = 8883,
|
||||||
client_name = "automation-" .. host,
|
client_name = "automation-" .. host,
|
||||||
username = "mqtt",
|
username = "mqtt",
|
||||||
password = secrets.mqtt_password,
|
password = secrets.mqtt_password,
|
||||||
tls = false,
|
tls = host == "zeus" or host == "hephaestus",
|
||||||
},
|
},
|
||||||
modules = {
|
modules = {
|
||||||
require("config.battery"),
|
require("config.battery"),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ function module.setup(mqtt_client)
|
|||||||
local light = nil
|
local light = nil
|
||||||
|
|
||||||
local bambu = devices.Bambu.new({
|
local bambu = devices.Bambu.new({
|
||||||
host = "10.0.0.108",
|
host = "thalia.huizinga.lan",
|
||||||
device_id = secrets.printer_device_id,
|
device_id = secrets.printer_device_id,
|
||||||
access_code = secrets.printer_access_code,
|
access_code = secrets.printer_access_code,
|
||||||
callbacks = {
|
callbacks = {
|
||||||
|
|||||||
Reference in New Issue
Block a user