Running a Docker container when the machine starts

Normally when I have a Docker container that I want to automatically come up whenever the machine restarts, I simply use –restart=always when running the container (or “restart: always” in a Docker Compose YAML file).  Recently encountered a situation where that didn’t meet my needs.  I thought it would be quick and easy to start the container from a service (a la systemd).  It ended up being easy, but it wasn’t as quick as I thought because I made some incorrect assumptions and sloppy mistakes along the way–so in case I need to do this again I am documenting what I did here . . .

I was using an Ubuntu 16.04 machine and for my example I’m using my Beaverton School District Calendar image.  To create the actual service, I created the file /etc/systemd/system/schoolCal.service with the contents:

[Unit]
Description=School Calendar Service
Requires=docker.service
After=docker.service

[Service]
Restart=always
ExecStart=/etc/systemd/system/schoolCal.sh

[Install]
WantedBy=multi-user.target

There’s nothing special about the service definition, it basically runs the schoolCal.sh script.  The problem I encountered when creating the service file was I forgot to add the dependency on the docker.service (I’m not sure if both “Requires” and “After” need to be set, but at least one of them does).  To enable the service I ran:

sudo systemctl enable schoolCal

Here are the contents of the schoolCal.sh script:

#!/bin/sh
docker pull bakchoy/beavertonschoolcalendar
docker run -i --net host -p 9999:9999 bakchoy/beavertonschoolcalendar

The script is very simple, but it took several tries for me to get it right.  Here are some details I encountered/considered:

  • It’s necessary to make the script executable
  • The explicit pull means that the latest image will always be used when starting up a new container.
  • Since I want the container log to be available via journalctl, the container has to be run in interactive mode “-i” instead of in detached mode.
  • Normally when I run stuff in interactive mode, I use “-i -t”.  When I had that, the script worked fine when I ran it manually, but when invoked by the service it would fail with “the input device is not a TTY”.  It took me awhile to figure out the fix was simply to remove the “-t”.
  • In this case, I wanted the container ip/hostname to be the same as the host, so I set “–net host”.  In most situations that probably isn’t necessary.
  • Space isn’t an issue here and I have a different mechanism for cleaning old containers.  Otherwise I might have added a “-rm” (but I’m not certain it would work as expected).

I found https://docs.docker.com/engine/admin/host_integration/ which also has an example invoking a Docker container via systemd (and upstart), but it seems closer to using a Docker restart policy than what I’m doing.  Although in general I think using the built-in Docker restart policies is a better approach, here are some aspects that differentiate my approach:

  • No specific container tied to the service–a container doesn’t need to exist for things to work when the service is started
  • I pull request can be included to basically provide automatic updates
  • Logging can be directed to the standard service logging mechanism (such as journalctl)
  • The service can be monitored with the same tools for monitoring other services rather than Docker way

My New Toy (Part 4)

I finally got to the point where my new toy is able to publish temperature information to a database, so next is to make that information available on BakBoard.  With the main pieces already deployed, the only thing necessary is to add the necessary connections.

First I wrote a some JavaScript to poll the Webdis/Redis server for the temperature.  For extra credit I also have it contacting the FAA Services REST API to get information about weather at the Portland airport.  Below is “temperature.js”.

function temperature() {
    setupTemperature();
    updateTemperature();
    window.setInterval(function(){ updateTemperature(); }, 100000);
}

function setupTemperature() {
    $('.temperature').html("<div class='pdx'/><div class='upstairs'/>");
}

function updateTemperature() {
    var myJson;
    var url = "http://192.168.1.35:7379/GET/temperature";
    
    myJson = $.getJSON(url, function(obj) {
        var f = parseFloat(obj.GET);
        var c = (f - 32) * 5 / 9;
        $('.upstairs').html("Upstairs: " + f.toFixed(1) + "F (" + c.toFixed(1) + " C)");
    });
    
    url = "http://services.faa.gov/airport/status/PDX";
    myJson = $.getJSON(url, function(obj) {
        $('.pdx').html("Airport: " + obj.weather.temp);
    });
};

And here’s a very simple HTML file that uses the script above to display the airport and upstairs (where I put my new toy) temperatures:

<html>
    <head>
        <!-- I downloaded jQuery from http://code.jquery.com/jquery-2.2.0.min.js-->
        <script src="jquery-2.2.0.min.js"></script>
        <script src="temperature.js"></script>
        <title>Temperature</title>
    </head>
    <body>
        <div class="temperature"></div> 
        <script>
            temperature();
        </script>
    </body>
</html>

Viewing that script in a browser showed:

Airport: 73.0 F (22.8 C)
Upstairs: 71.1F (21.7 C)

I basically added the bold HTML parts to the BakBoard .html file along with some css goodness and the temperature information is now displaying on BakBoard.

bakboardTemp

I had fun playing with my new toy and learned a lot.  The ESP8266 seems to have a lot of potential and I want to try more things.  Of course now that I have my only module in use, I may have to get another one for play . . .

My New Toy (Part 3)

In my previous “New Toy” post I managed to wirelessly publish a count, so I determined the next step to be to publish some “real” information: the temperature.

I’m not the first to use an ESP8266 module to publish temperature information and I found an excellent tutorial on Adafruit.  However, it was written for another (now discontinued) ESP8266 module with significant differences from my Electrow.  Also, the sample code provide has the module host a web server and allow clients to connect to it whereas I wanted my module to push the information to a database.  This meant I could use the tutorial as a guide, but there were still various things to figure out.

First I had to do the wiring to connect the DHT22 temperature and humidity sensor I purchased like the one used in the tutorial.  I ended up spending a lot of time and muttering various working words trying to get it to work right.  My module has onboard USB and a voltage regulator, so the wiring is much simpler, but I couldn’t get any readings.  I tried resistor changes, testing connections, and verifying voltages among other things.  Finally I discovered that when I specify pin 2 it means D04 (the fifth digital pin) on my board.  So here’s what I ended up with:

2016-08-02 15.35.48

  • The ground pin connects to the fourth pin of the DHT22 (black wire)
  • The D04 digital pin connects to the second pin of the DHT22 (white wire)
  • The 3.3v pin provides voltage (via the red wire) to the both the first pin of the DHT22 and it also goes through a 10K resister to the second pin.

 

 

The code is basically pasting together the Adafruit sample code with the code I wrote previously.  It looks like this:

#include <ESP8266WiFi.h>
#include <DHT.h>
#define DHTTYPE DHT22
#define DHTPIN  2

const char* ssid = "name of wifi network";
const char* pass = "wifi network password";
const char* ip = "192.168.1.35";
const int port = 7379;

// Initialize DHT sensor 
DHT dht(DHTPIN, DHTTYPE, 11); // 11 works fine for ESP8266
 
void setup(void)
{
  dht.begin();
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
}
 
void loop(void)
{
    float temp_f = dht.readTemperature(true);

    WiFiClient client;
    client.connect(ip, port);
    String url = String("/SET/temperature/") + temp_f;
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
           "Host: " + String(ip) + "\r\n" + 
           "Connection: close\r\n" + 
           "Content-Length: 0\r\n" + 
           "\r\n");
    delay(5000);
} 

I had already started up a Webdis/Redis server as described before, so I could verify it worked by running curl and confirming that it returned a value (in this case 72.68F).

$ curl http://192.168.1.35:7379/GET/temperature
{"GET":"72.68"}

Searching online, I found the ConnectSense CS-TH Wireless Temperature and Humidity Sensor that seems pretty much like what I made, but in a pretty box and costing $150 (granted it does come with some nice software as well).  Now that I have my own budget version, I can look to do something with that temperature data I’m collecting.

My Boots

Boots

Last week while backpacking in the Mount Jefferson Wilderness area, I had a sad incident related to my boots.  There was a stream crossing, but the stream wasn’t running too high, so I just walked right across.  Boy#1 and Boy#2 were with me and neither had waterproof footwear so I went back and carried their packs across so that they could lightly hop across on rocks without wetting their feet.  By then some of the other boys in the party had caught up and I ended up carrying over another three or four packs.  I got my pack on again and started hiking again, and then I noticed that my right little toe was damp.  The seal failed and my boots are no longer waterproof.  It is time to buy new boots.

My boots were purchased back in the late 1990’s, so it’s been awhile since I’ve had to select new boots.  I’ve been thinking about some of the attributes I like about my boots.  In no particular order:

  • Vibram soles – The soles are worn such that the writing is no longer legible on the yellow emblem, but there is still tread.  I rarely wore my boots on man made surfaces which I think contributed to their longevity.  I always had the traction I needed.
  • Waterproof – as long as the water didn’t go above the top, my feet were dry.  The leather upper and integrated one piece tongue are joined so that there are no gaps in the outside barrier.  It was nice to be able to tromp right through water without worrying about wet feet.
  • Step-in crampon friendly – I’ve never done enough mountaineering to justify fancy plastic shell boots, but being able to quickly slap on some crampons for an ascent has been nice.
  • Sturdy lacing system – I’ve got skinny feet, so I really need to be able to tighten things down.  One of the original laces broke back in 2000 while hiking in Rocky Mountain National Park, but I found a store in Estes Park that sold shoe laces by the foot; I took off the unbroken lace and bought new laces in classic red.
  • Smooth lining – With my bony heels, I tend to wear through the back of shoes before anything else.  The smooth lining slowed that wear significantly and also helped to avoid blisters.
  • Ankle support – The boot came up high enough that it gave great ankle support.  The smooth padding allowed me to have the ankle be tight but still comfortable.
  • Classic – My boots have the classic, Italian style look of a hiking boot.  They are simple, honest boots.

I’m sad that it’s time to retire my boots–I’ve had many adventures with them on my feet.  I’m also excited to find new boots and have some new adventures.

 

 

My New Toy (Part 2)

In the previous post, I implemented a simple counter with serial output and today I improved it.  The main reason I purchased the ESP8266 module in the first place was to get WiFi for cheap, so I wanted to try out the WiFi capabilities.  The resulting sketch is still a counter, but instead of publishing the count via the serial interface, it connects wirelessly to a database and publishes the count there.

To begin with, I needed a simple database that I could access via HTTP.  Redis is a simple key/value type database, but it doesn’t have an HTTP interface.  I found Webdis “A fast HTTP interface for Redis”.  To set things up quickly, I found that someone had already put everything together and published a Docker image on DockerHub.  So, through the magic of Docker, all I had to do to get Redis and Webdis up and running on my computer was run this magic command:

docker run -d -p 7379:7379 -e LOCAL_REDIS=true anapsix/webdis

I then wrote a sketch that would publish to my new database:

#include <ESP8266WiFi.h>
const char* ssid = "name of wifi network";
const char* pass = "wifi network password";
const char* ip = "192.168.1.35";
const int port = 7379;
int count = 0;

void setup() {
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
}

void loop() {
  delay(5000);
  WiFiClient client;
  client.connect(ip, port);
  String url = String("/SET/count/") + count++;
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + String(ip) + "\r\n" + 
               "Connection: close\r\n" + 
               "Content-Length: 0\r\n" + 
               "\r\n");
}

Basically, it connects to the wifi network (ssid) using the provided password (pass) and then publishes the count to the database (located at ip).  It publishes the new count value every five seconds.

To verify that it was working, I simply plugged this URL into my web browser :

192.168.1.35.7379/GET/count

It returns the current value of count:
getCount

So now I can not only program my new toy, but also use some of its wireless capabilities.  It’s not useful, but it is a good step to learning how to use the ESP8266.

My New Toy (Part 1)

Today my new toy arrived.  It’s an ESP8266 IOT WiFi Module.

ESP8622

Specifically I selected the “Elecrow ESP8266 IOT Board WiFi Module with Built in USB and Battery Charging” out of the many ESP8266 variants because of the following features:

  • Onboard USB (I find it easier than FTDI)
  • NOT breadboard friendly (Pins sticking up not down)
  • In stock and eligible for Prime shipping

To start with, I just wanted to verify that I could run some code on it.  Here’s what I did:

  1. Installed the Arduino IDE from https://www.arduino.cc/en/Main/Software.  I used the latest available (1.6.9).
  2. Configured the Arduino IDE to support ESP8266 boards:
    1. Opened up the preferences and added http://arduino.esp8266.com/versions/2.3.0/package_esp8266com_index.json to the “Additional Boards Manager URLs”.
    2. Opened the “Boards Manager”, found the “esp8266” listing, and clicked the “Install” button (using the latest 2.3.0 version).
    3. Since there wasn’t a specific Electrow entry, I selected “Generic ESP8266 Module” for the board type.
  3. Wrote some code.  Here is my very simple sketch to slowly count and send the number via serial:
    int count = 0;
     void setup() {
     Serial.begin(9600);
     }
     void loop() {
     Serial.println(count++);
     delay(1000);
     }
  4. Ran the code.  I uploaded it to the module, opened the serial terminal, and saw that it was counting as designed.
    serialTerminal

Of course it took a bit of kicking and swearing to do that.  Here are a few of the things that I did before everything worked:

  1. Ran the Arduino IDE as root
  2. The upload speed is 115200, but the terminal speed is 9600 baud
  3. Change the reset method to “nodemcu”.
  4. Sometimes (but not always) hold the flash button and than hit the reset button before I could successfully upload my sketch.
  5. Switch USB cords (the first is a cheap, old cord that in recent years has only been used for charging devices).
  6. Check the port whenever I plugged in the module (it sometimes switched between /dev/ttyUSB0 and /dev/ttyUSB1 just to spite me).

There’s nothing exciting about my counting program, but by getting it running I confirmed that I can 1) Connect to the module 2) Upload code to it and 3) Run the code.  Now that I can do that, I can see what else I can make my new toy do . . .

Dangerous Field for Alexa

Dangerous fieldThe nostalgia of coding and playing Dangerous Field on the calculator inspired me to revive the series with an all new version of the game.  This latest incarnation is implemented as an Alexa Skill for the Amazon Echo.  Although the interface is completely different, I think that it has a certain charm due to the simpleness and silliness.

From a technical perspective, there are two parts:  the voice interface and the game implementation.  Amazon makes the voice “Interaction Model” fairly easy to configure–it least for this simple scenario.  The Intent Schema basically defines a way for users to specify how to move (direction and with an optional  movement type) as well as indicate that they want to play and support some basic Amazon intents.

{
  "intents": [
    {
      "intent": "move",
      "slots": [
        {
          "name": "direction",
          "type": "DIRECTION"
        }
      ]
    },
    {
      "intent": "movewithstyle",
      "slots": [
        {
          "name": "movementtype",
          "type": "MOVEMENT_TYPE"
        },
                {
          "name": "direction",
          "type": "DIRECTION"
        }
      ]
    },
    {
      "intent": "playGame"
    },
    {
      "intent": "AMAZON.NoIntent"
    },
    {
      "intent": "AMAZON.YesIntent"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    }
  ]
}

I added two custom slot types to let users specify which direction to go and which movement type to use.

DIRECTION 	NORTH | SOUTH | EAST | WEST 	
MOVEMENT_TYPE 	hop | skip | jump | leap | walk | run | gallop

With that in place, it was easy to provide a handful of sample utterances.

playGame to play
playGame to play game
playGame play
playGame play game
movewithstyle {movementtype} {direction}
move move {direction}
move go {direction}
move travel {direction}
move {direction}

And that is all there is to defining the user interface to parse what the user is doing.  Amazon’s magic converts what the user says into JSON which is passed to the actual game implementation.

I wrote the game portion as a Lambda Function using Java.  I installed the AWS Toolkit into Eclipse and found that made it a lot easier to write code on my computer and then push it up to the cloud.

So, here’s how a basic game goes:

Me:    Alexa, start Dangerous Field.
Alexa: You are standing in a field.  What do you want to do?
Me:    Go east.
Alexa: With a jiffy jog you jump joyfully to the east.
You are standing in a field.  What do you want to do?
Me:    Leap south.
Alexa: South you leap like a lascivious leprechaun launched over the rainbow.  You fall into a hole.  You die.  
You are standing in a field.  What do you want to do?  You failed to escape from the Dangerous Field.

Anyway, click the picture below to go to the Echo page and enable Dangerous Field.
dangerousFieldSkill

Farmer Giles of Ham

Tolkien BooksI have long been familiar with Tolkien’s The Hobbit and also The Lord of the Rings, but remained mostly ignorant of his other works apart from a 1982 print of The Silmarillion which somehow ended up in my collection.  This past Mother’s Day my wife received a couple volumes of other Tolkien tales and I noticed in one that among the “other books by the author” it listed The Adventures of Tom Bombadil and was intrigued enough to order it in a volume combined with Farmer Giles of Ham.

When the book arrived, I took a quick peek and immediately selected Farmer Giles of Ham as the next after dinner read aloud book for the family.  Upon completion, the family unanimously agreed that it is a terrific tale.  I think what made it so great for the entire family is that the writing is very Tolkienish, but it’s an easier read of a fantasy story (perhaps more a fairy tale) as compared to the more well-known stories involving hobbits and elves.

The story certainly contains a sufficient quantity of elements to hold the attention of all ages:  An unexpected hero going on a quest, knights, a magic sword, giants, dragons, battles, and a talking dog named Garm.  There was also the unconventional inclusion of a blunderbuss.  There are no spoilers here, but it can safely be said that the story is both amusing and entertaining.

In true Tolkien fashion, all the key players have clever names; often both a formal “book-Latin” name as well as the common “vulgar” name.  Even the the book title is referred on the title page with the lengthier “The Rise and Wonderful Adventures of Farmer Giles, Lord of Tame, Count of Worminghall and King of the Little Kingdom”.  These names tend to be more pompous and less serious than what I’ve seen in other works by Tolkien.  While the reasoning behind the names is explained when appropriate, the descriptions do not seem to require as many lengthy history lessons or descriptions of lineages as compared with that with which I was previously accustomed.

The writing style is elegant, but also accessible.  Tolkien puts words together in clever combinations that not only tell the story, but also contain wit enough to make reading alone pleasurable even were there no plot.  I did find the tone less formal than is typical.  Also, I think the words used are a little easier–I think I understood all the words and only had trouble pronouncing a few.

While not at the same literary level as The Lord of the Rings, Farmer Giles of Ham is a fun, accessible story.  Many people (especially younger readers) stall when reading Tolkien for the first time due to the immensity of Middle Earth and the history and culture that is described between (and occasionally even during) the action scenes.  For those who have started and failed or those that want a more gentle introduction, at under 80 pages Farmer Giles of Ham may be just the thing.

 

 

A refrigerator that sings

samsungFamilyHub

Unlike Talkie Toaster, the Samsung Family Hub Refrigerator is a real product and it has some interesting features.  The product page lists features such as:

  • Food Management (knowing what you have)
  • Family Connection
  • Entertainment
  • Apps

It’s not until the “More features to love” section that there is any mention that this contraption can keep food cold.  Perhaps that ability was considered obvious, but it’s interesting that the main purpose of the device is the last thing listed even though it does have some innovative cooling functionality such as FlexZone(TM) which lets you use the bottom right section as either a freezer or a fridge and a “Triple Cooling System” (apparently there are three separate evaporators to better maintain temperature and humidity).

I’d take the Family Hub Refrigerator if someone gave it to me, but I’m not going to rush out and buy one for $6,000.  I think most people could have equal smart-fridge-satisfaction by purchasing a similarly sized high-end fridge for thousands less and then slapping a Triby on the door.  Still, I think it’s worth looking at the “smart” features.

So the fridge doesn’t really sing, but it can stream music from Pandora or TuneIn.  From how frequently the Amazon Echo is used to play music during chore time, I concur that it’s nice to be able to easily play music in the kitchen.  However, this is a problem already solved in multiple ways and I’m not seeing the benefit of shoving that capacity into a refrigerator.  I certainly know of no relationship between music and food cooling.  I suppose it is possible that the size of the fridge could be used to improve sound quality (a big woofer in the bottom or using the full width to separate speakers for a better surround sound), but that doesn’t seem to be the case here.  Something I see useful in some situations in a first world problem sort of way is screen mirroring–it can mirror your TV so that when you run in from the other room to grab a snack you don’t miss what’s going on in your show.

The Family Hub includes a clock, calendar, photo display, and notes–all features that are on BakBoard and are nice, but the only benefit I see putting it on the fridge is that it provides screen real estate in a convenient location.  The screen can show weather information and some of the pictures suggest displaying the “word of the day” and “on this day in history” factoids.  There’s a “Family Bulletin Board” display and a “Morning Brief” as well.

What’s more interesting are the food related features integrated with the Family Hub. Since a refrigerator is for food, I think making a smarter refrigerator should improve that relationship with food.

Putting cameras inside and letting you view the contents without opening the door (or even being in the vicinity if using the cell phone app) is a good attempt to make refrigerator a better refrigerator.  My refrigerator is always more densely packed than the pristine Family Hub examples, so I’m not sure if it really is practical, but I would prefer it if my kids could look at a screen on the door instead of standing with the door open staring inside for minutes while trying to decide what to eat.

I won’t go into detail about the ability to search recipes or order groceries–I think those are fine and at least related to food, but not exciting.  The obvious missing piece is that the Family Hub doesn’t really know what’s in it, so it can’t suggest recipes using ingredients you have, nor can it automatically order something when you are almost out of it.  One video I saw mentions the ability to track the age of items in the fridge, but only if you always put the items back in the same spot–there aren’t any smarts to track item movement.

I think the main problem with the Samsung Family Hub is that it’s trying to be the hub of things instead of a thing in the Internet of Things.  I want smart solutions for things like food management, but a picture of the inside where I don’t see any ketchup only tells me there is no ketchup in the fridge and doesn’t tell me whether there is any in the pantry or garage.  The refrigerator is not the central hub of my home, it is merely one of many things in my home and any truly smart fridge will know its place–no matter how well it can sing.

A toaster that sings

I don’t want a toaster that sings.  I don’t want a toaster that makes polite conversation and suggests assorted bread products.  I don’t want a toaster that comes with a custom app.  I don’t want a toaster that plays games or gives a weather forecast.  I want a toaster that can toast bread.

The whole IoT (Internet of Things) concept is a nifty idea, but I think sometimes it’s taken the wrong way.  It is cheap and easy to add features and so everything is being packed with features that may or may not be useful or necessary just so the device can be labeled “smart”.  It’s easy to pick on toasters (apparently many people do)–it’s something that’s been ubiquitous in kitchens for decades and has essentially one purpose; adding “smart” features doesn’t help it accomplish its purpose better and in some cases complicates and hinders.