Wednesday, August 27, 2025

Finishing Up The Color Thermometer

 

Finished Color Thermometer

In the last post I looked at building a thermometer that showed the temperature and humidity of a room through the use of a color display that indicated the relative comfort level of the room, using an Arduino and a couple of extra components. 

While the thermometer worked quite well, it really did just look like just a bunch of wires that glowed. To have it be part of polite society, it needed to be dressed in more appropriate attire. 

Since the circuit is a fairly compact design, the thermometer would lend itself well to being housed a fancy box that could look pretty sitting on a shelf. On a recent clean-up of the shop I noticed that I had few pieces of red cedar and popular sitting in the scrap bin.  I always liked the look (and the smell!) of red cedar so I always try to avoid throwing of it out on the off chance I had use for it. As luck should have it, the scrap pieces looked to be a good size to house the Arduino. 

Designing The Case  

With my source materials acquired, I set about designing my enclosure. Basically the enclosure had to:

  • Of course contain the Arduino, Temperature sensor and the LED strip.
  • Have a way to mount the LED strip so that it seamlessly integrates into the case
    • To do that I decided that the case should have a slot cut into it to mount the LED.
    • To add a bit of a diffusion to the LED's the slot would also be cut to accommodate a plastic strip to mount in front of the LED's 
  • Provide proper air flow so that the temperature sensor can properly detect the room conditions
  • Be simple, basically the case should just be a your basic box.
With the criteria defined and based on the wood I had on hand, I sketched out a quick design



Bill of Materials 

  • Two 1x4x6.5 inch pieces of popular
  • Two 1/4x4x6.5 pieces of red cedar
  • One 1/8x3/4x6.5 piece of clear acrylic 
  • Frosted glass paint
  • Wood glue
  • Furniture felts
  • Small rubber grommet

Tools Required
  • Table saw
  • Router with a 3/4 inch straight bit
  • Wood clamps
  • Drill Press
  • Glue

Case Assembly

I started off by cutting out the 4 pieces of wood that will be used to make up the case

Wood parts

Next I marked out the cavity that will be used to house the Arduino and sensor on the two popular pieces and routed out the cavities

Marking out the cavity

Cutting out the cavity

Cut out cavities

Once everything was cut out, I then glued the two Poplar pieces together along with one of the Red Cedar pieces (which will serve as the top for our case)

Gluing things together

Gluing the top

Gluing things together

 Once the glue hard dried. I next had to put in a grove near the top of the case. To do that I took a 3/4 inch straight bit on my router and I cut a 1/2 inch deep groove about one inch down from the top of the case along the front. This groove needs to be deep enough to accommodate the LED strip and the 1/8 inch thick acrylic strip. 

Routing the strip

Routing the strip

LED Test Fit

Completed Groove

One problem that I found with the groove is that I did have it come out of the sides of the case which didn't really look very good as far as I was concerned so I really wanted to have it look a little bit better.

To solve that I cut out and glued in a couple of red cedar "plugs" to fill the ends of the grooves but still left some space on the end for the acrylic strip to be flush against the front of the case. 

Acrylic strip test fit

Cutting out plugs

Plugs installed

At this point, the main part of the case is now assembled. 

Perfect time to give every a quick sanding to neat everything up. 

Quick Sanding

With the groove in place I next cut a 3/4 inch wide strip of acrylic and cut it to the length of the case.

After a quick test fit to the case (and some trimming to make it fit better) I then gave the strip a coat of glass frosting paint to get a more diffused look when the LED's are lit. 

Cutting  acrylic

Doing a test fit

painting the strip

To complete the construction of the top part of the case I finished off by drilling in a few vent holes so that I could have some air flow for the temperature sensor.

Top of the case

Drilling out the vent



Installing the Innards 


The next step in the process was to put all the electronic bits into the case. I started off by looking at what would be best way to mount the Arduino.  To do this, I decided on mounting it to the remaining piece of red cedar that I hadn't yet glued to the case. 

After doing a test fit of the Arduino to the bottom plate I determined what would be the best place to mount the Arduino I then cut out and glued a couple of wooden rails to the red cedar, which would serve as a mounting point for the Arduino. 

Mounting the Arduino

Gluing in the Rails

Once the glue dried, I then mounted the Arduino to the base with a few screws.

Mounting the Arduino

The next thing to do was to mount the temperature sensor into the case. Since I drilled the ventilation holes into the top of the case, it makes the most sense to have the sensor mounted as close as possible to the vent. To do this I glued another small wood block to the top of the case and attached the sensor to the block.

Sensor Mount

Sensor Mounted


Finally I mounted the LED's into the groove that I had earlier cut, luckily the groove also opened up an access to the internals of the case, so the wiring for the LED was pretty easy to feed through 

I glued the LED strip in place followed by the acrylic strip 

Installing the LED strip

Installing the LED strip

Installing the acrylic strip



With all the various components mounted the next step was to wire everything up and buttoning up the case. 
Wiring up the circuit

Wiring up the circuit


One thing I failed to note was how I planned to power up the Arduino once it was sealed up. 

To power the Arduino, I chose to power it through the Arduino's USB connector, which will also give me an opportunity to do any tweaks to the programming that I might want to do in the future. 

To provide power access, I usually would drill a half inch hole into the back of the case, but as a lucky coincidence, one of my popular pieces had a knot that popped out that was the ideal size. So I fed the USB cable through the knot hole and used a rubber grommet to neatly cover the hole.

Installing the USB cable

Finishing the wiring

 Finally I glued the rest of the case together

Gluing it all together

Gluing it all together

I finished up the job with some varnish and after installing some felt pads on the bottom, the project is done!

Varnishing

Felt pads

At the moment the thermometer is still on my desk here at work giving my a nice visual interpretation on the office climate.  It's certainly been a bit of a conversation piece. 

Next month, I going to revisit a topic that I first posted about a few years ago. 


Tuesday, July 15, 2025

Building A Color Thermometer



This month I wanted to get back onto more "hands on" stuff that was more based in the real world than the virtual one. When looking around for ideas, I found a small stash of Arduino Uno's that I got from my Creation Crate subscription a while back (by the way - I highly recommend them - the neat little projects I got each month were a lot of fun to put together - and I learn quite a lot on what the Arduino is capable of) so I wanted to find a unique project that I could make with and Arduino and whatever components I could find lurking around the workbench.

Rooting around, I came across a roll of NeoPixel programable color LEDs. These are pretty neat since you can do a lot of different light effects and you could program it so that individual LED's on the strip to light up. The original reason I had that roll was for a clock project that didn't quite pan out the way I wanted it to go. 

I also came across a DHT11 module, which is a small temperature/humidity sensor that feeds its data through a single wire data feed. 

So, with those 3 items, the obvious solution is to put together a thermometer that displays the temperature and humidity in the room as a color display. 

Since the LED's and the sensor are digitally controlled, it really makes for a simple circuit to put together - basically I just need to plug the components directly to the Arduino's power outputs and digital inputs and some fairly straight forward Arduino code should handle the rest. 

The basic premise of the project is to be a smart weather display that automatically changes light patterns based on the temperature and humidity in the room. The temperature sensor continuously monitors the air conditions and then creates different colorful lighting effects on the LED strip to show what the weather felt like.



Showing The Room Conditions

To properly visualize the room conditions I really needed to come up with an appropriate color effect that reflected how it felt in the room. 

After some playing around with the NeoPixel, I came up with the following patterns: 

  • Cold and Damp (Under 15°C with high humidity over 40%)
    • Effect: Cool Blue Pulse
      • The lights glow in cool blue tones that slowly pulse brighter and dimmer
      • Represents the feeling of being underwater or in a cold, misty environment
      • Creates a calming, cool atmosphere

  • Hot and Dry (Over 25°C with humidity under 70%)
    • Effect: Fire Flicker
      • The lights flicker in red, orange, and yellow colors like real flames
      • Each light changes randomly to create a realistic fire effect
      • Represents the dry heat of a desert or fireplace

  • Comfortable Conditions (15-25°C with moderate humidity 40-70%)
    • Effect: Calm Green Breathing
      • Soft green lights that slowly fade in and out like gentle breathing
      • Creates a peaceful, natural feeling
      • Indicates ideal living conditions

  • Hot and Humid (Over 30°C with high humidity over 70%)
    • Effect: Storm Swirl
      • Purple and magenta colors that swirl and move along the strip
      • Creates a chaotic, energetic pattern
      • Represents the unsettled feeling of hot, sticky weather

  • All Other Conditions
    • Effect: Rainbow Cycle
      • A smooth rainbow pattern that continuously moves along the strip
      • Shows all colors in a pleasing sequence
      • Acts as the default display when conditions don't match the other categories

The lighting effects are intended to be intuitive - cooler colors for cooler conditions, warmer colors for hotter conditions, and special effects for extreme or unusual combinations of temperature and humidity.


Now that I have the effects that I wanted to have to represent the conditions in the room, that next step is to start putting things together



Components

To start the project, I collected the following times




Temperature and Humidity Sensor (DHT11)
  • A small electronic sensor that measures how hot or cold it is and how much moisture is in the air
  • Takes readings every few seconds automatically
  • Connected to your Arduino microcontroller

LED Strip (NeoPixels)
  • A strip of  colorful lights that can display any color
  • For this project I'll use a string of 7 LED's
  • Each light can be controlled individually
  • Can create smooth animations and effects

Arduino Uno Microcontroller
  • The "brain" that reads the sensor data and controls the lights



Technical Details

  • Temperature Range: Celsius measurements are to be used
  • Humidity Range: Measured as relative humidity percentage (0-100%)
  • Update Speed: The lights on the NeoPixel update every 20-80 milliseconds depending on the effect
  • Power: The thermometer will runs on standard Arduino power (5V). In particular I plan on running the Arduino off the USB connector, which will allow me to apply future software updates. 
  • Installation: I am planning on enclosing the thermometer in some sort of case, but it will need to be able to have access to power and good air circulation for accurate readings.



Wiring It Up

With the components all collected, I looked at how to connect everything up.  

In reality, connecting all the components together are pretty straightforward. 

Connections to the Arduino are:
  • The positive connection from the LED was connected to the +5 port
  • Data line from the LED was inserted to the D6 socket
  • Ground on the LED was inserted into one of the Ground sockets
  • Positive connection from the DHT11 was put into the  Vcc socket
If you're more picture oriented, I've also included a handy schematic diagram below



Writing The Code 

With everything all connected, the next step is to tell the Arduino to start monitoring the output of the DHT11, check the readings it got against the display rules that I defined earlier and tell the NeoPixel LEDs to display the appropriate color display. 

The Arduino checks the temperature and humidity continuously and updates the light display in real-time. The effects needed to be smooth and change gradually as the environmental conditions changed.

To get everything to work, I put together the following program and uploaded it up to the Arduino:


#include <Adafruit_NeoPixel.h>
#include <DHT.h>

#define DHTPIN 6
#define DHTTYPE DHT11
#define LED_PIN 2
#define NUM_LEDS 7

DHT dht(DHTPIN, DHTTYPE);
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  dht.begin();
  strip.begin();
  strip.show();
}

void loop() {
  float temp = dht.readTemperature();
  float hum = dht.readHumidity();
  Serial.begin(9600);

  if (temp < 15 && hum > 40) {
    coolBluePulse();
  } else if (temp > 25 && hum < 70) {
    fireFlicker();
  } else if (temp >= 15 && temp <= 25 && hum >= 40 && hum <= 70) {
    calmBreathGreen();
    } else if (temp > 30 && hum > 70) {
    stormSwirl();
  } else {
    rainbowCycle();
  }
}

void calmBreathGreen() {
  static float brightness = 0;
  static int fadeDirection = 1;
  static unsigned long lastUpdate = 0;

  const unsigned long interval = 100;    // Slower fade timing
  const float step = 0.8;                // Smaller step for smoothness

  if (millis() - lastUpdate >= interval) {
    lastUpdate = millis();

    brightness += fadeDirection * step;

    // Reverse direction at full brightness and full darkness
    if (brightness >= 150) {
      brightness = 150;
      fadeDirection = -1;
    } else if (brightness <= 0) {
      brightness = 0;
      fadeDirection = 1;
    }

    // Set all LEDs to green with current brightness
    for (int i = 0; i < NUM_LEDS; i++) {
      strip.setPixelColor(i, strip.Color(0, (int)brightness, 0));
    }
    strip.show();
  }
}

// Effect: underwater blue pulse
void coolBluePulse() {
  static uint8_t brightness = 0;
  static int fadeDirection = 1;

  for (int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, strip.Color(0, brightness, brightness + 40));
  }
  strip.show();

  brightness += fadeDirection * 3;
  if (brightness <= 10 || brightness >= 120) fadeDirection *= -1;

  delay(40);
}

// Effect: flickering fire
void fireFlicker() {
  for (int i = 0; i < NUM_LEDS; i++) {
    int r = random(180, 255);
    int g = random(50, 100);
    strip.setPixelColor(i, strip.Color(r, g, 0));
  }
  strip.show();
  delay(80);
}

// Effect: chaotic swirl (hot & humid)
void stormSwirl() {
  static int pos = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    int val = (i + pos) % 256;
    strip.setPixelColor(i, strip.Color(val, 0, 255 - val));
  }
  strip.show();
  pos++;
  delay(50);
}

// Backup effect
void rainbowCycle() {
  static uint16_t j = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, Wheel((i * 256 / NUM_LEDS + j) & 255));
  }
  strip.show();
  j++;
  delay(20);
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85)
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


Once the code was uploaded, the LED's started doing their thing. To get a sense of what the effects look like, I've attached a quick video that showed all the available light effects.




At this point I had a working prototype of a color thermometer and I really like the effects that are being produced. I did have to tweak the settings a little to remove some of the gaps in the temperature and humidity rules in order to cut down the cases where it defaulted to the rainbow effect. 

As of now, while the lights are pretty cool, it's basically just a lump of glowing wires, so to make it really practical I need to properly house it. 

Next - my thermometer gets a proper home. 

Tuesday, June 17, 2025

Posting ACARS Messages Online



After all the work done to set up a radio monitor to scan the ACARS frequenices, figuring out what kind of messages I wanted to see, and finally building a way to easily view the messages, the final  part of the project is to now post these messages up somewhere where I can view them almost anywhere.

 As mentioned in the previous post, I had looked into building a feed to the usual social media applications, but usually these types of feeds usually required the use of API connections to make things work. While this is pretty common within the IT world where I spend my working hours, I also realize that a good part of the world may not be familiar with the voodoo that define electronic data interchange standards, so I wanted to develop a solution that would be pretty simple to implement by someone who wasn't a tech guru. 

After some experiementing, I settled on a solution that would post my daily ACARS feed up to a fairly simple Blogger web site. The main reason for using Blogger is that it's a platform that is built to allow people to post to a personal webpage via a relativley simple user interface.  Blogger also has the ability to customize the look and feel of your webpage, so you can be creative and have your webpage suit your personal taste.  The third (and probably the most important) reason I chose Blogger was that it was free. 

Since Blogger utilizes a graphical interface for creating posts, I thought it might be interesting to try and create a solution that minics a live person creating a post. Granted, this would probably be seen as sacraligous by my IT colleagues to consider this sort of solution, but like I said earlier, I wanted to build something that a "non-techy" person might be able to build with a minimal amount of fuss.    

 With those goals in mind, I started work by creating a Blogger site called "ACARS Radio Log" <Click To Visit Site> and after doing some tinkering on my site's look and feel, I had somethng that allowed me to easily see the current messages.

With the website set up, I next looked into how to build the process of loading up ACARS messages to the site.

Obviously I wanted to look at some sort of programmed solution and since I've had pretty good luck with Python so far I wanted to still some how be able to use it for the solution's foundation. 

In sketching out a logic flow, I can up with this high level process:

  • Open a browser (I chose Chrome as the browser for my solution)
  • Log onto the Google account (since Blogger is owned by Google)
  • Open the blogger session for my ACARS Log site and click on the New Post button
  • Set the Edit window that opens up to "HTML" mode
  • Copy the contents of the "blog_ready.html" file that was created in the previous process into the Blogger Edit window
  • Save and Post the Blog Post.    

An Interactive Session

To make this work, I needed to program something that was going to work in interactive mode, which as it suggests, means that the program needs to "interact" with the computer's GUI environment, which is a bit different for Python program, which usually likes to work behnd the scenes. 

The one thing that I like the most about Python is that there seems to be a really extensive library of companion tools that seems to give it the ability do almost anything. After some research, I came across a plug in called Playwright, which is a general purpose browser automation tool. 

Doing some experimenting with Playwright, I found that it would do a great job of opening up a browser and logging onto my Blogger page. However it was having troubles navigating the editor on Blogger. Doing some investigation showed that Playwright was looking for specific html code snippets within the Blogger page itself that didn't exist in the current Blogger site. What this told me was that Blogger would occasionally make some internal changes to their site, which even if I could get it to evetually work with Playwright, it was likely a matter of time before it broke again. 

To get around that I needed to find a method that avoided the need for looking at the internal programming of the site.  After some poking around, I decided I needed to resort to a good old fashion key logger. 

Key Logging

Again, looking at the Python libraries, I did find a plugin that would play back recorded key stokes. I ended up using a plugin called Pynput. This tool will allow you to record and playback any keystrokes on a computer, which is then stored as a json file, making editting of your keystrokes pretty easy if you need to modify anything. 

The first step was to get my Blogger session to the point where I was starting to have problems with Playwright. To create the keylogger file, I needed to create a "throw away" Python to create the log:

# keylogger.py
from pynput import keyboard
import json

keystrokes = []

def on_press(key):
    try:
        keystrokes.append(key.char)
    except AttributeError:
        keystrokes.append(str(key))

def on_release(key):
    if key == keyboard.Key.esc:
        # Save to file on ESC key press
        with open("keystrokes+2.json", "w") as f:
            json.dump(keystrokes, f)
        print("Keystrokes saved. Exiting...")
        return False  # Stop listener

with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
    print("Recording... Press ESC to stop.")
    listener.join()

Executing this program turns the recorder on and I can start recording keystrokes (I noticed that it won't record any mouse activity). After I finished my keystrokes, I simply turned the recorder off by pressing the Escape key. 

After recording, I got this as a json file:

["Key.tab", "Key.tab", "Key.tab", "Key.tab", "Key.tab", "Key.enter", "Key.down", "Key.up", "Key.enter"]

After putting together some Pynput playback code, I gave it a quick test 


It certainly will do what I want it to do. 

Posting To The Blog

Now that I've sorted out the mechanics how things should work, I threw together a small Python program that follows the logic flow that I've highlighted earlier

import os
import time
from playwright.sync_api import sync_playwright
from pynput.keyboard import Controller, Key
import json
import pyperclip


# === CONFIGURATION ===
BLOGGER_URL = "https://www.blogger.com"
HTML_FILE_PATH = "blog_ready.html"
PASTE_DELAY = 1.0

# === Credentials ===
EMAIL = "<My Google Account>"
PASSWORD = "<My Password>"

if not EMAIL or not PASSWORD:
    raise ValueError("Missing EMAIL or PASSWORD")

# === Load HTML content ===
with open(HTML_FILE_PATH, 'r', encoding='utf-8') as file:
    html_content = file.read()

# === Copy to clipboard ===
pyperclip.copy(html_content)

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False, args=[
        '--disable-blink-features=AutomationControlled',
        '--incognito',
        '--disable-extensions',
        '--start-maximized'
    ])
    context = browser.new_context()
    page = context.new_page()

    # Stealth
    page.add_init_script("""
        Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
    """)

    # Step 1: Google login
    page.goto("https://accounts.google.com/")
    page.wait_for_selector("input[type='email']", timeout=10000)
    page.fill("input[type='email']", EMAIL)
    page.click("#identifierNext")

    page.wait_for_selector("input[type='password']", timeout=10000)
    page.fill("input[type='password']", PASSWORD)
    page.click("#passwordNext")

    page.wait_for_timeout(5000)  # Let login settle

    # Step 2: Go to Blogger dashboard
    page.goto(BLOGGER_URL)
    page.wait_for_load_state("load", timeout=15000)
    page.wait_for_timeout(5000)

    # Click New Post
    print("Clicking NEW POST button...")
    try:
        new_post_button = page.get_by_role("button", name="New Post").first
        new_post_button.wait_for(state="visible", timeout=10000)
        new_post_button.click()
    except Exception as e:
        print(f"Failed to click NEW POST button: {e}")
    # Do not close the browser; just wait for user input
        input("Press Enter to exit and close the browser...")
        exit(1)

    keyboard_controller = Controller()

    # Load keystrokes from file
    with open("keystrokes_1.json", "r") as f:
        keystrokes = json.load(f)
 
    print("Replaying keystrokes in 3 seconds...")
    time.sleep(3)

    for key in keystrokes:
        if key.startswith("Key."):
            # Convert string back to actual Key
            try:
                k = getattr(Key, key.split(".")[1])
                keyboard_controller.press(k)
                keyboard_controller.release(k)
            except AttributeError:
                pass  # Unknown key
        else:
            keyboard_controller.press(key)
            keyboard_controller.release(key)
        time.sleep(0.05)  # slight delay to mimic real typing

    # === Wait for user to focus editor ===
    print("📋 HTML content copied to clipboard.")
    print("Switch to the editor window in the next few seconds...")
    time.sleep(PASTE_DELAY)

    # === Paste using keyboard (Ctrl+V) ===
    keyboard = Controller()
    keyboard.press(Key.ctrl)
    keyboard.press('v')
    keyboard.release('v')
    keyboard.release(Key.ctrl)

    print("✅ Content pasted.")
  
     # === Publish post ===
    try:
        print("🚀 Attempting to publish post...")

    # Look for 'Publish' button
        publish_button = page.locator('div[role="button"] span:has-text("Publish")').first
        publish_button.wait_for(state="visible", timeout=10000)
        publish_button.click()
        print("🟡 Clicked Publish button...")
        
    except Exception as e:
        print("❌ Could not publish post:", e)
    

    # Confirm Publish
    
    with open("keystrokes_2.json", "r") as f:
        keystrokes = json.load(f)
 
    print("Replaying keystrokes in 3 seconds...")
    time.sleep(3)

    for key in keystrokes:
        if key.startswith("Key."):
            # Convert string back to actual Key
            try:
                k = getattr(Key, key.split(".")[1])
                keyboard_controller.press(k)
                keyboard_controller.release(k)
            except AttributeError:
                pass  # Unknown key
        else:
            keyboard_controller.press(key)
            keyboard_controller.release(key)
        time.sleep(0.05)  # slight delay to mimic real typing

    print("✅ Confirmed Publish.")

    time.sleep(3)
    browser.close()

The program follows this flow:
  • It first logs onto my Blogger page through the associated Google account. 
  • Next it navigates to the Blogger Editor by simulating the pressing of the New Post button.
  • Once the Editor screen is open, the Keylogger playback navigates the editor by first setting the editor to html mode, and tabbing over to the edit screen. 
  • The html code that has been created in the ACARS_to_htm program is pasted to the Editor
  • The post is then published 

Putting It All Together


Now that I've got a full end to end process to collect, filter and post the ACARS messages, the last step is to put the whole thing together as a consolidated script that will run everything at once.  

To do this I created a script file called Create_post.sh on my ACARS computer:

# Run file_rename.py
python3 file_rename.py

# Check if the first script succeeded
if [ $? -ne 0 ]; then
    echo "file_rename.py failed. Aborting."
    exit 1
fi
# Run ACARS_to_html.py
python3 ACARS_to_html.py
# Check if the second script succeeded
if [ $? -ne 0 ]; then
    echo "ACARS_to_html.py failed."
    exit 1
fi
# Run ACARS_to_html.py
python3 Post_Blog.py
# Check if the second script succeeded
if [ $? -ne 0 ]; then
    echo "Post_Blog.py failed."
    exit 1
fi

echo "All scripts executed successfully."

To finish things up I then set up a crontab schedule to run this script at midnight every day. 

So far it's been running like clockwork everyday, and I love really being able to pop in anytime to check out the activity. 

So that completes the ACARS project. I'll admit that there was probably a bit more software with this one. I promise that the next project will be a bit more hands on!