Easy modular home automation

Attention

This solution is given as it is, and I can/will not guarantee that it can not be hacked or abused by others. So use your common sense if you put it into use, and let me know if you got some security/stability improvements. 🙂

What is this?

This is a cheap way of making some simple home automation, so far this system can only switch relays/pins on and off, and control PWM channels.

What does make this system so genious?

  • It uses cheap RF modules (4-6£ per set)
  • It can use all arduino versions as receivers (sender does require a version that can interface with Ethernet)
  • It can use cheap pre-assembled relay boards that can handle 230V and are op-to isolated from the controller
  • It is very easy to add additional receivers to the system
  • It is easy to have something like PHP interface with it to control stuff from a website
  • It is free and opensource 🙂

How to use it?

I got the sender and receiver ready, how to I use it?

First you need the sender’s ip.

To turn a pin on, you then call http://sender-ip/_ident-pin-status_

ident is the ident in the receiver you gave it in the top of the sketch

pin is the pin number on the arduino you want to turn on

status is what you want that pin to do, 1 turns a digital pin HIGH and 0 turns it LOW

But I want to use it to control something that just needs an inpulse!

To do that, you add one extra value to it, so it will be http://sender-ip/_ident-pin-pulses-delay_

ident is the ident in the receiver you gave it in the top of the sketch

pulses is how many times you want it to pulse that pin

delay is how long a delay you want between changing the pin

  

Sender

When calling http://192.168.1.88/_gar-12-0_ this will send gar-12-0 over RF. “gar” is the identifier for the receiver, 12 is the pin number, and 0 is the value the pin will be set to.

#include <VirtualWire.h>
#define txPin 5

//Used for ethernet
#include <Ethernet.h>
#include <SPI.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 88 };
byte gw[] = { 192,168,1,1 };
byte subnet[] = { 255, 255, 255, 0 };

Server server(80);

String inString = String(35);

void setup()
{
  pinMode(13, OUTPUT);

  Serial.begin(9600);

  Ethernet.begin(mac, ip, gw, subnet);
  server.begin();
  Serial.println();
  Serial.println("Connecting...");
  delay(1000);
  vw_set_tx_pin(txPin);
}

void loop()
{
  Client client = server.available();
  if (client)
  {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;

    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        inString += c;

        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();

          break;
        }

        if (c == '\n')
        {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r')
        {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);

    int startCommand = inString.indexOf('_');
    int stopCommand = inString.indexOf('_', startCommand + 1);

    if (startCommand > 0 && stopCommand > 0)
    {
      client.print("RF > ");
      client.println(inString.substring(startCommand+1, stopCommand));
    }
    // close the connection:
    client.stop();

    if (startCommand > 0 && stopCommand > 0)
    {
      Serial.print("RF > ");
      Serial.println(inString.substring(startCommand+1, stopCommand));
      rfSend(inString.substring(startCommand+1, stopCommand));
    }

    inString = "";
  }
}

//Send message over RF
void rfSend(String message)
{
  digitalWrite(13, HIGH);
  char output[100];

  message.toCharArray(output, 99);

  vw_setup(1000);
  vw_send((uint8_t *)output, strlen(output));
  vw_wait_tx();                          // Wait for message to finish
  digitalWrite(13, LOW);

  Ethernet.begin(mac, ip, gw, subnet);
  server.begin();
}

Receiver

This expects a message from the sender like identifierpin-value, and will then set the defined pin to the defined value

/*
  Home Automation Node by bld @ http://captain-slow.dk/
 Version 0.2
 */

static String ident = "gar";    // Identification for this device

#include <VirtualWire.h>
#define rxPin 7

#define DEBUG 2 //Define to include serial communication

const int ledPin = 13;           // The number of the LED pin, LED used to indicate we got a message
long onMillis = 0;               // Will store last time LED was updated

#define startPin 3               // The first pin we connect a relay to
#define stopPin 6                // The last pin we connect a relay to

int stepsLeft[(stopPin-startPin)+1]; //Array to store how many times it should flash the pin
int stepDelay[(stopPin-startPin)+1]; //Array to store how long a delay there should be between the pin state changing
unsigned long lastStep[(stopPin-startPin)+1];  //Array to store when the pin was changed last


void rf_start()
{
  //Set-up the RF receiver
  vw_rx_stop();                  // Stop it in case it is already running
  vw_set_rx_pin(rxPin);          // We will be receiving on pin 2 ie the RX pin from the module connects to this pin.
  vw_setup(1000);                // Bits per sec
  vw_rx_start();                 // Start the receiver
}

void setup()
{

#ifdef DEBUG
  Serial.begin(9600);
#endif

  pinMode(ledPin, OUTPUT); 

  //Set-up the RF receiver
  rf_start();

  for (int i = startPin; i <= stopPin; i++) // We need to set the pins that control the relays to OUTPUT
  {
#ifdef DEBUG
    Serial.print("Setting pinMode on pin: ");
    Serial.println(i);
#endif
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW); // We set the pin to LOW because pulling it HIGH will turn the relay on
  }

#ifdef DEBUG
  Serial.println("Ready to receive!");
#endif
}

void loop()
{
  for (int i = 0; i <= stopPin-startPin; i++) // Run through the arrays to see if any pin should be changed
  {    
    if (stepsLeft[i] > 0) // Do we have to do any steps on this pin?
    {
      if (millis() - lastStep[i] > stepDelay[i]) // Is it time to change the pin?
      {

#ifdef DEBUG && DEBUG == 2
        Serial.print("Pin: ");
        Serial.print(stopPin-i);
        Serial.print(" - stepsLeft: ");
        Serial.print(stepsLeft[i]);
        Serial.print(" - lastStep: ");
        Serial.print(lastStep[i]);
        Serial.print(" - stepDelay: ");
        Serial.print(stepDelay[i]);
        Serial.print(" - arrayPos: ");
        Serial.print(i);
        Serial.print(" - digitalRead: ");
        Serial.println(!digitalRead(stopPin-i));
#endif

        lastStep[i] = millis(); // Set when we last changed the pin
        digitalWrite(stopPin-i, !digitalRead(stopPin-i)); // Set the pin to the opposite of what it just was
        stepsLeft[i]--; // Remove one step

        if (stepsLeft[i] < 1) digitalWrite(stopPin-i, LOW); // Set the pin to LOW, just to be sure.
      }
    }
  }

  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) // Check to see if anything has been received
  {
    String message((char *)buf); //Store the message received

#ifdef DEBUG && DEBUG == 2
    Serial.print("RF incomming: ");
    Serial.print(message);
#endif

    if (message.substring(0,ident.length()) == ident) // Check if this message was for us
    {
      digitalWrite(ledPin, HIGH); // Turn led on to indicate we received something, and is going to look more at it
      onMillis = millis(); // Save when led was turned on so we remember to turn it off again later

      message = message.substring(ident.length()+1); // Remove the identifier from the message

      int startCommand = message.indexOf('-'); // Find where we split pin number from pin status

      String getPinNum = message.substring(0, startCommand); // Save a String with the pin number
      String getPinSet = message.substring(startCommand + 1, message.length()); // Save a String with the value we are going to send to the pin

      int delayCommand = message.indexOf('-', startCommand + 2); // Check if there is added a delay for the pin to be turned off again

      char tempNum[10]; //Char to hold the message before converting it to an integer

      int pinDelay = 0;

      if (delayCommand > 0)
      {
        getPinSet = message.substring(startCommand + 1, delayCommand); // Save a String with the value we are going to flash the pin

        String getPinDel = message.substring(delayCommand + 1, message.length()); // Save a String with the value we are going to delay the flash
        tempNum[getPinDel.length() + 1]; // Temp save pin value
        getPinDel.toCharArray(tempNum, 10);
        pinDelay = atoi(tempNum); // Convert char array to an integer
      }
      else
      {
        pinDelay = 0;
      }

      tempNum[getPinNum.length() + 1]; // Temp save pin number
      getPinNum.toCharArray(tempNum, 10);
      int pinNum = atoi(tempNum); // Convert char array to an integer

      tempNum[getPinSet.length() + 1]; // Temp save pin value
      getPinSet.toCharArray(tempNum, 10);
      int pinSet = atoi(tempNum); // Convert char array to an integer

#ifdef DEBUG
      Serial.print("Pin num: ");
      Serial.print(pinNum);
#endif

      if (pinNum != rxPin) //Make sure it won't be possible to accidently diable communication
      {
        if (pinDelay > 0)
        {

#ifdef DEBUG
          Serial.print(" - Cycles: ");
          Serial.print(pinSet);

          Serial.print(" - Delay: ");
          Serial.println(pinDelay);
#endif

          stepsLeft[stopPin-pinNum] = pinSet*2; //Store how many times the pin should flash, it is changing state for each pass, so it should be done twice for 1 on/off cycle
          stepDelay[stopPin-pinNum] = pinDelay; //Store the delay between pin changes
          lastStep[stopPin-pinNum] = 0; //Set the last time it changed to 0 so it will happen on next loop
        }
        else
        {

#ifdef DEBUG
          Serial.print(" - Pin status: ");
          Serial.println(pinSet);
#endif

          digitalWrite(pinNum, pinSet); // Set the pin defined earlier
        }
      }

#ifdef DEBUG
      else
      {
        Serial.println(" - WARNING: Can not change RX pin!");
      }
#endif

    }
  }

  buf[buflen] = '\0'; //Empty String message again

  if (millis() - onMillis > 250 && onMillis > 0) // Check if it is time to turn the led off
  {
    onMillis = 0;
    digitalWrite(ledPin, LOW);
  }
}

To add multiple receivers, you simply just change ident, and it is then possible to send a message to each controller.

One comment

  • you can share the circuit scheme? or tell how pins i use to conect the RF receiver/transmiter and the reles pins?? thanks…

Leave a Reply