don't send 0 values master
authorDobrica Pavlinusic <dpavlin@rot13.org>
Sun, 10 Mar 2024 13:14:51 +0000 (14:14 +0100)
committerDobrica Pavlinusic <dpavlin@rot13.org>
Sun, 10 Mar 2024 13:14:51 +0000 (14:14 +0100)
24 files changed:
README
alsamixer-left-53-70.png [new file with mode: 0644]
audio2influx.sh [new file with mode: 0755]
ble-mijia.sh [new file with mode: 0755]
datasheets/MH-Z19B.pdf [new file with mode: 0644]
debian-install.sh [new file with mode: 0755]
dsm501.pl [new file with mode: 0755]
dust.sh [new file with mode: 0755]
iio2mqtt.pl [new file with mode: 0755]
mh-z19b.pl [new file with mode: 0755]
mq.sh [new file with mode: 0755]
mq7.sh [new file with mode: 0755]
pms3003.pl
system/air-dsm501.service [new file with mode: 0644]
system/air-mh-z19b.service [new file with mode: 0644]
system/air-mq.service [new file with mode: 0644]
system/air-mq7.service [new file with mode: 0644]
system/air-pms3003.service [new file with mode: 0644]
system/air-zph02.service [new file with mode: 0644]
system/audio2influx.service [new file with mode: 0644]
system/ble-mijia@.service [new file with mode: 0644]
system/dust.service [new file with mode: 0644]
system/iio2mqtt.service [new file with mode: 0644]
zph02.pl

diff --git a/README b/README
index aa1c861..65b31d5 100644 (file)
--- 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 (file)
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 (executable)
index 0000000..a8a49cc
--- /dev/null
@@ -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 (executable)
index 0000000..908d63f
--- /dev/null
@@ -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 (file)
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 (executable)
index 0000000..451f31a
--- /dev/null
@@ -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 (executable)
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 (executable)
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 (executable)
index 0000000..50668f0
--- /dev/null
@@ -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 (executable)
index 0000000..52e3812
--- /dev/null
@@ -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 (executable)
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 (executable)
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
index 7c0205e..e90d1c0 100755 (executable)
@@ -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 (file)
index 0000000..724fe2c
--- /dev/null
@@ -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 (file)
index 0000000..fd6e52e
--- /dev/null
@@ -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 (file)
index 0000000..eed118f
--- /dev/null
@@ -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 (file)
index 0000000..2175f9c
--- /dev/null
@@ -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 (file)
index 0000000..a26ce98
--- /dev/null
@@ -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 (file)
index 0000000..26e1c8f
--- /dev/null
@@ -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 (file)
index 0000000..670f9d4
--- /dev/null
@@ -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 (file)
index 0000000..b12201c
--- /dev/null
@@ -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 (file)
index 0000000..2744a77
--- /dev/null
@@ -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 (file)
index 0000000..95ebc8a
--- /dev/null
@@ -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
index d0797d9..10f961e 100755 (executable)
--- 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";
                }
        }