rssi vs. relative humidity

receive signal strength indication vs. relative humidity data logger
receive signal strength indication vs. relative humidity data logger

I finally got around to deploying my rssi / temperature / relative humidity data logger and recorded nearly 6,000 samples of each metric over a five day period. This radio system operates in the ISM band, and is susceptible to propagation issues due to atmospheric conditions, especially humidity. The logic board provides a terminal that outputs a DC voltage that represents the rssi in dBm. My data logger uses a raspberry pi zero w, and reads the rssi voltage with an MCP3004 analog to digital converter using a bit-banged driver I wrote in perl. Each reading is timestamped using time derived from a DS3231 i2c real-time clock chip.

I use a HTU21 temperature / relative humidity sensor break out board from adafruit. This chip is MUCH MORE STABLE & RELIABLE than the DHT22 I was originally using.

temperature vs. relative humidity data capture
temperature vs. relative humidity data capture

For starters, here is the temperature in fahrenheit (red) vs. the relative humidity (green). Predictably, when the temperature rises, the relative humidity goes down and vice versa.

rssi level vs. relative humidity at 900MHz
rssi level vs. relative humidity at 900MHz

Now here is the relative humidity vs. the rssi. This radio is about 20 miles away from the transmitter over flat terrain with an output of 37dBm (5 watts), and has an average rssi of about -90dBm. You can see from the above graph that at about sample 4,000 when the relative humidity takes a noticeable dip that the rssi has a corresponding, albeit small, increase: precisely what we would expect to see.

Nothing surprising here. It just proves the effectiveness of my data logger device. It would be useful in situations where an RF path is going up and down due to atmospheric conditions or other obstructions, and real-time data would be useful in diagnosing problems and coming up with solutions like a higher gain antenna or increasing height.

homemade bluetooth work speaker that kicks

home made 25W stereo bluetooth speaker project
home made 25W stereo bluetooth speaker project

I have a huge project going on at work right now, and loud music is absolutely essential.  I ordered some Boss CH3220 140W speakers and used a 25W bluetooth audio amplifier board and whipped up in one evening a killer work speaker that kicks hard.

It is working great as is, but I am totally not done.  I am going to add a raspberry pi to play my saved mp3’s and roll some of my own features.

25W bluetooth audio amplifier board
25W bluetooth audio amplifier board

I am very impressed with the quality of the sound and how easy it was to pair with this board.  I tested the speakers with ‘dont tread on me’ by metallica.  The frequency response of these 3.5″ speakers is surprisingly very good.

data logging rssi on a GE MDS9710 with perl, dht22, and raspberry pi

pi zero w data logging temperature, rssi, and humidity
pi zero w data logging temperature, rssi, and humidity

I work on 900MHz point to multi-point data radio systems.  Humidity can greatly affect the propagation of rf waves at this frequency.  I wanted to do some data logging and analysis of how moisture in the air affected the received signal strength indication over time.

The GE MDS 9710 P70 radio system has an analog voltage test point that corresponds to the rssi on it’s interface board.  I used a DHT22 to measure the temperature and humidity,  an MCP3004  10-bit analog to digital converter to read the rssi voltage, and a pi zero W for the brains.

arduino nano every and DHT22. Readings displayed on 16X2 LCD
arduino nano every and DHT22. Readings displayed on 16X2 LCD

I originally implemented this project with an arduino nano every.   It worked great.  I was going to log the data by connecting the nano every to a pi zero via UART while a screen session was running on the pi with the screen output (STDOUT) saved to a file .  This method would require a logic level converter which I did not have on hand at the time, so I decided to implement the whole project on my pi zero.

It is much easier to use a DHT22 sensor with arduino using adafruit’s unified sensor library.

adafruit unified sensor library for DHT22
adafruit unified sensor library for DHT22

Here is the source:

// REQUIRES the following Arduino libraries:
// - DHT Sensor Library:
// - Adafruit Unified Sensor Lib:

#include "DHT.h"
#define DHTPIN 2     // Digital pin connected to the DHT sensor

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)


const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//number of samples
int sn = 0;

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("MDS RSSI Data   Logger");

void loop() {
  // Wait a few seconds between measurements.

  //increment sample number

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    Serial1.println(F("Failed to read from DHT sensor!"));

  //read rssi voltage
  int bv = analogRead(A0);
  float v = (5 * bv) / 1023.0;
  float rssi = v - 1.5;
  rssi = (rssi/0.8) * 20 - 120; 
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);

  //print to console
  Serial.print(F("Humidity: "));
  Serial.print(F("%  Temperature: "));
  Serial.print(F("°F  Heat index: "));

  //print to pi
  Serial1.print("Humidity: ");
  Serial1.print(F(" Temp: "));
  Serial1.print("F RSSI: ");

  lcd.print("F ");

To use perl to interface with the DHT22 on my pi required the RPi::PIGPIO::Device::DHT22 module on cpan.  Before I could use this,  I needed to install PIGPIO and run it as sudo before executing my script.  PIGPIO is a VERY interesting library for controlling a pi’s gpio’s locally or remotely via socket, and I will hopefully find the time to explore more possibilities in the near future.  It is, however, somewhat of a resource hog.

pigpiod daemon cpu resources on a raspberry pi
pigpiod daemon cpu resources on a raspberry pi

Once all the modules are loaded on the pi and the PIGPIO daemon is fired up,  I just had to translate the ardino C code into perl.

use strict;
require "/home/pi/gpio/";
use RPi::PIGPIO;
use RPi::PIGPIO::Device::DHT22;

loggs the temperature, humidity, and rssi of a
control point radio using a DHT22.  requires
PIGPIO daemon to be started first.  from home dir, 
cd/PIGPIO.  then, sudo pigpiod.  cd back into
gpio dir, and sudo perl  

my $pi = RPi::PIGPIO->connect('');
my $dht22 = RPi::PIGPIO::Device::DHT22->new($pi,23);

#ADC channel
my @ch0 = (1,1,0,0,0);

#init ADC

#open log file
open RD, ">", "ctc_data.log" or die $!;
#print table description
print RD "index,epoch,date,humidity,temperature,voltage,rssi\n";

my $i = 0;
	#formatted date string 
	my $time_str = `date`;
	print "$i\n";
	print $time_str;

	my $deg_f = ($dht22->temperature * (9/5)) + 32;
	#$deg_f = sprintf("%.1f", $deg_f);
	$deg_f = int($deg_f);

	print "Temp: $deg_f \n";
	my $humidity = $dht22->humidity;
	$humidity = sprintf("%.1f", $humidity);
	print "Humidity: ".$dht22->humidity."%\n";

	#take 5 samples from ADC and avg
	my $v_avg = 0;
	my $v_accum = 0;
	for(my $s=0;$s<5;$s++){
		my ($reading, $binval, $voltage ) = read3004(\@ch0, 50, 4.966);
		#print "binval: $binval\tvoltage: $voltage vdc\n";
		#print RD "$s\n$voltage\n";

		$v_accum += $voltage; 
	}#end for
	$v_avg = $v_accum / 5;
	$v_avg = sprintf("%.2f", $v_avg);
	#print "avg: $v_avg\n";
	#calculate RSSI
	my $rssi = 0;
	$rssi = $v_avg - 1.5;
	$rssi = ($rssi / 0.8) * 20;
	$rssi -= 120;
	#format rssi
	$rssi = sprintf("%.2f", $rssi);
	print "rssi: $rssi dBm \n";
	print "-----------------------------------\n";

	#print to LCD
	`./lcd "Humidity: $humidity%     $deg_f F $rssi dBm"`;

	#print to log file
	my $log_str = '';
	my $uts = time;
	my $hr_time = localtime();
	$log_str = "$i,$uts,$hr_time,$humidity,$deg_f,$v_avg,$rssi\n";	
	select((select(RD), $|=1)[0]);
	print RD $log_str;

}#end for

close RD;

So far, it’s working great on the test bench.

pi zero rssi humidity data logger
pi zero rssi humidity data logger

Forgot to mention.  I used a DS3231 real time clock to keep time on the pi.  It works great and was easy to set up using this tutorial.

DS3231 RTC on pi zero
DS3231 RTC on pi zero

I will be deploying the data logger in the field this week and will post the results.  My bench test results are as follows.  Here is my humidity graph after nearly 9K samples.

dht22 humidity readings with pi zero w
dht22 humidity readings with pi zero w

And here is the rssi over the same dataset.  You can definitely see a higher rssi when the humidity is lower as expected.

rssi readings using raspberry pi
rssi readings using raspberry pi

family alarm clock project III

trinket Pro 5V 16MHz based alarm clock / stereo project using a PCF8523 real time clock breakout from adafruit
trinket Pro 5V 16MHz based alarm clock / stereo project using a PCF8523 real time clock breakout from adafruit

Nearly done with our family project.  It has been so much fun, and I hate that it’s nearly over, but Eli and Addy are pumped for another project.  The maker space  has been the new cool hangout:  loud music, chips + cheese dip, Teen titans Go, roller skating, and making a killer boom box that everybody loves.

trinket Pro 5V 16MHz based alarm clock / stereo project using a PCF8523 real time clock breakout from adafruit
the brains is a trinket Pro 5V 16MHz

This is my first project with a trinket Pro.  I love this platform.  Tiny, cheap, powerful,  easy to use; comparable to an arduino nano.  I did run out of GPIO pins (mostly due the the 16×2 LCD display), but got around it adding an MCP23008 for the alarm control buttons (also using libraries from adafruit) .

PCF8523 adafruit trinktet project
It’s adisaster on the inside, but pretty cool on the outside.

family alarm clock project II

We are making progress on our alarm clock / boom box project.  Eli soldered the 220 ohm resistors to the cathodes of the LEDs for the hours and Addy soldered the common ground wire to the resistors, hot glued them to the clock face, and tested them with a 6V battery.  I re-purposed an old POW3U prototype board for the 10 74HC595 shift registers we will need for the LEDs (they hate when I help!).  We put together what we have of the cabinet so far, and it looks pretty cool.  Not only that, it THUMPS!  Tested it with Wildflower from The Cult.  The kids are more enthused with seeing the progress.

The PCF8523 RTC breakout came in.  I downloaded the RTC libraries from Adafruit and ran the example scripts.  I am very impressed.  I will definitely buy more for other projects.  I connected it to an old CHIP pro I have and experimented with it just using i2cget commands reading the different registers and it seems to be an easy , straightforward RTC IC to use.  It is really coming together.

array of 74HC595 shift registers to drive our LED clock on a POW3U prototype board
array of 74HC595 shift registers to drive our LED clock on a POW3U prototype board

alarm clock / boom box cabinet front
alarm clock / boom box cabinet front

cabinet back view with sub woofer

family alarm clock project

Eli, Addy, and I are working on an arduino-based LED alarm clock project.  The design is totally Eli’s idea.  He wants 60 LEDs around the face of the clock for the minutes, and 12 LEDs on the top for the hour.  We gutted the audio system from one of their old gaming chairs that got tore up, and are using it for the sound.  I ordered a PCF8523 real time clock breakout board from adafruit to keep time, and are going to use a 5V 16MHz Trinket Pro for the brains. With over 72 LEDs to drive, we plan on using 10 74HC595 shift registers.  We are also going to use a 16X2 LCD display to show the time and maybe temperature.  So far, Eli has cut all the pieces out with a jig saw and he and Addy drilled all the holes for the LEDs.  Eli soldered a 220 Ohm resistor to the cathode of all the LEDs, and Addy used a glue gun to fasten them to the clock face.  I am new to arduino, so I am experimenting with using it to drive the LCD and the 74HC595’s.

Elegoo Uno driving a 16X2 LCD and 74595 shift register

family LED clock project

pi pet camera

We’re on spring break this week, and couldn’t get any takers to look after out guinea pig, Mon$ter.  The plan was to just put lots of extra food and water in his habitat.  I repurposed my pi-zero based front door security device (because we replaced it with a ring) and set it up to take a picture of Mon$ter every hour, and post it on my home web server so we can see how he’s doing.

rasspberry pi pet cam
Screenshot of my web browser pet cam app

pi zero w with camera and 12VDC lead-acid backup battery
pi zero w with camera and 12VDC lead-acid backup battery facing Mon$ter’s cage

Here’s the simple script.  It makes some system calls to some other scripts I wrote to scp the images to the web server.

DIY Home security with Raspberry pi zero w + Perl

I got a ring doorbell for Christmas.  It was a very thoughtful gift and I gotta admit it is very slick.  However, for some time, I have been using a home made security system based on the raspberry pi zero w and perl.

home made home security node based on pi zero w
home made home security node based on pi zero w

I designed it so that each node sends udp messages to a udp + LAMP server. I can view all the events on the server’s web interface.

UDP server receiving message from a node
UDP server receiving message from a node

The front-door node also has a TMP36 temperature sensor read by an MCP3008 adc, and a raspberry pi camera.  When the door is opened, it takes a picture two seconds later, and uploads it to the LAMP server.

diy home security web interface
diy home security web interface

I set up port forwarding on my ISP router so I can view my LAMP server from anywhere.

The udp client and server scripts are incredibly simple.

perl udp client script
perl udp client script

perl udp server script
perl udp server script

tmp36 + MCP3008 schematic
tmp36 + MCP3008 schematic

entry contact and LCD schematic
entry contact and LCD schematic

I go into somewhat more detail on my hackster account.  Off-the-shelf home security and automation products are fairly inexpensive and easy to set up nowadays, but for me, it’s just so much fun to build my own from scratch.

analyzing SPI on an MCP3208 12-bit analog to digital converter

The MCP3208 12-bit analog-to-digitial converter is the basis of my battery load test analyzer and online monitoring system which I call pid3A .  As I have mentioned before,  I implemented a bit-banged SPI driver for the mcp3208 in the perl programming language.  I use the analog-to-digital converters (adc’s) to sample the voltages of each cell in the battery plant at regular intervals to make graphs of the discharge curves.

MCP3208 Analog to digital converter
MCP3208 Analog to digital converter

pid3A is in it’s 2nd prototype and can accurately measure up to 24 cell voltages at a time with it’s three 8-channel mcp3208’s.  Occasionally, I will burn up a single channel on one of the adc’s, rendering the whole chip useless for my application.

I have written a lot of diagnostic software for pid3A to make sure the adc’s are functioning properly before I begin an IEEE450  load test.  To test all 24 channels, I made a test plug that puts 2.5VDC on each channel, takes 5 samples, and give the the binary output code and actual voltage of each sample.  It then gives me a color-coded go/no-go visual indication.  If there are any bad channels, I just change out the adc chip and re-run the diagnostic test.

mcp3208 test plug
pid3A test plug

Here is a sample of the output:

mcp3208 diagnostics
diagnostic testing of each ADC channel

You can see that the adc output codes and voltages are very steady.  The voltage is a function of the digital output code of the adc.  Above, most of the output codes are 2049.  Knowing this, and the reference voltage of 4.998VDC, you can calculate the actual voltage using this equation:

mcp3208 digital output code equation
mcp3208 digital output code equation

This is absolutely necessary for troubleshooting quickly, but sometimes I need to know what is going on at a microscopic level.  My multi-channel logic analyzer is the perfect tool to look at the underlying SPI protocol.

IEEE450 battery load test analyzer
IEEE450 battery load test analyzer

I know this just looks like a mess of wires, but I have my logic analyzer hooked up to the data-in, data-out, chip select, and clock lines of one of my mcp3208 chips.  Here is a close up of a frame from my diagnostic script:

SPI examination using PulseView
SPI examination using PulseView

This shows the driver clocking in 19 pulses.  The first few bits on the MOSI line tell the adc to use single (as opposed to differential) mode, and sample channel 001.  The rest of the MOSI bits are ‘don’t care’ bits, so my driver just set them all high.  The MISO line is the mcp3208 clocking out the actual binary output code.  In this case it is 2045, which in binary is 011111111101.  The slave select line goes low to initiate a sample, and goes high when finished.  PulseView shows me precisely what is happening, and lets me easily analyze the SPI protocol for proper function per the datasheet below:

mcp3208 SPI protocol framing
mcp3208 SPI protocol framing

using the MCP23008 gpio expander with chip Pro and perl

I’ve mentioned the next thing co.  chip family of single board computers before.  It was billed as the world’s first $9 computer.  I first heard of it on NPR one morning and couldn’t get to a computer to pre-order one fast enough.  A full-blown debian distribution, wifi, i2c, SPI, 8-gpio pins, composite video, UART, USB and more about the size of a credit card.  It seemed too good to be true.  I guess it was, because they did not last long.  I bought 15 of them, but never received the last five before they tanked.  They also came out with the chip Pro,  an even smaller, somewhat stripped down version of the chip aimed at being a platform for mass-produced products for $16.  I really liked the optional ufl wifi antenna port.  With an external high-gain antenna, it is really great at sniffing wifi networks.   It is totally awesome, and I wish I had 100 of them.

chip pro
chip Pro

Sadly, I burned up all my gpio pins on a project.  I didn’t want to scrap my chip pro, however, and decided to use the MCP23008 gpio I/O expander to get my gpio back up and working.

I wrote my own easy to use perl based driver to interface with the MCP23008.  There are some great tools on CPAN that implement I2C for stuff like this, but I went an even simpler route.  My driver (at a mere 40 lines of code)  uses system calls (via backticks)  to read and write to registers on the gpio expander.  For example, to read the gpio register, the script will just make a system call like so:

sudo i2cget -y 1 0X20 0x09

This tells the chip Pro to talk to the i2c device on bus 1, at address 0x20, and read the value in register 0x09 (gpio register).   Here is the driver in it’s entirety:

#!/usr/bin/perl -w
use strict;

utilities for MCP23008 gpio extender
execute any scripts that use this as sudo

#global variables
my $address;
my $gpio_w = 0;

sub gpio_enable{
	#function takes the i2c address of the MCP23008
	#it also  sets the IO direction
	#register.  Must be a value from 0-255
	#1 is input, 0 is output

	$address = $_[0];
	my $ioreg_val = $_[1];

	#write io reg
	`i2cset -y 1 $address 0x00 $ioreg_val`;
}#end gpio_enable

sub gpio_read{
	#function uses i2cget to
	#read gpio register 0x09
	my $reading = `i2cget -y 1 $address 0x09`;
	return $reading;
}#end gpio_read

sub gpio_write{
	#takes int from 0-255 to write to the
	#gpio register
	$gpio_w = $_[0];
	`i2cset -y 1 $address 0x09 $gpio_w`;
}#end gpio_write


So simple, I’m embarrassed, but it works great.  To test, I wrote a simple script that visually counts to 255 in binary with LED output.

perl mcp23008 driver
i2c mcp23008 binary counter with chip Pro and perl

Here is the script:

use strict;
use Time::HiRes qw(usleep);
require '';

#init the 23008 IO register as output
gpio_enable(0x20, 0);

for(my $i=0;$i<256;$i++){
}#end for