diff --git a/boswatch.py b/boswatch.py index 8d316b6..76d8f99 100755 --- a/boswatch.py +++ b/boswatch.py @@ -287,6 +287,17 @@ try: logging.error("cannot load description lists") logging.debug("cannot load description lists", exc_info=True) + # + # Load location RegEx + # + try: + from includes import locationCoordinates + locationCoordinates.loadFilters() + except: + # It's an error, but we could work without that stuff... + logging.error("cannot load location regex") + logging.debug("cannot load location regex", exc_info=True) + # # Start rtl_fm # diff --git a/config/config.template.ini b/config/config.template.ini index e20a7eb..c097993 100644 --- a/config/config.template.ini +++ b/config/config.template.ini @@ -127,6 +127,23 @@ geo_enable = 0 geo_format = #C(\d{2})(\d{5}),(\d{2})(\d{5})# geo_order = LON, lon, LAT, lat +[LocationCoordinates] +# Regex Coordinate replacement (only for POC) +# All fields in data structure can be used, also dynamically added fields that have been evaluated in "schemaPOCMsg". +# Multiple search criteria can be given, then all of them must be hit (AND-condition). +# Coordinates must be the last field, consisting of latitude and longitude (order is important), split by comma. +# First match has priority; search will not proceed as soon as one hit is found. +# Important: Semicolon and comma must not be part of a field or regex, as they are used internally for splitting up the config value correctly. +#LocationName = field1;regex1;...;lat, lon + +# Examples: +# msg starting with "BOSWatch-Test" +Location1 = msg;^BOSWatch-Test;49.344394413024084, 8.167496841047555 +# Objekt containing "VS Wachtenburg" +Location2 = Objekt;VS Wachtenburg;49.437673, 8.173793 +# Ort starting with "B9 ", Ortsteil starting with "16 AK " +B9_16 = Ort;^B9 .*$;Ortsteil;^16 AK .*$;49.428685, 8.408548 + [multicastAlarm] # Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). diff --git a/includes/decoders/poc.py b/includes/decoders/poc.py index bf906fd..d51e7d0 100644 --- a/includes/decoders/poc.py +++ b/includes/decoders/poc.py @@ -15,6 +15,7 @@ import re # Regex for validation from includes import globalVars # Global variables from includes import doubleFilter # double alarm filter +from includes import locationCoordinates ## # @@ -161,6 +162,9 @@ def decode(freq, decoded): if has_geo == True: data["lon"] = lon data["lat"] = lat + else: + locationCoordinates.findCoordinates(data) + # Add function as character a-d to dataset data["functionChar"] = data["function"].replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d") data["ricFuncChar"] = data["ric"] + data["functionChar"] diff --git a/includes/locationCoordinates.py b/includes/locationCoordinates.py new file mode 100644 index 0000000..d9c6e52 --- /dev/null +++ b/includes/locationCoordinates.py @@ -0,0 +1,77 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Functions for the location RegEX + +@author: Marco Schotthöfer + +@requires: Configuration has to be set in the config.ini +""" + +import logging # Global logger +import re #Regex for Filter Check + +from includes import globalVars # Global variables + +# local variables +filterList = [] + + +def loadFilters(): + try: + logging.debug("Loading Location Coordinates") + + for key,val in globalVars.config.items("LocationCoordinates"): + logging.debug(" - %s = %s", key, val) + filterData = val.split(";") + + # at least 3 items needed (field1;pattern1;lat,lon), and in any case an uneven count of items + if len(filterData) < 3 and len(filterData) % 2 == 0: + logging.debug("Invalid argument count; skipping") + else: + # first store all regular expressions in list + filterItem = [] + i = 0 + + while i < len(filterData) - 2: + filterItem.append({"field": filterData[i], "pattern": filterData[i+1]}) + + # step to next field + i += 2 + # then transfer to filterList; include coordinates + filterList.append({"name": key, "filterItem": filterItem, "coordinates": filterData[len(filterData) - 1]}) + except: + logging.error("cannot read config file") + logging.debug("cannot read config file", exc_info=True) + return + +def findCoordinates(data): + try: + logging.debug("Find coordinates") + for i in filterList: + logging.debug("Filter: " + str(i)) + regexMatch = True + for k in i["filterItem"]: + logging.debug("Pattern : " + str(k)) + if k["field"] not in data.keys(): + logging.debug("field " + k["field"] + " not in data structure, hence no match") + regexMatch = False + break + else: + if (k["field"] and not re.search(k["pattern"], data.get(k["field"]))): + logging.debug("No match") + regexMatch = False + if regexMatch: + coordinatesString = i["coordinates"] + logging.debug("Coordinate String: " + coordinatesString) + coordinatesList = coordinatesString.replace(" ", "").split(",") + if len(coordinatesList) == 2: + data["lat"] = coordinatesList[0] + data["lon"] = coordinatesList[1] + data["has_geo"] = True + logging.info("Coordinates found!") + break + except: + logging.error("cannot read config file") + logging.debug("cannot read config file", exc_info=True)