Receiving P2000 messages using RTL-SDR stick and post them to Home Assistant and/or MQTT.
Read the Credits section below.
- Standalone P2000 messages receiver using a local RTL-SDR compatible receiver
- Linux based only
- Post P2000 message information to a Home Assistant sensor using the REST API (no need to install something on HA side)
- Post P2000 message information to an MQTT topic
- Capcodes database (text based for now), see 'db_capcodes.txt'
- Optional text match filter (white-list), see 'match_text.txt'
- Capcode ignore filter (black-list), see 'ignore_capcodes.txt'
- Get GPS latitude/longitude for addresses using OpenCage service
Preparing a Raspberry Pi:
Download and install Raspbian software on an SD card using Raspberry Imager from https://www.raspberrypi.com/software/ Choose Raspberry Pi OS Other and then Raspberry Pi OS Lite (32-bit)
Insert the SD card, connect the display and keyboard and boot the Raspberry Pi. Default login pi/raspberry
NOTE: Use a good quality SD card otherwise it will wear out soon (also make backups of your config)
sudo raspi-config
Select Interface options and then P2 SSH to enable SSH Back Finish Set your own password for user ‘pi’
passwd
Gather assigned IP address to login with SSH
ip addr
Look for eth0
when connected wired
If you want to use Wi-Fi use raspi-config to set country and Wi-Fi credentials using System
Options, S1 Wireless LAN
Fix timezone settings if time is incorrect:
sudo dpkg-reconfigure tzdata
Login and update software:
sudo apt update
sudo apt upgrade
sudo reboot
sudo apt-get install build-essential cmake unzip pkg-config libusb-1.0-0-dev git qt5-qmake \
libpulse-dev libx11-dev python3-pip
Download and build the software:
cd
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr
mkdir build;cd build
cmake ../ -DINSTALL_UDEV_RULES=ON -DDETACH_KERNEL_DRIVER=ON
make
sudo make install
sudo ldconfig
To be able to communicate with the dongle as a non-root user install and activate the udev rules
sudo cp ../rtl-sdr.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && sudo udevadm trigger
Then remove and insert the RTL-SDR dongle.
Test the rtl-sdr functionality like so:
$ rtl_test
Found 1 device(s):
0: Realtek, RTL2838UHIDIR, SN: 00000001
Using device 0: Generic RTL2832U OEM
Detached kernel driver
Found Rafael Micro R820T tuner
Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9
25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6
[R82XX] PLL not locked!
Sampling at 2048000 S/s.
Info: This tool will continuously read from the device, and report if
samples get lost. If you observe no further output, everything is fine.
Reading samples in async mode...
...
[Ctrl-C]
Download and build the software:
cd
git clone https://github.com/Zanoroy/multimon-ng.git
cd multimon-ng
mkdir build;cd build
qmake -qt=qt5 ../multimon-ng.pro
make
sudo make install
The multimon-ng command should work after this install.
$ multimon-ng -h
multimon-ng 1.1.8
(C) 1996/1997 by Tom Sailer HB9JNX/AE4WA
(C) 2012-2019 by Elias Oenal
Available demodulators: POCSAG512 POCSAG1200 POCSAG2400 FLEX EAS UFSK1200 CLIPFSK FMSFSK AFSK1200 AFSK2400 AFSK2400_2 AFSK2400_3 HAPN4800 FSK9600 DTMF ZVEI1 ZVEI2 ZVEI3 DZVEI PZVEI EEA EIA CCIR MORSE_CW DUMPCSV X10 SCOPE
Usage: multimon-ng [file] [file] [file] ...
If no [file] is given, input will be read from your default sound
hardware. A filename of "-" denotes standard input.
-t <type> : Input file type (any other type than raw requires sox)
-a <demod> : Add demodulator
-s <demod> : Subtract demodulator
-c : Remove all demodulators (must be added with -a <demod>)
-q : Quiet
-v <level> : Level of verbosity (e.g. '-v 3')
For POCSAG and MORSE_CW '-v1' prints decoding statistics.
-h : This help
-A : APRS mode (TNC2 text output)
-m : Mute SoX warnings
-r : Call SoX in repeatable mode (e.g. fixed random seed for dithering)
-n : Don't flush stdout, increases performance.
-j : FMS: Just output hex data and CRC, no parsing.
-e : POCSAG: Hide empty messages.
-u : POCSAG: Heuristically prune unlikely decodes.
-i : POCSAG: Inverts the input samples. Try this if decoding fails.
-p : POCSAG: Show partially received messages.
-f <mode> : POCSAG: Overrides standards and forces decoding of data as <mode>
(<mode> can be 'numeric', 'alpha', 'skyper' or 'auto')
-b <level> : POCSAG: BCH bit error correction level. Set 0 to disable, default is 2.
Lower levels increase performance and lower false positives.
-C <cs> : POCSAG: Set Charset.
-o : CW: Set threshold for dit detection (default: 500)
-d : CW: Dit length in ms (default: 50)
-g : CW: Gap length in ms (default: 50)
-x : CW: Disable auto threshold detection
-y : CW: Disable auto timing detection
--timestamp: Add a time stamp in front of every printed line
--label : Add a label to the front of every printed line
Raw input requires one channel, 16 bit, signed integer (platform-native)
samples at the demodulator's input sampling rate, which is
usually 22050 Hz. Raw input is assumed and required if piped input is used.
Most of the needed packages are installed by default on Debian 11. If you get errors about missing packages when starting the software, you may need to install them for your distro. Install these packages to support MQTT and opencage:
sudo pip3 install paho.mqtt
sudo pip3 install opencage
sudo pip3 install geopy
cd
git clone https://github.com/cyberjunky/RTL-SDR-P2000Receiver-HA.git
cd RTL-SDR-P2000Receiver-HA
./p2000.py
RTL-SDR P2000 Receiver for Home Assistant Version 0.0.6
Checking if required software is installed
rtl_fm is found
multimon-ng is found
Created config file 'config.ini', edit it and restart the program.
See the Configuration section for more information
After successful configuraton and testing by running it manually you have two options to start it automatically:
sudo nano /etc/rc.local
# Insert this just above the exit 0 line
su - pi -c /home/pi/RTL-SDR-P2000Receiver-HA/p2000.py > /dev/null 2>&1 &
sudo nano rtlsdrp2000.service
# If needed change these lines to match the location of the software on your system:
StandardOutput=file:/home/pi/RTL-SDR-P2000Receiver-HA/rtlsdrp2000.log
StandardError=file:/home/pi/RTL-SDR-P2000Receiver-HA/rtlsdrp2000.log
ExecStart=/usr/bin/python3 /home/pi/RTL-SDR-P2000Receiver-HA/p2000.py
sudo cp rtlsdrp2000.service /etc/systemd/system
sudo systemctl enable rtlsdrp2000
sudo systemctl start rtlsdrp2000
cd
sudo rm -r rtl-sdr multimon-ng
Fill in the generated config.ini
(after the first run of p2000.py)
Set debug = True
to see what's happening to check your configuration, disable if all is
working to save writes to SD card.
home-assistant section:
enabled = True
baseurl = the IP address or url of your Home-Assistant instance including port.
token = A long lived token generated inside Home-Assistant
If you want to use geocoding set opencage
opencage section:
enabled = True
token = Your opencage tokenUpdate all database files:
update_db.py
Run p2000.py Check Home Assistant sensor after first message trigger Filtering I use match_text.txt to match all my plaatsnamen:
# Only pass messages when filter matches, format: one string per line, * and ? masks are
allowed.
# When empty or all entries are commented with # all messages pass
*Dordrecht*
*DORDRT*
*Zwijndrecht*
*ZWIJND*
*Sliedrecht*
*SLIEDR*
And ignore_text.txt to ignore unwanted stuff:
# Ignore messages when filter matches, format: one string per line, * and ? masks are
allowed.
# When empty or all commented with # all messages pass
*Test*
*test*
*TEST*
NOTE: All tools makes backups of current files inside the 'convert' directory with timestamps appended to filename. This is also the location the temp data is downloaded to.
I tested the software with: RTL-SDR / FM+DAB / DVB-T USB 2.0 Mini Digital TV Stick DVBT Dongle SDR
The software searches for device 0 by default, see Configuration section for more details.
Sample output:
$ rtl_fm -f 169.65M -M fm -s 22050 | multimon-ng -a FLEX -t raw -
Found 1 device(s):
0: Realtek, RTL2838UHIDIR, SN: 00000001
multimon-ng 1.1.8
(C) 1996/1997 by Tom Sailer HB9JNX/AE4WA
(C) 2012-2019 by Elias Oenal
Available demodulators: POCSAG512 POCSAG1200 POCSAG2400 FLEX EAS UFSK1200 CLIPFSK FMSFSK AFSK1200 AFSK2400 AFSK2400_2 AFSK2400_3 HAPN4800 FSK9600 DTMF ZVEI1 ZVEI2 ZVEI3 DZVEI PZVEI EEA EIA CCIR MORSE_CW DUMPCSV X10 SCOPE
Enabled demodulators: FLEX
Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Tuner gain set to automatic.
Tuned to 169903575 Hz.
Oversampling input by: 46x.
Oversampling output by: 1x.
Buffer size: 8.08ms
Exact sample rate is: 1014300.020041 Hz
Allocating 15 zero-copy buffers
Sampling at 1014300 S/s.
Output at 22050 Hz.
FLEX|2021-06-28 16:50:07|1600/2/K/A|12.077|001180000|ALN|TESTOPROEP HOOFDSYSTEEM MKOB DEN BOSCH
FLEX|2021-06-28 16:50:35|1600/2/K/A|12.092|002029568 000126999 000126164|ALN|A2 (dia: ja) 12164 Rit 79824 Hotel Herbergh Amsterdam Airport Sloterweg Badhoevedorp
...
Start the program for the first time to create a default config.ini file.
$ ./p2000.sh
RTL-SDR P2000 Receiver for Home Assistant Version 0.0.1
Checking if required software is installed
rtl_fm is found
multimon-ng is found
Created config file 'config.ini', edit it and restart the program.
Then edit the file config.ini:
[main]
debug = False
logtofile = True
[rtl-sdr]
cmd = rtl_fm -f 169.65M -M fm -s 22050 | multimon-ng -a FLEX -t raw -
[home-assistant]
enabled = True
baseurl = http://homeassistant.local:8123
token = Place your Long-Lived Access Token here
sensorname = P2000
[mqtt]
enabled = False
mqtt_server = 192.168.1.100
mqtt_port = 1883
mqtt_user = mqttuser
mqtt_password = somepassword
mqtt_topic = p2000
[opencage]
enabled = False
token = Place your OpenCage API Token here
[sensor_p2000_radius]
friendlyname = P2000 1km from GPS
zone_latitude = 52.37602835336776
zone_longitude = 4.902929475786443
zone_radius = 1
[sensor_p2000_keyword]
friendlyname = P2000 keyword
searchkeyword = *GRIP*,*Grip*,*grip*
[sensor_p2000_capcode]
friendlyname = P2000 capcodes Lifeliners
searchcapcode = *000120901*,*000726001*,*000923993*
[sensor_p2000_region]
friendlyname = P2000 Region Amsterdam-Amstelland and Utrecht
searchregion = Amsterdam-Amstelland,Flevoland
[sensor_p2000_discipline_]
friendlyname = P2000 Brandweer
searchdiscipline = Brandweer
main - debug
Set to True to get debugging output.
main - logtofile
Set to True to create daily logfiles from all send and ignored messages
rtl-sdr - cmd
My dongle works with these default settings (without -g and -p), with them I get no output.
You may need to add these gain or correction parameters: -g = 'gain' - a number between 0-50 -p = 'correction' - specific ppm deviation -d = 'device id' - if you have more than one dongle
For example:
cmd = rtl_fm -f 169.65M -M fm -s 22050 -g 20 -p 0 | multimon-ng -a FLEX -t raw -
U can test this by running the command line from the shell, see RTL-SDR dongle section above. You should see the FLEX messages appear after some seconds.
home-assistant - enabled
True to post data to HA, False to disable
home-assistant - baseurl
Enter the url to your local Home Assistant instance including port.
home-assistant - token
Goto your user profile menu in Home Assistant lovelace GUI, and create a so called 'Long-Lived Access Token'. Name it 'P2000Receiver' for example and copy and paste this token here in the config.ini file.
mqtt - enabled
True to post data to MQTT, False to disable
mqtt - mqtt_server mqtt - mqtt_port mqtt - mqtt_user mqtt - mqtt_password mqtt - mqtt_topic
MQTT server address, port, user credentials to connect with and topic to post to
opencage - enabled
True to fetch latitude/longitude for address
opencage - token
To use OpenCage support you need to create a (free max 2500 request per day, 1 per second) account at https://opencagedata.com Then fill in your API key here
sensor_p2000_radius
Sensor naming in Home-Assistant, you may name the sensor as you want, but it has to start with "sensor_"
friendlyname
This is the displayname from the sensor in Home-Assistant, change to whatever you find suitable
zone_latitude zone_longitude zone_radius
These three values are mandatory for a GPS based sensor, zone_radius is defined in KM
searchkeyword
Keywords for the sensor, comma separated and with use of wildcards
searchregion
Regions as criteria for a sensor, values are case-sensitive and can be comma separated
searchcapcode Capcodes for the sensor, comma separated and with use of wildcards
searchdiscipline Disciplines for the sensor, comma separated and with use of wildcards
There is basic filtering implemented (this can be changed during development)
The following files are used:
ignore_text.txt ignore_capcodes.txt
A specific type of filtering is ignored if the file is empty or only has commented lines in it. (lines with leading #)
The syntax for match_text.txt and ignore_text.txt is using fnmatch.
https://docs.python.org/3/library/fnmatch.html
So entries need to match whole message exactly, or use wildcards to match parts of it.
This is the order in which the filters are processed:
You can get message events on your mobile device(s) by using a notify event, for example like this:
automation:
- alias: "Melding P2000 Bericht"
trigger:
platform: state
entity_id: sensor.p2000
action:
service: notify.telegram
data_template:
message: >
{{ states.sensor.p2000.state + "\n" + states.sensor.p2000.attributes.disciplines }}
If you want an OpenStreetMap link included (if GPS location was found using OpenCage):
automation:
- alias: "Melding P2000 Bericht"
trigger:
platform: state
entity_id: sensor.p2000
action:
service: notify.telegram
data_template:
message: >
{{ states.sensor.p2000.state + "\n" + states.sensor.p2000.attributes.disciplines + "\n" + states.sensor.p2000.attributes.mapurl }}
If you want to use native Telegram location support (if GPS location was found using OpenCage):
automation:
- alias: "Melding P2000 Bericht"
trigger:
platform: state
entity_id: sensor.p2000
action:
service: notify.telegram
data_template:
message: >
{{ states.sensor.p2000.state + "\n" + states.sensor.p2000.attributes.disciplines }}
- condition: or
conditions: "{{ states.sensor.p2000.attributes.latitude|float > 0 }}"
- service: script.notify_telegram_location
script:
notify_telegram_location:
alias: Test notify.telegram location template
sequence:
- service: notify.telegram
data:
message: "Not used here but needed..."
data:
location:
latitude: "{{ states.sensor.p2000.attributes.latitude|float }}"
longitude: "{{ states.sensor.p2000.attributes.longitude|float }}"
If you have issues with the dongle not being recognized try this:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830
If you don't get any output from the script, no messages try this:
Run this command to see if you get output lines:
rtl_fm -f 169.65M -M fm -s 22050 | multimon-ng -a FLEX -t raw -
If not try ti place the antenna near the window/outside.
If you get output from this command, maybe the filters are too strict/wrong. Create an empty match_text.txt file
My project is based on https://github.com/dmitryelj/RPi-P2000Receiver written by https://github.com/dmitryelj, thanks for the inspiration!
I rewrote it heavily though, left out all unneeded code for my specific purpose, and added some functionality:
-
Removed websocket code
-
Removed httpserver code
-
Removed POCSAG code
-
Removed all RPi specific code and functionality (e.g. LCD, Reboot. Power, CPU)
-
Make it more Linux distro independent
-
Removed Windows specific code
-
Added config file support, see config.ini (run program ones to create it)
-
Added P2000 address extract/guess code
-
Added support for city database, see db_plaatsnamen.txt
-
Added support for finding and translating city shortnames, see db_pltsnmn.txt
-
Rewrote 3rd party post to server code to post to Home Assistant REST API
-
Created class based code instead of monolith using globals
-
Renamed files to see which are filters and which are databases
-
Added tools to create these files, find them under 'tools'
-
Pylint, flake8, black, isort checked code, some rewriting todo to get pylint 10 score.
-
https://github.com/bduijnhouwer for MQTT support
-
https://github.com/Dinges28 for OpenCage geolocation support
https://www.tomzulu10capcodes.nl/
https://www.tomzulu10capcodes.nl/
NOTE: We only support one sensor for now. Some filter functionalty (e.g. disciplinces, regions) is not implemented yet.
Unless you fill match_filter.txt you will receive all P2000 messages!
Could be that we re-add websocket functionality, and create a matching Home Assistant custom integration.
There is a chance we make other big breaking changes.
Focus of development is now on getting as much as data from the FLEX messages as possible.
Replace text files with a database (MongoDB/SQLite?)
Set debug = True in config.ini file to get all debbugging info when running.