|
|
|
@ -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<dyn std::error::Error + Send + Sync>;
|
|
|
|
|
type Context<'a> = poise::Context<'a, Data, Error>;
|
|
|
|
@ -25,6 +26,9 @@ lazy_static! {
|
|
|
|
|
tld: "com",
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
static ref SERIAL: std::sync::Mutex<Box<dyn serialport::SerialPort>> = 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<f32>,
|
|
|
|
|
) -> 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::<Data, Error>::Ok(Data { dnd: Mutex::new(false) }) }));
|
|
|
|
|
|
|
|
|
|
framework.run().await.unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|