mirror of
https://github.com/janishutz/mqtt-remote-gpio.git
synced 2026-10-08 20:56:22 +02:00
feat: separate files, basic gpio util prep, config parsing
This commit is contained in:
1 parent
f665027373
commit
f044a5b5bd
9 files changed
+290
-167
No files matched your search
@@ -24,3 +24,4 @@ target
|
|||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
config.secret.yml
|
||||||
Generated
+33
-107
@@ -3,13 +3,10 @@
|
|||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "arraydeque"
|
||||||
version = "1.1.5"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-lc-rs"
|
name = "aws-lc-rs"
|
||||||
@@ -34,12 +31,6 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.22.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.13.1"
|
version = "2.13.1"
|
||||||
@@ -102,10 +93,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "encoding_rs"
|
||||||
version = "1.0.2"
|
version = "0.8.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
@@ -130,6 +124,12 @@ dependencies = [
|
|||||||
"spin",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs_extra"
|
name = "fs_extra"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -200,17 +200,17 @@ name = "hashbrown"
|
|||||||
version = "0.17.1"
|
version = "0.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "hashlink"
|
||||||
version = "2.14.0"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
checksum = "32069d97bb81e38fa67eab65e3393bf804bb85969f2bc06bf13f64aef5aba248"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"serde",
|
|
||||||
"serde_core",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -244,21 +244,6 @@ version = "0.4.34"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memmap2"
|
|
||||||
version = "0.9.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
@@ -276,7 +261,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"gpio",
|
"gpio",
|
||||||
"rumqttc",
|
"rumqttc",
|
||||||
"rust-yaml",
|
"yaml-rust2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -327,35 +312,6 @@ version = "6.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.14"
|
version = "0.17.14"
|
||||||
@@ -391,18 +347,6 @@ dependencies = [
|
|||||||
"tokio-util",
|
"tokio-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rust-yaml"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3597280f43f5f5c9b7e7f281eab078651cf3a551a439e86d9506fe3a85d74f1d"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"indexmap",
|
|
||||||
"memmap2",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.43"
|
version = "0.23.43"
|
||||||
@@ -509,35 +453,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.229"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
||||||
dependencies = [
|
|
||||||
"serde_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_core"
|
|
||||||
version = "1.0.229"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.229"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -773,6 +688,17 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust2"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6edb26322e610d4f04b7cd34478317685d24d0999437e551fb97c5441151041"
|
||||||
|
dependencies = [
|
||||||
|
"arraydeque",
|
||||||
|
"encoding_rs",
|
||||||
|
"hashlink",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|||||||
+1
-1
@@ -6,4 +6,4 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
gpio = "0.4.1"
|
gpio = "0.4.1"
|
||||||
rumqttc = "0.25.1"
|
rumqttc = "0.25.1"
|
||||||
rust-yaml = "1.1.0"
|
yaml-rust2 = "0.12.0"
|
||||||
+8
-2
@@ -107,12 +107,18 @@
|
|||||||
"mode"
|
"mode"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"cycleInterval": {
|
"pollInterval": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"minimum": 50,
|
"minimum": 50,
|
||||||
"maximum": 65535,
|
"maximum": 65535,
|
||||||
"default": 100,
|
"default": 100,
|
||||||
"description": "How many miliseconds should ellapse between polls of the pin states. Updates are only sent when the state actually changes"
|
"description": "How many miliseconds should ellapse between polls of the pin states. Updates are only sent when the state actually changes"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"pollInterval",
|
||||||
|
"topics",
|
||||||
|
"mqtt"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -5,3 +5,12 @@ mqtt:
|
|||||||
authentication: true
|
authentication: true
|
||||||
password: "234"
|
password: "234"
|
||||||
user: "mqtt"
|
user: "mqtt"
|
||||||
|
|
||||||
|
# TODO: Consider adding an auto-off setting for out mode
|
||||||
|
# Add default setting (also only for out)
|
||||||
|
topics:
|
||||||
|
- topic: ""
|
||||||
|
pin: 0
|
||||||
|
mode: "in"
|
||||||
|
|
||||||
|
pollInterval: 100
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
use std::fs;
|
||||||
|
use yaml_rust2::{Yaml, YamlLoader};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Topic {
|
||||||
|
pub topic: String,
|
||||||
|
pub pin: u16,
|
||||||
|
pub mode: PinMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
pub enum PinMode {
|
||||||
|
IN,
|
||||||
|
OUT,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MqttConfig {
|
||||||
|
pub host: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub authentication: bool,
|
||||||
|
pub user: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
pub mqtt: MqttConfig,
|
||||||
|
pub topics: Vec<Topic>,
|
||||||
|
pub poll_interval: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config(path: &str) -> Result<Config, Box<dyn std::error::Error>> {
|
||||||
|
// Read config file
|
||||||
|
let conf = fs::read_to_string(path).unwrap_or_else(|_| String::from("test"));
|
||||||
|
let yaml = &YamlLoader::load_from_str(&conf).unwrap()[0];
|
||||||
|
let conf = yaml
|
||||||
|
.as_hash()
|
||||||
|
.expect("Invalid config found at line 1. Not an object");
|
||||||
|
let mqtt_conf = conf
|
||||||
|
.get(&Yaml::String(String::from("mqtt")))
|
||||||
|
.expect("MQTT config is missing.")
|
||||||
|
.as_hash()
|
||||||
|
.expect("MQTT config is invalid");
|
||||||
|
|
||||||
|
// Load topics and pin config
|
||||||
|
let mut topics: Vec<Topic> = Vec::new();
|
||||||
|
let mut i = 0;
|
||||||
|
for raw_topic in conf
|
||||||
|
.get(&Yaml::String(String::from("topics")))
|
||||||
|
.expect("Topics config missing")
|
||||||
|
.as_vec()
|
||||||
|
.expect("Topics config invalid. Expected an array")
|
||||||
|
{
|
||||||
|
i += 1;
|
||||||
|
let topic = raw_topic.as_hash().expect(
|
||||||
|
&format!("Invalid topic configuration found for topic at index {}. All topics should be objects with topic, pin and mode!", i));
|
||||||
|
topics.push(
|
||||||
|
Topic {
|
||||||
|
topic: String::from(
|
||||||
|
topic
|
||||||
|
.get(&Yaml::String(String::from("topic")))
|
||||||
|
.expect(&format!("Invalid topic configuration found at index {}. The topic name is missing", i))
|
||||||
|
.as_str()
|
||||||
|
.expect(&format!("Invalid topic configuration found index {}. The topic name should be a string", i)),
|
||||||
|
),
|
||||||
|
pin: topic
|
||||||
|
.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,
|
||||||
|
mode: if topic
|
||||||
|
.get(&Yaml::String(String::from("mode")))
|
||||||
|
.expect(&format!("Invalid topic configuration found at index {}. Mode is unset", i))
|
||||||
|
.as_str()
|
||||||
|
.expect(&format!("Invalid topic configuration found at index {}. Mode should be a string of either 'in' or 'out'", i)) == "in"
|
||||||
|
{ PinMode::IN } else { PinMode::OUT },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the config struct
|
||||||
|
Ok(Config {
|
||||||
|
mqtt: MqttConfig {
|
||||||
|
host: String::from(
|
||||||
|
mqtt_conf
|
||||||
|
.get(&Yaml::String(String::from("host")))
|
||||||
|
.expect("Host config missing")
|
||||||
|
.as_str()
|
||||||
|
.expect("Host configuration is invalid"),
|
||||||
|
),
|
||||||
|
port: mqtt_conf
|
||||||
|
.get(&Yaml::String(String::from("port")))
|
||||||
|
.unwrap_or(&Yaml::Integer(1883))
|
||||||
|
.as_i64()
|
||||||
|
.expect("Invalid port configuration. Expected integer") as u16,
|
||||||
|
authentication: mqtt_conf
|
||||||
|
.get(&Yaml::String(String::from("authentication")))
|
||||||
|
.unwrap_or(&Yaml::Boolean(false))
|
||||||
|
.as_bool()
|
||||||
|
.expect("Authentication configuration value incorrect"),
|
||||||
|
user: String::from(
|
||||||
|
mqtt_conf
|
||||||
|
.get(&Yaml::String(String::from("user")))
|
||||||
|
.unwrap_or(&Yaml::String(String::from("")))
|
||||||
|
.as_str()
|
||||||
|
.expect("User configuration invalid"),
|
||||||
|
),
|
||||||
|
password: String::from(
|
||||||
|
mqtt_conf
|
||||||
|
.get(&Yaml::String(String::from("password")))
|
||||||
|
.unwrap_or(&Yaml::String(String::from("")))
|
||||||
|
.as_str()
|
||||||
|
.expect("Password configuration invalid"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
topics: topics,
|
||||||
|
poll_interval: conf
|
||||||
|
.get(&Yaml::String(String::from("pollInterval")))
|
||||||
|
.expect("Missing config for pollInterval")
|
||||||
|
.as_i64()
|
||||||
|
.expect("pollInterval is not an integer value") as u16,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::conf::{PinMode, Topic};
|
||||||
|
|
||||||
|
/// Split topics into in and out pins. Returns them in this order
|
||||||
|
///
|
||||||
|
/// * `topics`: The topics to use
|
||||||
|
pub fn split_topics_and_configure_pins(topics: Vec<Topic>) -> (Vec<Topic>, Vec<Topic>) {
|
||||||
|
let mut in_pins: Vec<Topic> = Vec::new();
|
||||||
|
let mut out_pins: Vec<Topic> = Vec::new();
|
||||||
|
for topic in topics {
|
||||||
|
if topic.mode == PinMode::IN {
|
||||||
|
in_pins.push(topic);
|
||||||
|
} else {
|
||||||
|
out_pins.push(topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (in_pins, out_pins);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_pin_value(id: u16) {}
|
||||||
|
|
||||||
|
pub struct GPIOController {
|
||||||
|
in_pins: HashMap<String, Topic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GPIOController {
|
||||||
|
/// Create a new GPIO controller.
|
||||||
|
/// Note that the move of ownership is intentional behaviour. Only create one instance of this controller!
|
||||||
|
///
|
||||||
|
/// * `topics`: The topics that are going to be managed by this controller (All OUT mode pins
|
||||||
|
/// are dropped without error)
|
||||||
|
pub fn new(topics: Vec<Topic>) -> Self {
|
||||||
|
let mut controller = GPIOController {
|
||||||
|
in_pins: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build hash maps
|
||||||
|
for topic in topics {
|
||||||
|
if topic.mode == PinMode::IN {
|
||||||
|
controller
|
||||||
|
.in_pins
|
||||||
|
.insert(String::from(topic.topic.as_str()), topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_event(&self) {}
|
||||||
|
}
|
||||||
+11
-57
@@ -1,64 +1,18 @@
|
|||||||
use rumqttc::{Client, MqttOptions, QoS};
|
use std::{thread, time::Duration};
|
||||||
use std::{fs, thread, time::Duration};
|
mod conf;
|
||||||
|
mod gpio_utils;
|
||||||
struct Topic {
|
mod mqtt;
|
||||||
name: String,
|
|
||||||
pin: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// TODO: Proper cli interface and start screen
|
||||||
|
// CLI interface should allow setting the config file
|
||||||
println!("mqtt-remote-gpio");
|
println!("mqtt-remote-gpio");
|
||||||
|
|
||||||
// Read config file
|
let config = conf::load_config("config.yml").unwrap();
|
||||||
let conf = fs::read_to_string("config.yml").unwrap_or_else(|_| String::from("test"));
|
|
||||||
println!("{}", conf);
|
|
||||||
|
|
||||||
pin_setup();
|
// TODO: Remove this when done
|
||||||
|
println!("{:#?}", config);
|
||||||
|
thread::sleep(Duration::from_secs(2));
|
||||||
|
|
||||||
let mut mqttoptions = MqttOptions::new("mqtt", "10.0.9.60", 1883);
|
mqtt::handler(config);
|
||||||
mqttoptions.set_keep_alive(Duration::from_secs(5));
|
|
||||||
mqttoptions.set_credentials("mqtt", "PNS#Ka!kk8cb5uYYgXdGZkBvGPP24x");
|
|
||||||
listener(
|
|
||||||
vec![Topic {
|
|
||||||
name: String::from("garage/test"),
|
|
||||||
pin: 0,
|
|
||||||
}],
|
|
||||||
vec![Topic {
|
|
||||||
name: String::from("garage/test"),
|
|
||||||
pin: 0,
|
|
||||||
}],
|
|
||||||
mqttoptions,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pin_setup() {
|
|
||||||
// TODO: Check that a pin is not both in and out
|
|
||||||
println!("Pin setup complete");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MQTT connection handler
|
|
||||||
///
|
|
||||||
/// * `topics`: The MQTT topics to subscribe to
|
|
||||||
/// * `mqttoptions`: MQTT options for conenction
|
|
||||||
fn listener(subscribe_topics: Vec<Topic>, publish_topics: Vec<Topic>, mqttoptions: MqttOptions) {
|
|
||||||
let (client, mut connection) = Client::new(mqttoptions, 10);
|
|
||||||
for topic in subscribe_topics {
|
|
||||||
client.subscribe(topic.name, QoS::AtMostOnce).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn thread to update pins
|
|
||||||
thread::spawn(move || {
|
|
||||||
loop {
|
|
||||||
for topic in &publish_topics {
|
|
||||||
client
|
|
||||||
.publish(&topic.name, QoS::AtLeastOnce, false, vec![0; 0 as usize])
|
|
||||||
.unwrap_or_default();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (_, notification) in connection.iter().enumerate() {
|
|
||||||
println!("{:?}", notification);
|
|
||||||
// TODO: Handle pin value change instructions
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
use crate::conf::{Config};
|
||||||
|
use crate::gpio_utils::{GPIOController, split_topics_and_configure_pins};
|
||||||
|
use rumqttc::{Client, MqttOptions, QoS};
|
||||||
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
|
/// MQTT connection handler
|
||||||
|
///
|
||||||
|
/// * `topics`: The MQTT topics to subscribe to
|
||||||
|
/// * `mqttoptions`: MQTT options for conenction
|
||||||
|
pub fn handler(config: Config) {
|
||||||
|
// Configure pins
|
||||||
|
let (subscribe_topics, publish_topics) = split_topics_and_configure_pins(config.topics);
|
||||||
|
|
||||||
|
// Configure MQTT
|
||||||
|
let mut mqttoptions = MqttOptions::new("mqtt", config.mqtt.host, config.mqtt.port);
|
||||||
|
mqttoptions.set_keep_alive(Duration::from_secs(5));
|
||||||
|
if config.mqtt.authentication {
|
||||||
|
mqttoptions.set_credentials(config.mqtt.user, config.mqtt.password);
|
||||||
|
}
|
||||||
|
let (client, mut connection) = Client::new(mqttoptions, 10);
|
||||||
|
|
||||||
|
// Subscribe to events
|
||||||
|
for topic in subscribe_topics.iter() {
|
||||||
|
println!("Setting up topic {}", topic.topic);
|
||||||
|
client
|
||||||
|
.subscribe(topic.topic.as_str(), QoS::AtMostOnce)
|
||||||
|
.unwrap_or_else(|x| println!("Setup failed, error: {:?}", x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn thread to monitor pins
|
||||||
|
thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
for topic in &publish_topics {
|
||||||
|
// TODO: handle fails
|
||||||
|
client
|
||||||
|
.publish(&topic.topic, QoS::AtLeastOnce, false, vec![0 as u8; 1])
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Main thread listens to topic updates
|
||||||
|
let controller = GPIOController::new(subscribe_topics);
|
||||||
|
for (_, notification) in connection.iter().enumerate() {
|
||||||
|
println!("Notification {:?}", notification);
|
||||||
|
controller.handle_event();
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
// TODO: Handle pin value change instructions
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user