diff --git a/.gitignore b/.gitignore index 03d330b..77b6753 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ *.psd *.pyc -*.log *.log \ No newline at end of file diff --git a/README.md b/README.md index 03949f5..8e464f8 100644 --- a/README.md +++ b/README.md @@ -13,32 +13,37 @@ unless you are developer you can use the develop-Branch - may be unstable! ### Features ##### Implemented Features: -- FMS, ZVEI and POCSAG decoding and Displaying +- FMS, ZVEI and POCSAG512/1200 decoding and Displaying +- Plugin support for easy Functions extension - Filtering double alarms with adjustable time -- Data validation (plausibility test) -- MySQL Database Support -- simple HTTP request at alarm to URL you want +- Filtering of POCSAG RIC´s - All configurations in seperate config File -- simple Web Frontend with Data Parsing +- Data validation (plausibility test) - Logfiles for better Troubleshooting - verbose/quiet Mode for more/none information -- POCSAG1200 and POCSAG512 support -- Filtering of POCSAG RIC´s (adjustment at config) ##### Features for the Future: - extensive filtering options - POCSAG 2400 support (need RAW data from multimon-ng) -- automatic Audio recording at alarm -- E-Mail Notification -- Web Frontend with Overview and configuration + + +###Plugins +##### Implemented Plugins: +- MySQL +- BosMon + +##### Plugins for the Future: +- HTTP-Push +- E-mail Notification +- Other Ideas per Issues + ### Configuration ##### boswatch.py -The configuration for the Script you can find in config.ini -- You can set the ignore time for double alarms in seconds. -- you can adjust your rangefilter for POCSAG Decode. -- to use the script with MySQL Support set "useMySQL = 1" and the Userdata to your local MySQL Database. -- to use the script with HTTP request Support set "useHTTPrequest = 1" and set a URL to your destination. +Take a look into the /config/config.ini +In the Section `[BOSWatch]` you can set double_alarm_time etc. +In the Section `[Plugins]` you can activate or deactivate the Plugins +For each Plugin that requires configurations a own Section with his Name is available For the other Functions see "Usage" below. @@ -47,9 +52,11 @@ Put the Files in Folder /wwww/ into your local Webserver Folder (/var/www/). Now you must edit the "config.php" with your Userdata to your local Database. For the Parsing Functions take a look into the parser.php + ### Usage `sudo python boswatch.py -f 85.235M -a FMS ZVEI` Starts boswatch at Frequency 85.235 MHz with the Demodulation Functions FMS and ZVEI. +Parameter -f/--freq and -a/--demod are required! Help to all usable Parameters with `sudo python boswatch.py -h` @@ -59,21 +66,19 @@ usage: boswatch.py [-h] -f FREQ [-d DEVICE] [-e ERROR] -a [{FMS,ZVEI,POC512,POC1200,POC2400} ...] [-s SQUELCH] [-v] optional arguments: - -h, --help show this help message and exit - -f FREQ, --freq FREQ Frequency you want to listen - -d DEVICE, --device DEVICE - Device you want to use (Check with rtl_test) - -e ERROR, --error ERROR - Frequency-Error of your Device in PPM + -h, --help show this help message and exit + -f FREQ, --freq FREQ Frequency you want to listen + -d DEVICE, --device DEVICE Device you want to use (Check with rtl_test) + -e ERROR, --error ERROR Frequency-Error of your Device in PPM -a {FMS,ZVEI,POC512,POC1200,POC2400} [{FMS,ZVEI,POC512,POC1200,POC2400} ...], --demod {FMS,ZVEI,POC512,POC1200,POC2400} [{FMS,ZVEI,POC512,POC1200,POC2400} ...] - Demodulation Functions - -s SQUELCH, --squelch SQUELCH - Level of Squelch - -v, --verbose Shows more Information - -q, --quiet Shows no Information. Only Logfiles + Demodulation Functions + -s SQUELCH, --squelch SQUELCH Level of Squelch + -v, --verbose Shows more Information + -q, --quiet Shows no Information. Only Logfiles ``` + ### Installation You can easy install BOSWatch with the install.sh Script. - Download the install.sh in any Folder you want. @@ -87,16 +92,9 @@ In case of an Error during the Installation, check the Logfile in `~/boswatch/in Caution, script don't install a Webserver with PHP and MySQL. So you have to make up manually if you want to use MySQL support. + ### Requirements - RTL_SDR (rtl_fm) - Multimon-NG - Python Support - MySQL Connector for Python - -##### optional -- Webserver with PHP -- MySQL Database Server - -Thanks to smith_fms and McBo from [Funkmeldesystem.de - Forum](http://www.funkmeldesystem.de/) for Inspiration and Groundwork! - -###### Greetz Schrolli diff --git a/boswatch.py b/boswatch.py index 78154c5..7af76b6 100644 --- a/boswatch.py +++ b/boswatch.py @@ -8,60 +8,66 @@ # For more Information see the README.md ##### Info ##### -import time -#import sys -import subprocess -import os #for absolute path: os.path.dirname(os.path.abspath(__file__)) -import mysql -import mysql.connector -import httplib #for the HTTP request +import globals # Global variables +import pluginloader + +import logging import argparse #for parse the args import ConfigParser #for parse the config file import re #Regex for validation +import os #for script path +import time #timestamp for doublealarm + +#create new logger +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) +#set log string format +formatter = logging.Formatter('%(asctime)s - %(module)-12s [%(levelname)-8s] %(message)s', '%d.%m.%Y %H:%M:%S') +#create a file logger +fh = logging.FileHandler('log/boswatch.log', 'w') +fh.setLevel(logging.DEBUG) #log level >= Debug +fh.setFormatter(formatter) +logger.addHandler(fh) +#create a display logger +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) #log level >= info +ch.setFormatter(formatter) +logger.addHandler(ch) -# Functions -def curtime(format="%Y-%m-%d %H:%M:%S"): - return time.strftime(format) - -#Loglevel -#[LOG] for the logfile -#[INFO] normal display -#[ERROR] errors -def log(msg, level="log"): - log_entry = curtime("%H:%M:%S")+" ["+level.upper()+"] "+msg - - if not level == "log" and not args.quiet or args.verbose: - print log_entry - - bos_log = open(script_path+"/log/log_bos.txt", "a") - bos_log.write(log_entry+"\n") - bos_log.close() - +def throwAlarm(typ,data): + for i in pluginloader.getPlugins(): + plugin = pluginloader.loadPlugin(i) + logging.debug("call Plugin: %s", i["name"]) + plugin.run(typ,"0",data) + # Programm try: - #Clear the Logfiles + #first Clear the Logfiles for logging try: script_path = os.path.dirname(os.path.abspath(__file__)) if not os.path.exists(script_path+"/log/"): os.mkdir(script_path+"/log/") - bos_log = open(script_path+"/log/log_bos.txt", "w") - rtl_log = open(script_path+"/log/log_rtl.txt", "w") - mon_log = open(script_path+"/log/log_mon.txt", "w") - bos_log.write("##### "+curtime()+" #####\n\n") - rtl_log.write("##### "+curtime()+" #####\n\n") - mon_log.write("##### "+curtime()+" #####\n\n") + bos_log = open(script_path+"/log/boswatch.log", "w") + rtl_log = open(script_path+"/log/rtl_fm.log", "w") + mon_log = open(script_path+"/log/multimon.log", "w") +# bos_log.write("##### "+curtime()+" #####\n\n") +# rtl_log.write("##### "+curtime()+" #####\n\n") +# mon_log.write("##### "+curtime()+" #####\n\n") bos_log.close() rtl_log.close() mon_log.close() + logging.debug("BOSWatch has started") + logging.debug("Logfiles cleared") except: - log("cannot clear logfiles","error") + logging.exception("cannot clear Logfiles") try: + logging.debug("parse args") #With -h or --help you get the Args help #ArgsParser 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") @@ -75,27 +81,44 @@ try: parser.add_argument("-q", "--quiet", help="Shows no Information. Only Logfiles", action="store_true") args = parser.parse_args() except: - log("cannot parse Args","error") + logging.exception("cannot parse args") #Read Data from Args, Put it into working Variables freq = args.freq device = args.device error = args.error + squelch = args.squelch + + logging.debug(" - Frequency: %s", freq) + logging.debug(" - Device: %s", device) + logging.debug(" - PPM Error: %s", error) + logging.debug(" - Squelch: %s", squelch) demodulation = "" if "FMS" in args.demod: demodulation += "-a FMSFSK " + logging.debug(" - Demod: FMS") if "ZVEI" in args.demod: demodulation += "-a ZVEI2 " + logging.debug(" - Demod: ZVEI") if "POC512" in args.demod: demodulation += "-a POCSAG512 " + logging.debug(" - Demod: POC512") if "POC1200" in args.demod: - demodulation += "-a POCSAG1200 " + demodulation += "-a POCSAG1200 " + logging.debug(" - Demod: P") if "POC2400" in args.demod: demodulation += "-a POCSAG2400 " - - squelch = args.squelch + logging.debug(" - Demod: POC2400") + + logging.debug(" - Verbose Mode: %s", args.verbose) + logging.debug(" - Quiet Mode: %s", args.quiet) + if args.verbose: + ch.setLevel(logging.DEBUG) + if args.quiet: + ch.setLevel(logging.CRITICAL) + if not args.quiet: #only if not quiet mode print " ____ ____ ______ __ __ __ " print " / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ b" @@ -123,10 +146,10 @@ try: print "Squelch: "+str(squelch) if args.verbose: print "Verbose Mode!" - print "" + print "" #variables pre-load - log("pre-load variables") + logging.debug("pre-load variables") fms_id = 0 fms_id_old = 0 fms_time_old = 0 @@ -139,105 +162,60 @@ try: poc_id_old = 0 poc_time_old = 0 - + #ConfigParser - log("reading config file") + logging.debug("reading config file") try: - config = ConfigParser.ConfigParser() - config.read(script_path+"/config/config.ini") - fms_double_ignore_time = int(config.get("FMS", "double_ignore_time")) - zvei_double_ignore_time = int(config.get("ZVEI", "double_ignore_time")) - poc_double_ignore_time = int(config.get("POC", "double_ignore_time")) - poc_filter_range_start = int(config.get("POC", "filter_range_start")) - poc_filter_range_end = int(config.get("POC", "filter_range_end")) - - #MySQL config - useMySQL = int(config.get("Module", "useMySQL")) #use MySQL support? - 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") - - #HTTPrequest config - useHTTPrequest = int(config.get("Module", "useHTTPrequest")) #use HTTPrequest support? - if useHTTPrequest: #only if HTTPrequest is active - url_fms = config.get("HTTPrequest", "url_fms") - url_zvei = config.get("HTTPrequest", "url_zvei") - url_poc = config.get("HTTPrequest", "url_poc") - + globals.config = ConfigParser.ConfigParser() + globals.config.read(script_path+"/config/config.ini") + for key,val in globals.config.items("BOSWatch"): + logging.debug(" - %s = %s", key, val) except: - log("cannot read config file","error") - - #in case of reading error, set standard values - log("set to standard configuration") - fms_double_ignore_time = 5 - zvei_double_ignore_time = 5 - poc_double_ignore_time = 10 - poc_filter_range_start = 0000000 - poc_filter_range_end = 9999999 - - #no config - no modules ;-) - useMySQL = 0 - useHTTPrequest = 0 - - - - if useMySQL: #only if MySQL is active - log("testing MySQL connection") - try: - connection = mysql.connector.connect(host = str(dbserver), user = str(dbuser), passwd = str(dbpassword), db = str(database)) - log("connection test successful") - except: - log("connection test failed - MySQL support deactivated","error") - useMySQL = 0 - finally: - connection.close() #Close connection in every case + logging.exception("cannot read config file") - log("starting rtl_fm") - 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(script_path+"/log/log_rtl.txt","a"), - shell=True) - except: - log("cannot start rtl_fm","error") - - #multimon_ng = subprocess.Popen("aplay -r 22050 -f S16_LE -t raw", - log("starting multimon-ng") - try: - multimon_ng = subprocess.Popen("multimon-ng "+str(demodulation)+" -f alpha -t raw /dev/stdin - ", - stdin=rtl_fm.stdout, - stdout=subprocess.PIPE, - stderr=open(script_path+"/log/log_mon.txt","a"), - shell=True) - except: - log("cannot start multimon-ng","error") + logging.debug("starting rtl_fm") +# 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(script_path+"/log/rtl_fm.log","a"), +# shell=True) +# except: +# logging.exception("cannot start rtl_fm") +# + logging.debug("starting multimon-ng") +# try: +# multimon_ng = subprocess.Popen("multimon-ng "+str(demodulation)+" -f alpha -t raw /dev/stdin - ", +# stdin=rtl_fm.stdout, +# stdout=subprocess.PIPE, +# stderr=open(script_path+"/log/multimon.log","a"), +# shell=True) +# except: +# logging.exception("cannot start multimon-ng") - log("start decoding") + logging.debug("start decoding") 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 - + #decoded = str(multimon_ng.stdout.readline()) #Get line data from multimon stdout + + #only for develop + decoded = "ZVEI2: 25832" + #decoded = "FMS: 43f314170000 (9=Rotkreuz 3=Bayern 1 Ort 0x25=037FZG 7141Status 3=Einsatz Ab 0=FZG->LST 2=III(mit NA,ohneSIGNAL)) CRC correct\n'" + time.sleep(1) + + 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 - #check FMS: -> check CRC -> validate -> check double alarm -> log -> (MySQL) + #check FMS: -> check CRC -> validate -> check double alarm -> log if "FMS:" in decoded: - log("recived FMS") + logging.debug("recieved FMS") fms_service = decoded[19] #Organisation fms_country = decoded[36] #Bundesland @@ -250,94 +228,48 @@ try: if "CRC correct" in decoded: #check CRC is correct fms_id = fms_service+fms_country+fms_location+fms_vehicle+fms_status+fms_direction #build FMS id if re.search("[0-9a-f]{8}[0-9a-f]{1}[01]{1}", fms_id): #if FMS is valid - if fms_id == fms_id_old and timestamp < fms_time_old + fms_double_ignore_time: #check for double alarm - log("FMS double alarm: "+fms_id_old) + if fms_id == fms_id_old and timestamp < fms_time_old + globals.config.getint("BOSWatch", "fms_double_ignore_time"): #check for double alarm + logging.warning("FMS double alarm: %s within %s second(s)", fms_id_old, timestamp-fms_time_old) fms_time_old = timestamp #in case of double alarm, fms_double_ignore_time set new else: - log("FMS:"+fms_id[0:8]+" Status:"+fms_status+" Richtung:"+fms_direction+" TKI:"+fms_tsi,"info") - fms_id_old = fms_id #save last id - fms_time_old = timestamp #save last time + logging.info("FMS:%s Status:%s Richtung:%s TKI:%s", fms_id[0:8], fms_status, fms_direction, fms_tsi) + data = {"fms":fms_id[0:8], "status":fms_status, "direction":fms_direction, "tki":fms_tsi} + throwAlarm("FMS",data) - if useMySQL: #only if MySQL is active - log("FMS to MySQL") - try: - connection = mysql.connector.connect(host = str(dbserver), user = str(dbuser), passwd = str(dbpassword), db = str(database)) - cursor = connection.cursor() - cursor.execute("INSERT INTO "+tableFMS+" (time,fms,status,direction,tsi) VALUES (%s,%s,%s,%s,%s)",(curtime(),fms_id[0:8],fms_status,fms_direction,fms_tsi)) - cursor.close() - connection.commit() - except: - log("FMS to MySQL failed","error") - finally: - connection.close() #Close connection in every case - - if useHTTPrequest: #only if HTTPrequest is active - log("FMS to HTTP") - try: - httprequest = httplib.HTTPConnection(url_fms) - httprequest.request("HEAD", "/") - httpresponse = httprequest.getresponse() - if str(httpresponse.status) == "200": #Check HTTP Response an print a Log or Error - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason)) - else: - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason),"error") - except: - log("FMS to HTTP failed","error") + fms_id_old = fms_id #save last id + fms_time_old = timestamp #save last time else: - log("No valid FMS: "+fms_id) + logging.warning("No valid FMS: %s", fms_id) else: - log("FMS CRC incorrect") - + logging.warning("FMS CRC incorrect") + #ZVEI Decoder Section - #check ZVEI: -> validate -> check double alarm -> log -> (MySQL) + #check ZVEI: -> validate -> check double alarm -> log if "ZVEI2:" in decoded: - log("recived ZVEI") - + logging.debug("recieved ZVEI") + zvei_id = decoded[7:12] #ZVEI Code if re.search("[0-9F]{5}", zvei_id): #if ZVEI is valid - if zvei_id == zvei_id_old and timestamp < zvei_time_old + zvei_double_ignore_time: #check for double alarm - log("ZVEI double alarm: "+zvei_id_old) + if zvei_id == zvei_id_old and timestamp < zvei_time_old + globals.config.getint("BOSWatch", "zvei_double_ignore_time"): #check for double alarm + logging.warning("ZVEI double alarm: %s within %s second(s)", zvei_id_old, timestamp-zvei_time_old) zvei_time_old = timestamp #in case of double alarm, zvei_double_ignore_time set new else: - log("5-Ton: "+zvei_id,"info") + logging.info("5-Ton: %s", zvei_id) + data = {"zvei":zvei_id} + throwAlarm("ZVEI",data) + zvei_id_old = zvei_id #save last id zvei_time_old = timestamp #save last time - - if useMySQL: #only if MySQL is active - log("ZVEI to MySQL") - try: - connection = mysql.connector.connect(host = str(dbserver), user = str(dbuser), passwd = str(dbpassword), db = str(database)) - cursor = connection.cursor() - cursor.execute("INSERT INTO "+tableZVEI+" (time,zvei) VALUES (%s,%s)",(curtime(),zvei_id)) - cursor.close() - connection.commit() - except: - log("ZVEI to MySQL failed","error") - finally: - connection.close() #Close connection in every case - - if useHTTPrequest: #only if HTTPrequest is active - log("ZVEI to HTTP") - try: - httprequest = httplib.HTTPConnection(url_zvei) - httprequest.request("HEAD", "/") - httpresponse = httprequest.getresponse() - if str(httpresponse.status) == "200": #Check HTTP Response an print a Log or Error - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason)) - else: - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason),"error") - except: - log("ZVEI to HTTP failed","error") else: - log("No valid ZVEI: "+zvei_id) + logging.warning("No valid ZVEI: %s", zvei_id) #POCSAG512 Decoder Section - #check POCSAG512: -> validate -> check double alarm -> log -> (MySQL) + #check POCSAG512: -> validate -> check double alarm -> log #POCSAG512: Address: 1234567 Function: 1 Alpha: XXMSG MEfeweffsjh if "POCSAG512:" in decoded: - log("recived POCSAG512") + logging.debug("recieved POCSAG512") poc_id = decoded[20:27] #POC Code poc_sub = decoded[39].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") @@ -347,54 +279,31 @@ try: poc_text = "" if re.search("[0-9]{7}", poc_id): #if POC is valid - if poc_id >= poc_filter_range_start: - if poc_id >= poc_filter_range_start: - if poc_id == poc_id_old and timestamp < poc_time_old + poc_double_ignore_time: #check for double alarm - log("POC512 double alarm: "+poc_id_old) + if poc_id >= globals.config.getint("BOSWatch", "poc_filter_range_start"): + if poc_id <= globals.config.getint("BOSWatch", "poc_filter_range_end"): + if poc_id == poc_id_old and timestamp < poc_time_old + globals.config.getint("BOSWatch", "poc_double_ignore_time"): #check for double alarm + logging.warning("POC512 double alarm: %s within %s second(s)", poc_id_old, timestamp-poc_time_old) poc_time_old = timestamp #in case of double alarm, poc_double_ignore_time set new else: - log("POCSAG512: "+poc_id+" "+poc_sub+" "+poc_text,"info") + logging.info("POCSAG512: %s %s %s ", poc_id, poc_sub, poc_text) + data = {"ric":poc_id, "function":poc_sub, "msg":poc_text} + throwAlarm("POC",data) + poc_id_old = poc_id #save last id - poc_time_old = timestamp #save last time - - if useMySQL: #only if MySQL is active - log("POC to MySQL") - try: - connection = mysql.connector.connect(host = str(dbserver), user = str(dbuser), passwd = str(dbpassword), db = str(database)) - cursor = connection.cursor() - cursor.execute("INSERT INTO "+tablePOC+" (time,ric,funktion,text) VALUES (%s,%s,%s,%s)",(curtime(),poc_id,poc_sub,poc_text,)) - cursor.close() - connection.commit() - except: - log("POC512 to MySQL failed","error") - finally: - connection.close() #Close connection in every case - - if useHTTPrequest: #only if HTTPrequest is active - log("POC512 to HTTP") - try: - httprequest = httplib.HTTPConnection(url_poc) - httprequest.request("HEAD", "/") - httpresponse = httprequest.getresponse() - if str(httpresponse.status) == "200": #Check HTTP Response an print a Log or Error - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason)) - else: - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason),"error") - except: - log("POCSAG512 to HTTP failed","error") + poc_time_old = timestamp #save last time else: - log("POCSAG512: "+poc_id+" out of filter range") + logging.warning("POCSAG512: %s out of filter range", poc_id) else: - log("POCSAG512: "+poc_id+" out of filter range") + logging.warning("POCSAG512: %s out of filter range", poc_id) else: - log("No valid POCSAG512: "+poc_id) + logging.warning("No valid POCSAG512: %s", poc_id) #POCSAG1200 Decoder Section - #check POCSAG1200: -> validate -> check double alarm -> log -> (MySQL) + #check POCSAG1200: -> validate -> check double alarm -> log #POCSAG1200: Address: 1234567 Function: 1 Alpha: XXMSG MEfeweffsjh if "POCSAG1200:" in decoded: - log("recived POCSAG1200") + logging.debug("recieved POCSAG1200") poc_id = decoded[21:28] #POC Code poc_sub = decoded[40].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") @@ -404,60 +313,37 @@ try: poc_text = "" if re.search("[0-9]{7}", poc_id): #if POC is valid - if poc_id >= poc_filter_range_start: - if poc_id >= poc_filter_range_start: - if poc_id == poc_id_old and timestamp < poc_time_old + poc_double_ignore_time: #check for double alarm - log("POC1200 double alarm: "+poc_id_old) + if poc_id >= globals.config.getint("BOSWatch", "poc_filter_range_start"): + if poc_id <= globals.config.getint("BOSWatch", "poc_filter_range_end"): + if poc_id == poc_id_old and timestamp < poc_time_old + globals.config.getint("BOSWatch", "poc_double_ignore_time"): #check for double alarm + logging.warning("POC1200 double alarm: %s within %s second(s)", poc_id_old, timestamp-poc_time_old) poc_time_old = timestamp #in case of double alarm, poc_double_ignore_time set new else: - log("POCSAG1200: "+poc_id+" "+poc_sub+" "+poc_text,"info") + logging.info("POCSAG1200: %s %s %s", poc_id, poc_sub, poc_text) + data = {"ric":poc_id, "function":poc_sub, "msg":poc_text} + throwAlarm("POC",data) + poc_id_old = poc_id #save last id - poc_time_old = timestamp #save last time - - if useMySQL: #only if MySQL is active - log("POC to MySQL") - try: - connection = mysql.connector.connect(host = str(dbserver), user = str(dbuser), passwd = str(dbpassword), db = str(database)) - cursor = connection.cursor() - cursor.execute("INSERT INTO "+tablePOC+" (time,ric,funktion,text) VALUES (%s,%s,%s,%s)",(curtime(),poc_id,poc_sub,poc_text,)) - cursor.close() - connection.commit() - except: - log("POC1200 to MySQL failed","error") - finally: - connection.close() #Close connection in every case - - if useHTTPrequest: #only if HTTPrequest is active - log("POC1200 to HTTP") - try: - httprequest = httplib.HTTPConnection(url_poc) - httprequest.request("HEAD", "/") - httpresponse = httprequest.getresponse() - if str(httpresponse.status) == "200": #Check HTTP Response an print a Log or Error - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason)) - else: - log("HTTP response: "+str(httpresponse.status)+" - "+str(httpresponse.reason),"error") - except: - log("POCSAG1200 to HTTP failed","error") + poc_time_old = timestamp #save last time else: - log("POCSAG1200: "+poc_id+" out of filter range") + logging.warning("POCSAG1200: %s out of filter range", poc_id) else: - log("POCSAG1200: "+poc_id+" out of filter range") + logging.warning("POCSAG1200: %s out of filter range", poc_id) else: - log("No valid POCSAG1200: "+poc_id) - + logging.warning("No valid POCSAG1200: %s", poc_id) + except KeyboardInterrupt: - log("Keyboard Interrupt","error") + logging.warning("Keyboard Interrupt") except: - log("unknown Error","error") + logging.exception("unknown error") finally: try: - rtl_fm.terminate() - log("rtl_fm terminated") - multimon_ng.terminate() - log("multimon-ng terminated") - log("exiting BOSWatch") +# rtl_fm.terminate() + logging.debug("rtl_fm terminated") +# multimon_ng.terminate() + logging.debug("multimon-ng terminated") + logging.debug("exiting BOSWatch") except: - log("failed in clean-up routine","error") + logging.exception("failed in clean-up routine") finally: exit(0) diff --git a/config/config.ini b/config/config.ini index 253da4e..5c7d780 100644 --- a/config/config.ini +++ b/config/config.ini @@ -2,28 +2,31 @@ # BOSWatch Config File # ######################## -[FMS] +[BOSWatch] #time to ignore same alarm in a row (sek) -double_ignore_time = 5 +fms_double_ignore_time = 5 -[ZVEI] #time to ignore same alarm in a row (sek) -double_ignore_time = 5 +zvei_double_ignore_time = 5 -[POC] #time to ignore same alarm in a row (sek) -double_ignore_time = 10 -filter_range_start = 0000000 -filter_range_end = 9999999 +poc_double_ignore_time = 10 +#start and end of the filter range +poc_filter_range_start = 0000000 +poc_filter_range_end = 9999999 + + +#can take on or off the plugins (0|1) +[Plugins] +MySQL = 0 +BosMon = 0 +# for developing template-module is enabled +template = 1 +#none has no function, only demo +none = 1 -#can take on or off the modules (0|1) -[Module] -useMySQL = 0 -useHTTPrequest = 0 -useBosMon = 0 [MySQL] -#Data for MySQL connection dbserver = localhost dbuser = root dbpassword = root @@ -34,8 +37,21 @@ tableFMS = bos_fms tableZVEI = bos_zvei tablePOC = bos_pocsag -[HTTPrequest] -#url without http:// ! -url_fms = www.google.de -url_zvei = www.google.de -url_poc = www.google.de + +[BosMon] +#Server as IP of DNS-Name (without http://) +#actually no ssl supported +bosmon_server = 192.168.0.1 +bosmon_port = 80 +#channel-name of typ "Web-Telegramm" +bosmon_channel = pocsag +#Use this, when BosMon has restricted access +bosmon_user = +bosmon_password = + + +[template] +data1 = test123 +data2 = test345 +data3 = test567 +data4 = test789 \ No newline at end of file diff --git a/plugin_test/globals.py b/globals.py similarity index 94% rename from plugin_test/globals.py rename to globals.py index f412ff6..c613da1 100644 --- a/plugin_test/globals.py +++ b/globals.py @@ -1,5 +1,5 @@ -#!/usr/bin/python -# -*- coding: cp1252 -*- - -#Global variables +#!/usr/bin/python +# -*- coding: cp1252 -*- + +#Global variables config = 0 \ No newline at end of file diff --git a/includes/__init__.py b/includes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/includes/decoder/__init__.py b/includes/decoder/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/includes/decoder/fms.py b/includes/decoder/fms.py new file mode 100644 index 0000000..e69de29 diff --git a/includes/decoder/poc.py b/includes/decoder/poc.py new file mode 100644 index 0000000..e69de29 diff --git a/includes/decoder/zvei.py b/includes/decoder/zvei.py new file mode 100644 index 0000000..e69de29 diff --git a/plugin_test/plugin_test.py b/plugin_test.py old mode 100755 new mode 100644 similarity index 100% rename from plugin_test/plugin_test.py rename to plugin_test.py diff --git a/plugin_test/boswatch.py b/plugin_test/boswatch.py deleted file mode 100644 index 62472a7..0000000 --- a/plugin_test/boswatch.py +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/python -# -*- coding: cp1252 -*- - -##### Info ##### -# BOSWatch -# Autor: Bastian Schroll -# Python Script to receive and decode German BOS Information with rtl_fm and multimon-NG -# For more Information see the README.md -##### Info ##### - -import globals # Global variables -import pluginloader - -import logging - -import argparse #for parse the args -import ConfigParser #for parse the config file -import re #Regex for validation -import os #for script path -import time #timestamp for doublealarm - -#create new logger -logger = logging.getLogger() -logger.setLevel(logging.DEBUG) -#set log string format -formatter = logging.Formatter('%(asctime)s - %(module)-15s [%(levelname)-8s] %(message)s', '%d.%m.%Y %H:%M:%S') -#create a file logger -fh = logging.FileHandler('log/boswatch.log', 'w') -fh.setLevel(logging.DEBUG) #log level >= Debug -fh.setFormatter(formatter) -logger.addHandler(fh) -#create a display logger -ch = logging.StreamHandler() -ch.setLevel(logging.INFO) #log level >= info -ch.setFormatter(formatter) -logger.addHandler(ch) - - -def throwAlarm(typ,data): - for i in pluginloader.getPlugins(): - plugin = pluginloader.loadPlugin(i) - logging.debug(i["name"] + " Plugin called") - plugin.run(typ,"0",data) - -# Programm -try: - - #first Clear the Logfiles for logging - try: - script_path = os.path.dirname(os.path.abspath(__file__)) - - if not os.path.exists(script_path+"/log/"): - os.mkdir(script_path+"/log/") - - bos_log = open(script_path+"/log/boswatch.log", "w") - rtl_log = open(script_path+"/log/rtl_fm.log", "w") - mon_log = open(script_path+"/log/multimon.log", "w") -# bos_log.write("##### "+curtime()+" #####\n\n") -# rtl_log.write("##### "+curtime()+" #####\n\n") -# mon_log.write("##### "+curtime()+" #####\n\n") - bos_log.close() - rtl_log.close() - mon_log.close() - logging.debug("BOSWatch has started") - except: - logging.exception("cannot clear Logfiles") - - try: - logging.debug("parse args") - #With -h or --help you get the Args help - #ArgsParser - 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") - #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") - parser.add_argument("-q", "--quiet", help="Shows no Information. Only Logfiles", action="store_true") - args = parser.parse_args() - except: - logging.exception("cannot parse args") - - #Read Data from Args, Put it into working Variables - freq = args.freq - device = args.device - error = args.error - squelch = args.squelch - - logging.debug(" - Frequency: %s", freq) - logging.debug(" - Device: %s", device) - logging.debug(" - PPM Error: %s", error) - logging.debug(" - Squelch: %s", squelch) - - demodulation = "" - if "FMS" in args.demod: - demodulation += "-a FMSFSK " - logging.debug(" - Demod: FMS") - if "ZVEI" in args.demod: - demodulation += "-a ZVEI2 " - logging.debug(" - Demod: ZVEI") - if "POC512" in args.demod: - demodulation += "-a POCSAG512 " - logging.debug(" - Demod: POC512") - if "POC1200" in args.demod: - demodulation += "-a POCSAG1200 " - logging.debug(" - Demod: P") - if "POC2400" in args.demod: - demodulation += "-a POCSAG2400 " - logging.debug(" - Demod: POC2400") - - logging.debug(" - Verbose Mode: %s", args.verbose) - logging.debug(" - Quiet Mode: %s", args.quiet) - - if args.verbose: - ch.setLevel(logging.DEBUG) - if args.quiet: - ch.setLevel(logging.CRITICAL) - - if not args.quiet: #only if not quiet mode - print " ____ ____ ______ __ __ __ " - print " / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ b" - print " / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ e" - print " / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / t" - print " /_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ a" - print " German BOS Information Script " - print " by Bastian Schroll " - print "" - - print "Frequency: "+freq - print "Device-ID: "+str(device) - print "Error in PPM: "+str(error) - print "Active Demods: "+str(len(args.demod)) - if "FMS" in args.demod: - print "- FMS" - if "ZVEI" in args.demod: - print "- ZVEI" - if "POC512" in args.demod: - print "- POC512" - if "POC1200" in args.demod: - print "- POC1200" - if "POC2400" in args.demod: - print "- POC2400" - print "Squelch: "+str(squelch) - if args.verbose: - print "Verbose Mode!" - print "" - - #variables pre-load - logging.debug("pre-load variables") - fms_id = 0 - fms_id_old = 0 - fms_time_old = 0 - - zvei_id = 0 - zvei_id_old = 0 - zvei_time_old = 0 - - poc_id = 0 - poc_id_old = 0 - poc_time_old = 0 - - - #ConfigParser - logging.debug("reading config file") - try: - globals.config = ConfigParser.ConfigParser() - globals.config.read(script_path+"/config/config.ini") - fms_double_ignore_time = int(globals.config.get("FMS", "double_ignore_time")) - zvei_double_ignore_time = int(globals.config.get("ZVEI", "double_ignore_time")) - poc_double_ignore_time = int(globals.config.get("POC", "double_ignore_time")) - poc_filter_range_start = int(globals.config.get("POC", "filter_range_start")) - poc_filter_range_end = int(globals.config.get("POC", "filter_range_end")) - except: - logging.exception("cannot read config file") - - #in case of reading error, set standard values - logging.debug("set to standard configuration") - fms_double_ignore_time = 5 - zvei_double_ignore_time = 5 - poc_double_ignore_time = 10 - poc_filter_range_start = 0000000 - poc_filter_range_end = 9999999 - finally: - logging.debug(" - fms_double_ignore_time = %s", fms_double_ignore_time) - logging.debug(" - zvei_double_ignore_time = %s", zvei_double_ignore_time) - logging.debug(" - poc_double_ignore_time = %s", poc_double_ignore_time) - logging.debug(" - poc_filter_range_start = %s", poc_filter_range_start) - logging.debug(" - poc_filter_range_end = %s", poc_filter_range_end) - - - logging.debug("starting rtl_fm") -# 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(script_path+"/log/rtl_fm.log","a"), -# shell=True) -# except: -# logging.exception("cannot start rtl_fm") -# - logging.debug("starting multimon-ng") -# try: -# multimon_ng = subprocess.Popen("multimon-ng "+str(demodulation)+" -f alpha -t raw /dev/stdin - ", -# stdin=rtl_fm.stdout, -# stdout=subprocess.PIPE, -# stderr=open(script_path+"/log/multimon.log","a"), -# shell=True) -# except: -# logging.exception("cannot start multimon-ng") - - - logging.debug("start decoding") - 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 - - #only for develop - #decoded = "ZVEI2: 25832" - decoded = "FMS: 43f314170000 (9=Rotkreuz 3=Bayern 1 Ort 0x25=037FZG 7141Status 3=Einsatz Ab 0=FZG->LST 2=III(mit NA,ohneSIGNAL)) CRC correct\n'" - time.sleep(1) - - - if True: #if input data avalable - - timestamp = int(time.time())#Get Timestamp - - #FMS Decoder Section - #check FMS: -> check CRC -> validate -> check double alarm -> log - if "FMS:" in decoded: - logging.debug("recieved FMS") - - 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 - - if "CRC correct" in decoded: #check CRC is correct - fms_id = fms_service+fms_country+fms_location+fms_vehicle+fms_status+fms_direction #build FMS id - if re.search("[0-9a-f]{8}[0-9a-f]{1}[01]{1}", fms_id): #if FMS is valid - if fms_id == fms_id_old and timestamp < fms_time_old + fms_double_ignore_time: #check for double alarm - logging.warning("FMS double alarm: %s within %s second(s)", fms_id_old, timestamp-fms_time_old) - fms_time_old = timestamp #in case of double alarm, fms_double_ignore_time set new - else: - logging.info("FMS:%s Status:%s Richtung:%s TKI:%s", fms_id[0:8], fms_status, fms_direction, fms_tsi) - data = {"fms":fms_id[0:8], "status":fms_status, "direction":fms_direction, "tki":fms_tsi} - throwAlarm("FMS",data) - - fms_id_old = fms_id #save last id - fms_time_old = timestamp #save last time - else: - logging.warning("No valid FMS: %s", fms_id) - else: - logging.warning("FMS CRC incorrect") - - - #ZVEI Decoder Section - #check ZVEI: -> validate -> check double alarm -> log - if "ZVEI2:" in decoded: - logging.debug("recieved ZVEI") - - zvei_id = decoded[7:12] #ZVEI Code - if re.search("[0-9F]{5}", zvei_id): #if ZVEI is valid - if zvei_id == zvei_id_old and timestamp < zvei_time_old + zvei_double_ignore_time: #check for double alarm - logging.warning("ZVEI double alarm: %s within %s second(s)", zvei_id_old, timestamp-zvei_time_old) - zvei_time_old = timestamp #in case of double alarm, zvei_double_ignore_time set new - else: - logging.info("5-Ton: %s", zvei_id) - data = {"zvei":zvei_id} - throwAlarm("ZVEI",data) - - zvei_id_old = zvei_id #save last id - zvei_time_old = timestamp #save last time - else: - logging.warning("No valid ZVEI: %s", zvei_id) - - - #POCSAG512 Decoder Section - #check POCSAG512: -> validate -> check double alarm -> log - #POCSAG512: Address: 1234567 Function: 1 Alpha: XXMSG MEfeweffsjh - if "POCSAG512:" in decoded: - logging.debug("recieved POCSAG512") - - poc_id = decoded[20:27] #POC Code - poc_sub = decoded[39].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") - if "Alpha:" in decoded: #check if there is a text message - poc_text = decoded.split('Alpha: ')[1].strip().rstrip('').strip() - else: - poc_text = "" - - if re.search("[0-9]{7}", poc_id): #if POC is valid - if poc_id >= poc_filter_range_start: - if poc_id >= poc_filter_range_start: - if poc_id == poc_id_old and timestamp < poc_time_old + poc_double_ignore_time: #check for double alarm - logging.warning("POC512 double alarm: %s within %s second(s)", poc_id_old, timestamp-poc_time_old) - poc_time_old = timestamp #in case of double alarm, poc_double_ignore_time set new - else: - logging.info("POCSAG512: %s %s %s ", poc_id, poc_sub, poc_text) - data = {"ric":poc_id, "function":poc_sub, "msg":poc_text} - throwAlarm("POC",data) - - poc_id_old = poc_id #save last id - poc_time_old = timestamp #save last time - else: - logging.warning("POCSAG512: %s out of filter range", poc_id) - else: - logging.warning("POCSAG512: %s out of filter range", poc_id) - else: - logging.warning("No valid POCSAG512: %s", poc_id) - - - #POCSAG1200 Decoder Section - #check POCSAG1200: -> validate -> check double alarm -> log - #POCSAG1200: Address: 1234567 Function: 1 Alpha: XXMSG MEfeweffsjh - if "POCSAG1200:" in decoded: - logging.debug("recieved POCSAG1200") - - poc_id = decoded[21:28] #POC Code - poc_sub = decoded[40].replace("3", "4").replace("2", "3").replace("1", "2").replace("0", "1") - if "Alpha:" in decoded: #check if there is a text message - poc_text = decoded.split('Alpha: ')[1].strip().rstrip('').strip() - else: - poc_text = "" - - if re.search("[0-9]{7}", poc_id): #if POC is valid - if poc_id >= poc_filter_range_start: - if poc_id >= poc_filter_range_start: - if poc_id == poc_id_old and timestamp < poc_time_old + poc_double_ignore_time: #check for double alarm - logging.warning("POC1200 double alarm: %s within %s second(s)", poc_id_old, timestamp-poc_time_old) - poc_time_old = timestamp #in case of double alarm, poc_double_ignore_time set new - else: - logging.info("POCSAG1200: %s %s %s", poc_id, poc_sub, poc_text) - data = {"ric":poc_id, "function":poc_sub, "msg":poc_text} - throwAlarm("POC",data) - - poc_id_old = poc_id #save last id - poc_time_old = timestamp #save last time - else: - logging.warning("POCSAG1200: %s out of filter range", poc_id) - else: - logging.warning("POCSAG1200: %s out of filter range", poc_id) - else: - logging.warning("No valid POCSAG1200: %s", poc_id) - -except KeyboardInterrupt: - logging.warning("Keyboard Interrupt") -except: - logging.exception("unknown error") -finally: - try: -# rtl_fm.terminate() - logging.debug("rtl_fm terminated") -# multimon_ng.terminate() - logging.debug("multimon-ng terminated") - logging.debug("exiting BOSWatch") - except: - logging.exception("failed in clean-up routine") - finally: - exit(0) diff --git a/plugin_test/config/config.ini b/plugin_test/config/config.ini deleted file mode 100644 index 3a966c8..0000000 --- a/plugin_test/config/config.ini +++ /dev/null @@ -1,43 +0,0 @@ -######################## -# BOSWatch Config File # -######################## - -[FMS] -#time to ignore same alarm in a row (sek) -double_ignore_time = 5 - -[ZVEI] -#time to ignore same alarm in a row (sek) -double_ignore_time = 5 - -[POC] -#time to ignore same alarm in a row (sek) -double_ignore_time = 10 -filter_range_start = 0000000 -filter_range_end = 9999999 - - -#can take on or off the modules (0|1) -[Module] -BosMon = 0 -# for developing template-module is enabled -template = 1 -none = 1 - -[BosMon] -#Server as IP of DNS-Name (without http://) -#actually no ssl supported -bosmon_server = 192.168.0.1 -bosmon_port = 80 -#channel-name of typ "Web-Telegramm" -bosmon_channel = pocsag -#Use this, when BosMon has restricted access -bosmon_user = -bosmon_password = - - -[template] -data1 = test123 -data2 = test345 -data3 = test567 -data4 = test789 \ No newline at end of file diff --git a/plugin_test/plugins/template/template.py b/plugin_test/plugins/template/template.py deleted file mode 100644 index 0cebb17..0000000 --- a/plugin_test/plugins/template/template.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/python -# -*- coding: cp1252 -*- - -import logging # Global logger -import globals # Global variables - -def run(typ,freq,data): - try: - logging.debug("read config file") - data1 = globals.config.get("template", "data1") - data2 = globals.config.get("template", "data2") - data3 = globals.config.get("template", "data3") - data4 = globals.config.get("template", "data4") - logging.debug(" - Data1: %s", data1) - logging.debug(" - Data2: %s", data2) - logging.debug(" - Data3: %s", data3) - logging.debug(" - Data4: %s", data4) - - if typ == "FMS": - logging.debug("FMS: %s Status: %s Dir: %s", data["fms"], data["status"], data["direction"]) - elif typ == "ZVEI": - logging.debug("ZVEI: %s", data["zvei"]) - elif typ == "POC": - logging.debug("POC: %s/%s - %s", data["ric"], data["function"], data["msg"]) - else: - logging.warning(typ + " not supportet") - - except: - logging.exception("unknown error") \ No newline at end of file diff --git a/plugin_test/pluginloader.py b/pluginloader.py similarity index 60% rename from plugin_test/pluginloader.py rename to pluginloader.py index 80bc996..06da4d3 100644 --- a/plugin_test/pluginloader.py +++ b/pluginloader.py @@ -10,26 +10,25 @@ PluginFolder = "./plugins" def getPlugins(): plugins = [] - possibleplugins = os.listdir(PluginFolder) - for i in possibleplugins: + for i in os.listdir(PluginFolder): location = os.path.join(PluginFolder, i) # plugins have to be a subdir with MainModule, if not skip if not os.path.isdir(location) or not i + ".py" in os.listdir(location): continue - logging.debug("found plugin: "+i) # is the plugin enabled in the config-file? try: - usePlugin = int(globals.config.get("Module", i)) + if globals.config.getint("Plugins", i): + info = imp.find_module(i, [location]) + plugins.append({"name": i, "info": info}) + logging.debug("Plugin [ENABLED ] %s", i) + else: + logging.debug("Plugin [DISABLED] %s ", i) except: #no entry for plugin found in config-file, skip - logging.warning("Plugin not in config: "+i) + logging.warning("Plugin [NO CONF ] %s", i) - logging.debug("use Plugin: "+str(usePlugin)) - if usePlugin: - info = imp.find_module(i, [location]) - plugins.append({"name": i, "info": info}) - logging.debug("append Plugin: "+i) return plugins def loadPlugin(plugin): + logging.debug("load Plugin: %s", plugin["name"]) return imp.load_module(plugin["name"], *plugin["info"]) \ No newline at end of file diff --git a/plugin_test/plugins/BosMon/BosMon.py b/plugins/BosMon/BosMon.py similarity index 70% rename from plugin_test/plugins/BosMon/BosMon.py rename to plugins/BosMon/BosMon.py index 315c110..df73f08 100644 --- a/plugin_test/plugins/BosMon/BosMon.py +++ b/plugins/BosMon/BosMon.py @@ -10,19 +10,15 @@ import base64 #for the HTTP request with User/Password def run(typ,freq,data): try: - #get BosMon-Config - logging.debug("read config file") - bosmon_server = globals.config.get("BosMon", "bosmon_server") - bosmon_port = globals.config.get("BosMon", "bosmon_port") - bosmon_user = globals.config.get("BosMon", "bosmon_user") - bosmon_password = globals.config.get("BosMon", "bosmon_password") - bosmon_channel = globals.config.get("BosMon", "bosmon_channel") - logging.debug(" - typ: %s", typ) - logging.debug(" - Server: %s", bosmon_server) - logging.debug(" - Port: %s", bosmon_port) - logging.debug(" - User: %s", bosmon_user) - logging.debug(" - Channel: %s", bosmon_channel) + #ConfigParser + logging.debug("reading config file") + try: + for key,val in globals.config.items("BOSWatch"): + logging.debug(" - %s = %s", key, val) + except: + logging.exception("cannot read config file") + if typ == "FMS": logging.warning("FMS not implemented") @@ -44,8 +40,8 @@ def run(typ,freq,data): headers['Content-type'] = "application/x-www-form-urlencoded" headers['Accept'] = "text/plain" if bosmon_user: - headers['Authorization'] = "Basic {0}".format(base64.b64encode("{0}:{1}".format(bosmon_user, bosmon_password))) - httprequest = httplib.HTTPConnection(bosmon_server, bosmon_port) + headers['Authorization'] = "Basic {0}".format(base64.b64encode("{0}:{1}".format(globals.config.get("BosMon", "bosmon_user"), globals.config.get("BosMon", "bosmon_password")))) + httprequest = httplib.HTTPConnection(globals.config.get("BosMon", "bosmon_server"), globals.config.get("BosMon", "bosmon_port")) httprequest.request("POST", "/telegramin/"+bosmon_channel+"/input.xml", params, headers) httpresponse = httprequest.getresponse() if str(httpresponse.status) == "200": #Check HTTP Response an print a Log or Error diff --git a/plugins/MySQL/MySQL.py b/plugins/MySQL/MySQL.py new file mode 100644 index 0000000..3d8a5d9 --- /dev/null +++ b/plugins/MySQL/MySQL.py @@ -0,0 +1,30 @@ +#!/usr/bin/python +# -*- coding: cp1252 -*- + +import logging # Global logger +import globals # Global variables + +def run(typ,freq,data): + try: + #ConfigParser + logging.debug("reading config file") + try: + for key,val in globals.config.items("BOSWatch"): + logging.debug(" - %s = %s", key, val) + except: + logging.exception("cannot read config file") + + if typ == "FMS": + #logging.debug("FMS: %s Status: %s Dir: %s", data["fms"], data["status"], data["direction"]) + logging.debug("FMS") + elif typ == "ZVEI": + #logging.debug("ZVEI: %s", data["zvei"]) + logging.debug("ZVEI") + elif typ == "POC": + #logging.debug("POC: %s/%s - %s", data["ric"], data["function"], data["msg"]) + logging.debug("POC") + else: + logging.warning(typ + " not supportet") + + except: + logging.exception("unknown error") \ No newline at end of file diff --git a/plugin_test/plugins/interface.txt b/plugins/interface.txt similarity index 65% rename from plugin_test/plugins/interface.txt rename to plugins/interface.txt index e03e8eb..cf0887e 100644 --- a/plugin_test/plugins/interface.txt +++ b/plugins/interface.txt @@ -1,8 +1,11 @@ Übergabe an Plugin: -typ = FMS, ZVEI oder POC -freq = Frequenz in Hz -data = {"KEY":"VALUE"} als Python Dict +typ = [FMS|ZVEI|POC] +freq = [FREQ(Hz)] +data = {"KEY1":"VALUE1","KEY2":"VALUE2"} als Python Dict + + +Follgende Daten sind bei der jeweiligen Alarm-Art enthalten: ZVEI: - zvei @@ -18,7 +21,9 @@ POCSAG: - function - msg + Es stehen folgende globale Objecte zur Verfügung: + 1.) import logging # Global logger logging - Object diff --git a/plugin_test/plugins/none/none.py b/plugins/none/none.py similarity index 100% rename from plugin_test/plugins/none/none.py rename to plugins/none/none.py diff --git a/plugins/not/not.py b/plugins/not/not.py new file mode 100644 index 0000000..dffa895 --- /dev/null +++ b/plugins/not/not.py @@ -0,0 +1,9 @@ +#!/usr/bin/python +# -*- coding: cp1252 -*- + +import logging # Global logger +import globals # Global variables + +def run(typ,freq,data): + logging.info("Nothing to do") + \ No newline at end of file diff --git a/plugins/template/template.py b/plugins/template/template.py new file mode 100644 index 0000000..5b70cba --- /dev/null +++ b/plugins/template/template.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +# -*- coding: cp1252 -*- + +import logging # Global logger +import globals # Global variables + +######### +# USAGE +# +# Config +# ====== +# to read a option from config File +# VALUE = globals.config.get("SECTION", "OPTION") +# +# Data from boswatch.py +# ===================== +# use data["KEY"] for Alarm Data from boswatch.py +# for usable KEYs in different Functions (FMS|ZVEI|POC) see interface.txt +# +# LOG Messages +# ============ +# send Log Messages with logging.LOGLEVEL("MESSAGE") +# usable Loglevels debug|info|warning|error|exception|critical +# if you use .exception in Try:Exception: Construct, it logs the Python EX.message too + +def run(typ,freq,data): + try: + #ConfigParser + logging.debug("reading config file") + try: + for key,val in globals.config.items("BOSWatch"): + logging.debug(" - %s = %s", key, val) + except: + logging.exception("cannot read config file") + + if typ == "FMS": + logging.debug(typ + " not supported") + elif typ == "ZVEI": + logging.debug(typ + " not supported") + elif typ == "POC": + logging.debug(typ + " not supported") + else: + logging.warning(typ + " not supported") + + except: + logging.exception("unknown error") \ No newline at end of file