Raspberry Pi reading WH1081 weather sensors using an RFM01 and RFM12b

This article describes using an RFM01 or RFM12b FSK RF transceiver with a Raspberry Pi to receive sensor data from a Fine Offset WH1080 or WH1081 (specifically a Maplin N96GY) weather station’s RF transmitter.

I originally used the RFM12b, simply because I had one to hand, but later found that the RFM01 appears to work far better – the noise immunity and the range of the RFM01 in OOK mode is noticeably better.  They’re pin compatible, but the SPI registers differ between the modules, in terms of both register-address and function.

This project is changing to be microcontroller based, and using an AM receiver module (Aurel RX-4MM5) – a much more effective approach – arduino-yun-reading-wh1080-using-aurel-rx-4mm5. Currently testing on Arduino Yun, but will probably move to a more platform agnostic design to support Dragino and Carambola etc.

The weather station comprises an LCD display and a mast of sensors. The LCD display also incorporates temperature and humidity sensors for indoor readings, as well as a barometric pressure sensor. The mast contains sensors for temperature, humidity, wind-speed, wind-direction, and rainfall, and transmits data-packets using a 433MHz transmitter. It’s the data from the mast that this project is focused on, along with the addition of a Bosch BMP085 I2C module to get barometric pressure.

There are variants of the Fine Offset WH1080 with transmitters of differing types (e.g. different frequency, modulation, or both), so while this project will apply in principle to similar devices with different branding, in practice some tweaking may be required.

For anyone who already has a rough idea of what’s required, and just wants a quick overview for some pointers, I’ve presented a summary first below.

Wiring the Module

Note: the revision 2 boards affect this project in two ways. First, if you’re using the BMP085 pressure sensor, then you’ll need to address I2C-1 rather than I2c-0. Changing the base address of the I2C peripheral in the code should be all that’s required. Second, the GPIO pin on header P1-13 is now GPIO27 rather than GPIO21. Again, the code will need simple modifications. I’ll incorporate these into the code in future, but until then you’ll have to figure out where the changes go if you want to build this on Rev-2. Email me if you need help.

Pin connections from the RFM01 (and RFM12B) to the Raspberry Pi are as follows. You may choose to add current limiting resistors. Pull ups may be required for SDO and SDI (I’ve never found a definitive specification for SPI – it works with them, and it probably works without them too): -

SDO -> MISO  (PU resistor?)
SDI -> MOSI  (PU resistor?)
SCK -> SCLK
SEL -> CE0_N

FSK/DATA/nFFS -> GPIO21 (P1-13)

ANT -> 17.3cm wire
VDD -> 3V3 from Pi
GND -> GND on Pi

Optionally, you may want to drive nRES from a GPIO output
(I used 'nRES -> GPIO22' in the code, though this will
probably be removed after I finish experimenting).

I used a breadboard to wire this up, and unsurprisingly found this to be far from ideal with the RFM12b module. At close range, the receiver works very reliably, but as the signal weakens, noise often drowns it out (even just leaning close to the circuit, or moving a component).

A breadboard is fine to test the SPI stuff, and also works well when the transmitter is in close range, but to test the receiver properly, etching a PCB (or even just wiring the bits together) would be a better idea.

Wired in the noisy breadboard

I decided to wire the RFM12b to a 26-pin female header to avoid breadboard noise, but discovered that the Pi was generating enough of noise of its own, and having the module (more accurately, the antenna) so close to the Pi was affecting reception. A long ribbon cable improved things, as did a length of coax to move the antenna away from the rest of the electronics.

When I switched in the RFM01 (after carelessly frying my RFM12b), the situation seemed much better, and the device worked more reliably than the RFM12b did in exactly the same environment.

How it looks before adding the BMP085 barometer module

The RFM01 seems far more immune to noise -it’s wired to a 26-pin header and plugged directly onto the Pi. The antenna is simply a 1/4 wavelength (17.5cm) wire soldered to the module. It receives perfectly even in this harsh environment, possibly in part because it works on the lowest LNA (Low Noise Amplifier) settings.

Any wires near the Pi are capable of generating RF noise, even just a breadboard jumper wire sitting underneath the Pi, or an unshielded Ethernet cable. Be aware of this and keep noise sources out of the way while testing (or wire the antenna on a length of 50Ω coax).

Just connect SDA and SCL along with 3V3 and GND for the BMP085

Received Data

The transmitter sends 11 bytes of data as follows. Some of these differ from any of the documentation I’ve found on Fine Offset weather stations, so I’ve described them here (letters to the nibbles for the description below): -

Byte     0  1  2  3  4  5  6  7  8  9
Nibble  ab cd ef gh ij kl mn op qr st
Example a1 82 0e 5d 02 04 00 4e 06 86

I’ve interpreted the nibbles as follows: -

  • abc: device identifier
  • def: temperature
  • gh: humidity
  • ij: average wind speed low byte
  • kl: gust wind speed low byte
  • m: unknown
  • n: rainfall counter high nibble
  • op: rainfall counter
  • q: battery-low indicator
  • r: wind direction
  • st: checksum

The nibble ‘q’ is likely to be the low-battery indicator, thanks to Ken McCullagh reporting that his transmitter is now sending a ’1′ rather than a ’0′, and his LCD display is also now showing a low-battery symbol.

Nibble ‘m’ is unknown. It may be that the rainfall counter is two whole bytes (time will tell – I may take a watering can to the rain collector), or perhaps it’s the high nibble of either the wind-speed or gust-speed. Between them, nibbles ‘m’ and ‘q’ could provide this extra wind data.

To get temperature, subtract 400 (0×190) and divide the decimal by 10. For example, reading 0x2oe – 0×190 = 0x7e, which is 126. This represents 12.6 degrees C.

To get a wind speed values (in m/s), multiply the value by 0.34 and round the result to one decimal place. So, value 0×04 is round(4 * 0.34) = 1.4 m/s.

For rainfall, as documented elsewhere, multiply by 0.3 to get the recorded rainfall in millimetres. This value is a counter that increments to zero after 0xff (or 0xfff if it turns out that nibble ‘q’ is part of the counter).

Humidity is simply displayed as a decimal, and wind direction ranges from 0 to 15 for N, NNE, NE, ENE, E, etc., as per the LCD display. The checksum is CRC8, and a nicely written function, adapted from the OneWire Arduino Library by Luc Small, is included in the source code to calculate this checksum.

The Code

You can download the source code from here. Unpack the tarball on the Pi, cd into the created directory, and run ‘make’. This should generate the ‘wh1080_rf’ executable.

If you’re using a cross compiler, the you may need to edit the CC variable in ‘Makefile’ to point to your compiler. If you’re using an RFM12b, then edit file ‘rfm01.h’ and change  ‘#define RFM01′ to ‘#define RFM12B’.

The program configures the RFM01 using SPI, and then continuously looks for interesting data from the module on the Pi’s GPIO pin, and dumping valid packets to stdout as hex strings. It also decodes the hex-data into more meaningful values, and sends them to stdout as printf() formatted strings.

Note that the calculations on the Raspberry Pi are done using floating-point arithmetic, whereas the WH1080 uses fixed-point. This means that the output may differ slightly between the Pi and the LCD display, because the Pi’s calculations are more accurate. For example, raw wind speed of 0×01 yields 0.34m/s on the Pi, but only 0.3m/s on the WH1080. Converting this to mph yields 0.8 mph on the Pi, and 0.7 mph on the WH1080. Therefore the Raspberry Pi reading is more accurate.

You may notice that the output below also displays barometric pressure and an indoor temperature value. These have come from a Bosch BST-BMP085 Barometric Pressure Sensor via I2C. Wiring the module to the Pi was trivial, since it has the pull-up resistors and bypass capacitors already on-board. Therefore, simply wiring SDA and SCL, along with 3V3 and GND, to the Pi is enough to get this sensor working. If you don’t plan to use one of these, remove the line ‘#define USE_BMP085′ in wh1080_rf.h before compiling.

Only SDA/SCL and 3V3/GND, The other two needn’t be connected.

The output from the software includes a scan of RSSI duty on all amplification levels, RSSI thresholds, and baseband bandwidths. This lets you see where the noise is in your environment so that you can spot likely configuration values that will yield reliable results. I’ve omitted this from the example below for clarity.

root@pi:~/wh1080_rf# make
gcc -c -Wall wh1080_rf.c
gcc -c -Wall bcm2835.c
gcc wh1080_rf.o bcm2835.o -o wh1080_rf
root@pi:~/wh1080_rf# ./wh1080_rf

Initialising RFM01
SPI: mode 0, 8-bit, 1000 KHz
RSSI Duty 0.00

Listening for transmission
Data bits = 88   (offset 8) (0 short)
Frequency deviation 0.0KHz (0)
a1 82 0d 5a 03 06 00 4e 08 d3 crc ok (gap 48s)
Pulse stats: Hi: 478 - 658   Lo: 1441 - 1687  (88 point)
Threshold now 1049
Temperature: 23.3C
Pressure p0 (sea level): 1006.6 hPa
Station Id: 0A18
Temperature: 12.5C, Humidity: 90%
Wind speed: 1.0 m/s, Gust Speed 2.0 m/s, S
Wind speed: 2.3 mph, Gust Speed 4.6 mph, S
Total rain: 23.4 mm

Listening for transmission
Data bits = 88   (offset 8) (0 short)
Frequency deviation -1.0KHz (-1)
a1 82 0d 59 02 05 00 4e 0a 07 crc ok (gap 48s)
Pulse stats: Hi: 491 - 721   Lo: 1531 - 1720  (88 point)
Threshold now 1126
Temperature: 23.2C
Pressure p0 (sea level): 1006.8 hPa
Station Id: 0A18
Temperature: 12.5C, Humidity: 89%
Wind speed: 0.7 m/s, Gust Speed 1.7 m/s, SW
Wind speed: 1.5 mph, Gust Speed 3.8 mph, SW
Total rain: 23.4 mm

The data-bits are the number of bits seen in this packet, including preamble, and the offset is the position of the device-id byte (or zero if it wasn’t found). The short packet count gives an indication of how much noise is being seen as data.

The ‘gap’ value tells us how long it’s been since we’ve seen a valid packet, and the stats show the pulse widths (in microseconds) that the receiver’s demodulator sent to us. The frequency deviation shows the values of the AFC offset registers. The AFC is manually strobed on each successful packet, in order to slew the frequency offsets with frequency drift.

Prior to a reading, the code switches the process to the Kernel’s built-in realtime (SCHED_RR) scheduler policy so as not to miss any bit transitions on the GPIO pin, and this is enough to make the process immune even to heavy workloads. I’ve tried running multiple CPU and IO intensive processes while reading, and didn’t see any packet loss. This may not hold true over time but, if not, there are sysctl parameters for the scheduler that can be altered to improve latency, for example: -

root@pi:~# sysctl kernel.sched_wakeup_granularity_ns=50000

In any case, it should be possible to run weather software and perhaps a web server on the Pi at the same time, while reliably taking RF sensor readings. I haven’t got that far yet.

Note that the transmitter actually sends two packets in succession on every other transmit cycle. It sends a packet, and repeats it 100ms later. I presume this is to increase receive reliability on the LCD display, or perhaps their receiving circuit sometimes fails to set AGC appropriately with a single packet. The code will ignore any subsequent data after receiving a valid packet until the next 48 second gap elapses.

Tuning the RFM01 Settings

The RFM01 configuration will depend on your environment. The following lines of code are most relevant: -

uint16_t cmd_config    = CMD_CONFIG|BAND_433|LOAD_CAP_12C0|BW_67;
int16_t cmd_rcon = (CMD_RCON|RX_EN|VDI_DRSSI|LNA_MEDIUM|RSSI_97);

The CMD_CONFIG (the module settings) command includes the receiver bandwidth setting. This can be one of BW_67, BW_134, and BW_200, BW_270, BW_340, and BW_400, and the value determines how sensitive the receiver is, but wider bandwidths mean more susceptibility to noise.

The CMD_RCON (receiver settings) command sets the Low Noise Amplifier setting (LNA_LOW, LNA_MEDIUM, LNA_HIGH, and LNA_MAX), and the RSSI threshold (dBm) at which we consider a signal to be valid. The VDI setting follows RSSI in the above example, because I’m not sure how relevant the other settings are to an OOK signal.

If you launch the program with any parameter, it will enter RSSI mode, which continuously samples DRSSI with the current settings, and reports the duty (percent) of the DRSSI signal from the SPI status register. You can use this to figure out the best combination of settings for your setup.

I find that the lowest total-gain/bandwidth combination that reports a small amount of noise (e.g. < 5%), or that reports zero-noise close to that boundary, gives the best results. If you’re settings are too sensitive, you’ll lose signal strength in the noise. If they’re not sensitive enough, you won’t maximise your potential reception.

For weaker signals/longer ranges, you may have to allow for variations in the environment – heavy rain can affect reception, outside temperature variations will affect the transmitter to some degree.

If the transmitter is close enough to the receiver, most settings that don’t saturate the receiver with noise will work fine, particularly with an RFM01 module.

Oscilloscope and Logic Traces

The output from the transmitter looks like this in my logic analyser: -

Pulses generated at the transmitter.

This is the signal that comes from the the transmitter’s microcontroller to the RF part of the circuit, and is the modulation of the 433MHz carrier. I think this modulation is called RZI PWM (Return to Zero Inverted, Pulse Width Modulation), RZI because the fixed clock-pulse always returns to ‘not-zero’, and PWM because pulse width defines the data bits.

The narrow pulses are binary-one, the wide pulses are binary-zero, and these are interspersed with 1ms clock pulses. The first eight narrow pulses are the 0xff preamble, and the next eight pulses represent the first data byte (always 0xa1, the device id).

When it gets to the DATA pin on the RFM01 receiver, the signal looks something like this:-

Pulses seen from the RFM01 DATA pin

Note that it can now be seen as RTZ PWM (Return To Zero, Pulse Width Modulation) because the clock-pulse is now inverted (i.e. at zero) and the data pulses are at 3V3. Again, it’s the pulse-width that determines the data (and hence why this isn’t actually an OOK signal, and why the RF modules are being used out of specification).

This oscilloscope output is what our software is sampling via the GPIO pin. It samples hi-low transitions, recorded as pulse-width in microseconds, into a buffer that gets filled until a gap of 5ms is seen (or 500 points maximum, in which case we’re very unlikely to have valid data).

The software could be far more efficient and elegant – there’s really no need for a buffer to scan into, as it can all be done in realtime as it arrives. However capture-and-process is easier to experiment with and study, particularly when you have to wait 48 seconds for the next wave of bits.

Other Notes

You can play with the internal pull-up and pull-down resistors on GPIO pins using Gordon Henderson’s GPIO Utility. I have a compiled binary of this here (link) – make sure it’s executable (‘chmod a+x gpio’), and copy it to ‘/usr/local/bin/’.

However, by most accounts no pull-ups should be needed in this project, and any that are can be provided by the internal weak resistors already on the GPIO lines. If I used them in my wiring, it’s only because it was easier to pop one in the breadboard than it would have been to write code to configure them (before I found Gordon’s utility).

The RFM01 is accessed using the SPI kernel driver. Therefore the modules spi_bcm2708 and spidev should be loaded. If not, then you’ll get the error “can’t open device”.  To load them, run ‘modprobe spi_bcm2708′ and then ‘modprobe spidev’ – use sudo if you’re not root.

The RSSI will vary by environment – even the location of the Pi, and the antenna’s orientation to the Pi can make a noticeable difference with a weak signal and high-gain/low RSSI threshold parameters.

In the output of the software line with ‘Short’ in it means “short packets seen” – there should be zero in a quiet environment, but one or two are quite possible. If you’re getting lots of short packets reported, then you’re probably picking up noise, because your receiver configuration is too sensitive.

The code has a few lines specifically for the configuration of the receiver – the LNA and RSSI threshold values, and also the bandwidth values are the most important ones.

The table of data that shows on startup shows the noise sampled for each combination of these values. The columns, though they’re not labelled, are noise for the different  bandwidth settings of the RFM01 (e.g. how far above & below the centre frequency the receiver should listen for a signal).

You need to look at the table and pick some settings that have zero noise, but are close to settings that do have noise (e.g. we’re looking for a setting that’s sensitive enough to hear the signal, but not so sensitive that any background RF is picked up as data.

Next Steps

There are a number of things I want to do in this project: -

  • Integrate the decoded values into some open source weather software so that it’s usable from the Internet (probably wview).
  • Rewrite the code to improve the structure and make it more readable (the current version was only a tool for experimentation).
  • Add some heuristics to the software for auto-tuning of receiver parameters.

References

RFM01 Datasheet – from the HopeRF site. The title is ‘RFM01 Universal ISM Band FSK Receiver’ should you need to search for it because of a broken link.

Raspberry Pi Low Level Peripherals – wiki page describing the pin-headers and attached peripherals.

JeeLabs – Receiving OOK/ASK with a modified RFM12B – a detailed article on getting OOK signals out of an RFM12B.

JeeLabs RFM12B Command Calculator – a useful client-side browser application to calculate register settings using form inputs and selections. Only a few apply to the RFM01 (e.g. frequency, AFC, and data-rate).

Strobotics RFM12 Tutorials – a good, though micro-controller centric, description of the RFM12B. Much of the information also relates, broadly at least, to the RFM01.

Luc Small – Hacking the WH2 Wireless Weather Station Outdoor Sensor – this station seems to use a similar RF modulation and packet format (albeit a subset) of the Maplin WH1081 variant.

WH1080 EEPROM Data Definition – document detailing the memory organisation of the LCD display unit. This differs to some extent from that of the Maplin device, but there are enough clues in it to make it useful.

Raspberry Pi Forum Thread – discussion on this topic, includes information on hardware variations that others have tried with varying levels of success.

Links

Original source code on GitHub – https://github.com/Kevin-Sangeelee/wh1080_rf

pywws support added by Ken McCullagh – https://github.com/kenmcc/wh1080listener

Weather Underground support added by Andy Ayre – https://github.com/ajayre/WH1080-Weather-Underground – also includes changes for Rev 2 Pi, I think.

Some information from SevenWatt on FSK versions of the Fine Offset weather stations – http://www.sevenwatt.com/main/wh1080-protocol-v2-fsk/

 

112 thoughts on “Raspberry Pi reading WH1081 weather sensors using an RFM01 and RFM12b

  1. Hi Kevin
    I’m a retired production sound mixer and I have a ‘retirement project’ in France.
    Sounds far grander than it really is. Lots of remedial work to be done, and I mean lots!
    What I’d like to do is do some research on wind amounts and speeds with a view of going installing a wind turbine and generating my own electricity.
    I need to make sure I’ve got enough wind over a period of time, and will give me an indication of what power I can hopefully get.
    I did electronics earlier in my career but I am rather rusty now, but I can still solder!
    The Raspberry Pi answers my questions as to how to read the weather information back here in the UK from France. I’m right at the end of the telephone line, and am just within reach of broadband – just- 512K and no more. I jut need a way of ‘seeing’ the data without spending a fortune on a weather station with internet capability.
    So the Maplin £59.99 offering looked just the ticket so I bought one and so far it looks perfectly good for my ‘project’.
    I have a couple of questions if you don’t mind.
    Simple one first, where did you get your 26 way female header? I’ve looked on Farnell’s site, where I’ll get the RFM01 but can’t see any at a ‘sensible’ price.
    Do you have a schematic of the connections from the RFM01 to the GUIO pins?
    i.e. which connection goes where.
    I’ve set up the Raspberry Pi with Tightvncsever and will be looking at Apache as well.
    If you can help I’d be very grateful as my electronics is very rusty and somewhat out of date! I’m learning Linux which coming from a Mac orientated background isn’t too difficult. Code writing is NOT my strong point though!
    Many thanks in advance,
    Ian

    1. Hi Ian,

      The 26-way female header I think came from Tandy (http://www.tandyonline.co.uk/) £0.69 each. The RFM01 came from Maplin at £3.99.

      I didn’t draw a schematic because it’s little more than wiring to the SPI pins (and I2C if a pressure transducer is included), but you should be able to sketch it out easily enough from the pin mappings in the post. I may do a schematic in the future (mainly because I want to CNC mill a PCB), but I can’t say when.

      I’d be happy to verify your schematic if you choose do draw your own.

      Kevin

    2. Hi Ian,

      Check out some of the RPi forums – you maye be better using PuTTY for remote login as it is far less resource hungry – it is of course just command line driven though!

      Even though mine is hooked up to my network, it runs completely headless (no keyboard, mouse, screeen . just power supply, usb input, and ethernet, then accessed via PuTTY from my main pc.

      Hope that helps.

  2. Kevin,

    Many thanks for the tutorial, I’m looking to copy waht you’ve done for some remote weather station monitoring as the USB interface is just not reliable enough.

    Big news – Didn’t know that Tandy had come back! Always spent too much in their shops, have since been using Maplin and CPC / Farnell / Element 14 and RS , so it’s good to have them back on the block.

    Here’s Farnell’s header block http://uk.farnell.com/jsp/search/productdetail.jsp?SKU=1200506

    Just wanted to check one thing – the pull up resistors you mention, can I just put a 4k7 – 10K resistor between the SDO and SDI pins and the Pi 3v3 line – is that what you meant?

    (Couldn’t quite see from the photos :) )

    Thanks
    Gordon

    1. Hi Gordon, yes – the pull-ups would typically go from the RPi header pin to 3V3. However, looking around the net, most people say that pull-ups are not needed for SPI. I don’t know enough about the bus to say for sure. No harm having them, but perhaps no need either.

      More generally, there’s a Raspberry Pi forum thread (http://www.raspberrypi.org/phpBB3/viewtopic.php?f=37&t=9563&hilit=pywws) that discusses weather station software, and I recall that someone got pywws working. The author of that software mentioned that live-logging can leave the WH1080 in an indeterminate state periodically, but that longer logging intervals (e.g. hourly etc.) seems stable.

      I had looked to integrate my RF reader with pywws, but it appears very tightly bound to the USB interface. It looks non-trivial to make it work with live 48-second intervals, and I had more interesting things to do. However, if you do make your own reader, then contact me for any changes I might have made since (assuming I haven’t posted updates here).

      1. Hi Kevin,

        Thanks for that, my Pi is happily logging the data using pywws from the USB interface, however it is well known that the USB Interface (not the PI one!) from the display is somewhat unreliable and will freeze for no apparent reason which means that you have to pull the batteries and lose the data stored in the display.

        So I want to bypass the display. – hence the RFM board

        I got a TMP36 and an LDR and the BPM085 sensor working fine, ( http://learn.adafruit.com/using-the-bmp085-with-raspberry-pi/overview ) though still struggling with the DHT22/RHT03 – not giving up though! – The LCD display contains the humidity sensor hence the need to get that up and running.

        Once I can get the RFM reading the data, then it shouldn’t be too difficult to parse that to a MySql or SQLlite database for logging and display purposes.

        I’m then going to hook it up to the energy monitor from openenergymonitor.org, as we’ve got just a few kW of pv here as well. Goal is to get the Pi working for it’s living :)

        1. The WH1080 has both indoor and outdoor humidity (nibbles ‘gh’ described above), so you could forget about the the extra sensor.

          The two humidity sensors tally when I have the transmitter indoors, and my Bosch BMP085 tallies with the LCD display’s barometric pressure, so I’ve been pleasantly surprised with the Fine Offset sensors.

        2. Hi Gordon,

          I believe the usb problems associated with the pi and this weather station are all related to pywws and using LiveLog.py . Congratulations on your ambition for creating your own receiver but an easier workaround to get you up and running quickly in the meantime is to use Hourly.py and run it every 5 minutes.

          1. This is a fantastic article… i was midflow of trying to decode the signal when i stumbled across this site.

            I have RPi running pywss livelog.py… and get the random crashes… I want to use this technique to get rid of the usb interface too.

            I have also an alternative solution which was my fall back if i fail to get this solutionworking.

            GPIO controlled relay that resets the power to USB when it crashes…
            – USB Screen running without batteries
            – USB plugged into external board with a relay on the +5v…
            – GPIO 3.3v controlling the relay to reset…

            Alter the pywss livelog.py code to handle USBException… and just turn pwoeroff to weather station… and then continue!

            1. You could possibly just use a MOSFET to drive the +5V to the USB, and save the hassle and power requirements of a relay. See the power-controller article I’m currently writing for a suitable FET that switches at 1V and has a very low Rds. I’m driving it directly with a 3V3 PIC, and the Pi works fine even with a borderline PSU, so it should easily work for the weather station’s LCD unit.

  3. Hi Kevin,
    This article is really useful in replacing my earlier failed attempts to make sense of the N96GY tranmissions using an Arduino and http://uk.farnell.com/radiotronix/rcr-433-epr/module-rf-ask-ook-rx-433mhz/dp/1565153?Ntt=1565153 and then realising that I’d loose the pressure reading…so I returned to USB connected weather station receiver and pywws. I’ve also suffered problems similar to freezing mentioned by Gordon.

    Thus I’m now going to follow your guide and would appreciate clarification:

    - the current Maplin module still at £3.99 appears to be A59JN, not billed as Hope RFM01 but looks the same, datasheet is from Alpha. Is it same/equivalent?

    - where did you get your BMP085 breakout board? There are several suppliers of similar in the UK. I assume any one will do?

    If you’ve made any improvements in the last few weeks, please keep us posted.

    Kelvin

    1. The Maplin part A59JN is the same one I used – there are other UK suppliers of this module who resell it under different names (e.g. RF Solutions ALPHA-RX433S).

      I bought the barometer module from eBay seller ‘bionicbot’ (http://www.ebay.co.uk/itm/320939715020), but yes – any BMP085 module that exposes the the I2C SDA/SCL pins and operates at 3V3 would work.

      I think that the code is up to date as I write this. It still needs work, like parameterising the altitude for barometric pressure calculations, and almost certainly writing the data to an SQL database (I think SQLite, to give more control over how tables relate to SD card files).

      I’m also considering adding an LCD display, buttons, and perhaps an real-time clock, so that it can operate entirely on just a power connection. Ultimately I might end up with a PCB to hold everything neatly.

      Since I know of a few people have gone ahead and built this, I’ll post significant updates to thread http://www.raspberrypi.org/phpBB3/viewtopic.php?f=37&t=14777, so anyone who ‘watches’ this thread will get notifications.

  4. Thanks for the writeup Kevin, your instructions have been brilliant, and I’ve just received my barometer chip (also picked up an indoor humidity sensor to play with as well, since the head unit has both indoor and outdoor humidity.

    I’ve got it interfacing with pywws processing and plotting – I made your code store the data in the same format as pywws expects, and then I removed the bit from the pywws code where it tries to use the USB to interact with the headunit and just takes the data which I’ve stored – currently using the Hourly.py script, even though I’m essentially livelogging at 48 seconds.

    Couple of things I still want to do: I want to make it wifi, but have ran into issues with my RALink micro USB dongle and a cheap 7 port powered hub – the hub I think causes the pi/ethernet/wifi to hang up regularly, a real PITA. Ultimately I want this to have this as an autonomous unit in the spare bedroom, wifi connected to the web. Obviously still have to add in the barometer and humidity. I assembled it all on a stripboard and have ribbon connectors, so will add it to these.

    Also still need to make the code slightly more robust – will need to add a timeout to send a reset command if it doesn’t get a transmission in a 60 second window or something. And will hopefully put the code up in github or something….

    Anyway, thanks again for the headstart!
    Ken

    1. Great news Ken, particularly about pywws – I tried and failed to get live-data working, so gave up after that – but the live-data could be handled independently (e.g. a static page generated for Apache to serve) to complement the hourly feed that you’re pushing to pywws.

      I haven’t found the need to do a chip reset – certainly not for a missed transmission (I had used hardware and software resets while testing with the RFM12B, but they never solved any of the problems I was having). However, the whole main loop does need to be broken into functional chunks to allow, among other things, timeouts to be handled elegantly.

      There are plenty improvements we could make to the code, so perhaps we should make it a shared effort.

      1. Yeah no bother collaborating, not sure how much time i’ll get to spend on it but sure every little helps! I’ve started to restructure the files into a more generic structure, will upload it to a github soon

  5. Kevin

    I am trying to get this going with a 868MHz module, would you be so kind as to give me some pointers on constants that have to change please?

    I have added BAND_868 = (1 << 12) which I think is correct? Anything else to change?

    1. Hi Mark; yes assuming you’re using an RFM01, bit 12 is correct for the band (giving 10 in bits 12 and 11).

      The frequency register will also need to be set. The datasheet gives the calculation, the result of which should be set in the code where ‘cmd_freq’ is defined. It’s best to find the exact frequency of your transmitter (433.92MHz is a very common centre-frequency for devices working in the 433MHz band, I suspect there’ll be a similar favourite for 868MHz devices).

      Off hand, I think the calculation expressed for F (which is the value you set in the register) is F = ((f0 / (10 * c1)) – c2) * 4000. e.g. for f0 exactly 433.92MHz I used F = ((433.92 / (10 * 1)) – 43) * 4000 which gives 1568 or 620h. The c1 and c2 values are 1 and 43 for 433MHz configs, 2 and 43 for 868MHz configs.

      Other than that, I guess the code will work as-is. Don’t trust my algebra, I think it’s correct but the datasheet is definitely correct.

      1. Thanks Kevin, I’m still playing with this. The console has a sticker on the back that says 868.3MHz which is the mid-point of 868 band 1.

        Next problem, most of the RSSI readings are 100%, a few dropping into the 99′s 98′s

        I haven’t added the pull ups to data lines, maybe its time to try that…

        1. The table of RSSI readings that’s displayed on startup is intended to help you pick Low Noise Amplifier (LNA) and RSSI threshold settings, and a also bandwidth setting. If you’re seeing near 100% even for LNA_0,RSSI_73 on the lowest baseband bandwidth (first column – 67KHz), then something’s amiss.

          Things I’d try: -

          1. Dump the other bits of the status register from the RFM01 to check they’re sensible (e.g. I’d temporarily hack strobe_afc() to dump the ‘status’ variable then call in main() and exit). This should confirm that your SPI communications are working correctly.

          2. Use the gpio utility from WiringPi (https://projects.drogon.net/raspberry-pi/wiringpi/the-gpio-utility/) to make the pull-down resistor active on GPIO21 (the DATA input we’re sampling). I’m not sure how crucial this is, I have an external pull-up but I think the RFM01 is driving this pin high or low at all times regardless. It occurred to me that the DATA pin is irrelevant – the RSSI duty is read from the RFM01′s status register.

          3. Unwire the antenna and see if the RSSI drops mostly to zero (as it should). If so, check you’re using a 17.5cm wire, and ideally locate it a good few inches (at least) from the Pi. For testing, I used a long ribbon cable and also a length of coax – with similar results for both.

          Note the copper pad on the RFM01 that the antenna connects to can be quite fragile, so don’t let any heavy wires pull at the solder joint, or the copper might come away – recoverable, but best avoided.

          A quick way to tell if you have a pull-up/down resistor already active is to use my gpfsel utility (see other blog post) to dump the state of the pins and then touch your finger on the pin and see if it changes. A floating (tri-state) input pin will jump between high and low if your finger goes near it. If it remains constant ‘low’, likely the pull-down resistor is active, and with a constant ‘high’ then the pull-up is active.

          1. Doh! I had reversed SDO/SDI, the RSSI values now look sensible, just trying to find a signal. I expect the data packet to be longer as my transmitter has a DCF clock receiver, nothing consistent found yet, but I’ll move the Pi closer to the transmitter tomorrow.

            One thought on your rainfall reading and checking the high nibble – just swap your wind/rain cables around, you soon clock up hundreds/thousands of rain ‘tips’.

            1. Great – if you’re picking an LNA/RSSI/Bandwidth config combination, look for settings showing zero near some noise – you’re looking for a ‘sweet spot’ that’s sensitive to signals, but not to noise. I did most of my initial development with the transmitter unit right beside the Pi, leaving little chance of noise or other transmitters bleeding over the signal.

              It’ll be interesting to see how the DCF stuff is transmitted – if it’s an independent follow-on packet, then the code should work without modification – it looks for around (or exactly, I forget) 88 bits. If you need to hack the code to look for a DCF packet, bear in mind that I look for the 8-bit preamble before considering a packet to be present. This should be disabled if you just want to dump anything returned by the receiver.

              Thanks for the tip, someone suggested the very same on the Sandaysoft forum, and it’s on my todo list when I get time.

  6. That’s it for tonight, the ‘noise’ appears to be a constant stream of 10 byte packets – several per second, I have no idea what it is. No wonder the base station kept losing the signal.

    I’ll have to move the Pi out to the observatory near to the transmitter tomorrow so I can up the threshold and try and capture some ‘real’ data.

  7. Thanks Kevin for your work.

    I also experience freezing of the usb using pywws livedata(). The only solution when this happens seams to unplug the batteries :-(
    My project is a meteo telephone answering machine for HangGliding and Paragliding (www.vololiberomontecucco.it) so the station will be installed remotely ( on top of a mountain ) and freezing is a big problem.

    Just ordered a RFM01 and will try it. My questions :

    - To you ( or some body ) has a version of the code for 868MHz and RPI Rev 2 ?
    - My project is in python. Did somebody bing the code to python ( ctypes,swig ,cython … )

    Thanks
    Tony

    1. Hi Tony,

      There are some pointers in the comments on getting this to work with 868 MHz, and the Rev 2 board should just need the code to use GPIO 27 rather than GPIO 21 (see first paragraph in Wiring section of post). I’ve just received a couple of Rev 2 boards, so I’ll doubtless make changes and commit new code before too long.

      There’s no Python code for this, and I’m sure it would be too slow to sample the DATA pin of the RFM01 module. I have an esoteric idea about doing it using a DMA trick which would free up the processor (and allow slower languages to be used), but it’s too much effort for too little gain at the moment. I’d be happy to share the idea by email with anyone not scared off by the DMA section of the datasheet.

      Ken McCullagh has had some success with getting data into pywws, though with some caveats I think.

      The best approach to my mind is to keep the C code to harvest the data, and then shell to whatever language you care to use for processing (e.g. into MySQL or SQLite database or, as Ken does, into pywws).

  8. Modified the folowing lines :

    #define BAND_868 (1 << 12)
    uint16_t cmd_freq = CMD_FREQ|0x67c; // 868.3 MHz
    uint16_t cmd_config = CMD_CONFIG|BAND_868|LOAD_CAP_12C0|BW_67;

    Forgot something ??

    Tony

    1. Just cmd_rcon – the RSSI threshold and LNA should be chosen according to your environment (I added a couple of paragraphs with notes on interpreting the table of numbers that show on startup).

      As an aside, I recommend you disconnect the sensors and bring the transmitter unit indoors to the computer – from experience, it will take less time to unscrew the unit from the mast than it will to investigate the unknowns caused by a weak signal/poor soldering/ineffective antenna/noise from the Pi/etc.

      If it’s beside you, then the signal will be as good as it gets and will shout over most interference. You’ll also be able to see the LED come on when the transmitter is sending. You could probably also dump output from sample_rssi() in a tight loop to see it spike when a signal is seen.

  9. Hi Kevin, I am a newby to and can’t seem to get any of this to work. When you say “If you’re using a cross compiler, the you may need to edit the CC variable in ‘Makefile’ to point to your compiler. If you’re using an RFM12b, then edit file ‘rfm01.h’ and change ‘#define RFM01′ to ‘#define RFM12B’.: Please explain. Do I need to compile this (how?) or should it just unpack and run.? Do I need to remove all of the ‘#’ symbols from this file to select the different devices?

    sorry it seems so basic to you but I need the blindingly obvious spelt out please.
    regards
    Ken

    1. You’ll need to compile the code, and you’ll also need to edit a few variables to configure the receiver for your particular environment. You should use the ‘gcc’ compiler that’s part of Raspbian – I mentioned cross-compilers because some people like to do their development on a separate computer, and then run the executable on the Raspberry Pi (this is cross-compiling).

      The # symbol is the character that introduces pre-compiler directives in C. They’re not comments like you might see in bash or Perl, etc.

      Note that there’s an issue with the code’s use of a specific transmitter-id value – it turns out that this value can change, so I need to modify the code. Someone (another Ken) has done this on his version of the software, see the Raspberry Pi forum for a link to his GitHub repository which may have this modification. Also, if you have a V2 Raspberry Pi, then the I2C port and GPIO pin have changed – simple enough changes, but it requires you to read the code and modify accordingly.

      You might want to practise compiling some ‘hello world’ stuff in C before embarking on this project. I think it’s a bit ambitious to try without understanding at least the basics of C (in other words, don’t be too disheartened if you struggle at first).

  10. I updated the code to handle changing station-ids. This was highlighted by Ken McCullagh, whereby when batteries are changed, the station-id also changes. This could easily prevent packets being recognised. The new code looks for 0xfa rather than 0xa1. The ‘f’ nibble is part of the packet preamble, and the ‘a’ nibble appears to be constant in all valid packets.

  11. Hi
    I am a newbie regarding PI and have a problem.

    I changed ‘#define RFM01′ to ‘#define RFM12B’ in file ‘rfm01.h’and received following result. What am i doing wrong.

    gcc -c -Wall wh1080_rf.c

    wh1080_rf.c:57:2: error: ‘LNA_0’ undeclared here (not in a function)
    wh1080_rf.c:58:2: error: ‘LNA_6’ undeclared here (not in a function)
    wh1080_rf.c:59:2: error: ‘LNA_14’ undeclared here (not in a function)
    wh1080_rf.c:60:2: error: ‘LNA_20’ undeclared here (not in a function)
    wh1080_rf.c: In function ‘main’:
    wh1080_rf.c:263:49: error: ‘LNA_XX’ undeclared (first use in this function)
    wh1080_rf.c:263:49: note: each undeclared identifier is reported only once for each function it appears in
    make: *** [wh1080_rf.o] Error 1

    Thanks for some help.

    1. These are defined as LNA_LOW/MEDIUM/HIGH/MAX for the RFM12B, which I changed after switching to the RFM01 (I recommend you use this instead). I’m about to remove the RFM12B code, since I no longer have one to test against. You should be able to fix up anomalies easily enough if you want to proceed with the RFM12B – the register arrangement is slightly different, but not by much.

      1. Hi,
        I really need this but have the same problem. Searching the file I could only find LNA_0 to change to LNA_LOW but the others are not there even though they error, plus there is one that doesn’t fit called LNA_XX. I know you say you don’t have ability to test but please help with solution.

  12. Kevin, sorry to be a pain, but I am unsure which lines to change in wh1080_rf.c to change the GPIO to 27 for the REV 2 board. Can you post the changes here we need to do please?
    I am all connected up eith nowhere to go!
    Excellent project and want to say thanks for all your hard work thats gone ito it!
    Dicky

    1. Hi, the line that you’d need to change has ‘datapin = ((*(gpio.addr + 13)) >> 21) & 1′, and should read ‘datapin = ((*(gpio.addr + 13)) >> 27) & 1′ (i.e. 21 becomes 27).

      There’s also the line ‘*(gpio.addr + 2) = (*(gpio.addr + 2) & 0xfffffe07)|(0×001 << 6)’ that sets pins up for input or output. However the pins should default to Input mode anyway, and the other pin that’s referenced in the code was only used by me when debugging (to reset the module, and later to drive an LED).

      Therefore I think that line could be ignored/removed/corrected as you see fit. Personally, I’d recommend reworking it to set just GPIO 27 to an input (just in case it’s been left as an output by another program). If nothing else, it would be a useful exercise to understand how the FSELn registers work.

      Also, note that if you’re driving any I2C modules (e.g. I include a barometer), then the I2C address has changed from BSC0 to BSC1 that’s now routed to header P1.

      1. I have successfully got the RFM01 working with the Rev.2 board (need to improve my antenna though). However, I am struggling to get the Bosch humidity sensor working. I have changed the memory address for the BSC0 define to point to BSC1, and also changed the line that configures GPIO0/1 as ALT0 functions to configure GPIO2/3 instead. All the data values I get from the device are zero. I have checked the SDA and SCL lines with a meter and they both sit at +3V3 so are being pulled up correctly. Is there something else I might have missed?

        1. I’d first try lsmod to make sure that neither ‘i2c-bcm2708′ nor ‘i2c-dev’ are loaded, since we access the hardware directly for I2C stuff. Although I’ve not had problems hitting the hardware with kernel drivers loaded, it’s probably not a good idea.

          Also double-check you’ve wired SDA and SCL correctly. Beyond this, assuming you don’t have any digital analyser available, you could place the I2C read call into a continuous loop and watch for voltage fluctuations with a voltmeter.

          Another possibility for testing would be to wire up SDA and/or SCL to a GPIO configured as input (hence high impedance) and to sample the GPIO pin during I2C transactions. I haven’t ever done this, but it could act something like a logic analyser. Since you’re only watching for transitions, only a small amount of data need be held, and it could be relatively easily deciphered.

          If you’re using current-limiting resistors on the I2C lines, then check that their values aren’t too high.

          Lastly, double check the BSC1 address – I assume you defined it in the header from 0×205000 to 0×804000 (yielding effective address of 0×20804000).

          1. I have checked the loaded modules and the i2c ones are not listed.

            SDA and SCL are wired correctly and there are no current limiting resistors in the lines.

            I am using
            #define BSC0_BASE (IOBASE + 0×804000)
            for the peripheral address.

            Unfortunately I don’t have access to a scope or logic analyser, but putting a meter on both the SDA and SCL lines indicates that there is no activity. I would expect my meter to flicker a bit, but it sits at a solid 3.307V for both lines (fluctuating by 0.001 occasionally).

            To me it looks like the SDA and SCL lines are not being driven through the software.

            I’ll keep looking to see if I can find anything on the Pi forums.

            1. Just for clarification, I have configured GPIO 2&3 to be ALT0 as follows:

              *gpio.addr &= ~0xfc0; // Mask out bits 6-11 of FSEL0 (i.e. force to zero)
              *gpio.addr |= 0×900; // Set bits 6-11 of FSEL0 to binary ’100100′

              Does that look right to you?

              I have loaded up the I2C kernel driver and used i2cdetect to probe the bus. It detects a device at address 0×77, so the wiring seems to be OK. I’ll look at changing the code to use the kernel driver.

              1. Yes, looks fine to me – multiply the original values by 0×40 (e.g. << 6) which gives the numbers you’ve used.

                It would be interesting to see if, after using the kernel’s I2C driver, the code now works (e.g. the BSC1 peripheral has now been properly configured by the driver).

                1. I have now rewritten the code to use the i2c-1 device driver and have the barometer working correctly. I can send you the code if you would like – please send me an email.
                  Mark.

          1. Hi, I don’t have updated code for the R2 board, but if you follow the forum topic mentioned in (or near) the references, you’ll find some from others that have made the necessary changes.

  13. Thanks very much for your quick reply. I am not a ‘C’ pprogrammer and I did see that line and knew it had to be changed but didnt think it was a simple as changing 21 to 27 – perhaps I should have just tried it!
    But the other thing was the setting of the pin as an input (which I don’t understand how that line works) as leaving that line would still try and set GPIO 21 as an input which is now not available on the rev 2 board of course.
    Yes, saw the LED code there so might try usng that to tell me when I have recieved data.
    I am not using the barometer yet so have commented that out as specified above.
    So I will try this out again tonight!
    Again, sorry to bother you on this and thanks for your post – HAppy New Year!

  14. I have the Ambient Weather WS1080 and broke the LCD on the display so I took it apart and low and behold it is using a RFM01 rev.3 DIP board for RF! I am now using that board for this mod.

    I have modified the code for use with the Pi rev 2. After compiling, I run it and get this error:

    Initialising RFM01
    can’t open device: No such file or directory
    Aborted

    I’ve had my head in the code for a while and am having a hard time finding what it is referring to. Any suggestions?

    Also, how can I get the new code that uses the I2C drivers, I have been using them for another project with my BMP085 already and it would simplify things.

      1. Awesome work, loving getting to know my Pi :) Got a quick q tho. I seem to be getting something, but nothing is being shown on the command line. Start the program and it gets to:

        RSSI Duty 0.00

        then sits there until the first signal comes through and I get a single fullstop:

        .

        Starting going thru the code, but any tips would be greatly appreciated :)

        Cheers!

        1. The dots indicate short packets – that means, some data on RF but not enough to be considered a candidate weather-station packet. You’ll see a couple of lines in the code where LNA, RSSI, and Bandwidth are configured – these are the central parameters in setting the receiver sensitivity. Bring your transmitter (the long grey box) beside the Pi to get the strongest signal – always a good place to start. You’re looking for settings that are appropriate for the signal strength – it’s a bit of an art! Note LNA_0 is highest amplification.

          1. Been mostly a software guy, so getting my head around this hardware :) As far as I can tell:

            Bandwidth – in Oz, so 433mhz, so that shouldn’t change, should it?
            LNA – Low-noise amplification – 0 is highest as u mentioned. Does highest amplification also mean most noise? This is the 0, 6 etc numbers right?
            RSSI – not 100% sure but these are the numbers 86, 91, 97, 103 etc. Some sort of intermediate freq?

            Like other examples I’ve seen in this thread and the rPi forum, all RSSI 103 seems to be at 100%, while other values seem to change as you run at diff times.

            To get the best results, do I just start at one end, and change numbers to see what yields results? Tried a number of values, but still only got a single dot once, then nothing else no matter how long it runs. Is there some way I can dump data packets to make sure the RFM01 is picking up data?

            I was also thinking of adding a full 69cm antennae which should pick up the full wavelength?

            Will def be blogging my learnings for hardware n00bs as love the tech, just getting my head around many new principles :)

            Cheers

            1. LNA – any noise does get amplified along with the signal, but an LNA is designed to minimise this. So, if you can reliably receive at lower amplification, then your noise immunity should generally be better.

              RSSI – the receiver’s signal strength indicator threshold, essentially the receiver throws away anything below this threshold – the actual threshold is the sum of the RSSI setting and the LNA gain setting (both expressed as dBm).

              The bandwidth setting is a margin above and below the configured frequency of the device (e.g. 433.92MHz + any auto-frequency offset) within which the receiver will look for a signal. Again, too wide and it may pick up unwanted signals, too narrow and it might miss data packets (e.g. altered transmitted frequency due to temperature coefficient of the electronics, or humid atmosphere, etc.).

              1. W00t!! I got it working – my problem was I hadn’t wired the GND of the RFM01 module to the RPi (wasn’t in your wiring details above – u may want to update). Used this as ref: PDF wiring diagram.

                Now to tinker :)

  15. Hi Kevin,

    I’ve hopped over here from the RPi site thread (chsims1 over there). Quick recap: 868.3MHz transmitter, rev 2 board, not seeing transmitter signals. I am using the Maplin A62JN, which I am assuming is the same as the Hope RFM01. I am getting short packet dots when near obvious noise, but do not see anything elsewhere at 48s intervals. What do you see as a good method of problem solving here …. Maplin do not provide a datasheet for their A62JN, which worries me that I can’t check connections, wiring is always problematic, and the difference in frequency band and rev board all make me think extra possible problems. I take on board your passing parameters to wh1080_rf to do continuous RSSI scanning, but I am beginning to think the problem is further up the line.

    Oh btw, just to show what a novice I am, I hadn’t shortened my antenna for 868MHz! At least, that is one thing ruled out now.

    Your write-up here is very much appreciated, and I hope that you feel you can keep up with the “poor fools” trying to emulate your exploits,

    regards,

    Ian

    1. So, assuming you have the transmitter close by, I’d drop the LNA to -20 or -14, the RSSI to something like -73 or -79 and the bandwidth to 67kHz. Not much noise will get through those settings, but the signal will.

      You could add an ‘if > 0.0 then print “Got something”‘ inside the bit of code that loops continuously sampling DRSSI (the bit inside ‘if(argc > 1)’), or better still dump the time of, or interval since, the last RSSI spike. Leave for five minutes and see what comes up.

      The Maplin module really is just an RFM01 – it’s not even re-badged. So the datasheet I’ve included in the references has all the info you need.

      You may need to do what I did originally – that is, open both the transmitter and the receiver (get some photos) and see if there’s anything to learn there. My concern with an 868MHz unit is that the RF part could be completely different – that is, perhaps it’s using FSK rather than OOK/PWM. If this is the case, it would need some rework to get working (but would probably give you more resilient comms, over longer distances).

      I’m happy to help you work through this one if you’re eager to fathom it out – the forum topic or email would probably be the best place to discuss (we run out of indentation here!). Close-up photos of inside your transmitter and LCD display will tell us a lot.

      1. Ok, thanks Kevin. I will put this aside until the weather clears, then do the dissections on the receiver & transmitter. Thanks again for your help,

        Ian

        1. Kevin

          I still cannot get anything from my 868MHz box either. Now I do have a spare ‘faulty’ transmitter. It appears to work apart from no RF.

          If (big if?) the fault is purely on the RF side, I’m wondering if I can tap into the data lines on this transmitter and snoop the firstly the configuration data (if it is using an on-board RFM unit) and the data packets.

          I have no ‘scope, would a sound card OSC be any use? or even patch through to the Pi GPIO pins directly?

          Way beyond my expertise here!

          Feel free to email.

          Mark

          1. Yes, I’m convinced it’s possible to tap into the PCB to get the data, and transmit it yourself (it was my original intention). Maybe you could post photos of your transmitter (and, if possible, the LCD display) internals first to the forum.

            Panalyzer might be worth trying for a protocol analyser. I don’t know much about soundcard scopes – I’d guess they’re fine for low bitrate stuff, but rubbish for 8MHz SPI, for example.

  16. Hey Kevin – the PDF was linked in this article:

    http://www.raspberrypi.org/phpBB3/viewtopic.php?p=259228#p259228

    I have downloaded a PDF if u let me know yr email address. I’ve also updated your code and included a few things:

    1) Saving the data out into a comma delimited file in /tmp
    2) Doing a HTTP get with the data so I can remotely log the data to a web server
    3) Added a sample_frequency variable – logging data every 48 seconds is quite granular, so this just logs/posts the data every X polls.

    Happy to share the minor changes… I plan on plotting the data on the server for real time web data. Just doing some custom ASP.NET MVC bits to keep it simple. I also want to poll other devices on 433mhz, so will prob look to spinning off threads for each device to share the code for a number of different devices/crc’s etc…

    One more thing – I didn’t use any resistors and it worked fine. I’ve had trouble picking up the signal once I placed the unit back outside, but I think I fried my antennae connection, so I’ve ordered a new RFM01 so I can test.

    Cheers
    Kolchy

    1. It’s likely you’ll need to find new settings when you move the unit – you need to choose settings that match the signal present at the point of reception, so a significant increase in the distance between the units will need different settings (lower RSSI threshold, wider bandwidth, higher amplification, or any combination). I moved the transmitter (or the Pi, I forget) in stages of around 10 metres at a time to keep a hold of the signal.

      Thanks for the forum link – PDF seems to work fine from there.

  17. Thank you for posting this project! Although I have slightly different plans, I still have a Raspberry Pi that I would like to interface to a RFM transceiver module. With your recipe and information I think I can hit the ground running!

  18. Hi, I have this setup running now for two months and receive two different weather stations from the neighborhood, presumably Alecto WS4000′s, at 868MHz.

    Frequency 868.300-868.500MHz, but with signal voids around 868.420MHz, so be careful here. Optimal results at 868.360-868.380MHz, LNA=0, RSSI=103, BW=134.

    There is an additional bonus on those stations. They have a DCF77 receiver, which can be received with a small mod to the code. It appears that the third nibble (first two are the 0xFF preamble), is a message type. Normally this is 0xA for sensor readings, but it is 0xB for time readings. So adding to the detection byte 0xFA, a test on 0xFB, I recieve time signals as well.

    Those time signals are transmitted at the same 48sec interval, but at the start of each even hour. E.g. at 21:59, the normal transmission stop. It is quite for three minutes, and then 4-5 repetations of time signal occur with 48 sec interval, after which normal sensor data transmission is resumed.

    One more remark:
    Ever since I updated to the latest raspbian 3.6.11+ #371, the code hangs frequently on the raspberry pi. This is avoided by increasing the usleep(5) at the end of the signal loop to usleep(25). It does not harm reception, and the raspberry remains more responsive.

  19. Hello,
    this project is great.
    I will also try to get my weather station working.
    Could you please post the circuit diagram for the RFM01 connect to Raspberry.
    Which resistors do i need?

    Thanks.

    1. Have a read of the comments (or is it in the forum thread? I forget) – someone already created a circuit diagram, though you could sketch it in a minute or so given the pin mappings above.

  20. Is this what would be expected from your program. I don’t appear to be getting what you have in your output listing when wh1080_rf is run. Thanks.
    -Jim
    Initialising RFM01
    SPI: mode 0, 8-bit, 1000 KHz
    Ctrl+C to exit
    LNA_0,RSSI_73 idx 0 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_0,RSSI_79 idx 1 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_0,RSSI_85 idx 2 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_0,RSSI_91 idx 3 0.00< 0.00 0.00 0.00 0.00 0.00
    LNA_0,RSSI_97 idx 4 3.12 100.00 100.00 100.00 100.00 100.00
    LNA_0,RSSI_103 idx 5 100.00 100.00 100.00 100.00 100.00 100.00
    LNA_6,RSSI_73 idx 6 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_6,RSSI_79 idx 7 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_6,RSSI_85 idx 8 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_6,RSSI_91 idx 9 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_6,RSSI_97 idx 10 0.00 0.00 10.31 96.84 100.00 100.00
    LNA_6,RSSI_103 idx 11 100.00 100.00 100.00 100.00 100.00 100.00
    LNA_14,RSSI_73 idx 12 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_14,RSSI_79 idx 13 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_14,RSSI_85 idx 14 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_14,RSSI_91 idx 15 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_14,RSSI_97 idx 16 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_14,RSSI_103 idx 17 0.00 7.29 95.79 100.00 100.00 100.00
    LNA_20,RSSI_73 idx 18 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_20,RSSI_79 idx 19 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_20,RSSI_85 idx 20 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_20,RSSI_91 idx 21 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_20,RSSI_97 idx 22 0.00 0.00 0.00 0.00 0.00 0.00
    LNA_20,RSSI_103 idx 23 0.00 0.00 0.00 0.00 12.63 95.74
    RSSI Duty 0.00

    1. Looks ok to me – the table shows noise levels being received nearby for each combination of configuration values. You need to choose a combination that suits your own environment (e.g. amplified enough to pick up your signal, but not so much it’s drowned out by noise). You need to edit a couple of lines of code to set your chosen configuration values (LNA, RSSI threshold, and band width).

      See the blog article, previous comments, and the forum thread mentioned above for more details if needed.

  21. Thanks, I have it working, I am getting sensible measurement values but I’m not sure what values I need to edit, it has just worked. Are the LNA, RSSI threshold, and band width just added as arguments on the command line when running the sudo ./wh1080_rf, I have printed out your code and I am wading my way through it ;).
    Thanks for your hard work much appreciated. I don’t really want to use the supplied Maplin display for real data capture, its more of a vanity thing. I want the Raspberry PI to do all the heavy lifting and will use your code as a base.
    Regards
    -Jim

  22. Have you any idea what the Pulse stats lines that occur instead of the normal output see bottom of the screen output, is it signal level or interference? Thanks. Jim
    +++++++++++++++++++++++++++
    Temperature: 20.7C, Humidity: 43%
    Wind speed: 0.00 m/s, Gust Speed 0.00 m/s, NE
    Wind speed: 0.0 mph, Gust Speed 0.0 mph, NE
    Total rain: 50.1 mm
    Listening for transmission
    Data bits = 88 (offset 8) (0 short) Packet signature found
    Frequency deviation 6.0KHz (6)
    a1 82 5f 2b 00 00 00 a7 02 5d crc ok (gap 48s)
    Pulse stats: Hi: 584 – 655 Lo: 1571 – 1646 (88 point)
    Threshold now 1113
    Station Id: 0A18
    Temperature: 20.7C, Humidity: 43%
    Wind speed: 0.00 m/s, Gust Speed 0.00 m/s, NE
    Wind speed: 0.0 mph, Gust Speed 0.0 mph, NE
    Total rain: 50.1 mm
    Listening for transmission
    .Pulse stats: Hi: 109 – 1104 Lo: 1135 – 1356 (43 point)
    .Pulse stats: Hi: 142 – 1098 Lo: 1186 – 1422 (52 point)
    .Pulse stats: Hi: 137 – 1095 Lo: 1123 – 1397 (41 point)
    ++++++++++++++++++++++++++++

    1. Hi Jim, The pulse stats say how wide the margin is for received pulses, above and below the threshold. A good signal will have threshold near 1000 (microseconds), and high/low pulses will be around 500 and 1500 microseconds respectively (I may have them the wrong way round, you might want to check). Typically, wider the margins mean a less reliably signal, so the information can be used to choose receiver settings, for example.

  23. Hi, Very useful information, thanks very much. Just to let you know that I have your code working with the Maplins WH1050 weather station. This is the “little brother” to the WH1080 and doesn’t have the wind direction indicator, and there is no USB output on the receiver unit.
    Only minor changes were required to your code. Mainly due to the fact that the WH1050 1 less byte. There was also a problem that the bitstream was offset by 1 bit, this was handled by changing:
    “uint8_t bit = rssitime_buf[packet_offset + 1 + (idx * 8 + b)]”
    and by adding an extra bit to the end of the stream.
    After this, all the results match the LCD display (discarding wind direction), even the CRC is OK.
    Thanks again for your great work

  24. Hi,

    I am trying to receive data from WH2 temperature sensor. I am using RFM22B module.. I can see RSSI changing when signal is received.

    But I am not sure what settings do I have to need to decode data using RSSI.

    1. My initial thoughts would be to sample the RSSI into a buffer and try to visualise the hi/lo transitions (e.g. process them into a spreadsheet) to figure out if the signal is meaningful. You might expect to see some preamble, followed by data, and then perhaps a checksum.

      Using RSSI is really only feasible for OOK signals – that is, signals where the RF is on/off to signify hi/lo. For FSK, where the signal alternates between frequencies, it wouldn’t be feasible to discern data from the RSSI.

      Note that digital RSSI over the SPI bus may not be fast enough to get all necessary transitions. I had trouble getting reliable readings from an RFM12B using digital RSSI from the status word. I don’t know about the RFM22B.

      1. Thank you very much Kevin for your reply,

        Yes I am receiving OOK signal only with RFM22B.
        I am able to measure a RSSI when there is no any signal transmission and it is around 90 and when there is High Signal RSSI goes up to 150..

        I am trying to receive data from this device :- http://lucsmall.com/2012/04/27/weather-station-hacking-part-1/

        So its freq is 500usec.

        I am reading RSSI register in one while loop and trying to get the time taken from High to Low transition but I am not able to get it atleast around 500usec it’s far more than that around 98msec..

        What can be reason for this kind of behavior ? Do you have any suggestion.
        Regards,

        1. I’m assuming you’re working with a Raspberry Pi. If you’re reading RSSI using a register, then SPI may be a bottleneck, especially if you’re going through the operating system to read/write the SPI bus. I don’t know much about the RFM22B, but there may also be a delay in the module sampling the Analogue RSSI.

          You may be able to get the Digital RSSI after setting a threshold to eliminate noise. This would then become a matter of reading a flag from the status register which may be faster than reading an arbitrary register.

          You might consider reading an analogue RSSI value directly from the RFM22B, in which case you’d need extra circuitry to convert to a digital RSSI (e.g. a comparitor with an adjustable threshold).

          However, 98ms is really quite high. None of the above could account for such a discrepancy in my opinion, particularly if the code is in C. You might want to check that there’s no blocking code in the sampling loop – it needs to be as simple as possible. Also, check that no applications are hogging the CPU (run console only, not X).

  25. Hi Kevin,

    Great project. Your code is the closest I could find to tackle what I want to accomplish. I am trying to use a 433.92 Mhz receiver (i.e. this: https://duckduckgo.com/?q=AK-R03A) to receive and decode the chatter of my external temp sensor(s). What do I need to change if there is just one data GPIO pin that I am interested in? Or am I on the wrong track here?

    1. In the existing code, there is essentially only one data GPIO pin that we’re interested in, leaving out the SPI and I2C stuff. It should already be quite close to what you need to experiment with.

      I don’t have any experience of the receiver you mentioned, but in your situation I’d be looking to sample the RXD pin transitions on a GPIO and store them alongside a timestamp in order to graph them (e.g dump to CSV and import to a spreadsheet). You may need a big buffer if you’re unable to trigger a transmission on demand.

      Another option would be to use ‘panalyser’ to snapshot the pin data (I haven’t followed the development of this, but it seemed usable when I last read up on it). In any case, you should be able to show whether or not the module is capable of providing the GPIO with suitable data to work with.

  26. Hi All
    Need some help, pls….. I wanna build a receiver with rfm01 and attiny13 / 45. I try use ook mode, but not skill for write this soft for avr. The rf module is 868mhz. Like this self tuning, self gaining software. Can somebody help for me? Thx for ALL :-)

  27. Thanks for your great webpage :-)
    I want to use “TX 29-IT”. Where can i change the follow values:

    Mittenfrequenz 868,3 MHz
    Modulation: FSK
    Frequenzhub: +/- 90 kHz
    Datenrate: 17.241 kbit/s

    Each packet is 5 Byte
    I use this tool for the configuration of RFM12B:
    http://tools.jeelabs.org/rfm12b.html

    1. The send_command16() is used to send the ‘cmd_’ variables to the transceiver. The variables are defined together, near the top of the source file ‘wh1080_rf.c’. This is typically where you would change the radio parameters.

      If you follow the thread(s) on the Raspberry Pi forum, I think you’ll find others who have received FSK transmissions – it’s something of a simplification, since you can use the FIFO rather than having to sample the data pin.

      1. thanks Kevin.
        Is it right, that i have to use a different Connection for FSK?
        I found the follow Possibility:
        * GND — GND (Pin 25)
        * VDD — 3.3V (Pin 17)
        * FSK/DAA/nFFS — with 10k to 3.3V (Pin 1)
        * SDO — MISO (Pin 21)
        * SDI — MOSI (Pin 19)
        * nIRQ — GPIO 22 (Pin 15)
        * nSEL — CS1 (Pin 26)

        I found nobody, which resolved the same problem :-(

        1. The later posts on the forum topic (http://www.raspberrypi.org/phpBB3/viewtopic.php?p=152023#p152023) discuss using a FIFO – these relate to the receiver operating in FSK mode. I think your options are to sample the DATA pin with FIFO off (wired as you suggest, perhaps also using DCLK), or else to read the FIFO buffer using SPI. I’d suggest sampling the DATA pin, initially at least – it’s easier to observe what the radio is receiving without the extra layer of the FIFO (e.g. try graphing the output in Gnumeric).

  28. I have been using your code, slightly modified for the wh1050, for some time now but I get some unusual hangs. Every so often, usually after a period between 24 and 48 hours, no data is received and the Pi stays in RealTime scheduler mode until data is finally received. The odd thing is that on the last 5 occasions (at least) the delay waiting for the data is 4368secs. Is there anything significant about 4368?
    I have tried to add checks to the main loop in the code so that the Pi returns to Standard scheduler after 120 secs, but it would appear that it never gets to the bottom of the loop when waiting for the data.
    When I added the check to the “for(idx=0; idx < count; idx++) {" loop the Pi appears to hang if the 120sec time out is exceeded. I can ping the Pi, but cannot SSH in. The Pi never recovers from this.
    Any ideas? The Pi is only about 5 meters from the transmitter.
    Many Thanks
    Bob

    1. Hi Bob, nothing comes to mind on the curious 4368s delay – maybe there’s something locally generating interference for an hour or so?

      Make sure there’s a sleep somewhere in your loop – I don’t have the code in front of me right now, but I’m sure we yield to the OS periodically – if this isn’t happening, then I can see how SSH would become unresponsive.

      Alternatively, don’t ever enter realtime mode – if the Pi isn’t doing much else anyway, then it’s less important.

      1. Hi Kevin, thanks for the reply.

        Yes, I do have a sleep (two in fact), in my loop. I can’t imagine what would be interfering, especially as the problem does not occur at set intervals.
        I cannot see where your code yields to the OS, but I am not very familiar with “C”. I was brought up on COBOL (yes, I am that old) and have quite a lot of experience with VBScripting.
        I will try not running in Realtime at all, but I do use the Pi as a web server to display the weather information, an dI would also like to add some 1-wire probes (and possibly the pressure sensor). That is why I was trying to release the Realtime after a wait of 2+ minutes.
        I will let you know if it works.
        Thanks again
        Bob

      2. Hi Kevin, hi Bob,

        I’ve exactly the same issue. Tried a lot a things: new SD, fresh Raspbian, power supply, cables, removing USBs, USB hub, cooling, monitoring… Nothing in logs.

        When wh1080_rf runs, after some hours it hangs. Following your advise, I commented calls to scheduler_realtime() and scheduler_standard(). Nothing change. I confirm the 4368sec delay/hang.

        Any idea to resolve or debug this? I’m not C developper but I learned to manage this (I do PHP).

        Thanks for your help and this helpful software!

        1. Hi, I wonder if it’s caused by the microsecond timer overflowing? This would occur after roughly 4294 seconds. If there’s an error causing the code to hang on the timer, where the exit case only occurs after an overflow (e.g. after returning to zero), then it could account for most of the 4368s delay.

          It might be worth adding that I think it unlikely to be hardware related – it’s either software failing to sample the data, or the receiver not getting (or not interpreting) the RF signal correctly.

            1. If this is the source of the problem, then we may need to throw away any timer reads that deviate too much from expected values. Since the CPU is running at 700MHz it shouldn’t interfere with readings, which are measured on a 1MHz timer.

              I’ll probably have a look at the existing code when I get a chance, in light of the link that you gave. It could explain some of the drop-out anomalies that I’ve seen and put down to RF issues (though the link mentions interrupts, which we’re not making use of, so maybe a ‘red-herring’).

            2. Hi,
              if you still need help, I had similar issues and solved the issue with this code:

              do { //
              } while(((TIMER_ARM_COUNT-StartTime)&0xffffffff) <= Timeout);

              Starttime: store TIMER_ARM_COUNT to this value when timeout starts
              Timeout: this is the time you plan to wait
              (both of type "uint")

              I'm no quite sure wheter "&0xffffffff" is really needed to cut of an overflow (after the timer overlows), should work also without because variables are of type "uint" but didn't test.

              Claus

              1. Thanks Claus. Where are you using this in your code?

                On GCC (at least on Raspbian), an unsigned int and unsigned long is 32 bits, so ‘and 0xffffffff’ will have no effect (e.g. b & 1 == b).

                1. Hi,
                  I’m using this code in a simulation of a Kopp Free control transmitter to generate timeouts between transmission blocks (up to 5,5 sec, RaspberryPi and RFM12b Module). It was also expected by me that &0xffffffff is not needed, but I’m not a “C” expert. I had also effects with timer overrun, after using code above it runs fine even if the timer generates an overrun. But of course the code is only fine if the timeout itself is below 1/2 of the max timer value (@32 bit timer and 1µsec timer resolution < 2147sec)

                  Thanks
                  Claus

  29. Hi All
    For those who have tinkered with an RFM22B, any idea which is the “FSK/DATA/nFFS” pin to connect to GPIO27 please?

    Just getting started in this stuff so i’m on a long learning curve here. I’ve searched all over the place and can’t see the answer i’m looking for.

    I have SDN, nIRQ, RXANT, TXANT, IO_0, IO_1 and IO_2 free.

    Any assistance appreciated.

    Thanks

    Mike

    1. Hi Kevin,I have purchased the smartalpha 868Mhz module and the evaluation board. I was hoping having bought the evaluation board it would make it relatively easy for me to interface my windows pc with the module. My initial aim is simple, just to be able to make the module transmit and receive. I downloaded the software utility which RF Solutions supply. This allows me to configure the baud rate, frequency etc of the module, but that is as far as I’ve got. I have sent a number of emails to RF Solutions re how do I get the unit to receive or transmit but the emails I receive assume a knowledge that I don’t have. I was hoping that I could use something like Hyperterminal to send commands to it via USB to get it to transmit and receive. I guess my question to you is, is there an easy way to talk to the unit using a piece of existing windows software, or should I give up now before I tear all my hair out?

      1. If the device is not in configuration mode, then it’s in transmit/receive mode, in which case all data sent via the serial port is sent over the air. However, it work in packets, where Hyperterminal works in streams of single characters. If you can get RTS/CTS to work appropriately (hardware handshaking) via Hyperterminal, you might get somewhere sending packets with only ASCII characters.

        My modules have older firmware that didn’t handle handshaking properly. This seems to have been addressed in later versions, but I haven’t used any of these, so I can’t really say much more. I think, even if you get some communications working, you’d be coercing both the module and Hyperterminal into doing things they weren’t really designed for – fine if you enjoy experimenting and hacking, but not if you want something that just works.

  30. Hi Kevin.
    I have to say that after I came across with this blog entry, I’ve immediately bought a some rfm01s and 2 of those sensors from maplin.

    I’m a rpi / cubieboard and home automation enthusiastic, and I’ve already installed a lightwave rf inline relay next to my drayton lp522 boiler/ heating control. (The lp522 can turn on and off the heating 3 times a day)
    using the inline relay I can now control the heating from both smartphone and from crontab (after sniffing the packets sent by the smartphone and replicating it)

    I’ve seen in your later posts that you’ve lost interest on raspberry pi. I’m really sad to read that but I’m still hoping if you could spend just a little effort on this project because I’m looking to integrate this along with my rf heating control, but this code doesn’t work very well. I’ve added some timestamps to the code, and considering I’m using 2 maplin heat sensors I’ve dropped the 48 second sleep as well. As descripbed above I’m also experiencing that the code locks up for 4200ish seconds. I also noticed that the sw clock on the raspbian also gets skewed. I’m not too much concerned on this, but is there any way to fix these 1 hour+ lags to achieve constantly reliable temperature monitoring somehow ?

    Thanks,
    Istvan

    1. Hi,

      Just to follow up my own comment, I’ve found that in “wh1080_rf.c”
      If I comment the following line:
      usleep(5); // No point running with nanosecond loops when pulses are in the hundreds of microseconds…

      It will no longer stop receiving signals and also the clock remains in sync as well.
      The only problem from comment the line above is it will constantly try to read signals without any delay, and it will render the PI almost completely useless for anything else. the wh1080 process with go up 99% cpu and the pi wil lag big time as well over ssh, but at least the weather readings are reliable.

      1. Hi Istvan, bear in mind that the 48 second sleep time relates to the transmit interval of the weather station that the code was designed to work with – it’s tied quite closely to this hardware, but of course if you leave out the sleep intervals and simply dedicate 100% CPU to reading RF signals, then it can be used to read from other devices too.

        Thanks for sharing your experience.

  31. Hi Kevin,
    thanks a lot for your wh1080_rf project.
    I reused your code to emulate a “Kopp Free Control” home automation transmitter within an FHEM home automation setup.
    After I found your web page I suddenly ordered a RFM12b module and mounted this module to my RaspberryPi.
    After modifieng your code (GPIO’s etc.) I was able to record the Kopp transmitter signals via RFM12b’s “FSK/DATA/nFFS” pin via Oscilloscope.
    With this data I could calculate the baudrate (about 4,8 kBaud), afterwards I was able to receive the transmitters data in Fifo mode and decode the messages.
    As a next step I was able to send this data also and use the whole stuff within FHEM to switch on/off the Kopp home automation moduls.
    Everthing works fine, now.
    I started about 4 weeks ago and I would need about half an year without your wh1080_rf project.
    I posted my work here:
    http://forum.fhem.de/index.php?topic=14790.0
    but its in German language (I’m sure you will understand/recognize the attached modified code)

    So again, thanks for your really good project which was easy to understand and a big support for my own project.
    Claus

    1. Thanks for sharing Andy. I recently re-implemented the reading algorithm for the Arduino Yun’s MCU (also Leonardo, perhaps any Arduino – I don’t know enough about them).

      It’s a lot more reliable and dependable than I ever achieved with a Raspberry Pi – WiFi is stable and with a receiver such as the AUREL RX-4MM5 (Farnell 169-9487), it reads reliably over decent distances. Cheaper super-regen receivers also work well, but with less sensitivity.

      My sketch just reads the data and dumps it to the console, the idea being that the Linux side of the Yun can do the decoding and posting/hosting of the data. Much more like I’d originally wanted, thanks to the dedicated MCU of the Arduino Yun.

      I posted the current sketch here on the site.

        1. Good to hear it’s stable Andy. What distance is there between your transmitter and receiver? I’ve had my doubts about long-term use of these FSK receivers for anything other than the strongest of signals.

          1. I’m using a 18cm piece of wire and it’s getting a strong signal. I tried to use a purpose-designed 433MHz antenna into a SMA connector and the signal is weak.

            I am not sure if the antenna is defective or not, but I am looking for a more robust solution than a piece of wire.

            You mention coax cable, but that has shielding in it. Would you be able to elaborate more on what you have tried?

            Thanks, Andy

    1. Beautifully done – if you want to work with me on an AM/PIC receiver version (we could interface the entire thing with I2C or UART to the RPI, but it would work with SBCs too), then I’d write some appropriate firmware etc. You might have noted from another post – this is a rock-solid way of getting RF signals into an SBC – nothing missed, and the possibility of grabbing all sorts of other data from the airwaves at the same time.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>