2015-04-03 15:55:10 +02:00
#!/usr/bin/python
# -*- coding: cp1252 -*-
##### Info #####
# BOSWatch
2015-04-04 19:21:42 +02:00
# Autor: Bastian Schroll
2015-04-03 23:11:54 +02:00
# Python Script to Recive and Decode German BOS Information with rtl_fm and multimon-NG
2015-04-03 16:35:34 +02:00
# For more Information see the README.md
2015-04-03 15:55:10 +02:00
##### Info #####
import time
#import sys
import subprocess
#import os
import mysql
import mysql . connector
2015-04-04 21:47:09 +02:00
import httplib
2015-04-03 15:55:10 +02:00
import argparse #for parse the args
import ConfigParser #for parse the config file
import re #Regex
def curtime ( format = " % Y- % m- %d % H: % M: % S " ) :
return time . strftime ( format )
2015-04-04 22:08:51 +02:00
def log ( msg ) :
if args . verbose : print " [LOG " + curtime ( " % H: % M: % S " ) + " ] " + msg
2015-04-03 15:55:10 +02:00
def stop_script ( err ) :
2015-04-03 22:38:53 +02:00
print " "
2015-04-03 15:55:10 +02:00
print " ERR: " + err
try :
2015-04-03 21:43:00 +02:00
if useMySQL : #only if MySQL is active
2015-04-04 22:08:51 +02:00
log ( " disconnect MySQL " )
2015-04-03 21:43:00 +02:00
connection . close ( )
2015-04-03 15:55:10 +02:00
rtl_fm . terminate ( )
2015-04-04 22:08:51 +02:00
log ( " rtl_fm terminated " )
2015-04-03 15:55:10 +02:00
multimon_ng . terminate ( )
2015-04-04 22:08:51 +02:00
log ( " multimon-ng terminated " )
log ( " exiting BOSWatch " )
2015-04-03 15:55:10 +02:00
except :
2015-04-04 22:08:51 +02:00
log ( " Error in cleaning " )
exit ( 0 )
2015-04-03 15:55:10 +02:00
#With -h or --help you get the Args help
#ArgsParser
2015-04-03 23:11:54 +02:00
parser = argparse . ArgumentParser ( prog = " boswatch.py " , description = " BOSWatch is a Python Script to Recive and Decode German BOS Information with rtl_fm and multimon-NG " , epilog = " More Options you can find in the extern config.ini File in this Folder " )
2015-04-03 15:55:10 +02:00
#parser.add_argument("-c", "--channel", help="BOS Channel you want to listen")
parser . add_argument ( " -f " , " --freq " , help = " Frequency you want to listen " , required = True )
parser . add_argument ( " -d " , " --device " , help = " Device you want to use (Check with rtl_test) " , type = int , default = 0 )
parser . add_argument ( " -e " , " --error " , help = " Frequency-Error of your Device in PPM " , type = int , default = 0 )
parser . add_argument ( " -a " , " --demod " , help = " Demodulation Functions " , choices = [ ' FMS ' , ' ZVEI ' , ' POC512 ' , ' POC1200 ' , ' POC2400 ' ] , required = True , nargs = " + " )
parser . add_argument ( " -s " , " --squelch " , help = " Level of Squelch " , type = int , default = 0 )
parser . add_argument ( " -v " , " --verbose " , help = " Shows more Information " , action = " store_true " )
args = parser . parse_args ( )
#Read Data from Args, Put it into working Variables and Display them
2015-04-04 16:18:27 +02:00
print ( " ____ ____ ______ __ __ __ " )
print ( " / __ )/ __ \ / ___/ | / /___ _/ /______/ /_ b " )
print ( " / __ / / / / \ __ \ | | /| / / __ `/ __/ ___/ __ \ e " )
print ( " / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / t " )
print ( " /_____/ \ ____//____/ |__/|__/ \ __,_/ \ __/ \ ___/_/ /_/ a " )
print ( " German BOS Information Script " )
2015-04-04 19:21:42 +02:00
print ( " by Bastian Schroll " )
2015-04-03 15:55:10 +02:00
print ( " " )
freq = args . freq
print " Frequency: " + freq
#channel = args.channel
#print("Frequency: ",channel)
device = args . device
print " Device-ID: " + str ( device )
error = args . error
print " Error in PPM: " + str ( error )
demodulation = " "
print " Active Demods: " + str ( len ( args . demod ) )
if " FMS " in args . demod :
demodulation + = " -a FMSFSK "
print " - FMS "
if " ZVEI " in args . demod :
demodulation + = " -a ZVEI2 "
print " - ZVEI "
if " POC512 " in args . demod :
demodulation + = " -a POCSAG512 "
print " - POC512 "
if " POC1200 " in args . demod :
demodulation + = " -a POCSAG1200 "
print " - POC1200 "
if " POC2400 " in args . demod :
demodulation + = " -a POCSAG2400 "
print " - POC2400 "
squelch = args . squelch
print " Squelch: " + str ( squelch )
if args . verbose :
print ( " Verbose Mode! " )
print " "
try :
#ConfigParser
2015-04-04 22:08:51 +02:00
log ( " reading config file " )
2015-04-03 15:55:10 +02:00
try :
config = ConfigParser . ConfigParser ( )
config . read ( " ./config.ini " )
fms_double_ignore_time = int ( config . get ( " FMS " , " double_ignore_time " ) )
zvei_double_ignore_time = int ( config . get ( " ZVEI " , " double_ignore_time " ) )
2015-04-03 21:43:00 +02:00
#MySQL config
2015-04-04 19:21:42 +02:00
useMySQL = int ( config . get ( " Module " , " useMySQL " ) ) #use MySQL support?
2015-04-03 21:43:00 +02:00
if useMySQL : #only if MySQL is active
dbserver = config . get ( " MySQL " , " dbserver " )
dbuser = config . get ( " MySQL " , " dbuser " )
dbpassword = config . get ( " MySQL " , " dbpassword " )
database = config . get ( " MySQL " , " database " )
#MySQL tables
tableFMS = config . get ( " MySQL " , " tableFMS " )
tableZVEI = config . get ( " MySQL " , " tableZVEI " )
tablePOC = config . get ( " MySQL " , " tablePOC " )
2015-04-04 21:47:09 +02:00
#HTTPrequest config
useHTTPrequest = int ( config . get ( " Module " , " useHTTPrequest " ) ) #use HTTPrequest support?
if useHTTPrequest : #only if HTTPrequest is active
url = config . get ( " HTTPrequest " , " url " )
2015-04-03 15:55:10 +02:00
except :
stop_script ( " config reading error " )
2015-04-03 21:43:00 +02:00
if useMySQL : #only if MySQL is active
2015-04-04 22:08:51 +02:00
log ( " connect to MySQL database " )
2015-04-03 21:43:00 +02:00
try :
connection = mysql . connector . connect ( host = str ( dbserver ) , user = str ( dbuser ) , passwd = str ( dbpassword ) , db = str ( database ) )
except :
print " MySQL connect error "
2015-04-03 15:55:10 +02:00
2015-04-03 21:43:00 +02:00
#variables pre-load
2015-04-04 22:08:51 +02:00
log ( " pre-load variables " )
2015-04-03 15:55:10 +02:00
fms_id = 0
fms_id_old = 0
fms_time_old = 0
zvei_id = 0
zvei_id_old = 0
zvei_time_old = 0
2015-04-04 22:08:51 +02:00
log ( " starting rtl_fm " )
2015-04-03 15:55:10 +02:00
try :
rtl_fm = subprocess . Popen ( " rtl_fm -d " + str ( device ) + " -f " + str ( freq ) + " -M fm -s 22050 -p " + str ( error ) + " -E DC -F 0 -l " + str ( squelch ) + " -g 100 " ,
#stdin=rtl_fm.stdout,
stdout = subprocess . PIPE ,
stderr = open ( ' log.txt ' , ' a ' ) ,
shell = True )
except :
stop_script ( " cannot start rtl_fm " )
#multimon_ng = subprocess.Popen("aplay -r 22050 -f S16_LE -t raw",
2015-04-04 22:08:51 +02:00
log ( " starting multimon-ng " )
2015-04-03 15:55:10 +02:00
try :
multimon_ng = subprocess . Popen ( " multimon-ng " + str ( demodulation ) + " -f alpha -t raw /dev/stdin - " ,
stdin = rtl_fm . stdout ,
stdout = subprocess . PIPE ,
stderr = open ( ' log.txt ' , ' a ' ) ,
shell = True )
except :
stop_script ( " cannot start multimon-ng " )
2015-04-04 22:08:51 +02:00
log ( " start decoding " )
2015-04-03 22:38:53 +02:00
print " "
2015-04-03 15:55:10 +02:00
while True :
#RAW Data from Multimon-NG
#ZVEI2: 25832
#FMS: 43f314170000 (9=Rotkreuz 3=Bayern 1 Ort 0x25=037FZG 7141Status 3=Einsatz Ab 0=FZG->LST2=III(mit NA,ohneSIGNAL)) CRC correct\n'
decoded = str ( multimon_ng . stdout . readline ( ) ) #Get line data from multimon stdout
if True : #if input data avalable
timestamp = int ( time . time ( ) ) #Get Timestamp
#if args.verbose: print "RAW: "+decoded #for verbose mode, print Raw input data
#FMS Decoder Section
2015-04-03 22:38:53 +02:00
#check FMS: -> check CRC -> validate -> check double alarm -> print -> (MySQL)
2015-04-03 15:55:10 +02:00
if " FMS: " in decoded :
2015-04-04 22:08:51 +02:00
log ( " recived FMS " )
2015-04-03 15:55:10 +02:00
fms_service = decoded [ 19 ] #Organisation
fms_country = decoded [ 36 ] #Bundesland
fms_location = decoded [ 65 : 67 ] #Ort
fms_vehicle = decoded [ 72 : 76 ] #Fahrzeug
fms_status = decoded [ 84 ] #Status
fms_direction = decoded [ 101 ] #Richtung
fms_tsi = decoded [ 114 : 117 ] #Taktische Kruzinformation
2015-04-03 22:38:53 +02:00
if " CRC correct " in decoded : #check CRC is correct
2015-04-03 15:55:10 +02:00
fms_id = fms_service + fms_country + fms_location + fms_vehicle + fms_status + fms_direction #build FMS id
2015-04-04 14:03:46 +02:00
if re . search ( " [0-9a-f] {2} [0-9] {6} [0-9a-f] {1} [01] {1} " , fms_id ) : #if FMS is valid
2015-04-03 22:38:53 +02:00
if fms_id == fms_id_old and timestamp < fms_time_old + fms_double_ignore_time : #check for double alarm
2015-04-04 22:08:51 +02:00
log ( " FMS double alarm: " + fms_id_old )
2015-04-03 22:38:53 +02:00
fms_time_old = timestamp #in case of double alarm, fms_double_ignore_time set new
else :
print curtime ( " % H: % M: % S " ) + " BOS: " + fms_service + " Bundesland: " + fms_country + " Ort: " + fms_location + " Fahrzeug: " + fms_vehicle + " Status: " + fms_status + " Richtung: " + fms_direction + " TKI: " + fms_tsi
fms_id_old = fms_id #save last id
fms_time_old = timestamp #save last time
if useMySQL : #only if MySQL is active
2015-04-04 22:08:51 +02:00
log ( " FMS to MySQL " )
2015-04-03 22:38:53 +02:00
cursor = connection . cursor ( )
cursor . execute ( " INSERT INTO " + tableFMS + " (time,service,country,location,vehicle,status,direction,tsi) VALUES ( %s , %s , %s , %s , %s , %s , %s , %s ) " , ( curtime ( ) , fms_service , fms_country , fms_location , fms_vehicle , fms_status , fms_direction , fms_tsi ) )
cursor . close ( )
connection . commit ( )
2015-04-04 21:47:09 +02:00
if useHTTPrequest : #only if HTTPrequest is active
httprequest = httplib . HTTPConnection ( url )
httprequest . request ( " HEAD " , " / " )
httpresponse = httprequest . getresponse ( )
2015-04-04 22:08:51 +02:00
#if args.verbose: print httpresponse.status, httpresponse.reason
log ( " FMS to HTTP " )
2015-04-04 21:47:09 +02:00
2015-04-04 22:08:51 +02:00
else :
log ( " No valid FMS: " + fms_id )
else :
log ( " CRC incorrect " )
2015-04-03 15:55:10 +02:00
2015-04-03 22:38:53 +02:00
#ZVEI Decoder Section
#check ZVEI: -> validate -> check double alarm -> print -> (MySQL)
2015-04-03 15:55:10 +02:00
if " ZVEI2: " in decoded :
2015-04-04 22:08:51 +02:00
log ( " recived ZVEI " )
2015-04-03 15:55:10 +02:00
2015-04-03 22:38:53 +02:00
zvei_id = decoded [ 7 : 12 ] #ZVEI Code
if re . search ( " [0-9F] {5} " , zvei_id ) : #if ZVEI is valid
2015-04-03 15:55:10 +02:00
if zvei_id == zvei_id_old and timestamp < zvei_time_old + zvei_double_ignore_time : #check for double alarm
2015-04-04 22:08:51 +02:00
log ( " ZVEI double alarm: " + zvei_id_old )
2015-04-03 15:55:10 +02:00
zvei_time_old = timestamp #in case of double alarm, zvei_double_ignore_time set new
else :
print curtime ( " % H: % M: % S " ) + " 5-Ton: " + zvei_id
zvei_id_old = zvei_id #save last id
zvei_time_old = timestamp #save last time
2015-04-03 21:43:00 +02:00
if useMySQL : #only if MySQL is active
2015-04-04 22:08:51 +02:00
log ( " ZVEI to MySQL " )
2015-04-03 21:43:00 +02:00
cursor = connection . cursor ( )
cursor . execute ( " INSERT INTO " + tableZVEI + " (time,zvei) VALUES ( %s , %s ) " , ( curtime ( ) , zvei_id ) )
cursor . close ( )
connection . commit ( )
2015-04-04 21:47:09 +02:00
if useHTTPrequest : #only if HTTPrequest is active
httprequest = httplib . HTTPConnection ( url )
httprequest . request ( " HEAD " , " / " )
httpresponse = httprequest . getresponse ( )
2015-04-04 22:08:51 +02:00
#if args.verbose: print httpresponse.status, httpresponse.reason
log ( " ZVEI to HTTP " )
2015-04-04 21:47:09 +02:00
2015-04-04 22:08:51 +02:00
else :
log ( " No valid ZVEI: " + zvei_id )
2015-04-03 15:55:10 +02:00
except KeyboardInterrupt :
2015-04-04 21:47:09 +02:00
stop_script ( " Keyboard Interrupt " )
except :
stop_script ( " other Error " )