From 7b091fabe4ecfa0c99a37440a9e81a34c022603f Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Tue, 18 Feb 2020 22:12:53 +0100 Subject: [PATCH 01/11] Add Telegram Plugin and Documentation --- docu/docs/plugin/telegram.md | 66 +++++++++++++++++++++ docu/mkdocs.yml | 3 +- plugin/telegram.py | 112 +++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 docu/docs/plugin/telegram.md create mode 100644 plugin/telegram.py diff --git a/docu/docs/plugin/telegram.md b/docu/docs/plugin/telegram.md new file mode 100644 index 0000000..1f1b3d4 --- /dev/null +++ b/docu/docs/plugin/telegram.md @@ -0,0 +1,66 @@ +#
Telegram
+--- + +## Beschreibung +Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. +Außerdem unterstützt das Plugin das Versenden von Location über folgende geocoding-Api's: + +- Mapbox +- Google Maps + +## Resource +`telegram` + +## Konfiguration + +|Feld|Beschreibung|Default| +|----|------------|-------| +|name|Beliebiger Name des Plugins|| + +#### `config:` + +|Feld|Beschreibung|Default| +|----|------------|-------| +|botToken|Der Api-Key des Telegram-Bots|| +|chatId|Die Chat-Id des Empfängers / der Emfänger-Gruppe|| +|geocoding|Aktivieren des Geocodings|false| +|geoRegex|Regex Capture-Group zum Herausfiltern der Adresse|| +|geoApiProvider|Der Provider für das Geocoding|| +|geoApiToken|Der Api-Token fuer die Geocoding-Api|| + +#### Verfügbare Geocoding Provider + +|Name|Einstellungswert| +|----|------------| +|Mapbox|mapbox| +|Google Maps|google| + +**Beispiel:** +```yaml + - type: plugin + name: Telegram Plugin + res: telegram + config: + botToken: {{ Telegram Bot Token }} + chatId: {{ Telegram Chat Id }} + geocoding: true + geoRegex: ((?:[^ ]*,)*?) + geoApiProvider: mapbox + geoApiToken: {{ Mapbox Api Key }} +``` + +--- +## Abhängigkeiten + +- python-telegram-bot +- geocoder + +--- +## Paket Modifikationen + +- keine + +--- +## Zusätzliche Wildcards + +- keine diff --git a/docu/mkdocs.yml b/docu/mkdocs.yml index 0948dd6..846363e 100644 --- a/docu/mkdocs.yml +++ b/docu/mkdocs.yml @@ -21,7 +21,8 @@ nav: - Mode Filter: modul/mode_filter.md - Regex Filter: modul/regex_filter.md - Descriptor: modul/descriptor.md - - Plugins: tbd.md + - Plugins: + - Telegram: plugin/telegram.md - Entwickler: - Eigenes Modul/Plugin schreiben: develop/ModulPlugin.md - BOSWatch Alarmpaket Format: develop/packet.md diff --git a/plugin/telegram.py b/plugin/telegram.py new file mode 100644 index 0000000..6250ce4 --- /dev/null +++ b/plugin/telegram.py @@ -0,0 +1,112 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: template_module.py +@date: 14.01.2018 +@author: Bastian Schroll +@description: Template Plugin File +""" +import logging + +from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, ChatMigrated, NetworkError) +from plugin.pluginBase import PluginBase +import telegram +import re +import geocoder + +# ###################### # +# Custom plugin includes # + +# ###################### # + +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""" + pass + + def setup(self): + """!Called before alarm""" + self.bot = telegram.Bot(token=self.config.get("botToken", default="")) + pass + + def fms(self, bwPacket): + """!Called on FMS alarm + + @param bwPacket: bwPacket instance""" + logging.warning('Telegram Plugin does not work for FMS') + pass + + def pocsag(self, bwPacket): + """!Called on POCSAG alarm + + @param bwPacket: bwPacket instance""" + + try: + # Send Message via Telegram + msg = bwPacket.get("ric") + " (" + bwPacket.get("subric") + ")\n" + bwPacket.get("message") + self.bot.send_message(chat_id=self.config.get("chatId", default=""), text=msg) + + # Send Location via Telegram if Geocoding is enabled and Provider and Key are set + if self.config.get("geocoding", default=False): + try: + address = re.search(self.config.get("geoRegex"), bwPacket.get("message"))[1] + provider = self.config.get("geoApiProvider") + + if "mapbox" == provider: + g = geocoder.mapbox(address, key=self.config.get("geoApiToken")) + elif "google" == provider: + g = geocoder.google(address, key=self.config.get("geoApiToken")) + else: + return + + (lat, lng) = g.latlng + self.bot.sendLocation(chat_id=self.config.get("chatId", default=""), latitude=lat, longitude=lng) + except Exception: + logging.error('Error while sending location, please Check your geocoding provider and api-key') + except Unauthorized: + logging.error('Error while Telegram Message, please Check your api-key') + except TimedOut or NetworkError: + logging.error('Error while Telegram Message, please Check your connectivity') + except BadRequest or TelegramError: + logging.error('Error while Telegram Message') + + pass + + def zvei(self, bwPacket): + """!Called on ZVEI alarm + + @param bwPacket: bwPacket instance""" + logging.warning('Telegram Plugin does not work for ZVEI') + pass + + def msg(self, bwPacket): + """!Called on MSG packet + + @param bwPacket: bwPacket instance""" + logging.warning('Telegram Plugin does not work for MSG') + pass + + def teardown(self): + """!Called after alarm""" + pass + + def onUnload(self): + """!Called by destruction of the plugin""" + pass From 4e79feb92b25c131d2b15509d8542178de36aa24 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Tue, 18 Feb 2020 23:06:14 +0100 Subject: [PATCH 02/11] coding-styles --- plugin/telegram.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugin/telegram.py b/plugin/telegram.py index 6250ce4..ebaf1cf 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -50,7 +50,7 @@ class BoswatchPlugin(PluginBase): """!Called on FMS alarm @param bwPacket: bwPacket instance""" - logging.warning('Telegram Plugin does not work for FMS') + logging.warning("Telegram Plugin does not work for FMS") pass def pocsag(self, bwPacket): @@ -78,14 +78,16 @@ class BoswatchPlugin(PluginBase): (lat, lng) = g.latlng self.bot.sendLocation(chat_id=self.config.get("chatId", default=""), latitude=lat, longitude=lng) + except IndexError: + logging.warning("Address was not found in current Message, skipping Location") except Exception: - logging.error('Error while sending location, please Check your geocoding provider and api-key') + logging.error("Error while sending location, please Check your geocoding provider and api-key") except Unauthorized: - logging.error('Error while Telegram Message, please Check your api-key') + logging.error("Error while Telegram Message, please Check your api-key") except TimedOut or NetworkError: - logging.error('Error while Telegram Message, please Check your connectivity') + logging.error("Error while Telegram Message, please Check your connectivity") except BadRequest or TelegramError: - logging.error('Error while Telegram Message') + logging.error("Error while Telegram Message") pass @@ -93,14 +95,14 @@ class BoswatchPlugin(PluginBase): """!Called on ZVEI alarm @param bwPacket: bwPacket instance""" - logging.warning('Telegram Plugin does not work for ZVEI') + logging.warning("Telegram Plugin does not work for ZVEI") pass def msg(self, bwPacket): """!Called on MSG packet @param bwPacket: bwPacket instance""" - logging.warning('Telegram Plugin does not work for MSG') + logging.warning("Telegram Plugin does not work for MSG") pass def teardown(self): From 4a2f2992b2f1b541142d1f5d6c659b086db070e5 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Tue, 18 Feb 2020 23:26:13 +0100 Subject: [PATCH 03/11] better error handling --- plugin/telegram.py | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/plugin/telegram.py b/plugin/telegram.py index ebaf1cf..e97c5bc 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -65,29 +65,28 @@ class BoswatchPlugin(PluginBase): # Send Location via Telegram if Geocoding is enabled and Provider and Key are set if self.config.get("geocoding", default=False): - try: - address = re.search(self.config.get("geoRegex"), bwPacket.get("message"))[1] - provider = self.config.get("geoApiProvider") + address = re.search(self.config.get("geoRegex"), bwPacket.get("message"))[1] + provider = self.config.get("geoApiProvider") - if "mapbox" == provider: - g = geocoder.mapbox(address, key=self.config.get("geoApiToken")) - elif "google" == provider: - g = geocoder.google(address, key=self.config.get("geoApiToken")) - else: - return + if "mapbox" == provider: + g = geocoder.mapbox(address, key=self.config.get("geoApiToken")) + elif "google" == provider: + g = geocoder.google(address, key=self.config.get("geoApiToken")) + else: + return - (lat, lng) = g.latlng - self.bot.sendLocation(chat_id=self.config.get("chatId", default=""), latitude=lat, longitude=lng) - except IndexError: - logging.warning("Address was not found in current Message, skipping Location") - except Exception: - logging.error("Error while sending location, please Check your geocoding provider and api-key") + (lat, lng) = g.latlng + self.bot.sendLocation(chat_id=self.config.get("chatId", default=""), latitude=lat, longitude=lng) + except (IndexError, TypeError, ValueError): + logging.warning("Address was not found in current Message, skipping Location") except Unauthorized: - logging.error("Error while Telegram Message, please Check your api-key") - except TimedOut or NetworkError: - logging.error("Error while Telegram Message, please Check your connectivity") - except BadRequest or TelegramError: - logging.error("Error while Telegram Message") + logging.error("Error while sending Telegram Message, please Check your api-key") + except (TimedOut, NetworkError): + logging.error("Error while sending Telegram Message, please Check your connectivity") + except (BadRequest, TelegramError): + logging.error("Error while sending Telegram Message") + except Exception as e: + logging.error("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e)) pass From 4aea7b5d78c2d8f2bb299804deb583b24c1411a4 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Sat, 22 Feb 2020 19:08:53 +0100 Subject: [PATCH 04/11] add geocoding module, resolve threads --- docu/docs/modul/geocoding.md | 53 ++++++++++++++ docu/docs/plugin/telegram.md | 36 ++-------- docu/mkdocs.yml | 1 + module/geocoding.py | 72 +++++++++++++++++++ plugin/telegram.py | 95 +++++++------------------ testPackage.py | 134 +++++++++++++++++++++++++++++++++++ 6 files changed, 291 insertions(+), 100 deletions(-) create mode 100644 docu/docs/modul/geocoding.md create mode 100644 module/geocoding.py create mode 100644 testPackage.py diff --git a/docu/docs/modul/geocoding.md b/docu/docs/modul/geocoding.md new file mode 100644 index 0000000..ca939ea --- /dev/null +++ b/docu/docs/modul/geocoding.md @@ -0,0 +1,53 @@ +#
Geocoding
+--- + +## Beschreibung +Mit diesem Modul können einem Paket die Koordinaten eines Ortes oder einer Adresse angefügt werden. + +## Unterstützte Alarmtypen + - Pocsag + +## Resource +`geocoding` + +## Konfiguration + +|Feld|Beschreibung|Default| +|----|------------|-------| +apiProvider|Der Provider für das Geocoding| +apiToken|Der Api-Token fuer die Geocoding-Api| +geoRegex|Regex Capture-Group zum Herausfiltern der Adresse| + +#### Verfügbare Geocoding Provider + +|Name|Einstellungswert| +|----|------------| +|Mapbox|mapbox| +|Google Maps|google| + +**Beispiel:** +```yaml + - type: module + name: Geocoding Module + res: geocoding + config: + apiProvider: "{{ Provider für Geocoding }}" + apiToken: "{{ API-Key für Provider }}" + regex: "((?:[^ ]*,)*?)" +``` + +--- +## Abhängigkeiten + +- geocoder +- re + +--- +## Paket Modifikationen + +- Im Paket werden die Felder `lat` und `lng` hinterlegt + +--- +## Zusätzliche Wildcards + +- keine \ No newline at end of file diff --git a/docu/docs/plugin/telegram.md b/docu/docs/plugin/telegram.md index 1f1b3d4..d6afdfb 100644 --- a/docu/docs/plugin/telegram.md +++ b/docu/docs/plugin/telegram.md @@ -2,38 +2,20 @@ --- ## Beschreibung -Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. -Außerdem unterstützt das Plugin das Versenden von Location über folgende geocoding-Api's: +Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. Außerdem werden Locations versenden, wenn die Felder `lat` und `lng` im Paket definiert sind. -- Mapbox -- Google Maps +## Unterstütze Alarmtypen +- Pocsag ## Resource `telegram` ## Konfiguration -|Feld|Beschreibung|Default| -|----|------------|-------| -|name|Beliebiger Name des Plugins|| - -#### `config:` - |Feld|Beschreibung|Default| |----|------------|-------| |botToken|Der Api-Key des Telegram-Bots|| -|chatId|Die Chat-Id des Empfängers / der Emfänger-Gruppe|| -|geocoding|Aktivieren des Geocodings|false| -|geoRegex|Regex Capture-Group zum Herausfiltern der Adresse|| -|geoApiProvider|Der Provider für das Geocoding|| -|geoApiToken|Der Api-Token fuer die Geocoding-Api|| - -#### Verfügbare Geocoding Provider - -|Name|Einstellungswert| -|----|------------| -|Mapbox|mapbox| -|Google Maps|google| +|chatIds|Liste mit Chat-Ids der Empfängers / der Emfänger-Gruppen|| **Beispiel:** ```yaml @@ -41,19 +23,15 @@ Außerdem unterstützt das Plugin das Versenden von Location über folgende geoc name: Telegram Plugin res: telegram config: - botToken: {{ Telegram Bot Token }} - chatId: {{ Telegram Chat Id }} - geocoding: true - geoRegex: ((?:[^ ]*,)*?) - geoApiProvider: mapbox - geoApiToken: {{ Mapbox Api Key }} + botToken: "{{ Telegram Bot Token }}" + chatIds: + - "{{ Telegram Chat Id }}" ``` --- ## Abhängigkeiten - python-telegram-bot -- geocoder --- ## Paket Modifikationen diff --git a/docu/mkdocs.yml b/docu/mkdocs.yml index 846363e..5ba0bc9 100644 --- a/docu/mkdocs.yml +++ b/docu/mkdocs.yml @@ -21,6 +21,7 @@ nav: - Mode Filter: modul/mode_filter.md - Regex Filter: modul/regex_filter.md - Descriptor: modul/descriptor.md + - Geocoding: modul/geocoding.md - Plugins: - Telegram: plugin/telegram.md - Entwickler: diff --git a/module/geocoding.py b/module/geocoding.py new file mode 100644 index 0000000..b2bbb5c --- /dev/null +++ b/module/geocoding.py @@ -0,0 +1,72 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: geocoding.py +@date: 01.03.2019 +@author: Jan Speller +@description: Geocoding Module +""" +import logging +from module.moduleBase import ModuleBase + +# ###################### # +# Custom plugin includes # +import geocoder +import re +# ###################### # + +logging.debug("- %s loaded", __name__) + + +class BoswatchModule(ModuleBase): + """!Description of the Module""" + def __init__(self, config): + """!Do not change anything here!""" + super().__init__(__name__, config) # you can access the config class on 'self.config' + + def doWork(self, bwPacket): + """!start an run of the module. + + @param bwPacket: A BOSWatch packet instance""" + if bwPacket.get("mode") == "pocsag": + self.geocode(bwPacket) + pass + + return bwPacket + + def geocode(self, bwPacket): + """!find address in message and get latitude and longitude + + @param bwPacket: A BOSWatch packet instance""" + try: + address = re.search(self.config.get("regex"), bwPacket.get("message"))[1] + provider = self.config.get("apiProvider") + if "mapbox" == provider: + g = geocoder.mapbox(address, key=self.config.get("apiToken")) + print(address) + elif "google" == provider: + g = geocoder.google(address, key=self.config.get("apiToken")) + else: + return bwPacket + + (lat, lng) = g.latlng + bwPacket.set("lat", lat) + bwPacket.set("lng", lng) + return bwPacket + except (IndexError, TypeError, ValueError): + logging.warning("Address was not found in current Message, skipping geocoding") + except Exception as e: + logging.error("Unknown Error while executing geocoding module: " + str(type(e).__name__) + ": " + str(e)) + return bwPacket + + def onUnload(self): + """!Called by destruction of the plugin""" + pass diff --git a/plugin/telegram.py b/plugin/telegram.py index e97c5bc..f32a0cf 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -9,22 +9,19 @@ German BOS Information Script by Bastian Schroll -@file: template_module.py -@date: 14.01.2018 -@author: Bastian Schroll -@description: Template Plugin File +@file: telegram.py +@date: 20.02.2020 +@author: Jan Speller +@description: Telegram Plugin """ import logging -from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, ChatMigrated, NetworkError) from plugin.pluginBase import PluginBase -import telegram -import re -import geocoder # ###################### # # Custom plugin includes # - +from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, ChatMigrated, NetworkError) +import telegram # ###################### # logging.debug("- %s loaded", __name__) @@ -39,75 +36,31 @@ class BoswatchPlugin(PluginBase): def onLoad(self): """!Called by import of the plugin""" - pass - - def setup(self): - """!Called before alarm""" self.bot = telegram.Bot(token=self.config.get("botToken", default="")) pass - def fms(self, bwPacket): - """!Called on FMS alarm - - @param bwPacket: bwPacket instance""" - logging.warning("Telegram Plugin does not work for FMS") - pass - def pocsag(self, bwPacket): """!Called on POCSAG alarm @param bwPacket: bwPacket instance""" + msg = bwPacket.get("ric") + " (" + bwPacket.get("subric") + ")\n" + bwPacket.get("message") - try: - # Send Message via Telegram - msg = bwPacket.get("ric") + " (" + bwPacket.get("subric") + ")\n" + bwPacket.get("message") - self.bot.send_message(chat_id=self.config.get("chatId", default=""), text=msg) - - # Send Location via Telegram if Geocoding is enabled and Provider and Key are set - if self.config.get("geocoding", default=False): - address = re.search(self.config.get("geoRegex"), bwPacket.get("message"))[1] - provider = self.config.get("geoApiProvider") - - if "mapbox" == provider: - g = geocoder.mapbox(address, key=self.config.get("geoApiToken")) - elif "google" == provider: - g = geocoder.google(address, key=self.config.get("geoApiToken")) - else: - return - - (lat, lng) = g.latlng - self.bot.sendLocation(chat_id=self.config.get("chatId", default=""), latitude=lat, longitude=lng) - except (IndexError, TypeError, ValueError): - logging.warning("Address was not found in current Message, skipping Location") - except Unauthorized: - logging.error("Error while sending Telegram Message, please Check your api-key") - except (TimedOut, NetworkError): - logging.error("Error while sending Telegram Message, please Check your connectivity") - except (BadRequest, TelegramError): - logging.error("Error while sending Telegram Message") - except Exception as e: - logging.error("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e)) + if bwPacket.get("lat") is not None and bwPacket.get("lng") is not None: + (lat, lng) = (bwPacket.get("lat"), bwPacket.get("lng")) + for chatId in self.config.get("chatIds", default=[]): + try: + # Send Message via Telegram + self.bot.send_message(chat_id=chatId, default=""), text=msg) - pass - - def zvei(self, bwPacket): - """!Called on ZVEI alarm - - @param bwPacket: bwPacket instance""" - logging.warning("Telegram Plugin does not work for ZVEI") - pass - - def msg(self, bwPacket): - """!Called on MSG packet - - @param bwPacket: bwPacket instance""" - logging.warning("Telegram Plugin does not work for MSG") - pass - - def teardown(self): - """!Called after alarm""" - pass - - def onUnload(self): - """!Called by destruction of the plugin""" + # Send Location via Telegram if lat and lng exist in Package + if lat is not None and lng is not None: + self.bot.sendLocation(chat_id=chatId, latitude=lat, longitude=lng) + except Unauthorized: + logging.error("Error while sending Telegram Message, please Check your api-key") + except (TimedOut, NetworkError): + logging.error("Error while sending Telegram Message, please Check your connectivity") + except (BadRequest, TelegramError): + logging.error("Error while sending Telegram Message") + except Exception as e: + logging.error("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e)) pass diff --git a/testPackage.py b/testPackage.py new file mode 100644 index 0000000..a9bfeb7 --- /dev/null +++ b/testPackage.py @@ -0,0 +1,134 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import logging +import socket +import select + +logging.debug("- %s loaded", __name__) + +HEADERSIZE = 10 +class TCPClient: + """!TCP client class""" + + def __init__(self, timeout=3): + """!Create a new instance + + @param timeout: timeout for the client in sec. (3)""" + socket.setdefaulttimeout(timeout) + self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + def connect(self, host="localhost", port=8080): + """!Connect to the server + + @param host: Server IP address ("localhost") + @param port: Server Port (8080) + @return True or False""" + try: + if not self.isConnected: + self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._sock.connect((host, port)) + logging.debug("connected to %s:%s", host, port) + return True + logging.warning("client always connected") + return True + except socket.error as e: + logging.error(e) + return False + + def disconnect(self): + """!Disconnect from the server + + @return True or False""" + try: + if self.isConnected: + self._sock.shutdown(socket.SHUT_RDWR) + self._sock.close() + logging.debug("disconnected") + return True + logging.warning("client always disconnected") + return True + except socket.error as e: + logging.error(e) + return False + + def transmit(self, data): + """!Send a data packet to the server + + @param data: data to send to the server + @return True or False""" + try: + logging.debug("transmitting:\n%s", data) + data = data.encode("utf-8") + header = str(len(data)).ljust(HEADERSIZE).encode("utf-8") + self._sock.sendall(header + data) + logging.debug("transmitted...") + return True + except socket.error as e: + logging.error(e) + return False + + def receive(self, timeout=1): + """!Receive data from the server + + @param timeout: to wait for incoming data in seconds + @return received data""" + try: + read, _, _ = select.select([self._sock], [], [], timeout) + if not read: # check if there is something to read + return False + + header = self._sock.recv(HEADERSIZE).decode("utf-8") + if not len(header): # check if there data + return False + + length = int(header.strip()) + received = self._sock.recv(length).decode("utf-8") + + logging.debug("recv header: '%s'", header) + logging.debug("received %d bytes: %s", len(received), received) + return received + except socket.error as e: + logging.error(e) + return False + + @property + def isConnected(self): + """!Property of client connected state""" + try: + if self._sock: + _, write, _ = select.select([], [self._sock], [], 0.1) + if write: + data = "".encode("utf-8") + header = str(len(data)).ljust(HEADERSIZE).encode("utf-8") + self._sock.sendall(header + data) + return True + return False + except socket.error as e: + if e.errno != 32: + logging.exception(e) + return False + except ValueError: + return False + +client = TCPClient() +client.connect() +client.transmit(str({ + 'serverName': 'TestServer', + 'serverVersion': '3.0', + 'serverBuildDate': '01.01.2020', + 'serverBranch': 'develop', + 'clientName': 'TestClient', + 'clientIP': '127.0.0.1', + 'clientVersion': '3.0', + 'clientBuildDate': '01.01.2020', + 'clientBranch': 'develop', + 'inputSource': 'sdr', + 'timestamp': '15:30', + 'frequency': '173.240', + 'mode': 'pocsag', + 'bitrate': '512', + 'ric': '1326089', + 'subric': '1', + 'subricText': 'a', + 'message': '17:22 FW 18865 Gebäudebrand_kle Sandkampstr.,15,-,Hopsten,NRW rauchentwicklung' +})) \ No newline at end of file From c7f99bcfcbe96d6cdc69eda3b72db6c8f8ec232e Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Sat, 22 Feb 2020 19:11:21 +0100 Subject: [PATCH 05/11] changes to telegram --- plugin/telegram.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/plugin/telegram.py b/plugin/telegram.py index f32a0cf..3050afc 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -15,12 +15,11 @@ @description: Telegram Plugin """ import logging - from plugin.pluginBase import PluginBase # ###################### # # Custom plugin includes # -from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, ChatMigrated, NetworkError) +from telegram.error import (TelegramError, Unauthorized, BadRequest, TimedOut, NetworkError) import telegram # ###################### # @@ -44,15 +43,15 @@ class BoswatchPlugin(PluginBase): @param bwPacket: bwPacket instance""" msg = bwPacket.get("ric") + " (" + bwPacket.get("subric") + ")\n" + bwPacket.get("message") - if bwPacket.get("lat") is not None and bwPacket.get("lng") is not None: (lat, lng) = (bwPacket.get("lat"), bwPacket.get("lng")) + for chatId in self.config.get("chatIds", default=[]): try: # Send Message via Telegram - self.bot.send_message(chat_id=chatId, default=""), text=msg) - - # Send Location via Telegram if lat and lng exist in Package + self.bot.send_message(chat_id=chatId, text=msg) + + # Send Location via Telegram if lat and lng are defined if lat is not None and lng is not None: self.bot.sendLocation(chat_id=chatId, latitude=lat, longitude=lng) except Unauthorized: From 716d7a18c0477e00b624dd78aa3211e1fc5385a9 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Sat, 22 Feb 2020 19:14:45 +0100 Subject: [PATCH 06/11] Delete test env --- testPackage.py | 134 ------------------------------------------------- 1 file changed, 134 deletions(-) delete mode 100644 testPackage.py diff --git a/testPackage.py b/testPackage.py deleted file mode 100644 index a9bfeb7..0000000 --- a/testPackage.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -import logging -import socket -import select - -logging.debug("- %s loaded", __name__) - -HEADERSIZE = 10 -class TCPClient: - """!TCP client class""" - - def __init__(self, timeout=3): - """!Create a new instance - - @param timeout: timeout for the client in sec. (3)""" - socket.setdefaulttimeout(timeout) - self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - def connect(self, host="localhost", port=8080): - """!Connect to the server - - @param host: Server IP address ("localhost") - @param port: Server Port (8080) - @return True or False""" - try: - if not self.isConnected: - self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._sock.connect((host, port)) - logging.debug("connected to %s:%s", host, port) - return True - logging.warning("client always connected") - return True - except socket.error as e: - logging.error(e) - return False - - def disconnect(self): - """!Disconnect from the server - - @return True or False""" - try: - if self.isConnected: - self._sock.shutdown(socket.SHUT_RDWR) - self._sock.close() - logging.debug("disconnected") - return True - logging.warning("client always disconnected") - return True - except socket.error as e: - logging.error(e) - return False - - def transmit(self, data): - """!Send a data packet to the server - - @param data: data to send to the server - @return True or False""" - try: - logging.debug("transmitting:\n%s", data) - data = data.encode("utf-8") - header = str(len(data)).ljust(HEADERSIZE).encode("utf-8") - self._sock.sendall(header + data) - logging.debug("transmitted...") - return True - except socket.error as e: - logging.error(e) - return False - - def receive(self, timeout=1): - """!Receive data from the server - - @param timeout: to wait for incoming data in seconds - @return received data""" - try: - read, _, _ = select.select([self._sock], [], [], timeout) - if not read: # check if there is something to read - return False - - header = self._sock.recv(HEADERSIZE).decode("utf-8") - if not len(header): # check if there data - return False - - length = int(header.strip()) - received = self._sock.recv(length).decode("utf-8") - - logging.debug("recv header: '%s'", header) - logging.debug("received %d bytes: %s", len(received), received) - return received - except socket.error as e: - logging.error(e) - return False - - @property - def isConnected(self): - """!Property of client connected state""" - try: - if self._sock: - _, write, _ = select.select([], [self._sock], [], 0.1) - if write: - data = "".encode("utf-8") - header = str(len(data)).ljust(HEADERSIZE).encode("utf-8") - self._sock.sendall(header + data) - return True - return False - except socket.error as e: - if e.errno != 32: - logging.exception(e) - return False - except ValueError: - return False - -client = TCPClient() -client.connect() -client.transmit(str({ - 'serverName': 'TestServer', - 'serverVersion': '3.0', - 'serverBuildDate': '01.01.2020', - 'serverBranch': 'develop', - 'clientName': 'TestClient', - 'clientIP': '127.0.0.1', - 'clientVersion': '3.0', - 'clientBuildDate': '01.01.2020', - 'clientBranch': 'develop', - 'inputSource': 'sdr', - 'timestamp': '15:30', - 'frequency': '173.240', - 'mode': 'pocsag', - 'bitrate': '512', - 'ric': '1326089', - 'subric': '1', - 'subricText': 'a', - 'message': '17:22 FW 18865 Gebäudebrand_kle Sandkampstr.,15,-,Hopsten,NRW rauchentwicklung' -})) \ No newline at end of file From a12af18b544299236fcbb98e77c50f9a90d8f5df Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Sat, 22 Feb 2020 22:53:03 +0100 Subject: [PATCH 07/11] resolve threads (: --- docu/docs/modul/geocoding.md | 2 +- docu/docs/plugin/telegram.md | 4 +++- module/geocoding.py | 17 ++++++++--------- plugin/telegram.py | 15 ++++++++------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/docu/docs/modul/geocoding.md b/docu/docs/modul/geocoding.md index ca939ea..5876f08 100644 --- a/docu/docs/modul/geocoding.md +++ b/docu/docs/modul/geocoding.md @@ -45,7 +45,7 @@ geoRegex|Regex Capture-Group zum Herausfiltern der Adresse| --- ## Paket Modifikationen -- Im Paket werden die Felder `lat` und `lng` hinterlegt +- Im Paket werden die Felder `lat` und `lon` hinterlegt --- ## Zusätzliche Wildcards diff --git a/docu/docs/plugin/telegram.md b/docu/docs/plugin/telegram.md index d6afdfb..d72a84e 100644 --- a/docu/docs/plugin/telegram.md +++ b/docu/docs/plugin/telegram.md @@ -2,7 +2,9 @@ --- ## Beschreibung -Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. Außerdem werden Locations versenden, wenn die Felder `lat` und `lng` im Paket definiert sind. +Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. +Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket definiert sind. (beispielsweise durch das Geocoding-Modul) + ## Unterstütze Alarmtypen - Pocsag diff --git a/module/geocoding.py b/module/geocoding.py index b2bbb5c..765bafc 100644 --- a/module/geocoding.py +++ b/module/geocoding.py @@ -10,7 +10,7 @@ by Bastian Schroll @file: geocoding.py -@date: 01.03.2019 +@date: 22.02.2020 @author: Jan Speller @description: Geocoding Module """ @@ -38,7 +38,6 @@ class BoswatchModule(ModuleBase): @param bwPacket: A BOSWatch packet instance""" if bwPacket.get("mode") == "pocsag": self.geocode(bwPacket) - pass return bwPacket @@ -49,24 +48,24 @@ class BoswatchModule(ModuleBase): try: address = re.search(self.config.get("regex"), bwPacket.get("message"))[1] provider = self.config.get("apiProvider") + + logging.info("Found address: '" + address + "' in packet") if "mapbox" == provider: + logging.info("Using Mapbox as provider") g = geocoder.mapbox(address, key=self.config.get("apiToken")) - print(address) elif "google" == provider: + logging.info("Using Google as provider") g = geocoder.google(address, key=self.config.get("apiToken")) else: return bwPacket - (lat, lng) = g.latlng + (lat, lon) = g.latlng + logging.info("Found following coordinates for address: [lat=" + str(lat) + ", lon=" + str(lon) + "]") bwPacket.set("lat", lat) - bwPacket.set("lng", lng) + bwPacket.set("lon", lon) return bwPacket except (IndexError, TypeError, ValueError): logging.warning("Address was not found in current Message, skipping geocoding") except Exception as e: logging.error("Unknown Error while executing geocoding module: " + str(type(e).__name__) + ": " + str(e)) return bwPacket - - def onUnload(self): - """!Called by destruction of the plugin""" - pass diff --git a/plugin/telegram.py b/plugin/telegram.py index 3050afc..b27ce6d 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -36,24 +36,26 @@ class BoswatchPlugin(PluginBase): def onLoad(self): """!Called by import of the plugin""" self.bot = telegram.Bot(token=self.config.get("botToken", default="")) - pass def pocsag(self, bwPacket): """!Called on POCSAG alarm @param bwPacket: bwPacket instance""" msg = bwPacket.get("ric") + " (" + bwPacket.get("subric") + ")\n" + bwPacket.get("message") - if bwPacket.get("lat") is not None and bwPacket.get("lng") is not None: - (lat, lng) = (bwPacket.get("lat"), bwPacket.get("lng")) + if bwPacket.get("lat") is not None and bwPacket.get("lon") is not None: + logging.info("Found coordinates in packet") + (lat, lon) = (bwPacket.get("lat"), bwPacket.get("lon")) for chatId in self.config.get("chatIds", default=[]): try: # Send Message via Telegram + logging.info("Sending message to " + chatId) self.bot.send_message(chat_id=chatId, text=msg) - # Send Location via Telegram if lat and lng are defined - if lat is not None and lng is not None: - self.bot.sendLocation(chat_id=chatId, latitude=lat, longitude=lng) + # Send Location via Telegram if lat and lon are defined + if lat is not None and lon is not None: + logging.info("Sending location to " + chatId) + self.bot.sendLocation(chat_id=chatId, latitude=lat, longitude=lon) except Unauthorized: logging.error("Error while sending Telegram Message, please Check your api-key") except (TimedOut, NetworkError): @@ -62,4 +64,3 @@ class BoswatchPlugin(PluginBase): logging.error("Error while sending Telegram Message") except Exception as e: logging.error("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e)) - pass From 4b0614c7dacd7d8e8f0be1c4cb96cbae5ee12579 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Mon, 24 Feb 2020 21:51:19 +0100 Subject: [PATCH 08/11] threads and a few fixes to wildcards --- boswatch/wildcard.py | 8 ++++---- docu/docs/develop/packet.md | 2 +- docu/docs/modul/geocoding.md | 5 +++-- docu/docs/plugin/telegram.md | 12 ++---------- module/geocoding.py | 15 ++++++++++++--- plugin/telegram.py | 4 ++-- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/boswatch/wildcard.py b/boswatch/wildcard.py index 91f2fea..3519502 100644 --- a/boswatch/wildcard.py +++ b/boswatch/wildcard.py @@ -65,8 +65,8 @@ def replaceWildcards(message, bwPacket): "{CBRCH}": bwPacket.get("clientBranch"), # boswatch wildcards - "{INSRC}": bwPacket.get("mode"), - "{TIMES}": bwPacket.get("mode"), + "{INSRC}": bwPacket.get("inputSource"), + "{TIMES}": bwPacket.get("timestamp"), "{FREQ}": bwPacket.get("frequency"), "{MODE}": bwPacket.get("mode"), @@ -78,7 +78,7 @@ def replaceWildcards(message, bwPacket): "{VEHC}": bwPacket.get("vehicle"), "{STAT}": bwPacket.get("status"), "{DIR}": bwPacket.get("direction"), - "{DIRT}": bwPacket.get("dirextionText"), + "{DIRT}": bwPacket.get("directionText"), "{TACI}": bwPacket.get("tacticalInfo"), # pocsag wildcards @@ -99,6 +99,6 @@ def replaceWildcards(message, bwPacket): for wildcard, field in _additionalWildcards.items(): if field is not None: - message = message.replace(wildcard, bwPacket.getField(field)) + message = message.replace(wildcard, bwPacket.get(field)) return message diff --git a/docu/docs/develop/packet.md b/docu/docs/develop/packet.md index 14d2e88..e67de83 100644 --- a/docu/docs/develop/packet.md +++ b/docu/docs/develop/packet.md @@ -47,5 +47,5 @@ Ein BOSWatch Datenpaket wird in einem Python Dict abgebildet. In der nachfolgend |vehicle|X||||`{VEC}`|| |status|X||||`{STAT}`|| |direction|X||||`{DIR}`|| -|dirextionText|X||||`{DIRT}`|(Fhz->Lst, Lst->Fhz)| +|directionText|X||||`{DIRT}`|(Fhz->Lst, Lst->Fhz)| |tacticalInfo|X||||`{TACI}`|(I, II, III, IV)| diff --git a/docu/docs/modul/geocoding.md b/docu/docs/modul/geocoding.md index 5876f08..eb69eff 100644 --- a/docu/docs/modul/geocoding.md +++ b/docu/docs/modul/geocoding.md @@ -40,7 +40,6 @@ geoRegex|Regex Capture-Group zum Herausfiltern der Adresse| ## Abhängigkeiten - geocoder -- re --- ## Paket Modifikationen @@ -50,4 +49,6 @@ geoRegex|Regex Capture-Group zum Herausfiltern der Adresse| --- ## Zusätzliche Wildcards -- keine \ No newline at end of file +- `{ADDRESS}`: gefundene Adresse +- `{LAT}`: Latitude der Adresse +- `{LON}`: Longitude der Adresse \ No newline at end of file diff --git a/docu/docs/plugin/telegram.md b/docu/docs/plugin/telegram.md index d72a84e..2273cc5 100644 --- a/docu/docs/plugin/telegram.md +++ b/docu/docs/plugin/telegram.md @@ -16,6 +16,7 @@ Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket d |Feld|Beschreibung|Default| |----|------------|-------| +|message|Format der Nachricht|| |botToken|Der Api-Key des Telegram-Bots|| |chatIds|Liste mit Chat-Ids der Empfängers / der Emfänger-Gruppen|| @@ -25,6 +26,7 @@ Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket d name: Telegram Plugin res: telegram config: + message: "{RIC}({SRIC})\n{MSG}" botToken: "{{ Telegram Bot Token }}" chatIds: - "{{ Telegram Chat Id }}" @@ -34,13 +36,3 @@ Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket d ## Abhängigkeiten - python-telegram-bot - ---- -## Paket Modifikationen - -- keine - ---- -## Zusätzliche Wildcards - -- keine diff --git a/module/geocoding.py b/module/geocoding.py index 765bafc..c6cb8c5 100644 --- a/module/geocoding.py +++ b/module/geocoding.py @@ -46,10 +46,18 @@ class BoswatchModule(ModuleBase): @param bwPacket: A BOSWatch packet instance""" try: - address = re.search(self.config.get("regex"), bwPacket.get("message"))[1] + addressArray = re.search(self.config.get("regex"), bwPacket.get("message")) provider = self.config.get("apiProvider") + if addressArray[1] is None: + logging.warning("Address was not found in current Message, skipping geocoding") + return bwPacket + + address = addressArray[1] + bwPacket.set("address", address) + self.registerWildcard("{ADDRESS}", "address") logging.info("Found address: '" + address + "' in packet") + if "mapbox" == provider: logging.info("Using Mapbox as provider") g = geocoder.mapbox(address, key=self.config.get("apiToken")) @@ -63,9 +71,10 @@ class BoswatchModule(ModuleBase): logging.info("Found following coordinates for address: [lat=" + str(lat) + ", lon=" + str(lon) + "]") bwPacket.set("lat", lat) bwPacket.set("lon", lon) + self.registerWildcard("{LAT}", "lat") + self.registerWildcard("{LON}", "lon") + return bwPacket - except (IndexError, TypeError, ValueError): - logging.warning("Address was not found in current Message, skipping geocoding") except Exception as e: logging.error("Unknown Error while executing geocoding module: " + str(type(e).__name__) + ": " + str(e)) return bwPacket diff --git a/plugin/telegram.py b/plugin/telegram.py index b27ce6d..b37ebf5 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -41,9 +41,9 @@ class BoswatchPlugin(PluginBase): """!Called on POCSAG alarm @param bwPacket: bwPacket instance""" - msg = bwPacket.get("ric") + " (" + bwPacket.get("subric") + ")\n" + bwPacket.get("message") + msg = self.parseWildcards(self.config.get("message")) if bwPacket.get("lat") is not None and bwPacket.get("lon") is not None: - logging.info("Found coordinates in packet") + logging.debug("Found coordinates in packet") (lat, lon) = (bwPacket.get("lat"), bwPacket.get("lon")) for chatId in self.config.get("chatIds", default=[]): From e5d11b74afd2af3122589fc60fceb1c70a44c14d Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Mon, 24 Feb 2020 22:07:23 +0100 Subject: [PATCH 09/11] threads --- docu/docs/modul/geocoding.md | 4 +++- module/geocoding.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docu/docs/modul/geocoding.md b/docu/docs/modul/geocoding.md index eb69eff..8f7d1f5 100644 --- a/docu/docs/modul/geocoding.md +++ b/docu/docs/modul/geocoding.md @@ -44,7 +44,9 @@ geoRegex|Regex Capture-Group zum Herausfiltern der Adresse| --- ## Paket Modifikationen -- Im Paket werden die Felder `lat` und `lon` hinterlegt +- `address`: gefundene Adresse +- `lat`: Latitude der Adresse +- `lon`: Longitude der Adresse --- ## Zusätzliche Wildcards diff --git a/module/geocoding.py b/module/geocoding.py index c6cb8c5..c8e2f3c 100644 --- a/module/geocoding.py +++ b/module/geocoding.py @@ -50,7 +50,7 @@ class BoswatchModule(ModuleBase): provider = self.config.get("apiProvider") if addressArray[1] is None: - logging.warning("Address was not found in current Message, skipping geocoding") + logging.info("No address found, skipping geocoding") return bwPacket address = addressArray[1] From 9fb7fe9ea5dd436b1ae7f324319af23b8b8cb924 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Mon, 24 Feb 2020 22:15:28 +0100 Subject: [PATCH 10/11] threads --- docu/docs/modul/geocoding.md | 7 +++++-- docu/docs/plugin/telegram.md | 4 +++- module/geocoding.py | 2 +- plugin/telegram.py | 8 ++++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docu/docs/modul/geocoding.md b/docu/docs/modul/geocoding.md index 8f7d1f5..0acf43e 100644 --- a/docu/docs/modul/geocoding.md +++ b/docu/docs/modul/geocoding.md @@ -4,8 +4,11 @@ ## Beschreibung Mit diesem Modul können einem Paket die Koordinaten eines Ortes oder einer Adresse angefügt werden. +## Externe Abhängigkeiten +- geocoder + ## Unterstützte Alarmtypen - - Pocsag +- Pocsag ## Resource `geocoding` @@ -39,7 +42,7 @@ geoRegex|Regex Capture-Group zum Herausfiltern der Adresse| --- ## Abhängigkeiten -- geocoder +- keine --- ## Paket Modifikationen diff --git a/docu/docs/plugin/telegram.md b/docu/docs/plugin/telegram.md index 2273cc5..cad7821 100644 --- a/docu/docs/plugin/telegram.md +++ b/docu/docs/plugin/telegram.md @@ -5,6 +5,8 @@ Mit diesem Plugin ist es moeglich, Telegram-Nachrichten für POCSAG-Alarmierungen zu senden. Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket definiert sind. (beispielsweise durch das Geocoding-Modul) +## Externe Abhängigkeiten +- python-telegram-bot ## Unterstütze Alarmtypen - Pocsag @@ -35,4 +37,4 @@ Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket d --- ## Abhängigkeiten -- python-telegram-bot +- keine diff --git a/module/geocoding.py b/module/geocoding.py index c8e2f3c..572bc0d 100644 --- a/module/geocoding.py +++ b/module/geocoding.py @@ -76,5 +76,5 @@ class BoswatchModule(ModuleBase): return bwPacket except Exception as e: - logging.error("Unknown Error while executing geocoding module: " + str(type(e).__name__) + ": " + str(e)) + logging.exception("Unknown Error while executing geocoding module: " + str(type(e).__name__) + ": " + str(e)) return bwPacket diff --git a/plugin/telegram.py b/plugin/telegram.py index b37ebf5..80ff9e7 100644 --- a/plugin/telegram.py +++ b/plugin/telegram.py @@ -57,10 +57,10 @@ class BoswatchPlugin(PluginBase): logging.info("Sending location to " + chatId) self.bot.sendLocation(chat_id=chatId, latitude=lat, longitude=lon) except Unauthorized: - logging.error("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): - logging.error("Error while sending Telegram Message, please Check your connectivity") + logging.exception("Error while sending Telegram Message, please Check your connectivity") except (BadRequest, TelegramError): - logging.error("Error while sending Telegram Message") + logging.exception("Error while sending Telegram Message") except Exception as e: - logging.error("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e)) + logging.exception("Unknown Error while sending Telegram Message: " + str(type(e).__name__) + ": " + str(e)) From 4d9bf5b126bcb85d4d59a492727b1f3576d387bd Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Mon, 24 Feb 2020 22:35:30 +0100 Subject: [PATCH 11/11] threads --- docu/docs/plugin/telegram.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docu/docs/plugin/telegram.md b/docu/docs/plugin/telegram.md index cad7821..3003bbe 100644 --- a/docu/docs/plugin/telegram.md +++ b/docu/docs/plugin/telegram.md @@ -37,4 +37,6 @@ Außerdem werden Locations versenden, wenn die Felder `lat` und `lon` im Paket d --- ## Abhängigkeiten -- keine +- Modul geocoding (Falls in Paket vorhanden): + - `lat` + - `lon`