Home Automation - Chapter 2

WiFi Checks

In this chapter I’ll go over the ‘modules/wifi_check.rb’ module. Here’s the complete code:

#!/usr/bin/env ruby

# Libraries

require 'logger'
require 'pry'

# Logger settings

logger = Logger.new(STDOUT)
logger.level = Logger::INFO
logger.datetime_format = '%Y-%m-%d %H:%M:%S'

os_check = %x{uname}.strip
if os_check == "Darwin"
  logger.info("WiFi --> MacOS detected")
else
  logger.fatal("WiFi --> Sorry, I don't know how to handle WiFi on your system.")
  exit(0)
end

logger.info("WiFi --> Running wifi_check...")  

wifi_connected = %x{/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I}.match(/\ SSID: (.*)/)[1]

if wifi_connected == ENV['wifi_net']
  logger.info("WiFi --> WiFi OK")
else
  logger.warn("WiFi --> WiFi connected to wrong network!")
  if ENV['wifi_pass'] == nil
    logger.fatal("WiFi --> Cannot connect to the correct network. Set your pass to ENV['wifi_pass']!")
  else
    %x{/usr/sbin/networksetup -setairportnetwork en0 #{ENV['wifi_net']} #{ENV['wifi_pass']}} || logger.fatal("WiFi: Cannot connect to correct WiFi network!")
    wifi_connected = %x{/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I}.match(/\ SSID: (.*)/)[1]
    if wifi_connected == ENV['wifi_net']
      logger.info("WiFi --> WiFi reconnected to correct network!")
    end
  end
end

We’ll start with libraries section.

# Libraries

require 'logger'
require 'pry'

I’m loading the logger gem which I’ll use for the message that I’ll throw at stdout. I’m also loading pry which is my favorite debugger. Notice that I’m not really using it and that’s generally a bad idea - to load library that’s not used. I’m leaving it there so that I can call ‘binding.pry’ whenever I need to without caring too much for anything else. Feel free to remove it as it’s not really required for the code to work.

Next we’ll look at the logger initialization:

# Logger settings

logger = Logger.new(STDOUT)
logger.level = Logger::INFO
logger.datetime_format = '%Y-%m-%d %H:%M:%S'

The logger can be configured to log on STDOUT, STDERR or even a log file. Here are few examples of those:

logger = Logger.new(STDERR)
logger = Logger.new(STDOUT)
logger = Logger.new('logfile.log')

You can find documentation for it on the ruby-docs page.

The next thing I did is a small OS check.

os_check = %x{uname}.strip
if os_check == "Darwin"
  logger.info("WiFi --> MacOS detected")
else
  logger.fatal("WiFi --> Sorry, I don't know how to handle WiFi on your system.")
  exit(0)
end

My laptop is Mac so I have the code running only on it for the simple reason that I haven’t tested it elsewhere. That’s why I prefer to have such check and fail fast pointing the attention at this error in case someone else is looking at porting the code to his situation.

The reason I’m checking for MacOS specifically is that I’m using the ‘airport’ and ‘networksetup’ tools which are specific to Mac. In Linux or other Operating Systems those commands would differ. So, if you’re running something else you’ll have to adapt both - the OS check and the tools used later on the code:

wifi_connected = %x{/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I}.match(/\ SSID: (.*)/)[1]
%x{/usr/sbin/networksetup -setairportnetwork en0 #{ENV['wifi_net']} #{ENV['wifi_pass']}} || logger.fatal("WiFi: Cannot connect to correct WiFi network!")

The interesting parts of those checks are actually two:

  • I’m using %x{} structure where the x is just a variable. You can put anything there. In the {} I have the system command that will execute.
  • I’m using the ‘.match’ method which uses regular expressions to match text. That could be relatively tricky so what I usually do here is call ‘binding.pry’ and try different matches in the pry debugger. That helps a lot because it gives me a quick way to debug and tune my regex.

In this section I want also to talk a bit about ENV. For example this piece of code:

ENV['wifi_net']

This will return an environment variable called ‘wifi_net’. I’m using such variables so that I can hide all sensitive information (such as passwords and API keys) in variables that I’m sourcing from a file. In my case the file is “.env”. See the example in the root directory called “env.example”:

# You need to setup those variables in a file called ".env"

# Put here the correct WiFi network to connect to it instead of somewhere else:
export wifi_net="<WiFi network>"
# That's the WiFi password:
export wifi_pass="<WiFi password for the network>"

# Credentials for the router

export router_user="<user>"
export router_pass="<pass>"

You’ll have to adapt this file with your settings and for your shell. My shell is “/bin/bash” so I’ll be using the ‘export’ command to set those variables. In the next chapter we’ll talk about Internet checks.

The whole code of my Home Automation project is available on Github.

Home Automation - Chapter 1

Home Automation - Chapter 2

Home Automation - Chapter 3

Home Automation - Chapter 4

Categories:

Updated: