I’ve been building my home automation system for years and have achieved extensive lighting, climate, entertainment, security and entry control. Never satisfied, I’m forever pondering potential refinements that would enhance the overall effectiveness and capability of my system. I recently concluded that one of those refinements would involve automating the control of the natural-gas fireplaces in my home.

Let me interject here that one should exercise EXTREME caution before deciding to implement any kind of automated home controls such as those I will outline below!

The key to gaining control of a fireplace is to have some kind of automated ignition system. In my case, I had Skytech remote control systems installed on each fireplace when I built our home. This system makes starting and terminating a fire as simple as pressing a button.

Why
As I’ve built my home automation system, I have focused on centralization and ease of control. Most of the house can be managed through a central console, but the interface is also accessible from a myriad of other devices throughout the house. My motivation was to get rid of the “ugly” Skytech remotes and incorporate control of the fireplaces into the central control system. This is not only more elegant than the current system, it, more importantly, allows me to incorporate the fireplaces into my HA scenes. Another reason for implementing automated control of the fireplaces is safety. Imagine, if you will, that one of my children are the last to leave the house for the day and forgets to turn off a fireplace. With centralized control, the HA system can now automatically turn off all fireplaces when it senses that the house is empty or when the security system is engaged. Another scenario would be to automatically shut-off the fireplaces if the HA system senses a structure fire or if high levels of carbon monoxide are detected.

The Plan
Since I’ll replace the every-day use of the fireplace remotes with my centralized control system, I thought the easiest way to accomplish my goal was to use an Arduino and a couple of reed relays to simulate button presses on the remote.

Circuit Schematic

Circuit Schematic

Since my goal is to automate control, I decided to use an Ethernet Shield so I could make a simple URL call to turn a fireplace on and another call to turn a fireplace off.

The schematic above shows what I actually implemented.

The parts

  1. Breadboard
  2. 1 x Arduino Uno
  3. 1 x Ethernet Shield
  4. 2 x Reed Relays
  5. Spool of solid 22 AWG wire

The relays I had on-hand were NTE Electronics SPST NO R56-1D.5-6D, although the on-board diode contained in this model is unnecessary, these would work just fine for this application.

The Implementation
The key to accomplishing our goal is to open the remote and locate the buttons. In this case, the buttons are mini push button switches. I then turned the PCB over and located the pads for both the ON button and the OFF button. Once I knew where I needed to connect my relays, I then set up my soldering iron and proceeded to connect a six inch lead to two pads on each button and then put the remote unit back together.

Next I wired up my circuit:

ON Relay

  • Arduino PIN2 to relay PIN2
  • Arduino GRD to relay PIN6
  • Relay PIN1 to remote ON lead
  • Relay PIN7 to remote ON lead

OFF Relay

  • Arduino PIN3 to relay PIN2
  • Arduino GRD to relay PIN6
  • Relay PIN1 to remote OFF lead
  • Relay PIN7 to remote OFF lead

Now we need software to drive the circuit. The simple sketch below will tell the Arduino to engage our ON button relay, which should turn the fireplace on when 192.168.1.10/?RELAY=1 is called from an external application. Calling 192.168.1.10/?RELAY=2 will tell the Arduino to fire the off relay, which should turn the fireplace off.

#include <SPI.h>
#include <Ethernet.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
IPAddress ip(192, 168, 1, 10); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

String HTTP_req;          // stores the HTTP request

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for diagnostics
    pinMode(2, OUTPUT);       // relay on pin 2
    pinMode(3, OUTPUT);       // relay on pin 3
}

void loop()
{
      EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                HTTP_req += c;  // save the HTTP request 1 char at a time
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    // send web page
                    ProcessRequest(client);
                    Serial.print(HTTP_req);
                    HTTP_req = "";    // finished with request, empty string
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)

}

// process request
void ProcessRequest(EthernetClient cl)
{
    if (HTTP_req.indexOf("RELAY=1") > -1) {  // see if request is for the ON relay
        digitalWrite(2, HIGH);
        delay(1500);
        digitalWrite(2, LOW);
        cl.println("1");
    }
    
    if (HTTP_req.indexOf("RELAY=2") > -1) {  // see if request is for OFF relay
        digitalWrite(3, HIGH);
        delay(1500);
        digitalWrite(3, LOW);
        cl.println("2");
    }
}

That’s it!

If you have more than one fireplace, just add additional relays and modify the sketch accordingly.

Conclusion
This method worked like a charm! I didn’t have to remove the fascia from the fireplaces themselves to access and modify the electronic valve control system. This method also leaves the remotes fully functional even though they have a tethered connection to the Arduino. This allows me to use the remote to start a fire even if there is a power failure in the house and the HA system is inaccessible.

Last but not least, another benefit of this implementation approach is the fact that there is no permanent damage. When I decide to sell my home, I’ll just snip the leads off of each remote and the new owners can use the remotes the “old fashioned” way!

Until next time – GEEK OUT!

~GT~

 

I’ve worked with a LOT of genealogy software applications over the years and all of them have left me, for one reason or another, unsatisfied.

I started experimenting with The Next Generation of Genealogy Sitebuilding, also known as TNG, back in mid-2010, but really started digging deep into the application over the past few months. What makes TNG so unique is that it’s a web based app instead of a Windows or Mac fat-client application. I love this approach as it gives me total access to my data, and since the application is written in PHP and has a built-in Mod architecture and manager, it’s really, REALLY easy to extend the application to make it do things that it doesn’t do natively.

I’m currently editing a book for a particular line in my database and needed the Person and Group Sheets to include divorce information. Unfortunately the reports that ship with TNG 9, the latest version, do not support this. My first thought was to export a GEDCOM and import it into an application like Reunion, but without going into the details, I HATED the results. That led me to creating my own Mod to extend both the Person Sheet and Group Sheet PDFs to include divorce information.

To use the mod, save the code below or download this file to gt_sheet_v9.0.0.1.cfg in your tng/mods folder and then install like any other mod.

I’ve only tested the Mod with TNG V9, so I can’t speak to its compatibility with previous versions.

%name:GT Custom Sheet%
%version:V9.0.0.0%
%description:This mod will modify the person and group sheet pdf reports to add divorce information.%

%target:tngdblib.php%
%location:%
//Get most family data for a known spouse
function getSpouseFamilyDataPlusDates($tree, $spouse1, $spouse1ID, $spouseorder) {
    global $families_table;

        $query = "SELECT gedcom, husband, wife, familyID, marrdate, marrdatetr, marrplace, marrtype, living, private, branch,
                YEAR(marrdatetr) as marryear, MONTH(marrdatetr) as marrmonth, DAYOFMONTH(marrdatetr) as marrday, marrplace, sealdate, sealplace
                FROM $families_table
                WHERE $spouse1 = \"$spouse1ID\" AND gedcom = \"$tree\"
                ORDER BY $spouseorder";

    return dbExecuteQuery($query);
}

//Get most family data for a known spouse with unknown gender
function getSpouseFamilyDataUnionPlusDates($tree, $spouse1ID) {
    global $families_table;

        $query = "SELECT gedcom, husband, wife, familyID, marrdate, marrdatetr, marrplace, marrtype, living, private, branch,
                        YEAR(marrdatetr) as marryear, MONTH(marrdatetr) as marrmonth, DAYOFMONTH(marrdatetr) as marrday, marrplace, sealdate, sealplace
        FROM $families_table
        WHERE husband = \"$spouse1ID\" AND gedcom = \"$tree\"
        UNION
            SELECT gedcom, husband, wife, familyID, marrdate, marrdatetr, marrplace, marrtype, living, private, branch,
                                YEAR(marrdatetr) as marryear, MONTH(marrdatetr) as marrmonth, DAYOFMONTH(marrdatetr) as marrday, marrplace, sealdate, sealplace
            FROM $families_table
            WHERE wife = \"$spouse1ID\" AND gedcom = \"$tree\"";

    return dbExecuteQuery($query);
}
%end:%
%replace:%
//Get most family data for a known spouse
function getSpouseFamilyDataPlusDates($tree, $spouse1, $spouse1ID, $spouseorder) {
    global $families_table;

        $query = "SELECT gedcom, husband, wife, familyID, marrdate, marrdatetr, marrplace, marrtype, divdate, divplace, living, private, branch,
                YEAR(marrdatetr) as marryear, MONTH(marrdatetr) as marrmonth, DAYOFMONTH(marrdatetr) as marrday, marrplace, sealdate, sealplace
                FROM $families_table
                WHERE $spouse1 = \"$spouse1ID\" AND gedcom = \"$tree\"
                ORDER BY $spouseorder";

    return dbExecuteQuery($query);
}

//Get most family data for a known spouse with unknown gender
function getSpouseFamilyDataUnionPlusDates($tree, $spouse1ID) {
    global $families_table;

        $query = "SELECT gedcom, husband, wife, familyID, marrdate, marrdatetr, marrplace, marrtype, divdate, divplace, living, private, branch,
                        YEAR(marrdatetr) as marryear, MONTH(marrdatetr) as marrmonth, DAYOFMONTH(marrdatetr) as marrday, marrplace, sealdate, sealplace
        FROM $families_table
        WHERE husband = \"$spouse1ID\" AND gedcom = \"$tree\"
        UNION
            SELECT gedcom, husband, wife, familyID, marrdate, marrdatetr, marrplace, marrtype, divdate, divplace, living, private, branch,
                                YEAR(marrdatetr) as marryear, MONTH(marrdatetr) as marrmonth, DAYOFMONTH(marrdatetr) as marrday, marrplace, sealdate, sealplace
            FROM $families_table
            WHERE wife = \"$spouse1ID\" AND gedcom = \"$tree\"";

    return dbExecuteQuery($query);
}
%end:%

%target:rpt_ind.php%
%location:%
                if($rights['both']) {
                    $cite = reorderCitation($marriagerow['familyID']."_MARR", 0);
                    doubleLine($text['married'], displayDate($marriagerow['marrdate']), $text['place'], $marriagerow['marrplace'], $cite);
                }
%end:%
%replace:%
                if($rights['both']) {
                    $cite = reorderCitation($marriagerow['familyID']."_MARR", 0);
                    $citex = reorderCitation($marriagerow['familyID']."_DIV", 0);
                    doubleLine($text['married'], displayDate($marriagerow['marrdate']), $text['place'], $marriagerow['marrplace'], $cite);
                    doubleLine($text['divorced'], displayDate($marriagerow['divdate']), $text['place'], $marriagerow['divplace'], $citex);
                }
%end:%

%target:rpt_fam.php%
%location:%
        // married
        if ($frights['both']) {
            $cite = reorderCitation($familyID."_MARR", 0);
            dateLine($text['married'], displayDate($fam['marrdate']), $fam['marrplace'], $cite);
        }
%end:%
%replace:%
        // married
        if ($frights['both']) {
            $cite = reorderCitation($familyID."_MARR", 0);
            $citex = reorderCitation($familyID."_DIV", 0);
            dateLine($text['married'], displayDate($fam['marrdate']), $fam['marrplace'], $cite);
            dateLine($text['divorced'], displayDate($fam['divdate']), $fam['divplace'], $citex);
        }
%end:%

Until next time – GEEK OUT!

~GT~

 

Back in February of this year, I released a Greasemonkey Script that would modify the theme from the Hack A Day site so it was a little easier on my “old eyes”!

The script works by changing CSS and HTML elements after they have been received by my browser.

The good folks over at Hack A Day overhauled their theme last week which meant my old hack needed quite a few modifications so it would work as it had with the old site.

Just as before, I’m a Firefox user so I’ve only tested the script with Firefox, but it should work just fine with other browsers. Other Hack A Day readers reported that my previous script worked with Opera and Chrome.

To use the script, do the following:

  • Install the Greasemonkey extension (Firefox.. Tools.. Add-ons)
  • Save the script as hackaday.user.js
  • Restart firefox
  • Drag the hackaday.user.js script from your desktop to Firefox

A couple of items to be aware of:

  • I didn’t take the time to test each of the previous modifications to see if they were still being used. That means the code could be tightened-up a bit, but it works just fine as is. If you care to take the time to test each of the old changes to see if they are still required, please do so and let me know your findings and I’ll update the code listing below.
  • I’m using a different logo image in my header (see screenshots) than the logo that Hack A Day is using. If you choose to use your own image, you’ll need to modify the link in the code. I don’t have permission to share my image, so don’t ask!

For more information on my original hack, please read my original post.

// ==UserScript==
// @name           Hackaday
// @namespace      http://localhost
// @description    Re-Theme hackaday.com
// @include        http://hackaday.com/*
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_addStyle
// ==/UserScript==

// Let's change the body background to white
document.body.style.background = "#fff";

// Let's set our link hover, heading3 and paragraph settings
GM_addStyle("a:hover {background-color: transparent; border-bottom:0px;}");
GM_addStyle("h3 {color: #000;}");
GM_addStyle("p {color: #000; background-color: #fff; font-size: medium; line-height: normal}");

// Let's get rid of the border around the body text
GM_addStyle("#container {border-width: 0px;}");

// Change comment block backgrounds, colors and margins
GM_addStyle(".comment-body {background-color: #fff;}");
GM_addStyle("li.depth-2 {background-color: #fff;}");
GM_addStyle("li.depth-1 {background-color: #fff;}");
GM_addStyle(".comment-body {margin-left: 6px; margin-right: 6px;}");
GM_addStyle(".fn {color: #888;}");
GM_addStyle(".says {color: #888;}");
GM_addStyle(".cle h3 {color: #fff;}");

// Change the color of each link
var zElements = document.getElementsByTagName("a");
for (var i=0; i<zElements.length; i++) {
   zElements[i].style.color="red";
}

// Change the color of each blogroll block
var zElements = document.getElementsByClassName("statsclass1");
for (var i=0; i<zElements.length; i++) {
   zElements[i].style.backgroundColor="#959595";
}
var zElements = document.getElementsByClassName("statsclass2");
for (var i=0; i<zElements.length; i++) {
   zElements[i].style.backgroundColor="#aaa";
}

// Change the color of each sharedaddy instance
var zElements = document.getElementsByClassName("sharedaddy");
for (var i=0; i<zElements.length; i++) {
   zElements[i].style.backgroundColor="#555";
   zElements[i].style.color="#fff";
}

// Change the sharedaddy title settings
var zElements = document.getElementsByClassName("sd-title");
for (var i=0; i<zElements.length; i++) {
   zElements[i].style.color="#fff";
   zElements[i].style.marginLeft="6px";
}

// Change the color of the comment counts
var zElements = document.getElementsByClassName("cat-item");
for (var i=0; i<zElements.length; i++) {
   zElements[i].style.color="#000";
}

// Added on 06/11/2012
// Change images
var images = document.getElementsByTagName ("img");
var x=0;
while(x<images.length)
{
  if(images[x].src.indexOf("hackaday-logo.gif") != -1)
  {
    images[x].src = "http://use.yourownimage.com/hackaday-logo.gif";
  }
  else if(images[x].src.indexOf("tips1.jpg") != -1)
  {
    images[x].src = "http://use.yourownimage.com/tips1.jpg";
  }
  else if(images[x].src.indexOf("feed1.jpg") != -1)
  {
    images[x].src = "http://use.yourownimage.com/feed1.jpg";
  }
  else if(images[x].src.indexOf("store1.jpg") != -1)
  {
    images[x].src = "http://use.yourownimage.com/store1.jpg";
  }
  else if(images[x].src.indexOf("forum.jpg") != -1)
  {
    images[x].src = "http://use.yourownimage.com/forum.jpg";
  }
 
  x=x+1;
}

// Added on 11/21/2012 to account for 11/16/2012 Theme Changes
// http://hackaday.com/2012/11/16/the-new-template-has-arrived/

// Let's change the header bg color and image
GM_addStyle("body, p, select, textarea {color: rgb(0,0,0)}");
GM_addStyle("#header {background-color: rgb(255,255,255)}");
GM_addStyle(".header-image #title-area {background-image: url(\"http://use.yourownimage.com/hackaday-logo.gif\");}");
GM_addStyle(".header-image #title-area {width: 457px;}");
GM_addStyle("#header .widget-area {width: 450px;}");
GM_addStyle(".header-image #title-area {height: 130px;}");
GM_addStyle("#header {min-height: 130px;}");

// Let's tweak the menu-bar
GM_addStyle(".menu {height: 25px;}");
GM_addStyle(".menu a {padding-top: 4px;}");
GM_addStyle(".menu {background-color: rgb(160,160,160)}");
GM_addStyle("#nav .s {margin-right: 10px;}");
GM_addStyle("input {vertical-align: middle;}");
GM_addStyle("input.s {height: 12px;}");
GM_addStyle("input.searchsubmit {height: 18px;}");
GM_addStyle("input.searchsubmit {padding-top: 0px;}");

// Let's change the wrap DIV bg color
GM_addStyle("#wrap {background-color: rgb(248,248,248)}");
GM_addStyle("span.date.published.time {color: #000;}");
GM_addStyle("span.categories {color: #000;}");
GM_addStyle("span.tags {color: #000;}");

GM_addStyle("#tl_ad {background-color: rgb(248,248,248)}");
GM_addStyle(".sidebar .widget {background-color: rgb(248,248,248)}");
GM_addStyle(".sidebar .widget p {background-color: rgb(248,248,248)}");
GM_addStyle(".widget-area h4 {background-color: rgb(85,85,85)}");
GM_addStyle(".header-image #title {opacity: 0;}");

// Let's change the comment boxes
GM_addStyle(".odd {background-color: rgb(255,255,255)}");
GM_addStyle(".even {background-color: rgb(255,255,255)}")

// Let's tweak the category box
GM_addStyle(".widget_archive select, #cat {background-color: rgb(85,85,85)}");
GM_addStyle(".widget_archive select, #cat {color: rgb(255,255,255)}");

Following is a before and after image that shows the transformation.

Until next time – GEEK OUT!

~GT~

   

© 2012 Geek-Tips Suffusion theme by Sayontan Sinha