From e1bd96c7dda1dc38e20347c641411c75f99c1f55 Mon Sep 17 00:00:00 2001 From: gwe Date: Fri, 17 May 2024 15:27:44 +0200 Subject: [PATCH 1/9] add again command that will print again the last file add fix for camera with new version --- README.md | 4 +- octoprint_telegram/__init__.py | 88 +++++++++++-------- octoprint_telegram/static/js/telegram.js | 4 +- octoprint_telegram/telegramCommands.py | 19 ++++ .../templates/telegram_settings.jinja2 | 8 ++ setup.py | 2 +- 6 files changed, 84 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 76cc5ee..0c4913b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This plugin integrates Telegram Messenger with Octoprint. It sends messages (with photos if available) on print start, end and failure. Also it sends messages during the print at configurable intervals. That way you don't have to remember to regularly have a look at the printing process. Also, you can control Octoprint via messages (settings, start a print and much more). Send `/status` to get the current printer status or `/abort` to abort the current print. Send `/help` for a list of all recognized commands. You may also use this bot in groups. -**Latest release: [1.6.5](https://github.com/fabianonline/OctoPrint-Telegram/releases)** +**Latest release: [1.6.8](https://github.com/fabianonline/OctoPrint-Telegram/releases)** ## Contents @@ -262,7 +262,7 @@ sudo apt-get install cpulimit - the TuyaSmartplug plugin API. Requires the [TuyaSmartplug plugin](https://github.com/ziirish/OctoPrint-TuyaSmartplug/) sadly for now wait on accept the push request to get the list of plug -**`/gcode`** - Send the gcode to the printer where XXX is the gcode command (/gcode_M117 HelloWorld for exemple) +**`/gcode_XXX`** - Send the gcode to the printer where XXX is the gcode command (/gcode_M117 HelloWorld for exemple) #### Notes: diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 24bca5f..0a6f475 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -1753,9 +1753,11 @@ def _send_msg( premethod = self._settings.get(["PreImgMethod"]) self._logger.debug("PreImgMethod {}".format(premethod)) precommand = self._settings.get(["PreImgCommand"]) + doneprecommand = False if premethod == "GCODE": self._logger.debug("PreImgCommand {}".format(precommand)) self._printer.commands(precommand) + doneprecommand = True elif premethod == "SYSTEM": self._logger.debug("PreImgCommand {}".format(precommand)) p = subprocess.Popen(precommand, shell=True) @@ -1769,10 +1771,18 @@ def _send_msg( r = p.returncode self._logger.debug( "PreImg system command returned: {}".format(r) - ) + doneprecommand = True + + if doneprecommand: + precommanddelay = self._settings.get_int(["precommand_delay"]) + if precommanddelay != None: + if precommanddelay > 0: + time.sleep(precommanddelay) + except Exception as ex: self._logger.exception("Exception PreImgMethod: " + str(ex)) + self._settings.get_int(["message_at_print_done_delay"]) if delay > 0: time.sleep(delay) try: @@ -1982,15 +1992,10 @@ def _send_msg( self._logger.debug("multicam_profiles : " + str(curr)) for li in curr: try: - snapshot_url = li.get("snapshot") # try to get the snapshot url - self._logger.debug( - "multicam url : " + str(snapshot_url) - ) - - if not snapshot_url: # if snapshot url is not stored try to create it - self._logger.debug( - "multicam profile: " + str(li) - ) + self._logger.debug("multicam profile: " + str(li)) + snapshot_url = li.get("snapshot") + self._logger.debug("multicam snapshot : " + str(snapshot_url)) + if(snapshot_url == "" or snapshot_url == "http://" or snapshot_url == "https://" or snapshot_url == None): snapshot_url = li.get("URL") self._logger.debug( "multicam url : " + str(snapshot_url) @@ -2177,6 +2182,12 @@ def _send_msg( try: if with_image or with_gif: + #delay + postcommanddelay = self._settings.get_int(["postcommand_delay"]) + if postcommanddelay != None: + if postcommanddelay > 0: + time.sleep(postcommanddelay) + ##find a way to decide if should and what command to light on postmethod = self._settings.get(["PostImgMethod"]) self._logger.debug("PostImgMethod {}".format(postmethod)) @@ -2500,7 +2511,8 @@ def setMyCommands(self, force=False): "description": "Makes the bot talk again (opposite of `/shutup`)", } ) - commands.append( + commands.append({"command":"again","description":"Print again the same file"}) + commands.append( {"command": "help", "description": "Shows this help message"} ) resp = requests.post( @@ -2578,11 +2590,11 @@ def take_image(self, snapshot_url=""): rotate = self._settings.global_get(["webcam", "rotate90"]) self._logger.debug( "Image transformations [H:%s, V:%s, R:%s]", flipH, flipV, rotate - ) + image = Image.open(bytes_reader_class(data)) if data == None: return None if flipH or flipV or rotate: - image = Image.open(bytes_reader_class(data)) + if flipH: image = image.transpose(Image.FLIP_LEFT_RIGHT) if flipV: @@ -2714,16 +2726,17 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0): if self.TestProgram(["nice", "--version"]) > 0: params = ["nice", "-n", "20"] - self._logger.info("test if cpulimit exist") - if self.TestProgram(["cpulimit", "--help"]) <= 0: - self._logger.info( - "cpulimit don't exist so send a message to install and exit" - ) - self.send_msg( - self.gEmo("dizzy face") - + " Problem creating gif, please check log file, and make sure you have installed cpulimit with following command : `sudo apt-get install cpulimit`", - chatID=chatID, - ) + if(os.name != 'nt'): + self._logger.info("test if cpulimit exist") + if self.TestProgram(["cpulimit", "--help"]) <= 0: + self._logger.info( + "cpulimit don't exist so send a message to install and exit" + ) + self.send_msg( + self.gEmo("dizzy face") + + " Problem creating gif, please check log file, and make sure you have installed cpulimit with following command : `sudo apt-get install cpulimit`", + chatID=chatID, + ) return "" self._logger.info("test if ffmpeg exist") @@ -2788,20 +2801,21 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0): "Caught an exception trying to get number of cpu : " + str(ex) ) - self._logger.info( - "limit_cpu=" - + str(limit_cpu) - + " | used_cpu=" - + str(used_cpu) - + " | because nb_cpu=" - + str(nb_cpu) - ) - params.append("cpulimit") - params.append("-l") - params.append(str(limit_cpu)) - params.append("-f") - params.append("-z") - params.append("--") + if(os.name != 'nt'): + self._logger.info( + "limit_cpu=" + + str(limit_cpu) + + " | used_cpu=" + + str(used_cpu) + + " | because nb_cpu=" + + str(nb_cpu) + ) + params.append("cpulimit") + params.append("-l") + params.append(str(limit_cpu)) + params.append("-f") + params.append("-z") + params.append("--") params.append("ffmpeg") params.append("-y") params.append("-threads") diff --git a/octoprint_telegram/static/js/telegram.js b/octoprint_telegram/static/js/telegram.js index f1fbdc4..54c3a97 100644 --- a/octoprint_telegram/static/js/telegram.js +++ b/octoprint_telegram/static/js/telegram.js @@ -590,7 +590,9 @@ $(function() { var settings_to_check_number = [ settings.notification_height, settings.notification_time, - settings.message_at_print_done_delay + settings.message_at_print_done_delay, + setting.precommand_delay, + setting.postcommand_delay ]; for (var i = 0; i < settings_to_check_number.length; i++) { if (!self.isNumber(settings_to_check_number[i]())) { diff --git a/octoprint_telegram/telegramCommands.py b/octoprint_telegram/telegramCommands.py index 02ef32b..cf677f6 100644 --- a/octoprint_telegram/telegramCommands.py +++ b/octoprint_telegram/telegramCommands.py @@ -46,6 +46,7 @@ def __init__(self, main): "/dontshutup": {"cmd": self.cmdNShutup}, "/print": {"cmd": self.cmdPrint, "param": True}, "/files": {"cmd": self.cmdFiles, "param": True}, + "/again": {"cmd": self.cmdAgain, "param": True}, #giloser 16-10-2021 "/upload": {"cmd": self.cmdUpload}, "/filament": {"cmd": self.cmdFilament, "param": True}, "/sys": {"cmd": self.cmdSys, "param": True}, @@ -780,6 +781,24 @@ def cmdUpload(self, chat_id, from_id, cmd, parameter, user = ""): chatID=chat_id, ) + ############################################################################################ + def cmdAgain(self,chat_id,from_id,cmd,parameter): + try: + data = self.main._printer.get_current_data() + if self.main._printer.is_printing(): + self.main.send_msg(self.gEmo("warning") + " A print job is already running. You can"t print two thing at the same time. Maybe you want to use /abort?",chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + elif not self.main._printer.is_operational(): + self.main.send_msg(self.gEmo("warning") + gettext(" Can"t start printing: I"m not connected to a printer."),chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + elif data["job"]["file"]["name"] is not None: + file = data["job"]["file"]["name"] + msg = self.gEmo("info") + gettext(" The file " +str(file)+" is loaded.\n\n"+self.gEmo("question")+" Do you want me to start printing it now?", file=data["job"]["file"]["name"]) + self.main.send_msg(msg,noMarkup=True, responses=[[[self.main.emojis["check"]+gettext("Print"),"/print_s"], [self.main.emojis["cross mark"]+gettext(" Cancel"),"/print_x"]]],chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + else: + self.main.send_msg(self.gEmo("warning") + gettext(" File not loaded. Please use this after another print."),chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + except Exception as e: + self._logger.warn("Command failed: %s" % e) + self.main.send_msg(self.gEmo("warning") + " Command failed with exception: %s!" % e,chatID = chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + ############################################################################################ def cmdSys(self, chat_id, from_id, cmd, parameter, user = ""): if parameter and parameter != "back": diff --git a/octoprint_telegram/templates/telegram_settings.jinja2 b/octoprint_telegram/templates/telegram_settings.jinja2 index 6b30db5..d592b0f 100644 --- a/octoprint_telegram/templates/telegram_settings.jinja2 +++ b/octoprint_telegram/templates/telegram_settings.jinja2 @@ -249,6 +249,10 @@ Action pre image could be none, a gcode or a system command (script name with full path) + + + s + Wait this many seconds after pre image action. Set to 0 to disable. @@ -263,6 +267,10 @@ Action post image could be none, a gcode or a system command (script name with full path) + + + s + Wait this many seconds before post image action. Set to 0 to disable. diff --git a/setup.py b/setup.py index 1cc1987..df95b5d 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ plugin_name = "OctoPrint-Telegram" # The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module -plugin_version = "1.6.7" +plugin_version = "1.6.8" # The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin # module From 987dbfe30f7cf404060e7ee6c0b09b726b2ee588 Mon Sep 17 00:00:00 2001 From: gwe Date: Fri, 17 May 2024 15:58:47 +0200 Subject: [PATCH 2/9] fix tab and space typo --- .gitignore | 4 +- octoprint_telegram/__init__.py | 96 +++++++++++++++++----------------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 7003767..74db954 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ dist *.*~ *.yaml dev_utils/NOTES.txt -dev_utils/NOTES.txt \ No newline at end of file +dev_utils/NOTES.txt +octoprint_telegram/__init__.py.bak +octoprint_telegram/telegramCommands.py.bak diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 0a6f475..7740cb2 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -1753,11 +1753,11 @@ def _send_msg( premethod = self._settings.get(["PreImgMethod"]) self._logger.debug("PreImgMethod {}".format(premethod)) precommand = self._settings.get(["PreImgCommand"]) - doneprecommand = False + doneprecommand = False if premethod == "GCODE": self._logger.debug("PreImgCommand {}".format(precommand)) self._printer.commands(precommand) - doneprecommand = True + doneprecommand = True elif premethod == "SYSTEM": self._logger.debug("PreImgCommand {}".format(precommand)) p = subprocess.Popen(precommand, shell=True) @@ -1769,20 +1769,21 @@ def _send_msg( while p.poll() is None: time.sleep(0.1) r = p.returncode - self._logger.debug( + self._logger.debug ( "PreImg system command returned: {}".format(r) - doneprecommand = True + ) + doneprecommand = True - if doneprecommand: - precommanddelay = self._settings.get_int(["precommand_delay"]) - if precommanddelay != None: - if precommanddelay > 0: - time.sleep(precommanddelay) + if doneprecommand: + precommanddelay = self._settings.get_int(["precommand_delay"]) + if precommanddelay != None: + if precommanddelay > 0: + time.sleep(precommanddelay) except Exception as ex: self._logger.exception("Exception PreImgMethod: " + str(ex)) - self._settings.get_int(["message_at_print_done_delay"]) + self._settings.get_int(["message_at_print_done_delay"]) if delay > 0: time.sleep(delay) try: @@ -1992,10 +1993,10 @@ def _send_msg( self._logger.debug("multicam_profiles : " + str(curr)) for li in curr: try: - self._logger.debug("multicam profile: " + str(li)) - snapshot_url = li.get("snapshot") - self._logger.debug("multicam snapshot : " + str(snapshot_url)) - if(snapshot_url == "" or snapshot_url == "http://" or snapshot_url == "https://" or snapshot_url == None): + self._logger.debug("multicam profile: " + str(li)) + snapshot_url = li.get("snapshot") + self._logger.debug("multicam snapshot : " + str(snapshot_url)) + if(snapshot_url == "" or snapshot_url == "http://" or snapshot_url == "https://" or snapshot_url == None): snapshot_url = li.get("URL") self._logger.debug( "multicam url : " + str(snapshot_url) @@ -2183,10 +2184,10 @@ def _send_msg( try: if with_image or with_gif: #delay - postcommanddelay = self._settings.get_int(["postcommand_delay"]) - if postcommanddelay != None: - if postcommanddelay > 0: - time.sleep(postcommanddelay) + postcommanddelay = self._settings.get_int(["postcommand_delay"]) + if postcommanddelay != None: + if postcommanddelay > 0: + time.sleep(postcommanddelay) ##find a way to decide if should and what command to light on postmethod = self._settings.get(["PostImgMethod"]) @@ -2512,7 +2513,7 @@ def setMyCommands(self, force=False): } ) commands.append({"command":"again","description":"Print again the same file"}) - commands.append( + commands.append( {"command": "help", "description": "Shows this help message"} ) resp = requests.post( @@ -2588,9 +2589,10 @@ def take_image(self, snapshot_url=""): flipH = self._settings.global_get(["webcam", "flipH"]) flipV = self._settings.global_get(["webcam", "flipV"]) rotate = self._settings.global_get(["webcam", "rotate90"]) - self._logger.debug( + self._logger.debug ( "Image transformations [H:%s, V:%s, R:%s]", flipH, flipV, rotate - image = Image.open(bytes_reader_class(data)) + ) + image = Image.open(bytes_reader_class(data)) if data == None: return None if flipH or flipV or rotate: @@ -2726,17 +2728,17 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0): if self.TestProgram(["nice", "--version"]) > 0: params = ["nice", "-n", "20"] - if(os.name != 'nt'): - self._logger.info("test if cpulimit exist") - if self.TestProgram(["cpulimit", "--help"]) <= 0: - self._logger.info( - "cpulimit don't exist so send a message to install and exit" - ) - self.send_msg( - self.gEmo("dizzy face") - + " Problem creating gif, please check log file, and make sure you have installed cpulimit with following command : `sudo apt-get install cpulimit`", - chatID=chatID, - ) + if(os.name != 'nt'): + self._logger.info("test if cpulimit exist") + if self.TestProgram(["cpulimit", "--help"]) <= 0: + self._logger.info( + "cpulimit don't exist so send a message to install and exit" + ) + self.send_msg( + self.gEmo("dizzy face") + + " Problem creating gif, please check log file, and make sure you have installed cpulimit with following command : `sudo apt-get install cpulimit`", + chatID=chatID, + ) return "" self._logger.info("test if ffmpeg exist") @@ -2801,21 +2803,21 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0): "Caught an exception trying to get number of cpu : " + str(ex) ) - if(os.name != 'nt'): - self._logger.info( - "limit_cpu=" - + str(limit_cpu) - + " | used_cpu=" - + str(used_cpu) - + " | because nb_cpu=" - + str(nb_cpu) - ) - params.append("cpulimit") - params.append("-l") - params.append(str(limit_cpu)) - params.append("-f") - params.append("-z") - params.append("--") + if(os.name != 'nt'): + self._logger.info( + "limit_cpu=" + + str(limit_cpu) + + " | used_cpu=" + + str(used_cpu) + + " | because nb_cpu=" + + str(nb_cpu) + ) + params.append("cpulimit") + params.append("-l") + params.append(str(limit_cpu)) + params.append("-f") + params.append("-z") + params.append("--") params.append("ffmpeg") params.append("-y") params.append("-threads") From 99a630161f7886d858603c1ba79b831914f80d51 Mon Sep 17 00:00:00 2001 From: gwe Date: Fri, 17 May 2024 16:06:59 +0200 Subject: [PATCH 3/9] again a typo --- octoprint_telegram/telegramCommands.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octoprint_telegram/telegramCommands.py b/octoprint_telegram/telegramCommands.py index cf677f6..d9c7d1b 100644 --- a/octoprint_telegram/telegramCommands.py +++ b/octoprint_telegram/telegramCommands.py @@ -786,9 +786,9 @@ def cmdAgain(self,chat_id,from_id,cmd,parameter): try: data = self.main._printer.get_current_data() if self.main._printer.is_printing(): - self.main.send_msg(self.gEmo("warning") + " A print job is already running. You can"t print two thing at the same time. Maybe you want to use /abort?",chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + self.main.send_msg(self.gEmo("warning") + " A print job is already running. You can't print two thing at the same time. Maybe you want to use /abort? ",chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) elif not self.main._printer.is_operational(): - self.main.send_msg(self.gEmo("warning") + gettext(" Can"t start printing: I"m not connected to a printer."),chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) + self.main.send_msg(self.gEmo("warning") + gettext(" Can't start printing: I'm not connected to a printer."),chatID=chat_id)#, msg_id = self.main.getUpdateMsgId(chat_id)) elif data["job"]["file"]["name"] is not None: file = data["job"]["file"]["name"] msg = self.gEmo("info") + gettext(" The file " +str(file)+" is loaded.\n\n"+self.gEmo("question")+" Do you want me to start printing it now?", file=data["job"]["file"]["name"]) From 603247f1c12ec37cfd4ec14f29000f61925cc5f9 Mon Sep 17 00:00:00 2001 From: gwe Date: Mon, 27 May 2024 16:48:53 +0200 Subject: [PATCH 4/9] add new management of webcam --- octoprint_telegram/__init__.py | 462 +++++++++++++++++++++------------ 1 file changed, 298 insertions(+), 164 deletions(-) diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 7740cb2..4cd4142 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -3,6 +3,8 @@ from subprocess import Popen, PIPE import threading, requests, urllib3, re, time, datetime, io, json, random, logging, traceback, io, collections, os, flask, base64, PIL, pkg_resources, subprocess, zipfile, glob, sys, multiprocessing import octoprint.plugin, octoprint.util, octoprint.filemanager +from octoprint.schema.webcam import RatioEnum, Webcam, WebcamCompatibility +from octoprint.webcams import WebcamNotAbleToTakeSnapshotException from flask_babel import gettext from flask_login import current_user from .telegramCommands import TCMD # telegramCommands. @@ -43,7 +45,7 @@ def __init__(self, main): self.do_stop = False self.username = "UNKNOWN" self._logger = main._logger.getChild("listener") - self.gEmo = self.main.gEmo + self.gEmo = self.main.gEmo def run(self): self._logger.debug("Try first connect.") @@ -901,6 +903,18 @@ def __init__(self, version): "stop": "\U000025FC", } self.emojis.update(telegramEmojiDict) + self.cameras = [] + self.snap_new_method = False + + def initialize_cameras(self): + self._logger.info("Initialize the camera") + if hasattr(octoprint.plugin.types, "WebcamProviderPlugin"): + self.cameras = self._plugin_manager.get_implementations(octoprint.plugin.types.WebcamProviderPlugin) + self.snap_new_method = True + else: + self.cameras = [] + self.snap_new_method = False + # all emojis will be get via this method to disable them globaly by the corrosponding setting # so if you want to use emojis anywhere use gEmo("...") istead of emojis["..."] @@ -988,6 +1002,7 @@ def get_wizard_version(self): def on_after_startup(self): self.set_log_level() self._logger.addFilter(TelegramPluginLoggingFilter()) + self.initialize_cameras() self.tcmd = TCMD(self) self.triggered = False self.tmsg = TMSG( @@ -1729,6 +1744,32 @@ def _send_edit_msg( except Exception as ex: self._logger.debug("Caught an exception in _send_edit_msg(): " + str(ex)) + def take_webcam_snapshot(self, provided_webcam): + webcam = provided_webcam.config + + if webcam is None: + self._logger.exception("Exception WebcamNotAbleToTakeSnapshotException(provided_webcam is None)") + return None + + # using compat.snapshot because snapshotDisplay is supposedly only for user + snapshot_url = webcam.compat.snapshot + can_snapshot = snapshot_url is not None and snapshot_url != "http://" and snapshot_url != "" + + if not can_snapshot: + self._logger.exception("Exception WebcamNotAbleToTakeSnapshotException("+webcam.name+")") + return None + + with self._capture_mutex: + self._logger.debug(f"Capturing image from {snapshot_url}") + r = requests.get( + snapshot_url, + stream=True, + timeout=self.snapshotTimeout, + verify=self.snapshotSslValidation, + ) + r.raise_for_status() + return r.iter_content(chunk_size=1024) + def _send_msg( self, message="", @@ -1854,61 +1895,92 @@ def _send_msg( else: self._logger.info("Will try to create a gif ") - # requests.get(self.main.bot_url + "/sendChatAction", params = {'chat_id': chat_id, 'action': 'upload_document'}, proxies=self.getProxies()) - if self._plugin_manager.get_plugin( - "multicam", True - ) and self._settings.get(["multicam"]): - try: - curr = self._settings.global_get( - ["plugins", "multicam", "multicam_profiles"] - ) - self._logger.debug("multicam_profiles : " + str(curr)) - ListGif = [] - for li in curr: + if self.snap_new_method: + for camera in self.cameras: + configs = camera.get_webcam_configurations() + for config in configs: try: - self._logger.debug( - "multicam profile : " + str(li) - ) - url = li.get("URL") + self._logger.debug("get_webcam_configurations : " + str(config)) + url = config.snapshotDisplay self._logger.debug("multicam URL : " + str(url)) - ret = self.create_gif_new(chatID, 0, li) + ret = self.create_gif_new(chatID, 0, 0,config) if ret != "": ListGif.append(ret) - # if not sendOneInLoop: - # self.send_file(chatID, ret,message) - # else: - # self.send_file(chatID, ret,"") - # sendOneInLoop = True except Exception as ex: self._logger.exception( - "Exception loop multicam URL to create gif: " + "Exception loop webcam configuration to create gif: " + str(ex) ) - ret = ListGif[-1] - self._logger.debug("ListGif: " + str(ListGif)) - for x in ListGif: - try: - if x != ret: + ret = ListGif[-1] + self._logger.debug("ListGif: " + str(ListGif)) + for x in ListGif: + try: + if x != ret: + self._logger.debug( + "send_file whithout message: " + str(x) + ) + self.send_file(chatID, x, "") + except Exception as ex: + self._logger.exception( + "Exception loop multicam URL to send gif: " + + str(ex) + ) + else: + # requests.get(self.main.bot_url + "/sendChatAction", params = {'chat_id': chat_id, 'action': 'upload_document'}, proxies=self.getProxies()) + if self._plugin_manager.get_plugin( + "multicam", True + ) and self._settings.get(["multicam"]): + try: + curr = self._settings.global_get( + ["plugins", "multicam", "multicam_profiles"] + ) + self._logger.debug("multicam_profiles : " + str(curr)) + ListGif = [] + for li in curr: + try: self._logger.debug( - "send_file whithout message: " + str(x) + "multicam profile : " + str(li) + ) + url = li.get("URL") + self._logger.debug("multicam URL : " + str(url)) + ret = self.create_gif_new(chatID, 0, li) + if ret != "": + ListGif.append(ret) + # if not sendOneInLoop: + # self.send_file(chatID, ret,message) + # else: + # self.send_file(chatID, ret,"") + # sendOneInLoop = True + except Exception as ex: + self._logger.exception( + "Exception loop multicam URL to create gif: " + + str(ex) + ) + ret = ListGif[-1] + self._logger.debug("ListGif: " + str(ListGif)) + for x in ListGif: + try: + if x != ret: + self._logger.debug( + "send_file whithout message: " + str(x) + ) + self.send_file(chatID, x, "") + except Exception as ex: + self._logger.exception( + "Exception loop multicam URL to send gif: " + + str(ex) ) - self.send_file(chatID, x, "") - except Exception as ex: - self._logger.exception( - "Exception loop multicam URL to send gif: " - + str(ex) - ) - except Exception as ex: - self._logger.exception( - "Exception occured on getting multicam options: " - + str(ex) - ) - else: - ret = self.create_gif_new(chatID, 0, 0) + except Exception as ex: + self._logger.exception( + "Exception occured on getting multicam options: " + + str(ex) + ) + else: + ret = self.create_gif_new(chatID, 0, 0,0) if ret == "": - ret = self.create_gif_new(chatID, 0, 0) + ret = self.create_gif_new(chatID, 0, 0,0) if ret != "" and not sendOneInLoop: self._logger.debug("send_video with message: " + str(ret)) @@ -1927,109 +1999,23 @@ def _send_msg( ) # and make sure you have installed libav-tools or ffmpeg with command : `sudo apt-get install libav-tools`",chatID=chat_id) else: self._logger.debug("data so far: " + str(data)) - + image_data = None if with_image: - try: - image_data = self.take_image( - self._settings.global_get(["webcam", "snapshot"]) - ) - except Exception as ex: - self._logger.info( - "Caught an exception trying take image: " + str(ex) - ) - - try: - printable_image_data = None - if image_data != None: # giloser check before using - if is_in_python_2(): - printable_image_data = image_data.decode( - "utf8", errors="ignore" - ) - else: - printable_image_data = str(image_data) - # self._logger.debug("image data so far: {}".format(printable_image_data)) - except Exception as ex: - self._logger.info( - "Caught an exception trying to create printable_image_data: " - + str(ex) - ) - - try: - if ( - not image_data - or image_data == None - or "html" in printable_image_data - ): - image_data = None - message = "[ERR GET IMAGE]\n\n " + "".join( - message - ) # .decode('utf-8', errors='ignore')) - except Exception as ex: - self._logger.info( - "Caught an exception trying to add info that we don't have image: " - + str(ex) - ) - - try: - self._logger.debug( - "message so far: {}".format(message) - ) # .decode('utf-8', errors='ignore'))) - except Exception as ex: - self._logger.info( - "Caught an exception trying to debug message so far: " - + str(ex) - ) - - try: - files = {} - sendOneInLoop = False - if self._plugin_manager.get_plugin( - "multicam", True - ) and self._settings.get(["multicam"]): - try: - curr = self._settings.global_get( - ["plugins", "multicam", "multicam_profiles"] - ) - self._logger.debug("multicam_profiles : " + str(curr)) - for li in curr: + if self.snap_new_method: + for camera in self.cameras: + configs = camera.get_webcam_configurations() + for config in configs: try: - self._logger.debug("multicam profile: " + str(li)) - snapshot_url = li.get("snapshot") - self._logger.debug("multicam snapshot : " + str(snapshot_url)) - if(snapshot_url == "" or snapshot_url == "http://" or snapshot_url == "https://" or snapshot_url == None): - snapshot_url = li.get("URL") - self._logger.debug( - "multicam url : " + str(snapshot_url) - ) - - defsnap = self._settings.global_get( - ["webcam", "snapshot"] - ) - defstream = self._settings.global_get( - ["webcam", "stream"] - ) - streamname = defstream.rsplit("/", 1).pop() - snapname = defsnap.rsplit("/", 1).pop() - if streamname in snapshot_url: - self._logger.debug( - str(streamname) - + " found so should be replaced by " - + str(snapname) - ) - snapshot_url = snapshot_url.replace( - streamname, snapname - ) - - self._logger.debug( - "Snapshot URL: " + str(snapshot_url) - ) - if snapshot_url != self._settings.global_get( - ["webcam", "snapshot"] - ): - image_data2 = self.take_image(snapshot_url) + self._logger.debug("get_webcam_configurations : " + str(config)) + url = config.snapshotDisplay + self._logger.debug("cam conf URL : " + str(url)) + if image_data == None: + image_data = self.take_image(url,config) + else: + image_data2 = self.take_image(url,config) if str(image_data2) != "": self._logger.debug( - "Image for " + str(li.get("name")) + "Image for " + str(config.name) ) files = { "photo": ("image.jpg", image_data2) @@ -2044,28 +2030,152 @@ def _send_msg( ) else: self._logger.debug( - "no image " + str(li.get("name")) + "no image " + str(config.name) ) - else: - self._logger.debug( - "url is the same as the one from octoprint " - ) - except Exception as ex: self._logger.exception( - "Exception loop multicam URL to create image: " + "Exception loop webcam configuration to create gif: " + str(ex) ) - except Exception as ex: - self._logger.exception( - "Exception occured on getting multicam options: " - + str(ex) - ) - except Exception as ex: - self._logger.exception( - "Exception occured on getting multicam plugin: " + str(ex) + else: + try: + image_data = self.take_image( + self._settings.global_get(["webcam", "snapshot"]) ) + except Exception as ex: + self._logger.info( + "Caught an exception trying take image: " + str(ex) + ) + + try: + files = {} + sendOneInLoop = False + if self._plugin_manager.get_plugin( + "multicam", True + ) and self._settings.get(["multicam"]): + try: + curr = self._settings.global_get( + ["plugins", "multicam", "multicam_profiles"] + ) + self._logger.debug("multicam_profiles : " + str(curr)) + for li in curr: + try: + self._logger.debug("multicam profile: " + str(li)) + snapshot_url = li.get("snapshot") + self._logger.debug("multicam snapshot : " + str(snapshot_url)) + if(snapshot_url == "" or snapshot_url == "http://" or snapshot_url == "https://" or snapshot_url == None): + snapshot_url = li.get("URL") + self._logger.debug( + "multicam url : " + str(snapshot_url) + ) + + defsnap = self._settings.global_get( + ["webcam", "snapshot"] + ) + defstream = self._settings.global_get( + ["webcam", "stream"] + ) + streamname = defstream.rsplit("/", 1).pop() + snapname = defsnap.rsplit("/", 1).pop() + if streamname in snapshot_url: + self._logger.debug( + str(streamname) + + " found so should be replaced by " + + str(snapname) + ) + snapshot_url = snapshot_url.replace( + streamname, snapname + ) + + self._logger.debug( + "Snapshot URL: " + str(snapshot_url) + ) + if snapshot_url != self._settings.global_get( + ["webcam", "snapshot"] + ): + image_data2 = self.take_image(snapshot_url) + if str(image_data2) != "": + self._logger.debug( + "Image for " + str(li.get("name")) + ) + files = { + "photo": ("image.jpg", image_data2) + } + data2 = data + data2["caption"] = "" + r = requests.post( + self.bot_url + "/sendPhoto", + files=files, + data=data2, + proxies=self.getProxies(), + ) + else: + self._logger.debug( + "no image " + str(li.get("name")) + ) + else: + self._logger.debug( + "url is the same as the one from octoprint " + ) + + except Exception as ex: + self._logger.exception( + "Exception loop multicam URL to create image: " + + str(ex) + ) + except Exception as ex: + self._logger.exception( + "Exception occured on getting multicam options: " + + str(ex) + ) + except Exception as ex: + self._logger.exception( + "Exception occured on getting multicam plugin: " + str(ex) + ) + + try: + printable_image_data = None + if image_data != None: # giloser check before using + if is_in_python_2(): + printable_image_data = image_data.decode( + "utf8", errors="ignore" + ) + else: + printable_image_data = str(image_data) + # self._logger.debug("image data so far: {}".format(printable_image_data)) + except Exception as ex: + self._logger.info( + "Caught an exception trying to create printable_image_data: " + + str(ex) + ) + + try: + if ( + not image_data + or image_data == None + or "html" in printable_image_data + ): + image_data = None + message = "[ERR GET IMAGE]\n\n " + "".join( + message + ) # .decode('utf-8', errors='ignore')) + except Exception as ex: + self._logger.info( + "Caught an exception trying to add info that we don't have image: " + + str(ex) + ) + + try: + self._logger.debug( + "message so far: {}".format(message) + ) # .decode('utf-8', errors='ignore'))) + except Exception as ex: + self._logger.info( + "Caught an exception trying to debug message so far: " + + str(ex) + ) + r = None try: @@ -2573,9 +2683,12 @@ def getUpdateMsgId(self, id): del self.updateMessageID[id] return uMsgID - def take_image(self, snapshot_url=""): + def take_image(self, snapshot_url="",cam_conf=0): if snapshot_url == "": - snapshot_url = self._settings.global_get(["webcam", "snapshot"]) + if cam_conf == 0: + snapshot_url = self._settings.global_get(["webcam", "snapshot"]) + else: + snapshot_url = cam_conf.snapshot self._logger.debug("Snapshot URL: " + str(snapshot_url)) data = None @@ -2586,9 +2699,16 @@ def take_image(self, snapshot_url=""): except Exception as e: self._logger.exception("TimeOut Exception: " + str(e)) return None - flipH = self._settings.global_get(["webcam", "flipH"]) - flipV = self._settings.global_get(["webcam", "flipV"]) - rotate = self._settings.global_get(["webcam", "rotate90"]) + + if cam_conf == 0: + flipH = self._settings.global_get(["webcam", "flipH"]) + flipV = self._settings.global_get(["webcam", "flipV"]) + rotate = self._settings.global_get(["webcam", "rotate90"]) + else: + flipH = cam_conf.flipH + flipV = cam_conf.flipV + rotate = cam_conf.rotate90 + self._logger.debug ( "Image transformations [H:%s, V:%s, R:%s]", flipH, flipV, rotate ) @@ -2684,12 +2804,15 @@ def calculate_ETA(self, printTime=0): return strtime + strdate - def create_gif_new(self, chatID, sec=7, multicam_prof=0): + def create_gif_new(self, chatID, sec=7, multicam_prof=0,cam_conf=0): ret = "" stream_url = 0 if multicam_prof != 0: stream_url = multicam_prof.get("URL") + if cam_conf != 0: + stream_url = cam_conf.snapshot + try: try: requests.get( @@ -2709,7 +2832,14 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0): outPath = ( self.get_plugin_data_folder() + "/tmpgif/gif_" - + multicam_prof.get("name").replace(" ", "_") + + multicam_prof.get("name").replace(" ", "_").replace("/","_") + + ".mp4" + ) + elif cam_conf != 0: + outPath = ( + self.get_plugin_data_folder() + + "/tmpgif/gif_" + + cam_conf.name.replace(" ", "_").replace("/","_") + ".mp4" ) else: @@ -2845,6 +2975,10 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0): flipH = multicam_prof.get("flipH") flipV = multicam_prof.get("flipV") rotate = multicam_prof.get("rotate90") + elif cam_conf != 0: + flipH = cam_conf.flipH + flipV = cam_conf.flipV + rotate = cam_conf.rotate90 else: flipH = self._settings.global_get(["webcam", "flipH"]) flipV = self._settings.global_get(["webcam", "flipV"]) From 0526ffe5b46bb8404e872357334c9065c95ae852 Mon Sep 17 00:00:00 2001 From: gwe Date: Fri, 31 May 2024 08:50:40 +0200 Subject: [PATCH 5/9] add function to send request for message and photo to manager error message when send photo and send message without image if with image it doesn't add trace of image to be send to try to understand why in some case the image is not send fix error in command again --- octoprint_telegram/__init__.py | 114 +++++++++++++------------ octoprint_telegram/telegramCommands.py | 2 +- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 4cd4142..7c05fa6 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -2011,23 +2011,20 @@ def _send_msg( self._logger.debug("cam conf URL : " + str(url)) if image_data == None: image_data = self.take_image(url,config) + self._logger.debug ("take_image return data : %s",image_data) else: image_data2 = self.take_image(url,config) + self._logger.debug ("take_image return data : %s",image_data2) if str(image_data2) != "": self._logger.debug( "Image for " + str(config.name) ) files = { - "photo": ("image.jpg", image_data2) + "photo": ("image.jpg", image_data2, 'image/jpeg') } data2 = data data2["caption"] = "" - r = requests.post( - self.bot_url + "/sendPhoto", - files=files, - data=data2, - proxies=self.getProxies(), - ) + r = self.send_request(self.bot_url,"/sendPhoto",files,data2,self.getProxies()) else: self._logger.debug( "no image " + str(config.name) @@ -2100,16 +2097,11 @@ def _send_msg( "Image for " + str(li.get("name")) ) files = { - "photo": ("image.jpg", image_data2) + "photo": ("image.jpg", image_data2 ,'image/jpeg') } data2 = data data2["caption"] = "" - r = requests.post( - self.bot_url + "/sendPhoto", - files=files, - data=data2, - proxies=self.getProxies(), - ) + r = self.send_request(self.bot_url,"/sendPhoto",files,data2,self.getProxies()) else: self._logger.debug( "no image " + str(li.get("name")) @@ -2218,66 +2210,41 @@ def _send_msg( "Sending with image.. and thumbnail so image first " + str(chatID) ) - files = {"photo": ("image.jpg", image_data)} + files = {"photo": ("image.jpg", image_data, 'image/jpeg')} data["caption"] = "" - r = requests.post( - self.bot_url + "/sendPhoto", - files=files, - data=data, - proxies=self.getProxies(), - ) - self._logger.debug("Sending image finished. " + str(r.status_code)) + r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) + + self._logger.debug("Sending finished. " + str(r.status_code)) self._logger.debug("Sending thumbnail.. " + str(chatID)) - files = {"photo": ("image.jpg", thumbnail_data)} + files = {"photo": ("image.jpg", thumbnail_data ,'image/jpeg')} if message is not "": data["caption"] = message - r = requests.post( - self.bot_url + "/sendPhoto", - files=files, - data=data, - proxies=self.getProxies(), - ) + r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) self._logger.debug("Sending finished. " + str(r.status_code)) elif image_data: self._logger.debug("Sending with image.. " + str(chatID)) - files = {"photo": ("image.jpg", image_data)} + files = {"photo": ("image.jpg", image_data ,'image/jpeg')} # self._logger.debug("files so far: " + str(files)) if message is not "": data["caption"] = message - r = requests.post( - self.bot_url + "/sendPhoto", - files=files, - data=data, - proxies=self.getProxies(), - ) - + r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) self._logger.debug("Sending finished. " + str(r.status_code)) elif thumbnail_data != None: self._logger.debug("Sending with thumbnail.. " + str(chatID)) - files = {"photo": ("image.jpg", thumbnail_data)} + files = {"photo": ("image.jpg", thumbnail_data, 'image/jpeg')} if message is not "": data["caption"] = message - r = requests.post( - self.bot_url + "/sendPhoto", - files=files, - data=data, - proxies=self.getProxies(), - ) - + r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) self._logger.debug("Sending finished. " + str(r.status_code)) else: self._logger.debug("Sending without image.. " + str(chatID)) data["text"] = message - r = requests.post( - self.bot_url + "/sendMessage", - data=data, - proxies=self.getProxies(), - ) + r = self.send_request(self.bot_url,"/sendMessage",None,data,self.getProxies()) self._logger.debug("Sending finished. " + str(r.status_code)) if r is not None and inline: @@ -2323,6 +2290,32 @@ def _send_msg( except Exception as ex: self._logger.exception("Exception PostImgMethod: " + str(ex)) + def send_request(self,url,urlfct,files,data,proxies): + if files != None: + r = requests.post( + url + urlfct, + files=files, + data=data, + proxies=proxies, + ) + self._logger.debug("Sending image finished. " + str(r.status_code)) + if r.status_code >= 300: + self._logger.error("Message with image not send because => " + str(r.reason)) + self._logger.debug("full response => " + str(r.text)) + message = "[ERR SEND IMAGE]\n\n " + "".join( + message + ) + data["text"] = message + r = self.send_request(url,"/sendMessage",None,data,proxies) + else: + r = requests.post( + url + urlfct, + data=data, + proxies=proxies, + ) + self._logger.debug("Sending message finished. " + str(r.status_code)) + return r + def humanbytes(self, B): "Return the given bytes as a human friendly KB, MB, GB, or TB string" B = float(B) @@ -2396,12 +2389,9 @@ def send_video(self, chatID, video_file, message): return files = {"video": open(video_file, "rb")} - r = requests.post( - self.bot_url + "/sendVideo", - files=files, - data={"chat_id": chatID, "caption": message}, - proxies=self.getProxies(), - ) + data={"chat_id": chatID, "caption": message} + + r = self.send_request(self.bot_url,"/sendVideo",files,data,self.getProxies()) self._logger.debug( "Sending finished. " + str(r.status_code) + " " + str(r.content) ) @@ -2714,6 +2704,7 @@ def take_image(self, snapshot_url="",cam_conf=0): ) image = Image.open(bytes_reader_class(data)) if data == None: + self._logger.debug ("data is None so return None") return None if flipH or flipV or rotate: @@ -2731,8 +2722,19 @@ def take_image(self, snapshot_url="",cam_conf=0): data = output.getvalue() output.close() + self._logger.debug ("take_image return data : %s",str(data)) + encoded_image = self.encode_image_to_base64(image) + self._logger.debug ("take_image return image as base64 : %s",str(encoded_image)) return data + def encode_image_to_base64(self, image): + """ + Encodes a PIL Image object to a base64 string for easy embedding or storage. + """ + buffered = bytes_reader_class() + image.save(buffered, format="JPEG") + return "data:image/jpeg;base64," + base64.b64encode(buffered.getvalue()).decode('utf-8') + def get_current_layers(self): layers = None try: diff --git a/octoprint_telegram/telegramCommands.py b/octoprint_telegram/telegramCommands.py index d9c7d1b..8751287 100644 --- a/octoprint_telegram/telegramCommands.py +++ b/octoprint_telegram/telegramCommands.py @@ -782,7 +782,7 @@ def cmdUpload(self, chat_id, from_id, cmd, parameter, user = ""): ) ############################################################################################ - def cmdAgain(self,chat_id,from_id,cmd,parameter): + def cmdAgain(self,chat_id,from_id,cmd,parameter, user=""): try: data = self.main._printer.get_current_data() if self.main._printer.is_printing(): From 5290d43373aef242582e798a9d8a6d83d87d14cf Mon Sep 17 00:00:00 2001 From: gwe Date: Sat, 15 Jun 2024 16:58:22 +0200 Subject: [PATCH 6/9] try fix webcam problem for some users --- octoprint_telegram/__init__.py | 45 +++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 7c05fa6..22c77f3 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -2010,10 +2010,10 @@ def _send_msg( url = config.snapshotDisplay self._logger.debug("cam conf URL : " + str(url)) if image_data == None: - image_data = self.take_image(url,config) + image_data = self.take_image(url,config,camera) self._logger.debug ("take_image return data : %s",image_data) else: - image_data2 = self.take_image(url,config) + image_data2 = self.take_image(url,config,camera) self._logger.debug ("take_image return data : %s",image_data2) if str(image_data2) != "": self._logger.debug( @@ -2302,6 +2302,11 @@ def send_request(self,url,urlfct,files,data,proxies): if r.status_code >= 300: self._logger.error("Message with image not send because => " + str(r.reason)) self._logger.debug("full response => " + str(r.text)) + message = "" + if data["caption"] != "": + message = data["caption"] + elif data["text"] != "": + message = data["text"] message = "[ERR SEND IMAGE]\n\n " + "".join( message ) @@ -2673,23 +2678,37 @@ def getUpdateMsgId(self, id): del self.updateMessageID[id] return uMsgID - def take_image(self, snapshot_url="",cam_conf=0): + def take_image(self, snapshot_url="",cam_conf=0,camera = None): + snapshot = None if snapshot_url == "": if cam_conf == 0: snapshot_url = self._settings.global_get(["webcam", "snapshot"]) else: snapshot_url = cam_conf.snapshot - - self._logger.debug("Snapshot URL: " + str(snapshot_url)) - data = None - if snapshot_url: + + + if cam_conf != 0 and camera != None: try: - r = requests.get(snapshot_url, timeout=10, proxies=self.getProxies()) - data = r.content + self._logger.debug("will try to get the snapshot from the plugin for " + str(cam_conf.name)) + snapshot = camera.take_webcam_snapshot(cam_conf.name) except Exception as e: - self._logger.exception("TimeOut Exception: " + str(e)) - return None - + self._logger.exception("Exception get snaposhot from octoprint: " + str(e)) + snapshot = None + + if snapshot != None: + self._logger.debug("set the snapshot to data to try to continue") + data = snapshot + else: + self._logger.debug("Snapshot URL: " + str(snapshot_url)) + data = None + if snapshot_url: + try: + r = requests.get(snapshot_url, timeout=10, proxies=self.getProxies()) + data = r.content + except Exception as e: + self._logger.exception("TimeOut Exception: " + str(e)) + return None + if cam_conf == 0: flipH = self._settings.global_get(["webcam", "flipH"]) flipV = self._settings.global_get(["webcam", "flipV"]) @@ -2702,6 +2721,8 @@ def take_image(self, snapshot_url="",cam_conf=0): self._logger.debug ( "Image transformations [H:%s, V:%s, R:%s]", flipH, flipV, rotate ) + + image = Image.open(bytes_reader_class(data)) if data == None: self._logger.debug ("data is None so return None") From 5cb60f52ea2bc78005863ee905f3a15c93122653 Mon Sep 17 00:00:00 2001 From: gwe Date: Tue, 24 Dec 2024 13:56:08 +0100 Subject: [PATCH 7/9] try fix problem with webcam for some users --- octoprint_telegram/__init__.py | 77 ++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 22c77f3..3aa4203 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -4,7 +4,7 @@ import threading, requests, urllib3, re, time, datetime, io, json, random, logging, traceback, io, collections, os, flask, base64, PIL, pkg_resources, subprocess, zipfile, glob, sys, multiprocessing import octoprint.plugin, octoprint.util, octoprint.filemanager from octoprint.schema.webcam import RatioEnum, Webcam, WebcamCompatibility -from octoprint.webcams import WebcamNotAbleToTakeSnapshotException +from octoprint.webcams import WebcamNotAbleToTakeSnapshotException, get_snapshot_webcam from flask_babel import gettext from flask_login import current_user from .telegramCommands import TCMD # telegramCommands. @@ -14,7 +14,7 @@ ) # dict of known notification messages from .emojiDict import telegramEmojiDict # dict of known emojis from babel.dates import format_date, format_datetime, format_time - +from io import BytesIO bytes_reader_class = io.BytesIO @@ -46,6 +46,7 @@ def __init__(self, main): self.username = "UNKNOWN" self._logger = main._logger.getChild("listener") self.gEmo = self.main.gEmo + self._capture_mutex = threading.Lock() def run(self): self._logger.debug("Try first connect.") @@ -1745,10 +1746,12 @@ def _send_edit_msg( self._logger.debug("Caught an exception in _send_edit_msg(): " + str(ex)) def take_webcam_snapshot(self, provided_webcam): + self._logger.debug("###########my take_webcam_snapshot ") + webcam = provided_webcam.config if webcam is None: - self._logger.exception("Exception WebcamNotAbleToTakeSnapshotException(provided_webcam is None)") + self._logger.error("Exception WebcamNotAbleToTakeSnapshotException(provided_webcam is None)") return None # using compat.snapshot because snapshotDisplay is supposedly only for user @@ -1756,7 +1759,7 @@ def take_webcam_snapshot(self, provided_webcam): can_snapshot = snapshot_url is not None and snapshot_url != "http://" and snapshot_url != "" if not can_snapshot: - self._logger.exception("Exception WebcamNotAbleToTakeSnapshotException("+webcam.name+")") + self._logger.error("Exception WebcamNotAbleToTakeSnapshotException("+webcam.name+")") return None with self._capture_mutex: @@ -2678,23 +2681,63 @@ def getUpdateMsgId(self, id): del self.updateMessageID[id] return uMsgID - def take_image(self, snapshot_url="",cam_conf=0,camera = None): + def take_image(self, snapshot_url="",cam_conf= None,camera = None): + MAX_JPEG_SIZE = 5000000 snapshot = None if snapshot_url == "": - if cam_conf == 0: + if cam_conf == None: snapshot_url = self._settings.global_get(["webcam", "snapshot"]) else: snapshot_url = cam_conf.snapshot - if cam_conf != 0 and camera != None: + if cam_conf != None and camera != None: try: self._logger.debug("will try to get the snapshot from the plugin for " + str(cam_conf.name)) - snapshot = camera.take_webcam_snapshot(cam_conf.name) + #snapshot = camera.take_webcam_snapshot(cam_conf) + snapshot = camera.take_webcam_snapshot(camera) + except Exception as e: self._logger.exception("Exception get snaposhot from octoprint: " + str(e)) snapshot = None + if snapshot == None: + try: + can_snapshot = snapshot_url is not None and snapshot_url != "http://" and snapshot_url != "" + + if not can_snapshot: + raise WebcamNotAbleToTakeSnapshotException(cam_conf.name) + + #with self._capture_mutex: + self._logger.debug(f"Capturing image from {snapshot_url}") + r = requests.get( + snapshot_url, + stream=True, + timeout=15, + verify=False, + ) + r.raise_for_status() + snap = b'' + #snap = r.iter_content(chunk_size=1024) + for chunk in r.iter_content(chunk_size=1024): + snap += chunk + if len(snap) > MAX_JPEG_SIZE: + r.close() + raise Exception('Payload returned from the snapshot_url is too large. Did you configure stream_url as snapshot_url?') + + r.close() + snapshot = bytes().join(snap) + self._logger.debug("Got snapshot of {} bytes".format(len(snapshot))) + #snapshot = BytesIO(image) + #output = bytes_reader_class() + #image.save(output, format="JPEG") + #snapshot = output.getvalue() + #output.close() + except Exception as e: + self._logger.exception("Exception get snaposhot from octoprint: " + str(e)) + snapshot = None + + if snapshot != None: self._logger.debug("set the snapshot to data to try to continue") data = snapshot @@ -2827,13 +2870,13 @@ def calculate_ETA(self, printTime=0): return strtime + strdate - def create_gif_new(self, chatID, sec=7, multicam_prof=0,cam_conf=0): + def create_gif_new(self, chatID, sec=7, multicam_prof=None,cam_conf=None): ret = "" - stream_url = 0 - if multicam_prof != 0: + stream_url = None + if multicam_prof != None: stream_url = multicam_prof.get("URL") - if cam_conf != 0: + if cam_conf != None: stream_url = cam_conf.snapshot try: @@ -2851,14 +2894,14 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0,cam_conf=0): # saveDir = os.getcwd() # os.chdir(self.get_plugin_data_folder()+"/tmpgif") - if multicam_prof != 0: + if multicam_prof != None: outPath = ( self.get_plugin_data_folder() + "/tmpgif/gif_" + multicam_prof.get("name").replace(" ", "_").replace("/","_") + ".mp4" ) - elif cam_conf != 0: + elif cam_conf != None: outPath = ( self.get_plugin_data_folder() + "/tmpgif/gif_" @@ -2892,7 +2935,7 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0,cam_conf=0): + " Problem creating gif, please check log file, and make sure you have installed cpulimit with following command : `sudo apt-get install cpulimit`", chatID=chatID, ) - return "" + return "" self._logger.info("test if ffmpeg exist") if self.TestProgram(["ffmpeg", "-h"]) <= 0: @@ -2919,7 +2962,7 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0,cam_conf=0): ) # os.nice(20) # force this to use less CPU - if stream_url == 0: + if stream_url == None: stream_url = self._settings.global_get(["webcam", "stream"]) if "http" not in stream_url: stream_url = "http://localhost" + stream_url @@ -2994,7 +3037,7 @@ def create_gif_new(self, chatID, sec=7, multicam_prof=0,cam_conf=0): # params.append( '-movflags') # params.append( 'faststart') - if multicam_prof != 0: + if multicam_prof != None: flipH = multicam_prof.get("flipH") flipV = multicam_prof.get("flipV") rotate = multicam_prof.get("rotate90") From 78b8339327209b52e26940cd24538eb771c77b91 Mon Sep 17 00:00:00 2001 From: gwe Date: Fri, 3 Jan 2025 12:43:42 +0100 Subject: [PATCH 8/9] fix some warning fix the way to work with new camera config and multicam --- octoprint_telegram/__init__.py | 109 +++++++++++++++---------- octoprint_telegram/telegramCommands.py | 9 +- 2 files changed, 71 insertions(+), 47 deletions(-) diff --git a/octoprint_telegram/__init__.py b/octoprint_telegram/__init__.py index 3aa4203..eda9faa 100644 --- a/octoprint_telegram/__init__.py +++ b/octoprint_telegram/__init__.py @@ -4,7 +4,7 @@ import threading, requests, urllib3, re, time, datetime, io, json, random, logging, traceback, io, collections, os, flask, base64, PIL, pkg_resources, subprocess, zipfile, glob, sys, multiprocessing import octoprint.plugin, octoprint.util, octoprint.filemanager from octoprint.schema.webcam import RatioEnum, Webcam, WebcamCompatibility -from octoprint.webcams import WebcamNotAbleToTakeSnapshotException, get_snapshot_webcam +from octoprint.webcams import WebcamNotAbleToTakeSnapshotException, get_snapshot_webcam, get_webcams from flask_babel import gettext from flask_login import current_user from .telegramCommands import TCMD # telegramCommands. @@ -905,17 +905,28 @@ def __init__(self, version): } self.emojis.update(telegramEmojiDict) self.cameras = [] + self.plugincamera = None self.snap_new_method = False + self.tcmd = TCMD(self) def initialize_cameras(self): self._logger.info("Initialize the camera") + self._logger.debug("Initialize the camera") if hasattr(octoprint.plugin.types, "WebcamProviderPlugin"): - self.cameras = self._plugin_manager.get_implementations(octoprint.plugin.types.WebcamProviderPlugin) - self.snap_new_method = True + plugin_manager = self._plugin_manager.get_implementations(octoprint.plugin.types.WebcamProviderPlugin) + + for plugin in plugin_manager: + self._logger.debug("webCam plugin name " +str(plugin)) + self.cameras = get_webcams() + self._logger.debug("cameras " +str(self.cameras)) + self.plugincamera = plugin + self.snap_new_method = True else: self.cameras = [] self.snap_new_method = False + self._logger.debug("self.snap_new_method : " + str(self.snap_new_method)) + # all emojis will be get via this method to disable them globaly by the corrosponding setting # so if you want to use emojis anywhere use gEmo("...") istead of emojis["..."] @@ -987,7 +998,7 @@ def get_template_configs(self): ########## def is_wizard_required(self): - return self._settings.get(["token"]) is "" + return self._settings.get(["token"]) == "" def get_wizard_version(self): return 1 @@ -1004,7 +1015,8 @@ def on_after_startup(self): self.set_log_level() self._logger.addFilter(TelegramPluginLoggingFilter()) self.initialize_cameras() - self.tcmd = TCMD(self) + self.tcmd.on_after_startup(self) + #self.tcmd = TCMD(self) self.triggered = False self.tmsg = TMSG( self @@ -1038,7 +1050,7 @@ def on_after_startup(self): # Update user profile photos for key in self.chats: try: - if key is not "zBOTTOMOFCHATS": + if key != "zBOTTOMOFCHATS": kwargs = {} kwargs["chat_id"] = int(key) t = threading.Thread(target=self.get_usrPic, kwargs=kwargs) @@ -1676,7 +1688,7 @@ def send_msg(self, message, **kwargs): # This is a 'editMessageText' message elif ( "msg_id" in kwargs - and kwargs["msg_id"] is not "" + and kwargs["msg_id"] != "" and kwargs["msg_id"] is not None ): threading.Thread(target=self._send_edit_msg, kwargs=kwargs).run() @@ -1900,7 +1912,8 @@ def _send_msg( if self.snap_new_method: for camera in self.cameras: - configs = camera.get_webcam_configurations() + configs = camera.config + #configs = camera.get_webcam_configurations() for config in configs: try: self._logger.debug("get_webcam_configurations : " + str(config)) @@ -2004,40 +2017,48 @@ def _send_msg( self._logger.debug("data so far: " + str(data)) image_data = None if with_image: + self._logger.debug("self.snap_new_method : " + str(self.snap_new_method)) if self.snap_new_method: - for camera in self.cameras: - configs = camera.get_webcam_configurations() - for config in configs: - try: - self._logger.debug("get_webcam_configurations : " + str(config)) - url = config.snapshotDisplay - self._logger.debug("cam conf URL : " + str(url)) - if image_data == None: - image_data = self.take_image(url,config,camera) - self._logger.debug ("take_image return data : %s",image_data) + self._logger.debug("cameras " +str(self.cameras)) + #for camera in self.cameras: + for name, camera in self.cameras.items(): + self._logger.debug("camera : " + str(name)) + config = camera.config + #configs = camera.get_webcam_configurations() + + #for config in configs: + try: + + self._logger.debug("get_webcam_configurations : " + str(config)) + url = config.snapshotDisplay + self._logger.debug("cam conf URL : " + str(url)) + if image_data == None: + image_data = self.take_image(url,config,camera) + self._logger.debug ("take_image return data : %s",image_data) + else: + image_data2 = self.take_image(url,config,camera) + self._logger.debug ("take_image return data : %s",image_data2) + if str(image_data2) != "": + self._logger.debug( + "Image for " + str(config.name) + ) + files = { + "photo": ("image.jpg", image_data2, 'image/jpeg') + } + data2 = data + data2["caption"] = "" + r = self.send_request(self.bot_url,"/sendPhoto",files,data2,self.getProxies()) else: - image_data2 = self.take_image(url,config,camera) - self._logger.debug ("take_image return data : %s",image_data2) - if str(image_data2) != "": - self._logger.debug( - "Image for " + str(config.name) - ) - files = { - "photo": ("image.jpg", image_data2, 'image/jpeg') - } - data2 = data - data2["caption"] = "" - r = self.send_request(self.bot_url,"/sendPhoto",files,data2,self.getProxies()) - else: - self._logger.debug( - "no image " + str(config.name) - ) - except Exception as ex: - self._logger.exception( - "Exception loop webcam configuration to create gif: " - + str(ex) - ) + self._logger.debug( + "no image " + str(config.name) + ) + except Exception as ex: + self._logger.exception( + "Exception loop webcam configuration to create gif: " + + str(ex) + ) else: + try: image_data = self.take_image( self._settings.global_get(["webcam", "snapshot"]) @@ -2221,7 +2242,7 @@ def _send_msg( self._logger.debug("Sending thumbnail.. " + str(chatID)) files = {"photo": ("image.jpg", thumbnail_data ,'image/jpeg')} - if message is not "": + if message != "": data["caption"] = message r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) self._logger.debug("Sending finished. " + str(r.status_code)) @@ -2229,7 +2250,7 @@ def _send_msg( self._logger.debug("Sending with image.. " + str(chatID)) files = {"photo": ("image.jpg", image_data ,'image/jpeg')} # self._logger.debug("files so far: " + str(files)) - if message is not "": + if message != "": data["caption"] = message r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) self._logger.debug("Sending finished. " + str(r.status_code)) @@ -2238,7 +2259,7 @@ def _send_msg( self._logger.debug("Sending with thumbnail.. " + str(chatID)) files = {"photo": ("image.jpg", thumbnail_data, 'image/jpeg')} - if message is not "": + if message != "": data["caption"] = message r = self.send_request(self.bot_url,"/sendPhoto",files,data,self.getProxies()) @@ -2654,7 +2675,7 @@ def set_log_level(self): def isCommandAllowed(self, chat_id, from_id, command): if "bind_none" in self.tcmd.commandDict[command]: return True - if command is not None or command is not "": + if command is not None or command != "": if self.chats[chat_id]["accept_commands"]: if self.chats[chat_id]["commands"][command]: return True @@ -2695,7 +2716,7 @@ def take_image(self, snapshot_url="",cam_conf= None,camera = None): try: self._logger.debug("will try to get the snapshot from the plugin for " + str(cam_conf.name)) #snapshot = camera.take_webcam_snapshot(cam_conf) - snapshot = camera.take_webcam_snapshot(camera) + snapshot = bytes().join(self.plugincamera.take_webcam_snapshot(camera)) except Exception as e: self._logger.exception("Exception get snaposhot from octoprint: " + str(e)) diff --git a/octoprint_telegram/telegramCommands.py b/octoprint_telegram/telegramCommands.py index 8751287..5c3ced0 100644 --- a/octoprint_telegram/telegramCommands.py +++ b/octoprint_telegram/telegramCommands.py @@ -20,8 +20,7 @@ class TCMD: def __init__(self, main): self.main = main - self.gEmo = self.main.gEmo - self._logger = main._logger.getChild("TCMD") + self.gEmo = self.main.gEmo self.SettingsTemp = [] self.tuneTemp = [100, 100] self.tempTemp = [] @@ -29,7 +28,7 @@ def __init__(self, main): self.dirHashDict = {} self.tmpFileHash = "" self._spoolManagerPluginImplementation = None - self.port = self.main._settings.global_get(["server", "port"]) + self.commandDict = { "Yes": {"cmd": self.cmdYes, "bind_none": True}, "No": {"cmd": self.cmdNo, "bind_none": True}, @@ -60,6 +59,10 @@ def __init__(self, main): "/gcode": {"cmd": self.cmdGCode, "param": True}, } + def on_after_startup(self,main): + self._logger = main._logger.getChild("TCMD") + self.port = self.main._settings.global_get(["server", "port"]) + ############################################################################################ # COMMAND HANDLERS ############################################################################################ From 5223ae4747fa7d46eb670201993322c0384b099c Mon Sep 17 00:00:00 2001 From: gwe Date: Fri, 3 Jan 2025 12:45:53 +0100 Subject: [PATCH 9/9] update version number --- README.md | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0c4913b..5a4cd7c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This plugin integrates Telegram Messenger with Octoprint. It sends messages (with photos if available) on print start, end and failure. Also it sends messages during the print at configurable intervals. That way you don't have to remember to regularly have a look at the printing process. Also, you can control Octoprint via messages (settings, start a print and much more). Send `/status` to get the current printer status or `/abort` to abort the current print. Send `/help` for a list of all recognized commands. You may also use this bot in groups. -**Latest release: [1.6.8](https://github.com/fabianonline/OctoPrint-Telegram/releases)** +**Latest release: [1.6.9](https://github.com/fabianonline/OctoPrint-Telegram/releases)** ## Contents diff --git a/setup.py b/setup.py index df95b5d..ff98e15 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ plugin_name = "OctoPrint-Telegram" # The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module -plugin_version = "1.6.8" +plugin_version = "1.6.9" # The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin # module