Click here to Skip to main content
13,148,107 members (71,883 online)
Click here to Skip to main content
Add your own
alternative version

Stats

114.5K views
1.7K downloads
161 bookmarked
Posted 20 Dec 2014

IoT for Home Automation

, 12 Jan 2015
Rate this:
Please Sign up or sign in to vote.
I built my own Internet of Things, IoT, home automation system that is controlling 30 different things with 4 different types of microcontrollers with nearly 150 commands. This article talks about IoT design patterns and the lessons learned from the design patterns that I have used.

Introduction

We live in an exciting time where more and more everyday items "things" are becoming smart!  "Things" have sensors and can communicate to other "things" and can provide control to more "things".  The Internet of Things, IoT, is upon us in a huge way and people are rapidly inventing new gadgets that enhance our lives.  The price of microcontrollers with the ability to talk over a network keeps dropping and developers can now tinker and build things inexpensively.  Developers and hardware enthusiasts no longer need to wait on others to invent or build all the "cool" stuff!  

The value of IoT is in both data and control.  With home automation it is nice to have a log of events to know when a family member did something like got home or when they turned on the fireplace.  The control aspects of IoT are really great for home automation.  It's great to be able to play with the cat via my IoT cat toy while we are on a trip anywhere in the world with an internet connection!

My Evolution of IoT Projects

My ventures into the IoT space all started with wanting to play with my kids while I was in the office and they were home swimming in the pool.  I built an IoT squirt gun out of a netduino microcontroller, a couple of servos, a solenoid valve and a water hose.  The details of this project can be read on the following article:

Home Automation with Netduino and Kinect

After having success with the squirt gun I started building other things that I could control in my home over the internet.  I used a central netduino microcontroller and started adding control for many things to the same microprocessor.  I ran wires through the walls and under my house and through my attic to control things such as the garage door, watering the gardens, and controlling the fireplace.  I built what was probably the first IoT control for a fireplace.  To top off the project I embedded a URL in a QR barcode that would open a webpage displaying a countdown.  The JavaScript on the page calls a Web API which functions as a broker to pass a message over the network to the netduino microcontroller which in turn actuates a solenoid to turn on the gas for the fireplace.  The details of that project can be read in the following article:

Using jQuery Mobile with MVC and Netduino for Home Automation

I came up with an idea to remotely control monsters in the yard for Halloween, but did not want to run wires all the way from my existing netduino to the front of the house.  The solution was to purchase a $20 Ethernet bridge and a second netduino.  

Make Each Thing Smart

It became extremely cumbersome to run wires through the house to a central microcontroller.  I also became concerned and did not want to build too much into the house that I could not take with me if we moved.  With the IoT movement starting I realized that I could make each "thing" in the house smart and on the network so that I would not need to run extra wires.  There is a lot of benefit to having each "thing" smart, including being flexible with moving things around.

Logical Living Open Source Home Automation System

I built the Logical Living open source home automation system out of out of inexpensive microcontrollers, custom circuits and other mostly household components.  The code is open source through this and other Code Project articles.  The mobile web interface has nearly a hundred and fifty buttons for controlling features in my house.  I organically built up control for each "thing" and am starting to have an intelligent house.  The best part is that it did not cost a bunch of money and even my laptop is more expensive than my home automation.   There are multiple user interfaces including gestures and speech as can be read about in the following article:

Home Automation with Microsoft Kinect Point Cloud and Speech Recognition

Microcontrollers used in Logical Living

I'm using a fleet of 4 different types of microcontrollers in my home automation system. I have learned the strengths and weaknesses of each type.  In total I'm controlling 30 things with nearly 150 features.  I have also learned the strengths and weaknesses of different design patterns for IoT.

Netduino Plus 2 - Halloween

The Netduino is an awesome open-source electronics prototyping platform based on the .NET Micro Framework.  I'm using netduino plus 2 microcontrollers to control the fireplace, 4 gardens, garage, squirt gun, 5 Halloween things including monsters, and a cat toy.  The code for the netduino is easy to maintain because its object oriented and you can do real debugging with breakpoints and such.  The netduino plus 2 microcontroller has a built in Ethernet adapter for network communication.  This adapter is not Wi-Fi but third party Wi-Fi Ethernet bridges can be added for around $20.  The form factor of the netduino plus 2 is the same as arduino and shields built for the arduino can be used with netduino.  There is not nearly as much community around the netduino as there is arduino, but I prefer netduino over most of the arduino microcontrollers for complex projects because of its strengths of running well structured object oriented code and most arduino microcontrollers do not have real debugging.  My company does a ton of C# development so it's a bonus to be able to code in C# on the .NET Micro Framework.  VB.Net is supported to on the platform, however most people code in C#.

One of my netduinos in my IoT home automation system is tasked with controlling 5 Halloween things.  There is a zombie that rubs the ground, a skeleton that jumps up, a skull that launches out on a string, a compressed air scare, and a main feature of a ghost in a coffin that has servos to pan and tilt its head at different angles.  All of the devices can be controlled with a mobile website or from a Microsoft Kinect v2 application that senses where the kids are and makes the scene react to the kids' positions.  The ghost in the coffin turns it head to look at one of the kids while they walk on the sidewalk beside the display.

Watch video of the Netduino in action controlling IoT monsters!

Watch this IoT Halloween video for more fun including a skull launcher feature!

The LogicalLiving.Netduino project has a class for everything that it controls.  In addition, there are classes for Ethernet communication, servos, and a pan tilt class with two servos.  These classes are used throughout the application and for an example the PanTilt class is reused for the squirt gun, ghost head control, and twice on the cat toy that will be talked about later in the article.

The Halloween class has private variables for everything that it controls.  These private variables configure the pins on the netduino to be an input or an output.

private OutputPort _relayZombie = Config.ReusePins.GetInstance().OutputPort2;
private OutputPort _relaySkeleton = new OutputPort(Pins.GPIO_PIN_A4, false);
private OutputPort _launchSkullMotor = new OutputPort(Pins.GPIO_PIN_A3, false);
private OutputPort _airScare = new OutputPort(Pins.GPIO_PIN_D13, false);

PanTilt _ghost = Config.ReusePins.GetInstance().PanTilt1;
private InputPort _launchSkullLimitSwitch = new InputPort(Pins.GPIO_PIN_A2, true, Port.ResistorMode.PullUp);

 I'm using one program that runs on multiple netduinos where different netduinos have different responsibilities.  The Code Maintenance section of this article has more detail on this architecture.  The code above has a _ghost  object that pulls its pin configuration from a ReusePins singleton class to support using the pins for different functionality when the program is running on a different netduino with a different responsibility.

public class ReusePins
    {
        #region Private Variables
        private static ReusePins _reusePins;
        #endregion

        #region Public Static Methods
        public static ReusePins GetInstance()
        {
            if (_reusePins == null)
            {
                _reusePins = new ReusePins();
                _reusePins.PanTilt1 = new PanTilt(Pins.GPIO_PIN_D9, Pins.GPIO_PIN_D6);
                _reusePins.PanTilt2 = new PanTilt(Pins.GPIO_PIN_D10, Pins.GPIO_PIN_D5);
                _reusePins.OutputPort1 = new OutputPort(Pins.GPIO_PIN_D3, false);
                _reusePins.OutputPort2 = new OutputPort(Pins.GPIO_PIN_A5, false); 

            }
            return _reusePins;
        }
        #endregion

        #region Public Properties
        public PanTilt PanTilt1;
        public PanTilt PanTilt2;
        public OutputPort OutputPort1;
        public OutputPort OutputPort2;
        #endregion
    }

The constructor below reads from the configuration class to set limits for the servos.  It is a good idea to put all of the configuration values in its own class so that there is one place to go to make updates.

public Halloween()
{
    _ghost.Tilt.DegreeMax = (int)Config.Halloween.GhostTiltDegreeMax;
    _ghost.Tilt.DegreeMin = (int)Config.Halloween.GhostTiltDegreeMin;
    _ghost.Tilt.InvertAngle = true;

    _ghost.Pan.DegreeMax = (int)Config.Halloween.GhostPanDegreeMax;
    _ghost.Pan.DegreeMin = (int)Config.Halloween.GhostPanDegreeMin;
    _ghost.Pan.InvertAngle = false;

    _ghost.SweepSpeedMilliseconds = Config.Halloween.GhostSweepSpeedMilliseconds;
}

There are methods to control all of the actions of the monsters. The method below starts the zombie moving and calls a private method asynchronously through a Time class that I wrote to make working with asynchronous timed events easy.

public void MoveZombieTime(int seconds)
{
    this.MoveZombie = true;
    Time.RunOnDelay(TurnOffZombieCallback, seconds * 1000);
}

private void TurnOffZombieCallback()
{
    this.MoveZombie = false;
}

The AirScare is the latest feature that I have added. It added quite a bit of impact for not much work and hardly any code. I found that you can use a $10 solenoid valve intended for watering a garden to release compressed air. My kids and I built a cool rocket launcher and I re-tasked the parts on Halloween to shoot compressed air through a hose that is fed through a bush to blow on the kids when they get close.  The air shoots out so fast that it makes a boom noise that is scary in itself!  On Halloween I keep my phone handy and push the button every time that I want to scare the kids with a half a second push from 110 pounds of compressed air and the wonderful boom noise.

public void AirScare()
{
    _airScare.Write(true);
    Thread.Sleep(500);
    _airScare.Write(false);
}

I made a scare routine that moves all of the monsters at once.  All of these features can be turned on from anywhere through the mobile web interface. This is the method that I run most often to scare people from a distance. The MoveToPosition was a method of the PanTilt class that I originally added for the squirt gun project but it's handy for anytime you want to sweep slowly into a position. The code below sets the sweep milliseconds to 15 milliseconds per degree of movement.  The classes that I wrote to control the servos through pulse width modulation, PWM, are included in the source code as well.

public void Scare()
{
    MoveZombieTime(20);
    MakeSkeletonJump();

    _ghost.SweepSpeedMilliseconds = 15;
    Time.RunOnDelay(LaunchSkull, 4000);

    for (int count = 0; count < 2; count++)
    {
        _ghost.MoveToPosition(170, 120);
        _ghost.MoveToPosition(170, 60);
        _ghost.MoveToPosition(10, 90);
        _ghost.MoveToPosition(10, 120);
        _ghost.MoveToPosition(10, 170);
        _ghost.MoveToPosition(50, 50);
        _ghost.MoveToPosition(110, 110);
        _ghost.MoveToPosition(90, 90);
    }

    _ghost.DisengageServos();
}

The picture below shows how I mounted the skull to pan and tilt servos and even added LEDs for the eyes!

Netduino Plus 2 - Cat Toy

We have a spoiled cat and I came up with a way to spoil her more with help from the IoT!  I built an IoT cat toy that is controlled online so that I can play with the cat while I'm anywhere with an internet connection.  The cat toy has a netduino plus 2 microcontroller and a Netgear Ethernet bridge so that I can send messages over Wi-Fi to the cat toy from a broker that is a gateway to the internet.  It's a single unit with the only external wires being the power cord.

There is a laser mounted to an assembly of pan and tilt servos. The methods to control the cat toy are in the CatToy class of the LogicalLiving.Netduino project. The laser can be moved around in a random pattern but I found that the cat loses interest if she cannot ever catch the laser. The laser will sweep to a random position and then 25% of the time pause for a short random time before sweeping to the next position.

public void RandomLaserPattern(int repeat)
{
    this.FireLaser = true;
    Random rnd = new Random();
    for (int count = 0; count < repeat; count++)
    {
        _laser.SweepSpeedMilliseconds = rnd.Next(100);
        _laser.MoveToPosition(rnd.Next(175), rnd.Next(60) + 90);

        // Pause occasionally for half a second
        if (rnd.Next(100) > 75)
            Thread.Sleep(rnd.Next(500));
    }

    _laser.SweepSpeedMilliseconds = 50;
    this.FireLaser = false;
    _laser.DisengageServos();
}

There is also a mouse puppet on a string connected to servos that moves around in set patterns.

public void MouseLeftRight()
{
    _mouse.MoveToPosition(90, 90);
    _mouse.Pan.Angle = 30;
    Thread.Sleep(600);
    _mouse.Pan.Angle = 150;
    Thread.Sleep(600);
    _mouse.Pan.Angle = 30;
    Thread.Sleep(600);
    _mouse.MoveToPosition(90, 90);

    _mouse.DisengageServos();
}

public void MouseUpDown()
{
    _mouse.MoveToPosition(90, 90);
    _mouse.Tilt.Angle = 60;
    Thread.Sleep(600);
    _mouse.Tilt.Angle = 120;
    Thread.Sleep(600);
    _mouse.Tilt.Angle = 60;
    Thread.Sleep(600);
    _mouse.MoveToPosition(90, 90);

    _mouse.DisengageServos();
}

It is important to notice how similar the code is for moving the cat toy laser, cat toy mouse puppet, ghost's head on Halloween or controlling the squirt gun. Object oriented code for the netduino makes the netduino very powerful and leads to much reusable code.

Click here to see the cat toy in action!!!

Areon Z-Stick Z-Wave USB Adapter

Z-Wave is a wireless communications protocol designed for home automation.  There are tons of commercially available Z-Wave devices and some are even available on the shelf in retail chain stores.  My home automation includes 15 Z-Wave devices which are mostly lights and other 120 VAC powered things.  Z-Wave products are designed using low-cost, low-power RF transceiver chips and typically cost around $50 to control a light or outlet. All of the devices send messages over a mesh network.  The mesh network uses smart routing to deliver the messages to the targeted Z-Wave device node efficiently.  The messages are chatty to support the routing ability and to confirm that the message reached the proper Z-Wave node.  Z-Wave devices need to be close enough together to communicate over their low power radio and the range is around 100 ft or 40 m.  Z-wave devices on their own make a great local network, but need a broker to be a gateway to be controlled on the internet.   I'm using an Areon Z-Stick Z-Wave USB Adapter connected to a broker that I wrote with a Web API. 

The LogicalLiving.ZWave project contains all the methods to communicate with the Z-Wave USB Adapter that are consumed by a Web API and by the LogicalLiving.Zwave.DesktopMessenger windows forms application.  I built the desktop messenger forms application to learn about the byte arrays that needed to be sent and received to support the Z-Wave messages.  The byte array messages displayed in the UI helped me figure out how to hack the Areon Z-Stick Z-Wave USB Adapter to send and receive the proper byte arrays.  The desktop messenger is also helpful to troubleshoot issues with the Z-Wave devices that are not working.  The most common problem that I use the desktop messenger for now is to figure out the devices node.

The first step of the CommunicateWithZWave class of the LogicalLiving.ZWave project is to receive a message containing the deviceNode and the deviceState that you want to set it to.

public string Message(DeviceNode deviceNode, DeviceState deviceState)
{
    if (_serialPort == null || !_serialPort.IsOpen)
        OpenSerialPort();
    string message = "";
    if (deviceNode == DeviceNode.All)
    {
        UpdateStateOnAllDevices(deviceState);
    }
    else
    {
        message = AssuredZwaveMessage(deviceNode, deviceState);
    }
    return message;
}

If the serial port is not already open then it opens the serial port and sets up an event handler for serial data received.

private void OpenSerialPort()
{
    _serialPort = new SerialPort();

    //You can look up the COM port number in the computer devices.  
    //It shows up as a CP2102 USB to UART Bridge Controller in the computer devices.
    _serialPort.PortName = "COM3";  
    _serialPort.BaudRate = 115200;
    _serialPort.Parity = Parity.None;
    _serialPort.DataBits = 8;
    _serialPort.StopBits = StopBits.One;
    _serialPort.Handshake = Handshake.None;
    _serialPort.DtrEnable = true;
    _serialPort.RtsEnable = true;
    _serialPort.NewLine = System.Environment.NewLine;

    _serialPort.Open();

    _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
}

The AssuredZwaveMessage is a private method used to send out the message to the device node to set the device state.  It has a retry counter to try a hundred times before giving up.

private string AssuredZwaveMessage(DeviceNode deviceNode, DeviceState deviceState)
{
    string returnMessage = "Message not sent!";
    if (_serialPort.IsOpen)
    {
        byte[] message = new byte[] { 0x01, 0x09, 0x00, 0x13, (byte)deviceNode, 0x03, 0x20, 0x01, 
                                     (byte)deviceState, 0x05, 0x00 };

        int retryCount = 0;
        while (!SendMessage(message) && retryCount++ < 100)
        {
            Thread.Sleep(100);
        }
        returnMessage = ByteArrayToString(message);
    }
    return returnMessage;
}

The SendMessage method sends the byte array to the serial port for the USB adapter. All messages other than acknowledgement messages (0x06) require a checksum at the end. Writing to the serial port needs to be single threaded.

private Boolean SendMessage(byte[] message)
{
    if (_serialPort.IsOpen == true)
    {
        //All messages other than Acknowledgement Messages (0x06) require a checksum
        if (message[0] != 0x06)
        {
            if (!SetMessagingLock(true)) return false;
            _sendAcknowledgementAfterDataReceived = false;
            message[message.Length - 1] = GenerateChecksum(message); 
        }
        _serialPort.Write(message, 0, message.Length);
        SetMessagingLock(false);
        return true;
    }
    return false;
}

Messages received other than acknowledge messages need to send their own acknowledgement message. An event is raised by a serial message received so that the desktop messenger application can display the message received. This information would normally be private to the CommunicateWithZWave but is helpful to display the byte arrays in the desktop messenger application to help you figure out the messages that need to be sent and received for the Z-Wave devices.

private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    int bytesToRead = _serialPort.BytesToRead;
    if ((bytesToRead != 0) & (_serialPort.IsOpen == true))
    {
        byte[] message = new byte[bytesToRead];
        _serialPort.Read(message, 0, bytesToRead);

        RaiseEvent(EventHandlerMessageReceived, ByteArrayToString(message));

        if (_sendAcknowledgementAfterDataReceived) 
        {
            SendAcknowledgementMessage();
        }
        _sendAcknowledgementAfterDataReceived = true;
    }
}

IR Toy

The IR Toy is a USB device that allows you to send and receive IR signals.  I use the IR toy to send IR commands to our TV, satellite receiver for TV and music, and audio receiver.  

There is a WinLirc windows application that you can use to interface with the IR Toy. WinLIRC is the Windows equivalent of LIRC, http://www.lirc.org, the Linux Infrared Remote Control program.  The configuration files for most commercial remote controls can be found online at the URL: http://lirc.sourceforge.net/remotes/.  You need to write your own broker to be able to control the IR Toy over the internet. The broker will need to take your web requests and launch a process to send the IR code.

The LogicalLiving.IRToy project handles launching the process to send the IR signals to the devices based on the configuration files loaded in WinLirc.  Sending an IR command is as simple as launching a process.

private static void SendIR(string remoteControl, string remoteCommand)
{

    ProcessStartInfo startInfo = new ProcessStartInfo();

    startInfo.FileName = "C:\\LogicalLiving\\LogicalLiving.IRToy\\WinLirc\\Transmit.exe";
    startInfo.Arguments = remoteControl + " " + remoteCommand + " 0";
    Process processTransmit = Process.Start(startInfo);
    processTransmit.WaitForExit();
    return;
}

Macros can be built by launching a new process for each command. For example if your favorite music station was channel 6008 then you would run the code below to send the command to change the channel.

SendIR("dish5", "6");
SendIR("dish5", "0");
SendIR("dish5", "0");
SendIR("dish5", "8");

I'm not proud of my IR code other than the fact that it works and the end result is neat and it's handy to be able to control the TV from the internet. I plan on re-factoring my IR code and hardware to run on a device that is not connected to a computer. For now I have it running on a workstation in the home office and use an IR repeater that converts the IR signal to a radio signal and then have radio receivers in a line of site to the devices. The receiver reads the radio signal and transmits an IR signal to the devices.

Spark Core

The Spark Core is a tiny Wi-Fi development board that makes it easy to create internet-connected hardware. The Spark Core runs same C like programming language that Arduino uses, so the masses that are familiar with Arduino are productive from the start.  I prefer object orientated languages with debugging capabilities, but the Spark Core makes up for this and more by having some really cool and incredible features:

  • Its tiny - The Spark Core's form factor is somewhere in the order of ten times smaller than what I have been using for a microcontroller with Wi-Fi bridge.
  • Its easy to config your network's Wi-Fi settings - They created native mobile apps for both Android and iOS that you configure to connect to your Wi-Fi network.  Once your Wi-Fi network is configured in the app, then your phone sends the configuration to the Spark Core wirelessly.  That is so much easier than all the other devices that I have used in the past that required a wired connection.  It is such a pain to update the Wi-Fi network on my cat toy using a different microcontroller because I have to disconnect wires to connect the Wi-Fi bridge to my laptop and then finally reconnect everything back when done.  
  • Over The Air, OTA, updates of code facilitates rapid development - The best feature of the Spark Core is the ease that you can flash code updates to your remote device.  My Spark Core is outside and it's cold and raining today.  I can be sitting in the office or anywhere with an internet connection and flash code updates remotely.  It is very inconvenient to plug my laptop into some of my other IoT projects to do updates.  There is a simple feature that I have been wanting to add for a month to the cat toy project built on a different platform but the pain of connecting my laptop to the hard to access microcontroller has kept me from making the update.

Watch my Spark Core IoT Christmas Tree Video!!

I built a 20 foot Christmas tree that the Spark Core is controlling.  The construction was simple and I did the project over two weekends.  I constructed the tree the first weekend and built the control circuit and wrote the software the second weekend.  The tree was constructed with attaching 12 strands of lights to 2 threaded 10 foot cast iron pips connected together with a plumbing fitting.   The strands of lights are staked into the ground with tent stakes. The entire tree and control circuit was built for around $150.  The lights that I'm using require 120 VAC power and I'm using the Spark Core to drive solid state relays that are built for control of 120 VAC or 240 VAC things.

The pins are named at the start of the program.

int treeRelay1  = D0; 
int treeRelay2  = D1; 
int treeRelay3  = D2;
int treeRelay4  = D3;
int treeRelay5  = D4;
int treeRelay6  = D5;
int treeRelay7  = D6;
int treeRelay8  = D7;
int treeRelay9  = A4;
int treeRelay10 = A5;
int treeRelay11 = A6;
int treeRelay12 = A7;

The setup method runs once on reset and is used to configure 12 of the pins on the Spark Core to be digital output pins for each of the 12 branches of the tree.

void setup() 
{
    pinMode(treeRelay1,  OUTPUT);
    pinMode(treeRelay2,  OUTPUT);
    pinMode(treeRelay3,  OUTPUT);
    pinMode(treeRelay4,  OUTPUT);
    pinMode(treeRelay5,  OUTPUT);
    pinMode(treeRelay6,  OUTPUT);
    pinMode(treeRelay7,  OUTPUT);
    pinMode(treeRelay8,  OUTPUT);
    pinMode(treeRelay9,  OUTPUT);
    pinMode(treeRelay10, OUTPUT);
    pinMode(treeRelay11, OUTPUT);
    pinMode(treeRelay12, OUTPUT);
}

The lightTree method sets all the 12 channels of the tree to the desired state of on or off.

void lightTree(boolean tree1, boolean tree2, boolean tree3, boolean tree4, boolean tree5,
                boolean tree6, boolean tree7, boolean tree8, boolean tree9, boolean tree10, 
                boolean tree11, boolean tree12, int delayMilliSeconds) 
{
    digitalWrite(treeRelay1,  tree1);
    digitalWrite(treeRelay2,  tree2);
    digitalWrite(treeRelay3,  tree3);
    digitalWrite(treeRelay4,  tree4);
    digitalWrite(treeRelay5,  tree5);
    digitalWrite(treeRelay6,  tree6);
    digitalWrite(treeRelay7,  tree7);
    digitalWrite(treeRelay8,  tree8);
    digitalWrite(treeRelay9,  tree9);
    digitalWrite(treeRelay10, tree10);
    digitalWrite(treeRelay11, tree11);
    digitalWrite(treeRelay12, tree12);
    delay(delayMilliSeconds); 
}

The shiftTreeLeft method is to rotate all of the lights to the left.  The delayMilliSeconds parameter is used to set the time delay between frames of rotation.  The loopCount is used to set the number of frames to do the rotation on.  Most of the time this count is 12 so that the pattern can rotate through all of the branches in the tree.

void shiftTreeLeft(boolean tree1, boolean tree2, boolean tree3, boolean tree4, boolean tree5, 
                    boolean tree6, boolean tree7, boolean tree8, boolean tree9, boolean tree10, 
                    boolean tree11, boolean tree12, int delayMilliSeconds, int loopCount) 
{
    for (int count = 1; count <= loopCount; count++) 
    { 
        lightTree(tree1, tree2, tree3, tree4, tree5, tree6, tree7, tree8, tree9, tree10, 
                    tree11, tree12, delayMilliSeconds);
                    
        boolean treeHold = tree1;
        tree1=tree2;
        tree2=tree3;
        tree3=tree4;
        tree4=tree5;
        tree5=tree6;
        tree6=tree7;
        tree7=tree8;
        tree8=tree9;
        tree9=tree10;
        tree10=tree11;
        tree11=tree12;
        tree12=treeHold;
    }
}

The fadeTree method is similar to the lightTree method but each of the 12 branches have multiple states to indicate brightness instead of just a boolean state of on or off.  The states range from 0 to 10 where 0 is off, 5 is 50% bright, and 10 being all on.  The Spark Core has 8 pins that can be used for pulse width modulation, PWM, but I have 12 branches on the tree that need individual control.  This method acts like a crude pulse width modulator, PWM, to cycle the on state with the off state for the correct proportion of time to have the desired brightness level for each strand of lights on the tree.

void fadeTree(int tree1, int tree2, int tree3, int tree4, int tree5, int tree6, int tree7, 
                int tree8, int tree9, int tree10, int tree11, int tree12)
{
    for (int pulse = 1; pulse <= 10; pulse++) 
    { 
        lightTree(pulse<=tree1, pulse <= tree2, pulse<=tree3, pulse<=tree4, pulse<=tree5, 
                    pulse<=tree6, pulse<=tree7, pulse<=tree8, pulse<=tree9, pulse<=tree10, 
                    pulse<=tree11, pulse<=tree12, 5);
    }
}

The fadeTree method can be called many times with different frames of data to produce many cool effects.

void fadeTreeRotate()
{
    fadeTree(10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 10);
    fadeTree(8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 10, 10);
    fadeTree(6, 4, 2, 0, 2, 4, 6, 8, 10, 10, 10, 8);
    fadeTree(4, 2, 0, 2, 4, 6, 8, 10, 10, 10, 8, 6);
    fadeTree(2, 0, 2, 4, 6, 8, 10, 10, 10, 8, 6, 4);
    fadeTree(0, 2, 4, 6, 8, 10, 10, 10, 8, 6, 4, 2);
    fadeTree(2, 4, 6, 8, 10, 10, 10, 8, 6, 4, 2, 0);
    fadeTree(4, 6, 8, 10, 10, 10, 8, 6, 4, 2, 0, 2);
    fadeTree(6, 8, 10, 10, 10, 8, 6, 4, 2, 0, 2, 4);
    fadeTree(8, 10, 10, 10, 8, 6, 4, 2, 0, 2, 4, 6);
    fadeTree(10, 10, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8);
    fadeTree(10, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10);
}

The fadeAllTree method is used to fade all the lights on the tree from off to on and then fade them all off.

void fadeAllTree()
{
    for (int count = 0; count <= 10; count++)
    {
        fadeTree(count,count,count,count,count,count,count,count,count,count,count,count);
    }
    for (int count = 10; count >= 0; count--)
    {
        fadeTree(count,count,count,count,count,count,count,count,count,count,count,count);
    }
}

Like other Arduino Wiring programming frameworks, the loop method loops forever causing the tree to repeat its awesome light show!

void loop() 
{
    shiftTreeLeft(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 12);
    shiftTreeRight(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 12);
    fadeAllTree();
    fadeAllTree();
    fadeAllTree();
    fadeAllTree();
    shiftTreeLeft(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 600, 5);
    shiftTreeLeft(1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 40, 12*4);
    lightTree(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000);
    diamond(false);
    delay(300);
    diamond(true);
    shiftTreeLeft(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 150, 12*4);
    fadeTreeRotate();
    fadeTreeRotate();
    fadeTreeRotate();
    fadeTreeRotate();
    shiftTreeRight(1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 80, 12*6);
    lightTree(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1000);
}

Microcontroller Code Maintenance Design Pattern

It can become difficult to maintain separate programs for each "thing" that you have in your fleet.  The more things that you have the harder it is to maintain different versions of the code.  In many cases it is easy to have the same program running on a fleet of the same type of microcontroller even when they have different functions.  Rather than having separate programs for each netduino microcontroller, I presently have 3 netduinos running the same program and each netduino learns its identity and sets its responsibilities from its mac address.  The same program behaves differently based on switches from the microcontroller's identity.  

  • netduino 1 - Controls the fireplace, garden, garage and the squirt gun
  • netduino 2 - Controls the cat toy
  • netduino 3 - Controls the 5 Halloween things

The program on each netduino sets a static IP address based on the identity determined from its mac address.  A more flexible design would be to have each microcontroller connect to the network and obtain a DHCP IP address.  The microcontrollers would then send a message with their mac address to an identity service which would return a message containing identity and configuration information for that specific netduino.

IoT Communication Design Patterns

Pattern 1 - Thing is a server

The "thing" can be a server that accepts inbound requests.  This pattern can be configured on a "thing" by setting up a web server.  This might be ok security wise for internal networks, but is not secure for internet communications.  One major issue is that a port needs to be opened up through the firewall so that the request can be routed to the thing.  This can be insecure and is not very portable to move to another network.  The "thing" can also become overloaded with requests and this pattern has tight coupling with whatever is communicating with it.

Pattern 2 - Thing is a client

The easiest design pattern for IoT communication is having a "thing" be a client that connects to a service.  It is common for the "thing" to post, put or get data.  This pattern is more secure than the first pattern because no ports need to be opened up on the firewall.  The "thing" can also control how often it connects to the service so it is not going to become overloaded with requests.  Like the first pattern the "thing" is still tightly coupled with the service that it is communicating with.

 

Pattern 3 - Thing polls a service

With a polling strategy a "thing" can send and receive messages from a service without opening up a port on the firewall.  The polling strategy can be implemented many ways including a long polling or WebSockets.  The "thing" is not going to become overloaded with requests, but the service communicating with the "thing" will need to implement a queue to store messages until the thing is ready to process them.

Pattern 4 - Things communicate through a broker

A broker is software middleware between the "thing" and whatever is communicating with it.  Most of my previous IoT implementations have been done with "things" that are tightly coupled to a broker that dispatches messages to other "things".  I have learned that a well designed broker can connect publishers with subscribers in a loose coupled approach without opening up a port in the firewall.  I'm in the process of re-factoring my code to implement this approach leveraging MQTT protocol and an open source broker called Mosquitto.

 

Pattern 5 - Things communicate with both a local and remote broker

A more flexible IoT communication design pattern is to have to have brokers on both sides of your network firewall.  One of the brokers should be local and one hosted off your network in the cloud.  

This will allow for higher reliability.  It is important that losing your internet connection does not prohibit your home automation things from talking to other local things.  If your things and brokers communicate with a polling strategy then no ports need opened on the firewall and your things will not be overloaded with requests.

Design Lessons learned from my IoT projects

I have learned quite a bit from building my own IoT home automation: 

  • Lesson 1 - Make each thing smart.  It is hard to move things around when all of your things are connected with wires to a central controller.  If each "thing" is self-contained then it's easy to move it around and easy to take it with you when you move.
  • Lesson 2 - Being able to update the program (firmware) Over The Air, OTA, leads to more rapid development of new features.
  • Lesson 3 - Use DHCP and an identity service and have one program for all of the devices for each type of microcontroller in your fleet.
  • Lesson 4 - Use a publish / subscribe model with a broker to loosely couple all of the things

Funny Lessons learned from my IoT projects

  • Lesson 1 - With great power comes great responsibility!  One of my projects talked about in the article was to send IR signals to the TV, DVR, and music.  I added the control to my mobile web interface and started randomly changing the TV channels or music when I was away from home.  It was my way to tell my family that I was thinking of them, but only they did not see it that way!  When I got home someone had disabled the control by removing key wires!  I was however proud that my family member figured out which wires to remove to disable it though!
  • Lesson 2 - Be careful when controlling fire with IoT!  We have a cat that likes to play in funny places.  I was excited when I added control for the fireplace but the cat was also interested in the project and wanted to learn more!  I added speech recognition to the mix and voice from the TV would say the phrase occasionally to turn on the fireplace.  We can also turn on the fireplace when we are away if we want to make the house feel cozy when we get home.  A burned kitty would mean the end of my IoT projects so I quickly wired up a mesh screen to keep the cat out!
  • Lesson 3 - If you squirt the kids too often they will start ignoring it!  It is hard to resist nailing your friends and family with cold water when the control is as easy as pushing a few buttons on your phone.
  • Lesson 4 - When its in the home then it has to be nearly 100% reliable.  Family members are not forgiving of quality defects!  The home automation will not be used if it is not reliable and family members will let you know it!  My netduino's used to lock up after a couple of days because of Ethernet communication issues.  I knew I had a serious support problem with the reliability when my wife called me when I was away from home because the garden was not watering.  I spent days working out the issue and finally resolved it by having the code detect the issue and then reboot the device to recover.  The netduino's reboot quickly even with code that I wrote to call to a time service on start up to set the date and time.  The reboot is so fast that people do not usually notice the downtime.  The home automation needs to be nearly 100% reliable or its not worth the support efforts or the frustration of other family members.

Download the code

I hope that you enjoyed this article and hopefully you got some ideas for your own projects!

If you are running Windows 7 then load the first link of Logical Living. If you have Windows 8 or higher and have a Kinect v2 sensor then load the Kinect v2 version. You will need to install the Kinect SDK 2.0 from Microsoft to get the Kinect code working. The speech recognition code requires the Kinect Speech Language Packs and Speech Runtime to work. You can test the speech basics-WPF sample app that installs as a sample with the SDK to make sure you have everything installed to make the speech recognition work. The Kinect Living code can run on a remote machine on the internet and interact with the WebApi on your local network.

Follow Dan on Twitter

Dan tweets IoT topics and technology frequently. Follow Dan on twitter: @LogicalDan

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dan Thyer
Chief Technology Officer Logical Advantage
United States United States
Dan graduated summa cum laude from North Carolina State University with dual degrees in Electrical Engineering and Computer Engineering. Dan attended NC State on full scholarship program with General Motors. After working with GM, Dan served as application development director for the largest Microsoft Business Solutions Partner in the Carolinas. During this time, Dan's team won two Microsoft Pinnacle awards. For the past 10 years, as Co-Founder and Chief Technology Officer of, Logical Advantage (www.logicaladvantage.com), a software consulting business, Dan has successfully architected and delivered web-based and mobile applications for many Fortune 500 companies. Dan focuses his energies on emerging technologies, and ensuring that all projects are architected to meet the client's current and future needs. Dan collaborates with his Chief Solutions Officer and other architects to create technical standards, including coding standards, tools, and platforms. He holds a leadership role in the local Microsoft Enterprise Developer's Guild and has been on the steering committee for over a dozen years.

You may also be interested in...

Pro

Comments and Discussions

 
QuestionQuestion regarding IOT Pin
Member 1294509911-Jan-17 2:49
memberMember 1294509911-Jan-17 2:49 
Questionneed guidance to detect humans through xbox or camera Pin
Member 1030796327-Feb-16 2:15
memberMember 1030796327-Feb-16 2:15 
GeneralGot my 5!! Pin
Karl Shifflett7-Sep-15 14:07
memberKarl Shifflett7-Sep-15 14:07 
GeneralMy vote of 5 Pin
DVL Patel2-Sep-15 18:47
professionalDVL Patel2-Sep-15 18:47 
GeneralRe: My vote of 5 Pin
Dan Thyer3-Sep-15 1:43
memberDan Thyer3-Sep-15 1:43 
QuestionQuestion about video Pin
dlandrum9125-Feb-15 2:56
memberdlandrum9125-Feb-15 2:56 
AnswerRe: Question about video Pin
Dan Thyer26-Feb-15 14:05
memberDan Thyer26-Feb-15 14:05 
QuestionQuestion about MQTT and Mosquito Pin
dlandrum9119-Feb-15 3:51
memberdlandrum9119-Feb-15 3:51 
AnswerRe: Question about MQTT and Mosquito Pin
Dan Thyer19-Feb-15 4:07
memberDan Thyer19-Feb-15 4:07 
QuestionMicrosoft Azure IoT Contest Pin
Muhammad Gouda17-Feb-15 8:40
professionalMuhammad Gouda17-Feb-15 8:40 
AnswerRe: Microsoft Azure IoT Contest Pin
Dan Thyer17-Feb-15 9:52
memberDan Thyer17-Feb-15 9:52 
GeneralMy vote of 5 Pin
newton.saber13-Jan-15 10:19
membernewton.saber13-Jan-15 10:19 
GeneralRe: My vote of 5 Pin
Dan Thyer13-Jan-15 10:40
memberDan Thyer13-Jan-15 10:40 
QuestionHardware Question Pin
GPIB113-Jan-15 7:29
memberGPIB113-Jan-15 7:29 
AnswerRe: Hardware Question Pin
Dan Thyer13-Jan-15 10:39
memberDan Thyer13-Jan-15 10:39 
GeneralGreat Article! Pin
Member 1060974613-Jan-15 7:04
professionalMember 1060974613-Jan-15 7:04 
GeneralRe: Great Article! Pin
Dan Thyer13-Jan-15 7:14
memberDan Thyer13-Jan-15 7:14 
GeneralMy vote of 5 Pin
MarkBoreham13-Jan-15 6:32
professionalMarkBoreham13-Jan-15 6:32 
GeneralRe: My vote of 5 Pin
Dan Thyer13-Jan-15 6:36
memberDan Thyer13-Jan-15 6:36 
GeneralMy vote of 5 Pin
Tokinabo10-Jan-15 6:02
memberTokinabo10-Jan-15 6:02 
GeneralRe: My vote of 5 Pin
Dan Thyer10-Jan-15 10:08
memberDan Thyer10-Jan-15 10:08 
GeneralMy vote of 5 Pin
KChandos9-Jan-15 5:19
memberKChandos9-Jan-15 5:19 
GeneralRe: My vote of 5 Pin
Dan Thyer9-Jan-15 7:27
memberDan Thyer9-Jan-15 7:27 
GeneralMy vote of 5 Pin
Mahsa Hassankashi30-Dec-14 13:15
memberMahsa Hassankashi30-Dec-14 13:15 
GeneralRe: My vote of 5 Pin
Dan Thyer30-Dec-14 15:05
memberDan Thyer30-Dec-14 15:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.170924.1 | Last Updated 12 Jan 2015
Article Copyright 2014 by Dan Thyer
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid