Merge pull request #53 from BOSWatch/develop

dev to master
This commit is contained in:
Bastian Schroll 2020-07-17 07:38:26 +02:00 committed by GitHub
commit bd9228f0cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 310 additions and 72 deletions

View file

@ -18,6 +18,8 @@ import time
import logging import logging
import threading import threading
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from boswatch.utils import paths
from boswatch.processManager import ProcessManager
logging.debug("- %s loaded", __name__) logging.debug("- %s loaded", __name__)
@ -63,3 +65,23 @@ class InputBase(ABC):
self._inputQueue.put_nowait((data, time.time())) self._inputQueue.put_nowait((data, time.time()))
logging.debug("Add received data to queue") logging.debug("Add received data to queue")
print(data) print(data)
def getDecoderInstance(self, decoderConfig, StdIn):
mmProc = ProcessManager(str(decoderConfig.get("path", default="multimon-ng")), textMode=True)
if decoderConfig.get("fms", default=0):
mmProc.addArgument("-a FMSFSK")
if decoderConfig.get("zvei", default=0):
mmProc.addArgument("-a ZVEI1")
if decoderConfig.get("poc512", default=0):
mmProc.addArgument("-a POCSAG512")
if decoderConfig.get("poc1200", default=0):
mmProc.addArgument("-a POCSAG1200")
if decoderConfig.get("poc2400", default=0):
mmProc.addArgument("-a POCSAG2400")
if decoderConfig.get("char", default=0):
mmProc.addArgument("-C " + str(decoderConfig.get("char")))
mmProc.addArgument("-f alpha")
mmProc.addArgument("-t raw -")
mmProc.setStdin(StdIn)
mmProc.setStderr(open(paths.LOG_PATH + "multimon-ng.log", "a"))
return mmProc

View file

@ -40,21 +40,7 @@ class LineInInput(InputBase):
lineInProc.setStderr(open(paths.LOG_PATH + "asla.log", "a")) lineInProc.setStderr(open(paths.LOG_PATH + "asla.log", "a"))
lineInProc.start() lineInProc.start()
mmProc = ProcessManager(str(lineInConfig.get("mmPath", default="multimon-ng")), textMode=True) mmProc = self.getDecoderInstance(decoderConfig, lineInProc.stdout)
if decoderConfig.get("fms", default=0):
mmProc.addArgument("-a FMSFSK")
if decoderConfig.get("zvei", default=0):
mmProc.addArgument("-a ZVEI1")
if decoderConfig.get("poc512", default=0):
mmProc.addArgument("-a POCSAG512")
if decoderConfig.get("poc1200", default=0):
mmProc.addArgument("-a POCSAG1200")
if decoderConfig.get("poc2400", default=0):
mmProc.addArgument("-a POCSAG2400")
mmProc.addArgument("-f alpha")
mmProc.addArgument("-t raw -")
mmProc.setStdin(lineInProc.stdout)
mmProc.setStderr(open(paths.LOG_PATH + "multimon-ng.log", "a"))
mmProc.start() mmProc.start()
logging.info("start decoding") logging.info("start decoding")

View file

@ -0,0 +1,61 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""!
____ ____ ______ __ __ __ _____
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
German BOS Information Script
by Bastian Schroll
@file: pulseaudioInput.py
@date: 18.04.2020, 29.06.2020
@author: Philipp von Kirschbaum, b-watch
@description: Input source for PulseAudio
"""
import logging
from boswatch.utils import paths
from boswatch.processManager import ProcessManager
from boswatch.inputSource.inputBase import InputBase
logging.debug("- %s loaded", __name__)
class PulseAudioInput(InputBase):
"""!Class for the PulseAudio input source"""
def _runThread(self, dataQueue, PulseAudioConfig, decoderConfig):
PulseAudioProc = None
mmProc = None
try:
PulseAudioProc = ProcessManager("parec")
PulseAudioProc.addArgument("--channels=1") # supress any other outputs
PulseAudioProc.addArgument("--format=s16le") # set output format (16bit)
PulseAudioProc.addArgument("--rate=22050") # set output sampling rate (22050Hz)
PulseAudioProc.addArgument("--device=" +
str(PulseAudioConfig.get("device", default="boswatch")) +
".monitor") # sink name
PulseAudioProc.setStderr(open(paths.LOG_PATH + "pulseaudio.log", "a"))
PulseAudioProc.start()
mmProc = self.getDecoderInstance(decoderConfig, PulseAudioProc.stdout)
mmProc.start()
logging.info("start decoding")
while self._isRunning:
if not PulseAudioProc.isRunning:
logging.warning("PulseAudio was down - try to restart")
PulseAudioProc.start()
elif not mmProc.isRunning:
logging.warning("multimon was down - try to restart")
mmProc.start()
elif PulseAudioProc.isRunning and mmProc.isRunning:
line = mmProc.readline()
if line:
self.addToQueue(line)
except:
logging.exception("error in PulseAudio input routine")
finally:
mmProc.stop()
PulseAudioProc.stop()

View file

@ -41,21 +41,7 @@ class SdrInput(InputBase):
sdrProc.setStderr(open(paths.LOG_PATH + "rtl_fm.log", "a")) sdrProc.setStderr(open(paths.LOG_PATH + "rtl_fm.log", "a"))
sdrProc.start() sdrProc.start()
mmProc = ProcessManager(str(sdrConfig.get("mmPath", default="multimon-ng")), textMode=True) mmProc = self.getDecoderInstance(decoderConfig, sdrProc.stdout)
if decoderConfig.get("fms", default=0):
mmProc.addArgument("-a FMSFSK")
if decoderConfig.get("zvei", default=0):
mmProc.addArgument("-a ZVEI1")
if decoderConfig.get("poc512", default=0):
mmProc.addArgument("-a POCSAG512")
if decoderConfig.get("poc1200", default=0):
mmProc.addArgument("-a POCSAG1200")
if decoderConfig.get("poc2400", default=0):
mmProc.addArgument("-a POCSAG2400")
mmProc.addArgument("-f alpha")
mmProc.addArgument("-t raw -")
mmProc.setStdin(sdrProc.stdout)
mmProc.setStderr(open(paths.LOG_PATH + "multimon-ng.log", "a"))
mmProc.start() mmProc.start()
logging.info("start decoding") logging.info("start decoding")

View file

@ -51,6 +51,7 @@ from boswatch.utils import header
from boswatch.utils import misc from boswatch.utils import misc
from boswatch.inputSource.sdrInput import SdrInput from boswatch.inputSource.sdrInput import SdrInput
from boswatch.inputSource.lineInInput import LineInInput from boswatch.inputSource.lineInInput import LineInInput
from boswatch.inputSource.pulseaudioInput import PulseAudioInput
header.logoToLog() header.logoToLog()
header.infoToLog() header.infoToLog()
@ -91,6 +92,8 @@ try:
inputSource = SdrInput(inputQueue, bwConfig.get("inputSource", "sdr"), bwConfig.get("decoder")) inputSource = SdrInput(inputQueue, bwConfig.get("inputSource", "sdr"), bwConfig.get("decoder"))
elif bwConfig.get("client", "inputSource") == "lineIn": elif bwConfig.get("client", "inputSource") == "lineIn":
inputSource = LineInInput(inputQueue, bwConfig.get("inputSource", "lineIn"), bwConfig.get("decoder")) inputSource = LineInInput(inputQueue, bwConfig.get("inputSource", "lineIn"), bwConfig.get("decoder"))
elif bwConfig.get("client", "inputSource") == "PulseAudio":
inputSource = PulseAudioInput(inputQueue, bwConfig.get("inputSource", "PulseAudio"), bwConfig.get("decoder"))
else: else:
logging.fatal("Invalid input source: %s", bwConfig.get("client", "inputSource")) logging.fatal("Invalid input source: %s", bwConfig.get("client", "inputSource"))
exit(1) exit(1)

View file

@ -86,7 +86,7 @@ try:
incomingQueue = queue.Queue() incomingQueue = queue.Queue()
bwServer = TCPServer(incomingQueue) bwServer = TCPServer(incomingQueue)
if bwServer.start(): if bwServer.start(port=bwConfig.get('server', 'port', default=8080)):
while 1: while 1:
if incomingQueue.empty(): # pause only when no data if incomingQueue.empty(): # pause only when no data

View file

@ -27,11 +27,9 @@ inputSource:
squelch: 1 squelch: 1
gain: 100 gain: 100
rtlPath: /usr/bin/rtl_fm rtlPath: /usr/bin/rtl_fm
mmPath: /opt/multimon/multimon-ng
lineIn: lineIn:
card: 1 card: 1
device: 0 device: 0
mmPath: /opt/multimon/multimon-ng
decoder: decoder:
fms: yes fms: yes
@ -39,3 +37,5 @@ decoder:
poc512: yes poc512: yes
poc1200: yes poc1200: yes
poc2400: yes poc2400: yes
Path: /opt/multimon/multimon-ng
char: DE

View file

@ -11,7 +11,7 @@ zwingend in die Konfiguration eingetragen werden.
|Feld|Beschreibung|Default| |Feld|Beschreibung|Default|
|----|------------|-------| |----|------------|-------|
|name|Name zur Identifizierung der Client Instanz|| |name|Name zur Identifizierung der Client Instanz||
|inputSource|Art der zu nutzenden Input Quelle (`sdr` oder `lineIn`)|| |inputSource|Art der zu nutzenden Input Quelle (`sdr`, `lineIn` oder `PulseAudio`)||
|useBroadcast|Verbindungsdaten per [Broadcast](information/broadcast.md) beziehen|no| |useBroadcast|Verbindungsdaten per [Broadcast](information/broadcast.md) beziehen|no|
|reconnectDelay|Verzögerung für erneuten Verbindungsversuch zum Server|3| |reconnectDelay|Verzögerung für erneuten Verbindungsversuch zum Server|3|
|sendTries|Anzahl der Sendeversuche eines Pakets|3| |sendTries|Anzahl der Sendeversuche eines Pakets|3|
@ -36,7 +36,10 @@ server:
--- ---
### `inputSource:` ### `inputSource:`
Es gibt die Auswahl zwischen `sdr` oder `lineIn` als Input Quelle Es gibt die Auswahl zwischen `sdr`, `lineIn` oder `PulseAudio` als Input Quelle.
Mit `sdr` wird direkt per **rtl_sdr** die zu empfangende Frequenz an Multimon-NG weitergereicht.
Mit `lineIn` wird eine Quelle die (per **ALSA**) direkt an die Soundkarte angeschlossen ist an Multimon-NG weitergereicht.
Mit `PulseAudio` wird ein PulseAudio-Sink an Multimon-NG weitergereicht, z.B. in Kombination mit [RTLSDR-Airband](https://github.com/szpajder/RTLSDR-Airband) und/oder Docker.
#### `sdr:` #### `sdr:`
|Feld|Beschreibung|Default| |Feld|Beschreibung|Default|
@ -47,7 +50,6 @@ Es gibt die Auswahl zwischen `sdr` oder `lineIn` als Input Quelle
|squelch|Einstellung der Rauschsperre|1| |squelch|Einstellung der Rauschsperre|1|
|gain|Verstärkung des Eingangssignals|100| |gain|Verstärkung des Eingangssignals|100|
|rtlPath|Pfad zur rtl_fm Binary|rtl_fm| |rtlPath|Pfad zur rtl_fm Binary|rtl_fm|
|mmPath|Pfad zur multimon-ng Binary|multimon-ng|
**Beispiel:** **Beispiel:**
```yaml ```yaml
@ -59,14 +61,12 @@ inputSource:
squelch: 1 squelch: 1
gain: 100 gain: 100
rtlPath: /usr/bin/rtl-fm rtlPath: /usr/bin/rtl-fm
mmPath: /opt/multimon/multimon-ng
``` ```
#### `lineIn:` #### `lineIn:`
|Feld|Beschreibung|Default| |Feld|Beschreibung|Default|
|----|------------|-------| |----|------------|-------|
|device|die device Id der Soundkarte|1| |device|die device Id der Soundkarte|1|
|mmPath|Pfad zur multimon-ng Binary|multimon-ng|
**Device herausfinden** **Device herausfinden**
Durch eingabe des Befehls `aplay -l` werden alle Soundkarten ausgegeben. Das schaut ungefähr so aus: Durch eingabe des Befehls `aplay -l` werden alle Soundkarten ausgegeben. Das schaut ungefähr so aus:
@ -107,9 +107,30 @@ inputSource:
lineIn: lineIn:
card: 1 card: 1
device: 0 device: 0
mmPath: /opt/multimon/multimon-ng
``` ```
#### `PulseAudio:`
|Feld|Beschreibung|Default|
|----|------------|-------|
|device|Der Sinks-Name der Quelle|boswatch|
**Device herausfinden**
Durch eingabe des Befehls `pacmd list-sinks | grep name:` werden alle Sinks ausgegeben. Beispiel:
```console
bash-5.0# pacmd list-sinks | grep name:
name: <boswatch>
```
In der Konfiguration wird das Feld `device` nun auf den den Namen des gewünschten Sinks gesetzt (ohne spitze Klammern, <>).
**Beispiel:**
```yaml
inputSource:
...
PulseAudio:
device: boswatch
```
--- ---
### `decoder:` ### `decoder:`
|Feld|Beschreibung|Default| |Feld|Beschreibung|Default|
@ -119,6 +140,20 @@ inputSource:
|poc512|POCSAG Decoder (Bitrate 512)|no| |poc512|POCSAG Decoder (Bitrate 512)|no|
|poc1200|POCSAG Decoder (Bitrate 1200)|no| |poc1200|POCSAG Decoder (Bitrate 1200)|no|
|poc2400|POCSAG Decoder (Bitrate 2400)|no| |poc2400|POCSAG Decoder (Bitrate 2400)|no|
|path|Pfad zur multimon-ng Binary|multimon-ng|
|char|multimon-ng char-Set|not set|
**Beispiel:**
```yaml
decoder:
fms: yes
zvei: yes
poc512: no
poc1200: no
poc2400: yes
path: /opt/multimon/multimon-ng
char: DE
```
--- ---
## Server ## Server

View file

@ -0,0 +1,49 @@
# <center>Double Filter</center>
---
## Beschreibung
Mit diesem Modul ist es möglich, die Pakete auf Duplikate zu Filtern. Je nach Konfiguration werden doppelte Pakete im aktuellen Router weitergeleitet oder verworfen.
## Unterstütze Alarmtypen
- Fms
- Pocsag
- Zvei
## Resource
`filter.doubleFilter`
## Konfiguration
|Feld|Beschreibung|Default|
|----|------------|-------|
|ignoreTime|Zeitfenster für doppelte Pakte in Sekunden|10|
|maxEntry|Maximale Anzahl an Paketen in der Vergleichsliste|20|
|pocsagFields|Liste der Pocsag Felder zum Vergleichen: `ric`, `subric` und/oder `message`|`ric,subric`|
**Beispiel:**
```yaml
- type: module
res: filter.doubleFilter
config:
ignoreTime: 30
maxEntry: 10
pocsagFields:
- ric
- subric
```
---
## Modul Abhängigkeiten
- keine
---
## Externe Abhängigkeiten
- keine
---
## Paket Modifikationen
- keine
---
## Zusätzliche Wildcards
- keine

View file

@ -5,8 +5,13 @@
Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden.
Außerdem werden Locations versendet, wenn die Felder `lat` und `lon` im Paket definiert sind. (beispielsweise durch das [Geocoding](../modul/geocoding.md) Modul) Außerdem werden Locations versendet, wenn die Felder `lat` und `lon` im Paket definiert sind. (beispielsweise durch das [Geocoding](../modul/geocoding.md) Modul)
Die abarbeitung der Alarmierungen erfolgt per Queue nach den Limits der Telegram API, damit keine Nachrichten verloren gehen, diese Funktion kann mit dem ```queue``` Parameter deaktiviert werden.
## Unterstütze Alarmtypen ## Unterstütze Alarmtypen
- Fms
- Pocsag - Pocsag
- Zvei
- Msg
## Resource ## Resource
`telegram` `telegram`
@ -15,9 +20,13 @@ Außerdem werden Locations versendet, wenn die Felder `lat` und `lon` im Paket d
|Feld|Beschreibung|Default| |Feld|Beschreibung|Default|
|----|------------|-------| |----|------------|-------|
|message|Format der Nachricht||
|botToken|Der Api-Key des Telegram-Bots|| |botToken|Der Api-Key des Telegram-Bots||
|chatIds|Liste mit Chat-Ids der Empfängers / der Emfänger-Gruppen|| |chatIds|Liste mit Chat-Ids der Empfängers / der Emfänger-Gruppen||
|message_fms|Format der Nachricht für FMS|`{FMS}`|
|message_pocsag|Format der Nachricht für Pocsag|`{RIC}({SRIC})\n{MSG}`|
|message_zvei|Format der Nachricht für ZVEI|`{TONE}`|
|message_msg|Format der Nachricht für MSG||
|queue|Aktivieren/Deaktivieren der MessageQueue|true|
**Beispiel:** **Beispiel:**
```yaml ```yaml
@ -25,7 +34,7 @@ Außerdem werden Locations versendet, wenn die Felder `lat` und `lon` im Paket d
name: Telegram Plugin name: Telegram Plugin
res: telegram res: telegram
config: config:
message: "{RIC}({SRIC})\n{MSG}" message_pocsag: "{RIC}({SRIC})\n{MSG}"
botToken: "BOT_TOKEN" botToken: "BOT_TOKEN"
chatIds: chatIds:
- "CHAT_ID" - "CHAT_ID"
@ -33,7 +42,7 @@ Außerdem werden Locations versendet, wenn die Felder `lat` und `lon` im Paket d
--- ---
## Modul Abhängigkeiten ## Modul Abhängigkeiten
Aus dem Modul [Geocoding](../modul/geocoding.md) (optional): Aus dem Modul [Geocoding](../modul/geocoding.md) (optional/nur POCSAG):
- `lat` - `lat`
- `lon` - `lon`

View file

@ -22,6 +22,7 @@ nav:
- Geocoding: modul/geocoding.md - Geocoding: modul/geocoding.md
- Mode Filter: modul/mode_filter.md - Mode Filter: modul/mode_filter.md
- Regex Filter: modul/regex_filter.md - Regex Filter: modul/regex_filter.md
- Double Filter: modul/double_filter.md
- Plugins: - Plugins:
- Http: plugin/http.md - Http: plugin/http.md
- Telegram: plugin/telegram.md - Telegram: plugin/telegram.md

View file

@ -10,33 +10,45 @@
by Bastian Schroll by Bastian Schroll
@file: doubleFilter.py @file: doubleFilter.py
@date: 15.01.2018 @date: 09.07.2020
@author: Bastian Schroll @author: Bastian Schroll, b-watch
@description: Class to implement a filter for double alarms @description: Filter module for double packages
@todo test, refactor and document / check_msg is not implemented yet
""" """
import logging import logging
from module.moduleBase import ModuleBase
# ###################### #
# Custom plugin includes #
import time import time
# ######################
logging.debug("- %s loaded", __name__) logging.debug("- %s loaded", __name__)
class DoubleFilter: class BoswatchModule(ModuleBase):
"""!Double Filter Class""" """!Description of the Module"""
def __init__(self, config): def __init__(self, config):
"""!init""" """!Do not change anything here!"""
self._config = config super().__init__(__name__, config) # you can access the config class on 'self.config'
self._filterLists = {} self._filterLists = {}
logging.debug("Configured ignoreTime: %d", self.config.get("ignoreTime", default=10))
logging.debug("Configured maxEntry: %d", self.config.get("maxEntry", default=10))
def filter(self, bwPacket): def onLoad(self):
"""!Called by import of the plugin
Remove if not implemented"""
pass
def doWork(self, bwPacket):
"""!start an run of the module.
@param bwPacket: A BOSWatch packet instance"""
if bwPacket.get("mode") == "fms": if bwPacket.get("mode") == "fms":
scanWord = "fms" filterFields = ["fms"]
elif bwPacket.get("mode") == "pocsag": elif bwPacket.get("mode") == "pocsag":
scanWord = "ric" filterFields = self.config.get("pocsagFields", default=["ric", "subric"])
elif bwPacket.get("mode") == "zvei": elif bwPacket.get("mode") == "zvei":
scanWord = "zvei" filterFields = ["tone"]
else: else:
logging.error("No Filter for '%s'", bwPacket) logging.error("No Filter for '%s'", bwPacket)
return False return False
@ -45,31 +57,36 @@ class DoubleFilter:
logging.debug("create new doubleFilter list for '%s'", bwPacket.get("mode")) logging.debug("create new doubleFilter list for '%s'", bwPacket.get("mode"))
self._filterLists[bwPacket.get("mode")] = [] self._filterLists[bwPacket.get("mode")] = []
logging.debug("scanWord for '%s' is '%s'", bwPacket.get("mode"), scanWord) logging.debug("filterFields for '%s' is '%s'", bwPacket.get("mode"), ", ".join(filterFields))
return self._check(bwPacket, scanWord) return self._check(bwPacket, filterFields)
def _check(self, bwPacket, scanWord): def onUnload(self):
"""!Called by destruction of the plugin
Remove if not implemented"""
pass
def _check(self, bwPacket, filterFields):
self._filterLists[bwPacket.get("mode")].insert(0, bwPacket) self._filterLists[bwPacket.get("mode")].insert(0, bwPacket)
# delete entries that are to old # delete entries that are to old
counter = 0 counter = 0
for listPacket in self._filterLists[bwPacket.get("mode")][1:]: # [1:] skip first entry, thats the new one for listPacket in self._filterLists[bwPacket.get("mode")][1:]: # [1:] skip first entry, thats the new one
if listPacket.get("timestamp") < (time.time() - self._config["ignoreTime"]): if float(listPacket.get("timestamp")) < (time.time() - self.config.get("ignoreTime", default=10)):
self._filterLists[bwPacket.get("mode")].remove(listPacket) self._filterLists[bwPacket.get("mode")].remove(listPacket)
counter += 1 counter += 1
if counter: if counter:
logging.debug("%d old entry(s) removed", counter) logging.debug("%d old entry(s) removed", counter)
# delete last entry if list is to big # delete last entry if list is to big
if len(self._filterLists[bwPacket.get("mode")]) > self._config["maxEntry"]: if len(self._filterLists[bwPacket.get("mode")]) > self.config.get("maxEntry", default=20):
logging.debug("MaxEntry reached - delete oldest") logging.debug("MaxEntry reached - delete oldest")
self._filterLists[bwPacket.get("mode")].pop() self._filterLists[bwPacket.get("mode")].pop()
for listPacket in self._filterLists[bwPacket.get("mode")][1:]: # [1:] skip first entry, thats the new one for listPacket in self._filterLists[bwPacket.get("mode")][1:]: # [1:] skip first entry, thats the new one
if listPacket.get(scanWord) is bwPacket.get(scanWord): if all(listPacket.get(x) == bwPacket.get(x) for x in filterFields):
logging.debug("found duplicate: %s", bwPacket.get(scanWord)) logging.debug("found duplicate: %s", bwPacket.get("mode"))
return False return False
logging.debug("doubleFilter ok") logging.debug("doubleFilter ok")
return True return None

View file

@ -25,7 +25,7 @@ from module.moduleBase import ModuleBase
logging.debug("- %s loaded", __name__) logging.debug("- %s loaded", __name__)
class BoswatchModul(ModuleBase): class BoswatchModule(ModuleBase):
"""!Description of the Module""" """!Description of the Module"""
def __init__(self, config): def __init__(self, config):
"""!Do not change anything here!""" """!Do not change anything here!"""

View file

@ -20,12 +20,36 @@ from plugin.pluginBase import PluginBase
# ###################### # # ###################### #
# Custom plugin includes # # Custom plugin includes #
from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, NetworkError) from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, NetworkError)
import telegram from telegram.ext import messagequeue as mq
from telegram.utils.request import Request
import telegram.bot
# ###################### # # ###################### #
logging.debug("- %s loaded", __name__) logging.debug("- %s loaded", __name__)
class MQBot(telegram.bot.Bot):
'''A subclass of Bot which delegates send method handling to MQ'''
def __init__(self, *args, is_queued_def=True, mqueue=None, **kwargs):
super(MQBot, self).__init__(*args, **kwargs)
# below 2 attributes should be provided for decorator usage
self._is_messages_queued_default = is_queued_def
self._msg_queue = mqueue or mq.MessageQueue()
def __del__(self):
try:
self._msg_queue.stop()
except:
pass
@mq.queuedmessage
def send_message(self, *args, **kwargs):
'''Wrapped method would accept new `queued` and `isgroup`
OPTIONAL arguments'''
return super(MQBot, self).send_message(*args, **kwargs)
class BoswatchPlugin(PluginBase): class BoswatchPlugin(PluginBase):
"""!Description of the Plugin""" """!Description of the Plugin"""
@ -35,27 +59,72 @@ class BoswatchPlugin(PluginBase):
def onLoad(self): def onLoad(self):
"""!Called by import of the plugin""" """!Called by import of the plugin"""
self.bot = telegram.Bot(token=self.config.get("botToken", default="")) if self.config.get("queue", default=True):
q = mq.MessageQueue()
request = Request(con_pool_size=8)
self.bot = MQBot(token=self.config.get("botToken", default=""), request=request, mqueue=q)
print('queue')
else:
self.bot = telegram.Bot(token=self.config.get("botToken"))
print('normal')
def fms(self, bwPacket):
"""!Called on FMS alarm
@param bwPacket: bwPacket instance"""
msg = self.parseWildcards(self.config.get("message_fms", default="{FMS}"))
self._sendMessage(msg)
def pocsag(self, bwPacket): def pocsag(self, bwPacket):
"""!Called on POCSAG alarm """!Called on POCSAG alarm
@param bwPacket: bwPacket instance""" @param bwPacket: bwPacket instance"""
msg = self.parseWildcards(self.config.get("message")) msg = self.parseWildcards(self.config.get("message_pocsag", default="{RIC}({SRIC})\n{MSG}"))
self._sendMessage(msg)
if bwPacket.get("lat") is not None and bwPacket.get("lon") is not None: if bwPacket.get("lat") is not None and bwPacket.get("lon") is not None:
logging.debug("Found coordinates in packet") logging.debug("Found coordinates in packet")
(lat, lon) = (bwPacket.get("lat"), bwPacket.get("lon")) (lat, lon) = (bwPacket.get("lat"), bwPacket.get("lon"))
self._sendMessage(lat, lon)
def zvei(self, bwPacket):
"""!Called on ZVEI alarm
@param bwPacket: bwPacket instance"""
msg = self.parseWildcards(self.config.get("message_zvei", default="{TONE}"))
self._sendMessage(msg)
def msg(self, bwPacket):
"""!Called on MSG packet
@param bwPacket: bwPacket instance"""
msg = self.parseWildcards(self.config.get("message_msg"))
self._sendMessage(msg)
def _sendMessage(self, message):
for chatId in self.config.get("chatIds", default=[]): for chatId in self.config.get("chatIds", default=[]):
try: try:
# Send Message via Telegram # Send Message via Telegram
logging.info("Sending message to " + chatId) logging.info("Sending message to " + chatId)
self.bot.send_message(chat_id=chatId, text=msg) self.bot.send_message(chat_id=chatId, text=message)
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))
def _sendLocation(self, lat, lon):
for chatId in self.config.get("chatIds", default=[]):
try:
# Send Location via Telegram
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)
# 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: except Unauthorized:
logging.exception("Error while sending Telegram Message, please Check your api-key") logging.exception("Error while sending Telegram Message, please Check your api-key")
except (TimedOut, NetworkError): except (TimedOut, NetworkError):