Compare commits
4 Commits
14d51c0df6
...
d2d473c137
| Author | SHA1 | Date | |
|---|---|---|---|
|
d2d473c137
|
|||
|
a0ed373971
|
|||
|
5e13dff2b5
|
|||
|
ba818c6b60
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -99,6 +99,7 @@ dependencies = [
|
||||
"git-version",
|
||||
"google_home",
|
||||
"inventory",
|
||||
"lua_typed",
|
||||
"mlua",
|
||||
"reqwest",
|
||||
"rumqttc",
|
||||
|
||||
@@ -77,6 +77,7 @@ config = { version = "0.15.15", default-features = false, features = [
|
||||
] }
|
||||
git-version = "0.3.9"
|
||||
google_home = { workspace = true }
|
||||
lua_typed = { workspace = true }
|
||||
inventory = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::time::Duration;
|
||||
|
||||
use lua_typed::Typed;
|
||||
@@ -30,29 +29,6 @@ impl From<MqttConfig> for MqttOptions {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FulfillmentConfig {
|
||||
pub openid_url: String,
|
||||
#[serde(default = "default_fulfillment_ip")]
|
||||
pub ip: Ipv4Addr,
|
||||
#[serde(default = "default_fulfillment_port")]
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl From<FulfillmentConfig> for SocketAddr {
|
||||
fn from(fulfillment: FulfillmentConfig) -> Self {
|
||||
(fulfillment.ip, fulfillment.port).into()
|
||||
}
|
||||
}
|
||||
|
||||
fn default_fulfillment_ip() -> Ipv4Addr {
|
||||
[0, 0, 0, 0].into()
|
||||
}
|
||||
|
||||
fn default_fulfillment_port() -> u16 {
|
||||
7878
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Typed)]
|
||||
pub struct InfoConfig {
|
||||
pub name: String,
|
||||
|
||||
11
config.lua
11
config.lua
@@ -21,10 +21,6 @@ local function mqtt_automation(topic)
|
||||
return "automation/" .. topic
|
||||
end
|
||||
|
||||
local fulfillment = {
|
||||
openid_url = "https://login.huizinga.dev/api/oidc",
|
||||
}
|
||||
|
||||
local mqtt_client = require("automation:mqtt").new(device_manager, {
|
||||
host = ((host == "zeus" or host == "hephaestus") and "olympus.lan.huizinga.dev") or "mosquitto",
|
||||
port = 8883,
|
||||
@@ -748,4 +744,9 @@ device_manager:schedule("0 0 20 * * *", function()
|
||||
bedroom_air_filter:set_on(false)
|
||||
end)
|
||||
|
||||
return fulfillment
|
||||
---@type Config
|
||||
return {
|
||||
fulfillment = {
|
||||
openid_url = "https://login.huizinga.dev/api/oidc",
|
||||
},
|
||||
}
|
||||
|
||||
12
definitions/config.lua
Normal file
12
definitions/config.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
-- DO NOT MODIFY, FILE IS AUTOMATICALLY GENERATED
|
||||
---@meta
|
||||
|
||||
---@class FulfillmentConfig
|
||||
---@field openid_url string
|
||||
---@field ip string?
|
||||
---@field port integer?
|
||||
local FulfillmentConfig
|
||||
|
||||
---@class Config
|
||||
---@field fulfillment FulfillmentConfig
|
||||
local Config
|
||||
@@ -1,29 +1,23 @@
|
||||
#![feature(iter_intersperse)]
|
||||
mod config;
|
||||
mod secret;
|
||||
mod version;
|
||||
mod web;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
use ::config::{Environment, File};
|
||||
use automation_lib::config::FulfillmentConfig;
|
||||
use automation::config::{Config, Setup};
|
||||
use automation::secret::EnvironmentSecretFile;
|
||||
use automation::version::VERSION;
|
||||
use automation::web::{ApiError, User};
|
||||
use automation_lib::device_manager::DeviceManager;
|
||||
use axum::extract::{FromRef, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::routing::post;
|
||||
use axum::{Json, Router};
|
||||
use config::Config;
|
||||
use google_home::{GoogleHome, Request, Response};
|
||||
use mlua::LuaSerdeExt;
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use web::{ApiError, User};
|
||||
|
||||
use crate::secret::EnvironmentSecretFile;
|
||||
use crate::version::VERSION;
|
||||
|
||||
// Force automation_devices to link so that it gets registered as a module
|
||||
extern crate automation_devices;
|
||||
@@ -76,7 +70,7 @@ async fn app() -> anyhow::Result<()> {
|
||||
|
||||
info!(version = VERSION, "automation_rs");
|
||||
|
||||
let config: Config = ::config::Config::builder()
|
||||
let setup: Setup = ::config::Config::builder()
|
||||
.add_source(
|
||||
File::with_name(&format!("{}.toml", std::env!("CARGO_PKG_NAME"))).required(false),
|
||||
)
|
||||
@@ -138,12 +132,12 @@ async fn app() -> anyhow::Result<()> {
|
||||
|
||||
lua.register_module("automation:device_manager", device_manager.clone())?;
|
||||
|
||||
lua.register_module("automation:variables", lua.to_value(&config.variables)?)?;
|
||||
lua.register_module("automation:secrets", lua.to_value(&config.secrets)?)?;
|
||||
lua.register_module("automation:variables", lua.to_value(&setup.variables)?)?;
|
||||
lua.register_module("automation:secrets", lua.to_value(&setup.secrets)?)?;
|
||||
|
||||
let entrypoint = Path::new(&config.entrypoint);
|
||||
let fulfillment_config: mlua::Value = lua.load(entrypoint).eval_async().await?;
|
||||
let fulfillment_config: FulfillmentConfig = lua.from_value(fulfillment_config)?;
|
||||
let entrypoint = Path::new(&setup.entrypoint);
|
||||
let config: mlua::Value = lua.load(entrypoint).eval_async().await?;
|
||||
let config: Config = lua.from_value(config)?;
|
||||
|
||||
// Create google home fulfillment route
|
||||
let fulfillment = Router::new().route("/google_home", post(fulfillment));
|
||||
@@ -152,12 +146,12 @@ async fn app() -> anyhow::Result<()> {
|
||||
let app = Router::new()
|
||||
.nest("/fulfillment", fulfillment)
|
||||
.with_state(AppState {
|
||||
openid_url: fulfillment_config.openid_url.clone(),
|
||||
openid_url: config.fulfillment.openid_url.clone(),
|
||||
device_manager,
|
||||
});
|
||||
|
||||
// Start the web server
|
||||
let addr: SocketAddr = fulfillment_config.into();
|
||||
let addr: SocketAddr = config.fulfillment.into();
|
||||
info!("Server started on http://{addr}");
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
axum::serve(listener, app).await?;
|
||||
@@ -1,32 +1,57 @@
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
|
||||
use automation::config::{Config, FulfillmentConfig};
|
||||
use automation_lib::Module;
|
||||
use lua_typed::Typed;
|
||||
use tracing::{info, warn};
|
||||
|
||||
extern crate automation_devices;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
fn write_definitions(filename: &str, definitions: &str) -> std::io::Result<()> {
|
||||
let definitions_directory =
|
||||
std::path::Path::new(std::env!("CARGO_MANIFEST_DIR")).join("definitions");
|
||||
fs::create_dir_all(&definitions_directory)?;
|
||||
|
||||
let mut file = File::create(definitions_directory.join(filename))?;
|
||||
|
||||
file.write_all(b"-- DO NOT MODIFY, FILE IS AUTOMATICALLY GENERATED\n")?;
|
||||
file.write_all(definitions.as_bytes())?;
|
||||
|
||||
// Make sure we have a trailing new line
|
||||
if !definitions.ends_with("\n") {
|
||||
file.write_all(b"\n")?;
|
||||
}
|
||||
|
||||
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("FulfillmentConfig should have a definition");
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
for module in inventory::iter::<Module> {
|
||||
if let Some(definitions) = module.definitions() {
|
||||
info!(name = module.get_name(), "Generating definitions");
|
||||
|
||||
let filename = format!("{}.lua", module.get_name());
|
||||
let mut file = File::create(definitions_directory.join(filename))?;
|
||||
|
||||
file.write_all(b"-- DO NOT MODIFY, FILE IS AUTOMATICALLY GENERATED\n")?;
|
||||
file.write_all(definitions.as_bytes())?;
|
||||
file.write_all(b"\n")?;
|
||||
write_definitions(&filename, &definitions)?;
|
||||
} else {
|
||||
warn!(name = module.get_name(), "No definitions");
|
||||
}
|
||||
}
|
||||
|
||||
write_definitions("config.lua", &config_definitions())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
|
||||
use lua_typed::Typed;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Config {
|
||||
pub struct Setup {
|
||||
#[serde(default = "default_entrypoint")]
|
||||
pub entrypoint: String,
|
||||
#[serde(default)]
|
||||
@@ -15,3 +17,32 @@ pub struct Config {
|
||||
fn default_entrypoint() -> String {
|
||||
"./config.lua".into()
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Typed)]
|
||||
pub struct FulfillmentConfig {
|
||||
pub openid_url: String,
|
||||
#[serde(default = "default_fulfillment_ip")]
|
||||
#[typed(default)]
|
||||
pub ip: Ipv4Addr,
|
||||
#[serde(default = "default_fulfillment_port")]
|
||||
#[typed(default)]
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Typed)]
|
||||
pub struct Config {
|
||||
pub fulfillment: FulfillmentConfig,
|
||||
}
|
||||
|
||||
impl From<FulfillmentConfig> for SocketAddr {
|
||||
fn from(fulfillment: FulfillmentConfig) -> Self {
|
||||
(fulfillment.ip, fulfillment.port).into()
|
||||
}
|
||||
}
|
||||
fn default_fulfillment_ip() -> Ipv4Addr {
|
||||
[0, 0, 0, 0].into()
|
||||
}
|
||||
|
||||
fn default_fulfillment_port() -> u16 {
|
||||
7878
|
||||
}
|
||||
|
||||
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod config;
|
||||
pub mod secret;
|
||||
pub mod version;
|
||||
pub mod web;
|
||||
Reference in New Issue
Block a user