From: Dobrica Pavlinusic Date: Sun, 10 Mar 2024 13:14:51 +0000 (+0100) Subject: don't send 0 values X-Git-Url: http://git.rot13.org/?p=air-quality;a=commitdiff_plain;h=HEAD;hp=17cf177ad6527eb453f851cf8ae9d3bf2943df08 don't send 0 values --- diff --git a/README b/README index aa1c861..65b31d5 100644 --- a/README +++ b/README @@ -1,6 +1,8 @@ Experiments with air quality sensors -Scripts in this directory talk to sensors and store data into influxdb. +Scripts in this directory read from sensor serial port output (which +is 3.3V serial connected to usb serial dongle) and store data to +influxdb using curl. When receiving data from sensors, they check header and checksum to avoid sending garbage data. This also helps when you select wrong @@ -10,3 +12,24 @@ network latency to influxdb (which is somewhere in the cloud, and latency can vary just enough to create empty vertical stripes in graphs which is ugly and incorrect). + +Exception to that rule is dsm501.pl which is general serial to +influx bridge used by helper shell scripts to handle sensors +which require 5V by connecting them to Arduino-like mcu. +Example of that is: + +mq7.sh + +which uses https://github.com/dpavlin/mq7-co-monitor/ + +on Arduino to produce output which is then fed to dsm501.pl. + + +Another strage one is audio2influx.sh which doesn't require +any external hardware but instead report sox info about 1s +or audio to influxdb. I'm using this to passivly monitor +fan rotation by connecting it directly to microphone input +on netbook and adjusting input gain to prevent clipping +using alsamixer. + +To make alsamixer work, I had to remove pulseaudio. diff --git a/alsamixer-left-53-70.png b/alsamixer-left-53-70.png new file mode 100644 index 0000000..af574ff Binary files /dev/null and b/alsamixer-left-53-70.png differ diff --git a/audio2influx.sh b/audio2influx.sh new file mode 100755 index 0000000..a8a49cc --- /dev/null +++ b/audio2influx.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +while true ; do + +arecord -d 1 -r 96000 /dev/shm/tmp.wav 2>/dev/null +time=`date +'%s%N'` +info=`sox /dev/shm/tmp.wav -n stat 2>&1 | grep '[0-9][0-9][0-9]*$' | sed -e 's/[()]//g' -e 's/: */=/' -e 's/ */_/g' | tee /dev/shm/audio | tr '\n' ',' | sed 's/[, ]*$//'` +curl --silent -XPOST 'http://10.60.0.92:8086/write?consistency=any&db=rot13' --data-binary "fan,dc=trnjanska $info $time" + +done diff --git a/ble-mijia.sh b/ble-mijia.sh new file mode 100755 index 0000000..908d63f --- /dev/null +++ b/ble-mijia.sh @@ -0,0 +1,12 @@ +#!/bin/sh -e +mac=A4:C1:38:90:DC:63 +test ! -z "$1" && mac=$1 + +# based on https://ndimension.design.blog/2021/12/16/reading-data-from-xiaomi-mi-temperature-and-humidity-monitor-2-lywsd03mmc/ +# find sensor with: sudo hcitool lescan +# A4:C1:38:D8:3F:9C LYWSD03MMC + +gatttool -b $mac --char-write-req --handle='0x0038' --value="0100" --listen | \ + awk 'BEGIN { OFS=","; ORS="\n" } /value:/ { print "temperature=" strtonum("0x"$7$6) / 100, "humidity=" strtonum("0x"$8), "battery=" strtonum("0x"$10$9) / 1000 ; fflush() }' | \ + xargs -i curl --silent -XPOST 'http://10.60.0.92:8086/write?consistency=any&db=rot13' --data-binary "mijia,dc=trnjanska,mac=$mac {}" + diff --git a/datasheets/MH-Z19B.pdf b/datasheets/MH-Z19B.pdf new file mode 100644 index 0000000..9b762ae Binary files /dev/null and b/datasheets/MH-Z19B.pdf differ diff --git a/debian-install.sh b/debian-install.sh new file mode 100755 index 0000000..451f31a --- /dev/null +++ b/debian-install.sh @@ -0,0 +1,3 @@ +#!/bin/sh -xe + +apt install libdevice-serialport-perl libdata-dump-perl diff --git a/dsm501.pl b/dsm501.pl new file mode 100755 index 0000000..0a237a7 --- /dev/null +++ b/dsm501.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +use warnings; +use strict; +# sudo apt install libdevice-serialport-perl libdata-dump-perl +use Device::SerialPort; +use Time::HiRes; +use Data::Dump qw(dump); + +my $port = shift @ARGV || '/dev/serial/by-path/platform-3f980000.usb-usb-0:1.3:1.0-port0'; +my $influx_url = shift @ARGV || 'http://192.168.3.40:8086/write?consistency=any&db=rot13'; +my $measurement = $ENV{MEASUREMENT} || 'dsm501'; + +my $s = new Device::SerialPort( $port ) || die $!; +$s->baudrate(115200); +$s->databits(8); +$s->parity('none'); +$s->stopbits(1); +$s->handshake('none'); +$s->read_char_time(0); # don't wait for each char +$s->read_const_time(200); # ms for complete read + + +while (1) { + + my ($len, $string) = $s->read(128); + my $t = int( Time::HiRes::time() * 1_000_000_000 ); + die $! if ! defined($len); + if ( $len > 0 ) { + #warn "# len=$len ",dump($string); + if ( $string !~ m/^#/ ) { + $string =~ s/[\r\n]+$//; + $string =~ s/\s/,/g; + my $influx = "$measurement,dc=trnjanska $string $t"; + print "$influx\n" if -e '/dev/shm/air-debug'; + system "curl --silent -XPOST '$influx_url' --data-binary '$influx'" + } else { + warn "SKIP: $string\n"; + } + } + +}; + + +$s->close; diff --git a/dust.sh b/dust.sh new file mode 100755 index 0000000..47c9b28 --- /dev/null +++ b/dust.sh @@ -0,0 +1,4 @@ +#!/bin/sh -xe + +cd /nuc/air-quality/ +MEASUREMENT=dust ./dsm501.pl /dev/ttyACM0 diff --git a/iio2mqtt.pl b/iio2mqtt.pl new file mode 100755 index 0000000..50668f0 --- /dev/null +++ b/iio2mqtt.pl @@ -0,0 +1,64 @@ +#!/usr/bin/perl +use warnings; +use strict; + +use Time::HiRes; + +# sudo apt install libiio-utils mosquitto-clients + +my $influx_url = shift @ARGV || 'http://192.168.3.40:8086/write?consistency=any&db=rot13'; + +my $delay = $ENV{DELAY} || 1; + +my $hostname = `hostname -s`; +chomp($hostname); + +while(1) { + + my $t = Time::HiRes::time; + my $t_influx = int( $t * 1_000_000_000 ); + + my $iio = `iio_info`; + + my $device; + my $name; + + my $influx = ''; + + foreach ( split(/\n/, $iio) ) { + if ( m/iio:device\d+:\s+(\S+)/ ) { + $device = $1; + + if ( $influx =~ m/,$/ ) { + $influx =~ s/,$/ $t_influx\n/; + } elsif ( $influx =~ m/ $/ ) { # only device + $influx =~ s/\S+\s$//; + } + $influx .= "iio,dc=trnjanska,host=$hostname,device=$device "; + + } elsif ( m/(\S+):\s+\(input\)/ ) { + $name = $1; + } elsif ( m/attr\s+0:\s+input\svalue: (\d+[\.\d]+)/ ) { + my $val = $1; + if ( $val !~ m/\d+\.\d+/ ) { + $val = $val / 1000; + } + my $topic = "iio/$hostname/$device/$name"; + #print "$topic $val\n"; + system "mosquitto_pub -h rpi2 -t $topic -m $val"; + + $influx .= "$name=$val,"; + } else { + #warn "# $_\n"; + } + } + + $influx =~ s/,$/ $t_influx/; + system "curl --silent -XPOST '$influx_url' --data-binary '$influx'"; + warn "$influx\n"; + + my $dt = Time::HiRes::time + $delay - $t - 0.01; + if ( $dt > 0 ) { + sleep $dt; + } +} diff --git a/mh-z19b.pl b/mh-z19b.pl new file mode 100755 index 0000000..52e3812 --- /dev/null +++ b/mh-z19b.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +use warnings; +use strict; +# sudo apt install libdevice-serialport-perl libdata-dump-perl +use Device::SerialPort; +use Time::HiRes; +use Data::Dump qw(dump); + +my $port = shift @ARGV || '/dev/serial/by-path/platform-3f980000.usb-usb-0:1.5:1.2'; +my $influx_url = shift @ARGV || 'http://192.168.3.40:8086/write?consistency=any&db=rot13'; + +my $s = new Device::SerialPort( $port ) || die $!; +$s->baudrate(9600); +$s->databits(8); +$s->parity('none'); +$s->stopbits(1); +$s->handshake('none'); +$s->read_char_time(1); +$s->read_const_time(10); +$s->debug(1); + +$s->write("\xFF\x01\x86\x00\x00\x00\x00\x00\x79"); + +while (1) { + + my ($len, $string) = $s->read(9); + my $t = int( Time::HiRes::time() * 1_000_000_000 ); + die $! if ! defined($len); + if ( $len > 0 ) { + my @v = unpack('C*', $string); + if ( $#v < 8 ) { + die "# $len ",dump($string), dump( @v ), $/; + } + + my $sum = 0; + foreach my $i ( 1 .. $#v - 1 ) { + $sum += $v[$i]; + $sum = $sum & 0xff; + } + $sum = 0xff - $sum + 1; + + my $checksum = $v[8]; + my $co2 = $v[2] * 255 + $v[3]; + if ( $v[0] == 0xff && $sum == $checksum ) { + my $influx = "mh-z19b,dc=trnjanska co2=$co2 $t"; + print "$influx\n" if -e '/dev/shm/air-debug'; + system "curl --max-time 2 --silent -XPOST '$influx_url' --data-binary '$influx'"; + system "mosquitto_pub -h rpi2 -t 'air/mh-z19b/co2' -m $co2"; + } else { + die "checksum error"; + } + sleep 1; + $s->write("\xFF\x01\x86\x00\x00\x00\x00\x00\x79"); + } + +}; + + +$s->close; diff --git a/mq.sh b/mq.sh new file mode 100755 index 0000000..83ba1f6 --- /dev/null +++ b/mq.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +MEASUREMENT=mq /home/dpavlin/air-quality/dsm501.pl /dev/serial/by-path/pci-0000:00:1d.0-usb-0:2:1.0-port0 'http://10.60.0.92:8086/write?consistency=any&db=rot13' # debee diff --git a/mq7.sh b/mq7.sh new file mode 100755 index 0000000..7713a6d --- /dev/null +++ b/mq7.sh @@ -0,0 +1,4 @@ +#!/bin/sh -xe + +# https://github.com/dpavlin/mq7-co-monitor/ +MEASUREMENT=mq7 /home/pi/air-quality/dsm501.pl /dev/serial/by-path/platform-3f980000.usb-usb-0:1.2:1.0-port0 diff --git a/pms3003.pl b/pms3003.pl index 7c0205e..e90d1c0 100755 --- a/pms3003.pl +++ b/pms3003.pl @@ -6,9 +6,8 @@ use Device::SerialPort; use Time::HiRes; use Data::Dump qw(dump); -my $port = shift @ARGV || '/dev/ttyUSB0'; -my $influx_url = shift @ARGV || 'http://10.13.37.229:8186/write?db=telegraf'; -$influx_url = 'http://10.13.37.92:8086/write?db=rot13'; +my $port = shift @ARGV || '/dev/serial/by-path/platform-3f980000.usb-usb-0:1.3:1.0-port0'; +my $influx_url = shift @ARGV || 'http://192.168.3.40:8086/write?consistency=any&db=rot13'; my $debug = $ENV{DEBUG} || 0; @@ -60,8 +59,8 @@ while (1) { }; $influx =~ s/,$//; $influx .= " $t"; - print "$influx\n"; - system "curl --silent -XPOST '$influx_url' --data-binary '$influx'" + print "$influx\n" if -e '/dev/shm/air-debug'; + system "curl --max-time 2 --silent -XPOST '$influx_url' --data-binary '$influx'" } } diff --git a/system/air-dsm501.service b/system/air-dsm501.service new file mode 100644 index 0000000..724fe2c --- /dev/null +++ b/system/air-dsm501.service @@ -0,0 +1,10 @@ +[Unit] +Description=Air + +[Service] +User=dpavlin +ExecStart=/home/dpavlin/air-quality/dsm501.pl +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/system/air-mh-z19b.service b/system/air-mh-z19b.service new file mode 100644 index 0000000..fd6e52e --- /dev/null +++ b/system/air-mh-z19b.service @@ -0,0 +1,11 @@ +[Unit] +Description=Air + +[Service] +User=pi +ExecStart=/home/pi/air-quality/mh-z19b.pl +Restart=always +RestartSec=1s + +[Install] +WantedBy=multi-user.target diff --git a/system/air-mq.service b/system/air-mq.service new file mode 100644 index 0000000..eed118f --- /dev/null +++ b/system/air-mq.service @@ -0,0 +1,10 @@ +[Unit] +Description=Air + +[Service] +User=dpavlin +ExecStart=/home/dpavlin/air-quality/mq.sh +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/system/air-mq7.service b/system/air-mq7.service new file mode 100644 index 0000000..2175f9c --- /dev/null +++ b/system/air-mq7.service @@ -0,0 +1,11 @@ +[Unit] +Description=Air + +[Service] +User=pi +ExecStart=/home/pi/air-quality/mq7.sh +Restart=on-failure +RestartSec=2s + +[Install] +WantedBy=network-online.target diff --git a/system/air-pms3003.service b/system/air-pms3003.service new file mode 100644 index 0000000..a26ce98 --- /dev/null +++ b/system/air-pms3003.service @@ -0,0 +1,11 @@ +[Unit] +Description=Air + +[Service] +User=pi +ExecStart=/home/pi/air-quality/pms3003.pl +Restart=on-failure +RestartSec=2s + +[Install] +WantedBy=network-online.target diff --git a/system/air-zph02.service b/system/air-zph02.service new file mode 100644 index 0000000..26e1c8f --- /dev/null +++ b/system/air-zph02.service @@ -0,0 +1,11 @@ +[Unit] +Description=Air + +[Service] +User=pi +ExecStart=/home/pi/air-quality/zph02.pl +Restart=always +RestartSec=3s + +[Install] +WantedBy=multi-user.target diff --git a/system/audio2influx.service b/system/audio2influx.service new file mode 100644 index 0000000..670f9d4 --- /dev/null +++ b/system/audio2influx.service @@ -0,0 +1,10 @@ +[Unit] +Description=audio to influx + +[Service] +User=dpavlin +ExecStart=/home/dpavlin/air-quality/audio2influx.sh +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/system/ble-mijia@.service b/system/ble-mijia@.service new file mode 100644 index 0000000..b12201c --- /dev/null +++ b/system/ble-mijia@.service @@ -0,0 +1,11 @@ +[Unit] +Description=Xiomi Mijia %i + +[Service] +User=pi +ExecStart=/home/pi/air-quality/ble-mijia.sh %i +Restart=always +RestartSec=3s + +[Install] +WantedBy=network-online.target diff --git a/system/dust.service b/system/dust.service new file mode 100644 index 0000000..2744a77 --- /dev/null +++ b/system/dust.service @@ -0,0 +1,11 @@ +[Unit] +Description=dust sensor + +[Service] +User=dpavlin +ExecStart=/nuc/air-quality/dust.sh +Restart=always +RestartSec=2s + +[Install] +WantedBy=multi-user.target diff --git a/system/iio2mqtt.service b/system/iio2mqtt.service new file mode 100644 index 0000000..95ebc8a --- /dev/null +++ b/system/iio2mqtt.service @@ -0,0 +1,11 @@ +[Unit] +Description=iio2mqtt + +[Service] +User=dpavlin +ExecStart=/home/dpavlin/air-quality/iio2mqtt.pl +Restart=always +RestartSec=2s + +[Install] +WantedBy=multi-user.target diff --git a/zph02.pl b/zph02.pl index d0797d9..10f961e 100755 --- a/zph02.pl +++ b/zph02.pl @@ -6,9 +6,8 @@ use Device::SerialPort; use Time::HiRes; use Data::Dump qw(dump); -my $port = shift @ARGV || '/dev/ttyUSB0'; -my $influx_url = shift @ARGV || 'http://10.13.37.229:8186/write?db=telegraf'; -$influx_url = 'http://10.13.37.92:8086/write?db=rot13'; +my $port = shift @ARGV || '/dev/serial/by-path/platform-3f980000.usb-usb-0:1.5:1.0'; +my $influx_url = shift @ARGV || 'http://192.168.3.40:8086/write?consistency=any&db=rot13'; my $s = new Device::SerialPort( $port ) || die $!; $s->baudrate(9600); @@ -22,6 +21,11 @@ $s->read_const_time(10); while (1) { + alarm 3; + # Usb serial which I'm using is buggy and blocks from time to time. + # This will ensure that we have passed here every 3 seconds + # or we will be killed and systemd will restart us + my ($len, $string) = $s->read(9); my $t = int( Time::HiRes::time() * 1_000_000_000 ); die $! if ! defined($len); @@ -39,10 +43,11 @@ while (1) { my $checksum = $v[8]; my $pcnt = $v[3] + ( $v[4] / 100 ); - if ( $v[0] == 0xff && $sum == $checksum ) { + if ( $v[0] == 0xff && $sum == $checksum && $pcnt > 0) { my $influx = "zph02,dc=trnjanska pm25_pcnt=$pcnt $t"; - print "$influx\n"; - system "curl --silent -XPOST '$influx_url' --data-binary '$influx'" + print "$influx\n" if -e '/dev/shm/air-debug'; + system "curl --max-time 2 --silent -XPOST '$influx_url' --data-binary '$influx'"; + system "mosquitto_pub -h rpi2 -t 'air/zph02/pm25' -m $pcnt"; } }