One of my Nexa switches is operated programmaticly from a computer via a tellstick. Whenever I want to control this device manually I will log in to the computer and issue the proper commands to operate the switch. However, not everybody finds this procedure acceptable so I needed a way to operate the switch both from the tellstick and from a Nexa remote.
First I reprogrammed the Nexa switch to accept the Nexa remote.
Then, by using the hard- and software described in decoding-new-nexa-protocol I could extract the ID code sent from the Nexa remote. This ID code could be directly entered into the "/etc/tellstick.conf" file and after a restart of the tellstick daemon the switch were operable by both the Nexa remote and the tellstick.
Friday, July 26, 2013
Tuesday, May 28, 2013
Using a MCE remote control with mythtv / xbmc
No lircd please.
After five years of mythtv 0.19 / xbmc (no udates of any kind during that time) and numerous restarts of lirc I got myself a new remote with an usb reciever, "MCE remote". A remote that shows up directly in the /dev/input directory of ubuntu 12.04. In addition to some standard buttons it also got a built in mouse. If one presses and holds down one of the numeric buttons it first emit a digit and then, after a while, emit a backspace and a character. E.g: Holding down "2" gives "2", delay, "<bs>A", delay, <bs>B, etc.
All very handy, but in the end I will probably use the reciever with my learning remote control wich also controls the amplifier and other stuff.
All very handy, but in the end I will probably use the reciever with my learning remote control wich also controls the amplifier and other stuff.
It was bought under the brand name "Fractal design", but as ubuntu concerns this is the important stuff:
(since ubuntu 12.04 lists this device in /dev/input/by-id it is easy to locate, otherwise one could plug/unplug and look in the /dev/input/ directory)
sudo udevadm info -a --name=/dev/input/by-id/usb-Cypress_Cypress_USB_Keyboard-event-mouse Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/pci0000:00/0000:00:02.0/usb3/3-1/3-1:1.0/input/input2/event2': KERNEL=="event2" SUBSYSTEM=="input" DRIVER=="" looking at parent device '/devices/pci0000:00/0000:00:02.0/usb3/3-1/3-1:1.0/input/input2': KERNELS=="input2" SUBSYSTEMS=="input" DRIVERS=="" ATTRS{name}=="Cypress Cypress USB Keyboard" ATTRS{phys}=="usb-0000:00:02.0-1/input0" ATTRS{uniq}=="" ATTRS{properties}=="0" looking at parent device '/devices/pci0000:00/0000:00:02.0/usb3/3-1/3-1:1.0': KERNELS=="3-1:1.0" SUBSYSTEMS=="usb" DRIVERS=="usbhid" ATTRS{bInterfaceClass}=="03" ATTRS{bInterfaceSubClass}=="01" ATTRS{bInterfaceProtocol}=="01" ATTRS{bNumEndpoints}=="01" ATTRS{supports_autosuspend}=="1" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceNumber}=="00" looking at parent device '/devices/pci0000:00/0000:00:02.0/usb3/3-1': KERNELS=="3-1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{devpath}=="1" ATTRS{idVendor}=="04b4" ATTRS{speed}=="1.5" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bMaxPacketSize0}=="8" ATTRS{busnum}=="3" ATTRS{devnum}=="2" ATTRS{configuration}=="" ATTRS{bMaxPower}==" 98mA" ATTRS{authorized}=="1" ATTRS{bmAttributes}=="a0" ATTRS{bNumConfigurations}=="1" ATTRS{maxchild}=="0" ATTRS{bcdDevice}=="0100" ATTRS{avoid_reset_quirk}=="0" ATTRS{quirks}=="0x0" ATTRS{version}==" 1.10" ATTRS{urbnum}=="12" ATTRS{manufacturer}=="Cypress" ATTRS{removable}=="unknown" ATTRS{idProduct}=="0100" ATTRS{bDeviceClass}=="00" ATTRS{product}=="Cypress USB Keyboard"
In order to remap the remote keys we have to write a keymaps file and run this when the usb reciever are plugged into the system. A great "howto" on this is in writing udev rules.
As shown by the '/dev/by-id' contents, the remote control is two units; the mouse part and the rest. The difference between these are the 'KERNEL==' attribute. Since one can use info from the device itself and one of the parent devices I used this rule:SUBSYSTEM=="input", KERNEL=="event*", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0100", RUN+="/bin/sh -c 'echo $name >> /tmp/test.udev"
SUBSYSTEM=="input", KERNEL=="event*", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0100", RUN+="keymap $name cypressusb"
This is the method I use to convince myself that the udev rules are hit. Just check the '/tmp/test.udev' for which devices that match the rule. '/lib/udev/keymap device keymapfile' (where 'keymapfile' is located in /lib/udev/keymaps/ updates the keymap of the device). To simulate adding devices use
sudo udevadm trigger
'ir-keytable' may be used to check the keycodes emitted from the remote:
#From ir-keytable -t -d /dev/input/by-id/usb-Cypress_Cypress_USB_Keyboard-event-mouse
#Pressing buttons from top left across to the right and down
700e0 KEY_LEFTCTRL (0x001d)
70015 KEY_R (0x0013)
c00b7 KEY_STOPCD (0x00a6)
700e2 KEY_LEFTALT (0x0038)
7003d KEY_F4 (0x003e)
**
700e0 KEY_LEFTCTRL (0x001d)
70005 KEY_LEFT (0x0069)
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70013 KEY_P (0x0019)
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70005 KEY_LEFT (0x0069)
**
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70005 KEY_LEFT (0x0069)
700e0 KEY_LEFTCTRL (0x001d)
70013 KEY_P (0x0019)
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70009 KEY_RIGHT (0x006a)
**
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70010 KEY_M (0x0032)
700e2 KEY_LEFTALT (0x0038)
700e3 KEY_LEFTMETA (0x007d)
70028 KEY_ENTER (0x001c)
700e0 KEY_LEFTCTRL (0x001d)
7000a KEY_G (0x0022)
**
70028 KEY_ENTER (0x001c)
7002a KEY_BACKSPACE (0x000e)
70050 KEY_LEFT
70052 KEY_UP
7004f KEY_RIGHT
70051 KEY_DOWN
then the mouse buttons
left mouse btn 90001 BTN_MOUSE (0x0110)
right mouse btn 90002 BTN_RIGHT (0x0111)
and joystick
and continuing...
RecTV
700e0 KEY_LEFTCTRL
70012 KEY_O
Vol+
70043 KEY_F10
Vol-
70042 KEY_F9
Ch/Pg+
7004b KEY_PAGEUP
Ch/Pg-
7004e KEY_PAGEDOWN
LiveTV
700e0 KEY_LEFTCTRL
70017 KEY_T
**
S1 c0223 KEY_HOMEPAGE
S2 c022a KEY_BOOKMARKS
mute 70041 KEY_F8
S3 c0224 KEY_BACK
S4 c0225 KEY_FORWARD
red 700e0 KEY_LEFTCTRL
700e1 KEY_LEFTSHIFT
70017 KEY_T
green 700e0 KEY_LEFTCTRL
70008 KEY_E
yellow 700e0 KEY_LEFTCTRL
7000c KEY_I
blue 700e0 KEY_LEFTCTRL
70010 KEY_M
the numeric keys, and finally...;
clear 7002a KEY_BACKSPACE (0x000e)
enter 70028 KEY_ENTER (0x001c)
The remote dublicates the keycodes sent from the "back" and "clear" buttons and also the "ok" and "enter" buttons.
Mythtv uses <ESC> as back key, but I don't want to reassign the 'back' key on the remote from backspace, it could be needed. Therefore the first iteration of the keymap would be to reassign left and right mouse button to OK and ESC.
/lib/udev/keymaps/cypressusb
0x90001 OK # left mouse btn -> OK
0x90002 ESC # right mouse btn -> ESC
Wednesday, January 16, 2013
Decoding the "new" NEXA protocol
Description of the NEXA protocol
![]() |
| One burst of data from a NEXA remote. |
The "new" NEXAprotocol are described here. Basically it is like this: The signal for start TX is a pulse (0.2 ms) followed by a delay of 2.7 ms. A pulse followed by a short delay (0.4 ms) reads as "0". A pulse followed by a longer delay (1.4 ms) reads as "1". The data are then combined into a 32 bit string by assigning "01" as '0' and "10" as '1'.
00000000001000000000000010010010
The sequence above were generated from a tellstick using "house=32770" and "unit=3".
The first 26 bits defines the ID of the remote as a binary number. If set, the 27th bit defines the command active for all recievers with the ID ( group command). The 28th bit are the command, '1' for "ON", '0' for "OFF". The last four bits are the unit code. For my NEXA remote control "unit 1" are "0000", "unit 2" are "0001" and "unit 3" are "0010". Every push on the remote generates a train of four pulse bursts, the tellstick generated five.
Decoding
![]() |
| It is noisy in the 433 MHz range and hard to get the first burst of data. |
An Atmega 328P available at hand were chosen to do the decoding. The 433 MHz RX data pin were connected to one of the PCINT22 interrupt pins, PD6. The 16 bit timer1 were used to time pulse widths and delays. Power to the 433 MHz RX unit were provided from PD5 (GND) and PD7 (5V). PC5 were used for debugging by outputting pulses to a logic analyzer. Data were outputted to a LCD screen using code from extremeelectronics.
The 328P were run at 8 MHz. A check for how slow it can run and still decode the data are left for later.
/*
* WirelessReader.c
*
* Sample signals from 433 MHz reciver and decode in a state machine.
*
* PCB: SousVide V.1
* Using Using port 11, 12 and 13 (PD5, PD6 and PD7) for 433 MHz RX, drawing ~4 mA
*
*
*
*
*
*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd.h"
#define T01 1
#define T10 0
// shortest and longest accepted pulsewidth
#define kMinPulseWidth 140
#define kMaxPulseWidth 300 //210
// Minimum time between two pulsetrains
#define kPulseTrainDelay 9700
// Minimum time between init pulse and data stream
#define kMinInitDelay 2200 //2600
#define kMaxInitDelay 2800
// Maximum time between two data pulses
#define kMaxDataDelay 1450 //1363
// A delay longer than reads as a '1'
#define kZeroDelay 687 //346
// The data arrives in pairs, '01' or '10', ministate
// keeps track of these pairs
// -1 undefined, waiting for '0' or '1'
// 0 '0' read, waiting for '1'
// 1 '1' read, waiting for '0'
volatile int8_t ministate = -1;
//#state
//# 0 - wait for 9.3 ms (kPulseTrainDelay) silence
//# 1 - wait for and measure init pulse width
//# 2 - measure init delay
//# 3 - check data pulse width and start measuring data delay
//# 4 - read data delay and determine '0', '1'. n time out store data
volatile uint8_t state = 0;
volatile uint32_t rawdata, data;
volatile uint8_t dataready;
//PD5, ground for 433 MHz RX
#define RX_GND_PIN PD5
#define RX_DTA_PIN PD6
#define RX_VCC_PIN PD7
int main(void)
{
// Set up interrupts
PCMSK2 |= (1<<PCINT22);
PCICR |= (1<<PCIE2);
// Set up timer, do not start it
TCCR1B |= (1 << WGM12); //CTC mode
TIMSK1 |= (1<<OCIE1A);
state = 0;
rawdata = 0;
data = 0;
dataready = 0;
// Set up 433MHz RX
DDRD |= (1 << RX_GND_PIN) | (1 << RX_VCC_PIN);
DDRD &= ~(1<<RX_DTA_PIN);
PORTD &= ~(1 << RX_GND_PIN); // set to 0V
PORTD |= (1 << RX_VCC_PIN); // set to 5V
// PORTD |= (1 << RX_DTA_PIN); // pullup
// For debugging
DDRC |= (1 << PC5);
//Initialize LCD module
LCDInit(LS_NONE);//(LS_BLINK|LS_ULINE);
LCDClear();
sei();
while(1)
{
if (dataready==1)
{
cli();
char buff[8];
uint8_t tmp = data &0x000000FF;
sprintf(buff,"%04X", (data>>(16+6))&0x0000FFFF);
LCDWriteStringXY(0,0,buff);
sprintf(buff,"%04X", (data>>6)&0xFFFF);
LCDWriteStringXY(4,0,buff);
if (tmp & 0x10)
{
LCDWriteStringXY(0,1,"ON");
}
else
{
LCDWriteStringXY(0,1,"OFF");
}
// LCDWriteStringXY(4,1,"U ");
// LCDWriteIntXY(6,1,(tmp&0x0f),3);
if ((tmp & 0x0F) == 0x00) LCDWriteStringXY(4,1,"U 1");
if ((tmp & 0x0F) == 0x01) LCDWriteStringXY(4,1,"U 2");
if ((tmp & 0x0F) == 0x02) LCDWriteStringXY(4,1,"U 3");
if (tmp & 0x20) LCDWriteStringXY(4,1,"Grp");
sei();
for (int ii=0;ii<100;ii++)
{
_delay_ms(30);
}
dataready = 0;
cli();
LCDClear();
sei();
}
}
}
//reset state to initial
void inline resetstate()
{
unsigned char sreg;
state=0;
ministate=-1;
data = 0;
rawdata = 0;
TCCR1B &= ~(1 << CS11); //stop timer 1
sreg = SREG; // save global interrupt flag
cli();
TCNT1 = 0;
SREG = sreg; // restore interrrupt flag
}
// start timer
void inline starttimer(int v)
{
unsigned char sreg;
sreg = SREG; // save global interrupt flag
cli();
TCNT1 = 0;
OCR1A = v;
SREG = sreg; // restore interrrupt flag
TCCR1B |= (1 << CS11); //prescale 8
}
// This interrupt is called when the 433 MHz RX pin changes state
ISR(PCINT2_vect)
{
char transition;
// determine the state change direction, 0->1 or 1->0
if (PIND & (1<<PIND6))transition = T01;
else transition = T10;
//state 0: should time out, we need 9.3 ms silence, otherwise try again
if (state == 0)
{
starttimer(kPulseTrainDelay-100);
return;
}
// state 1: we had a 9.3 ms delay, now we are recieving the init pulse
// start the pulsewidth timer
if ((state==1) && (transition == T01))
{
starttimer(kMaxPulseWidth);
return;
}
if ((state==1) && (transition == T10))
{
if (TCNT1<kMinPulseWidth)
{
resetstate();
return;
}
else // pulse OK, too long and it will time out in the timer part
{
state = 2;
starttimer(kMaxInitDelay);
return;
}
}
// state 2: measure the init delay
if (state == 2)// && (transition == T01))
{
if (transition == T10)
{
resetstate();
return;
}
if (TCNT1<kMinInitDelay) // to short
{
resetstate();
return;
}
else // delay OK, too long and it times out
{
starttimer(kMaxPulseWidth);
rawdata = 0;
state = 3;
return;
}
}
//state 3: check pulsewidth in data transmission
if ((state == 3))// && (transition==T10))
{
if (TCNT1<kMinPulseWidth)
{
resetstate();
return;
}
else // pulse OK, too long and it will time out from the timer
{
starttimer(kMaxDataDelay);
state = 4;
return;
}
}
//state 4: read data, '0' or '1'
if (state == 4)
{
int t = TCNT1;
//observing 1310 or 320
if (t > kZeroDelay) // we read '1'
{
if (ministate==1) // error, two '1' in a row
{
resetstate();
return();
}
else if (ministate==-1) // OK, next bit should be '0'
{
ministate = 1;
}
else if (ministate==0) // OK, bit pair completed
{
ministate = -1;
rawdata = (rawdata<<1);
// no need to add '0'
}
}
else // we read '0'
{
if (ministate==0) // error, two '0' in a row
{
resetstate();
return();
}
else if (ministate==-1) // OK, next bit should be '1'
{
ministate = 0;
}
else if (ministate==1) // OK, bit pair completed
{
ministate = -1;
rawdata = (rawdata<<1);
rawdata +=1;
}
}
state = 3;
starttimer(kMaxPulseWidth);
return;
}
}
ISR(TIMER1_COMPA_vect)
{
if (state==0)
{
state = 1;
TCCR1B &= ~(1 << CS11); //stop the timer
return;
}
// pulsewidth/delay were to long
if ((state == 1) || (state == 2) || (state == 3))
{
PORTC = 0b00100000;
PORTC = 0b00000000;
_delay_us(5);
PORTC = 0b00100000;
PORTC = 0b00000000;
resetstate();
return;
}
// end of data burst, wait for next burst
if (state==4)
{
data = rawdata;
rawdata = 0;
dataready=1;
starttimer(kPulseTrainDelay>>1);
state = 0;
}
}
This extracts the data in the pulsetrain, but it does not do any accumulation of the data in the pulse trains. Usaully there are at least four bursts that contains the same data.
Monday, December 17, 2012
A state machine for decoding 433 MHz signals
- 0 - Wait for signal. In this state we have not seen any signals yet.
- 1 - Peak detected. We want to determine if this is a valid peak for us.
- 2 - Delay detected. Here we want to determine if the delay is valid. It should not be to short, not to long and it could also be a "0" or a "1". If we have recieved all our expected bits we should store the packet and look for more packets.
Instead of hacking with some microcontroller, that eventually will do this decoding, I wrote up a python program to do this offline. Files from the logic analyser running at 1 MHz sampling rate are sendt through the python program. The program calls a function everytime the input changes, simulating a interrupt pin on a MCU. It also increases a count for each entry in the file, simulating a 1MHz timer.
This python program works as expected, at least as long as the signal quality is good.
#return the "port" state, 1 if transmission otherwise 0
def readport(line):
return int(line.split('\t')[1])
# a pulse is ca 387
# init ca 9617
# 1 is ca 4600
# 0 is ca 2060
#state
# 0 - wait for pulse
# 1 - make sure the pulse is of correct length, 200 to 500
# 2 - measure delay, "init", "0","1" or "illegal" delay
# simulate interrupt due to pin state change
def statechange():
global state, counter, res, timer
if nextportstate == 1: # we are going from 0 -> 1
transition = 1
else:
transition = 2 #from 1 -> 0
#print debugtime, state, res
if state == 0 and transition == 1: # possible transmission/pulse detected
state = 1
timer = 500 #time out after 500
counter = 0 # reset timer
return
if state == 0 and transition == 2: # disregard
state = 0
timer = 0
counter = 0
return
if state == 1: #(and transition == 2):
if transition ==1 or counter < 200: #200
#print "counter " , counter
#print "ERROR in state==1"
state = 0
timer = 0
counter = 0 # reset timer
else: # we detected a legal pulse, determine delay length
# 0 < delay 1500 illegal, goto state 0
# 1500 < delay < 2500 legal, "0"
# 2500 < delay <5000 legal "1"
# 5000 < delay < 8000 illegal, goto state 0
# 9000 < delay 11000 legal, init delay
# 11000 < delay illegal, state 0
state = 2
timer = 10000
counter = 0 # reset timer
return
if state == 2: #(and transition == 1)
if transition == 2: #and counter < 8000:
print "ERROR in state==2"
state = 0
timer = 0
counter = 0
else: #legal init delay
#print "counter state==2 ",counter
if counter > 9000: # init pulse, reset data
print "RES", res
res = ''
state = 1
timer = 500
counter = 0
elif counter > 4000: #got a "1"
res = res + "1"
#print res
state = 1
timer = 500
counter = 0
elif counter > 1700: #got a "0"
res = res + "0"
#print res
state = 1
timer = 500
counter = 0
else: # illegal, to short
res = ""
state = 0
timer = 0
counter = 0
if len(res) == 28:
print "RES", res
res = ''
state = 0
timer = 0
counter = 0
return
#simulate interrupt due to timer
#if something times out it is du to a to long pulse or delay
# we will return to state==0
def timerint():
global state, counter, timer
state = 0
timer = 0
counter = 0
#fp = open("untitled.tsv", "r") #noisy data
fp = open("untitled13.tsv", "r")
data = fp.readlines()
fp.close()
# timer
# 0 do not time out
#
timer = 0
print "file read"
transition = 0
# 0 no change
# 1 low to high
# 2 high to low
counter = 0 # simulate an interrupt counting
portstate = 0
nextportstate = 0
debugtime = -1
res = "XXX"
timer = 0
state = 0
for l in data:
#print debugtime, state, counter,timer
if timer > 0:
if counter>= timer:
timerint()
#counter = 0
counter = counter + 1
debugtime = debugtime + 1
#print debugtime, portstate
if portstate != nextportstate:
callint = 1
else:
callint = 0
portstate = nextportstate
nextportstate = readport(l)
if callint==1:
statechange()
#res 0100010100011111100100110100
# 0100010100011111100100110100
This python program works as expected, at least as long as the signal quality is good.
Making the signal weaker tend to split the peaks into several, shorter peaks, sending the routine back to state "0" without recording any transmission. It is not clear if this should be adressed.
Only a real test on an MCU could provide that answer.
Tuesday, December 11, 2012
Replacing toner in my Brother HL-2030
During the weekend the toner lamp in my laser printer turned on.
Checking the largest online suppliers here in Sweden, I noticed that they wanted almost as much for a 2500 pages toner cartridge as I had paid for the laser printer itself.
This situation reminded me somewhat of the situation with ink jet printers, they are sold cheap or given away with computer purchases. The trick being that the ink in the printer are almost empty already, forcing their unsuspecting customers to a buy expensive ink almost immediately.
Probably a wise thing to do as well, I have never considered the ink/toner level in a printer when I considered buying it.
According to Brother the HL-2030 came with a 1500 page toner supply. There exists a standard, ISO/IEC-19752 that defines a standard page. I can not complain, pressing the "Go" button on the printer three times produced a page telling me that I had printed out 1594 pages.
After some "googling" I found a company, nordicink.se, that promised to deliver a toner cartridge for approximately one-third of the price of the original toner cartridge sold by my regular office material suppliers.
I ordered the cartridge on a Saturday, the following Monday I received an SMS telling me that it were in the postal system and today, Tuesday it were in my mailbox. Not bad. The replacement instructions were understandable and the first pages printed looks completely as expected. Now all that remains to discover are when the toner lamp turn on again.
Checking the largest online suppliers here in Sweden, I noticed that they wanted almost as much for a 2500 pages toner cartridge as I had paid for the laser printer itself.
This situation reminded me somewhat of the situation with ink jet printers, they are sold cheap or given away with computer purchases. The trick being that the ink in the printer are almost empty already, forcing their unsuspecting customers to a buy expensive ink almost immediately.
Probably a wise thing to do as well, I have never considered the ink/toner level in a printer when I considered buying it.
According to Brother the HL-2030 came with a 1500 page toner supply. There exists a standard, ISO/IEC-19752 that defines a standard page. I can not complain, pressing the "Go" button on the printer three times produced a page telling me that I had printed out 1594 pages.
After some "googling" I found a company, nordicink.se, that promised to deliver a toner cartridge for approximately one-third of the price of the original toner cartridge sold by my regular office material suppliers.
I ordered the cartridge on a Saturday, the following Monday I received an SMS telling me that it were in the postal system and today, Tuesday it were in my mailbox. Not bad. The replacement instructions were understandable and the first pages printed looks completely as expected. Now all that remains to discover are when the toner lamp turn on again.
Saturday, December 8, 2012
Writing data to the Denver TRC-1480
One useful aspect of knowing the protocol used by a wireless thermometer would be to add own sensors. The Denver TRC-1480 have three available channels where one could display custom data. It is also possible to buy additional sensors from Denver.
By sending a temperature packet identical to a packet the Denver sensor could have sent one may check how sensitive the Denver decoder are to timing issues.
The test revealed that the decoder only scans for data a few seconds each time it expects a transmission, but once this were addressed the Denver decoder were not very picky about the timing and bits sent.
Sending "01111" as bits 32 - 36 always displayed the intended temperature so the purpose of these bits are somewhat unclear.
Thursday, December 6, 2012
Observing the 433MHz band
I recently "stumbled" over a 433 MHz transmitter-receiver set from iteadstudio. Hooking the receiver up to my logic analyzer I could observe three different signals that appeared regularly, 30 - 60 seconds,
Signal 1 were repeated 12 times in a burst and signal 3 were repeated a little bit more than 8 times, leaving the ninth repetition partially complete.
Signal 1 were easy to identify, it disappeared when I stopped my wireless thermometer...
All pulses are of the same length, 0.55 ms with different delays in between. Each packet starts with a pulse and a 4.4 ms delay. Each "1" is a pulse with a 2.45 ms delay and a "0" is a pulse with a 1.45 ms delay.
By varying different parameters the following information were revealed:
![]() |
| Signal 1 |
![]() |
| Signal 2 |
![]() |
| Signal 3 |
Signal 1 were repeated 12 times in a burst and signal 3 were repeated a little bit more than 8 times, leaving the ninth repetition partially complete.
Signal 1 were easy to identify, it disappeared when I stopped my wireless thermometer...
Signal 1, decoding the Denver TRC-1480
The Denver TRC-1480 have the possibility to read from three different temperature sensors.All pulses are of the same length, 0.55 ms with different delays in between. Each packet starts with a pulse and a 4.4 ms delay. Each "1" is a pulse with a 2.45 ms delay and a "0" is a pulse with a 1.45 ms delay.
By varying different parameters the following information were revealed:
bit 1 - 8 sensor IDbit 9 0 indicates low batterybit 10 always 0bit 11 - 12 channel-1bit 13 - 24 temperature * 10 as two's complement (invert all bits, add 1 and negate for numbers starting with "11".bit 25 - 28 always 1bit 29 - 31 always 0bit 32 - 36 some sort of checksum?
![]() |
| Some readings from channel 3 |
In addition channel 1 sends at 57 seconds interval, channel 2 at 67 seconds and channel 3 at 80 seconds.Signal 2, unknown origin
Transmits every 48 seconds. Consists of 0.5 ms "short" pulses and 1.5 ms "long pulses. A short pulse indicates a "0" and a long pulse a "1". The transmission starts with eight "0". The signal are sometimes very weak.
Bit 17 to 24 may be correlated to the outside temperature by subtracting 234 and dividing by 10. There have to be more to this since the temperature reading with those eight bits are limited to -23.4 to 2.1C. [EDIT:] Or the temperature may be stored as two's complement as well.[]
I do not yet know the brand of this thermometer.
Signal 3, unknown origin
Transmits every 36 seconds. Consists of 0.4 ms pulses with either 4.6 ms ("1") or 2.4 ms ("0") delays. Each signal frame starts with a pulse followed by a 9.6 ms. delay.
Bits 17 to 24 correlates to the temperature by subtracting 238 and dividing by 10.
[EDIT:] Or the temperature may be stored as two's complement as well.[]
As with signal 2, clearly more data are needed to assign the different bits.
[EDIT:] Or the temperature may be stored as two's complement as well.[]
As with signal 2, clearly more data are needed to assign the different bits.
Sources used
A description of some Lacrosse sensors, Jean-Paul ROUBELAT - F6FBB @ http://www.f6fbb.org
A very informative series from spook @ http://lucsmall.com regarding Fine Offset Electronics instruments.
An eye opener from bertrik.
More important things yet to be followed up
Subscribe to:
Posts (Atom)










