diff --git a/.gitignore b/.gitignore index 7617a01..f37fd5c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,11 @@ *.log config.ini log/ + +\.project + +\.pydevproject + +\.settings/ + +\.idea/ diff --git a/.travis.yml b/.travis.yml index d1103be..0082739 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ sudo: required branches: only: - master - - beta - develop before_script: diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3a5e25e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,73 @@ +# Changelog + + +### __[v2.3.1]__ - Unreleased +##### Added +- Config Eintrag um Port für MySQL Plugin festzulegen [#345](https://github.com/Schrolli91/BOSWatch/pull/345) +- FMS und ZVEI Support für Pushover Plugin [#352](https://github.com/Schrolli91/BOSWatch/pull/352) +- Benutzerdefinierte Nachrichten für Pushover Plugin in config [#352](https://github.com/Schrolli91/BOSWatch/pull/352) +##### Changed +- multicastAlarm Plugin - RICs die von multicastAlarm genutzt werden, müssen nicht mehr in der config bei allow_ric bzw. filter_range_start/filter_range_end berücksichtigt werden. [#357](https://github.com/Schrolli91/BOSWatch/pull/357) +- FFAgent Plugin - Debug Logging für die alarmHeaders eingebaut zwecks Troubleshooting [#354](https://github.com/Schrolli91/BOSWatch/pull/354) +##### Deprecated +##### Removed +##### Fixed +- Fehler beim Auslesen der netIdent_RIC im MySQL Plugin [#347](https://github.com/Schrolli91/BOSWatch/pull/347) +- FFAgent Plugin - Typo bei alarmHeaders für Live Betrieb gefixt [#354](https://github.com/Schrolli91/BOSWatch/pull/354) +##### Security + + +### __[v2.3]__ - 22.12.2017 +##### Added +- zuschaltbare POCSAG Multicast-Alarm Funktionalität [#307](https://github.com/Schrolli91/BOSWatch/pull/307) +- Flag in Config um nur letzte Net Ident oder gesamte Historie zu speichern [#317](https://github.com/Schrolli91/BOSWatch/pull/317) +##### Removed +- Beta Branch aus Readme, Installer und Travis-CI entfernt [#324](https://github.com/Schrolli91/BOSWatch/pull/324) +##### Fixed +- Bug in httpRequest Plugin (data Field wurde überschrieben) [#337](https://github.com/Schrolli91/BOSWatch/pull/337) +- Kommentar für FirEmergency Einstellung angepasst [#338](https://github.com/Schrolli91/BOSWatch/pull/338) + + +### __[v2.2.2]__ - 21.10.2017 +##### Added +- Installations Script für Services [#316](https://github.com/Schrolli91/BOSWatch/pull/316) +##### Changed +- Telegram Plugin importiert Google Maps Funktionen nur noch wenn API Key eingetragen ist [#315](https://github.com/Schrolli91/BOSWatch/pull/315) +- Versions Nummer und Branch Name getrennt [3fed1ac](https://github.com/Schrolli91/BOSWatch/commit/3fed1ac12af8690213766e0e81d71c237530ed2c) +##### Deprecated +- Beta Branch wird mit nächstem Update entfernt [Forum](http://boswatch.de/index.php?thread/16-beta-branch-abschaffen/&postID=113#post113) +##### Fixed +- Schreibfehler der Pfadangabe im Installer [#317](https://github.com/Schrolli91/BOSWatch/pull/317) +- Schreibfehler in Service Readme [#313](https://github.com/Schrolli91/BOSWatch/issues/313) +- Einige Code-Style Verbesserungen [#310](https://github.com/Schrolli91/BOSWatch/pull/310) + + +### __[v2.2.1]__ - 19.09.2017 +##### Added +- Neues Service Script [#263](https://github.com/Schrolli91/BOSWatch/pull/263) +- Eigene Message für jeden Typ im Telegram Plugin in der config definierbar [#267](https://github.com/Schrolli91/BOSWatch/pull/267) +- httpRequest Plugin unterstützt nun mehrere URLs [254](https://github.com/Schrolli91/BOSWatch/pull/254) + +##### Changed +- Name der csv Dateien geändert um überschreiben bei Update zu vermeiden [#262](https://github.com/Schrolli91/BOSWatch/pull/262) +- Description Liste kann nun zusätzlich Einträge für jede Subric enthalten (POCSAG) [#271](https://github.com/Schrolli91/BOSWatch/pull/271) +- RegEX verbietet nun grundsätzlich alles - Es muss explizit zugelassen werden (wenn RegEX aktiv) [#284](https://github.com/Schrolli91/BOSWatch/pull/284) + +##### Fixed +- Bug im SMS77 Plugin behoben [#257](https://github.com/Schrolli91/BOSWatch/issues/257) +- einige Code-Style Verbesserungen + + +---------------------------- + + +Zum schreiben des Changelog's siehe: +http://keepachangelog.com/de/1.0.0/ + +### __[v#.#]__ - date +##### Added +##### Changed +##### Deprecated +##### Removed +##### Fixed +##### Security diff --git a/Konzept.md b/Konzept.md index 6e3a5b1..7903dcc 100644 --- a/Konzept.md +++ b/Konzept.md @@ -2,6 +2,7 @@ ============ +Python 3 Verpacken der Funktionalitäten in Klassen um OOP-Grundsätze zu erreichen. @@ -12,11 +13,13 @@ Verpacken der Funktionalitäten in Klassen um OOP-Grundsätze zu erreichen. - reine Dekodierung mittels rtl-fm und multimon - Keine Filter usw. nur die Dekoder, Daten verpacken, verschicken - per TCP Socket an den Server + - versch Eingabequellen (DVB-T Stick, Audio Eingang) ### Server: - Empfängt die TCP Socket Pakete der einzelnen Clients - Durch doubleFiltering fallen doppelt eingehende Alarme der Clienten sowieso raus - - Danach Filterung usw. dann call an die plugins + - Danach Filterung nach neuen Filterkonzept + - dann call an die plugins diff --git a/README.md b/README.md index ac3d336..c9b570b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ +### Arbeiten an BOSWatch 3 gestartet +#### Work on BOSWatch 3 has started +## see: https://boswatch.de/index.php?thread/29-boswatch-3/ + + |Branch|Code Qualität|CI-Build| |---|---|---| |master|[![Codacy Badge](https://img.shields.io/codacy/grade/d512976554354a199555bd34ed179bb1/master.svg)](https://www.codacy.com/app/Schrolli91/BOSWatch/dashboard?bid=3763821)|[![Build Status](https://travis-ci.org/Schrolli91/BOSWatch.svg?branch=master)](https://travis-ci.org/Schrolli91/BOSWatch)| -|beta|[![Codacy Badge](https://img.shields.io/codacy/grade/d512976554354a199555bd34ed179bb1/beta.svg)](https://www.codacy.com/app/Schrolli91/BOSWatch/dashboard?bid=4213030)|[![Build Status](https://travis-ci.org/Schrolli91/BOSWatch.svg?branch=beta)](https://travis-ci.org/Schrolli91/BOSWatch)| |develop|[![Codacy Badge](https://img.shields.io/codacy/grade/d512976554354a199555bd34ed179bb1/develop.svg)](https://www.codacy.com/app/Schrolli91/BOSWatch/dashboard?bid=3763820)|[![Build Status](https://travis-ci.org/Schrolli91/BOSWatch.svg?branch=develop)](https://travis-ci.org/Schrolli91/BOSWatch)| @@ -16,6 +20,10 @@ In der Zukunft wollen wir die Möglichkeit schaffen, codierte Nachrichten zu ent :satellite: Python Script to receive and decode German BOS Information with rtl_fm and multimon-NG :satellite: +#### WICHTIG +**Es wird darauf hingewiesen, dass für die Teilnahme am BOS-Funk nur nach den Technischen Richtlinien der BOS zugelassene Funkanlagen verwendet werden dürfen.** +**Der BOS-Funk ist ein nichtöffentlicher mobiler Landfunk. Privatpersonen gehören nicht zum Kreis der berechtigten Funkteilnehmer.** _(Quelle: TR-BOS)_ + #### Notice: The intercept of the German BOS radio is **strictly prohibited** and will be prosecuted. the use is **only authorized** personnel permitted. The software was developed using the Multimon-NG code, a function in the real operation can not be guaranteed. @@ -23,10 +31,13 @@ The software was developed using the Multimon-NG code, a function in the real op **Please** only use Code from **master**-Branch - thats **the only stable!** +beta-branch is for beta-test of new features + unless you are developer you can use the develop-Branch - may be unstable! ### Features ##### Implemented features: +**list is not complete!** - FMS, ZVEI and POCSAG512/1200/2400 decoding and displaying - Plugin support for easy functional extension - Filtering double alarms with adjustable time and check width @@ -40,31 +51,14 @@ unless you are developer you can use the develop-Branch - may be unstable! - Ready for use BOSWatch as daemon - possibility to start plugins asynchron - NMA Error Handler - -##### Features for the future: -- more plugins -- other Ideas per Issues please +- multicastAlarm for transmission optimized networks ### Plugins If you want to code your own Plugin, see `plugins/README.md`. ##### Implemented plugins: - -|Plugin|Function|FMS|ZVEI|POC| -|-----|---------|:-:|:--:|:-:| -|MySQL|insert data into MySQL database|:white_check_mark:|:white_check_mark:|:white_check_mark:| -|httpRequest|send a request with parameter to an URL|:white_check_mark:|:white_check_mark:|:white_check_mark:| -|eMail|send Mails with own text|:white_check_mark:|:white_check_mark:|:white_check_mark:| -|BosMon|send data to BosMon server|:white_check_mark:|:white_check_mark:|:white_check_mark:| -|firEmergency|send data to firEmergency server|:x:|:white_check_mark:|:white_check_mark:| -|jsonSocket|send data as jsonString to a socket server|:white_check_mark:|:white_check_mark:|:white_check_mark:| -|NMA|send data to Notify my Android|:white_check_mark:|:white_check_mark:|:white_check_mark:| - -- for more Information to the plugins see `config.ini` - -##### Plugins for the Future: -- Ideas per Issues please +please look at the wiki page ### Configuration @@ -105,52 +99,15 @@ Take a look into the parser.php for the parsing functions~~ ### 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` - -``` -usage: boswatch.py [-h] -f FREQ [-d DEVICE] [-e ERROR] -a - {FMS,ZVEI,POC512,POC1200,POC2400} - [{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 - -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 - -u, --usevarlog Use '/var/log/boswatch' for logfiles instead of subdir 'log' in BOSWatch directory - -v, --verbose Shows more information - -q, --quiet Shows no information. Only logfiles -``` - +please look at the wiki page ### Installation -Please follow the instructions written down in the wiki: - -https://github.com/Schrolli91/BOSWatch/wiki - -You just need to download a single file since the installer manages the whole process except the installation of a webserver and a database. +please look at the wiki page If you want to use BOSWatch as a daemon, you have to set your configuration in `service/boswatch.sh` and copy it to `/etc/init.d`. Then you can start BOSWatch with `sudo /etc/init.d/boswatch.sh start`. For configuration-details see `service/README.md`. -### Requirements -- RTL_SDR (rtl_fm) -- Multimon-NG -- Python Support -- MySQL Connector for Python (for MySQL-plugin) - -Thanks to smith_fms and McBo from Funkmeldesystem.de - Forum for Inspiration and Groundwork! - - -### Code your own Plugin -See `plugins/README.md` +##### Big thanks +to smith_fms and McBo from Funkmeldesystem.de - Forum for Inspiration and Groundwork! diff --git a/boswatch.py b/boswatch.py index e8b7b3a..2ad194d 100755 --- a/boswatch.py +++ b/boswatch.py @@ -18,11 +18,12 @@ GitHUB: https://github.com/Schrolli91/BOSWatch import logging import logging.handlers -import argparse # for parse the args -import ConfigParser # for parse the config file -import os # for log mkdir -import time # for time.sleep() -import subprocess # for starting rtl_fm and multimon-ng +import argparse # for parse the args +import ConfigParser # for parse the config file +import os # for log mkdir +import sys # for py version +import time # for time.sleep() +import subprocess # for starting rtl_fm and multimon-ng from includes import globalVars # Global variables from includes import MyTimedRotatingFileHandler # extension of TimedRotatingFileHandler @@ -162,7 +163,9 @@ try: # try: logging.debug("SW Version: %s",globalVars.versionNr) + logging.debug("Branch: %s",globalVars.branch) logging.debug("Build Date: %s",globalVars.buildDate) + logging.debug("Python Vers: %s",sys.version) logging.debug("BOSWatch given arguments") if args.test: logging.debug(" - Test-Mode!") @@ -217,9 +220,14 @@ try: # if given loglevel is debug: if globalVars.config.getint("BOSWatch","loglevel") == 10: configHandler.checkConfig("BOSWatch") + configHandler.checkConfig("multicastAlarm") + configHandler.checkConfig("Filters") configHandler.checkConfig("FMS") configHandler.checkConfig("ZVEI") configHandler.checkConfig("POC") + configHandler.checkConfig("Plugins") + configHandler.checkConfig("Filters") + #NMAHandler is outputed below except: # we couldn't work without config -> exit logging.critical("cannot read config file") diff --git a/citest/config.httpRequest.ini b/citest/config.httpRequest.ini index bfa08ec..512070a 100644 --- a/citest/config.httpRequest.ini +++ b/citest/config.httpRequest.ini @@ -114,6 +114,26 @@ ricd = Unwetter # Usually sent periodically, separated by comma netIdent_ric = 0174760, 1398098 + +[multicastAlarm] +# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). +# In this optimized transmission scheme, a POCSAG telegram with each RIC that needs to be alarmed will be send in a sequence. These telegrams are send without a text message. This sequence is directly followed by a telegram with a specific RIC and the text message that belongs to the sequnece send right before. +# A POCSAG pager (DME) can be configured to start an acoustic alarm if a specific RIC without text has been received. If afterwards the specific RIC with the text message will be received, the pager will show the message in it's display. +# multicastAlarm enables BOSwatch to process the all received RICs joined with the text message. +# +# enable multicastAlarm (0 - off | 1 - on) +multicastAlarm = 0 + +# time limit for alarms that do not belong to the multicastAlarm sequence in seconds +multicastAlarm_ignore_time = 15 + +# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence) (can be empty) +multicastAlarm_delimiter_ric = + +# multicastAlarm RIC that is used to send the text message +multicastAlarm_ric = + + [Filters] # RegEX Filter Configuration # http://www.regexr.com/ - RegEX Test Tool an Documentation @@ -154,8 +174,10 @@ template = 0 [MySQL] # MySQL configuration +#default port: 3306 dbserver = localhost -dbuser = root +dbport = 3306 +dbuser = boswatch dbpassword = root database = boswatch diff --git a/citest/config.mysql.ini b/citest/config.mysql.ini index 7766f77..bad62e6 100644 --- a/citest/config.mysql.ini +++ b/citest/config.mysql.ini @@ -114,6 +114,26 @@ ricd = Unwetter # Usually sent periodically, separated by comma netIdent_ric = 0174760, 1398098 + +[multicastAlarm] +# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). +# In this optimized transmission scheme, a POCSAG telegram with each RIC that needs to be alarmed will be send in a sequence. These telegrams are send without a text message. This sequence is directly followed by a telegram with a specific RIC and the text message that belongs to the sequnece send right before. +# A POCSAG pager (DME) can be configured to start an acoustic alarm if a specific RIC without text has been received. If afterwards the specific RIC with the text message will be received, the pager will show the message in it's display. +# multicastAlarm enables BOSwatch to process the all received RICs joined with the text message. +# +# enable multicastAlarm (0 - off | 1 - on) +multicastAlarm = 0 + +# time limit for alarms that do not belong to the multicastAlarm sequence in seconds +multicastAlarm_ignore_time = 15 + +# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence) (can be empty) +multicastAlarm_delimiter_ric = + +# multicastAlarm RIC that is used to send the text message +multicastAlarm_ric = + + [Filters] # RegEX Filter Configuration # http://www.regexr.com/ - RegEX Test Tool an Documentation @@ -154,7 +174,9 @@ template = 0 [MySQL] # MySQL configuration +#default port: 3306 dbserver = localhost +dbport = 3306 dbuser = boswatch dbpassword = root database = boswatch diff --git a/citest/testdata.txt b/citest/testdata.txt index e4ac22e..4f1d5d1 100644 --- a/citest/testdata.txt +++ b/citest/testdata.txt @@ -35,7 +35,7 @@ POCSAG512: Address: 1000003 Function: 3 Alpha: BOSWatch-Test: okay POCSAG512: Address: 1200001 Function: 1 Alpha: BOSWatch-Test ÖÄÜß: okay POCSAG512: Address: 1200001 Function: 1 Alpha: BOSWatch-Test öäü: okay -# witch csv +# with csv POCSAG512: Address: 1234567 Function: 1 Alpha: BOSWatch-Test: with csv # without csv @@ -86,6 +86,22 @@ POCSAG1200: Address: 7777777 Function: 1 Alpha: BOSWatch-Test: denied POCSAG1200: Address: 0000004 Function: 1 Alpha: BOSWatch-Test: out of filter start POCSAG1200: Address: 9000000 Function: 1 Alpha: BOSWatch-Test: out of filter end +#Probealram +POCSAG1200: Address: 0871004 Function: 1 Alpha: Dies ist ein Probealarm! +## Multicast Alarm +POCSAG1200: Address: 0871002 Function: 0 Alpha: +POCSAG1200: Address: 0860001 Function: 0 +POCSAG1200: Address: 0860002 Function: 0 +POCSAG1200: Address: 0860003 Function: 0 +POCSAG1200: Address: 0860004 Function: 0 +POCSAG1200: Address: 0860005 Function: 0 +POCSAG1200: Address: 0860006 Function: 0 +POCSAG1200: Address: 0860007 Function: 0 +POCSAG1200: Address: 0860008 Function: 0 +POCSAG1200: Address: 0860009 Function: 0 +POCSAG1200: Address: 0860010 Function: 0 +POCSAG1200: Address: 0871003 Function: 0 Alpha: B2 Feuer Gebäude Pers in Gefahr. bla bla bla + # regEx-Filter? diff --git a/config/config.template.ini b/config/config.template.ini index d943faf..d17cd3f 100644 --- a/config/config.template.ini +++ b/config/config.template.ini @@ -1,6 +1,17 @@ -######################## -# BOSWatch Config File # -######################## + +# ____ ____ ______ __ __ __ +# / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ +# / __ / / / /\__ \| | /| / / __ / __/ ___/ __ \ +# / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / +# /_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ +# German BOS Information Script +# configuration file +# +# The intercept of the German BOS radio is strictly +# prohibited and will be prosecuted. +# The use is only authorized personnel permitted! +# + [BOSWatch] # set loglevel for logfile @@ -31,6 +42,7 @@ processAlarmAsync = 0 # Using RegEx-filter (0 - off | 1 - on) # filter-configuration in section [Filters] +# if you are using the RegEx filter you must add filter rules to forward alarms useRegExFilter = 0 # for double check save the last n IDs @@ -51,6 +63,7 @@ doubleFilter_check_msg = 0 # writes the multimon-ng raw data stream into a text file named mm_raw.txt writeMultimonRaw = 0 + [NMAHandler] # you can use a logging handler for sending logging records to NotifyMyAndroid # enableHandler (0|1) will enable the NMA handler @@ -79,12 +92,14 @@ idDescribed = 0 # Better use RegEX to verify the correct data checkCRC = 0 + [ZVEI] # look-up-table for adding a description # using description (0 - off | 1 - on) # descriptions are loaded from csv/zvei.csv idDescribed = 0 + [POC] # some very simple filters: # Allow only this RICs (empty: allow all, separator ",") @@ -113,17 +128,39 @@ ricd = Unwetter # RIC for net identification # Usually sent periodically, separated by comma netIdent_ric = 0174760, 1398098 +# you can hold one entry per netIdent_ric [0] or the whole history [1] +netIdent_history = 0 + + +[multicastAlarm] +# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). +# In this optimized transmission scheme, a POCSAG telegram with each RIC that needs to be alarmed will be send in a sequence. These telegrams are send without a text message. This sequence is directly followed by a telegram with a specific RIC and the text message that belongs to the sequnece send right before. +# A POCSAG pager (DME) can be configured to start an acoustic alarm if a specific RIC without text has been received. If afterwards the specific RIC with the text message will be received, the pager will show the message in it's display. +# multicastAlarm enables BOSwatch to process the all received RICs joined with the text message. +# +# enable multicastAlarm (0 - off | 1 - on) +multicastAlarm = 0 + +# time limit for alarms that do not belong to the multicastAlarm sequence in seconds +multicastAlarm_ignore_time = 15 + +# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence) (can be empty) +multicastAlarm_delimiter_ric = + +# multicastAlarm RIC that is used to send the text message +multicastAlarm_ric = + [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 +# If RegEX is enabled - only alloewd data will pass! +# INDIVIDUAL_NAME = TYP;DATAFIELD;PLUGIN;FREQUENZ;REGEX # TYP = the Data Typ (FMS|ZVEI|POC) -# DATAFIELD = the field of the Data Array (see readme.md in plugin folder) +# DATAFIELD = the field of the Data Array (see readme.md in plugin folder) # 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 +# 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 #testfilter = ZVEI;zvei;*;85500000;25[0-9]{3} @@ -148,13 +185,15 @@ Pushover = 0 Telegram = 0 yowsup = 0 -# for developing template-module +# for developing - template-module template = 0 [MySQL] # MySQL configuration +#default port: 3306 dbserver = localhost +dbport = 3306 dbuser = boswatch dbpassword = root database = boswatch @@ -171,36 +210,18 @@ tableSIG = bos_signal # multiple URLs can be separated by comma -# you can use the following wildcards in your URL as GET params: +# you can use the wildcards in your URL as GET params: # http://en.wikipedia.org/wiki/Query_string -# %FMS% = FMS Code -# %STATUS% = FMS Status -# %DIR% = Direction of the telegram (0/1) -# %DIRT% = Direction of the telegram (Text-String) -# %TSI% = Tactical Short Information (I-IV) -# %DESCR% = Description from csv-file -# %TIME% = Time (by script) -# %DATE% = Date (by script) +#Wildcards can be used, see end of the file! #fms_url = http://www.google.de?code=%FMS%&stat=%STATUS% fms_url = -# %ZVEI% = ZVEI 5-tone Code -# %DESCR% = Description from csv-file -# %TIME% = Time (by script) -# %DATE% = Date (by script) +#Wildcards can be used, see end of the file! #zvei_url = http://www.google.de?zvei=%ZVEI% zvei_url = -# %RIC% = POCSAG RIC -# %FUNC% = POCSAG function/Subric (1-4) -# %FUNCCHAR% = POCSAG function/Subric as character (a-d) -# %FUNCTEXT% = POCSAG function/Subric static massage definded in POCSAG section -# %MSG% = Message of the POCSAG telegram -# %BITRATE% = Bitrate of the POCSAG telegram -# %DESCR% = Description from csv-file -# %TIME% = Time (by script) -# %DATE% = Date (by script) +#Wildcards can be used, see end of the file! #poc_url = http://www.google.de?ric=%RIC%&subric=%FUNC%&msg=%MSG% poc_url = @@ -225,42 +246,15 @@ to = user@irgendwo, user2@woanders # normal|urgent|non-urgent priority = urgent -# %FMS% = FMS Code -# %STATUS% = FMS Status -# %DIR% = Direction of the telegram (0/1) -# %DIRT% = Direction of the telegram (Text-String) -# %TSI% = Tactical Short Information (I-IV) -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %BR% = Insert line wrap (only in message) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! fms_subject = FMS: %FMS% fms_message = %DATE% %TIME%: %FMS%%BR%Status: %STATUS% - Direction: %DIRT% - TSI: %TSI% -# %ZVEI% = ZVEI 5-tone Code -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %BR% = Insert line wrap (only in message) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! zvei_subject = Alarm: %ZVEI% zvei_message = %DATE% %TIME%: %ZVEI% -# %RIC% = POCSAG RIC -# %FUNC% = POCSAG function/Subric (1-4) -# %FUNCCHAR% = POCSAG function/Subric als character (a-d) -# %FUNCTEXT% = POCSAG function/Subric static massage definded in POCSAG section -# %MSG% = Message of the POCSAG telegram -# %BITRATE% = Bitrate of the POCSAG telegram -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %BR% = Insert line wrap (only in message) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! poc_subject = Alarm: %RIC%%LPAR%%FUNCCHAR%%RPAR% poc_message = %DATE% %TIME% - %DESCR%: %MSG% @@ -383,14 +377,24 @@ api_key = # Pushover Userkey or Groupkey to receive message user_key = -# Title of the message -title = BOSWatch Message - +# Section for POCSAG # Adapt Pocsag Subric (a,b,c,d) to Pushover Priorities (see https://pushover.net/api#priority) -SubA = 0 -SubB = 2 -SubC = 1 -SubD = 0 +SubA = 1 +SubB = 1 +SubC = 2 +SubD = -2 +poc_title = Alarm: %RIC%%LPAR%%FUNCCHAR%%RPAR% +poc_message = %DATE% %TIME% - %DESCR%: %MSG% + +# Section for ZVEI +zvei_prio = 1 +zvei_title = Alarm: %ZVEI% +zvei_message = %DATE% %TIME%: %ZVEI% + +# Section for FMS +fms_prio = 1 +fms_title = FMS: %FMS% +fms_message = %DATE% %TIME%: %FMS%%BR%Status: %STATUS% - Direction: %DIRT% - TSI: %TSI% %LPAR%%DESCR%%RPAR% # how often should Pushover re-alert in seconds (emergency-messages) retry = 30 @@ -415,36 +419,13 @@ RICforLocationAPIKey = # Required if you want to create a map based on location information received with the above RIC. GoogleAPIKey = -# %FMS% = FMS Code -# %STATUS% = FMS Status -# %DIR% = Direction of the telegram (0/1) -# %DIRT% = Direction of the telegram (Text-String) -# %TSI% = Tactical Short Information (I-IV) -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! FMS_message = %DATE% %TIME%: %FMS% -# %ZVEI% = ZVEI 5-tone Code -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! ZVEI_message = %DATE% %TIME%: %ZVEI% -# %RIC% = POCSAG RIC -# %FUNC% = POCSAG function/Subric (1-4) -# %FUNCCHAR% = POCSAG function/Subric als character (a-d) -# %MSG% = Message of the POCSAG telegram -# %BITRATE% = Bitrate of the POCSAG telegram -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! POC_message = %MSG% @@ -456,36 +437,13 @@ sender = # password from this number password= -# %FMS% = FMS Code -# %STATUS% = FMS Status -# %DIR% = Direction of the telegram (0/1) -# %DIRT% = Direction of the telegram (Text-String) -# %TSI% = Tactical Short Information (I-IV) -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! fms_message = %DATE% %TIME%: %FMS% -# %ZVEI% = ZVEI 5-tone Code -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! zvei_message = %DATE% %TIME%: %ZVEI% -# %RIC% = POCSAG RIC -# %FUNC% = POCSAG function/Subric (1-4) -# %FUNCCHAR% = POCSAG function/Subric als character (a-d) -# %MSG% = Message of the POCSAG telegram -# %BITRATE% = Bitrate of the POCSAG telegram -# %DESCR% = Description, if description-module is used -# %DATE% = Date (by script) -# %TIME% = Time (by script) -# %LPAR% = ( -# %RPAR% = ) +#Wildcards can be used, see end of the file! poc_message = %MSG% @@ -496,3 +454,44 @@ poc_message = %MSG% [template] test1 = testString test2 = 123456 + + +##################### +##### WILDCARDS ##### +##################### + +##### FMS +# %FMS% = FMS Code +# %STATUS% = FMS Status +# %DIR% = Direction of the telegram (0/1) +# %DIRT% = Direction of the telegram (Text-String) +# %TSI% = Tactical Short Information (I-IV) +# %DESCR% = Description, if description-module is used +# %DATE% = Date (by script) +# %TIME% = Time (by script) +# %BR% = Insert line wrap (only in message) +# %LPAR% = ( +# %RPAR% = ) + +##### ZVEI +# %ZVEI% = ZVEI 5-tone Code +# %DESCR% = Description, if description-module is used +# %DATE% = Date (by script) +# %TIME% = Time (by script) +# %BR% = Insert line wrap (only in message) +# %LPAR% = ( +# %RPAR% = ) + +##### POCSAG +# %RIC% = POCSAG RIC +# %FUNC% = POCSAG function/Subric (1-4) +# %FUNCCHAR% = POCSAG function/Subric als character (a-d) +# %FUNCTEXT% = POCSAG static Subric message (see [POC]) +# %MSG% = Message of the POCSAG telegram +# %BITRATE% = Bitrate of the POCSAG telegram +# %DESCR% = Description, if description-module is used +# %DATE% = Date (by script) +# %TIME% = Time (by script) +# %BR% = Insert line wrap (only in message) +# %LPAR% = ( +# %RPAR% = ) diff --git a/csv/poc.template.csv b/csv/poc.template.csv index 87a5073..9dfe7d4 100644 --- a/csv/poc.template.csv +++ b/csv/poc.template.csv @@ -5,6 +5,12 @@ ric,description # For each RIC-Address you could set a description-text # Use the structure: ric,"Description-Text" # +# You can even define specific subrics, therefore you +# 1. need to specify a main RIC: 1234567, "Unit One" +# 2. specify a certain subric: 1234567B, "Subunit Bravo" +# The result for 1234567B will be "Unit One Subunit Bravo" +# - Be sure having defined the main RIC (step one)! - +# # !!! DO NOT delete the first line !!! # 1234567,"POCSAG testdata äöüß" diff --git a/exampleAddOns/simpleWeb/mysql.class.php b/exampleAddOns/simpleWeb/mysql.class.php index 69d5fbd..a74b4b6 100644 --- a/exampleAddOns/simpleWeb/mysql.class.php +++ b/exampleAddOns/simpleWeb/mysql.class.php @@ -23,16 +23,16 @@ Simple Database Class (C) by Bastian Schroll function __construct($host, $user, $password, $database, $show_error = 1) { $this->show_error = $show_error; - @$this->conn = mysql_connect($host, $user, $password); + @$this->conn = mysqli_connect($host, $user, $password); if ($this->conn == false) { - $this->error("Keine Verbindung zum Datenbank Server!", mysql_error()); + $this->error("Keine Verbindung zum Datenbank Server!", mysqli_error($this->conn)); return false; } - if (!@mysql_select_db($database, $this->conn)) + if (!@mysqli_select_db($this->conn, $database)) { - $this->error("Datenbank nicht gefunden!", mysql_error()); + $this->error("Datenbank nicht gefunden!", mysqli_error($this->conn)); return false; } return true; @@ -41,17 +41,17 @@ Simple Database Class (C) by Bastian Schroll /** * Database::query() * - * F�hrt einen MySQL Query aus + * Fuehrt einen MySQL Query aus * - * @param mixed $query Auszuf�hrender Query + * @param mixed $query Auszufuehrender Query * @return Result-Handler/FALSE */ function query($query) { - $this->result = @mysql_query($query, $this->conn); + $this->result = @mysqli_query($this->conn, $query); if ($this->result == false) { - $this->error("Fehlerhafte Datenbank Anfrage!", mysql_error()); + $this->error("Fehlerhafte Datenbank Anfrage!", mysqli_error($this->conn)); return false; } return $this->result; @@ -60,51 +60,51 @@ Simple Database Class (C) by Bastian Schroll /** * Database::fetchAssoc() * - * Liefert alle gefundnen Datens�tze als Assoc + * Liefert alle gefundnen Datensaetze als Assoc * * @param mixed $result Externer Result-Handler - * @return gefundene Datens�tze als Assoc + * @return gefundene Datensaetze als Assoc */ function fetchAssoc($result = null) { if ($result != null) { - return @mysql_fetch_assoc($result); + return @mysqli_fetch_assoc($result); } else { - return @mysql_fetch_assoc($this->result); + return @mysqli_fetch_assoc($this->result); } } /** * Database::count() * - * Z�hlt alle gefundenen Datens�tze + * Zaehlt alle gefundenen Datensaetze * * @param mixed $result Externer Result-Handler - * @return Anzahl gefundener Datens�tze + * @return Anzahl gefundener Datensaetze */ function count($result = null) { if ($result != null) { - return @mysql_num_rows($result); + return @mysqli_num_rows($result); } else { - return @mysql_num_rows($this->result); + return @mysqli_num_rows($this->result); } } /** * Database::closeConnection() * - * Schlie�t die bestehende MySQL Verbindung + * Schliesst die bestehende MySQL Verbindung * * @return TRUE/FALSE */ function closeConnection() { - if (!@mysql_close($this->conn)) + if (!@mysqli_close($this->conn)) { $this->error("Verbindung zur Datenbank konnte nicht getrennt werden!", mysql_error()); return false; diff --git a/includes/decoders/poc.py b/includes/decoders/poc.py index b0198f0..30a0e22 100644 --- a/includes/decoders/poc.py +++ b/includes/decoders/poc.py @@ -62,11 +62,23 @@ def isAllowed(poc_id): return True else: allowed = 0 + # 5.) Implementation for multicastAlarm + if globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric"): + if poc_id in globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric"): + logging.info("RIC %s as multicastAlarm delimiter", poc_id) + return True + else: + allowed = 0 + if globalVars.config.get("multicastAlarm", "multicastAlarm_ric"): + if poc_id in globalVars.config.get("multicastAlarm", "multicastAlarm_ric"): + logging.info("RIC %s as multicastAlarm message", poc_id) + return True + else: + allowed = 0 if allowed == 0: return False return True - ## # # POCSAG decoder function @@ -117,23 +129,40 @@ def decode(freq, decoded): if re.search("[0-9]{7}", poc_id) and re.search("[1-4]{1}", poc_sub): #if POC is valid if isAllowed(poc_id): + # check for double alarm if doubleFilter.checkID("POC", poc_id+poc_sub, poc_text): - 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, "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") + + logging.info("POCSAG%s: %s %s %s ", data["bitrate"], data["ric"], data["function"], data["msg"]) + # If enabled, look up description if globalVars.config.getint("POC", "idDescribed"): from includes import descriptionList - data["description"] = descriptionList.getDescription("POC", poc_id+data["functionChar"]) - # processing the alarm - try: - from includes import alarmHandler - alarmHandler.processAlarmHandler("POC", freq, data) - except: - logging.error("processing alarm failed") - logging.debug("processing alarm failed", exc_info=True) + data["description"] = descriptionList.getDescription("POC", data["ric"]+data["functionChar"]) + + # multicastAlarm processing if enabled and a message without text or delimiter RIC or netIdent_ric received + if globalVars.config.getint("multicastAlarm", "multicastAlarm") and data["ric"] != globalVars.config.get("POC", "netIdent_ric") and (data["msg"] == "" or data["ric"] in globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric")): + logging.debug(" - multicastAlarm without msg") + from includes import multicastAlarm + multicastAlarm.newEntrymultiList(data) + + # multicastAlarm processing if enabled and alarm message has been received + elif globalVars.config.getint("multicastAlarm", "multicastAlarm") and data["msg"] != "" and data["ric"] in globalVars.config.get("multicastAlarm", "multicastAlarm_ric"): + logging.debug(" - multicastAlarm with message") + from includes import multicastAlarm + multicastAlarm.multicastAlarmExec(freq, data) + + else: + # processing the alarm + try: + from includes import alarmHandler + alarmHandler.processAlarmHandler("POC", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) # in every time save old data for double alarm doubleFilter.newEntry(poc_id+poc_sub, poc_text) else: diff --git a/includes/globalVars.py b/includes/globalVars.py index 2cdcfa7..3b71248 100644 --- a/includes/globalVars.py +++ b/includes/globalVars.py @@ -9,8 +9,10 @@ Global variables """ # version info -versionNr = "2.2-dev" -buildDate = "2017/03/30" +versionNr = "2.3.1" +branch = "dev" +buildDate = "unreleased" + # Global variables config = 0 diff --git a/includes/helper/stringConverter.py b/includes/helper/stringConverter.py index 01ada06..acd9a26 100644 --- a/includes/helper/stringConverter.py +++ b/includes/helper/stringConverter.py @@ -159,7 +159,6 @@ def convertToUTF8(inputString = ""): raise # End of exception UnicodeDecodeError: check given string is already UTF-8 - pass except: logging.warning("error checking given string") diff --git a/includes/multicastAlarm.py b/includes/multicastAlarm.py new file mode 100644 index 0000000..40a8344 --- /dev/null +++ b/includes/multicastAlarm.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +multicastAlarm is the function to enable BOSwatch to work in networks that optimise the transmission of POCSAG telegrams + +@author: Fabian Kessler + +@requires: Configuration has to be set in the config.ini +""" + +import logging # Global logger +import time # timestamp for multicastAlarm + +from includes import globalVars # Global variables + +# +# ListStructure [0..n] = (Data, TimeStamp) +# +multiList = [] + +def newEntrymultiList(data): + """ + add entry to multi alarm list and remove old entries + + @return: nothing + """ + global multiList + timestamp = int(time.time()) + # multicastAlarm processing if enabled and delimiter RIC has been received + if data['ric'] == globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric"): + multiList = [] + logging.debug("delimiter RIC received - buffer cleared") + else: + multiList.append([data, timestamp]) + logging.debug("Added %s to multiList", data['ric']) + # check for old entries in multiList + for (xData, xTimestamp) in multiList[:]: + if xTimestamp < timestamp-globalVars.config.getint("multicastAlarm", "multicastAlarm_ignore_time"): + multiList.remove([xData, xTimestamp]) + logging.debug("RIC %s removed - %s sec. older than current timestamp", xData['ric'], xTimestamp-timestamp) + + +def multicastAlarmExec(freq, data): + """ + call alarmHandler for every entry in multiList + + @return: nothing + """ + logging.debug("data before update from multiList: %s", data) + for (xData, _) in multiList: + #update data with values multiList + data['ric'] = xData['ric'] + data['function'] = xData['function'] + data['functionChar'] = xData['functionChar'] + data['description'] = xData['description'] + logging.debug("data after update from multiList: %s", data) + try: + from includes import alarmHandler + alarmHandler.processAlarmHandler("POC", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) diff --git a/includes/pynma/pynma.py b/includes/pynma/pynma.py index 08a71cb..5649f05 100644 --- a/includes/pynma/pynma.py +++ b/includes/pynma/pynma.py @@ -3,14 +3,14 @@ from xml.dom.minidom import parseString try: - from http.client import HTTPSConnection + from http.client import HTTPSConnection except ImportError: - from httplib import HTTPSConnection + from httplib import HTTPSConnection try: - from urllib.parse import urlencode + from urllib.parse import urlencode except ImportError: - from urllib import urlencode + from urllib import urlencode __version__ = "1.0" @@ -55,10 +55,10 @@ takes 2 optional arguments: def delkey(self, key): "Removes a key (unregister ?)" - if type(key) == str: + if isinstance(key, str): if key in self._apikey: self._apikey.remove(key) - elif type(key) == list: + elif isinstance(key, list): for k in key: if key in self._apikey: self._apikey.remove(k) @@ -71,7 +71,7 @@ takes 2 optional arguments: def pushWithAPIKey(self, apikey=[], application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False): """Special Funktion""" if apikey: - if type(apikey) == str: + if isinstance(apikey, str): apikey = [apikey] self._apikey = uniq(apikey) return self.push(application, event, description, url, contenttype, priority, batch_mode, html) diff --git a/includes/shellHeader.py b/includes/shellHeader.py index 561603a..ab82eae 100644 --- a/includes/shellHeader.py +++ b/includes/shellHeader.py @@ -31,6 +31,7 @@ def printHeader(args): print " by Bastian Schroll, Jens Herrmann " print "" print "SW Version: "+globalVars.versionNr + print "Branch: "+globalVars.branch print "Build Date: "+globalVars.buildDate print "" diff --git a/install.sh b/install.sh index 5c251ea..5470b24 100644 --- a/install.sh +++ b/install.sh @@ -12,7 +12,7 @@ function exitcodefunction { echo "Action: $action on $module failed." echo "Exitcode: $errorcode" echo "" - echo " -> If you want to open an Issue at https://github.com/Schrolli91/BOSWatch/issues" + echo " -> If you want to open an issue at https://github.com/Schrolli91/BOSWatch/issues" echo " please post the logfile, located at $boswatchpath/install/setup_log.txt" exit 1 else @@ -51,7 +51,7 @@ didBackup=false if [ -f $boswatchpath/BOSWatch/boswatch.py ]; then echo "Old installation found!" echo "A backup will be copied to $boswatchpath/old" - + mkdir /tmp/boswatch mv $boswatchpath/BOSWatch/* /tmp/boswatch/ didBackup=true @@ -61,7 +61,7 @@ fi if [ -f $boswatchpath/boswatch.py ]; then echo "Old installation found!" echo "A backup will be copied to $boswatchpath/old" - + mkdir /tmp/boswatch mv $boswatchpath/* /tmp/boswatch/ didBackup=true @@ -78,11 +78,10 @@ for (( i=1; i<=$#; i=$i+2 )); do -b|--branch) case $arg2 in dev|develop) echo " !!! WARNING: you are using the DEV BRANCH !!! "; branch=dev ;; - beta) echo " !!! WARNING: you are using the BETA BRANCH !!! "; branch=beta ;; *) branch=master ;; esac ;; - -p|--path) echo " !!! WARNING: you install BOSWATCH to alternative path !!! "; boswatchpath=$arg2 ;; + -p|--path) echo " !!! WARNING: you'll install BOSWATCH to alternative path !!! "; boswatchpath=$arg2 ;; *) echo "Internal error!" ; exit 1 ;; esac @@ -205,16 +204,15 @@ tput cup 15 5 echo "-> configure..........................." cd $boswatchpath/ chmod +x * -echo $'# BOSWatch - blacklist the DVB drivers to avoid conflict 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 +echo $'# BOSWatch - 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 echo "BOSWatch is now installed in $boswatchpath/" echo "Installation ready!" tput cup 19 3 -echo "Watch out: to run BOSWatch you have to generate and modify the config.ini!" -echo "Do the following steps to have a running version of BOSWatch:" -echo "sudo cp $boswatchpath/BOSWatch/config/config.template.ini $boswatchpath/BOSWatch/config/config.ini" -echo "sudo nano $boswatchpath/BOSWatch/config/config.ini" +echo "Watch out: to run BOSWatch you have to modify the config.ini!" +echo "Do the following step to do so:" +echo "sudo nano $boswatchpath/config/config.ini" echo "and modify the config as you need. This step is optional if you are upgrading an old version of BOSWatch. " tput cnorm diff --git a/plugins/FFAgent/FFAgent.py b/plugins/FFAgent/FFAgent.py index 8dcff85..561ca86 100644 --- a/plugins/FFAgent/FFAgent.py +++ b/plugins/FFAgent/FFAgent.py @@ -132,9 +132,10 @@ def run(typ,freq,data): "selectiveCallCode": selectiveCallCode, "hmac": hmac.new(webApiKey, webApiToken + selectiveCallCode + accessToken + alarmData, digestmod=hashlib.sha256).hexdigest() } + logging.debug(alarmHeaders) if globalVars.config.get("FFAgent", "live") == "1": - r = requests.post(url, data=alarmData, headers=headers, verify=serverCertFile, cert=(clientCertFile, clientCertPass)) + r = requests.post(url, data=alarmData, headers=alarmHeaders, verify=serverCertFile, cert=(clientCertFile, clientCertPass)) else: r = requests.post(url, data=alarmData, headers=alarmHeaders, verify=serverCertFile) diff --git a/plugins/MySQL/MySQL.py b/plugins/MySQL/MySQL.py index 5941571..c38410f 100644 --- a/plugins/MySQL/MySQL.py +++ b/plugins/MySQL/MySQL.py @@ -21,23 +21,23 @@ from includes import globalVars # Global variables from includes.helper import configHandler def isSignal(poc_id): - """ - @type poc_id: string - @param poc_id: POCSAG Ric + """ + @type poc_id: string + @param poc_id: POCSAG Ric - @requires: Configuration has to be set in the config.ini + @requires: Configuration has to be set in the config.ini - @return: True if the Ric is Signal, other False - @exception: none - """ - # If RIC is Signal return True, else False - if globalVars.config.get("POC", "netIdent_ric"): - if poc_id in globalVars.config.get("POC", "netIdent_ric"): - logging.info("RIC %s is net ident", poc_id) - return True - else: - logging.info("RIC %s is no net ident", poc_id) - return False + @return: True if the Ric is Signal, other False + @exception: none + """ + # If RIC is Signal return True, else False + if globalVars.config.get("POC", "netIdent_ric"): + if poc_id in globalVars.config.get("POC", "netIdent_ric"): + logging.info("RIC %s is net ident", poc_id) + return True + else: + logging.info("RIC %s is no net ident", poc_id) + return False ## @@ -87,11 +87,11 @@ def run(typ,freq,data): if configHandler.checkConfig("MySQL"): #read and debug the config try: - # + # # Connect to MySQL # logging.debug("connect to MySQL") - connection = mysql.connector.connect(host = globalVars.config.get("MySQL","dbserver"), user = globalVars.config.get("MySQL","dbuser"), passwd = globalVars.config.get("MySQL","dbpassword"), db = globalVars.config.get("MySQL","database"), charset='utf8') + connection = mysql.connector.connect(host = globalVars.config.get("MySQL","dbserver"), port = globalVars.config.get("MySQL","dbport"), user = globalVars.config.get("MySQL","dbuser"), passwd = globalVars.config.get("MySQL","dbpassword"), db = globalVars.config.get("MySQL","database"), charset='utf8') cursor = connection.cursor() except: logging.error("cannot connect to MySQL") @@ -111,11 +111,14 @@ def run(typ,freq,data): elif typ == "POC": if isSignal(data["ric"]): - cursor.execute("UPDATE "+globalVars.config.get("MySQL","tableSIG")+" SET time = NOW() WHERE ric = '"+data["ric"]+"';") - if cursor.rowcount == 0: + if globalVars.config.getint("POC","netIdent_history"): cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (time,ric) VALUES (NOW(), '"+data["ric"]+"');") + else: + cursor.execute("UPDATE "+globalVars.config.get("MySQL","tableSIG")+" SET time = NOW() WHERE ric = '"+data["ric"]+"';") + if cursor.rowcount == 0: + cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (time,ric) VALUES (NOW(), '"+data["ric"]+"');") else: - cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tablePOC")+" (time, ric, function, functionChar, msg, bitrate, description) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["ric"], data["function"], data["functionChar"], data["msg"], data["bitrate"], data["description"])) + cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tablePOC")+" (time, ric, function, functionChar, msg, bitrate, description) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["ric"], data["function"], data["functionChar"], data["msg"], data["bitrate"], data["description"])) else: logging.warning("Invalid Typ: %s", typ) diff --git a/plugins/Pushover/Pushover.py b/plugins/Pushover/Pushover.py index 1f97c95..d220de6 100644 --- a/plugins/Pushover/Pushover.py +++ b/plugins/Pushover/Pushover.py @@ -9,13 +9,15 @@ Pushover-Plugin to send FMS-, ZVEI- and POCSAG - messages to Pushover Clients @requires: Pushover-Configuration has to be set in the config.ini """ -import logging # Global logger -import httplib #for the HTTP request +import logging # Global logger +import httplib # for the HTTP request import urllib from includes import globalVars # Global variables -#from includes.helper import timeHandler +# from includes.helper import timeHandler from includes.helper import configHandler +from includes.helper import wildcardHandler + ## # @@ -23,16 +25,16 @@ from includes.helper import configHandler # will be called one time by the pluginLoader on start # def onLoad(): - """ - While loading the plugins by pluginLoader.loadPlugins() - this onLoad() routine is called one time for initialize the plugin + """ + While loading the plugins by pluginLoader.loadPlugins() + this onLoad() routine is called one time for initialize the plugin - @requires: nothing + @requires: nothing - @return: nothing - """ - # nothing to do for this plugin - return + @return: nothing + """ + # nothing to do for this plugin + return ## @@ -40,82 +42,112 @@ def onLoad(): # Main function of Pushover-plugin # will be called by the alarmHandler # -def run(typ,freq,data): - """ - This function is the implementation of the Pushover-Plugin. - It will send the data to Pushover API +def run(typ, freq, data): + """ + This function is the implementation of the Pushover-Plugin. + It will send the data to Pushover API - @type typ: string (FMS|ZVEI|POC) - @param typ: Typ of the dataset - @type data: map of data (structure see readme.md in plugin folder) - @param data: Contains the parameter - @type freq: string - @keyword freq: frequency of the SDR Stick + @type typ: string (FMS|ZVEI|POC) + @param typ: Typ of the dataset + @type data: map of data (structure see readme.md in plugin folder) + @param data: Contains the parameter + @type freq: string + @keyword freq: frequency of the SDR Stick - @requires: Pushover-Configuration has to be set in the config.ini + @requires: Pushover-Configuration has to be set in the config.ini - @return: nothing - """ - try: - if configHandler.checkConfig("Pushover"): #read and debug the config + @return: nothing + """ + try: + if configHandler.checkConfig("Pushover"): # read and debug the config - try: - # - # Pushover-Request - # - logging.debug("send Pushover %s", typ) + if typ == "FMS": + # + # building message for FMS + # - if data["function"] == '1': - priority = globalVars.config.get("Pushover", "SubA") - elif data["function"] == '2': - priority = globalVars.config.get("Pushover", "SubB") - elif data["function"] == '3': - priority = globalVars.config.get("Pushover", "SubC") - elif data["function"] == '4': - priority = globalVars.config.get("Pushover", "SubD") - else: - priority = 0 + message = globalVars.config.get("Pushover", "fms_message") + title = globalVars.config.get("Pushover", "fms_title") + priority = globalVars.config.get("Pushover", "fms_prio") + logging.debug("Sending message: %s", message) - conn = httplib.HTTPSConnection("api.pushover.net:443") - conn.request("POST", "/1/messages.json", - urllib.urlencode({ - "token": globalVars.config.get("Pushover", "api_key"), - "user": globalVars.config.get("Pushover", "user_key"), - "message": ""+data["description"]+"
"+data["msg"].replace(";", "
"), - "html": globalVars.config.get("Pushover", "html"), - "title": globalVars.config.get("Pushover", "title"), - "priority": priority, - "retry": globalVars.config.get("Pushover", "retry"), - "expire": globalVars.config.get("Pushover", "expire") - }),{"Content-type": "application/x-www-form-urlencoded"}) + elif typ == "ZVEI": + # + # building message for ZVEI + # + message = globalVars.config.get("Pushover", "zvei_message") + title = globalVars.config.get("Pushover", "zvei_title") + priority = globalVars.config.get("Pushover", "zvei_prio") + logging.debug("Sending message: %s", message) - except: - logging.error("cannot send Pushover request") - logging.debug("cannot send Pushover request", exc_info=True) - return + elif typ == "POC": - else: - try: - # - # check Pushover-Response - # - response = conn.getresponse() - if str(response.status) == "200": #Check Pushover Response and print a Log or Error - logging.debug("Pushover response: %s - %s" , str(response.status), str(response.reason)) - else: - logging.warning("Pushover response: %s - %s" , str(response.status), str(response.reason)) - except: #otherwise - logging.error("cannot get Pushover response") - logging.debug("cannot get Pushover response", exc_info=True) - return + # + # Pushover-Request + # + logging.debug("send Pushover for %s", typ) - finally: - logging.debug("close Pushover-Connection") - try: - request.close() - except: - pass + if data["function"] == '1': + priority = globalVars.config.get("Pushover", "SubA") + elif data["function"] == '2': + priority = globalVars.config.get("Pushover", "SubB") + elif data["function"] == '3': + priority = globalVars.config.get("Pushover", "SubC") + elif data["function"] == '4': + priority = globalVars.config.get("Pushover", "SubD") + else: + priority = 0 + message = globalVars.config.get("Pushover", "poc_message") + title = globalVars.config.get("Pushover", "poc_title") - except: - logging.error("unknown error") - logging.debug("unknown error", exc_info=True) + else: + logging.warning("Invalid type: %s", typ) + + try: + # replace the wildcards + message = wildcardHandler.replaceWildcards(message, data) + title = wildcardHandler.replaceWildcards(title, data) + + # start the connection + conn = httplib.HTTPSConnection("api.pushover.net:443") + conn.request("POST", "/1/messages.json", + urllib.urlencode({ + "token": globalVars.config.get("Pushover", "api_key"), + "user": globalVars.config.get("Pushover", "user_key"), + "message": message, + "html": globalVars.config.get("Pushover", "html"), + "title": title, + "priority": priority, + "retry": globalVars.config.get("Pushover", "retry"), + "expire": globalVars.config.get("Pushover", "expire") + }), {"Content-type": "application/x-www-form-urlencoded"}) + + except: + logging.error("cannot send Pushover request") + logging.debug("cannot send Pushover request", exc_info=True) + return + + try: + # + # check Pushover-Response + # + response = conn.getresponse() + if str(response.status) == "200": # Check Pushover Response and print a Log or Error + logging.debug("Pushover response: %s - %s", str(response.status), str(response.reason)) + else: + logging.warning("Pushover response: %s - %s", str(response.status), str(response.reason)) + except: # otherwise + logging.error("cannot get Pushover response") + logging.debug("cannot get Pushover response", exc_info=True) + return + + finally: + logging.debug("close Pushover-Connection") + try: + request.close() + except: + pass + + except: + logging.error("unknown error") + logging.debug("unknown error", exc_info=True) diff --git a/plugins/Sms77/Sms77.py b/plugins/Sms77/Sms77.py index e4353d1..6d30a1a 100644 --- a/plugins/Sms77/Sms77.py +++ b/plugins/Sms77/Sms77.py @@ -58,7 +58,7 @@ def run(typ,freq,data): """ try: if configHandler.checkConfig("Sms77"): #read and debug the config - + # create an empty message an fill it with the required information message = "Alarm" if typ == "FMS": diff --git a/plugins/Telegram/Telegram.py b/plugins/Telegram/Telegram.py index fc4acc7..dc4cc6e 100644 --- a/plugins/Telegram/Telegram.py +++ b/plugins/Telegram/Telegram.py @@ -11,9 +11,11 @@ Plugin to send FMS-, ZVEI- and POCSAG-messages via Telegram # Imports # import logging # Global logger -import urllib, telegram, googlemaps +import telegram from telegram.error import (TelegramError, Unauthorized, BadRequest, NetworkError) from includes import globalVars # Global variables +if globalVars.config.get("Telegram","RICforLocationAPIKey"): + import urllib, googlemaps # Helper function, uncomment to use from includes.helper import wildcardHandler diff --git a/plugins/firEmergency/firEmergency.py b/plugins/firEmergency/firEmergency.py index a724cd2..89a325c 100644 --- a/plugins/firEmergency/firEmergency.py +++ b/plugins/firEmergency/firEmergency.py @@ -5,7 +5,7 @@ firEmergency-Plugin to dispatch ZVEI- and POCSAG - messages to firEmergency firEmergency configuration: -- set input to "FMS32" at Port 5555 +- set input to "Standartschnittstelle" at Port 5555 @autor: Smith-fms diff --git a/plugins/httpRequest/httpRequest.py b/plugins/httpRequest/httpRequest.py index 744f621..1622a8b 100644 --- a/plugins/httpRequest/httpRequest.py +++ b/plugins/httpRequest/httpRequest.py @@ -68,11 +68,13 @@ def run(typ,freq,data): try: # - # Replace special characters in data Strings for URL + # Make a copy of the data field to not overwrite the data in it + # Replace special characters in dataCopy Strings for URL # - for key in data: - if isinstance(data[key], basestring): - data[key] = urllib.quote(data[key]) + dataCopy = dict(data) + for key in dataCopy: + if isinstance(dataCopy[key], basestring): + dataCopy[key] = urllib.quote(dataCopy[key]) # # Get URLs # @@ -90,7 +92,7 @@ def run(typ,freq,data): # replace wildcards # for (i, url) in enumerate(urls): - urls[i] = wildcardHandler.replaceWildcards(urls[i].strip(), data) + urls[i] = wildcardHandler.replaceWildcards(urls[i].strip(), dataCopy) # # HTTP-Request # diff --git a/plugins/notifyMyAndroid/notifyMyAndroid.py b/plugins/notifyMyAndroid/notifyMyAndroid.py index 7fa535f..a8ab127 100644 --- a/plugins/notifyMyAndroid/notifyMyAndroid.py +++ b/plugins/notifyMyAndroid/notifyMyAndroid.py @@ -268,23 +268,23 @@ def run(typ,freq,data): # nothing found pass # 3. lets look for ric prefixes in pocAPIKeyList - for prefixLength in reversed(range(6)): - ricPrefix = data['ric'][:prefixLength] - #fill the ric with stars - ricPrefix = ricPrefix.ljust(8,'*') - try: - xID = ricPrefix - # data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) - for i in range(len(pocAPIKeyList[xID])): - xEvent = event - (xAPIKey, xPriority, xEventPrefix) = pocAPIKeyList[xID][i] - if len(xEventPrefix) > 0: - xEvent = xEventPrefix + ": " + xEvent - response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) - checkResponse(response, xAPIKey) - except KeyError: - # nothing found - pass + for prefixLength in reversed(range(6)): + ricPrefix = data['ric'][:prefixLength] + #fill the ric with stars + ricPrefix = ricPrefix.ljust(8,'*') + try: + xID = ricPrefix + # data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) + for i in range(len(pocAPIKeyList[xID])): + xEvent = event + (xAPIKey, xPriority, xEventPrefix) = pocAPIKeyList[xID][i] + if len(xEventPrefix) > 0: + xEvent = xEventPrefix + ": " + xEvent + response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) + checkResponse(response, xAPIKey) + except KeyError: + # nothing found + pass # end if "POC" in typ # end if usecsv == True diff --git a/service/README.md b/service/README.md index 41337a9..805ef88 100644 --- a/service/README.md +++ b/service/README.md @@ -8,10 +8,14 @@ We assume that BOSWatch is installed to /opt/boswatch! Otherwise you need to ada Enter the frequency and the decoder(s) you want to use in line 7; you can add more specific switches if you need to ### Install the service -1. Copy the file to /lib/systemd/system: sudo cp /opt/boswatch/service/boswatch.service /lib/systemd/system/ -2. Change the rights: sudo chmod 644 /lib/systemd/system/boswatch.service -3. Enable the service: sudo systemcl enable boswatch.service -4. Start the service: sudo systemcl start boswatch.service +1. Use the install-script install_service.sh as sudo: `sudo bash install_service.sh` (self explaining) + +OR + +1. Copy the file to /etc/systemd/system: sudo cp /opt/boswatch/service/boswatch.service /etc/systemd/system/ +2. Enable the service: sudo systemctl enable boswatch.service +3. Start the service: sudo systemctl start boswatch.service +4. Check the status: sudo systemctl status boswatch.service --- diff --git a/service/install_service.sh b/service/install_service.sh new file mode 100644 index 0000000..2789a35 --- /dev/null +++ b/service/install_service.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Tiny script to install BOSWatch-service via systemctl +# Just a few simple steps are required to (un)register your service + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root!" 1>&2 + exit 1 +fi + +read -p"Do you want to install (i) or remove (r) the service? " action + +if [ "$action" == "i" ]; then + + # 1 Check whether the right data are in the service-file + + read -p"Did you adapt the file boswatch.service (y/n)? " response + + if [ "$response" == "y" ]; then + # 2 Copy the file + cp boswatch.service /etc/systemd/system + + # 3 Enable the service and check status + systemctl enable boswatch.service + systemctl is-enabled boswatch.service + + # 4 fire it up + systemctl start boswatch.service + + # 5 post the status + systemctl status boswatch.service + elif [ "$response" == "n" ]; then + echo "Please adapt your personal boswatch.service-file" + exit 1 + else + echo "Invalid input - please try again" + exit 1 + fi +elif [ "$action" == "r" ]; then # we want to remove the service + # stop it... + systemctl stop boswatch.service + + # disable it + systemctl disable boswatch.service + + # and remove it + rm /etc/systemd/system/boswatch.service +else # error handling + echo "Invalid input - please try again" + exit 1 +fi