It's a reasonably cheap solution to the problem of high-voltage control, the transmitter is usually around $5 and the adapters start at $10. The main problem with any RF hack is that legislation (and thus hardware) will differ across countries, so while this can be made to work with other types of adapter you'll need to modify the code to send the appropriate signals. I used a logic analyser to capture the signal for this adapter but you could also use any of the numerous IR capture/playback libraries normally used for TV remotes.
These are still cheap and nasty devices, so a little common sense should always prevail. While safer than plugging directly into a 240V relay I still wouldn't plug an oven in and head on down to the pub!
Gamebuino code:
- Code: Select all
// GBAUTO - Gamebuino Home Automation
// by Myndale (simbuino@ppl-pilot.com)
//
// This demo enables Gamebuino control of Watts Clever RF power adapters
// (see https://www.wattsclever.com/au/products/easy-off-sockets).
// It requires a standard 434MHz ASK transmitter chip with the data pin tied to the Gamebuino's I2C SDA pin (analog 4).
#include <SPI.h>
#include <Gamebuino.h>
Gamebuino gb;
#define TX A4
#define DATA_PORT PORTC
#define DATA_BIT (1 << 4)
#define ON 0
#define OFF 1
const char * commands[][2] =
{
{"0011001011111101110111100", "0011001011111101110101100"},
{"0011001011111101110111000", "0011001011111101110101000"},
{"0011001011111101110110100", "0011001011111101110100100"},
{"0011001011111101110110010", "0011001011111101110100010"}
};
boolean states[] = {false, false, false, false};
void titleScreen()
{
gb.titleScreen(F("Gamebuino Automation"));
}
// the setup routine runs once when Gamebuino starts up
void setup(){
gb.begin();
pinMode(TX, OUTPUT);
titleScreen();
}
// the loop routine runs over and over again forever
void loop() {
if(gb.update()) {
if(gb.buttons.pressed(BTN_C))
titleScreen();
if (gb.buttons.pressed(BTN_UP)) states[0] ^= true, transmit(0);
if (gb.buttons.pressed(BTN_LEFT)) states[1] ^= true, transmit(1);
if (gb.buttons.pressed(BTN_RIGHT)) states[2] ^= true, transmit(2);
if (gb.buttons.pressed(BTN_DOWN)) states[3] ^= true, states[0] = states[1] = states[2] = states[3], transmit(3);
drawButton(42, 9, F(" 1 "), states[0]);
drawButton(27, 24, F(" 2 "), states[1]);
drawButton(57, 24, F(" 3 "), states[2]);
drawButton(42, 39, F("All"), states[3]);
}
}
void drawButton(const byte x, const byte y, const __FlashStringHelper * text, boolean state)
{
gb.display.setColor(state ? BLACK : WHITE);
gb.display.fillCircle(x, y, 8);
gb.display.setColor(BLACK);
gb.display.drawCircle(x, y, 8);
gb.display.cursorX = x - 5;
gb.display.cursorY = y - 2;
gb.display.setColor(INVERT);
gb.display.println(text);
}
void delayUs(volatile unsigned uS) {
while (--uS) {
__asm__ __volatile__ (
"nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop"
);
}
}
void zero() {
DATA_PORT |= DATA_BIT;
delayUs(117);
DATA_PORT ^= DATA_BIT;
delayUs(489);
}
void one() {
DATA_PORT |= DATA_BIT;
delayUs(425);
DATA_PORT ^= DATA_BIT;
delayUs(181);
}
void transmit(const byte channel)
{
const char * signal = commands[channel][states[channel] ? ON : OFF];
noInterrupts();
for (int i=0; i<5; i++)
{
const char * c = signal;
while (*c)
{
if (*c++=='1')
one();
else
zero();
}
delayUs(4237);
}
interrupts();
if (states[channel])
gb.sound.playOK();
else
gb.sound.playCancel();
}