Compare commits
7 Commits
5947098bfb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
8c6adae3ae
|
|||
|
2158bde1c2
|
|||
|
b547f66d86
|
|||
|
f3de8e36ea
|
|||
|
44f2c57819
|
|||
|
ad158f2c22
|
|||
|
f36adf2f19
|
@@ -9,10 +9,10 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
uses: dreaded_x/workflows/.gitea/workflows/rust-kubernetes.yaml@22ee0c1788a8d2157db87d6a6f8dbe520fe48592
|
uses: dreaded_x/workflows/.gitea/workflows/docker-kubernetes.yaml@ef78704b98c72e4a6b8340f9bff7b085a7bdd95c
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
upload_manifests: false
|
push_manifests: false
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy container
|
name: Deploy container
|
||||||
@@ -37,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 }} \
|
||||||
git.huizinga.dev/dreaded_x/automation_rs@${{ needs.build.outputs.digest }}
|
$(echo ${{ toJSON(needs.build.outputs.images) }} | jq .automation -r)
|
||||||
|
|
||||||
docker network connect web automation_rs
|
docker network connect web automation_rs
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ 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
|
||||||
|
|
||||||
FROM base AS planner
|
FROM base AS planner
|
||||||
COPY . .
|
COPY . .
|
||||||
@@ -21,5 +23,7 @@ RUN cargo auditable build --release
|
|||||||
|
|
||||||
FROM gcr.io/distroless/cc-debian12: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 LUA_PATH="/app/?.lua;;"
|
||||||
COPY ./config /app/config
|
COPY ./config /app/config
|
||||||
CMD [ "/app/automation" ]
|
CMD [ "/app/automation" ]
|
||||||
|
|||||||
@@ -25,10 +25,18 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -59,26 +59,21 @@ function module.setup(mqtt_client)
|
|||||||
})
|
})
|
||||||
hallway_automation.set_trash(trash)
|
hallway_automation.set_trash(trash)
|
||||||
|
|
||||||
---@param duration number
|
local timeout = utils.Timeout.new()
|
||||||
---@return fun(_, open: boolean)
|
local function frontdoor_presence(_, open)
|
||||||
local function frontdoor_presence(duration)
|
if open then
|
||||||
local timeout = utils.Timeout.new()
|
timeout:cancel()
|
||||||
|
|
||||||
return function(_, open)
|
if not presence.overall_presence() then
|
||||||
if open then
|
mqtt_client:send_message(helper.mqtt_automation("presence/contact/frontdoor"), {
|
||||||
timeout:cancel()
|
state = true,
|
||||||
|
updated = utils.get_epoch(),
|
||||||
if presence.overall_presence() then
|
})
|
||||||
mqtt_client:send_message(helper.mqtt_automation("presence/contact/frontdoor"), {
|
|
||||||
state = true,
|
|
||||||
updated = utils.get_epoch(),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
else
|
|
||||||
timeout:start(duration, function()
|
|
||||||
mqtt_client:send_message(helper.mqtt_automation("presence/contact/frontdoor"), nil)
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
timeout:start(debug.debug_mode and 10 or 15 * 60, function()
|
||||||
|
mqtt_client:send_message(helper.mqtt_automation("presence/contact/frontdoor"), nil)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -89,7 +84,7 @@ function module.setup(mqtt_client)
|
|||||||
topic = helper.mqtt_z2m("hallway/frontdoor"),
|
topic = helper.mqtt_z2m("hallway/frontdoor"),
|
||||||
client = mqtt_client,
|
client = mqtt_client,
|
||||||
callback = {
|
callback = {
|
||||||
frontdoor_presence(debug.debug_mode and 10 or 15 * 60),
|
frontdoor_presence,
|
||||||
hallway_automation.door_callback,
|
hallway_automation.door_callback,
|
||||||
},
|
},
|
||||||
battery_callback = battery.callback,
|
battery_callback = battery.callback,
|
||||||
|
|||||||
18
docker-bake.hcl
Normal file
18
docker-bake.hcl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
variable "TAG_BASE" {}
|
||||||
|
variable "RELEASE_VERSION" {}
|
||||||
|
|
||||||
|
group "default" {
|
||||||
|
targets = ["automation"]
|
||||||
|
}
|
||||||
|
|
||||||
|
target "docker-metadata-action" {}
|
||||||
|
|
||||||
|
target "automation" {
|
||||||
|
inherits = ["docker-metadata-action"]
|
||||||
|
context = "./"
|
||||||
|
dockerfile = "Dockerfile"
|
||||||
|
tags = [for tag in target.docker-metadata-action.tags : "${TAG_BASE}:${tag}"]
|
||||||
|
args = {
|
||||||
|
RELEASE_VERSION="${RELEASE_VERSION}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,8 @@
|
|||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use automation::config::{
|
use automation::config::generate_definitions;
|
||||||
Config, FulfillmentConfig, Module as ConfigModule, Schedule, SetupFunction,
|
|
||||||
};
|
|
||||||
use automation_lib::Module;
|
use automation_lib::Module;
|
||||||
use automation_lib::mqtt::{MqttConfig, WrappedAsyncClient};
|
|
||||||
use lua_typed::Typed;
|
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
extern crate automation_devices;
|
extern crate automation_devices;
|
||||||
@@ -29,28 +25,6 @@ fn write_definitions(filename: &str, definitions: &str) -> std::io::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_definitions() -> String {
|
|
||||||
let mut output = "---@meta\n\n".to_string();
|
|
||||||
|
|
||||||
output +=
|
|
||||||
&FulfillmentConfig::generate_full().expect("FulfillmentConfig should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &Config::generate_full().expect("Config should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &SetupFunction::generate_full().expect("SetupFunction should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &Schedule::generate_full().expect("Schedule should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &ConfigModule::generate_full().expect("Module should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &MqttConfig::generate_full().expect("MqttConfig should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output +=
|
|
||||||
&WrappedAsyncClient::generate_full().expect("WrappedAsyncClient should have a definition");
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
@@ -65,7 +39,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_definitions("config.lua", &config_definitions())?;
|
write_definitions("config.lua", &generate_definitions())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use automation_lib::action_callback::ActionCallback;
|
use automation_lib::action_callback::ActionCallback;
|
||||||
use automation_lib::device::Device;
|
use automation_lib::device::Device;
|
||||||
@@ -37,7 +38,7 @@ pub struct FulfillmentConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SetupFunction(mlua::Function);
|
struct SetupFunction(mlua::Function);
|
||||||
|
|
||||||
impl Typed for SetupFunction {
|
impl Typed for SetupFunction {
|
||||||
fn type_name() -> String {
|
fn type_name() -> String {
|
||||||
@@ -60,8 +61,16 @@ impl FromLua for SetupFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for SetupFunction {
|
||||||
|
type Target = mlua::Function;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Schedule(HashMap<String, ActionCallback<()>>);
|
struct Schedule(HashMap<String, ActionCallback<()>>);
|
||||||
|
|
||||||
impl Typed for Schedule {
|
impl Typed for Schedule {
|
||||||
fn type_name() -> String {
|
fn type_name() -> String {
|
||||||
@@ -83,12 +92,22 @@ impl FromLua for Schedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for Schedule {
|
||||||
|
type Item = <HashMap<String, ActionCallback<()>> as IntoIterator>::Item;
|
||||||
|
|
||||||
|
type IntoIter = <HashMap<String, ActionCallback<()>> as IntoIterator>::IntoIter;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Module {
|
struct Module {
|
||||||
pub setup: Option<SetupFunction>,
|
setup: Option<SetupFunction>,
|
||||||
pub devices: Vec<Box<dyn Device>>,
|
devices: Vec<Box<dyn Device>>,
|
||||||
pub schedule: Schedule,
|
schedule: Schedule,
|
||||||
pub modules: Vec<Module>,
|
modules: Vec<Module>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add option to typed to rename field
|
// TODO: Add option to typed to rename field
|
||||||
@@ -189,7 +208,7 @@ impl Modules {
|
|||||||
modules.extend(module.modules);
|
modules.extend(module.modules);
|
||||||
|
|
||||||
if let Some(setup) = module.setup {
|
if let Some(setup) = module.setup {
|
||||||
let result: mlua::Value = setup.0.call_async(client.clone()).await?;
|
let result: mlua::Value = setup.call_async(client.clone()).await?;
|
||||||
|
|
||||||
if result.is_nil() {
|
if result.is_nil() {
|
||||||
// We ignore nil results
|
// We ignore nil results
|
||||||
@@ -209,7 +228,7 @@ impl Modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
devices.extend(module.devices);
|
devices.extend(module.devices);
|
||||||
for (cron, f) in module.schedule.0 {
|
for (cron, f) in module.schedule {
|
||||||
scheduler.add_job(cron, f);
|
scheduler.add_job(cron, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,3 +264,25 @@ fn default_fulfillment_ip() -> Ipv4Addr {
|
|||||||
fn default_fulfillment_port() -> u16 {
|
fn default_fulfillment_port() -> u16 {
|
||||||
7878
|
7878
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_definitions() -> String {
|
||||||
|
let mut output = "---@meta\n\n".to_string();
|
||||||
|
|
||||||
|
output +=
|
||||||
|
&FulfillmentConfig::generate_full().expect("FulfillmentConfig should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &Config::generate_full().expect("Config should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &SetupFunction::generate_full().expect("SetupFunction should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &Schedule::generate_full().expect("Schedule should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &Module::generate_full().expect("Module should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &MqttConfig::generate_full().expect("MqttConfig should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output +=
|
||||||
|
&WrappedAsyncClient::generate_full().expect("WrappedAsyncClient should have a definition");
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user