diff --git a/.gitignore b/.gitignore index 196f560..5ecb75c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .direnv result .env -*.mp3 \ No newline at end of file +*.mp3 +frame.jpg diff --git a/Cargo.lock b/Cargo.lock index a6a9daa..1c28b94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,27 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "CoreFoundation-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b" +dependencies = [ + "libc", + "mach 0.1.2", +] + +[[package]] +name = "IOKit-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a" +dependencies = [ + "CoreFoundation-sys", + "libc", + "mach 0.1.2", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -35,7 +56,7 @@ dependencies = [ "alsa-sys", "bitflags 1.3.2", "libc", - "nix", + "nix 0.23.2", ] [[package]] @@ -358,10 +379,10 @@ dependencies = [ "js-sys", "lazy_static", "libc", - "mach", + "mach 0.3.2", "ndk", "ndk-glue", - "nix", + "nix 0.23.2", "oboe", "parking_lot 0.11.2", "stdweb", @@ -552,8 +573,11 @@ version = "0.1.0" dependencies = [ "dotenv", "lazy_static", + "num", "poise", "regex", + "rscam", + "serialport", "tokio", "tts_rust", ] @@ -1103,6 +1127,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "libudev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0" +dependencies = [ + "libc", + "libudev-sys", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "lock_api" version = "0.4.11" @@ -1119,6 +1163,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "mach" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9" +dependencies = [ + "libc", +] + [[package]] name = "mach" version = "0.3.2" @@ -1128,6 +1181,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.6.4" @@ -1296,6 +1358,17 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1306,6 +1379,40 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -1317,6 +1424,39 @@ dependencies = [ "syn 1.0.109", ] +[[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-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1819,6 +1959,15 @@ dependencies = [ "minimp3", ] +[[package]] +name = "rscam" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89056084211cd54924fedf2e2199b906409d1f795cfd8e7e3271061742457018" +dependencies = [ + "libc", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1996,6 +2145,24 @@ dependencies = [ "url", ] +[[package]] +name = "serialport" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c32634e2bd4311420caa504404a55fad2131292c485c97014cbed89a5899885f" +dependencies = [ + "CoreFoundation-sys", + "IOKit-sys", + "bitflags 1.3.2", + "cfg-if", + "libudev", + "mach2", + "nix 0.26.4", + "regex", + "scopeguard", + "winapi", +] + [[package]] name = "sha-1" version = "0.10.1" @@ -2038,7 +2205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25" dependencies = [ "libc", - "mach", + "mach 0.3.2", "winapi", ] diff --git a/discord-tts-bot/Cargo.toml b/discord-tts-bot/Cargo.toml index 05dc752..66f45eb 100644 --- a/discord-tts-bot/Cargo.toml +++ b/discord-tts-bot/Cargo.toml @@ -8,7 +8,10 @@ edition = "2021" [dependencies] dotenv = "0.15.0" lazy_static = "1.4.0" +num = "0.4.1" poise = "0.5.7" regex = "1.10.2" +rscam = "0.5.5" +serialport = "4.2.2" tokio = { version = "1.33.0", features = ["macros", "signal", "rt-multi-thread"] } tts_rust = "0.3.5" diff --git a/discord-tts-bot/src/main.rs b/discord-tts-bot/src/main.rs index 7776c52..178acd4 100644 --- a/discord-tts-bot/src/main.rs +++ b/discord-tts-bot/src/main.rs @@ -4,6 +4,7 @@ use poise::{serenity_prelude::{self as serenity, GatewayIntents}, Event, command use regex::Regex; use tts_rust::{ tts::GTTSClient, languages::Languages }; use lazy_static::lazy_static; +use std::time::Duration; type Error = Box; type Context<'a> = poise::Context<'a, Data, Error>; @@ -25,6 +26,9 @@ lazy_static! { tld: "com", } }; + static ref SERIAL: std::sync::Mutex> = serialport::new("/dev/ttyACM0", 115_200) + .timeout(Duration::from_millis(1000)) + .open().expect("Failed to open port").into(); } async fn event_handler( @@ -71,7 +75,7 @@ async fn register(ctx: Context<'_>) -> Result<(), Error> { Ok(()) } -#[command(slash_command, owners_only)] +#[command(slash_command, prefix_command, owners_only)] async fn toggle_dnd(ctx: Context<'_>) -> Result<(), Error> { let dnd = { // Put into closure so Mutex isn't locked across an await point @@ -87,6 +91,49 @@ async fn toggle_dnd(ctx: Context<'_>) -> Result<(), Error> { Ok(()) } +#[command(slash_command, prefix_command)] +async fn webcam( + ctx: Context<'_>, + #[description = "Angle"] angle: Option, +) -> Result<(), Error> { + // Move servo to angle if provided, wait for motion + if let Some(angle) = angle { + let angle = num::clamp(angle, 0.0, 180.0) as u8; + SERIAL.lock().unwrap().write(&[angle]).unwrap(); + std::thread::sleep(Duration::from_secs(2)); + } + + // Take the image + let mut camera = rscam::new("/dev/video0").unwrap(); + camera.start(&rscam::Config { + interval: (1, 30), // 30 fps. + resolution: (1920, 1080), + format: b"MJPG", + ..Default::default() + }).unwrap(); + let frame = camera.capture().unwrap(); + + // Take image + const FILENAME: &str = "frame.jpg"; + use tokio::fs::File; + use tokio::io::AsyncWriteExt; + let mut file = File::create(FILENAME).await.unwrap(); + file.write_all(&frame).await.unwrap(); + file.sync_all().await.unwrap(); + let file = File::open(FILENAME).await.unwrap(); + + // Send + ctx.send(|f| f + .attachment(serenity::AttachmentType::File { + file: &file, + filename: FILENAME.to_owned(), + }) + .reply(true) + ).await.unwrap(); + + Ok(()) +} + #[tokio::main] async fn main() { // This will load the environment variables located at `./.env`, relative to @@ -103,6 +150,7 @@ async fn main() { commands: vec![ register(), toggle_dnd(), + webcam(), ], event_handler: |_ctx, event, _framework, _data| { Box::pin(event_handler(_ctx, event, _framework, _data)) @@ -123,4 +171,4 @@ async fn main() { .setup(move |_ctx, _ready, _framework| Box::pin(async move { Result::::Ok(Data { dnd: Mutex::new(false) }) })); framework.run().await.unwrap(); -} \ No newline at end of file +} diff --git a/flake.nix b/flake.nix index adb8514..cdd0bb0 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,12 @@ Some utility commands: rustSettings = with pkgs; { src = ./.; nativeBuildInputs = [ pkg-config ]; - buildInputs = [ openssl alsa-lib ]; + buildInputs = [ + openssl + alsa-lib + libudev-zero + libv4l + ]; cargoHash = nixpkgs.lib.fakeHash; }; meta = with nixpkgs.lib; {