Compare commits

2 Commits

Author SHA1 Message Date
Dreaded_X 3f59f10cd1 fix: Chef cook uses wrong toolchain
Build and deploy / build (push) Failing after 1m2s
Build and deploy / Deploy container (push) Has been skipped
This adds a toolchain setup step to the base image so we do not have to
do it multiple times
2025-11-17 05:10:36 +01:00
Dreaded_X b87f27f149 chore: Upgraded to new workflow 2025-11-17 05:10:36 +01:00
14 changed files with 638 additions and 1041 deletions
+2 -6
View File
@@ -9,7 +9,7 @@ on:
jobs: jobs:
build: build:
uses: dreaded_x/workflows/.gitea/workflows/docker-kubernetes.yaml@ef78704b98c72e4a6b8340f9bff7b085a7bdd95c uses: dreaded_x/workflows/.gitea/workflows/docker-kubernetes.yaml@c50a935d1f1745f8c2775e828e57fc486048188c
secrets: inherit secrets: inherit
with: with:
push_manifests: false push_manifests: false
@@ -26,10 +26,6 @@ jobs:
docker stop automation_rs || true docker stop automation_rs || true
docker rm automation_rs || true docker rm automation_rs || true
- name: Login to registry
run: |
docker login git.huizinga.dev -u ${{ gitea.actor }} -p ${{ secrets.REGISTRY_TOKEN }} \
- name: Create container - name: Create container
run: | run: |
docker create \ docker create \
@@ -41,7 +37,7 @@ jobs:
-e AUTOMATION__SECRETS__MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }} \ -e AUTOMATION__SECRETS__MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }} \
-e AUTOMATION__SECRETS__HUE_TOKEN=${{ secrets.HUE_TOKEN }} \ -e AUTOMATION__SECRETS__HUE_TOKEN=${{ secrets.HUE_TOKEN }} \
-e AUTOMATION__SECRETS__NTFY_TOPIC=${{ secrets.NTFY_TOPIC }} \ -e AUTOMATION__SECRETS__NTFY_TOPIC=${{ secrets.NTFY_TOPIC }} \
$(echo ${{ toJSON(needs.build.outputs.images) }} | jq .automation -r) git.huizinga.dev/dreaded_x/automation_rs@${{ needs.build.outputs.digest }}
docker network connect web automation_rs docker network connect web automation_rs
Generated
+575 -908
View File
File diff suppressed because it is too large Load Diff
+21 -21
View File
@@ -16,28 +16,28 @@ members = [
[workspace.dependencies] [workspace.dependencies]
air_filter_types = { git = "https://git.huizinga.dev/Dreaded_X/airfilter", tag = "v0.4.4" } air_filter_types = { git = "https://git.huizinga.dev/Dreaded_X/airfilter", tag = "v0.4.4" }
anyhow = "1.0.102" anyhow = "1.0.99"
async-trait = "0.1.89" async-trait = "0.1.89"
automation_cast = { path = "./automation_cast" } automation_cast = { path = "./automation_cast" }
automation_devices = { path = "./automation_devices" } automation_devices = { path = "./automation_devices" }
automation_lib = { path = "./automation_lib" } automation_lib = { path = "./automation_lib" }
automation_macro = { path = "./automation_macro" } automation_macro = { path = "./automation_macro" }
axum = "0.8.9" axum = "0.8.4"
bytes = "1.11.1" bytes = "1.10.1"
dyn-clone = "1.0.20" dyn-clone = "1.0.20"
eui48 = { version = "1.1.0", features = [ eui48 = { version = "1.1.0", features = [
"disp_hexstring", "disp_hexstring",
"serde", "serde",
], default-features = false } ], default-features = false }
futures = "0.3.32" futures = "0.3.31"
google_home = { path = "./google_home/google_home" } 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.1"
inventory = "0.3.24" inventory = "0.3.21"
itertools = "0.14.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.11.6", features = [ mlua = { version = "0.11.3", features = [
"lua54", "lua54",
"vendored", "vendored",
"macros", "macros",
@@ -45,23 +45,23 @@ mlua = { version = "0.11.6", features = [
"async", "async",
"send", "send",
] } ] }
proc-macro2 = "1.0.106" proc-macro2 = "1.0.101"
quote = "1.0.45" quote = "1.0.40"
reqwest = { version = "0.13.3", features = [ reqwest = { version = "0.12.23", features = [
"json", "json",
"rustls", "rustls-tls",
], 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 = "0.25.1" rumqttc = "0.24.0"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.149" serde_json = "1.0.143"
serde_repr = "0.1.20" serde_repr = "0.1.20"
syn = { version = "2.0.117" } syn = { version = "2.0.106" }
thiserror = "2.0.18" thiserror = "2.0.16"
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.0"
tracing = "0.1.44" tracing = "0.1.41"
tracing-subscriber = "0.3.23" tracing-subscriber = "0.3.20"
wakey = "0.4.1" wakey = "0.3.0"
[dependencies] [dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
@@ -70,7 +70,7 @@ automation_devices = { workspace = true }
automation_lib = { workspace = true } automation_lib = { workspace = true }
automation_macro = { path = "./automation_macro" } automation_macro = { path = "./automation_macro" }
axum = { workspace = true } axum = { workspace = true }
config = { version = "0.15.22", default-features = false, features = [ config = { version = "0.15.15", default-features = false, features = [
"async", "async",
"toml", "toml",
] } ] }
+3 -2
View File
@@ -1,8 +1,9 @@
FROM rust:1.95 AS base FROM rust:1.89 AS base
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
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
COPY ./rust-toolchain.toml .
RUN rustup toolchain install RUN rustup toolchain install
FROM base AS planner FROM base AS planner
@@ -20,7 +21,7 @@ ARG RELEASE_VERSION
ENV RELEASE_VERSION=${RELEASE_VERSION} ENV RELEASE_VERSION=${RELEASE_VERSION}
RUN cargo auditable build --release RUN cargo auditable build --release
FROM gcr.io/distroless/cc-debian13:nonroot AS runtime FROM gcr.io/distroless/cc-debian12:nonroot 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;;"
+2 -2
View File
@@ -4,9 +4,9 @@ Custom home automation solution with Google Home integration and lua scripting.
## Development ## Development
This repository uses [prek](https://prek.j178.dev/) to make sure everything is ready to go when committing. This repository uses [pre-commit](https://pre-commit.com) to make sure everything is ready to go when committing.
Install the pre-commit hooks by running the following command: Install the pre-commit hooks by running the following command:
```bash ```bash
prek install pre-commit install
``` ```
-47
View File
@@ -2,7 +2,6 @@ use std::net::SocketAddr;
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use automation_lib::lua::traits::PartialUserData;
use automation_macro::{Device, LuaDeviceConfig}; use automation_macro::{Device, LuaDeviceConfig};
use google_home::errors::ErrorCode; use google_home::errors::ErrorCode;
use google_home::traits::OnOff; use google_home::traits::OnOff;
@@ -26,7 +25,6 @@ crate::register_type!(Config);
#[derive(Debug, Clone, Device)] #[derive(Debug, Clone, Device)]
#[device(traits(OnOff))] #[device(traits(OnOff))]
#[device(extra_user_data = AllOn)]
pub struct HueGroup { pub struct HueGroup {
config: Config, config: Config,
} }
@@ -124,47 +122,6 @@ impl OnOff for HueGroup {
} }
} }
struct AllOn;
impl PartialUserData<HueGroup> for AllOn {
fn add_methods<M: mlua::UserDataMethods<HueGroup>>(methods: &mut M) {
methods.add_async_method("all_on", async |_lua, this, ()| {
let res = reqwest::Client::new()
.get(this.url_get_state())
.send()
.await;
match res {
Ok(res) => {
let status = res.status();
if !status.is_success() {
warn!(id = this.get_id(), "Status code is not success: {status}");
}
let on = match res.json::<message::Info>().await {
Ok(info) => info.all_on(),
Err(err) => {
error!(id = this.get_id(), "Failed to parse message: {err}");
return Ok(false);
}
};
return Ok(on);
}
Err(err) => error!(id = this.get_id(), "Error: {err}"),
}
Ok(false)
});
}
fn definitions() -> Option<String> {
Some(format!(
"---@async\n---@return boolean\nfunction {}:all_on() end\n",
<HueGroup as Typed>::type_name(),
))
}
}
mod message { mod message {
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -207,9 +164,5 @@ mod message {
pub fn any_on(&self) -> bool { pub fn any_on(&self) -> bool {
self.state.any_on self.state.any_on
} }
pub fn all_on(&self) -> bool {
self.state.all_on
}
} }
} }
+8 -4
View File
@@ -122,11 +122,15 @@ impl OnMqtt for HueSwitch {
Action::LeftHold => self.config.left_hold_callback.call(self.clone()).await, Action::LeftHold => self.config.left_hold_callback.call(self.clone()).await,
Action::RightHold => self.config.right_hold_callback.call(self.clone()).await, Action::RightHold => self.config.right_hold_callback.call(self.clone()).await,
// If there is no hold action, the switch will act like a normal release // If there is no hold action, the switch will act like a normal release
Action::RightHoldRelease if self.config.right_hold_callback.is_empty() => { Action::RightHoldRelease => {
self.config.right_callback.call(self.clone()).await if self.config.right_hold_callback.is_empty() {
self.config.right_callback.call(self.clone()).await
}
} }
Action::LeftHoldRelease if self.config.left_hold_callback.is_empty() => { Action::LeftHoldRelease => {
self.config.left_callback.call(self.clone()).await if self.config.left_hold_callback.is_empty() {
self.config.left_callback.call(self.clone()).await
}
} }
_ => {} _ => {}
} }
+1
View File
@@ -1,3 +1,4 @@
#![feature(iter_intersperse)]
#![feature(iterator_try_collect)] #![feature(iterator_try_collect)]
mod device; mod device;
mod lua_device_config; mod lua_device_config;
+1 -32
View File
@@ -25,13 +25,6 @@ function module.setup(mqtt_client)
group_id = 3, group_id = 3,
scene_id = "60tfTyR168v2csz", scene_id = "60tfTyR168v2csz",
}) })
local wardrobe_light = devices.HueGroup.new({
identifier = "bedroom_lights_wardrobe",
ip = hue_bridge.ip,
login = hue_bridge.token,
group_id = 3,
scene_id = "1IDvpsN2YLZsDV95",
})
air_filter = devices.AirFilter.new({ air_filter = devices.AirFilter.new({
name = "Air Filter", name = "Air Filter",
@@ -39,36 +32,13 @@ function module.setup(mqtt_client)
url = "http://10.0.0.103", url = "http://10.0.0.103",
}) })
local wardrobe_door = devices.ContactSensor.new({
name = "Wardrobe Door",
room = "Bedroom",
sensor_type = "Door",
topic = helper.mqtt_z2m("bedroom/wardrobe_door"),
client = mqtt_client,
callback = function(_, open)
-- Technically this has an edge case where if one of the spots is
-- on, but that is not something I ever do
if not lights:all_on() then
wardrobe_light:set_on(open)
end
end,
battery_callback = battery.callback,
})
local switch = devices.HueSwitch.new({ local switch = devices.HueSwitch.new({
name = "Switch", name = "Switch",
room = "Bedroom", room = "Bedroom",
client = mqtt_client, client = mqtt_client,
topic = helper.mqtt_z2m("bedroom/switch"), topic = helper.mqtt_z2m("bedroom/switch"),
left_callback = function() left_callback = function()
local on = not lights:all_on() lights:set_on(not lights:on())
lights:set_on(on)
-- This is a bit janky as the light will start to dim before turning
-- back on, however this is really and edge case that probably won't
-- happen often, so for now it's fine
if not on and wardrobe_door:open_percent() == 100 then
wardrobe_light:set_on(true)
end
end, end,
left_hold_callback = function() left_hold_callback = function()
lights_relax:set_on(true) lights_relax:set_on(true)
@@ -91,7 +61,6 @@ function module.setup(mqtt_client)
lights, lights,
lights_relax, lights_relax,
air_filter, air_filter,
wardrobe_door,
switch, switch,
window, window,
}, },
-8
View File
@@ -25,18 +25,10 @@ function module.setup(mqtt_client)
}) })
windows.add(window) windows.add(window)
local printer = devices.OutletOnOff.new({
name = "3D Printer",
room = "Guest Room",
topic = helper.mqtt_z2m("guest/printer"),
client = mqtt_client,
})
--- @type Module --- @type Module
return { return {
light, light,
window, window,
printer,
} }
end end
-3
View File
@@ -116,9 +116,6 @@ devices.HueGroup = {}
---@param config HueGroupConfig ---@param config HueGroupConfig
---@return HueGroup ---@return HueGroup
function devices.HueGroup.new(config) end function devices.HueGroup.new(config) end
---@async
---@return boolean
function HueGroup:all_on() end
---@class HueGroupConfig ---@class HueGroupConfig
---@field identifier string ---@field identifier string
+22 -7
View File
@@ -2,17 +2,32 @@ variable "TAG_BASE" {}
variable "RELEASE_VERSION" {} variable "RELEASE_VERSION" {}
group "default" { group "default" {
targets = ["automation"] targets = ["automation"]
} }
target "docker-metadata-action" {} target "docker-metadata-action" {}
target "automation" { # TODO: Auto include this from the workflow
inherits = ["docker-metadata-action"] target "common" {
context = "./" cache-from = [
dockerfile = "Dockerfile" {
tags = [for tag in target.docker-metadata-action.tags : "${TAG_BASE}:${tag}"] type = "gha"
}
]
cache-to = [
{
type = "gha"
mode = "max"
}
]
args = { args = {
RELEASE_VERSION="${RELEASE_VERSION}" RELEASE_VERSION = "${RELEASE_VERSION}"
} }
} }
target "automation" {
inherits = ["docker-metadata-action", "common"]
context = "./"
dockerfile = "Dockerfile"
tags = [for tag in target.docker-metadata-action.tags : "${TAG_BASE}:${tag}"]
}
+1 -1
View File
@@ -1,4 +1,4 @@
[toolchain] [toolchain]
channel = "nightly-2026-05-12" channel = "nightly-2025-08-20"
components = ["rustfmt", "clippy", "rust-analyzer"] components = ["rustfmt", "clippy", "rust-analyzer"]
profile = "minimal" profile = "minimal"
+2
View File
@@ -1,3 +1,5 @@
#![feature(if_let_guard)]
pub mod config; pub mod config;
pub mod schedule; pub mod schedule;
pub mod secret; pub mod secret;