pi-sensors: init

This commit is contained in:
Astro 2021-09-29 21:58:29 +02:00
parent 1f4344f43e
commit 2b11e14863
10 changed files with 382 additions and 0 deletions

View File

@ -56,6 +56,15 @@
mapHqHosts = true;
hq.interface = "eth0";
hq.statistics.enable = true;
pi-sensors = [ {
type = "dht22";
pin = 17;
location = "Tisch";
} {
type = "dht22";
pin = 23;
location = "Tisch2";
} ];
};
nix = {

View File

@ -32,6 +32,7 @@ in {
./stats.nix
./openwebrx.nix
./audio-server
./pi-sensors.nix
];
options.c3d2 = with lib;

40
lib/pi-sensors.nix Normal file
View File

@ -0,0 +1,40 @@
{ pkgs, config, lib, ... }:
{
options.c3d2.pi-sensors = lib.mkOption {
default = [];
type = with lib.types; listOf (submodule ({ ... }: {
options = {
type = lib.mkOption {
description = "Sensor type";
type = enum ["dht22"];
};
pin = lib.mkOption {
description = "GPIO pin";
type = int;
};
location = lib.mkOption {
description = "Sensor location";
type = str;
};
};
}));
};
config = lib.mkIf (config.c3d2.pi-sensors != []) {
# GPIO requires access to /dev/mem
security.wrappers.pi-sensors = {
setuid = true;
owner = "root";
group = "root";
source = "${pkgs.pi-sensors}/bin/pi-sensors";
};
services.collectd.plugins.exec = ''
Exec "${config.services.collectd.user}" "/run/wrappers/bin/pi-sensors" "10"${lib.concatMapStrings (s: " \"${s}\"") (
lib.concatMap ({ type, pin, location }:
[ type (toString pin) location ]
) config.c3d2.pi-sensors
)}
'';
};
}

View File

@ -8,4 +8,6 @@ final: prev:
openwebrx = prev.python3Packages.callPackage ./openwebrx.nix { };
dump1090_sdrplus = prev.callPackage ./dump1090.nix { };
pi-sensors = prev.callPackage ./pi-sensors { };
}

113
overlay/pi-sensors/Cargo.lock generated Normal file
View File

@ -0,0 +1,113 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "dht-hal-drv"
version = "0.2.1"
source = "git+https://github.com/voteblake/dht-hal-drv.git#ed6ea0177573b977545016036fa10ff3b52fd16f"
dependencies = [
"embedded-hal",
]
[[package]]
name = "embedded-hal"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36cfb62ff156596c892272f3015ef952fe1525e85261fa3a7f327bd6b384ab9"
dependencies = [
"nb 0.1.3",
"void",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "nb"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
dependencies = [
"nb 1.0.0",
]
[[package]]
name = "nb"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "pi-sensors"
version = "0.0.0"
dependencies = [
"dht-hal-drv",
"embedded-hal",
"rppal",
"spin_sleep",
"void",
]
[[package]]
name = "rppal"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3225d01a8b7ae304645b4aa38f30061ee08539a1fc6458c68e2b55c803323679"
dependencies = [
"lazy_static",
"libc",
]
[[package]]
name = "spin_sleep"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a98101bdc3833e192713c2af0b0dd2614f50d1cf1f7a97c5221b7aac052acc7"
dependencies = [
"once_cell",
"winapi",
]
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -0,0 +1,14 @@
[package]
name = "pi-sensors"
version = "0.0.0"
edition = "2018"
[dependencies]
rppal = "0.13"
embedded-hal = "0.2"
void = "1"
dht-hal-drv = "0.2"
spin_sleep = "1"
[patch.crates-io]
dht-hal-drv = { git = "https://github.com/voteblake/dht-hal-drv.git" }

View File

@ -0,0 +1,8 @@
{ rustPlatform }:
rustPlatform.buildRustPackage {
name = "pi-sensors";
version = "0.0.0";
src = ./.;
cargoSha256 = "0pihg88jx61a3bxm6n6h0fila34xgfnpgqrsdk4bw165bwmp5laq";
}

View File

@ -0,0 +1,47 @@
use std::rc::Rc;
use std::time::Duration;
use dht_hal_drv::{dht_split_init, dht_split_read, DhtType};
use spin_sleep;
use rppal::gpio::IoPin;
use crate::open_pin::OpenPin;
use crate::{Measurement, Sensor};
pub struct DHT22 {
location: Rc<String>,
pin: OpenPin,
}
impl DHT22 {
pub fn new(pin: IoPin, location: String) -> Self {
DHT22 {
location: Rc::new(location),
pin: OpenPin::new(pin),
}
}
}
impl Sensor for DHT22 {
fn read(&mut self) -> Vec<crate::Measurement> {
let mut delay_us = |d: u16| {
// We are using here more accurate delays than in std library
spin_sleep::sleep(Duration::from_micros(d as u64));
};
self.pin.switch_output();
if let Err(_) = dht_split_init(&mut self.pin, &mut delay_us) {
return vec![];
}
self.pin.switch_input();
// match dht_read(DhtType::DHT22, &mut opin, &mut delay_us) {
match dht_split_read(DhtType::DHT22, &mut self.pin, &mut delay_us) {
Ok(readings) => vec![
Measurement::new(self.location.clone(), "temperature", readings.temperature()),
Measurement::new(self.location.clone(), "humidity", readings.humidity()),
],
Err(_) =>
vec![]
}
}
}

View File

@ -0,0 +1,82 @@
use std::rc::Rc;
use std::time::Duration;
use rppal::gpio::{Gpio, Mode};
mod open_pin;
mod dht;
#[derive(Debug, Clone)]
pub struct Measurement {
pub location: Rc<String>,
pub type_: &'static str,
pub value: f64,
}
impl Measurement {
pub fn new<V: Into<f64>>(
location: Rc<String>,
type_: &'static str,
value: V,
) -> Self {
Measurement {
location, type_,
value: value.into(),
}
}
}
pub trait Sensor {
fn read(&mut self) -> Vec<Measurement>;
}
fn main() {
let hostname = std::fs::read("/proc/sys/kernel/hostname")
.expect("hostname");
let hostname = String::from_utf8_lossy(&hostname);
let hostname = hostname.trim();
let gpio = Gpio::new().expect("Can not init Gpio structure");
let mut args = std::env::args().skip(1);
let interval: u64 = args.next()
.expect("interval argument")
.parse()
.expect("interval integer");
let interval = Duration::from_secs(interval);
let mut sensors: Vec<Box<dyn Sensor>> = vec![];
while let Some(kind) = args.next() {
match &kind[..] {
"dht22" => {
let pin: u8 = args.next()
.expect("pin argument")
.parse()
.expect("pin integer");
let location = args.next()
.expect("location");
let iopin = gpio
.get(pin)
.expect("Was not able to get Pin")
.into_io(Mode::Input);
let dht = dht::DHT22::new(iopin, location);
sensors.push(Box::new(dht));
}
_ => panic!("Unknown sensor kind: {}", kind),
}
}
loop {
for sensor in &mut sensors {
for m in sensor.read() {
println!(
"PUTVAL {}/{}-{}/{}-{} interval={} N:{}",
hostname,
"sensors", "sensors-pi",
m.type_, m.location,
interval.as_secs(),
m.value
);
}
}
std::thread::sleep(interval);
}
}

View File

@ -0,0 +1,66 @@
use embedded_hal::digital::v2::{InputPin, OutputPin};
use rppal::gpio::{IoPin, Mode};
use void;
/**
* Raspberry pi does not have open drain pins so we have to emulate it.
*/
pub struct OpenPin {
iopin: IoPin,
mode: Mode,
}
impl OpenPin {
pub fn new(mut pin: IoPin) -> OpenPin {
pin.set_mode(Mode::Input);
OpenPin {
iopin: pin,
mode: Mode::Input,
}
}
pub fn switch_input(&mut self) {
if self.mode != Mode::Input {
self.mode = Mode::Input;
self.iopin.set_mode(Mode::Input);
}
}
pub fn switch_output(&mut self) {
if self.mode != Mode::Output {
self.mode = Mode::Output;
self.iopin.set_mode(Mode::Output);
}
}
}
// Current rppal implementation does not support embedded_hal::gpio::v2 pins API.
impl InputPin for OpenPin {
type Error = void::Void;
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.iopin.is_high())
}
/// Is the input pin low?
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.iopin.is_low())
}
}
// Current rppal implementation does not support embedded_hal::gpio::v2 pins API.
impl OutputPin for OpenPin {
type Error = void::Void;
fn set_low(&mut self) -> Result<(), Self::Error> {
self.switch_output();
self.iopin.set_low();
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
self.iopin.set_high();
self.switch_input();
Ok(())
}
}