new functionality: lookUp description in a given csv-file for FMS, ZVEI and POC

you have the possibility to set a discription for every FMS, ZWEI oder RIC address
descriptions will be imported via csv-files
if enabled BOSWatch will look up the description and could be used in the plugins

eMail-plugin extended wildcards to use describtion %DESC%
This commit is contained in:
JHCD 2015-06-05 21:49:51 +02:00
parent 300675a0e3
commit f1f6503198
12 changed files with 234 additions and 46 deletions

View file

@ -106,7 +106,7 @@ try:
myLogger = logging.getLogger()
myLogger.setLevel(logging.DEBUG)
#set log string format
formatter = logging.Formatter('%(asctime)s - %(module)-12s [%(levelname)-8s] %(message)s', '%d.%m.%Y %H:%M:%S')
formatter = logging.Formatter('%(asctime)s - %(module)-15s [%(levelname)-8s] %(message)s', '%d.%m.%Y %H:%M:%S')
#create a file logger
fh = MyTimedRotatingFileHandler(globals.script_path+"/log/boswatch.log", "midnight", interval=1, backupCount=999)
#Starts with log level >= Debug
@ -220,6 +220,13 @@ try:
from includes import filter
filter.loadFilters()
#
# Load description lists
#
if globals.config.getint("BOSWatch","useDescription"):
from includes import descriptionList
descriptionList.loadDescriptionLists()
try:
#
# Start rtl_fm

View file

@ -3,69 +3,86 @@
########################
[BOSWatch]
#set loglevel for logfile
#10 = debug
#20 = info
#30 = warning
#40 = error
#50 = critical
# set loglevel for logfile
# 10 = debug
# 20 = info
# 30 = warning
# 40 = error
# 50 = critical
loglevel = 10
#BOSWatch use a rotating logfile
#Rotating is at midnight
#You can set the backupCount here
#backupCount = 7 (keeps logfiles for a week)
# BOSWatch use a rotating logfile
# Rotating is at midnight
# You can set the backupCount here
# backupCount = 7 (keeps logfiles for a week)
backupCount = 7
#Using RegEx-Filter (0|1)
#Filter-configuration in section [Filters]
# Using RegEx-Filter (0|1)
# Filter-configuration in section [Filters]
useRegExFilter = 0
# Using Description (0|1)
# You have to be enabled it for every typ in the sections below too
useDescription = 0
[FMS]
#time to ignore same alarm in a row (sek)
# time to ignore same alarm in a row (sek)
double_ignore_time = 5
# look-up-table for adding a description
# turn on functionality (0|1)
idDescribed = 0
[ZVEI]
#time to ignore same alarm in a row (sek)
# time to ignore same alarm in a row (sek)
double_ignore_time = 5
# look-up-table for adding a description
# turn on functionality (0|1)
idDescribed = 0
[POC]
#time to ignore same alarm in a row (sek)
# time to ignore same alarm in a row (sek)
double_ignore_time = 5
#some very simple filters:
#Allow only this RICs (empty: allow all, separator ",")
#f.e.: allow_ric = 1234566,1234567,1234568
# some very simple filters:
# Allow only this RICs (empty: allow all, separator ",")
# f.e.: allow_ric = 1234566,1234567,1234568
allow_ric =
#Deny this RICs (empty: allow all, separator ",")
#f.e.: deny_ric = 1234566,1234567,1234568
# Deny this RICs (empty: allow all, separator ",")
# f.e.: deny_ric = 1234566,1234567,1234568
deny_ric =
#start and end of an allowed filter range
# start and end of an allowed filter range
filter_range_start = 0000000
filter_range_end = 9999999
# look-up-table for adding a description
# turn on functionality (0|1)
idDescribed = 0
[Filters]
#RegEX Filter Configuration
#http://www.regexr.com/ - RegEX Test Tool an Documentation
#No Filter for a Typ/Plugin Combination = all Data pass
#INDIVIDUAL_NAME = TYP;DATAFIELD;PLUGIN;FREQUENZ;REGEX
#TYP = the Data Typ (FMS|ZVEI|POC)
#DATAFIELD = the field of the Data Array (See interface.txt)
#PLUGIN = the name of the Plugin to call with this Filter (* for all)
#FREQUENZ = the Frequenz to use the Filter (for more SDR Sticks (* for all))
#REGEX = the RegEX
# RegEX Filter Configuration
# http://www.regexr.com/ - RegEX Test Tool an Documentation
# No Filter for a Typ/Plugin Combination = all Data pass
# INDIVIDUAL_NAME = TYP;DATAFIELD;PLUGIN;FREQUENZ;REGEX
# TYP = the Data Typ (FMS|ZVEI|POC)
# DATAFIELD = the field of the Data Array (See interface.txt)
# PLUGIN = the name of the Plugin to call with this Filter (* for all)
# FREQUENZ = the Frequenz to use the Filter (for more SDR Sticks (* for all))
# REGEX = the RegEX
#only ZVEI to all Plugins with 25### at 85.5MHz
# only ZVEI to all Plugins with 25### at 85.5MHz
#testfilter = ZVEI;zvei;*;85500000;25[0-9]{3}
#only POCSAG to MySQL with the text "ALARM:" in the Message
# only POCSAG to MySQL with the text "ALARM:" in the Message
#pocTest = POC;msg;MySQL;*;ALARM:
[Plugins]
#can take on or off the plugins (0|1)
# can take on or off the plugins (0|1)
MySQL = 0
httpRequest = 0
eMail = 0
@ -77,22 +94,23 @@ template = 0
[MySQL]
# MySQL configuration
dbserver = localhost
dbuser = root
dbpassword = root
database = boswatch
#tables in the database
# tables in the database
tableFMS = bos_fms
tableZVEI = bos_zvei
tablePOC = bos_pocsag
[httpRequest]
#URL without http://
# URL without http://
#you can use the following wildcards in your URL as GET params:
#http://en.wikipedia.org/wiki/Query_string
# you can use the following wildcards in your URL as GET params:
# http://en.wikipedia.org/wiki/Query_string
# %FMS% = FMS Code
# %STATUS% = FMS Status
@ -158,20 +176,21 @@ poc_message = %TIME%: %MSG%
[BosMon]
#Server as IP of DNS-Name (without http://)
#actually no ssl supported
# 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"
# channel-name of typ "Web-Telegramm"
bosmon_channel = channel
#Use this, when BosMon has restricted access
# Use this, when BosMon has restricted access
bosmon_user =
bosmon_password =
[firEmergency]
# firEmergency configuration
firserver = localhost
firport = 9001

10
csv/fms.csv Normal file
View file

@ -0,0 +1,10 @@
fms,description
#
# BOSWatch CSV file for describing FMS-Addresses
#
# For each FMS-Address you could set a description-text
# Use the structure: fms,"Description-Text"
#
# !!! DO NOT delete the first line !!!
#
93377141,"John Q. Publics car"
Can't render this file because it has a wrong number of fields in line 2.

10
csv/poc.csv Normal file
View file

@ -0,0 +1,10 @@
ric,description
#
# BOSWatch CSV file for describing POCSAG-Addresses
#
# For each RIC-Address you could set a description-text
# Use the structure: ric,"Description-Text"
#
# !!! DO NOT delete the first line !!!
#
1234567,"John Q. Public"
Can't render this file because it has a wrong number of fields in line 2.

10
csv/zvei.csv Normal file
View file

@ -0,0 +1,10 @@
zvei,description
#
# BOSWatch CSV file for describing ZVEI-Addresses
#
# For each ZVEI-Address you could set a description-text
# Use the structure: zvei,"Description-Text"
#
# !!! DO NOT delete the first line !!!
#
25832,"John Q. Public"
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -53,7 +53,12 @@ def decode(freq, decoded):
globals.fms_time_old = timestamp #in case of double alarm, fms_double_ignore_time set new
else:
logging.info("FMS:%s Status:%s Richtung:%s TSI:%s", fms_id[0:8], fms_status, fms_direction, fms_tsi)
data = {"fms":fms_id[0:8], "status":fms_status, "direction":fms_direction, "directionText":fms_directionText, "tsi":fms_tsi}
data = {"fms":fms_id[0:8], "status":fms_status, "direction":fms_direction, "directionText":fms_directionText, "tsi":fms_tsi, "description":fms_id[0:8]}
# If enabled, look up description
if globals.config.getint("FMS", "idDescribed"):
from includes import descriptionList
data["description"] = descriptionList.getDescription("FMS", fms_id[0:8])
# processing the alarm
from includes import alarmHandler
alarmHandler.processAlarm("FMS",freq,data)

View file

@ -110,9 +110,14 @@ def decode(freq, decoded):
globals.poc_time_old = timestamp
else:
logging.info("POCSAG%s: %s %s %s ", bitrate, poc_id, poc_sub, poc_text)
data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate}
data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate, "description":poc_id}
# Add function as character a-d to dataset
data["functionChar"] = data["function"].replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d")
# If enabled, look up description
if globals.config.getint("POC", "idDescribed"):
from includes import descriptionList
data["description"] = descriptionList.getDescription("POC", poc_id)
# processing the alarm
from includes import alarmHandler
alarmHandler.processAlarm("POC",freq,data)

View file

@ -44,7 +44,12 @@ def decode(freq, decoded):
globals.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}
data = {"zvei":zvei_id, "description":zvei_id}
# If enabled, look up description
if globals.config.getint("ZVEI", "idDescribed"):
from includes import descriptionList
data["description"] = descriptionList.getDescription("ZVEI", zvei_id)
# processing the alarm
from includes import alarmHandler
alarmHandler.processAlarm("ZVEI",freq,data)

102
includes/descriptionList.py Normal file
View file

@ -0,0 +1,102 @@
#!/usr/bin/python
# -*- coding: cp1252 -*-
"""
Function to expand the dataset with a description.
@author: Jens Herrmann
@requires: Configuration has to be set in the config.ini
"""
import logging # Global logger
import csv
from includes import globals # Global variables
##
#
# Local function will load the csv-file
#
def loadCSV(typ, idField):
"""
Local function for loading csv-file into python list
Structure: [id] = description
@return: Python list of descriptions
@exception: Exception if loading failed
"""
resultList = {}
try:
logging.debug("-- loading %s.csv", typ)
with open(globals.script_path+'/csv/'+typ+'.csv') as csvfile:
# DictReader expected structure described in first line of csv-file
reader = csv.DictReader(csvfile)
for row in reader:
logging.debug(row)
# only import rows with an integer as id
if row[idField].isdigit() == True:
resultList[row[idField]] = row['description']
logging.debug("-- loading csv finished")
except:
logging.exception("loading csvList for typ: %s failed", typ)
return resultList;
##
#
# call this for loading the description lists
#
def loadDescriptionLists():
"""
Load data from the csv-files in global description list for FMS, ZVEI and POCSAG
@return: nothing
@exception: Exception if loading failed
"""
try:
logging.debug("loading description lists")
if globals.config.getint("FMS", "idDescribed"):
logging.debug("- load FMS description list")
globals.fmsDescribtionList = loadCSV("fms", "fms")
if globals.config.getint("ZVEI", "idDescribed"):
logging.debug("- load ZVEI description list")
globals.zveiDescribtionList = loadCSV("zvei", "zvei")
if globals.config.getint("POC", "idDescribed"):
logging.debug("- load pocsag description list")
globals.ricDescribtionList = loadCSV("poc", "ric")
except:
logging.exception("cannot load description lists")
##
#
# public function for getting a description
#
def getDescription(typ, id):
"""
Get description for id.
Will return id if no description will be found.
@return: description as string
"""
resultStr = id;
logging.debug("look up description lists")
try:
if typ == "FMS":
resultStr = globals.fmsDescribtionList[id]
elif typ == "ZVEI":
resultStr = globals.zveiDescribtionList[id]
elif typ == "POC":
resultStr = globals.ricDescribtionList[id]
else:
logging.warning("Invalid Typ: %s", typ)
except KeyError:
# will be thrown when there is no description for the id
# -> nothing to do...
pass
return resultStr

View file

@ -26,4 +26,10 @@ poc_time_old = 0
pluginList = {}
#filter
filterList = []
filterList = []
#idDescribing
fmsDescribtionList = {}
zveiDescribtionList = {}
ricDescribtionList = {}

View file

@ -125,12 +125,14 @@ def run(typ,freq,data):
subject = subject.replace("%FMS%", data["fms"]).replace("%STATUS%", data["status"]) #replace Wildcards
subject = subject.replace("%DIR%", data["direction"]).replace("%DIRT%", data["directionText"]) #replace Wildcards
subject = subject.replace("%TSI%", data["tsi"]) #replace Wildcards
subject = subject.replace("%DESCR%", data["description"]) # replace Wildcards
subject = subject.replace("%TIME%", curtime()) # replace Wildcards
# read mailtext-structure from config.ini
mailtext = globals.config.get("eMail", "fms_message")
mailtext = mailtext.replace("%FMS%", data["fms"]).replace("%STATUS%", data["status"]) #replace Wildcards
mailtext = mailtext.replace("%DIR%", data["direction"]).replace("%DIRT%", data["directionText"]) #replace Wildcards
mailtext = mailtext.replace("%TSI%", data["tsi"]) #replace Wildcards
mailtext = mailtext.replace("%DESCR%", data["description"]) # replace Wildcards
mailtext = mailtext.replace("%TIME%", curtime()) # replace Wildcards
# send eMail
doSendmail(server, subject, mailtext)
@ -143,10 +145,12 @@ def run(typ,freq,data):
# read subject-structure from config.ini
subject = globals.config.get("eMail", "zvei_subject")
subject = subject.replace("%ZVEI%", data["zvei"]) #replace Wildcards
subject = subject.replace("%DESCR%", data["description"]) # replace Wildcards
subject = subject.replace("%TIME%", curtime()) # replace Wildcards
# read mailtext-structure from config.ini
mailtext = globals.config.get("eMail", "zvei_message")
mailtext = mailtext.replace("%ZVEI%", data["zvei"]) #replace Wildcards
mailtext = mailtext.replace("%DESCR%", data["description"]) # replace Wildcards
mailtext = mailtext.replace("%TIME%", curtime()) # replace Wildcards
# send eMail
doSendmail(server, subject, mailtext)
@ -161,12 +165,14 @@ def run(typ,freq,data):
subject = subject.replace("%RIC%", data["ric"]) #replace Wildcards
subject = subject.replace("%FUNC%", data["function"]).replace("%FUNCCHAR%", data["functionChar"]) #replace Wildcards
subject = subject.replace("%MSG%", data["msg"]).replace("%BITRATE%", str(data["bitrate"])) #replace Wildcards
subject = subject.replace("%DESCR%", data["description"]) # replace Wildcards
subject = subject.replace("%TIME%", curtime()) # replace Wildcards
# read mailtext-structure from config.ini
mailtext = globals.config.get("eMail", "poc_message")
mailtext = mailtext.replace("%RIC%", data["ric"]) #replace Wildcards
mailtext = mailtext.replace("%FUNC%", data["function"]).replace("%FUNCCHAR%", data["functionChar"]) #replace Wildcards
mailtext = mailtext.replace("%MSG%", data["msg"]).replace("%BITRATE%", str(data["bitrate"])) #replace Wildcards
mailtext = mailtext.replace("%DESCR%", data["description"]) # replace Wildcards
mailtext = mailtext.replace("%TIME%", curtime()) # replace Wildcards
# send eMail
doSendmail(server, subject, mailtext)

View file

@ -9,6 +9,7 @@ They can be used by their Index Names: data['OPTION']
ZVEI:
- zvei
- description
FMS:
- fms
@ -16,6 +17,7 @@ FMS:
- direction
- directionText
- tsi
- description
POCSAG:
- ric
@ -23,6 +25,7 @@ POCSAG:
- functionChar
- msg
- bitrate
- description
Global Objects: