Forget Me Not : eLDERmon Hardware Hacking #3
This post continues with my Hardware modification to provide a 'status' indication back from RF switched Outlets
The intention is to fit the Transmitter and ATtiny85 inside an existing Watts Clever RF Switched Outlet.
As the picture shows there is very little room, and as such the final design has been modified very slightly to suit the construction.
I've used veroboard to connect everything, rather than run multiple wires.
As the photos show there are few connections, and removing the socket pins simplified the voltage connection to the transmitter.
Ideally I would have produced a pcb and sent it away, but I have only one socket which was not part of my original design.
However because I've seen how useful Openhab is, its worth adding it in now.
Control Pin
I'm using the relay drive pin on the main controller (pin 9)
It will either be HIGH when the relay is ON, or dragged low by the series resistor and base junction.
I don't want to continually send the status, so the ATtiny85 polls the pin for a change and sends the appropriate code.
This reduces the amount of RF floating around which could result in a data collision.
Status Delay
In order to prevent data collisions from the sender to the RF socket, we need to add a delay, before it responds.
Searching the RCSwitch library it shows that each pulse is 350uS for Protocol 1 (I checked earlier with a receiver and confirmed it was using protocol 1)
/** * Sets the protocol to send. */ void RCSwitch::setProtocol(int nProtocol) { this->nProtocol = nProtocol; if (nProtocol == 1){ this->setPulseLength(350); } else if (nProtocol == 2) { this->setPulseLength(650); } } /** * Sets the protocol to send with pulse length in microseconds. */ void RCSwitch::setProtocol(int nProtocol, int nPulseLength) { this->nProtocol = nProtocol; if (nProtocol == 1){ this->setPulseLength(nPulseLength); } else if (nProtocol == 2) { this->setPulseLength(nPulseLength); } }
Each data bit is a certain length, with a varying amount of HIGH/ON v LOW/OFF time
Checking the library shows.
void RCSwitch::send0() { if (this->nProtocol == 1){ this->transmit(1,3); } else if (this->nProtocol == 2) { this->transmit(1,2); } } /** * Sends a "1" Bit * ___ * Waveform Protocol 1: | |_ * __ * Waveform Protocol 2: | |_ */ void RCSwitch::send1() { if (this->nProtocol == 1){ this->transmit(3,1); } else if (this->nProtocol == 2) { this->transmit(2,1); } }
void RCSwitch::transmit(int nHighPulses, int nLowPulses) { //boolean disabled_Receive = false; //int nReceiverInterrupt_backup = nReceiverInterrupt; //if (this->nTransmitterPin != -1) { //if (this->nReceiverInterrupt != -1) { // this->disableReceive(); //disabled_Receive = true; // } digitalWrite(this->nTransmitterPin, HIGH); delayMicroseconds( this->nPulseLength * nHighPulses); digitalWrite(this->nTransmitterPin, LOW); delayMicroseconds( this->nPulseLength * nLowPulses); //if(disabled_Receive){ // this->enableReceive(nReceiverInterrupt_backup); //} //} }
So each data bit is either 350uS HIGH, then 3x 350uS LOW, for a 0 or 3x350uS HIGH, then 350uS LOW for a 1.
Thus each data bit is 1400uS long, and my code is 24 bits long = 33600 uS or 33.6mS long.
This contrasts with the EnOcean protocol which is 25mS long for 3 sub telegrams
The next item to check was the delay between repeats.
The library shows a sync is sent after the data.
/** * Sends a "Sync" Bit * _ * Waveform Protocol 1: | |_______________________________ * _ * Waveform Protocol 2: | |__________ */ void RCSwitch::sendSync() { if (this->nProtocol == 1){ this->transmit(1,31); } else if (this->nProtocol == 2) { this->transmit(1,10); } }
The sync is 32 x 350uS = 11.2mS.
So is my deciphering correct.??
single code transmission measured at 35.2mS
The calculation was 33.6mS so either the clock is out or there are some other delays ... but close enough.
two codes transmitted and measured at 80.4mS total
This contrasts with the 78.4mS I calculated ( 33.6mS + 11.2mS + 33.6mS ).... but will work just fine.
Now that I know it takes 80ish mS for TWO data transmissions, I can program a delay for the status transmission and be assured there is little chance of a clash.
I also want to ensure there is some variance in the delay, based on the ID, so I will multiple it by the ID to ensure there is staggered responses for the "ALL ON" or "ALL OFF" command that these outlets provide.
So the delays will be :-
ID | Delay mS |
---|---|
0 | 100 |
1 | 200 |
2 | 300 |
3 | 400 |
4 | 500 |
5 | 600 |
6 | 700 |
7 | 800 |
This means that every time the RF Outlet is changed, I should expect two status messages within 900mS (80 + 800 delay = 880 mS)
I have no idea if there are any delays built into the controller inside the RF Outlets, but we will find that out when its all assembled and tested.
ID Programming
Since I only have one outlet, I'm simply going to code the ID into the ATtiny85.
// ******** ID of each unit ********* const byte StatusID = 0; // change this to suit each unit (range 0 to 7 before adding more channels)
I've made the code so that the ID number changes the delay and sets the status code.
InputState = digitalRead(InputPin); if (InputState != PrevInputState) { delay(100); //delay to allow 2x code to be sent from the sending end to the Outlet. /* The state will be read and compared with the last state. If there is a change then the status will be sent after a delay If the Outlet changes again this will be detected and a second status sent ... hence the delay positions. In theory the controller inside the Outlet will not toggle unexpectedly, so no debounce is required. */ if (InputState == HIGH && PrevInputState == false) { //Outlet was OFF and now is ON delay(100 * (StatusID)); //delay based on ID to prevent collisions mySwitch.send((ChannelCodes[StatusID]+8), 24); PrevInputState = true; } if (InputState == LOW && PrevInputState == true) { //Outlet was ON and now is OFF delay(100 * (StatusID)); //delay based on ID to prevent collisions mySwitch.send(ChannelCodes[StatusID], 24); PrevInputState = false; } }
If you had quite a few to make, you could add jumpers, measure the DC voltage on a pin or other hardware methods of setting the ID.
Whatever you use, it takes some time, so for my single Outlet, changing the code takes the least time.
Installed
Despite forcing things to one side, bending transistors over, and generally being rough, it would not fit under the switch.
I resorted to fitting it beside the earth pin, which on hindsight is the better location.
Because everything is isolated from the user, there is no requirement to double insulate, so I could use whatever wire that suited and the separation distance didn't apply.
The 170mm antenna is looped up and around, which is the best you can do given the internal dimensions.
Mark
Top Comments