Viewing all Queued Builds in TFS: Part 2

As I discussed in part one of this article, TFS 2010 does not give a friendly view for an administrator to see what all builds are currently running. Because our TFS has so many team projects, it becomes extremely annoying to dig through each project to find out when a build has hung up a build agent.

Recently, we decided to retire our existing build machines and replace them with newer, more powerful machines, machines that would be capable of running more than one build at a time. Previously, we had several build machines (5-6), each of which had a single build controller and build agent running on them. Unfortunately, if six different developers on different development teams working in different Team Projects queued up a build on the same build machine, then five of the builds would be queued on that single machine, and none of those developers (or more importantly, me!) had an easy view into what they were waiting for. Ultimately, that one machine became wasteful bottleneck, as there would be several other unused machines.

Because of this, and other reasons, we revised our build machines’ topology. Now we are using a single build controller, and then we configured twelve new build agents spread across several machines. This allowed the build controller to make use of all the available build agents and solved the bottleneck caused by our prior topology.

Unfortunately, this made the console application that I wrote obsolete. Before, the console app only reported the build controllers that had builds running on them. This was fine, as long as there was a 1:1 relationship between build machines and build controllers. But now we only have one build controller, so if there was an issue with one of the twelve build agents assigned to that controller, the console app would not be useful to us as a troubleshooting tool.

To solve this problem, I further mangled/modified the console app posted on Bart Wullem’s blog to display the build controller’s name and the build agent’s name for all queued builds.

It is pretty simple to create a new console application in Visual Studio using the source I documented below. However, if you are anything like me you sure appreciate when someone shares a binary that they can use. You can download a copy here.

Installation Directions

  1. Unzip the contents to a folder. (Optional: For ease of use, add the folder you unzipped it to into your Windows PATH environment variable)
  2. Open the folder and edit the config file (TFSBuildQueue.exe.config), there is a single configuration entry in there for the URL of your TFS Project Collection (usually: http://yourtfsserver:8080/tfs/defaultcollection)
  3. Open a command console and set the width to at least 180 columns
  4. Change Directory to the path you unzipped TFSBuildQueue.zip to.
  5. Execute tfsbuildqueue.exe

Source Code

TFSBuildQueue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Build.Client;

namespace TFSBuildQueue
{
    class Program
    {
        static void Main(string[] args)
        {
            int BuildCount = 0;
            string TFS_URL = ConfigurationManager.AppSettings["TFS_URL"];
            Console.WriteLine("\nTFS Build Queue");
            Console.WriteLine("===============\n");
            Console.WriteLine("Connecting to: " + TFS_URL + " and querying build controllers...");
            TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new            Uri(TFS_URL));
            IBuildServer bs = tfs.GetService<IBuildServer>();
            IQueuedBuildSpec qbSpec = bs.CreateBuildQueueSpec("*", "*");
            IQueuedBuildQueryResult qbResults = bs.QueryQueuedBuilds(qbSpec);


            // Define DataTable for storage and manipulation of currently queued builds.
            DataTable QBTable = new DataTable();
            QBTable.Columns.Add("BuildMachine");
            QBTable.Columns.Add("Project");
            QBTable.Columns.Add("BuildDefinition");
            QBTable.Columns.Add("BuildStatus");
            QBTable.Columns.Add("Priority");
            QBTable.Columns.Add("Date");
            QBTable.Columns.Add("ElapsedTime");
            QBTable.Columns.Add("User");


            // Query TFS For Queued builds and write each build to QBTable
            foreach (IQueuedBuild qb in qbResults.QueuedBuilds)
            {
                qb.Build.RefreshAllDetails();
                string RequestedBy = qb.RequestedBy.PadRight(18);
                if (qb.RequestedBy != qb.RequestedFor)
                {
                    RequestedBy = String.Concat(qb.RequestedBy, " (for ", qb.RequestedFor, ")").PadRight(18);
                }
                DateTime CurrentTime = DateTime.Now;
                TimeSpan ElapsedTime = CurrentTime.Subtract(qb.QueueTime);
                string ElapsedTimeString = ElapsedTime.ToString();
                String TFSET = ElapsedTimeString;
                String TFS_TEAMPROJECT;
                String BuildAgentStr;
                String BuildMachineStr;
                if (qb.Status.ToString() != "InProgress")
                {
                    TFS_TEAMPROJECT = "-------";
                    BuildAgentStr = "N/A";
                }
                else
                {
                    TFS_TEAMPROJECT = qb.Build.TeamProject;
                    BuildAgentStr = GetBuildAgent(qb.Build);
                }
                BuildMachineStr = qb.BuildController.Name + " (" + BuildAgentStr.ToUpper() + ")";

                QBTable.Rows.Add(
                BuildMachineStr.PadRight(46),
                TFS_TEAMPROJECT.PadRight(17),
                qb.BuildDefinition.Name.PadRight(28),
                qb.Status.ToString().PadRight(11),
                qb.Priority.ToString().PadRight(9),
                qb.QueueTime.ToString().PadRight(23),
                TFSET.PadRight(17),
                RequestedBy.PadRight(19)
                );
             BuildCount++;
            }

            // Sorts QBTable on Build controller then by date
            DataRow[] QBSorted = QBTable.Select("", "BuildMachine ASC, Date ASC");

            // Writes the headers 
            WriteHeaders();

            foreach (DataRow dataRow in QBSorted)
            {
                WriteReportLine(
                    dataRow[0].ToString(),
                    dataRow[1].ToString(),
                    dataRow[2].ToString(),
                    dataRow[3].ToString(),
                    dataRow[4].ToString(),
                    dataRow[5].ToString(),
                    dataRow[6].ToString(),
                    dataRow[7].ToString());
            }


            Console.WriteLine("\n\nTotal Builds Queued: " + BuildCount + "\n\n");
        }

        static void WriteHeaders()
        {
            Console.WriteLine("\n\n");
            Console.WriteLine("Build Controller (Agent)".PadRight(46) + " " +
                              "Project".PadRight(17) + " " +
                              "Build Definition".PadRight(28) + " " +
                              "Status".PadRight(11) + " " +
                              "Priority".PadRight(9) + " " +
                              "Date & Time Started".PadRight(23) + " " +
                              "Elapsed Time".PadRight(17) + " " +
                              "User".PadRight(19));
            Console.WriteLine("============================================".PadRight(46) + " " +
                              "=======".PadRight(17) + " " +
                              "================".PadRight(28) + " " +
                              "=======".PadRight(11) + " " +
                              "========".PadRight(9) + " " +
                              "=====================".PadRight(23) + " " +
                              "================".PadRight(17) + " " +
                              "============".PadRight(19));
        }

        static void WriteReportLine(string TFSBuildController, string TFSProject, string TFSBuildDefinition, string TFSBuildStatus, string TFSBuildPriority, string TFSBuildDateTime, string ElapsedTime, string TFSBuildUser)
        {
            Console.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7}", TFSBuildController, TFSProject, TFSBuildDefinition, TFSBuildStatus, TFSBuildPriority, TFSBuildDateTime, ElapsedTime, TFSBuildUser);
        }

        public static string GetBuildAgent(IBuildDetail build)  //IQueuedBuild.Build
        {
            foreach (var child in build.Information.Nodes)
            {
                string AgentName = ShowChild(child, 1);
                if (!string.IsNullOrEmpty(AgentName))
                {
                    return AgentName;
                }
            }
            return string.Empty;
        }

        static string ShowChild(IBuildInformationNode node, int level)
        {
            string levelStr = new string(' ', level * 4);
            foreach (var field in node.Fields)
            {
                if (field.Key == "ReservedAgentName")
                {
                    return field.Value;
                }
            }

            foreach (var child in node.Children.Nodes)
            {
                string AgentName = ShowChild(child, level + 1);
                if (!string.IsNullOrEmpty(AgentName))
                {
                    return AgentName;
                }
            }
            return string.Empty;

        }

    }

}

My Network Cupboard: The Dramatic Conclusion

What We Did

In the end we wound cabling 6 rooms in total; the laundry room where the cupboard is located, the den/office, each of the three bedrooms and the living room. We built out a miniature 19” rack in an empty cupboard and on that rack we installed; a 48 port patch panel that I purchased cheaply from eBay, two 8 port Netgear Gigabit switches, and we relocated the Verizon FiOS modem inside the cupboard. Built into the cupboard is room for some future growth. Two of the ports on the Netgear switches are empty, three of the 10/100 ports on the Verizon FiOS modem are open and there are literally dozens of empty ports on the patch panel.

With this project, there was a little bit of “design-on-the-fly”, as I scaled things back a bit. I pared down the number of rooms to cable by deciding not to run cable in to the other rooms in the house. The more work I did cabling rooms, the more I realized that myself and future owners of the house would never have any need for a data connection in those rooms. We didn’t just pare down though, we wound up building a much more robust and functional “rack” inside the cupboard than I had originally planned. Plus, we wound up solving a sloppy installation by Verizon when we relocated the FiOS modem.

Things I Liked

  • I did not fall through the ceiling: At the forefront of my mind the entire time I was up in the attic, I felt that it was inevitable that I would put at best my foot through the ceiling in one of the rooms I was cabling. It was not quite a paralyzing fear, but it certainly caused me to sweat a little more profusely when navigating the attic.
  • My WiFi coverage problems are fixed: The entire motivation behind this project was to find a way to move my WiFi access point from one corner of the house into the middle of the house. Once I had decided to cable up one room for data, I wanted to go ahead and drop cables in the other frequently used (and computed in) rooms of the house. Before, the master bedroom had very poor WiFi coverage, and now the signal is strong enough to make it to all of the rooms in the house.
  • It was much easier than I anticipated: If you were a veteran do-it-yourselfer, I would not blame you for scoffing at any of my articles. I admit that I am at best a novice with these kinds of projects. On the off hand that you do not have much experience working with tools, I think something to this degree is an excellent project to learn on..
  • Inexpensive: For a long time, cost containment was my primary concern. I had ballparked out prices when I was considering all my different options but I feared that those costs would escalate a little bit as the project progressed. Thankfully, that did not happen. All told, I estimate that I spent about $350 on parts, and the bulk of that was on the network equipment. It also helped that a good friend donated a spool of CAT5e, so if you’re planning on doing a similar project budget in another 50-65 dollars for the cable.
  • I had lots of help: I will dig into this a little more later, but I had a great amount of help; help from friends completing the project, support from my wife, offers from friends who had tools to loan and finally no shortage of helpful advice from coworkers who had cabled up real networks.

Things I Didn’t Like

  • Tool-less RJ45 keystones: When I was shopping around for RJ45 keystones, I wound up finding these a bit cheaper than traditional RJ45 keystones. Since I needed so many of them, I thought it made sense to try and save money. I assume that they are cheaper because they were not made as well, but it is just as likely that we did not use them quite correctly. At any rate, we wound up spending time punching down a few of the network jacks a couple times. I would have gladly traded a few dollars for not having to spend the time re-doing the jacks several times.
  • Insulation: I am not sure if you are all aware of this, but insulation is everywhere up in attics. It gets in the way and it is a bit of a nuisance. I wished on a numerous times that I had a basement or a crawl space that would have allowed me to work up from below. I had bought a mask at Home Depot to stop from breathing the insulation when I spent considerable time up there, but in the “chilly” attic all I wound up doing was fogging up my glasses every time I exhaled.
  • Having to hire a professional: This is mostly prideful of me, but I really wanted to say that we were able to do this all on our own. I have no regrets about breaking down and hiring someone to help us out; I was at the point where we were going to spend hours what it took the professional to do, or scrap wiring up two of the rooms. It was a bit of a shot to the ego, but I am pleased with the results.
  • Building the rack compactly: The cupboard was just barely deep enough and narrow enough that when we measured and built the rack, we packed as much equipment into as small a space as possible. This made punching down the cables on certain ports of the patch panel quite difficult. Combine that with the business end of the mounting screws poking out the bottom of the pegboard and you have yourself the proverbial knuckle buster.

What I’d do Differently

For the most part, I am pretty regret-free on the project; the finished product turned out really well. But given the chance to do it all over again I would make a couple changes. Firstly, I would have moved the FiOS modem as the first step. We wound up having a hard time mounting the modem to the pegboard at the very end because the cupboard was getting pretty full by the time we finished the project. Secondly, the rack we built should have been built a little wider to spread out the pieces of the pegboard from the patch panel by another fraction of an inch. Lastly, I would have been a bit less vigorous in cutting a hole in the wall for the junction box on the one jack behind the TV I did punch through the other side of the wall.

Acknowledgements

I would not have been able to do this without the help of two people. Firstly, my darling wife basically gave me a blank check in completing the project, both in regards to the purchase of tools and equipment, and then she wound up being infinitely patient the past couple months on the days we spent working on it. I’m not sure that I would be able to exhibit the same patience in her shoes. Secondly, many thanks should be expressed to my friend Pat. Pat donated all of the CAT5e cable that now snakes throughout the house. Additionally, Pat was an extra set of hands and even more importantly an extra brain. Without Pat’s help, the project would have been much smaller and not nearly as brag-worthy as it turned out. I would probably still be up in the attic today tangled up in loose cable and in danger of falling through the ceiling. I look forward to buying Pat some more pizza and helping him with the upcoming projects at his own home.





Final Thoughts

This was a fun, inexpensive, and simple (yet challenging) project to do on our own. Even if you do not own a lot of tools, the necessary tools are relatively inexpensive. Originally, I set out to move the WiFi access point to a more centralized location. That wound up expanding to also wiring up all of the rooms where computing might happen. I am pretty certain that this investment of sweat equity has added some value to our home, and more importantly, the functionality of the network is going to enable me to do interesting things like streaming video over the network. All things considered, this project was a success in my books. For those of you unhappy with the WiFi coverage in your houses, wanting a faster, more stable connection for gaming consoles, interested in streaming high-quality video to your televisions, or interested in turning a spare bedroom into an office then I would recommend starting a similar project of your own.

My Network Cupboard: Completing Construction

After my last blog entry things seemed pretty bleak. I had a sneaking suspicion that if I had decided to try and push too far that I would wind up putting a sizable Brian-shaped hole in one or more of the bedrooms we were trying to wire up. On the other hand, it felt pretty hollow not being able to wire up a working network jack in each of the house’s three bedrooms. At this point, we felt like we really had two options: buy about 13 feet worth of flexible drill bits and extensions, hire someone to help us, or risk falling through the ceiling. At first, it seemed like the flexible drill bits was the route to go. We made a couple trips to the local big-box hardware stores and got a little bit of a sticker shock when we priced out the tools needed to drill the hole we were planning. Being a first time home buyer, I have been slowly buying all sorts of tools that I did not own before but I just could not justify spending so much on a tool I would likely never use again.

Thankfully, Mother Nature decided to help nudge me in the right direction in the form of a torrential downpour. A week or so ago, we got roughly 5 inches of rain in roughly 48 hours. That rain crept its way into my house via a leak in the roof (or two). Since then, we have had a revolving door of roofers, masons and handymen in our house looking at the leaks. We had hired a local handyman to repair a cracked 2x4” in the attic which happened to be right next to Mr. Impassible HVAC unit. In conversation, I had explained to him about the project and about how I had not had the gumption to try and work my way over. The sprightly man some 15-20 years my senior quite literally hopped, skipped and jumped over to the wall we wanted to run our cables down into. With his assistance, we ran two cables down in no time at all. Not only did he do this in about one fifth the time it would have taken the two of us, but his total bill (including other items around the house) was less than just buying the flexible drill bits we had been considering the week prior. If it had not been such a huge relief to have these cables run and to do it in a somewhat of an affordable fashion, I would have been knocked down a peg or two that this sprightly gray-haired gentleman had so easily completed something that I could not. There is something to be said about how invaluable experience truly is when accomplishing tasks like these.

That weekend, we also ran the cable for behind the TV, the entire purpose of this project from day one. Having a network jack behind the TV would enable me to move the wireless access point to the center of the rooms that would need it the most. This last network jack was completed with the first “oops” of the entire project. Our living room is paneled with wood, and the paneling is nailed down onto regular drywall. We started off trying to saw the hole for the electrical box with the drywall saw, but sawing through the paneling was quite a bit of work, and someone who shall remain nameless most vigorously pushed the drywall saw straight through both what we were cutting and then also the drywall behind it. As far as accidents go, it was not a bad one. Nothing a touch of glue or Spackle couldn’t fix. Having finally completed this network drop, I immediately moved our wireless access point to just behind the TV. I will blog about this in more detail, but I am quite happy to report that the WiFi coverage problems we were having on the east side of the house have been solved.

The weekend of the Superbowl, we decided to finish the remaining bits of work to relocate the Verizon FiOS modem, neaten up the cupboard and clean up all the messes we made along the way.

Ever since the Verizon technician had installed the FiOS, I had been unhappy with the installation. Mostly because they drilled into the house on the east side, pushed their cables (network & coax) through then fed that cable through the attic and drilled out the west side of the attic, routed the cable down the exterior wall of the house and then drilled back into the room we used for our office. It’s a messy installation, and involved drilling 3 holes in the outside of the house. When we started planning My Network Cupboard, I thought it would be icing on the cake to fix this convoluted installation. We unhooked the modem, disassembled the network jack that Verizon had installed and pulled the cable on the western side of our house back into the attic.

What we did next was a little fancy, but we had plenty of open space on the patch panel to use it. The modem had both a coaxial cable and an Ethernet cable plugged into it. We fished both those cables down into the cupboard. We mounted the modem onto the pegboard next to the routers and hooked up the coaxial cable to the modem. The ethernet cable we punched down to an empty port on the patch panel, and then punched down 5 additional ports for the ports on the modem (1xWAN, 4xSwitched). I do not have any immediate plans for the three unused switch ports, but it’s nice to have them wired into the network cupboard in case they’re needed.

We created some patch cords and patched the Verizon FiOS back into the rest of the network that had been completed already. We tested some throughput on various devices and made sure that the FiOS TV was fully functional. For all intents and purposes we had completed wiring the network.

We spent the next couple hours doing wrap up tasks. I had bought a gigantic spool of velcro, which we cut into thin strips and used to do some cable management in the cupboard. We also hooked up the second magnetic clasp on the cupboard due to the fact that just one magnetic clasp was not enough to hold the cupboard shut all the time. We fed all the remaining slack back up into the attic and up in the attic we used more velcro to manage the loose cable and hold it in place. I gathered up my trusty planks that I had spent so much time on and redistributed the insulation.

I took some pictures and even a short video, but I am saving that for my last blog about the project where I’ll talk about the cost (both time and money), lessons learned and advice I would like to pass along to others thinking about a similar project at their own homes.

Adding Bluetooth to My Car

Ever since buying my first Android phone, I have been tinkering with different ways to listen to music in my car. The problem is, they have never been very convenient and the audio quality has been bad. I drive a 2004 Mazda RX-8 and it does not have any kind of mini-stereo input. For awhile, I used an FM Modulator. It was powered using the cigarette lighter and you tuned the radio to an FM frequency that the modulator broadcast on. The modulator has a mini-stereo in so I’d run a headphone cable from my phone and into the modulator then plug the phone into a phone charger which was plugged in to a cigarette outlet in the center console. The net result of this was a mess of wires that ran all over and around the stick shift of the car. I am not much of an audiophile but the quality of the audio broadcast over the FM frequency was awful. And worst of all, it was difficult and inconvenient to get to the phone to control the audio.

RX8 Head UnitFor awhile, I was considering changing out the head unit in my RX-8. I could pick something with some sort of audio-in that could be neatly and easily plugged into my phone without much fuss. The problem with this plan, is that my car has some audio controls on the steering wheel and to my knowledge they would stop working if I changed out the stock head unit. Plus, because of the plastic molding in the RX-8 changing the head unit is not exactly a simple task.

On the Internet, I had read an interesting article on a CD player “hack” to wire in a mini-stereo in. From what I understand you could tap into the wiring from the CD player, place a “blank” audio CD into the CD player and then hook up your player. This is a very creative and inexpensive solution, but I did not think it’d meet all my criteria.

What I really wanted was a way to listen to music off my phone while in my car and have the ability to control the phone via the controls on the steering wheel or at least via the head unit. In doing my research I discovered that the best way to do this was going to be using AVRCP and A2DP over Bluetooth. Unfortunately, in 2004 when my RX-8 was made Bluetooth was not a common feature in cars and even today the Bluetooth you find in cars does not include A2DP, it mostly focuses on enabling users to place and receive phone calls.

GROM-AUX What I needed to do was to add Bluetooth to my car that somehow interfaced with the stock head unit and supported Bluetooth and included A2DP. Most of my research seemed to suggest that putting a new head unit into the car was the typical way to add Bluetooth into cars. However, due to some reading I did on the RX-8 Club Forums, I found that someone manufactures a device that would meet my needs. The folks at GROM Audio have a device called the GROM-AUX which has an optional Bluetooth adapter that plugs into it.GROM Mazda CableGROM BT Adapter

Normally in blogs, I want to talk about how I managed to install the subject of my blog. However I can very fondly remember spending a brisk Colorado fall evening bent in half trying to swap out the head unit on a friend’s car roughly 20 years ago. We made something we thought would be simple into something insanely difficult and frustrating. Ever since then, I have usually relied on professionals or bribed friends into installing my car audio components. This time, my car needed to go into the mechanic for regularly scheduled maintenance. I asked them if and how much they would charge to install the GROM-AUX and the Bluetooth accessory and found that their price was well worth the savings of time and frustration.

My phone quickly paired up with the GROM device, although it was a bit of an adventure. The garage pulled my car up and left it running while I paid the cashier. Which meant by the time I was driving out, the time in which the GROM-AUX was discoverable had elapsed. In order to pair up, I was going to need to turn the car off, set the ignition to “On”, then “Off” and then “On” again, then I was going to have to scan for nearby Bluetooth devices. Unfortunately, this is not as easy to do as it sounds when you are fighting your way home through rush hour. I am pretty sure I paired up with someone else’s Bluetooth head set on my phone and at one point I held up traffic while I was cycling the car’s power. Wisely, I concluded that it was probably best to try and pair up from the safety of my own garage.

Once the phone was paired up, we had a little bit of fun. Firing up different music apps on the phone, primarily Google Music. The AVRCP allows you to advance the tracks inside most of the Android apps that I took a look at. The GROM-AUX is smart enough to mute the audio and switch when a phone call comes in to your paired phone.

Using my favorite Android app, Tasker and a binder-clip phone mount I’ve been able to create a task. When my phone is tilted to the left (as it is in the phone mount) and plugged into power then the phone automatically enables its Bluetooth, pairs up with the GROM device and runs the phone’s Car Dock application.

All things considered, the GROM-AUX (and Bluetooth) accessory was reasonably inexpensive even when you add in the premium for having someone else install it. GROM Audio’s products seem to work with a variety of makes and models, so if your car lacks Bluetooth and you want to do something similar, check out their homepage. As popular as Android (and other devices) are becoming, A2DP and AVRCP are a must have for all road trips.

Building a NAS: Assembly & Configuration

Previously, I blogged about planning to build my own Network attached Storage (NAS) for the storage of critical backups and a place to house media. This week all of my three boxes came in from Newegg and by the end of the weekend, I had a functional NAS.

Assembly

It had been years since I had last built any kind of PC, so there was a very minor amount of rust to shake off. The assembly went particularly well. The extra money that I spent on the Lian Li PC-Q25B was well worth the investment, I was especially happy with the drive cage in the case. The case came with two 120mm fans which installed nicely on the two fan headers from the ASUS E35M1-I Fusion motherboard I selected.

Naturally, things never go quite as you planned. I had dangerously assumed that because the motherboard had 6 SATA ports that it would come with a glut of SATA cables. Instead, it only came with two cables and because one end of the cables had a 90 degree bend, the bent end would either block one of the SATA ports on the motherboard or one of the power plugs on the drive cage’s backplane. This was remedied pretty easily, but it required a trip to the local computer store the next day.

There was one issue with the front case fan. Something was scraping on the fan, causing it to make a pretty annoying rubbing noise on each turn of the fan. It was simple to pull the fan out and find the issue. There was a piece of screen in a plastic frame in front of the fan. That piece was a little bit deformed and pushing in on the hub of the fan and causing the noise. It was a simple task to remove that plastic piece and put the fan back in.

I had an additional issue with getting the motherboard to detect all four of the drives we put in. After a bit of swapping of cables we determined either that one of the cheap SATA cables we bought the previous day at the computer store was either defective or had not been firmly attached.


All NAS parts Motherboard Lian-LI PC-QC25B from Front Lian-LI PC-QC25B from Side NAS Assembled Hooked up and ready to Go FreeNAS Screenshot #1 FreeNAS Screenshot #2 Throughput Test

FreeNAS Configuration

Before I could button up the case, first we needed to install FreeNAS on the USB flash drive. Using a guide on the FreeNAS website and some 3rd party utilities, I had a bootable FreeNAS USB drive. Beginning the installation meant installing the USB drive inside the case and powering on the computer.

When booting up FreeNAS for the first time, there are a few configuration options that you need to make via the Console Menu like network and DNS settings. Once the network interface is configured, the web interface on the FreeNAS machine is functioning and the remainder of the configuration can be done from a browser on the local network.

Firstly, we created a Volume, added all four disks to it and picked ZFS as the file system. Moving along, we selected the RAID option. Because we had selected ZFS and because I began the array with four drives, I decided to select RAID Z2 (roughly equivalent of RAID 6). Picking this option made the array fault tolerant enough to survive losing two drives at any one point. On the volume, we wound up creating two ZFS datasets; “Homes” and “Backups.” The Homes dataset would be used to house a folder for each of the individual users; the Backups dataset would be used for the backups of our PCs. For these items, we chose ZFS datasets because of the snapshot features available. After that, we created some users and home directories for the users. Because of the ever-nifty Samba server, those home drives were available from our Windows machines as well as the Backup share we created previously.

Hopefully, as time progresses I will be getting my teeth into FreeNAS doing some blog-worthy and possibly even noteworthy things with the NAS.

Wrap Up

All in all, the assembly and configuration of the FreeNAS server was exceptionally uncomplicated. The available FreeNAS documentation walked me through anything that I had questions on or that were not clear from the interface. I have a feeling that we only started to scratch the surface of what FreeNAS is capable of. Hopefully,the flooded hard drive factories are not damaged too badly and they can start pumping out some very inexpensive 2 terabyte hard drives. When that happens, I’ll be adding two more drives to the NAS.

The alternative NAS-in-a-box products are all very tempting choices and I would expect that more options will hit the market over the next couple years. Because of the availability of great (and free) software like NAS Building a PC today is clearly the best option. Had I been more motivated by cost, it would have been incredibly easy to build the same box using a cheap PC. Overall, I am very pleased and would recommend this to anyone thinking about adding some network attached storage to their home network.

Building a NAS: Choosing Hardware

Introduction

Since starting the project up to wire my house with Ethernet, I have been thinking of interesting ways to put my network to use. For awhile now, we have been using a Western Digital Media player and an external USB hard drive to watch video content on the television. With products like Google TV I have been thinking there would be a value to having attached network storage. My hope is that sometime in 2012, I will have a device plugged into my TV that can stream video over my network both locally and from the Internet.

Most of my thinking was spurred on by a recent sale that Drobo had on one of their low-end models. I have been an admirer of the Drobo hardware for quite some time, but I have always found it to be cost-prohibitive; I had never thought I’d get the use to justify the price. In doing some research of the products out there, I felt I had about two choices: to either build a computer or to buy an enclosure with the functionality I need built into it.

The features that I was after were for the device to be network capable supporting Gigabit, to support at least 4 or more hard drives, to support redundancy via RAID, to have a smallish footprint and to be simple enough that I can manage it without having to hire an IT consulting firm.

Because of my requirements,I started off by researching quite a few enclosures, both USB and NAS-type devices. What I found, was that with the enclosures that had the features I was looking for you wound up paying a premium both for the smaller form factor and for the ease of use. Ultimately, a combination of this cost premium and my discovery of FreeNAS convinced me to go the do-it-yourself route.

Hardware

Because I decided to build the NAS from the ground up, I had the luxury to pick the parts I wanted and that suited my needs nearly perfectly. After researching hard drive prices (over half of the cost) I budgeted around $750-$800 in total and visited the website of my favorite vendor, Newegg. I probably could have saved a few dollars going with different vendors for different components, but I value getting all my parts from a company that I have enjoyed working with over the years.

Case

Lian-Li PC-QC25B One of the most important requirements was to consolidate all of this equipment down into the smallest reasonable footprint possible. This caused me to invest a little bit of effort and value into the case. I spent more time shopping for the case than I did for any other component. I needed a case that would hold at least 6 different drives and a Mini-ITX motherboard. I wound up choosing the Lian Li PC-Q25B. The case has room for 7 different drives internally and features a hot swap-able drive cage all in small-ish footprint of 14.41” x 7.83” x 11.02”.


Motherboard, CPU and RAM

ASUS E35M1-I Fusion For the motherboard I wanted something low power with an integrated CPU, Gigabit Ethernet and support for numerous (six or more) SATA drives. I wound up picking the ASUS E35M1-I Fusion, a mini-ITX board with an air cooled dual core 1.66GHz AMD CPU built on the board. The motherboard supports up to 8GB of RAM, so I chose two sticks of Crucial 4GB 240-Pin DDR3 SDRAM DDR3 1600 (PC3 12800).

In this blog as well as others about FreeNAS people have asked why I routinely pick non-ECC RAM. A question which I’ve answered in a blog discussing ECC vs. non-ECC. Crucial 4GB 240-Pin DDR3 SDRAM DDR3 1600 (PC3 12800)


Storage

WD Caviar Green WD20EARXThe most important and most expensive part of the build is the hard drives. To start off, I decided that I would begin with four drives and then add two more down the road in the future. Because of hard drives’ declining reliability, I wound up buying drives from two different manufacturer; the Western Digital Caviar Green WD20EARX and the HITACHI Deskstar 5K3000. Because hard drives often share problems across an entire batch there is a good chance that when buying two identical drives from the same vendor that both drives came from the same batch. By buying from two different manufacturers I help reduce the fact that half of the drives may in a short time span.HITACHI Deskstar 5K3000

In addition to the disk drives, I purchased a small 8GB USB Flash Drive and a USB cable that plugs directly to the motherboard’s USB header to mount inside the case. The purpose of the flash drive is to host the OS and the software to manage the NAS.

Alternatively, check out the Brian’s Face 16GB USB Drive on Tindie for $12.00 or pre-loaded with the current FreeNAS ISO for $15.00.


Software

The software to power the NAS was my biggest area of concern. I’ve tinkered with hardware RAID in the past using a 3Ware controller card. Once upon a time in a gaming rig, I had created a RAID 0 array across two disks for the fastest performance. My needs now are a little bit different I need something cheaper and that is not hardware-specific, so there are fewer points of hardware failure. Researching how to configure and support the RAID software choices made me lean towards buying one of the all-in-one enclosures. However the discovery of FreeNAS enabled me to go the PC route instead.

Directly from FreeNAS’ webpage:

FreenNASFreeNAS™ is an Open Source Storage Platform based on FreeBSD and supports sharing across; Windows, Apple, and UNIX-like systems. FreeNAS™ 8 includes ZFS, which supports high storage capacities and integrates file systems and volume management into a single piece of software.

From what I have been able to research so far, I am going to be able to place FreeNAS directly on a bootable USB device, and be able to configure/use it remotely via a web-interface running on NAS itself. I have read over their user documentation and I think that FreeNAS is something that a novice like myself can tackle.

Next Steps

Right now, my parts are coming in three different packages making the trek from Memphis, TN to my house. I have been eagerly tracking the packages throughout the beginning of the week. Hopefully over the next week or so I will have time to wrap up my other ongoing projects and begin to tackle this new project.

My Network Cupboard: The Immovable Object vs. The Uncoordinated Man

For those of you that follow my Twitter feed and those of you who live within a block or so of my house, then you already know that we have had a pretty difficult day in the MyNetworkCupboard effort two weeks ago.

Our goals were pretty simple: cable up the patch panel, test the existing cable runs, run the network drops to the remaining rooms, and relocate the Verizon FiOS router. From what we had accomplished the night before, I thought it was a slam-dunk that we would have the project wrapped up in a few hours and then be eating burgers and drinking beers. In retrospect, it is funny how wrong your assumptions can be about the work that is immediately before you.

We started off by measuring out and crimping down network cables for the patch panel. To be meticulous, we tested each cable we created. Our intent was to wire up the patch panel to such an extent that we could plug in the existing runs and do some throughput testing.

Upon completing the cable cutting, the wheels on our project began wobbling. We attempted to move the FiOS hardware into the cupboard. The FiOS router/modem has both a coaxial cable and an Ethernet cable run into it from the Verizon box on the side of the house. In our research online, we’d read that it needs one or the other, not necessarily both. To test things out, we powered off the FiOS router and disconnected the coaxial cable. With only the Ethernet plugged in, we were not able to access any of the Video-on-Demand services that we get with Verizon’s FiOS TV services. We were hoping that it would work with just Ethernet, but that was not the case. For the last step of project reroute both the coaxial cable and Ethernet cable fed into the FiOS router.

The wheels continued to wobble when we noticed during our throughput testing that on roughly half of the drops (8) we were only getting 100Mb and in some cases 10Mb from our runs. When we initially ran each of the drops, we put a cable tester and made sure that each jack lit up on all 8 strands so this came as a bit of surprise. What we found, was that the tool-less RJ45 keystone jacks we had been using were either a little fragile or that we were being careless with them after crimping them down. We had to fix and re-test several of the network jacks before they lit up the lights on the switches that we expected and measured out at gigabit speeds.

The next part of the project was a little fun and kind of humorous. Our house is a ranch style house and we have a two-sided fireplace right in the middle of the house. The fireplace separates the office/den and living room, the network cupboard is in the laundry room that is attached to the office/den, and the living room has vaulted ceilings. Getting the cable from one side of the house past the chimney, over the vaulted ceiling and within arm’s reach of the other attic access point was going to take some creativity, luck and athleticism; basically we needed Tim Tebow up in the attic with us. Although, I’m not sure Tebow would fit comfortably in the attic or that his awkward left-handed throwing motion would be conducive to making the throw at all.

I purchased a ball of very lightweight but sturdy twine and grabbed one of my puppy’s bone-shaped dog toys. I tied the twine to the toy and Pat held one end while I threw the toy, trying to thread a needle across the room near the roof. Twenty or thirty tries later, I finally hit the hole that I was aiming for, but the dog toy was going to be out of our reach from the other side of the attic. However, the dog toy snagged when I tried to pull it back and rather than risk losing one of the puppy’s favorite toys, I decided to go up into the other side of the attic and try and retrieve it somehow. From the other side of the attic, the toy was out of reach and out of sight, though we could see the twine hanging down across a round HVAC duct. But it’s resting place was going to be too small and cramped to crawl into.

Thankfully we had an 8 to 10 foot length of 1”x2” leftover from building the framing and equipment rack. Pat went down into the garage and rummaged around and managed to turn it into a hook of sorts with one of the clamps I we had been using. Thankfully, it was barely long enough that I could lean forward and snag the loose twine and retrieve the dog toy on the end.

The plan after that was to use the string to pull through the network cable to the other attic access point and to attach a new stretch of twine to the network cable we pulled through; that way we would have enough twine to pull cables back and forth between the two sides of the house. We pulled the first cable across without too much difficulty and then we ran into the Immovable Object.

The master bedroom, spare bedroom #1, spare bedroom #2 and guest bathroom are in a row through the hall. The hall is nearly intersected by the doorway to the living room with the attic access in that hallway. Up in the attic, the HVAC unit runs along the wall between the bedrooms and the hallway. HVAC ducting extends towards the front of the house to spare bedroom #2, towards the back of the house to the Master bedroom and then hangs off the back of the unit.

In order to run network cable into the two remaining bedrooms (spare bedroom #2 was already wired up with CAT5e by a previous owner), I was going to have to find a way over the HVAC unit, or the main trunk and then over another smaller HVAC duct. I raked away as much of loose insulation as I could and was dismayed to find that the rafters were running 90 degrees differently than they were over the office/den. The rafters were running parallel to the HVAC unit and there was only one rafter between HVAC & Main Trunk and the next run of HVAC ducting. Being a man of limited mobility and coordination, I had no faith that I would be able to climb over two obstacles, place my boards and move to drill holes down and run cables through them. To make matters worse, the roof slopes down three sides of the master bedroom; even if I could navigate safely past the HVAC obstacles being able to worm into the master bedroom and run a cable down the far wall was a very, very unlikely proposition. With that, the wheels finally shot off on the weekend’s progress and any promise of completing the project that weekend was lost.

By the time we finished that Saturday night (very very late), it turned out to be a very frustrating and disappointing day. At one point I was afraid that we would not be able to complete my goal of cabling every room but the kitchen and bathrooms with Ethernet. However, there are always alternatives, and I have been thinking about it for two weeks now; right now I’m trying to decide how feasible it would be to use a flexible drill bit (and some flexible extensions) to try and drill up into the attic and then fish the cable back down. Unfortunately, buying all of those tools is going to cost quite a few dollars. Since I am a new home owner, I’m not opposed to buying most tools, since they will likely come in handy down the road on another project. In this case, though, I’m hesitant to buy the tools because it’s going to wind up being something I only use this one time. We will see what kind of zany/creative/expensive solution we can come up with!

MyTouch 4G: Don’t Stand So Close to Me

I recently decided to replace my frustrating mobile phone (a Samsung Galaxy S phone, the Vibrant) because Samsung and T-Mobile has been terrible at keeping current with the latest version of Android. I did a bit of research on eBay and Craigslist, and found that the myTouch 4G (aka HTC Glacier) was a comparable phone with more memory and faster data speeds.

I spent New Year’s weekend crawling Craigslist trying to find the cheapest MyTouch 4G nearby. I figured it’d be a bit of a calculated risk, but I felt pretty good about it. I found a guy selling one nearby and met up and grabbed up the phone in the parking lot of a nearby McDonald’s. From what I could tell, the phone was in good shape but it had been a little loved.

I took the phone straight home, rooted it and installed my favorite Android ROM, CyanogenMod. It was not until a couple days later that I realized the phone had a quirky problem. Whenever I would receive (or place) a phone call, the screen would immediately go dark and remain dark until I either pulled the battery or received another call (and didn’t answer it).

After about a hundred different searches on Google, I began to suspect that the proximity sensor on the phone was not behaving properly. The proximity sensor’s purpose on phones is to detect how close to your face the phone is. When the phone is right up next to your face, the screen goes dark and does not respond to touch. Once you move the phone away from your face the screen should light back up.

I began by digging around in the CyanogenMod and Android settings. There were some settings that sounded like they might disable or ignore the proximity sensors, but unfortunately they did not quite do the trick for me. Regardless of what I tried, the proximity sensor remained enabled.

I wound up finding an app on the market that I used to troubleshoot the sensor. The name of the app was ‘Proximity Sensor.’ When I opened the app, it told me that the sensor was permanently engaged. Just for fun, I took my flash light and I turned it on and pointed it right at the sensor. When the flashlight was flush up against the phone at it’s brightest setting, the app began to report intermittently that the sensor was clearing.

But if it took a flashlight right up against the phone in order for the sensor to turn off, then surely the sensor is most likely kaput.

Since my phone is rooted, I thought I’d give a few different “fixes” a try. According to some of my research, the HTC’s proximity sensor is a CM3602. In considering options, I thought we’d have a few options:

  1. Deny all permissions on the CM3602 file in the /dev/ folder.
  2. Use an application like Tasker or Proximity Screen Off to disable the sensor.
  3. Switch to the MIUI ROM since it has an option to disable the proximity sensor.

Ultimately, setting the permissions had no effect. Tasker could read the sensor but could not disable it and the Proximity Screen Off app seemed a little convoluted to use. I briefly tried out the MIUI ROM, which fixed the issue. But, I have grown pretty accustomed to CyanogenMod and it was hard to give that up.

Ultimately, 8 or 9 pages deep into Google’s search results was a suggestion to hex edit file and overwrite information about the sensor. Because I was determined to make CyanogenMod work on the phone, I decided to give it a shot. Within the file, /system/lib/hw/sensors.glacier.so, I searched for and overwrote the “cm3602” text with “xxxxxx” and then rebooted the phone.

Because I flashed a different ROM a few months later and a few people had asked for more specific directions, I went ahead and wrote these directions:

  1. Get ADB Functioning on your desktop computer.
  2. Download and install a Hex Editor
  3. Use ADB to pull down the file sensors.glacier.so (adb pull /system/lib/hw/sensors.glacier.so)
  4. Open sensors.glacier.so in your Hex Editor
  5. Search for the text “cm3602” (no double-quotes) and save your changes. Please note, case sensitivity is important. If you’re paranoid, it’s good to check that the file size is exactly the same as it was before your edit.
  6. Re-mount the /System folder as read-write using an ADB Shell (mount -o remount,rw /dev/block/mmcblk0p25 /system)
  7. Open up a new command window and use ADB to push your edited file (adb push sensors.glacier.so /system/lib/hw/sensors.glacier.so)
  8. Reboot your phone.

Thankfully it worked the proximity sensor is disabled on my phone and I am able to make phone calls without causing my phone’s display to turn off indefinitely. This was confirmed by the Proximity Sensor app, which indicates now that there’s an error while trying to read sensor data. This basically turned my dysfunctional phone into something that I could continue to use until my contract runs out and I can upgrade my phone to something with native support for Ice Cream Sandwich in a few months.

According to Google, people frequently have problems with the proximity sensor; people do not seem to like them, they seem to be interfered with by screen protectors and phone cases, and then in a lot of instances, probably mine, people drop their phones and damage the proximity sensor.

I’ve posted this online in both on XDA Forums and in the CyanogenMod forums. And now, it’s forever preserved on my blog. Hopefully, someday down the road it’ll help a few other people out.

My Network Cupboard: Things Begin to Take Shape

Between the Holidays and the bacteria intent on ruining said Holidays, we wound up taking an extended break from My Network Cupboard. However, I made a resolution at the beginning of the New Year to see this project to completion and I am quite determined to keep at least one resolution in 2012.

Previously, we had measured out and cut what we called the equipment rack. The equipment rack would hold the patch panel, and then two “shelves” made out of peg board which we would mount the router to and then use to tie down cables and make everything neat. Then inside the cupboard, we would build out a wooden frame that we would mount the equipment rack to using some cupboard hinges and a magnetic clasp to hold it shut.

Today, we assembled the framing of the equipment rack and then we cut some notched pegboard that was six inches deep and ran the length of the equipment rack. The purposes of the notches in the pegboard are to help hold the shelf in place. At the back of the pegboard, we screwed in a couple stubby pieces to keep the shelves’ shape and to keep them study. Because the two pegboard shelves are installed within an inch of each other, I decided that we’d go ahead and mount the Netgear switches to one of the shelves.

Upon building out the equipment rack, we turned our attention to mounting a frame inside the cupboard that we would attach the hinges and magnetic clasp to. We wound up making the frame out of the excess 1”x2” lumber we had left over from the equipment rack. Our plan was to make the frame as tall as the inside of the cupboard and about the same width as the equipment rack. In order to install it we would screw the frame into the top and bottom of the cupboard.

Installing the wooden frame went surprising smoothly. We were worried that it’d go in crooked or that we would have a hard time with the amount of space available. The only complication ultimately was caused by my invaluable assistant, Pat. Pat was testing how sturdy the frame was, and he gently whacked it with the palm of his hand to see if it would move at all. Impressed with the sturdiness, Pat took a second hearty whack at it without the least bit of a budge. Then, inexplicably, Pat reared all the way back and smacked it a third time. Unfortunately, this time he put enough oomph into it that the vertical piece on the right side of the frame splintered and broke off. After a couple of “WTFs?!” and some laughter, we got out some longer screws and reattached the lumber. Finally some hinges and a magnetic clasp were attached to the cupboard’s wooden frame.

Finally, we attached the equipment rack to the other side of the hinges and guesstimated the appropriate location for the metal plate to hold the cupboard shut. We fed the patch panel, which already had a few of the previous cable runs punched down, through it’s hole in the equipment rack and mounted it too. We opened and closed the equipment rack a couple times to make sure we could access the back of the patch panel easily and we wrapped it up for a night.


Unassembled Network Rack Assembled Rack from Front Assembled Rack from Back Rack Shelf Rack Shelf with Switches Rack Shelf installed in Rack Rack Shelf with Switches Mounted Rack with Switches as it will be Installed Rack Mounting Frame Rack Mounting Frame Installed Rack mounted and in Open position Rack mounted and in Closed position

The project is mostly complete, but there is still a bunch of more work left to do; there’s at least three more cable runs to do, we still need to relocate the Verizon FiOS router, the WiFi router will need to get moved to a central location, and there is a good deal of cable management work to do to clean up behind the equipment rack. Lastly, my least favorite thing to do after any kind of project… cleaning up all the mess I made. Hopefully, we can knock this out in the next week or so.

My Network Cupboard: Inhaling Insulation

In planning the project, I had two fears related to damaging my house: first, I was convinced that at one point I would come crashing down through the ceiling as I clumsily stepped between rafters, and second, that where I had to cut holes in drywall, the holes I cut would be terribly misshapen and that I’d make a fool out of myself. Seeing as how this is our first house and I generally hate making a fool out of myself because of incompetence these two fears were very present as I went up into the attic again.

The past couple days, we’ve been running the network drops into the den/office of the house. The plan for the den/office is to put network outlets at my PC (4 drops), my wife’s PC (2 drops) and then against another wall (2 drops) for friends to use and for future use. Thankfully, there is a preexisting network drop that goes into the spare bedroom already near one of the computers (mine). Since the network cupboard is on the opposite side of the wall of my PC, I decided to re-use that network drop, and then run my four new cables down. For my PC, I didn’t really have to face either of my two primary fears. It was very straightforward. I drilled a hole (5/8”) in 2x4” at the top of the wall, and then we used a cable fish to push the cable through. Overall, it was pretty easy. Unfortunately, the wall plate I picked was a little narrower than the one that it replaced and the hole is just a little bit too big. There’s a tiny gap (about the width of a dime) between the wall plate and the edge of the hole. Depending on how much it bothers us (not too much so far), I may wind up having to find a way to shim that so it looks nicer.

The next two network plates are where I’d tackle my fears. My wife’s PC needed a new network jack, so I’d be cutting a hole in the wall for sure. The other wall plate was on a different wall, and there were quite a few rafters to navigate in order to reach it. My wife’s network plate wound up being no big deal at all. Her PC is roughly 6-7 feet down the same wall as my PC, and my network plate was right next to a stud. To make things easier, we bought low-voltage gang boxes that don’t necessarily need to be attached to a stud. They have little flappers that pinch the drywall as you tighten it down. We measured over 66” and cut a hole in the drywall. I was super conservative in my cutting, so it took a few adjustments to make the hole fit the gang box well and straight. We ran down two more cables for her PC. And I breathed a sigh of relief.

To navigate the attic, I was being super careful. We’d bought and cut down some 4x8’ sheets of plywood, and I’ve been using those to lay across the rafters to try and minimize any missteps down through the ceiling. For the most part, this has been working well, except you still have to be careful about where you put your feet. As I was using 3 of the sheets of plywood to snake across the attic to the other wall of the den/office, I put my foot (and weight) out on the leading edge of the plywood, which happened to be about 1 foot over the nearest rafter. The plywood see-sawed out from underneath me pretty good, nearly causing me to lose my balance, but I gracefully flopped around like a fish out of water and was able to inch back to solid footing before I put a hole in the ceiling. With that crisis averted, I set to running the cables for the last outlet in the den/office. There’s an ancient old coax hookup on the wall we wanted to use. That coax isn’t currently hooked up to anything and we don’t have any plans of putting a TV in the den/office, so we decided to just pull the orphaned coax up out of the wall and run down the strands of cat5e to replace it. Other than having a hard time getting to the existing coax run due to some HVAC ducting, this went pretty smoothly.


Cabling up Brian's PC Cabling up Julia's PC An additional couple of ports for the office. Cables run back to the Cupboard

Originally, I had an inkling of a desire to go ahead and run coax in certain rooms and tie it all into the coax that the FiOS guys set up for my TV room and master bedroom. In a perfect world, I’d love to be able to have all of my rooms wired up for coax without having to call out (and pay) to have an installer wire up another room. Each of the network plates I’ve bought has 4 ports, and every wall plate we install, except one, will have at least one or two empty ports if we ever decide to do this.

Having the den/office finished means that we’ve pretty much completed more than half of the network drops needed. We have four rooms remaining (TV/Living room, 2x Spare Bedrooms and the Master Bedroom) to run cables to, but that’ll probably happen later on after Christmas.

Up next, we’re going to finish out the network cupboard’s “rack”. We’ve got a good idea how we want it to look, but have only begun working on the construction.