WP
This commit is contained in:
parent
4f1f1ba88e
commit
d8ebb16486
31
src/main.rs
31
src/main.rs
@ -22,6 +22,7 @@ use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::thread;
|
||||
|
||||
use crate::filter::*;
|
||||
@ -73,7 +74,7 @@ fn main() {
|
||||
simplelog::TermLogger::init(
|
||||
level,
|
||||
simplelog::Config {
|
||||
time: Some(simplelog::Level::Debug),
|
||||
time: None,
|
||||
level: Some(simplelog::Level::Error),
|
||||
target: Some(simplelog::Level::Info),
|
||||
location: Some(simplelog::Level::Debug),
|
||||
@ -93,10 +94,14 @@ fn main() {
|
||||
let config: AppConfig =
|
||||
serde_yaml::from_str(&config_content).expect("Invalid config file content");
|
||||
|
||||
let thread_count = config.monitors.len() + config.outputs.len();
|
||||
let barrier = Arc::new(Barrier::new(thread_count + 1));
|
||||
|
||||
// Monitors -> dispatcher channel
|
||||
let (mon_sender, mon_receiver) = mpsc::channel();
|
||||
|
||||
// Instantiate monitor threads and structs
|
||||
let mut mon_threads = vec![];
|
||||
for mon_config in config.monitors {
|
||||
let mon_type = mon_config
|
||||
.get("type")
|
||||
@ -106,21 +111,23 @@ fn main() {
|
||||
.to_owned();
|
||||
|
||||
let snd = mon_sender.clone();
|
||||
let bar = barrier.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
mon_threads.push(thread::spawn(move || {
|
||||
log::info!("+> monitor: {}", mon_type);
|
||||
match monitors::factory(&mon_type, &mon_config) {
|
||||
Ok(mut mon) => loop {
|
||||
bar.wait();
|
||||
mon.run(&snd);
|
||||
},
|
||||
Err(e) => log::error!("Cannot instantiate monitor {}: {}", mon_type, e),
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// Instantiate output threads and structs
|
||||
// let mut outputs: Vec<(Box<Output>, Filter)> = vec![];
|
||||
let mut output_senders: Vec<mpsc::Sender<Message>> = vec![];
|
||||
let mut output_threads = vec![];
|
||||
for out_config in config.outputs {
|
||||
let out_type = out_config
|
||||
.get("type")
|
||||
@ -133,11 +140,13 @@ fn main() {
|
||||
output_senders.push(out_sender);
|
||||
|
||||
let filter = Filter::new(&out_config);
|
||||
let bar = barrier.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
output_threads.push(thread::spawn(move || {
|
||||
log::info!("+> output: {}", out_type);
|
||||
match outputs::factory(&out_type, &out_config) {
|
||||
Ok(mut output) => loop {
|
||||
bar.wait();
|
||||
let message = out_receiver.recv().unwrap();
|
||||
if filter.is_message_allowed(&message) {
|
||||
output.process_message(message);
|
||||
@ -145,10 +154,20 @@ fn main() {
|
||||
},
|
||||
Err(e) => log::error!("Cannot instantiate output {}: {}", out_type, e),
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
let output_senders = output_senders;
|
||||
|
||||
// Start all the threads
|
||||
barrier.wait();
|
||||
log::info!("Started rnetmon");
|
||||
for t in &mon_threads {
|
||||
t.thread().unpark();
|
||||
}
|
||||
for t in &output_threads {
|
||||
t.thread().unpark();
|
||||
}
|
||||
|
||||
// Dispatch messages
|
||||
loop {
|
||||
let message = mon_receiver.recv().unwrap();
|
||||
|
@ -31,14 +31,15 @@ impl Monitor for DHCPLeases {
|
||||
.get("config")
|
||||
.unwrap_or(&serde_yaml::Mapping::new().into())
|
||||
.clone();
|
||||
let config = serde_yaml::from_value(config_node).expect("Invalid config for dhcp_leases");
|
||||
let config = serde_yaml::from_value(config_node)?;
|
||||
|
||||
// Regex compilation
|
||||
let rgx_lease = Regex::new(r"(?s)lease\s+(\d+(?:\.\d+){3})\s*\{\n?(.*?)\}").unwrap();
|
||||
let rgx_mac =
|
||||
Regex::new(r"^\s*hardware\s+ethernet\s([a-f0-9]{2}(?::[a-f0-9]{2}){5})\s*;").unwrap();
|
||||
let rgx_date_start = Regex::new(r"^\s*starts\s+(.*?)\s*;").unwrap();
|
||||
let rgx_date_ends = Regex::new(r"^\s*ends\s+(.*?)\s*;").unwrap();
|
||||
Regex::new(r"(?m)^\s*hardware\s+ethernet\s([a-f0-9]{2}(?::[a-f0-9]{2}){5})\s*;")
|
||||
.unwrap();
|
||||
let rgx_date_start = Regex::new(r"(?m)^\s*starts\s+\d+\s+(.*?)\s*;").unwrap();
|
||||
let rgx_date_ends = Regex::new(r"(?m)^\s*ends\s+\d+\s+(.*?)\s*;").unwrap();
|
||||
|
||||
Ok(DHCPLeases {
|
||||
config: config,
|
||||
@ -66,36 +67,38 @@ impl Monitor for DHCPLeases {
|
||||
let mut unauthorized_macs: Vec<String> = vec![];
|
||||
|
||||
for cap in self.rgx_lease.captures_iter(&config_content) {
|
||||
let ip = cap.get(1).unwrap().as_str();
|
||||
let _ip = cap.get(1).unwrap().as_str();
|
||||
let content = cap.get(2).unwrap().as_str();
|
||||
|
||||
let mac = self
|
||||
.rgx_mac
|
||||
.captures(content)
|
||||
.expect("No 'hardware ethernet' field found for MAC address")
|
||||
.get(0)
|
||||
.expect(&format!(
|
||||
"No 'hardware ethernet' field found for MAC address in {}",
|
||||
content
|
||||
))
|
||||
.get(1)
|
||||
.unwrap()
|
||||
.as_str();
|
||||
let starts_str = self
|
||||
.rgx_date_start
|
||||
.captures(content)
|
||||
.expect("No 'starts' field found in lease")
|
||||
.get(0)
|
||||
.get(1)
|
||||
.unwrap()
|
||||
.as_str();
|
||||
let starts =
|
||||
chrono::naive::NaiveDateTime::parse_from_str(starts_str, "%U %Y/%m/%d %H:%M:%S")
|
||||
.expect("Bad date format");
|
||||
chrono::naive::NaiveDateTime::parse_from_str(starts_str, "%Y/%m/%d %H:%M:%S")
|
||||
.expect(&format!("Bad date format: '{}'", starts_str));
|
||||
let ends_str = self
|
||||
.rgx_date_ends
|
||||
.captures(content)
|
||||
.expect("No 'ends' field found in lease")
|
||||
.get(0)
|
||||
.get(1)
|
||||
.unwrap()
|
||||
.as_str();
|
||||
let ends =
|
||||
chrono::naive::NaiveDateTime::parse_from_str(ends_str, "%U %Y/%m/%d %H:%M:%S")
|
||||
.expect("Bad date format");
|
||||
let ends = chrono::naive::NaiveDateTime::parse_from_str(ends_str, "%Y/%m/%d %H:%M:%S")
|
||||
.expect(&format!("Bad date format: '{}'", ends_str));
|
||||
|
||||
let now = Local::now().naive_local();
|
||||
if starts <= now && now < ends {
|
||||
|
@ -2,6 +2,7 @@ extern crate blurz;
|
||||
|
||||
use blurz::bluetooth_adapter::BluetoothAdapter;
|
||||
use blurz::bluetooth_device::BluetoothDevice;
|
||||
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession;
|
||||
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic;
|
||||
use blurz::bluetooth_gatt_service::BluetoothGATTService;
|
||||
use blurz::bluetooth_session::BluetoothSession;
|
||||
@ -63,13 +64,19 @@ impl LightConfig {
|
||||
}
|
||||
}
|
||||
impl BluetoothLightbulb {
|
||||
fn set_color(&self, characs: &Vec<BluetoothGATTCharacteristic>, r: f64, g: f64, b: f64) {
|
||||
fn set_color(
|
||||
&self,
|
||||
targets: &Vec<(BluetoothDevice, BluetoothGATTCharacteristic)>,
|
||||
r: f64,
|
||||
g: f64,
|
||||
b: f64,
|
||||
) {
|
||||
let r = (r * 255.0) as u8;
|
||||
let g = (g * 255.0) as u8;
|
||||
let b = (b * 255.0) as u8;
|
||||
|
||||
// println!("r={} g={} b={}", r, g, b);
|
||||
for charac in characs {
|
||||
for (_, charac) in targets {
|
||||
charac
|
||||
.write_value(vec![0x55, 0x13, r, g, b, '\r' as u8, '\n' as u8], None)
|
||||
.unwrap();
|
||||
@ -78,10 +85,15 @@ impl BluetoothLightbulb {
|
||||
|
||||
fn initiate_scan(&self, adapter: &BluetoothAdapter) {
|
||||
if !adapter.is_discovering().unwrap() {
|
||||
log::info!("bluetooth adapter {}: Set scan ON", adapter.get_id());
|
||||
adapter
|
||||
log::info!("{}: Searching for new devices...", adapter.get_id());
|
||||
|
||||
let disc_session =
|
||||
BluetoothDiscoverySession::create_session(&self.session, adapter.get_id())
|
||||
.expect("Could not create discovery session");
|
||||
|
||||
disc_session
|
||||
.start_discovery()
|
||||
.expect("Cannot activate scanning on bluetooth device");
|
||||
.expect("Could not start discovery session");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,8 +106,7 @@ impl Output for BluetoothLightbulb {
|
||||
.get("config")
|
||||
.unwrap_or(&serde_yaml::Mapping::new().into())
|
||||
.clone();
|
||||
let config: BluetoothLightbulbConfig =
|
||||
serde_yaml::from_value(config_node).expect("Invalid config for light_beewi_bbl227");
|
||||
let config: BluetoothLightbulbConfig = serde_yaml::from_value(config_node)?;
|
||||
|
||||
let msg_types = config
|
||||
.msg_types
|
||||
@ -115,8 +126,7 @@ impl Output for BluetoothLightbulb {
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect();
|
||||
|
||||
let session =
|
||||
BluetoothSession::create_session(None).expect("Could not initialize bluetooth session");
|
||||
let session = BluetoothSession::create_session(None)?;
|
||||
|
||||
let ret = BluetoothLightbulb {
|
||||
config: config,
|
||||
@ -125,9 +135,8 @@ impl Output for BluetoothLightbulb {
|
||||
session: session,
|
||||
};
|
||||
|
||||
// Initialize bluetooth device
|
||||
let adapter =
|
||||
BluetoothAdapter::init(&ret.session).expect("Could not initialize bluetooth adapter");
|
||||
// Initialize bluetooth adapter
|
||||
let adapter = BluetoothAdapter::init(&ret.session)?;
|
||||
// Power on
|
||||
if !adapter.is_powered().unwrap() {
|
||||
log::info!("bluetooth adapter {}: Set power ON", adapter.get_id());
|
||||
@ -135,8 +144,6 @@ impl Output for BluetoothLightbulb {
|
||||
.set_powered(true)
|
||||
.expect("Cannot power on bluetooth device");
|
||||
}
|
||||
// Start scan
|
||||
ret.initiate_scan(&adapter);
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
@ -144,7 +151,7 @@ impl Output for BluetoothLightbulb {
|
||||
let adapter =
|
||||
BluetoothAdapter::init(&self.session).expect("Could not initialize bluetooth adapter");
|
||||
|
||||
let mut characs = vec![];
|
||||
let mut targets = vec![];
|
||||
let mut found_macs: HashMap<String, bool> = HashMap::new();
|
||||
for mac in self.config.mac.keys() {
|
||||
found_macs.insert(mac.to_owned(), false);
|
||||
@ -157,13 +164,19 @@ impl Output for BluetoothLightbulb {
|
||||
if self.config.mac.contains_key(&addr) {
|
||||
if !device.is_connected().unwrap() {
|
||||
log::info!("Connecting to {}", addr);
|
||||
match device.connect(5000) {
|
||||
match device.connect(30000) {
|
||||
Ok(_) => {
|
||||
let power = device.get_tx_power().expect("Could not request tx power");
|
||||
let power = match device.get_tx_power() {
|
||||
Ok(p) => p.to_string(),
|
||||
Err(_) => "?".to_owned(),
|
||||
};
|
||||
log::info!("Connected to {}, tx power={}", addr, power);
|
||||
|
||||
// GATT characteristics can take a second to correctly load once connected
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not connect to {}: {}", addr, e);
|
||||
log::error!("Could not connect to {}: {:?}", addr, e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -182,7 +195,7 @@ impl Output for BluetoothLightbulb {
|
||||
let charac_uuid = charac.get_uuid().unwrap();
|
||||
|
||||
if charac_uuid == "a8b3fff1-4834-4051-89d0-3de95cddd318" {
|
||||
characs.push(charac);
|
||||
targets.push((device.clone(), charac));
|
||||
found_macs.insert(addr.clone(), true);
|
||||
}
|
||||
}
|
||||
@ -191,11 +204,11 @@ impl Output for BluetoothLightbulb {
|
||||
}
|
||||
}
|
||||
|
||||
// List devices not found
|
||||
let macs_not_found: HashMap<String, bool> = found_macs
|
||||
.into_iter()
|
||||
.filter(|(_, v)| *v == false)
|
||||
.collect();
|
||||
|
||||
if macs_not_found.len() > 0 {
|
||||
log::warn!(
|
||||
"Could not find configured lightbulbs: {:?}",
|
||||
@ -205,7 +218,7 @@ impl Output for BluetoothLightbulb {
|
||||
return;
|
||||
}
|
||||
|
||||
// find out color & pattern to play
|
||||
// Merge LightConfig properties
|
||||
let mut cfg = LightConfig {
|
||||
color: Some(0xffffff),
|
||||
animation: Some(Animation::Smooth),
|
||||
@ -222,6 +235,7 @@ impl Output for BluetoothLightbulb {
|
||||
cfg.merge(level_cfg);
|
||||
}
|
||||
|
||||
// Aimation properties
|
||||
let color = cfg.color.unwrap();
|
||||
let r = ((color >> 16) & 0xff) as f64 / 255.0;
|
||||
let g = ((color >> 8) & 0xff) as f64 / 255.0;
|
||||
@ -235,16 +249,16 @@ impl Output for BluetoothLightbulb {
|
||||
for _ in 0..cfg.repeat.unwrap() {
|
||||
match anim {
|
||||
Animation::None => {
|
||||
self.set_color(&characs, r, g, b);
|
||||
self.set_color(&targets, r, g, b);
|
||||
std::thread::sleep(std::time::Duration::from_millis((2000.0 / speed) as u64));
|
||||
}
|
||||
Animation::Bounce => {
|
||||
for _ in 0..4 {
|
||||
self.set_color(&characs, r, g, b);
|
||||
self.set_color(&targets, r, g, b);
|
||||
std::thread::sleep(std::time::Duration::from_millis(
|
||||
(250.0 / speed) as u64,
|
||||
));
|
||||
self.set_color(&characs, r * 0.5, g * 0.5, b * 0.5);
|
||||
self.set_color(&targets, r * 0.5, g * 0.5, b * 0.5);
|
||||
std::thread::sleep(std::time::Duration::from_millis(
|
||||
(250.0 / speed) as u64,
|
||||
));
|
||||
@ -253,11 +267,11 @@ impl Output for BluetoothLightbulb {
|
||||
Animation::Smooth => {
|
||||
for i in 0..10 {
|
||||
let mult = i as f64 / 10.0;
|
||||
self.set_color(&characs, r * mult, g * mult, b * mult);
|
||||
self.set_color(&targets, r * mult, g * mult, b * mult);
|
||||
}
|
||||
for i in 0..10 {
|
||||
let mult = 1.0 - (i as f64 / 10.0);
|
||||
self.set_color(&characs, r * mult, g * mult, b * mult);
|
||||
self.set_color(&targets, r * mult, g * mult, b * mult);
|
||||
}
|
||||
}
|
||||
Animation::Blink => {
|
||||
@ -266,7 +280,7 @@ impl Output for BluetoothLightbulb {
|
||||
0 => (r, g, b),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
};
|
||||
self.set_color(&characs, r, g, b);
|
||||
self.set_color(&targets, r, g, b);
|
||||
std::thread::sleep(std::time::Duration::from_millis(
|
||||
(400.0 / speed) as u64,
|
||||
));
|
||||
@ -275,24 +289,24 @@ impl Output for BluetoothLightbulb {
|
||||
Animation::RampUp => {
|
||||
for i in 0..20 {
|
||||
let mult = i as f64 / 20.0;
|
||||
self.set_color(&characs, r * mult, g * mult, b * mult);
|
||||
self.set_color(&targets, r * mult, g * mult, b * mult);
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
self.set_color(&characs, 0.0, 0.0, 0.0);
|
||||
self.set_color(&targets, 0.0, 0.0, 0.0);
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
Animation::RampDown => {
|
||||
self.set_color(&characs, r, g, b);
|
||||
self.set_color(&targets, r, g, b);
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
for i in 1..20 {
|
||||
let mult = 1.0 - (i as f64 / 20.0);
|
||||
self.set_color(&characs, r * mult, g * mult, b * mult);
|
||||
self.set_color(&targets, r * mult, g * mult, b * mult);
|
||||
}
|
||||
self.set_color(&characs, 0.0, 0.0, 0.0);
|
||||
self.set_color(&targets, 0.0, 0.0, 0.0);
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.set_color(&characs, 0.0, 0.0, 0.0);
|
||||
self.set_color(&targets, 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user