diff --git a/docs/Configuration.md b/docs/Configuration.md index a77e4c19..fbe5c567 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -90,6 +90,9 @@ screw_rotation: 0 # Define distances and speeds for the extrude panel. CSV list 2 to 4 integers extrude_distances: 5, 10, 15, 25 extrude_speeds: 1, 2, 5, 25 + +# Camera configuration +camera_url: http://127.0.0.1/webcam/?action=stream ``` ## Preheat Options diff --git a/ks_includes/config.py b/ks_includes/config.py index 0b193bac..4c9283fd 100644 --- a/ks_includes/config.py +++ b/ks_includes/config.py @@ -165,7 +165,7 @@ class KlipperScreenConfig: strs = ( 'moonraker_api_key', 'moonraker_host', 'titlebar_name_type', 'screw_positions', 'power_devices', 'titlebar_items', 'z_babystep_values', - 'extrude_distances', "extrude_speeds", + 'extrude_distances', "extrude_speeds", "camera_url", ) numbers = ( 'moonraker_port', 'move_speed_xy', 'move_speed_z', diff --git a/ks_includes/defaults.conf b/ks_includes/defaults.conf index b44512ad..b7483c2e 100644 --- a/ks_includes/defaults.conf +++ b/ks_includes/defaults.conf @@ -128,6 +128,12 @@ icon: motor-off method: printer.gcode.script params: {"script":"M18"} +[menu __main actions camera] +name: {{ gettext('Camera') }} +icon: camera +panel: camera +enable: {{ camera_configured }} + [menu __main actions console] name: {{ gettext('Console') }} icon: console @@ -231,6 +237,13 @@ icon: custom-script panel: gcode_macros enable: {{ printer.gcode_macros.count > 0 }} + +[menu __print camera] +name: {{ gettext('Camera') }} +icon: camera +panel: camera +enable: {{ camera_configured }} + [menu __print console] name: {{ gettext('Console') }} icon: console diff --git a/panels/camera.py b/panels/camera.py new file mode 100644 index 00000000..98bb5de4 --- /dev/null +++ b/panels/camera.py @@ -0,0 +1,85 @@ +import mpv +import logging +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, Gdk + +from ks_includes.screen_panel import ScreenPanel + + +def create_panel(*args): + return CameraPanel(*args) + + +class CameraPanel(ScreenPanel): + def __init__(self, screen, title): + super().__init__(screen, title) + self.mpv = None + self.da = Gtk.DrawingArea() + self.da.set_hexpand(True) + self.da.set_vexpand(True) + fs = self._gtk.Button("move", _("Fullscreen"), None, self.bts, Gtk.PositionType.LEFT, 1) + fs.connect("clicked", self.play) + fs.set_hexpand(True) + fs.set_vexpand(False) + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + box.add(self.da) + box.add(fs) + self.content.add(box) + self.content.show_all() + self.url = self.ks_printer_cfg.get("camera_url", "http://127.0.0.1/webcam/?action=stream").replace('"', '') + logging.debug(f"Camera URL: {self.url}") + # wayland has no primary monitor with that we can detect it + self.wayland = Gdk.Display.get_default().get_primary_monitor() is None + # gpu output driver doesn't work on a pi3 and the autoselected sdl doesn't size correctly + # consider adding a software switch to enable the gpu backend if set by the user + self.vo = 'x11' if self.wayland else 'wlshm' + + def activate(self): + self.play() + + def deactivate(self): + if self.mpv: + self.mpv.terminate() + self.mpv = None + + def play(self, fs=None): + # Create mpv after show or the 'window' property will be None + self.mpv = mpv.MPV( + log_handler=self.log, + vo=self.vo, + profile='sw-fast', + ) + # On wayland mpv cannot be embedded at least for now + # https://github.com/mpv-player/mpv/issues/9654 + if fs or self.wayland: + self.mpv.fullscreen = True + + @self.mpv.on_key_press('MBTN_LEFT' or 'MBTN_LEFT_DBL') + def clicked(): + self.mpv.quit(0) + else: + self.mpv.wid = f'{self.da.get_property("window").get_xid()}' + + @self.mpv.on_key_press('MBTN_LEFT' or 'MBTN_LEFT_DBL') + def clicked(): + self._screen.show_popup_message(self.url, level=1) + self.mpv.play(self.url) + if fs or self.wayland: + try: + self.mpv.wait_for_playback() + except mpv.ShutdownError: + logging.info('Exiting Fullscreen') + except Exception as e: + logging.exception(e) + self.mpv.terminate() + self.mpv = None + if self.wayland: + self._screen._menu_go_back() + else: + self.play() + + @staticmethod + def log(loglevel, component, message): + logging.debug(f'[{loglevel}] {component}: {message}') diff --git a/panels/menu.py b/panels/menu.py index 04794cac..9383e7e1 100644 --- a/panels/menu.py +++ b/panels/menu.py @@ -31,10 +31,6 @@ class MenuPanel(ScreenPanel): self.content.add(scroll) def activate(self): - self.j2_data = self._printer.get_printer_status_data() - self.j2_data.update({ - 'moonraker_connected': self._screen._ws.connected - }) if self._screen.vertical_mode: self.arrangeMenuItems(self.items, 3) else: @@ -99,7 +95,8 @@ class MenuPanel(ScreenPanel): if enable == "{{ moonraker_connected }}": logging.info(f"moonraker connected {self._screen._ws.connected}") return self._screen._ws.connected - + elif enable == "{{ camera_configured }}": + return self.ks_printer_cfg.get("camera_url", None) is not None self.j2_data = self._printer.get_printer_status_data() try: j2_temp = Template(enable, autoescape=True) diff --git a/scripts/KlipperScreen-install.sh b/scripts/KlipperScreen-install.sh index 41e8c480..01c62ddf 100755 --- a/scripts/KlipperScreen-install.sh +++ b/scripts/KlipperScreen-install.sh @@ -9,11 +9,11 @@ FBDEV="xserver-xorg-video-fbdev" PYTHON="python3-virtualenv virtualenv python3-distutils" PYGOBJECT="libgirepository1.0-dev gcc libcairo2-dev pkg-config python3-dev gir1.2-gtk-3.0" MISC="librsvg2-common libopenjp2-7 libatlas-base-dev wireless-tools libdbus-glib-1-dev autoconf" -OPTIONAL="xserver-xorg-legacy fonts-nanum fonts-ipafont" +OPTIONAL="xserver-xorg-legacy fonts-nanum fonts-ipafont, libmpv-dev" # moonraker will check this list when updating # if new packages are required for existing installs add them below too. -PKGLIST="libdbus-glib-1-dev autoconf fonts-ipafont" +PKGLIST="libdbus-glib-1-dev autoconf fonts-ipafont, libmpv-dev" Red='\033[0;31m' Green='\033[0;32m' diff --git a/scripts/KlipperScreen-requirements.txt b/scripts/KlipperScreen-requirements.txt index 1c134ec2..ee1840d7 100644 --- a/scripts/KlipperScreen-requirements.txt +++ b/scripts/KlipperScreen-requirements.txt @@ -4,4 +4,5 @@ requests==2.28.1 websocket-client==1.4.2 pycairo==1.22.0 PyGObject==3.42.2 -python-networkmanager==2.2 \ No newline at end of file +python-networkmanager==2.2 +python-mpv==0.5.2