diff --git a/telegram/__init__.py b/telegram/__init__.py index f6df66617..cba8102da 100755 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -8,6 +8,8 @@ # # This file is part of SmartHomeNG. # +# Telegram Plugin for querying and updating items or sending messages via Telegram +# # SmartHomeNG is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -66,7 +68,7 @@ class Telegram(SmartPlugin): - PLUGIN_VERSION = "2.0.0" + PLUGIN_VERSION = "2.0.1" _items = [] # all items using attribute ``telegram_message`` _items_info = {} # dict used whith the info-command: key = attribute_value, val= item_list telegram_info @@ -83,12 +85,12 @@ def __init__(self, sh): """ self.logger.info('Init telegram plugin') - + # Call init code of parent class (SmartPlugin or MqttPlugin) super().__init__() if not self._init_complete: return - + if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug(f"init {__name__}") self._init_complete = False @@ -113,12 +115,12 @@ def __init__(self, sh): self._pretty_thread_names = self.get_parameter_value('pretty_thread_names') self._resend_delay = self.get_parameter_value('resend_delay') self._resend_attemps = self.get_parameter_value('resend_attemps') - + self._bot = None self._queue = Queue() - + self._application = Application.builder().token(self._token).build() - + if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug("adding command handlers to application") @@ -134,7 +136,7 @@ def __init__(self, sh): self._application.add_handler(CommandHandler('control', self.cHandler_control)) # Filters.text includes also commands, starting with ``/`` so it is needed to exclude them. self._application.add_handler(MessageHandler(filters.TEXT & (~filters.COMMAND), self.mHandler)) - + self.init_webinterface() if not self.init_webinterface(WebInterface): self.logger.error("Unable to start Webinterface") @@ -142,7 +144,7 @@ def __init__(self, sh): else: if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug("Init complete") - + self._init_complete = True def __call__(self, msg, chat_id=None): @@ -161,22 +163,22 @@ def run(self): """ if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug("Run method called") - + self.logics = Logics.get_instance() # Returns the instance of the Logics class, to be used to access the logics-api - + self.alive = True - + self._loop.run_until_complete(self.run_coros()) if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug(f"Run method ended") - + def stop(self): """ This is called when the plugins thread is about to stop """ if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug("stop telegram plugin") - + try: if self._bye_msg: cids = [key for key, value in self._chat_ids_item().items() if value == 1] @@ -185,7 +187,7 @@ def stop(self): self.logger.debug("sent bye message") except Exception as e: self.logger.error(f"could not send bye message [{e}]") - + time.sleep(1) self.alive = False # Clears the infiniti loop in sendQueue try: @@ -211,10 +213,10 @@ async def run_coros(self): self._taskConn = asyncio.create_task(self.connect()) self._taskQueue = asyncio.create_task(self.sendQueue()) await asyncio.gather(self._taskConn, self._taskQueue) - + async def connect(self): """ - Connects + Connects """ if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug("connect method called") @@ -222,7 +224,7 @@ async def connect(self): await self._application.initialize() await self._application.start() self._updater = self._application.updater - + q = await self._updater.start_polling(timeout=self._long_polling_timeout, error_callback=self.error_handler) if self.logger.isEnabledFor(logging.DEBUG): @@ -235,14 +237,14 @@ async def connect(self): self.logger.debug(f"sent welcome message {self._welcome_msg}") cids = [key for key, value in self._chat_ids_item().items() if value == 1] self.msg_broadcast(self._welcome_msg, chat_id=cids) - + except TelegramError as e: # catch Unauthorized errors due to an invalid token self.logger.error(f"Unable to start up Telegram conversation. Maybe an invalid token? {e}") return False if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug("connect method end") - + def error_handler(self, update, context): """ Just logs an error in case of a problem @@ -257,7 +259,7 @@ async def sendQueue(self): Waiting for messages to be sent in the queue and sending them to Telegram. The queue expects a dictionary with various parameters dict txt: {"msgType":"Text", "msg":msg, "chat_id":chat_id, "reply_markup":reply_markup, "parse_mode":parse_mode } - dict photo: {"msgType":"Photo", "photofile_or_url":photofile_or_url, "chat_id":chat_id, "caption":caption, "local_prepare":local_prepare} + dict photo: {"msgType":"Photo", "photofile_or_url":photofile_or_url, "chat_id":chat_id, "caption":caption, "local_prepare":local_prepare} """ if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug(f"sendQueue called - queue: [{self._queue}]") @@ -275,7 +277,7 @@ async def sendQueue(self): resendDelay = message["resendDelay"] if "resendAttemps" in message: resendAttemps = message["resendAttemps"] - + if resendDelay <= 0: if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug(f"message queue {message}") @@ -283,18 +285,18 @@ async def sendQueue(self): result = await self.async_msg_broadcast(message["msg"], message["chat_id"], message["reply_markup"], message["parse_mode"]) elif message["msgType"] == "Photo": result = await self.async_photo_broadcast(message["photofile_or_url"], message["caption"], message["chat_id"], message["local_prepare"]) - + # An error occurred while sending - result: list containing the dic of the failed send attempt - if result: + if result: for res in result: resendAttemps+=1 if resendAttemps > self._resend_attemps: if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug(f"don't initiate any further send attempts for: {res}") - break + break else: resendDelay = self._resend_delay - + # Including the sendDelay and sendAttempts in the queue message for the next send attempt. res["resendDelay"] = resendDelay res["resendAttemps"] = resendAttemps @@ -312,7 +314,7 @@ async def sendQueue(self): async def disconnect(self): """ - Stop listening to push updates and logout of this istances Apple TV + Stop listening to push updates and shutdown """ self.logger.info(f"disconnecting") @@ -522,7 +524,7 @@ async def async_msg_broadcast(self, msg, chat_id=None, reply_markup=None, parse_ sendResult = [] if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug(f"async msg_broadcast called") - + for cid in self.get_chat_id_list(chat_id): try: response = await self._bot.send_message(chat_id=cid, text=msg, reply_markup=reply_markup, parse_mode=parse_mode) @@ -543,7 +545,7 @@ async def async_msg_broadcast(self, msg, chat_id=None, reply_markup=None, parse_ return None else: return sendResult - + def msg_broadcast(self, msg, chat_id=None, reply_markup=None, parse_mode=None): if self.alive: @@ -554,7 +556,7 @@ def msg_broadcast(self, msg, chat_id=None, reply_markup=None, parse_mode=None): self._queue.put(q_msg) except Exception as e: self.logger.debug(f"Exception '{e}' occurred, please inform plugin maintainer!") - + async def async_photo_broadcast(self, photofile_or_url, caption=None, chat_id=None, local_prepare=True): """ Send an image to the given chat @@ -1042,7 +1044,7 @@ def list_items_control(self): if not text: text = self.translate("no items found with the attribute %s") % ITEM_ATTR_CONTROL #self._bot.sendMessage(chat_id=chat_id, text=text) - return text + return text async def change_item(self, update, context, name, dicCtl): """ @@ -1146,4 +1148,3 @@ async def telegram_change_item_timeout(self, **kwargs): self._waitAnswer = None # self._bot.send_message(chat_id=update.message.chat.id, text=self.translate("Control/Change item-values:"), reply_markup={"keyboard": self.create_control_reply_markup()}) await context.bot.sendMessage(chat_id=update.message.chat.id, text=self.translate("Control/Change item-values:"), reply_markup={"keyboard": self.create_control_reply_markup()}) - diff --git a/telegram/assets/telegram_webif.png b/telegram/assets/telegram_webif.png new file mode 100644 index 000000000..0044a2696 Binary files /dev/null and b/telegram/assets/telegram_webif.png differ diff --git a/telegram/assets/webif1.png b/telegram/assets/webif1.png deleted file mode 100755 index eb833903e..000000000 Binary files a/telegram/assets/webif1.png and /dev/null differ diff --git a/telegram/assets/webif2.png b/telegram/assets/webif2.png deleted file mode 100755 index 25b27b146..000000000 Binary files a/telegram/assets/webif2.png and /dev/null differ diff --git a/telegram/plugin.yaml b/telegram/plugin.yaml index 18bb738dc..2173691c7 100755 --- a/telegram/plugin.yaml +++ b/telegram/plugin.yaml @@ -7,12 +7,11 @@ plugin: en: 'Connects to the telegram messenger service' maintainer: gamade, ivan73, bmxp state: ready - tester: NONE + tester: onkelandy keywords: telegram chat messenger photo - documentation: http://smarthomeng.de/user/plugins/telegram/user_doc.html support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1548691-support-thread-für-das-telegram-plugin - version: 2.0.0 # Plugin version + version: 2.0.1 # Plugin version sh_minversion: 1.9.5 # minimum shNG version to use this plugin # sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest) # py_minversion: 3.6 # minimum Python version to use for this plugin @@ -147,7 +146,7 @@ item_attributes: telegram_control: type: str description: - de: 'Item schreiben per Telegram Keyboard. Der Wert des Attributes (mit mehreren Paramtern) bestimmt das Telegram Keyboard Kommando' + de: 'Item schreiben per Telegram Keyboard. Den Wert des Attributes (mit mehreren Paramtern) bestimmt das Telegram Keyboard Kommando' en: 'Write items with telegram keyboard. The value of the attribute (with parameters) defines the telegram keyboard command' logic_parameters: NONE diff --git a/telegram/user_doc.rst b/telegram/user_doc.rst index 245f4740e..e1b8890a8 100755 --- a/telegram/user_doc.rst +++ b/telegram/user_doc.rst @@ -5,6 +5,13 @@ telegram ======== +.. image:: webif/static/img/plugin_logo.svg + :alt: plugin logo + :width: 300px + :height: 300px + :scale: 50 % + :align: left + Das Plugin dient zum Senden und Empfangen von Nachrichten über den `Telegram Nachrichten Dienst `_ @@ -71,7 +78,7 @@ Im Dictionary sind Paare von Chat-ID und Berechtigung gespeichert. # Beispiel value: '{ 3234123342: 1, 9234123341: 0 }' # Ein Dictionary mit chat id und: # 2 für Lese und Schreibzugriff ohne Willkommens- und Ende Nachricht - # 1 für Lese und Schreibzugriff + # 1 für Lese und Schreibzugriff # 0 für einen nur Lese-Zugriff # Nachfolgend ein Chat dem Lese- und Schreibrechte gewährt werden value: '{ 3234123342: 1 }' @@ -148,7 +155,7 @@ Einfaches Beispiel telegram_value_match_regex: (true|True|1) Dadurch wird auf eine mehrfache Zuweisung des Items mit dem Wert ``True`` nur einmal mit einer Nachricht reagiert. Um eine weitere Nachricht zu generieren -muss das Item zunächst wieder den Wert ``False`` annehmen. Das Attribut ``telegram_value_match_regex`` filtert den Wert so das es bei der Änderung des Itemwertes +muss das Item zunächst wieder den Wert ``False`` annehmen. Das Attribut ``telegram_value_match_regex`` filtert den Wert so das es bei der Änderung des Itemwertes auf ``False`` zu keiner Meldung *Es klingelt an der Tür* kommt. @@ -173,8 +180,8 @@ Beispiel cache: True telegram_message: "TestBool: [VALUE]" telegram_value_match_regex: 1 # nur Nachricht senden wenn 1 (True) - - + + telegram_message_chat_id ------------------------ Ist zusätzlich zum Attribut ``telegram_message`` auch das Attribut ``telegram_message_chat_id`` gesetzt, wird die Nachricht nur an die dort angegebene Chat-ID (hier 3234123342) gesendet. @@ -277,24 +284,24 @@ Bei Auswahl eines dieser Kommandos im Telegram Client kann dann ein Item vom Typ ``name`` Item wird mit diesem Namen im Bot als Kommando dargestellt -``type`` +``type`` Möglichkeiten: on, off, onoff, toggle, num - on + on * nur Einschalten ist möglich - off + off * nur Ausschalten ist möglich - onoff - * das Ein- und Ausschalten muss mit einen weiteren Kommando vom Tastaturmenu ausgewählt werden + onoff + * das Ein- und Ausschalten muss mit einen weiteren Kommando vom Tastaturmenu ausgewählt werden [On] [Off] (nach einem Timeout ohne Antwort wird der Befehl abgebrochen) - toggle + toggle * der Wert des Items wird umgeschltet (0 zu 1; 1 zu 0) - num + num * es kann eine Zahl an SH gesendet werden und das entsprechende Item wird damit geschrieben. (nach einem Timeout ohne Antwort wird der Befehl abgebrochen) ``question`` Sicherheitsabfrage vor dem Schalten des Items (verwendbar bei type:on/off/toggle - nach einem Timeout ohne Antwort wird der Befehl abgebrochen) [Yes] [No] -``min`` +``min`` Minimalwert (verwendbar bei type:num) -``max`` +``max`` Maximalwert (verwendbar bei type:num) ``timeout`` Zeit nach welcher der Befehl mit Antwort(onoff/question/num) abgebrochen wird (default 20Sekunden) @@ -390,8 +397,8 @@ Die folgende Beispiellogik zeigt einige Nutzungsmöglichkeiten für die Funktion .. code:: python - telegram_plugin = sh.plugins.return_plugin('telegram') - + telegram_plugin = sh.plugins.return_plugin('telegram') + # Eine Nachricht `Hello world!` wird an alle vertrauten Chat Ids gesendet msg = "Hello world!" telegram_plugin.msg_broadcast(msg) @@ -590,4 +597,28 @@ dargestellt und die entsprechenden Aktionen ausgeführt. # Message senden if msg != '': - telegram_plugin.msg_broadcast(msg, message_chat_id, reply_markup, parse_mode) \ No newline at end of file + telegram_plugin.msg_broadcast(msg, message_chat_id, reply_markup, parse_mode) + +Web Interface +============= + +Das Webinterface bietet folgende Informationen: + +- **Allgemeines**: Oben rechts wird das Timeout, Begrüßungs- und Verabschiedungsnachricht angezeigt + +- **Output Items**: Sämtliche Items, die zum Senden einer Nachricht beitragen + +- **Input Items**: Items, über die Nachrichten empfangen werden können + +- **Telegram Control**: Items, die über Telegram geändert werden können + +- **Telegram Infos**: Befehle mit den zugehörigen Items, deren Werte auf eine Abfrage hin kommuniziert werden + +- **Chat IDs**: Registrierte Chat IDs inkl. Angabe der Zugriffe + +.. image:: assets/telegram_webif.png + :height: 1584px + :width: 3340px + :scale: 25% + :alt: Web Interface + :align: center diff --git a/telegram/webif/templates/index.html b/telegram/webif/templates/index.html index 04b66d672..fd4c95ec9 100755 --- a/telegram/webif/templates/index.html +++ b/telegram/webif/templates/index.html @@ -3,29 +3,14 @@