Merge branch 'master' into update_check

This commit is contained in:
Bastian Schroll 2020-04-13 21:52:39 +02:00 committed by GitHub
commit 64c8b5ab36
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 464 additions and 50 deletions

View file

@ -52,51 +52,53 @@ def replaceWildcards(message, bwPacket):
# info wildcards
# server
"{SNAME}": bwPacket.getField("serverName"),
"{SVERS}": bwPacket.getField("serverVersion"),
"{SDATE}": bwPacket.getField("serverBuildDate"),
"{SBRCH}": bwPacket.getField("serverBranch"),
"{SNAME}": bwPacket.get("serverName"),
"{SVERS}": bwPacket.get("serverVersion"),
"{SDATE}": bwPacket.get("serverBuildDate"),
"{SBRCH}": bwPacket.get("serverBranch"),
# client
"{CNAME}": bwPacket.getField("clientName"),
"{CIP}": bwPacket.getField("clientIP"),
"{CVERS}": bwPacket.getField("clientVersion"),
"{CDATE}": bwPacket.getField("clientBuildDate"),
"{CBRCH}": bwPacket.getField("clientBranch"),
"{CNAME}": bwPacket.get("clientName"),
"{CIP}": bwPacket.get("clientIP"),
"{CVERS}": bwPacket.get("clientVersion"),
"{CDATE}": bwPacket.get("clientBuildDate"),
"{CBRCH}": bwPacket.get("clientBranch"),
# boswatch wildcards
"{INSRC}": bwPacket.getField("mode"),
"{TIMES}": bwPacket.getField("mode"),
"{FREQ}": bwPacket.getField("frequency"),
"{MODE}": bwPacket.getField("mode"),
"{INSRC}": bwPacket.get("inputSource"),
"{TIMES}": bwPacket.get("timestamp"),
"{FREQ}": bwPacket.get("frequency"),
"{MODE}": bwPacket.get("mode"),
# fms wildcards
"{FMS}": bwPacket.getField("fms"),
"{SERV}": bwPacket.getField("service"),
"{COUNT}": bwPacket.getField("country"),
"{LOC}": bwPacket.getField("location"),
"{VEHC}": bwPacket.getField("vehicle"),
"{STAT}": bwPacket.getField("status"),
"{DIR}": bwPacket.getField("direction"),
"{DIRT}": bwPacket.getField("dirextionText"),
"{TACI}": bwPacket.getField("tacticalInfo"),
"{FMS}": bwPacket.get("fms"),
"{SERV}": bwPacket.get("service"),
"{COUNT}": bwPacket.get("country"),
"{LOC}": bwPacket.get("location"),
"{VEHC}": bwPacket.get("vehicle"),
"{STAT}": bwPacket.get("status"),
"{DIR}": bwPacket.get("direction"),
"{DIRT}": bwPacket.get("directionText"),
"{TACI}": bwPacket.get("tacticalInfo"),
# pocsag wildcards
"{BIT}": bwPacket.getField("bitrate"),
"{RIC}": bwPacket.getField("ric"),
"{SRIC}": bwPacket.getField("subric"),
"{SRICT}": bwPacket.getField("subricText"),
"{MSG}": bwPacket.getField("message"),
"{BIT}": bwPacket.get("bitrate"),
"{RIC}": bwPacket.get("ric"),
"{SRIC}": bwPacket.get("subric"),
"{SRICT}": bwPacket.get("subricText"),
"{MSG}": bwPacket.get("message"),
# zvei wildcards
"{TONE}": bwPacket.getField("tone"),
"{TONE}": bwPacket.get("tone"),
# message for MSG packet is done in poc
}
for wildcard, field in _wildcards.items():
message = message.replace(wildcard, field)
if field is not None:
message = message.replace(wildcard, field)
for wildcard, field in _additionalWildcards.items():
message = message.replace(wildcard, bwPacket.getField(field))
if field is not None:
message = message.replace(wildcard, bwPacket.get(field))
return message

View file

@ -47,5 +47,5 @@ Ein BOSWatch Datenpaket wird in einem Python Dict abgebildet. In der nachfolgend
|vehicle|X||||`{VEC}`||
|status|X||||`{STAT}`||
|direction|X||||`{DIR}`||
|dirextionText|X||||`{DIRT}`|(Fhz->Lst, Lst->Fhz)|
|directionText|X||||`{DIRT}`|(Fhz->Lst, Lst->Fhz)|
|tacticalInfo|X||||`{TACI}`|(I, II, III, IV)|

View file

@ -4,11 +4,16 @@
## Beschreibung
Mit diesem Modul können einem Alarmpaket beliebige Beschreibungen in Abhänigkeit der enthaltenen Informationen hinzugefügt werden.
## Unterstütze Alarmtypen
- Fms
- Pocsag
- Zvei
- Msg
## Resource
`descriptor`
## Konfiguration
Informationen zum Aufbau eines [BOSWatch Pakets](../develop/packet.md)
|Feld|Beschreibung|Default|
@ -19,7 +24,6 @@ Informationen zum Aufbau eines [BOSWatch Pakets](../develop/packet.md)
|descriptions|Liste der Beschreibungen||
#### `descriptions:`
|Feld|Beschreibung|Default|
|----|------------|-------|
|for|Inhalt im `scanField` auf welchem geprüft werden soll||
@ -50,17 +54,18 @@ Informationen zum Aufbau eines [BOSWatch Pakets](../develop/packet.md)
```
---
## Abhängigkeiten
## Modul Abhängigkeiten
- keine
---
## Externe Abhängigkeiten
- keine
---
## Paket Modifikationen
- Wenn im Paket das Feld `scanField` vorhanden ist, wird das Feld `descrField` dem Paket hinzugefügt
- Wenn keine Beschreibung vorhanden ist, wird im Feld `descrField` der Inhalt des Feldes `scanField` hinterlegt
---
## Zusätzliche Wildcards
- Von der Konfiguration abhängig
- Von der Konfiguration abhängig

View file

@ -0,0 +1,55 @@
# <center>Geocoding</center>
---
## Beschreibung
Mit diesem Modul können einem Paket die Koordinaten eines Ortes oder einer Adresse angefügt werden.
## Unterstützte Alarmtypen
- Pocsag
## Resource
`geocoding`
## Konfiguration
|Feld|Beschreibung|Default|
|----|------------|-------|
apiProvider|Der Provider für das Geocoding|
apiToken|Der Api-Token fuer die Geocoding-Api|
geoRegex|Regex Capture-Group zum Herausfiltern der Adresse|
#### Verfügbare Geocoding Provider
|Name|Einstellungswert|
|----|------------|
|Mapbox|mapbox|
|Google Maps|google|
**Beispiel:**
```yaml
- type: module
name: Geocoding Module
res: geocoding
config:
apiProvider: "{{ Provider für Geocoding }}"
apiToken: "{{ API-Key für Provider }}"
regex: "((?:[^ ]*,)*?)"
```
---
## Modul Abhängigkeiten
- keine
---
## Externe Abhängigkeiten
- geocoder
---
## Paket Modifikationen
- `address`: gefundene Adresse
- `lat`: Latitude der Adresse
- `lon`: Longitude der Adresse
---
## Zusätzliche Wildcards
- `{ADDRESS}`: gefundene Adresse
- `{LAT}`: Latitude der Adresse
- `{LON}`: Longitude der Adresse

View file

@ -4,11 +4,16 @@
## Beschreibung
Mit diesem Modul ist es möglich, die Pakete auf bestimmte Modes (FMS, POCSAG, ZVEI) zu Filtern. Je nach Konfiguration werden Pakete eines bestimmten Modes im aktuellen Router weitergeleitet oder verworfen.
## Unterstütze Alarmtypen
- Fms
- Pocsag
- Zvei
- Msg
## Resource
`filter.modeFilter`
## Konfiguration
|Feld|Beschreibung|Default|
|----|------------|-------|
|allowed|Liste der erlaubten Paket Typen `fms` `zvei` `pocsag` `msg`||
@ -24,16 +29,18 @@ Mit diesem Modul ist es möglich, die Pakete auf bestimmte Modes (FMS, POCSAG, Z
```
---
## Abhängigkeiten
## Modul Abhängigkeiten
- keine
---
## Externe Abhängigkeiten
- keine
---
## Paket Modifikationen
- keine
---
## Zusätzliche Wildcards
- keine

View file

@ -15,18 +15,22 @@ Folgendes gilt:
Vereinfacht kann man sagen, dass einzelnen Router ODER-verknüpft und die jeweiligen Checks UND-verknüpft sind.
## Unterstütze Alarmtypen
- Fms
- Pocsag
- Zvei
- Msg
## Resource
`filter.regexFilter`
## Konfiguration
|Feld|Beschreibung|Default|
|----|------------|-------|
|name|Beliebiger Name des Filters||
|checks|Liste der einzelnen Checks innerhalb des Filters||
#### `checks:`
|Feld|Beschreibung|Default|
|----|------------|-------|
|field|Name des Feldes innerhalb des BOSWatch Pakets welches untersucht werden soll||
@ -50,16 +54,17 @@ Vereinfacht kann man sagen, dass einzelnen Router ODER-verknüpft und die jeweil
```
---
## Abhängigkeiten
## Modul Abhängigkeiten
- keine
---
## Externe Abhängigkeiten
- keine
---
## Paket Modifikationen
- keine
---
## Zusätzliche Wildcards
- keine
- keine

45
docu/docs/plugin/http.md Normal file
View file

@ -0,0 +1,45 @@
# <center>Http</center>
---
## Beschreibung
Mit diesem Plugin ist es moeglich, Http-Anfragen für Alarmierungen zu senden.
Wildcards in den Urls werden automatisch ersetzt.
## Unterstütze Alarmtypen
- Fms
- Pocsag
- Zvei
- Msg
## Resource
`http`
## Konfiguration
|Feld|Beschreibung|Default|
|----|------------|-------|
|fms|Liste mit Urls für Fms-Alarmierung||
|pocsag|Liste mit Urls für Pocsag-Alarmierung||
|zvei|Liste mit Urls für Zvei-Alarmierung||
|msg|Liste mit Urls für Msg-Alarmierung||
**Beispiel:**
```yaml
- type: plugin
name: HTTP Plugin
res: http
config:
pocsag:
- "http://google.com?q={MSG}"
- "http://duckduckgo.com?q={MSG}"
fms:
- "http://duckduckgo.com?q={LOC}"
```
---
## Modul Abhängigkeiten
- keine
---
## Externe Abhängigkeiten
- asyncio
- aiohttp

View file

@ -0,0 +1,43 @@
# <center>Telegram</center>
---
## Beschreibung
Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden.
Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket definiert sind. (beispielsweise durch das [Geocoding](../modul/geocoding.md) Modul)
## Unterstütze Alarmtypen
- Pocsag
## Resource
`telegram`
## Konfiguration
|Feld|Beschreibung|Default|
|----|------------|-------|
|message|Format der Nachricht||
|botToken|Der Api-Key des Telegram-Bots||
|chatIds|Liste mit Chat-Ids der Empfängers / der Emfänger-Gruppen||
**Beispiel:**
```yaml
- type: plugin
name: Telegram Plugin
res: telegram
config:
message: "{RIC}({SRIC})\n{MSG}"
botToken: "{{ Telegram Bot Token }}"
chatIds:
- "{{ Telegram Chat Id }}"
```
---
## Modul Abhängigkeiten
Aus dem Modul [Geocoding](../modul/geocoding.md) (optional):
- `lat`
- `lon`
---
## Externe Abhängigkeiten
- python-telegram-bot

View file

@ -18,10 +18,13 @@ nav:
- Routing Mechanismus: information/router.md
- Changelog: changelog.md
- Module:
- Descriptor: modul/descriptor.md
- Geocoding: modul/geocoding.md
- Mode Filter: modul/mode_filter.md
- Regex Filter: modul/regex_filter.md
- Descriptor: modul/descriptor.md
- Plugins: tbd.md
- Plugins:
- Http: plugin/http.md
- Telegram: plugin/telegram.md
- Entwickler:
- Eigenes Modul/Plugin schreiben: develop/ModulPlugin.md
- BOSWatch Alarmpaket Format: develop/packet.md

80
module/geocoding.py Normal file
View file

@ -0,0 +1,80 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""!
____ ____ ______ __ __ __ _____
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
German BOS Information Script
by Bastian Schroll
@file: geocoding.py
@date: 22.02.2020
@author: Jan Speller
@description: Geocoding Module
"""
import logging
from module.moduleBase import ModuleBase
# ###################### #
# Custom plugin includes #
import geocoder
import re
# ###################### #
logging.debug("- %s loaded", __name__)
class BoswatchModule(ModuleBase):
"""!Description of the Module"""
def __init__(self, config):
"""!Do not change anything here!"""
super().__init__(__name__, config) # you can access the config class on 'self.config'
def doWork(self, bwPacket):
"""!start an run of the module.
@param bwPacket: A BOSWatch packet instance"""
if bwPacket.get("mode") == "pocsag":
self.geocode(bwPacket)
return bwPacket
def geocode(self, bwPacket):
"""!find address in message and get latitude and longitude
@param bwPacket: A BOSWatch packet instance"""
try:
addressArray = re.search(self.config.get("regex"), bwPacket.get("message"))
provider = self.config.get("apiProvider")
if addressArray[1] is None:
logging.info("No address found, skipping geocoding")
return bwPacket
address = addressArray[1]
bwPacket.set("address", address)
self.registerWildcard("{ADDRESS}", "address")
logging.info("Found address: '" + address + "' in packet")
if "mapbox" == provider:
logging.info("Using Mapbox as provider")
g = geocoder.mapbox(address, key=self.config.get("apiToken"))
elif "google" == provider:
logging.info("Using Google as provider")
g = geocoder.google(address, key=self.config.get("apiToken"))
else:
return bwPacket
(lat, lon) = g.latlng
logging.info("Found following coordinates for address: [lat=" + str(lat) + ", lon=" + str(lon) + "]")
bwPacket.set("lat", lat)
bwPacket.set("lon", lon)
self.registerWildcard("{LAT}", "lat")
self.registerWildcard("{LON}", "lon")
return bwPacket
except Exception as e:
logging.exception("Unknown Error while executing geocoding module: " + str(type(e).__name__) + ": " + str(e))
return bwPacket

100
plugin/http.py Normal file
View file

@ -0,0 +1,100 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""!
____ ____ ______ __ __ __ _____
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
German BOS Information Script
by Bastian Schroll
@file: http.py
@date: 23.02.2020
@author: Jan Speller
@description: Http Plugin
"""
import logging
from plugin.pluginBase import PluginBase
# ###################### #
# Custom plugin includes #
import asyncio
from aiohttp import ClientSession
# ###################### #
logging.debug("- %s loaded", __name__)
class BoswatchPlugin(PluginBase):
"""!Description of the Plugin"""
def __init__(self, config):
"""!Do not change anything here!"""
super().__init__(__name__, config) # you can access the config class on 'self.config'
def fms(self, bwPacket):
"""!Called on FMS alarm
@param bwPacket: bwPacket instance
Remove if not implemented"""
urls = self.config.get("fms")
self.makeRequests(urls)
def pocsag(self, bwPacket):
"""!Called on POCSAG alarm
@param bwPacket: bwPacket instance
Remove if not implemented"""
urls = self.config.get("pocsag")
self.makeRequests(urls)
def zvei(self, bwPacket):
"""!Called on ZVEI alarm
@param bwPacket: bwPacket instance
Remove if not implemented"""
urls = self.config.get("zvei")
self.makeRequests(urls)
def msg(self, bwPacket):
"""!Called on MSG packet
@param bwPacket: bwPacket instance
Remove if not implemented"""
urls = self.config.get("msg")
self.makeRequests(urls)
def makeRequests(self, urls):
"""Parses wildcard urls and handles asynchronus requests
@param urls: array of urls"""
urls = [self.parseWildcards(url) for url in urls]
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(self.asyncRequests(urls))
loop.run_until_complete(future)
async def asyncRequests(self, urls):
"""Handles asynchronus requests
@param urls: array of urls to send requests to"""
tasks = []
async with ClientSession() as session:
for url in urls:
task = asyncio.ensure_future(self.fetch(url, session))
tasks.append(task)
responses = asyncio.gather(*tasks)
await responses
async def fetch(self, url, session):
"""Fetches requests
@param url: url
@param session: Clientsession instance"""
async with session.get(url) as response:
logging.info("{} returned [{}]".format(response.url, response.status))
return await response.read()

View file

@ -189,4 +189,4 @@ class PluginBase(ABC):
if self._bwPacket is None:
logging.warning("wildcard replacing not allowed - no bwPacket set")
return msg
return wildcard.replaceWildcards(self._bwPacket, msg)
return wildcard.replaceWildcards(msg, self._bwPacket)

66
plugin/telegram.py Normal file
View file

@ -0,0 +1,66 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""!
____ ____ ______ __ __ __ _____
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
German BOS Information Script
by Bastian Schroll
@file: telegram.py
@date: 20.02.2020
@author: Jan Speller
@description: Telegram Plugin
"""
import logging
from plugin.pluginBase import PluginBase
# ###################### #
# Custom plugin includes #
from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, NetworkError)
import telegram
# ###################### #
logging.debug("- %s loaded", __name__)
class BoswatchPlugin(PluginBase):
"""!Description of the Plugin"""
def __init__(self, config):
"""!Do not change anything here!"""
super().__init__(__name__, config) # you can access the config class on 'self.config'
def onLoad(self):
"""!Called by import of the plugin"""
self.bot = telegram.Bot(token=self.config.get("botToken", default=""))
def pocsag(self, bwPacket):
"""!Called on POCSAG alarm
@param bwPacket: bwPacket instance"""
msg = self.parseWildcards(self.config.get("message"))
if bwPacket.get("lat") is not None and bwPacket.get("lon") is not None:
logging.debug("Found coordinates in packet")
(lat, lon) = (bwPacket.get("lat"), bwPacket.get("lon"))
for chatId in self.config.get("chatIds", default=[]):
try:
# Send Message via Telegram
logging.info("Sending message to " + chatId)
self.bot.send_message(chat_id=chatId, text=msg)
# Send Location via Telegram if lat and lon are defined
if lat is not None and lon is not None:
logging.info("Sending location to " + chatId)
self.bot.sendLocation(chat_id=chatId, latitude=lat, longitude=lon)
except Unauthorized:
logging.exception("Error while sending Telegram Message, please Check your api-key")
except (TimedOut, NetworkError):
logging.exception("Error while sending Telegram Message, please Check your connectivity")
except (BadRequest, TelegramError):
logging.exception("Error while sending Telegram Message")
except Exception as e:
logging.exception("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e))

3
pytest.sh Normal file
View file

@ -0,0 +1,3 @@
source ./venv/bin/activate
pytest -c test/pytest.ini
deactivate