Skip to content

colgreen/piook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 

Repository files navigation

piook

Raspberry Pi On-Off Keying (OOK) Decoder for the ClimeMET Weather Station, model CM9088 (with 433MHz remote/outdoor module).

Overview

piook is a small program for the Raspberry Pi computer that decodes radio transmissions from a ClimeMET weather station remote module. It uses a cheap 433 MHz radio receiver module wired to one of the Raspberry Pi's GPIO pins.

ClimeMET Weather Station

The ClimeMET CM9088 Weather Station consists of two items: an indoor module with an LCD display, and a remote/outdoor module (part number CM7-TX) for mounting on an outside wall to take readings of the external temperature and relative humidity (RH).

The remote module periodically (about once per minute) transmits a short burst of data to the main module for indoor display of the external readings. Radio transmission occurs at 433 MHz using on-off keying (OOK), a crude but simple data transmission scheme. The transmitter is switched on and off quickly, with well defined off intervals that define the binary bits of the data sequence being transmitted.

433 MHz Radio Receivers

433 MHz is a standard band for low power transmission. Devices using on-off keying on this band are common; wireless doorbells, thermostats, and electricity meters typically use it. As such, cheap 433 MHz receiver and transmitter modules are widely available.

I initially attempted this project using the widely available and very cheap XY-MK-5V receivers. They appear to be a simple regenerative or superregenerative type receiver - a primitive circuit with low sensitivity and selectivity. I was unable to get these to receive a clean signal beyond about 5 meters from the transmitter.

Web research led to the RXB6, a superior superheterodyne type 433 MHz receiver module. This module allows reception of the OOK signal inside the house from the outdoor module located about 10 meters away.

Connecting to a Raspberry Pi

Both the XY-MK-5V and RXB6 have simple physical interfaces: +5V and ground connectors for power, and a single data/signal connector. The data/signal connector should typically be wired to the positive power rail via a pull up resistor to prevent a floating voltage on the data line; I used a 10k Ohm resistor for this.

The data line can then be connected to one of the Raspberry Pi's GPIO pins which we can interface to in software using libgpiod.

Dependencies

This version requires libgpiod. On Raspberry Pi OS/Debian/Ubuntu:

sudo apt update
sudo apt install libgpiod-dev

On other distributions, install libgpiod from your package manager or build from source.

Building piook

piook consists of three files: piook.c, decoder.c, and piook.h. The only dependency is libgpiod.

Using Make (recommended)

make

This will build the piook executable.

Manual compilation

gcc -Wall -Wextra -O3 -std=gnu99 -march=native src/piook.c src/decoder.c -lgpiod -o piook

Installation

To install system-wide (requires root):

sudo make install

To uninstall:

sudo make uninstall

Running piook (Usage)

Usage:

piook [OPTIONS]

Options:
  -h, --help                 Show help message
  -v, --verbose              Enable verbose output
  -p, --pin PIN              GPIO line number (default: 7)
  -o, --output FILE          Output filename (required)
  -c, --chip CHIP            GPIO chip name (default: gpiochip0)

Examples:
  piook -p 17 -o weather.txt
  piook --verbose --chip gpiochip1 -p 23 -o data.txt
  piook -o weather.txt  (use default pin 7)

Notes:

  • Must be called with privileges to access /dev/gpiochip* (usually root or gpio group).
  • piook will listen on the specified gpio line for valid OOK sequences being received by the attached radio module.
  • Valid sequences are decoded to a temperature (in Celsius, C), and a relative humidity (RH%) value.
  • The temperature encoding has range -204.7 to +204.7 C, and precision of 0.1.
  • Relative humidity has range 0-100, and precision of 1.0.
  • The decoded data is written to the output file in the format: temp,RH with a newline (\n) terminator.
  • Each received transmission overwrites the previous file, i.e. the file will always contain a single line containing the most recently received data.

Data Modulation

Each transmission consists of a series of on-off transitions of the\ transmitter. These are observed on the data pin of the radio receiver module as a series of voltage transition steps. The steps encode binary bits; analysis of multiple transmissions yielded the following knowledge:

  • Each on-pulse has duration 1000 us (1 millisecond).
  • There are two different durations of off-pulse, 500 and 1,500 us
  • The short (500 us) off-pulse represents a binary 1.
  • The long (1,500 us) off-pulse represents a binary 0.

Message Format

Each transmission conveys 48 bits of data (6 bytes or 12 nibbles).

The message format is as follows:

byte# nibble# designation
0 0 Fixed preamble 0xF
0 1 Fixed preamble 0xF
1 2 Fixed preamble 0x8
1 3 Random code/ID (1st nibble)
2 4 Random code/ID (2nd nibble)
2 5 Temperature (1st nibble)
3 6 Temperature (2nd nibble)
3 7 Temperature (3rd nibble)
4 8 Humidity (1st nibble)
4 9 Humidity (2nd nibble)
5 10 Checksum (1st nibble)
5 11 Checksum (2nd nibble)

Notes:

  • The first three nibbles can be considered to be a fixed sequence/preamble used to detect the start of a message. The first nibble tends to be masked with noise, so piook tests for the sequence 0xF8 instead of 0xFF8. I imagine additional leading bits are present to allow for just such lead-in-noise issues.

  • Nibbles 3 and 4 straddle a byte boundary and contain a unique code that is generated by the remote unit when it is powered on. I haven't examined how this code changes to observe if there is any pattern, but it's possible that it's randomly generated. The purpose of this code is to 'lock' the remote unit to the indoor receiver unit. The indoor unit will learn the first code it receives and will ignore any messages with a different code (e.g. from a neighbour who happens to have the same type of module). piook does not use this code.

  • Nibbles 5,6,7 convey a temperature reading. We can decode to an 11 bit integer by appending the least significant 3 bits of nibble 5 with all the bits of nibbles 6 and 7. This gives an integer value of between 0 and (2^11)-1 = 2027. Dividing this by ten gives the magnitude of the temperature. The next least significant bit of nibble 5 indicates the sign, 0 => +ve, 1 => -ve. In principle this encoding scheme can encode temperatures from -204.7 to +204.7 degrees C, with precision of 0.1 degrees C.

  • Nibbles 8 and 9 convey humidity encoded as an unsigned integer. Humidity has range 0 to 100, precision 1, hence values above 100 aren't used.

  • Nibbles 10 and 11 are a checksum. The checksum is a CRC8 variant. See the source code for precise details.

Theory of Operation

How this program works is rather dumb and inefficient, but it does work. Read on...

The data line from the 433 MHz receiver module will receive random noise when no transmission is in progress, therefore the voltage on the GPIO pin will usually be noise. When a transmission begins, the voltage will follow the pattern of the on-off pulses.

piook attaches an event handler to the GPIO pin, which executes upon each low-high or high-low voltage transition. When there is noise on the pin the event handler is being constantly called, possibly thousands of times per second, certainly hundreds. The event handler records the time since it was last called and this allows it to determine pulse durations and whether the transition corresponds to a binary 0, 1, or noise. For 0s and 1s the bits are stored in a buffer until there are enough to pass to the decode subroutine.

Reverse Engineering the Data Modulation and Encoding

The message format was determined partly from internet searching and partly from reverse engineering the received signals. A raw signal can be recorded and manually examined by attaching the data pin of the receiver to an audio line-in of a PC and using audio recording software (I used Audacity on Windows) to record the raw pulse trains.

By comparing the pulse trains with the temperature and humidity readouts on the indoor modules we can gradually determine where the temp and RH data is located in the data sequence, and eventually, how those values are modulated and encoded. In order to determine how negative temperatures are encoded it was necessary to place the remote module in a freezer for a brief time. Similarly, the high end of the temperature range was tested by using an oven on a low heat.

Notable resources:

Colin,
January 26th, 2017

Revised and updated December 28th, 2025

About

Raspberry Pi On-Off Keying Decoder for ClimeMET 433 MHz weather station

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published