So you have a device which has a 433Mhz RF remote control and you would like to have an Arduino with a RF transmitter emulate the remote and control the device directly.
The first thing is to order a couple of parts that you will need. You will want a 433Mhz transmitter and receiver and you can get the ones advertised for the Arduino very cheaply off ebay. You will also need a prototype board and some jumper wires to temporarily connecting the RF receiver.
Next you will need a logic analyser so you can view the signal and decode it. I bought a 'USB Logic Analyser' from the ebay seller EllieShang. This logic analyser is programmable and there is a good guide that you should read about programming it to work with different software on jwandrews.co.uk. My logic analyser happened to already be set to work with the Salae Logic analyser software (can be freely downloaded) so I didn't need to reprogram it.
Now that you have all that you need connect the RF receiver to the prototype board. You can use the 5V and GND from the Arduino to power the RF receiver. You dont need to solder an additional antenna to the RF receiver as it will work fine if you just hold the transmitter remote control within a few cm. Connect the logic analyser to the GND and its first input to the RF receiver data pin and you are ready to go.
Now you should be able to hold the remote near the RF receiver, hold down a button and capture the waveform in the Saleae software. It should look something like this
Head over to Tinkerman's blog for instructions on how to decode the waveform. The only thing not mentioned there is how to calculate the pulse length. A 'short' is one pulse width wide and a 'long' is 3 pulse widths. So you can see that each of the four possible values are 8 pulse widths in length. There are twelve codes so that give 12*8=96. In addition there is also a synchronisation pulse at the end followed by 31 low pulse widths. So overall the transmission is 128 pulse widths. So you can calculate the pulse width as 39.24ms/128 = 307us. If you wish to make sure your Arduino is spot on with its timing you can just capture its signal and compare and tweak the timing as required.
To see how to program an Arduino with this data have a look at my blog entry Controlling Bye Bye Standby devices using an Arduino
Saturday, 14 June 2014
Controlling Bye Bye Standby devices using an Arduino
Note: Since the receivers are learning and the old Bye Bye units had a switch to select the channel and a 'house code' I don't know if all the transmitters are the same. It would make sense if they were not otherwise two neighbours could interfere with each others devices. Therefore the codes below probably wont work straight away but you could teach your devices to use these codes. If you wish to still use your existing remote then take a look at my next blog which gives instructions on how to decode the RF signal yourself.
First you will need a 433Mhz RF transmitter which can be bought cheaply off ebay. You will also need to download the RCSwitch library.
The Bye Bye Standby units use a quad state code which the RCSwitch library does not support. However on Tinkerman's blog he details the few changes that need to be added to get this supported. Its a very good blog so well worth reading any way.
The RF transmitter can work with a supply voltage up to 12V and with a good antenna can have a range of many hundreds of meters. A good option when interfacing with an Arduino is to run it off the built in 5V supply and solder a 17cm long wire to the antenna pad. I found that I was able to reliably control a device behind the TV in the front downstairs room from the back bedroom.
Next all you need are the codes for the Bye Bye Standby which I have included in the following sketch.
First you will need a 433Mhz RF transmitter which can be bought cheaply off ebay. You will also need to download the RCSwitch library.
The Bye Bye Standby units use a quad state code which the RCSwitch library does not support. However on Tinkerman's blog he details the few changes that need to be added to get this supported. Its a very good blog so well worth reading any way.
The RF transmitter can work with a supply voltage up to 12V and with a good antenna can have a range of many hundreds of meters. A good option when interfacing with an Arduino is to run it off the built in 5V supply and solder a 17cm long wire to the antenna pad. I found that I was able to reliably control a device behind the TV in the front downstairs room from the back bedroom.
Next all you need are the codes for the Bye Bye Standby which I have included in the following sketch.
#include <RCSwitch.h>
#define MAX_STRING_LEN 25
RCSwitch mySwitch = RCSwitch();
String lineinput = "";
void setup() {
Serial.begin(9600);
mySwitch.enableTransmit(10);
mySwitch.setProtocol(1);
mySwitch.setRepeatTransmit(10);
mySwitch.setPulseLength(300); // Bye Bye Standby
}
void loop() {
while (Serial.available() > 0)
{
char c = Serial.read();
if (c != '\n')
{
lineinput += c;
}
else {
// handle entered data or request
Serial.println("Entry='" + lineinput + "'");
lineinput.trim();
if (lineinput == "1on")
{
mySwitch.sendTriState("X0X1F00XXX11");
}
if (lineinput == "1off")
{
mySwitch.sendTriState("X0X1F00XXXF1");
}
if (lineinput == "2on")
{
mySwitch.sendTriState("X0X1F00XXX1F");
}
if (lineinput == "2off")
{
mySwitch.sendTriState("X0X1F00XXXFF");
}
if (lineinput == "3on")
{
mySwitch.sendTriState("X0X1F00XXXX1");
}
if (lineinput == "3off")
{
mySwitch.sendTriState("X0X1F00XXX01");
}
if (lineinput == "4on")
{
mySwitch.sendTriState("X0X1F00XXX1X");
}
if (lineinput == "4off")
{
mySwitch.sendTriState("X0X1F00XXXFX");
}
if (lineinput == "5on")
{
mySwitch.sendTriState("X0X1F00XXX10");
}
if (lineinput == "5off")
{
mySwitch.sendTriState("X0X1F00XXXF0");
}
if (lineinput == "6on")
{
mySwitch.sendTriState("X0X1F00XXXXX");
}
if (lineinput == "6off")
{
mySwitch.sendTriState("X0X1F00XXX0X");
}
if (lineinput == "allon")
{
mySwitch.sendTriState("X0X1F00XXXXF");
}
if (lineinput == "alloff")
{
mySwitch.sendTriState("X0X1F00XXX0F");
}
lineinput = "";
}
}
}
Wednesday, 24 July 2013
How to pause and resume Asterisk call recordings
If you record your calls you may wish to enable pausing and unpausing of the recordings. This is relativly simple to do once you understand the features.conf file and the ActivateOn and ActivatedBy fields.
Firstly lets take the example where you receive an incoming call and wish to pause and unpause it. features.conf would contain the following two lines in the [applicationmap] section :-
For doing the same with outbound calls its the caller who is allowed to pause and unpause and since this is the same channel which ran the Monitor() application the macro needs to be run on the same channel :-
Firstly lets take the example where you receive an incoming call and wish to pause and unpause it. features.conf would contain the following two lines in the [applicationmap] section :-
InPauseMonitor => #1,peer/callee,Macro,recpause,recording-disabledIt is the callee which is allowed to pause and unpause and since the Monitor() application is being run on the inbound channel the macro needs to be run on the peer.
InUnpauseMonitor => #3,peer/callee,Macro,recunpause,recording-enabled
For doing the same with outbound calls its the caller who is allowed to pause and unpause and since this is the same channel which ran the Monitor() application the macro needs to be run on the same channel :-
OutPauseMonitor => #1,self/caller,Macro,recpause,recording-disabledHere are the macros which are called and should be placed in extensions.conf. Rather than pausing and unapusing the recording we are actually stopping and starting the recording. That is purely because we have all the individual recordings sent to a remote server which combines and converts them to a mp3 file therefore reducing the cpu load on the asterisk server.
OutUnpauseMonitor => #3,self/caller,Macro,recunpause,recording-enabled
[macro-recpause]In the features.conf file in addition to specifying the macro to be run we also specified a music on hold class to be used for playing music on hold to the other party. Shown below are the contents of musiconhold.conf and exactly the same files are played as in the ones in the macros. This ensures both parties hear the exact same audio. You can use different audio files if you wish although make sure the music on hold files are the exact same duration otherwise they will be cut short if they are longer or partially repeated if they are shorter.
exten => s,1,Playback(/var/lib/asterisk/sounds/recording/beep/beep)
exten => s,n,NoOp(Call Paused - Channel=${CHANNEL} BrigdePeer=${BRIDGEPEER})
exten => s,n,StopMonitor
[macro-recunpause]
exten => s,1,Monitor(wav,${FNAME}_${EPOCH})
exten => s,n,NoOp(Call Unpaused - Channel=${CHANNEL} BrigdePeer=${BRIDGEPEER})
exten => s,n,Playback(/var/lib/asterisk/sounds/recording/beepbeep/beepbeep)
[recording-disabled]
mode=files
directory=/var/lib/asterisk/sounds/recording/beep
[recording-enabled]
mode=files
directory=/var/lib/asterisk/sounds/recording/beepbeep
How to get the SIP response code in Asterisk 10+
In early Asterisk 1.8 you used to be able to get the SIP response code by using a dialplan entry like :-
From asterisk version 10 there is now a new way to get the SIP cause however the way in which it is read is a bit convoluted. Contrary to the example given on the official Asterisk WIKI you cannot query it in the channel which performed the dial. It has to be queried by the channel which actually generated the SIP response.
You therefore have to do a few things :-
exten => _X.,n,Set(SIPcause=${MASTER_CHANNEL(HASH(SIP_CAUSE,${CDR(dstchannel)}))}The Asterisk developers discovered the way the information was being populated caused a significant performance hit and so decided to turn the feature off by default. It can be enabled by editing sip.conf and adding the following line
storesipcause=yes
From asterisk version 10 there is now a new way to get the SIP cause however the way in which it is read is a bit convoluted. Contrary to the example given on the official Asterisk WIKI you cannot query it in the channel which performed the dial. It has to be queried by the channel which actually generated the SIP response.
You therefore have to do a few things :-
- Add a hangup handler to the destination channel so that a dialplan routine is run when that channel hangs up.
- Use the new 'b' option to the Dial command which causes a dialplan routine to be called just before the dial happens and this is used to setup the hangup handler on the destination channel.
- In the hangup handler get a list of hangupcause strings which in most cases will be a single string which we can just use. If you simultaneously dialled two destinations you will have two strings however and will need to decide which to use.
- If the hangupcause string is blank then it probably just means the call was answered and was hungup normally so we can just return.
- Once we have the hangupcause to check read the SIP cause string.
- Now the problem of how to pass the variable back. Normal variable inheritance does not work properly because of the channel being hung up at this point so we use yet another new feature by setting a shared variable in the master channel.
- After the original dial we read the shared variable out of its own channel shared area and set a normal variable and then use the cut function to read the numerical value.
[dial_sip]
exten => _X.,1,Dial(SIP/${ddi}@${carrier},,b(dial_sip^set_handler^1))
exten => _X.,n,Set(SIPcause=${SHARED(SIPcause)}, Responsetime=$[${EPOCH}-${dialtime}])
exten => _X.,n,Set(SIPcode=${CUT(SIPcause," ",2)})
exten => set_handler,1,Set(CHANNEL(hangup_handler_push)=dial_sip,outbound_handler,1)
exten => set_handler,n,Return()
exten => outbound_handler,1,NoOp(Destination channel has hungup)
same => n,Set(HANGUPCAUSE_STRING=${HANGUPCAUSE_KEYS()})
; If no hangup causes are available then its probably because it is a regular call and the call ended normally so we just return.
same => n,ExecIf($["${HANGUPCAUSE_STRING}" = ""]?Return())
same => n,NoOp(Got Channel ID ${HANGUPCAUSE_STRING} master ${MASTERCHANNEL} with Technology Cause Code ${HANGUPCAUSE(${HANGUPCAUSE_STRING},tech)}, Asterisk Cause Code ${HANGUPCAUSE(${HANGUPCAUSE_STRING},ast)})
same => n,Set(SHARED(SIPcause,${MASTERCHANNEL})=${HANGUPCAUSE(${HANGUPCAUSE_STRING},tech)})
same => n,Return()
Subscribe to:
Posts (Atom)
