I'm promised some people that I would post my set-up on these boards. My system is still in development (when isn't it?) but I'm also curious on getting some feedback and maybe more ideas on the best way to implement a home automation system.
Ultimately, I would like to have various sensors and actuators working on a wireless mesh network that has the ability to communicate through Ethernet, likely with an Android device. So far, I do have sensors and actuators (relays) talking to each other and working in conjunction, and I'm working on a "network bridge" that will translate between the wireless signals and Ethernet to allow my Android to talk to these devices as well. Inspiried by the JeeNode, I made my own based on the ATTiny84:
It's as simple as it looks. An ATTiny84 connected to an RFM12B transceiver. DigiKey carries the chip for ~$2 each while you can find the transceiver for around $6.
I also made a "programming/prototyping" shield that breaks out the ISCP connectors, a reset button, and a handful of solder holes that can be used to prototype. Here is a picture of my light sensor that I've created using this "shield."
I designed an actual "sensor" shield that gives you some room to add a few analog/digital sensors and one of these coincell batteries, just waiting to get them in the mail.
So right now, I have the above pictured board sitting in my window reading and sending the light level every minute. There is another base unit with a relay (shield also on the way) and a cannibalized cheap USB power adapter inside my light switch box, effectively creating dusk-to-dawn porch lights that also have the potential to be controlled through Ethernet (via RF).
I've found that while the transceivers aren't rated for 5V, they can run off of them. I don't assume they'll run forever, so the relay shield has an LDO regulator on it.
Here are the sketches, as an example for how simple these things are, for the light sensor and the relay:
/* TinyLight.ino
* Small wireless sensor that will send out the data for a single light sensor every 65 seconds
* and sleep the system in between.
*/
#include <JeeLib.h>
// Initializes an interrupt routine to allow for easy sleeping
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
// The struct that will carry our packet
typedef struct {
unsigned long id;
int value;
} Payload;
Payload payload;
const int netID = 23; // The network ID
const int nodeID = 1; // The node ID
const unsigned long lightID = 0xA0000001; // id of our light sensor
const int lightPin = 0; // The pin that our sensor is connected to
void setup () {
// Initialize our rf12 library
rf12_initialize(nodeID, RF12_433MHZ, netID);
rf12_sleep(0); // Put the node to sleep
payload.id = lightID; // set the sensor id in our struct
}
void loop () {
payload.value = analogRead(lightPin); // get light level
rf12_sleep(-1); //wake up RF module
while (!rf12_canSend()) // wait until we can send
rf12_recvDone();
// Send our payload
rf12_sendStart(0, &payload, sizeof payload);
rf12_sendWait(2); //wait for RF to finish sending while in standby mode
rf12_sleep(0); //put RF module to sleep
Sleepy::loseSomeTime(65000); // Put to sleep for 65 seconds
}
/* TinyRelay.ino
* Listens for a certain light sensor ID. Uses the TinyRF header to abstract
* the parsing of the rf12 signals and assign the value of the sensor that we
* receive from the RF to a variable
*/
#include <JeeLib.h>
#include "TinyRF.h" // Simple library to
#define LENGTH_OF_PAYLOAD 10
const int netID = 23; // The network ID
const int nodeID = 2; // The node ID
const int relayPin = 9; // drives the relay
const int rxPin = 3; // led to signify we received something
const unsigned long lightID = 0xA0000001; // id of the sensor we're looking for
int lightLevel=500; // keeps track of the the current light level
const int darkLimit = 600; // When this light level is reached, turn off
const int lightLimit = 300; // When this light level is reached, turn on
void setup() {
pinMode(relayPin, OUTPUT);
pinMode(rxPin, OUTPUT);
rf12_initialize(nodeID, RF12_433MHZ, netID);
/* Whenever we receive an update for our lightID, store the value in our
* lightLevel variable */
tinyrf_subscribe(lightID, &lightLevel);
}
void loop() {
static int relayState = LOW;
if (rf12_recvDone() && rf12_crc == 0) {
digitalWrite(rxPin, HIGH);
// send data to update any variables we've subscribed to
tinyrf_checkinc(rf12_data, rf12_len);
delay(50);
digitalWrite(rxPin, LOW);
if (lightLevel > darkLimit)
relayState = LOW;
else if (lightLevel < lightLimit)
relayState = HIGH;
}
digitalWrite(relayPin, relayState);
}
This is the header that just abstracts some of the checking and allows me to "subscribe" a variable to updates for a certain sensor ID.
#ifndef TinyRF_h
#define TinyRF_h
#include <JeeLib.h>
#define rf_ids_match(A,B,C) (((uint16_t*)A)[0] == B[C].id)
#define MAX_SUBS 5
typedef struct {
uint16_t id;
int * var;
} Sub;
Sub subs[MAX_SUBS];
byte subCount=0;
void tinyrf_subscribe(uint16_t id, int *var) {
subs[subCount].id = id;
subs[subCount].var = var;
subCount++;
}
void tinyrf_checkinc(volatile uint8_t *inc, int len) {
if (len !=6) return;
for (int i=0; i<subCount; i++) {
if ( rf_ids_match(inc, subs, i) )
*subs[i].var = ((int*)(inc+4))[0];
}
}
#endif
Anyone have any insight on things I haven't considered? Maybe an angle that I am missing? Question? Comments? Emotional outbursts? If anyone is interested in the eagle files, I'm not shy about sharing those as well.