camera: add support for moonraker cameras, deprecates camera_url
this also adds support for flipping and rotation (configured in moonraker) close #976
This commit is contained in:
parent
77a24ec809
commit
8053e97d10
@ -173,7 +173,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", "camera_url",
|
||||
'extrude_distances', "extrude_speeds",
|
||||
)
|
||||
numbers = (
|
||||
'moonraker_port', 'move_speed_xy', 'move_speed_z',
|
||||
@ -199,6 +199,9 @@ class KlipperScreenConfig:
|
||||
for key in config[section]:
|
||||
if key not in bools and key not in strs and key not in numbers:
|
||||
msg = f'Option "{key}" not recognized for section "[{section}]"'
|
||||
if key == "camera_url":
|
||||
msg = "camera_url has been deprecated in favor of moonraker cameras"
|
||||
msg += "\n\n https://moonraker.readthedocs.io/en/latest/configuration/#webcam"
|
||||
if remove:
|
||||
# This should only be called for the auto-generated section
|
||||
self.config.remove_option(section, key)
|
||||
|
@ -147,7 +147,7 @@ enable: {{ printer.power_devices.count > 0 }}
|
||||
name: {{ gettext('Camera') }}
|
||||
icon: camera
|
||||
panel: camera
|
||||
enable: {{ camera_configured }}
|
||||
enable: {{ printer.cameras.count > 0 }}
|
||||
|
||||
[menu __main more console]
|
||||
name: {{ gettext('Console') }}
|
||||
|
@ -24,6 +24,7 @@ class Printer:
|
||||
self.busy_cb = busy_cb
|
||||
self.busy = False
|
||||
self.tempstore_size = 1200
|
||||
self.cameras = []
|
||||
|
||||
def reinit(self, printer_info, data):
|
||||
self.config = data['configfile']['config']
|
||||
@ -160,6 +161,10 @@ class Printer:
|
||||
}
|
||||
logging.debug(f"Power devices: {self.power_devices}")
|
||||
|
||||
def configure_cameras(self, data):
|
||||
self.cameras = data
|
||||
logging.debug(f"Cameras: {self.cameras}")
|
||||
|
||||
def get_config_section_list(self, search=""):
|
||||
if self.config is not None:
|
||||
return [i for i in list(self.config) if i.startswith(search)] if hasattr(self, "config") else []
|
||||
@ -228,6 +233,7 @@ class Printer:
|
||||
"idle_timeout": self.get_stat("idle_timeout").copy(),
|
||||
"pause_resume": {"is_paused": self.state == "paused"},
|
||||
"power_devices": {"count": len(self.get_power_devices())},
|
||||
"cameras": {"count": len(self.cameras)},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,35 +12,53 @@ class Panel(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)
|
||||
for i, cam in enumerate(self._printer.cameras):
|
||||
if not cam["enabled"]:
|
||||
continue
|
||||
logging.info(cam)
|
||||
cam[cam["name"]] = self._gtk.Button(
|
||||
image_name="camera", label=cam["name"], style=f"color{i % 4 + 1}",
|
||||
scale=self.bts, position=Gtk.PositionType.LEFT, lines=1
|
||||
)
|
||||
cam[cam["name"]].set_hexpand(True)
|
||||
cam[cam["name"]].set_vexpand(True)
|
||||
cam[cam["name"]].connect("clicked", self.play, cam)
|
||||
box.add(cam[cam["name"]])
|
||||
|
||||
self.scroll = self._gtk.ScrolledWindow()
|
||||
self.scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||
self.scroll.add(box)
|
||||
self.content.add(self.scroll)
|
||||
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}")
|
||||
|
||||
def activate(self):
|
||||
self.play()
|
||||
# if only 1 cam start playing fullscreen
|
||||
if len(self._printer.cameras) == 1:
|
||||
cam = next(iter(self._printer.cameras))
|
||||
if cam['enabled']:
|
||||
self.play(None, cam)
|
||||
|
||||
def deactivate(self):
|
||||
if self.mpv:
|
||||
self.mpv.terminate()
|
||||
self.mpv = None
|
||||
|
||||
def play(self, fs=None):
|
||||
def play(self, widget, cam):
|
||||
url = cam['stream_url']
|
||||
vf = ""
|
||||
if cam["flip_horizontal"]:
|
||||
vf += "hflip,"
|
||||
if cam["flip_vertical"]:
|
||||
vf += "vflip,"
|
||||
vf += f"rotate:{cam['rotation']*3.14159/180}"
|
||||
logging.info(f"video filters: {vf}")
|
||||
|
||||
if self.mpv:
|
||||
self.mpv.terminate()
|
||||
self.mpv = None
|
||||
# Create mpv after show or the 'window' property will be None
|
||||
self.mpv = mpv.MPV(log_handler=self.log, vo='gpu,wlshm,xv,x11')
|
||||
self.mpv = mpv.MPV(fullscreen=True, log_handler=self.log, vo='gpu,wlshm,xv,x11')
|
||||
|
||||
self.mpv.vf = vf
|
||||
|
||||
with suppress(Exception):
|
||||
self.mpv.profile = 'sw-fast'
|
||||
@ -51,22 +69,13 @@ class Panel(ScreenPanel):
|
||||
self.mpv.untimed = True
|
||||
self.mpv.audio = 'no'
|
||||
|
||||
# On wayland mpv cannot be embedded at least for now
|
||||
# https://github.com/mpv-player/mpv/issues/9654
|
||||
# if fs:
|
||||
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:
|
||||
|
||||
logging.debug(f"Camera URL: {url}")
|
||||
self.mpv.play(url)
|
||||
|
||||
try:
|
||||
self.mpv.wait_for_playback()
|
||||
except mpv.ShutdownError:
|
||||
@ -75,8 +84,10 @@ class Panel(ScreenPanel):
|
||||
logging.exception(e)
|
||||
self.mpv.terminate()
|
||||
self.mpv = None
|
||||
self._screen._menu_go_back()
|
||||
if len(self._printer.cameras) == 1:
|
||||
self._screen._menu_go_back()
|
||||
|
||||
@staticmethod
|
||||
def log(loglevel, component, message):
|
||||
def log(self, loglevel, component, message):
|
||||
logging.debug(f'[{loglevel}] {component}: {message}')
|
||||
if loglevel == 'error':
|
||||
self._screen.show_popup_message(f'{message}')
|
||||
|
@ -103,8 +103,6 @@ class Panel(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 and 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)
|
||||
|
13
screen.py
13
screen.py
@ -832,9 +832,16 @@ class KlipperScreen(Gtk.Window):
|
||||
# Moonraker is ready, set a loop to init the printer
|
||||
self.reinit_count += 1
|
||||
|
||||
powerdevs = self.apiclient.send_request("machine/device_power/devices")
|
||||
if powerdevs is not False:
|
||||
self.printer.configure_power_devices(powerdevs['result'])
|
||||
server_info = self.apiclient.get_server_info()["result"]
|
||||
logging.info(f"Moonraker info {server_info}")
|
||||
if "power" in server_info["components"]:
|
||||
powerdevs = self.apiclient.send_request("machine/device_power/devices")
|
||||
if powerdevs is not False:
|
||||
self.printer.configure_power_devices(powerdevs['result'])
|
||||
if "webcam" in server_info["components"]:
|
||||
cameras = self.apiclient.send_request("server/webcams/list")
|
||||
if cameras is not False:
|
||||
self.printer.configure_cameras(cameras['result']['webcams'])
|
||||
|
||||
if state['result']['klippy_connected'] is False:
|
||||
logging.info("Klipper not connected")
|
||||
|
Loading…
x
Reference in New Issue
Block a user