Introduction: Home Automation Project Based on 1-wire Devices
Home automation project using the following components
Arduino Mega 2560 http://arduino.cc/en/Main/arduinoBoardMega2560
Integrated circuits:
Maxim DS18B20 http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
Maxim DS2413 http://datasheets.maximintegrated.com/en/ds/DS2413.pdf
Panasonic AQH3213 http://www.panasonic-electric-works.com/peweu/en/downloads/ds_61613_en_aqh.pdf
UTP cabling with RJ11 connectors (star topology with serial buses, multiple devices on each bus)
Capable of handling:
8 1-wire buses (using dynamic class instances for the library)
256 switches
256 relays
128 temperature sensors (non-parasite mode for faster bus)
* Switch-to-relay associations are freely programmable
* No high voltage and power wires at wall switches, only 12V DC over UTP cable
* Lower surge current and electromagnetic radiation since SSRs turn on and off at zero crossing
* Switches are continuously scanned by the Arduino - as a result switching of relays/lamps work immediately just like for normal lamp switches (many home automation systems are a bit slow, with recognizable delay)
* Single 3.9 k pull-up resistors on the Arduino pins (passive pull-up solution)
* PIR movement sensors, light sensors etc. could be used as switch devices as well (monostable mode with adjustable timer)
* Relays are AC (SSR) or DC (MOSFET) for LED lighting etc.
* Current limitation: SSR maximum current is 1.2A therefore load should be less than 250W (at 220V AC)
* Temperature sensors readable anytime - they are "hidden" in wall switches
* Device data and settings are stored in the EEPROM of the Arduino board - system works even after power outage
* Changes are programmed by serial commands from PC, however it works standalone as well without a PC connected
* By design complex functions which are not time critical should be handled on the PC level instead of the micro controller - e.g activation of heating based on averaged temperature values
Command examples:
R4>1 Turn on lamp connected to Relay4
R4:1 (response)
Scan Scan for new connected devices
New devices added(list with IDs)
T8? Temperature measured by temperature sensor
T8:18.7
R14? State of relay
R14:1
S9>R6 Switch9 bound to Relay6
S9>R7 Switch9 also bound to Relay7 (wall switch 9 will control lamps (or other loads) 6 and 7 from now on)
Status message example:
R2:0 Lamp connected to Relay2 has been turned off by one of the associated switches or by command
---
Code sections (simplified)
Reading temperature sensor:
#include OneWire.h
#include EEPROM.h
OneWire *ow;; // class value initialization
byte addr[8]; // array to store 1-wire device address
float celsius;
byte m; // temperature sensor number (each sensor address uses 4 bytes in the EEPROM)
bus byte; // Arduino pin to use (pin=bus+1)
void MeasureTemp()
{
addr[0]=40; // hex28
addr[1]=EEPROM.read(m*4); // address bytes 1-4 (significant bytes) stored at these positions
addr[2]=EEPROM.read(1+m*4);
addr[3]=EEPROM.read(2+m*4);
addr[4]=(EEPROM.read(3+m*4))&15;
addr[5]=0; // bytes 5 ad 6 of the 1-wire device address are always 0
addr[6]=0;
addr[7]=addrOneWire::crc8(addr,7); // byte 7 (CRC) is generated from the previous 7 bytes
ow=new OneWire(bus+1); // creation of class instance
ow->.reset();
ow->select(addr); // select temperature sensor
ow->write(68); // start conversion, with zener (bus can be used during the conversion)
delete(ow); // delete of class instance
}
{ 800 ms delay (with timer routine) allowing the DS18B20 calculating the 12 bit temperature value }
void ReadTemp()
{
addr[0]=40;
addr[1]=EEPROM.read(m*4);
addr[2]=EEPROM.read(1+m*4);
addr[3]=EEPROM.read(2+m*4);
addr[4]=(EEPROM.read(3+m*4))&15;
addr[5]=0;
addr[6]=0;
addr[7]=addrOneWire::crc8(addr,7)
ow=new OneWire(bus+1);
ow->reset();
ow->select(addr);
ow->write(190); // command to read the sensor
datalow=ow->read(); // reading bytes 1 and 2 only, the actual temperature value
datahigh=ow->read();
delete(ow);
unsigned int raw = (datahigh << 8) | datalow; // shifting bits up to form a 12 bit value
celsius = int(((float)raw / 16.0)*10);
}
Serial.println (celsius/10); // result is in Celsius with 0.1 degree accuracy
---
Reading switch status:
byte PIOdata;
byte k; // switch ID
void ReadPIO()
{
ow->reset();
addr[0]=58;
addr[1]=(EEPROM.read(2048+k*8));
addr[2]=(EEPROM.read(2049+k*8));
addr[3]=(EEPROM.read(2050+k*8));
addr[4]=(EEPROM.read(2051+k*8)&15); // address byte is always less than 15
addr[5]=0;
addr[6]=0;
addr[7]=OneWire::crc8(addr,7);
ow->select(addr); // select switch
ow->write(245); // PIO read command
PIOdata=ow->read();
if (PIOdata==30) // switch A is closed*
{
ToggleLamp(); // relay state inverted and short delay added to prevent flapping
}
}
* if both contacts are open the result is 15
bit 0 DS2413 pin 6 (PIO A) input level
bit 1 DS2413 pin 6 (PIO A) inverted (!) output level (controls output transistor) , 0 = transistor pulls pin to ground
bit 2 DS2413 pin 4 (PIO B) input level
bit 3 DS2413 pin 4 (PIO B) inverted output level
bit 4-7 inverted values of bits 0-3
as a result 15 (0000 1111) means both input levels are HIGH (bits 0 and 2) due to the 22 kohm pullup resistors and both output transistors are open (bits 1 and 3) they allow the output to "float"
when switch A is closed pin 6 is shorted to ground resulting bit 0 to change to LOW:
input value will change from 15 (0000 1111) to 30( 0001 1110)
when switch B is closed (while switch A is released) the input is 75 (0100 1011)
---
Inverting Relay state:
void ToggleLamp()
{
addr[0]=58;
addr[1]=(EEPROM.read(1020+m*4));
addr[2]=(EEPROM.read(1021+m*4));
addr[3]=(EEPROM.read(1022+m*4));
addr[4]=(EEPROM.read(1023+m*4)&15);
addr[5]=0;
addr[6]=0;
addr[7]=OneWire::crc8(addr,7);
ow->reset();
ow->select(addr); // select relay,
ow->write(245); // PIO read command
PIOdata=dv.read();
if (PIOdata==15) // Transistors are open (=relay is open)
{
ow->reset();
ow->select(addr);
ow->write(90); // PIO write command
ow->write(254); // turn on transistor A*
ow->write(1); // inverted byte must be written as well for verification (!)
Serial.print("R");
Serial.print (m);
Serial.println (":1");
}
if (PIOdata==120) // relay is closed
{
ow->reset();
ow->select(addr);
ow->write(90); // PIO write command
ow->write(255); // turn off transistor A*
ow->write(0); // inverted byte must be written as well for verification (!)
Serial.print("R");
Serial.print (m);
Serial.println (":0");
}
}
* The SSR's internal LED is driven by transistor A (PIO A output) of the 1-wire switch, pin 6. When bit 0 is set to 0 (111111 10) the transistor pulls the output level to GND - activating the LED and the SSR. By setting bit 0 to 1 (111111 11) the SSR is deactivated.
Output B is not in use in my circuit, however of course it could activated similarly with bit 1 (111111 01). The remaing six bits must be high all the time.
Since both switches and relay use DS2413 chips they are differentiated when a new device is added. A routine activates transistor A for a short period. In case the remote device is a relay logical LOW will be detected on the PIO B input since the two pins are connected.
In progress:
*Test of PIR sensors and addition of adjustable delay function in the software
*Developing pressure sensor
*Modifying the OneWire library to allow parallel operation on all buses (currently all 1-wire commands are sequential)
*Testing 1-wire Overdrive mode
*Web based remote management (PHP+UDP)
> Further development is planned in 2018 since there seems to be an interest in this project.