diff --git a/.github/workflows/run_pytest.yml b/.github/workflows/run_pytest.yml index 69d1a7d..9ed7032 100644 --- a/.github/workflows/run_pytest.yml +++ b/.github/workflows/run_pytest.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9, 3.10.2] runs-on: ${{matrix.os}} steps: diff --git a/Dockerfile b/Dockerfile index 36568ce..8ac0c9f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.10 AS build-base +FROM alpine:3.13 AS build-base RUN apk add git make cmake g++ libusb-dev libpulse FROM build-base AS rtl_fm @@ -8,18 +8,18 @@ WORKDIR /opt/rtl_sdr/build RUN cmake .. && make FROM build-base AS multimon -ARG MULTIMON_VERSION=1.1.8 +ARG MULTIMON_VERSION=1.1.9 RUN git clone --depth 1 --branch ${MULTIMON_VERSION} https://github.com/EliasOenal/multimon-ng.git /opt/multimon WORKDIR /opt/multimon/build RUN cmake .. && make -FROM alpine:3.10 AS boswatch +FROM alpine:3.13 AS boswatch ARG BW_VERSION=develop RUN apk add git && \ git clone --depth 1 --branch ${BW_VERSION} https://github.com/BOSWatch/BW3-Core.git /opt/boswatch -FROM python:3.6-alpine AS runner +FROM python:3.9.1-alpine AS runner LABEL maintainer="bastian@schroll-software.de" # for RTL for MM @@ -27,5 +27,5 @@ RUN apk add libusb-dev libpulse && \ pip3 install pyyaml COPY --from=boswatch /opt/boswatch/ /opt/boswatch/ -COPY --from=multimon /opt/multimon/build/multimon-ng /opt/multimon/multimon-ng -COPY --from=rtl_fm /opt/rtl_sdr/build/src/ /opt/rtl_sdr/build/src/ \ No newline at end of file +COPY --from=multimon /opt/multimon/build/multimon-ng /opt/multimon-ng +COPY --from=rtl_fm /opt/rtl_sdr/build/src/ /opt/rtl_sdr diff --git a/boswatch/inputSource/sdrInput.py b/boswatch/inputSource/sdrInput.py index 6b1faf7..3fa2af3 100644 --- a/boswatch/inputSource/sdrInput.py +++ b/boswatch/inputSource/sdrInput.py @@ -36,6 +36,8 @@ class SdrInput(InputBase): sdrProc.addArgument("-p " + str(sdrConfig.get("error", default="0"))) # frequency error in ppm sdrProc.addArgument("-l " + str(sdrConfig.get("squelch", default="1"))) # squelch sdrProc.addArgument("-g " + str(sdrConfig.get("gain", default="100"))) # gain + if (sdrConfig.get("fir_size", default=None) is not None): + sdrProc.addArgument("-F " + str(sdrConfig.get("fir_size"))) # fir_size sdrProc.addArgument("-M fm") # set mode to fm sdrProc.addArgument("-E DC") # set DC filter sdrProc.addArgument("-s 22050") # bit rate of audio stream diff --git a/boswatch/router/routerManager.py b/boswatch/router/routerManager.py index cf26d5f..86f6326 100644 --- a/boswatch/router/routerManager.py +++ b/boswatch/router/routerManager.py @@ -28,6 +28,7 @@ logging.debug("- %s loaded", __name__) class RouterManager: """!Class to manage all routers""" + def __init__(self): """!Create new router""" self._routerDict = {} @@ -92,9 +93,8 @@ class RouterManager: logging.error("unknown type '%s' in %s", routeType, route) return False - # except ModuleNotFoundError: # only since Py3.6 - except ImportError: - logging.error("%s not found: %s", route.get("type"), route.get("res")) + except ModuleNotFoundError: + logging.exception("%s not found: %s", route.get("type"), route.get("res")) return False logging.debug("finished building routers") diff --git a/boswatch/wildcard.py b/boswatch/wildcard.py index 3519502..3c7debd 100644 --- a/boswatch/wildcard.py +++ b/boswatch/wildcard.py @@ -97,8 +97,9 @@ def replaceWildcards(message, bwPacket): if field is not None: message = message.replace(wildcard, field) - for wildcard, field in _additionalWildcards.items(): + for wildcard, fieldName in _additionalWildcards.items(): + field = bwPacket.get(fieldName) if field is not None: - message = message.replace(wildcard, bwPacket.get(field)) + message = message.replace(wildcard, field) return message diff --git a/config/client.yaml b/config/client.yaml index 1550eab..907e7fc 100644 --- a/config/client.yaml +++ b/config/client.yaml @@ -26,7 +26,8 @@ inputSource: error: 0 squelch: 1 gain: 100 - rtlPath: /usr/bin/rtl_fm + #fir_size: 0 + rtlPath: /usr/local/bin/rtl_fm lineIn: card: 1 device: 0 diff --git a/docu/docs/config.md b/docu/docs/config.md index b833101..08a761f 100644 --- a/docu/docs/config.md +++ b/docu/docs/config.md @@ -49,6 +49,7 @@ Mit `PulseAudio` wird ein PulseAudio-Sink an Multimon-NG weitergereicht, z.B. in |error|Frequenz Abweichung in ppm|0| |squelch|Einstellung der Rauschsperre|1| |gain|Verstärkung des Eingangssignals|100| +|fir_size| niedrig leckagearmen Filter|None| |rtlPath|Pfad zur rtl_fm Binary|rtl_fm| **Beispiel:** diff --git a/docu/docs/plugin/divera.md b/docu/docs/plugin/divera.md new file mode 100644 index 0000000..a78c7cb --- /dev/null +++ b/docu/docs/plugin/divera.md @@ -0,0 +1,67 @@ +#
Divera 24/7
+--- + +## Beschreibung +Mit diesem Plugin ist es möglich, HTTPS-Anfragen für Alarmierungen an Divera 24/7 zu senden. +Wildcards in den Urls werden automatisch ersetzt. + +## Unterstütze Alarmtypen +- Fms +- Pocsag +- Zvei +- Msg + +## Resource +`divera` + +## Konfiguration +|Feld|Beschreibung|Default| +|----|------------|-------| +|accesskey|Web-API-Schlüssel von Divera24/7 || +|priority|Sonderrechte|false| +|title| Titel der Meldung | s. Beispiel| +|message| Nachrichteninhalt| s. Beispiel| +|ric|Auszulösende RIC in Divera; Gruppen->Alarmierungs-RIC|| +|vehicle|Fahrzeug-Alarmierungs-RIC|| + +**Beispiel:** +```yaml + - type: plugin + name: Divera Plugin + res: divera + config: + accesskey: API-Key + pocsag: + priority: false + title: "{RIC}({SRIC})\n{MSG}" + message: "{MSG}" + # RIC ist in Divera definiert + ric: Probealarm + fms: + priority: false + title: "{FMS}" + message: "{FMS}" + vehicle: MTF + zvei: + ric: Probealarm + title: "{TONE}" + message: "{TONE}" + priority: false + msg: + priority: false + title: "{MSG}" + message: "{MSG}" + # RIC ist in Divera definiert + ric: Probealarm + +``` + +--- +## Modul Abhängigkeiten +- keine + +--- +## Externe Abhängigkeiten +- asyncio +- aiohttp +- urllib diff --git a/docu/docs/plugin/mysql.md b/docu/docs/plugin/mysql.md new file mode 100644 index 0000000..b2cd2d4 --- /dev/null +++ b/docu/docs/plugin/mysql.md @@ -0,0 +1,43 @@ +#
Mysql
+--- + +## Beschreibung +Mit diesem Plugin ist es moeglich, die Alarmierungen in einer Mysql / Mariadb Datenbank zu speichern. +Das Plugin legt die Tabelle "boswatch" selbststaendig an, wenn diese nicht vorhanden ist. + +## Unterstütze Alarmtypen +- Fms +- Pocsag +- Zvei +- Msg + +## Resource +`mysql` + +## Konfiguration +|Feld|Beschreibung|Default| +|----|------------|-------| +|host|IP-Adresse bzw. URL des Hosts|| +|user|Username|| +|password|Passwort|| +|database|Name der Datenbank|| + +**Beispiel:** +```yaml + - type: plugin + name: mysql + res: mysql + config: + host: HOST + user: USERNAME + password: PASSWORD + database: DATABASE +``` + +--- +## Modul Abhängigkeiten +- keine + +--- +## Externe Abhängigkeiten +- mysql-connector-python diff --git a/init_db.sql b/init_db.sql new file mode 100644 index 0000000..b5948bc --- /dev/null +++ b/init_db.sql @@ -0,0 +1,35 @@ +create table boswatch +( + id int auto_increment primary key, + packetTimestamp timestamp default now() not null, + packetMode enum('fms', 'pocsag', 'zvei', 'msg') not null, + pocsag_ric char(7) default null, + pocsag_subric enum('1', '2', '3', '4') default null, + pocsag_subricText enum('a', 'b', 'c', 'd') default null, + pocsag_message text default null, + pocsag_bitrate enum('512', '1200', '2400') default null, + zvei_tone char(5) default null, + fms_fms char(8) default null, + fms_service varchar(255) default null, + fms_country varchar(255) default null, + fms_location varchar(255) default null, + fms_vehicle varchar(255) default null, + fms_status char(1) default null, + fms_direction char(1) default null, + fms_directionText tinytext default null, + fms_tacticalInfo char(3) default null, + serverName varchar(255) not null, + serverVersion varchar(100) not null, + serverBuildDate varchar(255) not null, + serverBranch varchar(255) not null, + clientName varchar(255) not null, + clientIP varchar(255) not null, + clientVersion varchar(100) not null, + clientBuildDate varchar(255) not null, + clientBranch varchar(255) not null, + inputSource varchar(30) not null, + frequency varchar(30) not null +); +create unique index boswatch_id_uindex + on boswatch (id); + diff --git a/install.sh b/install.sh index 7c0611c..0e02751 100644 --- a/install.sh +++ b/install.sh @@ -37,17 +37,17 @@ function exitcodefunction { module=$3 if [ $errorcode -ne "0" ]; then - echo "Action: $action on $module failed." >> $boswatchpath/install/setup_log.txt - echo "Exitcode: $errorcode" >> $boswatchpath/install/setup_log.txt + echo "Action: ${action} on ${module} failed." >> ${boswatch_install_path}/setup_log.txt + echo "Exitcode: ${errorcode}" >> ${boswatch_install_path}/setup_log.txt echo "" - echo "Action: $action on $module failed." - echo "Exitcode: $errorcode" + echo "Action: ${action} on ${module} failed." + echo "Exitcode: ${errorcode}" echo "" echo " -> If you want to open an issue at https://github.com/BOSWatch/BW3-Core/issues" - echo " please post the logfile, located at $boswatchpath/install/setup_log.txt" + echo " please post the logfile, located at ${boswatch_install_path}/setup_log.txt" exit 1 else - echo "Action: $action on $module ok." >> $boswatchpath/install/setup_log.txt + echo "Action: ${action} on ${module} ok." >> ${boswatch_install_path}/setup_log.txt fi } @@ -76,6 +76,7 @@ echo "Caution, script does not install a webserver with PHP and MySQL" echo "So you have to make up manually if you want to use MySQL support" boswatchpath=/opt/boswatch3 +boswatch_install_path=/opt/boswatch3_install reboot=false for (( i=1; i<=$#; i=$i+2 )); do @@ -83,11 +84,11 @@ for (( i=1; i<=$#; i=$i+2 )); do eval arg=\$$i eval arg2=\$$t - case $arg in + case ${arg} in -r|--reboot) reboot=true ;; -b|--branch) - case $arg2 in + case ${arg2} in dev|develop) echo " !!! WARNING: you are using the DEV BRANCH !!! "; branch=dev ;; *) branch=master ;; esac ;; @@ -98,8 +99,7 @@ for (( i=1; i<=$#; i=$i+2 )); do esac done -mkdir -p $boswatchpath -mkdir -p $boswatchpath/install +mkdir -p ${boswatchpath} ${boswatch_install_path} echo "" @@ -107,57 +107,58 @@ tput cup 13 15 echo "[ 1/9] [#--------]" tput cup 15 5 echo "-> make an apt-get update................" -apt-get update -y > $boswatchpath/install/setup_log.txt 2>&1 +apt-get update -y > ${boswatch_install_path}/setup_log.txt 2>&1 tput cup 13 15 echo "[ 2/9] [##-------]" tput cup 15 5 echo "-> download GIT and other stuff.........." -apt-get -y install git cmake build-essential libusb-1.0 qt4-qmake qt4-default libpulse-dev libx11-dev sox >> $boswatchpath/install/setup_log.txt 2>&1 +apt-get -y install git cmake build-essential libusb-1.0 qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qt5-default libpulse-dev libx11-dev sox >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? download stuff tput cup 13 15 echo "[ 3/9] [###------]" tput cup 15 5 echo "-> download Python, Yaml and other stuff.." -sudo apt-get -y install python3 python3-yaml >> $boswatchpath/install/setup_log.txt 2>&1 +apt-get -y install python3 python3-yaml python3-pip alsa-utils>> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? download python tput cup 13 15 echo "[ 4/9] [####-----]" tput cup 15 5 echo "-> download rtl_fm........................." -cd $boswatchpath/install -git clone --branch v0.5.4 https://github.com/osmocom/rtl-sdr.git rtl-sdr >> $boswatchpath/install/setup_log.txt 2>&1 +cd ${boswatch_install_path} +git clone --branch master https://github.com/osmocom/rtl-sdr.git rtl-sdr >> ${boswatch_install_path}/setup_log.txt 2>&1 +cd ${boswatch_install_path}/rtl-sdr/ +git checkout 2659e2df31e592d74d6dd264a4f5ce242c6369c8 exitcodefunction $? git-clone rtl-sdr -cd $boswatchpath/install/rtl-sdr/ tput cup 13 15 echo "[ 5/9] [#####----]" tput cup 15 5 echo "-> compile rtl_fm......................" mkdir -p build && cd build -cmake ../ -DINSTALL_UDEV_RULES=ON >> $boswatchpath/install/setup_log.txt 2>&1 +cmake ../ -DINSTALL_UDEV_RULES=ON >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? cmake rtl-sdr -make >> $boswatchpath/install/setup_log.txt 2>&1 +make >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? make rtl-sdr -make install >> $boswatchpath/install/setup_log.txt 2>&1 +make install >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? make-install rtl-sdr -ldconfig >> $boswatchpath/install/setup_log.txt 2>&1 +ldconfig >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? ldconfig rtl-sdr tput cup 13 15 echo "[ 6/9] [######---]" tput cup 15 5 echo "-> download multimon-ng................" -cd $boswatchpath/install -git clone --branch 1.1.8 https://github.com/EliasOenal/multimon-ng.git multimonNG >> $boswatchpath/install/setup_log.txt 2>&1 +cd ${boswatch_install_path} +git clone --branch 1.1.8 https://github.com/EliasOenal/multimon-ng.git multimonNG >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? git-clone multimonNG -cd $boswatchpath/install/multimonNG/ +cd ${boswatch_install_path}/multimonNG/ tput cup 13 15 echo "[ 7/9] [#######--]" @@ -165,25 +166,24 @@ tput cup 15 5 echo "-> compile multimon-ng................." mkdir -p build cd build -qmake ../multimon-ng.pro >> $boswatchpath/install/setup_log.txt 2>&1 +qmake -qt=qt5 ../multimon-ng.pro >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? qmake multimonNG -make >> $boswatchpath/install/setup_log.txt 2>&1 +make >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? make multimonNG -make install >> $boswatchpath/install/setup_log.txt 2>&1 +make install >> ${boswatch_install_path}/setup_log.txt 2>&1 exitcodefunction $? qmakeinstall multimonNG tput cup 13 15 echo "[ 8/9] [########-]" tput cup 15 5 echo "-> download BOSWatch3.................." -cd $boswatchpath/ -case $branch in - "dev") git clone -b develop https://github.com/BOSWatch/BW3-Core >> $boswatchpath/install/setup_log.txt 2>&1 && \ +case ${branch} in + "dev") git clone -b develop https://github.com/BOSWatch/BW3-Core ${boswatchpath} >> ${boswatch_install_path}/setup_log.txt 2>&1 && \ exitcodefunction $? git-clone BW3-Core-develop ;; - *) git clone -b master https://github.com/BOSWatch/BW3-Core >> $boswatchpath/install/setup_log.txt 2>&1 && \ + *) git clone -b master https://github.com/BOSWatch/BW3-Core ${boswatchpath} >> ${boswatch_install_path}/setup_log.txt 2>&1 && \ exitcodefunction $? git-clone BW3-Core ;; esac @@ -191,22 +191,22 @@ tput cup 13 15 echo "[9/9] [#########]" tput cup 15 5 echo "-> configure..........................." -cd $boswatchpath/ +cd ${boswatchpath}/ chmod +x * echo $'# BOSWatch3 - blacklist the DVB drivers to avoid conflicts with the SDR driver\n blacklist dvb_usb_rtl28xxu \n blacklist rtl2830\n blacklist dvb_usb_v2\n blacklist dvb_core' >> /etc/modprobe.d/boswatch_blacklist_sdr.conf tput cup 17 1 tput rev # Schrift zur besseren lesbarkeit Revers -echo "BOSWatch is now installed in $boswatchpath/ Installation ready!" +echo "BOSWatch is now installed in ${boswatchpath}/ Installation ready!" tput sgr0 # Schrift wieder Normal tput cup 19 3 echo "Watch out: to run BOSWatch3 you have to modify the server.yaml and client.yaml!" echo "Do the following step to do so:" -echo "sudo nano $boswatchpath/config/client.yaml eg. server.yaml" +echo "sudo nano ${boswatchpath}/config/client.yaml eg. server.yaml" echo "and modify the config as you need. This step is optional if you are upgrading an old version of BOSWatch3." echo "You can read the instructions on https://docs.boswatch.de/" tput setaf 1 # Rote Schrift -echo "Please REBOOT bevor the first start" +echo "Please REBOOT before the first start" tput setaf 9 # Schrift zurücksetzen echo "start Boswatch3 with" echo "sudo python3 bw_client.py -c client.yaml and sudo python3 bw_server.py -c server.yaml" @@ -214,12 +214,9 @@ echo "sudo python3 bw_client.py -c client.yaml and sudo python3 bw_server.p tput cnorm # cleanup -mkdir $boswatchpath/log/install -p -mv $boswatchpath/install/setup_log.txt $boswatchpath/log/install/ -rm $boswatchpath/install/ -R - -mv $boswatchpath/BW3-Core/* $boswatchpath/ -rm $boswatchpath/BW3-Core -R +mkdir ${boswatchpath}/log/install -p +mv ${boswatch_install_path}/setup_log.txt ${boswatchpath}/log/install/ +rm ${boswatch_install_path} -R if [ $reboot = "true" ]; then /sbin/reboot diff --git a/plugin/divera.py b/plugin/divera.py new file mode 100644 index 0000000..b3cc39b --- /dev/null +++ b/plugin/divera.py @@ -0,0 +1,137 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: divera.py +@date: 16.01.2022 +@author: Lars Gremme +@description: Divera247 Plugin +""" +import logging +from plugin.pluginBase import PluginBase + +# ###################### # +# Custom plugin includes # +import asyncio +from aiohttp import ClientSession +import urllib +# ###################### # + +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""" + fms_data = self.config.get("fms") + apicall = urllib.parse.urlencode({ + "accesskey": self.config.get("accesskey", default=""), + "vehicle_ric": self.parseWildcards(fms_data.get("vehicle", default="")), + "status_id": bwPacket.get("status"), + "status_note": bwPacket.get("directionText"), + "title": self.parseWildcards(fms_data.get("title", default="{FMS}")), + "text": self.parseWildcards(fms_data.get("message", default="{FMS}")), + "priority": fms_data.get("priority", default="false"), + }) + apipath = "/api/fms" + self._makeRequests(apipath, apicall) + + def pocsag(self, bwPacket): + """!Called on POCSAG alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + poc_data = self.config.get("pocsag") + apicall = urllib.parse.urlencode({ + "accesskey": self.config.get("accesskey", default=""), + "title": self.parseWildcards(poc_data.get("title", default="{RIC}({SRIC})\n{MSG}")), + "ric": self.parseWildcards(poc_data.get("ric", default="")), + "text": self.parseWildcards(poc_data.get("message", default="{MSG}")), + "priority": poc_data.get("priority", default="false"), + }) + apipath = "/api/alarm" + self._makeRequests(apipath, apicall) + + def zvei(self, bwPacket): + """!Called on ZVEI alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + zvei_data = self.config.get("zvei") + apicall = urllib.parse.urlencode({ + "accesskey": self.config.get("accesskey", default=""), + "title": self.parseWildcards(zvei_data.get("title", default="{TONE}")), + "ric": self.parseWildcards(zvei_data.get("ric", default="{TONE}")), + "text": self.parseWildcards(zvei_data.get("message", default="{TONE}")), + "priority": zvei_data.get("priority", default="false"), + }) + apipath = "/api/alarm" + self._makeRequests(apipath, apicall) + + def msg(self, bwPacket): + """!Called on MSG packet + + @param bwPacket: bwPacket instance + Remove if not implemented""" + msg_data = self.config.get("msg") + apicall = urllib.parse.urlencode({ + "accesskey": self.config.get("accesskey", default=""), + "title": self.parseWildcards(msg_data.get("title", default="{MSG}")), + "ric": self.parseWildcards(msg_data.get("ric", default="")), + "text": self.parseWildcards(msg_data.get("message", default="{MSG}")), + "priority": msg_data.get("priority", default="false"), + }) + apipath = "/api/alarm" + self._makeRequests(apipath, apicall) + + def _makeRequests(self, apipath, apicall): + """Parses wildcard urls and handles asynchronus requests + + @param urls: array of urls""" + url = "https://www.divera247.com" + request = url + apipath + "?" + apicall + + loop = asyncio.get_event_loop() + + future = asyncio.ensure_future(self._asyncRequests(request)) + loop.run_until_complete(future) + + async def _asyncRequests(self, url): + """Handles asynchronus requests + + @param urls: array of urls to send requests to""" + tasks = [] + + async with ClientSession() as session: + logging.debug("Generated URL: [{}]".format(url)) + 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""" + logging.debug("Post URL: [{}]".format(url)) + async with session.post(url) as response: + logging.info("{} returned [{}]".format(response.url, response.status)) + return await response.read() diff --git a/plugin/http.py b/plugin/http.py index 5d206bc..1af3035 100644 --- a/plugin/http.py +++ b/plugin/http.py @@ -38,7 +38,7 @@ class BoswatchPlugin(PluginBase): @param bwPacket: bwPacket instance Remove if not implemented""" urls = self.config.get("fms") - self.makeRequests(urls) + self._makeRequests(urls) def pocsag(self, bwPacket): """!Called on POCSAG alarm @@ -46,7 +46,7 @@ class BoswatchPlugin(PluginBase): @param bwPacket: bwPacket instance Remove if not implemented""" urls = self.config.get("pocsag") - self.makeRequests(urls) + self._makeRequests(urls) def zvei(self, bwPacket): """!Called on ZVEI alarm @@ -54,7 +54,7 @@ class BoswatchPlugin(PluginBase): @param bwPacket: bwPacket instance Remove if not implemented""" urls = self.config.get("zvei") - self.makeRequests(urls) + self._makeRequests(urls) def msg(self, bwPacket): """!Called on MSG packet @@ -62,9 +62,9 @@ class BoswatchPlugin(PluginBase): @param bwPacket: bwPacket instance Remove if not implemented""" urls = self.config.get("msg") - self.makeRequests(urls) + self._makeRequests(urls) - def makeRequests(self, urls): + def _makeRequests(self, urls): """Parses wildcard urls and handles asynchronus requests @param urls: array of urls""" @@ -75,7 +75,7 @@ class BoswatchPlugin(PluginBase): future = asyncio.ensure_future(self.asyncRequests(urls)) loop.run_until_complete(future) - async def asyncRequests(self, urls): + async def _asyncRequests(self, urls): """Handles asynchronus requests @param urls: array of urls to send requests to""" @@ -83,13 +83,13 @@ class BoswatchPlugin(PluginBase): async with ClientSession() as session: for url in urls: - task = asyncio.ensure_future(self.fetch(url, session)) + task = asyncio.ensure_future(self._fetch(url, session)) tasks.append(task) responses = asyncio.gather(*tasks) await responses - async def fetch(self, url, session): + async def _fetch(self, url, session): """Fetches requests @param url: url diff --git a/plugin/mysql.py b/plugin/mysql.py new file mode 100644 index 0000000..f882703 --- /dev/null +++ b/plugin/mysql.py @@ -0,0 +1,188 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: mysql.py +@date: 15.02.2021 +@author: Jan Speller +@description: Mysql Plugin +""" +import logging +from plugin.pluginBase import PluginBase + +# ###################### # +# Custom plugin includes # +import mysql.connector +from datetime import datetime + +# ###################### # + +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 + Remove if not implemented""" + self.sqlInserts = { + "pocsag": "INSERT INTO boswatch (packetTimestamp, packetMode, pocsag_ric, pocsag_subric, pocsag_subricText, pocsag_message, pocsag_bitrate, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", + "zvei": "INSERT INTO boswatch (packetTimestamp, packetMode, zvei_tone, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", + "fms": "INSERT INTO boswatch (packetTimestamp, packetMode, fms_fms, fms_service, fms_country, fms_location, fms_vehicle, fms_status, fms_direction, fms_directionText, fms_tacticalInfo, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", + "msg": "INSERT INTO boswatch (packetTimestamp, packetMode, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + } + + self.connection = mysql.connector.connect( + host=self.config.get("host"), + user=self.config.get("user"), + password=self.config.get("password"), + database=self.config.get("database"), + ) + + self.cursor = self.connection.cursor() + self.cursor.execute("SHOW TABLES LIKE 'boswatch'") + + if self.cursor.fetchone() is None: + with open('init_db.sql') as f: + for stmnt in f.read().split(';'): + self.cursor.execute(stmnt) + self.connection.commit() + + self.cursor.close() + + def setup(self): + """!Called before alarm + Remove if not implemented""" + try: + self.connection.ping(reconnect=True, attempts=3, delay=2) + except mysql.connector.Error: + logging.warning("Connection was down, trying to reconnect...") + self.onLoad() + + self.cursor = self.connection.cursor() + + def fms(self, bwPacket): + """!Called on FMS alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("fms"), + bwPacket.get("service"), + bwPacket.get("country"), + bwPacket.get("location"), + bwPacket.get("vehicle"), + bwPacket.get("status"), + bwPacket.get("direction"), + bwPacket.get("directionText"), + bwPacket.get("tacticalInfo"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("fms"), val) + + def pocsag(self, bwPacket): + """!Called on POCSAG alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("ric"), + bwPacket.get("subric"), + bwPacket.get("subricText"), + bwPacket.get("message"), + bwPacket.get("bitrate"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("pocsag"), val) + + def zvei(self, bwPacket): + """!Called on ZVEI alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("tone"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("pocsag"), val) + + def msg(self, bwPacket): + """!Called on MSG packet + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("msg"), val) + + def teardown(self): + """!Called after alarm + Remove if not implemented""" + self.connection.commit() + self.cursor.close() + + def onUnload(self): + """!Called by destruction of the plugin + Remove if not implemented""" + self.connection.close()