mirror of
https://github.com/janishutz/mqtt-remote-gpio.git
synced 2026-10-09 05:06:21 +02:00
feat: testing code, switch to rppal gpio lib, get mqtt working in both directions
This commit is contained in:
1 parent
0b0efb1a0d
commit
cd0f894e73
8 files changed
+727
-32
No files matched your search
+2
-2
@@ -4,7 +4,7 @@ use yaml_rust2::{Yaml, YamlLoader};
|
||||
#[derive(Debug)]
|
||||
pub struct Topic {
|
||||
pub topic: String,
|
||||
pub pin: u16,
|
||||
pub pin: u8,
|
||||
pub mode: PinMode,
|
||||
pub off_timeout: u64,
|
||||
}
|
||||
@@ -69,7 +69,7 @@ pub fn load_config(path: &str) -> Result<Config, Box<dyn std::error::Error>> {
|
||||
.get(&Yaml::String(String::from("pin")))
|
||||
.expect(&format!("Invalid topic configuration found at index {}. A pin is required", i))
|
||||
.as_i64()
|
||||
.expect(&format!("Invalid topic configuration found at index {}. The pin should be a 16 bit integer (0-65535)", i)) as u16,
|
||||
.expect(&format!("Invalid topic configuration found at index {}. The pin should be a 16 bit integer (0-65535)", i)) as u8,
|
||||
off_timeout: topic
|
||||
.get(&Yaml::String(String::from("pin")))
|
||||
.unwrap_or(&Yaml::Integer(-1))
|
||||
|
||||
+20
-14
@@ -1,19 +1,19 @@
|
||||
use gpio::{GpioIn, GpioOut};
|
||||
use rppal::gpio;
|
||||
use rumqttc::Publish;
|
||||
use std::{collections::HashMap, time::SystemTime};
|
||||
|
||||
use crate::conf::{PinMode, Topic};
|
||||
|
||||
pub struct InputPin {
|
||||
pub gpio: gpio::sysfs::SysFsGpioInput,
|
||||
pub id: u16,
|
||||
pub gpio: gpio::InputPin,
|
||||
pub id: u8,
|
||||
pub topic: String,
|
||||
}
|
||||
|
||||
pub struct OutputPin {
|
||||
gpio: gpio::sysfs::SysFsGpioOutput,
|
||||
gpio: gpio::OutputPin,
|
||||
off_timeout: u64,
|
||||
pub id: u16,
|
||||
pub id: u8,
|
||||
pub topic: String,
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ pub struct OutputPin {
|
||||
pub fn split_topics_and_configure_pins(topics: Vec<Topic>) -> (Vec<InputPin>, Vec<OutputPin>) {
|
||||
let mut in_pins: Vec<InputPin> = Vec::new();
|
||||
let mut out_pins: Vec<OutputPin> = Vec::new();
|
||||
let mut in_used: Vec<u16> = Vec::new();
|
||||
let mut out_used: Vec<u16> = Vec::new();
|
||||
let mut in_used: Vec<u8> = Vec::new();
|
||||
let mut out_used: Vec<u8> = Vec::new();
|
||||
for topic in topics {
|
||||
if topic.mode == PinMode::IN {
|
||||
if in_used.contains(&topic.pin) {
|
||||
@@ -36,10 +36,13 @@ pub fn split_topics_and_configure_pins(topics: Vec<Topic>) -> (Vec<InputPin>, Ve
|
||||
} else if out_used.contains(&topic.pin) {
|
||||
panic!("Pin {} used for both input and output!", topic.pin)
|
||||
}
|
||||
let pin = gpio::Gpio::new().expect("GPIO pin access failed");
|
||||
in_pins.push(InputPin {
|
||||
topic: topic.topic,
|
||||
gpio: gpio::sysfs::SysFsGpioInput::open(topic.pin)
|
||||
.expect(&format!("Unable to find GPIO pin {}", topic.pin)),
|
||||
gpio: pin
|
||||
.get(topic.pin)
|
||||
.expect(&format!("Unable to find GPIO pin {}", topic.pin))
|
||||
.into_input(),
|
||||
id: topic.pin,
|
||||
});
|
||||
in_used.push(topic.pin)
|
||||
@@ -53,10 +56,13 @@ pub fn split_topics_and_configure_pins(topics: Vec<Topic>) -> (Vec<InputPin>, Ve
|
||||
} else if in_used.contains(&topic.pin) {
|
||||
panic!("Pin {} used for both input and output!", topic.pin)
|
||||
}
|
||||
let pin = gpio::Gpio::new().expect("GPIO pin access failed");
|
||||
out_pins.push(OutputPin {
|
||||
topic: topic.topic,
|
||||
gpio: gpio::sysfs::SysFsGpioOutput::open(topic.pin)
|
||||
.expect(&format!("Unable to find GPIO pin {}", topic.pin)),
|
||||
gpio: pin
|
||||
.get(topic.pin)
|
||||
.expect(&format!("Unable to find GPIO pin {}", topic.pin))
|
||||
.into_output_low(),
|
||||
id: topic.pin,
|
||||
off_timeout: topic.off_timeout,
|
||||
});
|
||||
@@ -67,8 +73,9 @@ pub fn split_topics_and_configure_pins(topics: Vec<Topic>) -> (Vec<InputPin>, Ve
|
||||
return (in_pins, out_pins);
|
||||
}
|
||||
|
||||
pub fn read_pin(pin: &mut gpio::sysfs::SysFsGpioInput) -> u8 {
|
||||
if let gpio::GpioValue::Low = pin.read_value().expect("Failed reading value") {
|
||||
pub fn read_pin(pin: &mut gpio::InputPin) -> u8 {
|
||||
// TODO: Consider moving to interrupt based solution
|
||||
if let gpio::Level::High = pin.read() {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -114,7 +121,6 @@ impl GPIOController {
|
||||
.expect("Failed to retrieve pin")
|
||||
.gpio
|
||||
.set_low()
|
||||
.unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-8
@@ -30,17 +30,27 @@ pub fn handler(config: Config) {
|
||||
|
||||
// Spawn thread to monitor pins
|
||||
thread::spawn(move || {
|
||||
let mut pin_state: Vec<u8> = vec![0; input_pins.len()];
|
||||
let off: Vec<u8> = b"OFF".to_vec();
|
||||
let on: Vec<u8> = b"ON".to_vec();
|
||||
loop {
|
||||
let mut i = 0;
|
||||
for topic in input_pins.iter_mut() {
|
||||
// TODO: handle fails
|
||||
client
|
||||
.publish(
|
||||
String::from(&topic.topic) + &format!("/{}", topic.id),
|
||||
QoS::AtLeastOnce,
|
||||
false,
|
||||
vec![read_pin(&mut topic.gpio)],
|
||||
)
|
||||
.unwrap_or_default();
|
||||
let val = read_pin(&mut topic.gpio);
|
||||
if val != pin_state[i] {
|
||||
println!("Value change for pin {} detected", topic.id);
|
||||
pin_state[i] = val;
|
||||
client
|
||||
.publish(
|
||||
String::from(&topic.topic) + &format!("/{}", topic.id),
|
||||
QoS::AtLeastOnce,
|
||||
false,
|
||||
if val == 0 { off.clone() } else { on.clone() },
|
||||
)
|
||||
.unwrap_or_default();
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(config.poll_interval));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user