arduino based hvac lead-lag controller

arduino lead-lag hvac control
Installed lead-lag controller
arduino lead-lag hvac control
arduino lead-lag hvac control
arduino hvac lead-lag controller
lead-lag controller using arduino nano

My office is in a telecommunications facility full of routers, radios, fiber-optic equipment etc. Reliable environmental controls are essential as this equipment will fail in extreme heat. I have two 20,000 BTU AC units in my office that run on 250VAC. I created this lead-lag controller to turn on the lead AC unit based on the temperature setting, and if the lead unit has run for six minutes without cooling to the setting, turns on the lag unit as well until the temperature setting is reached.

arduino lead-lag hvac controller
arduino lead-lag hvac controller

I have the programming down and the device built and installed. Initial tests work as designed. I am using some 10A 250VAC power relays. With the unit running on high fan speed and the compressor going the AC units draw about 5 amps; well within the rage of the relays.

the lead / lag controller turns on/off the 250VAC outlets of the air conditioner units

Here is the code ->

// include the library code:
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "RTClib.h"
RTC_DS3231 rtc;

// Sensor input pin
#define DATA_PIN 2
// How many bits to use for temperature values: 9, 10, 11 or 12
#define SENSOR_RESOLUTION 9
// Index of sensors connected to data pin, default: 0
#define SENSOR_INDEX 0

OneWire oneWire(DATA_PIN);
DallasTemperature sensors(&oneWire);
DeviceAddress sensorDeviceAddress;

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int sample_num = 0;

//thermostat setting; init to 72
int setting = 70; 

//heat or cool mode
char mode = 'C';

//relay pins
const int ac1Pin = 5;
const int ac2Pin = 4;
//const int heatPin = 6;

//control buttons
const int modePin = 3;
const int decrPin = 6;
const int incrPin = 0;

//AC ON/OFF flags
int ac1_f = 0;
int ac2_f = 0;
int heat_f = 0;

//on timers
int ac1_timer = 0;
int ac2_timer = 0;

//RTC stuff
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  Serial.begin(9600);

  //AC1 relay
  pinMode(ac1Pin, OUTPUT); 
  pinMode(ac2Pin, OUTPUT);
  //pinMode(heatPin, OUTPUT);

  //set AC1 off
  digitalWrite(ac1Pin, LOW);
  digitalWrite(ac2Pin, LOW);
  //digitalWrite(heatPin, LOW);    

  //control buttons
  pinMode(modePin, INPUT);
  pinMode(decrPin, INPUT);
  pinMode(incrPin, INPUT);

  sensors.begin();
  sensors.getAddress(sensorDeviceAddress, 0);
  sensors.setResolution(sensorDeviceAddress, SENSOR_RESOLUTION);  

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }  
}

  //array to hold 12 readings; 5-per min
  float t_readings[12];

  //sum of readings
  float sum = 0.0;

  //avg of readings
  float average = 0.0;

void loop() {
  
  // set the cursor to (0,0):
  lcd.setCursor(0, 0);

  //reset sum and avg on each iteration
  sum = 0;
  average = 0;

  //12 sample loop; takes 1 min
  for(int x=0;x<12; x++){
    lcd.setCursor(0, 0);
    sensors.requestTemperatures();
    // Measurement may take up to 750ms

    float temperatureInCelsius = sensors.getTempCByIndex(SENSOR_INDEX);
    float temperatureInFahrenheit = sensors.getTempFByIndex(SENSOR_INDEX);
  
    Serial.print("Temperature: ");
    Serial.print(temperatureInCelsius, 1);
    Serial.print(" Celsius, ");
    Serial.print(temperatureInFahrenheit, 1);
    Serial.print(" x: ");
    Serial.print( x );
    Serial.println(" Fahrenheit"); 

    //push reading into array
    t_readings[x] = temperatureInFahrenheit;
  
    lcd.print(temperatureInFahrenheit);
    lcd.print("F");
    //lcd.setCursor(0, 1);
    //lcd.print(sample_num);
    //sample_num++;

    if(digitalRead(modePin) == LOW){
      Serial.println("MODE BUTTON PRESSED! ENTERING SETUP....");
      setTemp();
    }//end if mode pressed

    //print setting to lcd row 2
    lcd.setCursor(0, 1);
    lcd.print("Setting: ");
    lcd.print(setting);    

    //print mode
    lcd.setCursor(15,0);
    lcd.print(mode);

    delay(5000);  //sleep 5 sec
  }//end for loop 12 sample

  //average samples
  for(int i=0; i<12; i++){
    sum = sum + t_readings[i];
  }//end for avg
    Serial.print("sum: ");
    Serial.println(sum);
    average = sum / 12;
    Serial.print("avg: ");
    Serial.println(average);

    //AC relay control
    if(average > setting && mode == 'C'){
      digitalWrite(ac1Pin, HIGH);

      //flag logic
      if(ac1_f == 0){ ac1_f = 1;}

      //timer logic
      ac1_timer += 60;    //60 because of the 12 samples/min cycle
      Serial.print("AC UNIT 1 ON ");
      Serial.print(ac1_timer);
      Serial.print(" seconds ");

      if(ac1_timer > 60){//turn on ac2 after 30 minutes
        if(ac2_f == 0){ 
          ac2_f = 1; 
          digitalWrite(ac2Pin, HIGH);
        }
        else{
          //increment ac2_timer
          ac2_timer += 60;
        }
        Serial.print("AC UNIT 2 ON ");
        Serial.print(ac2_timer);
        Serial.print(" seconds ");
      }//end if turn on AC2

      //poll RTC for time
      DateTime now = rtc.now();
   
      Serial.print(now.year(), DEC);
      Serial.print('/');
      Serial.print(now.month(), DEC);
      Serial.print('/');
      Serial.print(now.day(), DEC);
      Serial.print(" "); 
      Serial.print(" (");
      Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
      Serial.print(") ");
      Serial.print(now.hour(), DEC);
      Serial.print(':');
      Serial.print(now.minute(), DEC);
      Serial.print(':');
      Serial.println(now.second(), DEC);
    }//end if
    if(average < setting && mode == 'C'){
      //turn AC1 OFF, reset timer & flags
      digitalWrite(ac1Pin, LOW);
      ac1_f = 0;
      ac1_timer = 0;
      Serial.print("AC UNIT 1 OFF ");

      //if on, turn off AC2
      if(ac2_f == 1){
          digitalWrite(ac2Pin, LOW);
          ac2_f = 0;
          ac2_timer = 0;
          Serial.print("AC UNIT 2 OFF ");
      }//end if
      
      //poll RTC for time
      DateTime now = rtc.now();
      
      Serial.print(now.year(), DEC);
      Serial.print('/');
      Serial.print(now.month(), DEC);
      Serial.print('/');
      Serial.print(now.day(), DEC);
      Serial.print(" "); 
      Serial.print(" (");
      Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
      Serial.print(") ");
      Serial.print(now.hour(), DEC);
      Serial.print(':');
      Serial.print(now.minute(), DEC);
      Serial.print(':');
      Serial.println(now.second(), DEC);      
    }//end if
    
    delay(2000); 
}

void setTemp(){
  int su_flag = 1;
  int mode_flag = 1;
  Serial.println("SETUP MODE ->");
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Set temp: ");
  lcd.print(setting);
  delay(1000);
  //lcd.clear();
  while(su_flag == 1){
    if(digitalRead(decrPin) == LOW){
      setting--;
      lcd.setCursor(10, 0);
      lcd.print(setting);
    }//end if exit setup
    if(digitalRead(incrPin) == LOW){
      setting++;
      lcd.setCursor(10, 0);
      lcd.print(setting);
    }//end increment temp
    if(digitalRead(modePin) == LOW){
      //exit setup
      su_flag = 0;
    }//end exit setup mode
    delay(250);
  }//end while
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Set mode: ");
  lcd.print(mode);
  delay(1500);
  while(mode_flag == 1){
    if(digitalRead(decrPin) == LOW){
      mode = 'C';
      lcd.setCursor(10, 0);
      lcd.print(mode);
    }//end if
    if(digitalRead(incrPin) == LOW){
      mode = 'H';
      lcd.setCursor(10, 0);
      lcd.print(mode);
    }//end if heat mode
    if(digitalRead(modePin) == LOW){
      mode_flag = 0;
    }//end if exit mode set
    delay(250);
  }//end while set mode
  lcd.clear();
}//end setTemp function

arduino servo example analysis

futaba s3003 arduino servo example script
futaba s3003 arduino servo example script

I admit I know little about pulse width modulation, and have limited experience with robotics or servos. I’ve had a futaba s3003 servo in my toolbox for some time, and done nothing with it. On a lazy day when I had some down time, I decided to get it out and do some experimentation.

I’ve been doing some labor intensive projects at work lately, and while hard work is very rewarding, it takes a lot of physical and mental energy and crowds out innovation. Just out of boredom, I burned the most basic servo script example provided by the arduino IDE into a nano clone I recently bought, and analyzed it with pulseview to better understand pwm.

close up of PWM controlling a futaba s3003 servo
close up of PWM controlling a futaba s3003 servo

Above is a trace of the output of the default arduino ide servo script with me tuning a 10K pot. In this example script, the position of the servo corresponds to the position of the potentiometer. Just at a glance, you can see pulses bunched up at different intervals. What I empirically observed is that when the servo was at position 1, the pulse width was about 0.55ms in duration at the standard 50Hz required by the servo. This pulse was constant, and the servo was stationary. If the pulse width changes at all, it changes position proportionally.

The futaba s3003 has 180 degrees of rotation. At position 3 (180 degrees) the constant pulse width is about 2.4msec. as you can see in the graphic below:

futaba s3003 servo at 180 degrees of rotation

This simple analysis has demystified pwm somewhat for me. Next, I hope to experiment with some pwm on the raspberry pi using perl.

using an arduino as an ADC for a raspberry pi

reading a battery discharge with an arduino
discharging a 6V lead acid cell with two 50 ohm 10 watt resistors in parallel, reading the voltage with an arduino nano clone, and logging the data with a pi zero

Most everyone knows that unlike an arduino, the pi lacks an analog to digital converter. I normally use an MCP3004. These work ok for me most of the time, but I get a lot of readings that are outliers, and obviously not correct. I haven’t noticed this as much on the analog inputs on an arduino.

In this experiment (for an upcoming project) I essentially let an arduino nano clone read the voltage of a 6V lead acid battery that I was discharging with some low-value, high wattage resistors. The arduino read the voltage and printed it on it’s serial line at 9600 baud. The serial lines on the arduino were connected to the pi’s serial lines, and the pi recorded the readings by logging a screen session. First, you have to disable getty on the serial line, and then set up screen to log the session.
sudo systemctl stop serial-getty@ttyAMA0.service
sudo screen -L /dev/ttyAMA0 9600

I forgot to mention, that I used a 10K potentiometer as a voltage divider to step down the 6V so the arduino could read it.

6V battery discharging over 9 hour period under moderate load

I got a pretty good dataset with very little jitter and hardly any outliers. I think a pi and an ardino make a powerful combination. You can effectively extend all the arduino’s gpio’s, i2c, spi, etc. to the pi. You also have all the muscle and storage of the pi at your disposal for your projects.

interface raspberry pi zero with arduino via UART

interfacing arduino with a raspberry pi zero using uart
interfacing arduino with a raspberry pi zero using uart

I wanted to use a pi zero to log data captured by a arduino nano every.  The idea was to capture a screen session and parse the data with perl regular expressions.  Initially, I simply connected the UART pins directly.  You have to criss-cross the TX / RX lines.  I got a few readings from the arduino, then screen would terminate.  I was aware the logic levels were different (5V for the arduino, 3.3V for the pi) and thought that was the issue.  I connected a logic level converter and has the same result.  The issue was that I needed to disable getty.

disable getty on raspberry pi to connect to arduino via uart
disable getty on raspberry pi to connect to arduino via uart

After disabling getty,  I was able to maintain an open session between the pi and an arduino.

pi zero connected to an arduino via uart at 9600 baud
pi zero connected to an arduino via uart at 9600 baud

This output is messy, but not at all difficult to parse with perl.  The main thing is that it does not terminate suddenly because getty is disabled.  I forgot to mention that I was ssh’d into the pi zero via USB.  See my previous posts on how to enable ethernet via usb on a pi zero.

arduino nano bike speedometer

arduino nano bike speedometer and odometer
arduino nano bike speedometer and odometer

I tricked out my dad bike with an arduino nano based speedometer, odometer, clock, and temperature sensor.

A DS3231 RTC keeps the time and temperature.  I implemented a attachInterrupt() function to keep track of tire rotation via a reed switch.

reed switch for a bike speedometer / odomoeter using an arduino nano
reed switch for a bike speedometer / odomoeter using an arduino nano

This way, I do not have to programmatically monitor  the reed switch;  a routine is executed (in this case that calculates the distance traveled) each time the state of the digital pin the switch is connected to changes.

 //bike speedometer
#include 
#include "RTClib.h"
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 10;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

float start, finished;
float elapsed, time;
//float circMetric=2.164; // wheel circumference relative to sensor position (in meters)
float circMetric=1; // wheel circumference relative to sensor position (in meters)
float circImperial; // using 1 kilometer = 0.621371192 miles
float speedk, speedm;    // holds calculated speed vales in metric and imperial
float miles_traveled = 0;
float feet_traveled = 0;
char miles[100];

void setup () {
  attachInterrupt(0, speedCalc, CHANGE); //digital pin 2
  start=millis();
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("cr3d0");
  lcd.setCursor(0,1);
  lcd.print("BIKE SPEEDOMETER!");
  delay(4500); 
  lcd.clear();
  Serial.begin(9600);
  circImperial=circMetric*.62137; // convert metric to imperial for MPH calculations

  //rtc stuff
  int temp = 0;

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }//end if

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }//end if rtc lost power
  
}//end setup

void speedCalc()
{
  elapsed=millis()-start;
  start=millis();
  speedk=((3600*circMetric)/elapsed) * 0.12; // km/h
  speedm=((3600*circImperial)/elapsed) * 0.12; // Miles per hour
  feet_traveled += 1.1; 
  miles_traveled = feet_traveled / 5280; 
  //sprintf(miles, "%.2f", miles_traveled);
  
}

void loop()
{
  DateTime now = rtc.now();  
  int temp = 0;

  lcd.clear();
  lcd.setCursor(0,0);
  //lcd.print(int(speedk));
  //lcd.print(" km/h ");
  lcd.print(int(speedm));
  lcd.print(" MPH   ");
  lcd.print(miles_traveled);
  lcd.print(" mi");;
  //lcd.setCursor(0,1);
  //lcd.print(int(elapsed));
  //lcd.print(" ms/rev      ");
  lcd.setCursor(0,1);
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
  lcd.print(' ');
  temp = rtc.getTemperature() * 9/5 + 32;
  lcd.print(temp);
  lcd.print('F');
  delay(1000); // adjust for personal preference to minimise flicker
}

 

arduino bike speedometer
arduino bike speedometer

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: https://github.com/adafruit/DHT-sensor-library
// - Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

#include "DHT.h"
#include 
#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)

DHT dht(DHTPIN, DHTTYPE);

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() {
  Serial.begin(9600);
  Serial1.begin(9600);
  // 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");
  delay(2000);
  dht.begin();
}

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

  //increment sample number
  sn++;

  // 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!"));
    return;
  }

  //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(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hif);
  Serial.println(F("°F"));

  //print to pi
  Serial1.print("Humidity: ");
  Serial1.print(h);
  Serial1.print(F(" Temp: "));
  Serial1.print(f);
  Serial1.print("F RSSI: ");
  Serial1.print(rssi);
  Serial1.print("dBm");
  Serial1.print("\n");

  lcd.clear();
  lcd.print("Humidity:");
  lcd.print(h);
  lcd.print("%");
  lcd.setCursor(0,1);
  lcd.print(f);
  lcd.print("F ");
  //lcd.print(v);
  //lcd.print("V");
  lcd.print(rssi);
  lcd.print("dBm");
}

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.

 
#!/usr/bin/perl 
use strict;
require "/home/pi/gpio/MCP3004.pl";
use RPi::PIGPIO;
use RPi::PIGPIO::Device::DHT22;

=pod
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 CTC_datalogger.pl.  
=cut

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

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

#init ADC
init3004(3,4,5,6);

#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;
for(;;){
	#formatted date string 
	my $time_str = `date`;
	print "$i\n";
	print $time_str;
	chomp($time_str);

	$dht22->trigger();
	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";
	int($deg_f);

	#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";
		usleep(1000);

		$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;

	sleep(2);
	
	$i++;
}#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

building a telecom Transmission Impairment Measuring Set (TIMS) with arduino nano III

Telecom frequency generator and counter using arduino nano
Telecom frequency generator and counter using arduino nano

I have a working hand-held arduino based telecom test set made out of a plastic capacitor kit case.  It generates audio frequency tones from 0-3000 Hz.  The tone() function produces  audio frequencies at about -9.5dBm from what I have observed.  That level is very useful to my for my intended purposes.  I also need it to generate tones at a level of -16dBm.  To achieve this,  I put a selector switch to attenuate the level to -16dBm by putting the output of the tone() pin in series with 30K Ohms of resistance.

It measures the frequencies that it generates in TX mode, but also measures frequencies from other devices from it’s RX port.   The RX port must have a level of -3dBm or greater to work at this time.  I will be experimenting with an amplifier stage to measure weaker signals.

Arduino telecom frequency counter and generator
Arduino telecom frequency counter and generator

Schematic of telecom test set using arduino nano
Schematic of telecom test set using arduino nano

building a telecom Transmission Impairment Measuring Set (TIMS) with arduino nano II

arduino nano frequency counter
arduino nano frequency counter

I have considered several design possibilities for myTIMS project.  I was going to use the TimerFreeTone library because of the timer conflict between tone() and the FreqCount library, and have the user type in the desired frequency using a keypad.  I do not have enough GPIO on my nano for this as I need 6 pins for my LCD and seven for my 4-column 3-row keypad.  (I know I could get an i2c display, but I’m using what I have laying around!)

Anyway, the two nano approach is acutally looking better.  I am using one nano to generate the desired frequency when the TIMS is in transmit / generate mode.  I am using a 10-K potentiometer to tune to the desired frequency and basically copied and pasted the tonePitchFollower example sketch with a few modifications.  The other nano does the frequency counting and drives the LCD.  As you can see above, the nano frequency counter is only off by 1 Hz from a professional TIMS.

Here is the frequency counter sketch ->

     
     1	#include \<FreqCount.h\>
     2	#include \<LiquidCrystal.h\>
       
     3	const int rs = 12, en = 11, d4 = 10, d5 = 4, d6 = 3, d7 = 2;
     4	LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
       
       
     5	void setup() {
     6	  lcd.begin(16, 2);
     7	  lcd.print("Freq:");
     8	  FreqCount.begin(1000);
     9	}
       
    10	void loop() {
    11	  if (FreqCount.available()) {
    12	    unsigned long count = FreqCount.read();
    13	    lcd.setCursor(0, 1);
    14	    lcd.print(count);
    15	    lcd.print(" Hz       ");
    16	  }
    17	}
       

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