Compare commits

...

2 Commits

Author SHA1 Message Date
Sam W 3065040189 Update and format config example
Also add dhall-json for testing json/yaml conversion
2022-07-11 14:07:39 +00:00
Sam W 7b2a92012b Streamline configuration
Fixes triggermulti deserialization
Add 'generate-dhall' argument, which generates dhall for the config
enums.
2022-07-11 14:03:13 +00:00
8 changed files with 162 additions and 29 deletions

52
Cargo.lock generated
View File

@ -160,6 +160,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "concurrent-queue"
version = "1.2.2"
@ -667,7 +680,7 @@ checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
@ -700,6 +713,25 @@ dependencies = [
"version_check",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
@ -1019,6 +1051,7 @@ name = "sampad"
version = "0.1.0"
dependencies = [
"bitvec",
"chrono",
"hidapi",
"rumqttc",
"serde",
@ -1270,6 +1303,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1510,6 +1554,12 @@ dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

View File

@ -11,3 +11,4 @@ serde = "1"
serde_dhall = "0.11"
tracing = "0.1.35"
tracing-subscriber = "0.3.14"
chrono = "0.4.19"

13
build.rs Normal file
View File

@ -0,0 +1,13 @@
use std::error::Error;
use std::process::Command;
fn main() -> Result<(), Box<dyn Error>> {
let hash = Command::new("git")
.arg("rev-parse")
.arg("--short")
.arg("HEAD")
.output()?
.stdout;
println!("cargo:rustc-env=VERSION={}", std::str::from_utf8(&hash)?);
Ok(())
}

View File

@ -1,16 +1,26 @@
{ mqtt_servers.default = { host = "1.2.3.4", user = Some "username", pass = Some
"password" }
, layers.default
=
{ default_mapping = Mapping.Print "no mapping!"
, mappings =
let sometopic = "homeassistant/switch/something/set"
let T = ./types.dhall
in { key_0 =
Mapping.Trigger (Action.MQTTPub { topic = sometopic, payload = "ON" })
, key_1 =
Mapping.Trigger
(Action.MQTTPub { topic = sometopic, payload = "OFF" })
}
}
}
in { mqtt_servers.default
=
{ host = "1.2.3.4", user = Some "username", pass = Some "password" }
, layers.default
=
{ default_mapping = T.Action.Print "no mapping!"
, mappings =
let sometopic = "homeassistant/switch/something/set"
in { key_0 =
T.Mapping.Trigger
(T.Action.MQTTPub { topic = sometopic, payload = "ON" })
, key_1 =
T.Mapping.Trigger
(T.Action.MQTTPub { topic = sometopic, payload = "OFF" })
, key_2 =
T.Mapping.TriggerMulti
[ T.Action.Print "Doing a thing"
, T.Action.MQTTPub
{ topic = "thing/foo/bar", payload = "boop" }
]
}
}
}

View File

@ -34,6 +34,7 @@
buildInputs = with pkgs; [
# Dhall (config) stuff
dhall
dhall-json
dhall-lsp-server
# Rust!
(rust-bin.stable.latest.default.override {

View File

@ -1,5 +1,7 @@
use crate::StdError;
use chrono::Utc;
use serde::Deserialize;
use serde_dhall::StaticType;
use serde_dhall::{SimpleType, StaticType};
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
@ -24,7 +26,11 @@ impl fmt::Display for Action {
}
}
#[derive(Deserialize, StaticType, Debug)]
// Newtype wrapper around a Vec of actions.
// serde(transparent) and the imp StaticType below ensures we ignore the outer struct and
// transparently deserialize into the inner vec.
#[derive(Deserialize, Debug)]
#[serde(transparent)]
pub struct Actions(Vec<Action>);
impl Actions {
@ -40,6 +46,12 @@ impl fmt::Display for Actions {
}
}
impl StaticType for Actions {
fn static_type() -> SimpleType {
SimpleType::List(Box::new(Action::static_type()))
}
}
#[derive(Deserialize, StaticType, Debug)]
pub enum Mapping {
NOP, // Do nothing.
@ -87,16 +99,25 @@ pub struct Config {
impl Config {
pub fn from_file(p: &Path) -> Result<Self, Box<dyn Error>> {
match serde_dhall::from_file(p)
.with_builtin_type("Mapping".to_string(), Mapping::static_type())
.with_builtin_type("Action".to_string(), Action::static_type())
serde_dhall::from_file(p)
.parse::<Self>()
{
Ok(c) => Ok(c),
Err(e) => {
println!("{}", e);
Err(Box::new(e))
}
}
.map_err(|e| e.into())
}
pub fn generate_prelude() -> StdError<()> {
let mut m = HashMap::new();
m.insert("Action".to_string(), Action::static_type());
m.insert("Mapping".to_string(), Mapping::static_type());
println!(
"-- Sampad Dhall types, autogenerated by git#{} on {}",
option_env!("VERSION").unwrap_or("unknown"),
Utc::now(),
);
println!(
"{{ Action = {}, Mapping = {} }}",
Action::static_type(),
Mapping::static_type()
);
Ok(())
}
}

View File

@ -5,11 +5,14 @@ use config::{Action, Config, Mapping};
use hidapi::HidApi;
use rumqttc::{Client, MqttOptions, QoS};
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::path::Path;
use std::thread;
use tracing::{event, Level};
type StdError<T> = Result<T, Box<dyn Error>>;
struct State<'a> {
mqtt_servers: HashMap<String, Client>,
conf: &'a Config,
@ -107,7 +110,19 @@ impl<'a> State<'a> {
}
}
fn main() -> Result<(), Box<dyn Error>> {
fn main() -> StdError<()> {
let args: Vec<_> = env::args().collect();
if let [prog, args @ ..] = &args[..] {
if args == ["generate-dhall"] {
return Config::generate_prelude();
} else if args.len() > 0 {
eprintln!("Usage: {} [generate-dhall]", prog);
return Err("Invalid usage".into());
}
} else {
unreachable!();
}
tracing_subscriber::fmt::init();
event!(Level::INFO, "Starting...");
let conf = Config::from_file(Path::new("./config.dhall"))?;

22
types.dhall Normal file
View File

@ -0,0 +1,22 @@
-- Sampad Dhall types, autogenerated by git#96d9ca3 on 2022-07-11 13:54:53.099283885 UTC
{ Action =
< ActivateLayer : Text
| MQTTPub : { payload : Text, topic : Text }
| Print : Text
>
, Mapping =
< NOP
| Passthrough
| Trigger :
< ActivateLayer : Text
| MQTTPub : { payload : Text, topic : Text }
| Print : Text
>
| TriggerMulti :
List
< ActivateLayer : Text
| MQTTPub : { payload : Text, topic : Text }
| Print : Text
>
>
}