Skip to content

Python API (autogenerated)

This page is populated via mkdocstrings.

New formatted uptime helpers

The plugin exposes a few convenience formatting functions in the public API usable by other plugins or scripts:

  • format_uptime(seconds: float) -> str - full human-readable form (e.g. "1d 2h 3m 4s").
  • format_uptime_dhm(seconds: float) -> str - days/hours/minutes (omits seconds).
  • format_uptime_d(seconds: float) -> str - whole days only (e.g. "3d").

Example usage from a Python context inside OctoPrint:

from octoprint_uptime.plugin import format_uptime_dhm

print(format_uptime_dhm(93784))  # -> "1d 2h 3m"

OctoPrint-Uptime plugin module.

Provides a small API endpoint that returns formatted system uptime. This module avoids importing OctoPrint/Flask at import-time so it can be packaged and unit-tested without the OctoPrint runtime present.

VERSION module-attribute

VERSION = '0.3.0'

UptimePlugin module-attribute

UptimePlugin = OctoprintUptimePlugin

__all__ module-attribute

__all__ = [
    "VERSION",
    "OctoprintUptimePlugin",
    "UptimePlugin",
    "format_uptime",
    "format_uptime_d",
    "format_uptime_dh",
    "format_uptime_dhm",
]

__plugin_name__ module-attribute

__plugin_name__ = 'OctoPrint-Uptime'

__plugin_version__ module-attribute

__plugin_version__ = VERSION

__plugin_description__ module-attribute

__plugin_description__ = "Adds system uptime to the navbar and exposes a small uptime API."

__plugin_author__ module-attribute

__plugin_author__ = 'Ajimaru'

__plugin_url__ module-attribute

__plugin_url__ = (
    "https://github.com/Ajimaru/OctoPrint-Uptime"
)

__plugin_license__ module-attribute

__plugin_license__ = 'AGPLv3'

__plugin_pythoncompat__ module-attribute

__plugin_pythoncompat__ = '>=3.8,<4'

__plugin_implementation__ module-attribute

__plugin_implementation__ = OctoprintUptimePlugin()

OctoprintUptimePlugin

OctoprintUptimePlugin(*args, **kwargs)

Bases: SimpleApiPluginBase, AssetPluginBase, SettingsPluginBase, TemplatePluginBase

OctoPrint plugin implementation. Uses lazy imports for OctoPrint/Flask integration points so the module can be imported in environments where OctoPrint is not installed.

Initialize the OctoPrint-Uptime plugin.

Sets up default internal state variables for debug settings, display format, and uptime tracking.

Parameters:

Name Type Description Default
*args object

Variable length argument list passed to parent class.

()
**kwargs object

Arbitrary keyword arguments passed to parent class.

{}
Source code in octoprint_uptime/plugin.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def __init__(self, *args: object, **kwargs: object) -> None:
    """Initialize the OctoPrint-Uptime plugin.

    Sets up default internal state variables for debug settings,
    display format, and uptime tracking.

    Args:
        *args: Variable length argument list passed to parent class.
        **kwargs: Arbitrary keyword arguments passed to parent class.
    """
    super().__init__(*args, **kwargs)
    self._debug_enabled: bool = False
    self._display_format: str = "full"
    self._last_debug_time: float = 0.0
    self._last_throttle_notice: float = 0.0
    self._debug_throttle_seconds: int = 60
    self._last_uptime_source: Optional[str] = None

get_update_information

get_update_information()

Return update information for the OctoPrint-Uptime plugin.

This method provides metadata required for OctoPrint's update mechanism.

Returns:

Name Type Description
dict Dict[str, Any]

Update information dictionary.

Source code in octoprint_uptime/plugin.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def get_update_information(self) -> Dict[str, Any]:
    """Return update information for the OctoPrint-Uptime plugin.

    This method provides metadata required for OctoPrint's update mechanism.

    Returns:
        dict: Update information dictionary.
    """

    info: Dict[str, Any] = {
        "octoprint_uptime": {
            "displayName": "OctoPrint-Uptime",
            "displayVersion": VERSION,
            "type": "github_release",
            "user": "Ajimaru",
            "repo": "OctoPrint-Uptime",
            "current": VERSION,
            "pip": "https://github.com/Ajimaru/OctoPrint-Uptime/archive/{target_version}.zip",
        }
    }
    return info

is_api_protected

is_api_protected()

Indicate whether the plugin's API endpoint requires authentication.

Returns:

Name Type Description
bool bool

True if API is protected, False otherwise.

Source code in octoprint_uptime/plugin.py
211
212
213
214
215
216
217
218
def is_api_protected(self) -> bool:
    """Indicate whether the plugin's API endpoint requires authentication.

    Returns:
        bool: True if API is protected, False otherwise.
    """
    result: bool = True
    return result

get_assets

get_assets()

Return plugin asset files for OctoPrint-Uptime.

Returns:

Type Description
Dict[str, List[str]]

Dict[str, List[str]]: Dictionary mapping asset types to file lists.

Source code in octoprint_uptime/plugin.py
220
221
222
223
224
225
226
def get_assets(self) -> Dict[str, List[str]]:
    """Return plugin asset files for OctoPrint-Uptime.

    Returns:
        Dict[str, List[str]]: Dictionary mapping asset types to file lists.
    """
    return {"js": ["js/uptime.js"]}

get_template_configs

get_template_configs()

Returns a list of template configuration dictionaries for the OctoPrint plugin.

The configurations specify templates for the navbar and settings sections, including their types, display names, template file names, and whether they use custom bindings.

Returns:

Type Description
List[Dict[str, Any]]

List[Dict[str, Any]]: A list of dictionaries containing template configuration details.

Source code in octoprint_uptime/plugin.py
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
def get_template_configs(self) -> List[Dict[str, Any]]:
    """
    Returns a list of template configuration dictionaries for the OctoPrint plugin.

    The configurations specify templates for the navbar and settings sections,
    including their types, display names, template file names,
    and whether they use custom bindings.

    Returns:
        List[Dict[str, Any]]: A list of dictionaries containing template configuration details.
    """
    return [
        {
            "type": "navbar",
            "name": _("navbar_uptime"),
            "template": "navbar.jinja2",
            "custom_bindings": True,
        },
        {
            "type": "settings",
            "name": _("OctoPrint Uptime"),
            "template": "settings.jinja2",
            "custom_bindings": False,
        },
    ]

is_template_autoescaped

is_template_autoescaped()

Determine if template autoescaping is enabled.

Returns:

Name Type Description
bool bool

True if autoescaping is enabled for templates, otherwise False.

Source code in octoprint_uptime/plugin.py
254
255
256
257
258
259
260
261
def is_template_autoescaped(self) -> bool:
    """
    Determine if template autoescaping is enabled.

    Returns:
        bool: True if autoescaping is enabled for templates, otherwise False.
    """
    return True

_get_uptime_seconds

_get_uptime_seconds()

Attempts to retrieve system uptime using several strategies.

Returns a tuple of (seconds|None, source) where source is one of "proc", "psutil" or "none".

Source code in octoprint_uptime/plugin.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def _get_uptime_seconds(self) -> Tuple[Optional[float], str]:
    """Attempts to retrieve system uptime using several strategies.

    Returns a tuple of (seconds|None, source) where source is one of
    "proc", "psutil" or "none".
    """
    uptime = self._get_uptime_from_proc()
    if uptime is not None:
        self._last_uptime_source = "proc"
        return uptime, "proc"

    uptime = self._get_uptime_from_psutil()
    if uptime is not None:
        self._last_uptime_source = "psutil"
        return uptime, "psutil"

    self._last_uptime_source = "none"
    return None, "none"

_get_uptime_from_proc

_get_uptime_from_proc()

Get uptime from /proc/uptime if available.

Source code in octoprint_uptime/plugin.py
282
283
284
285
286
287
288
289
290
291
def _get_uptime_from_proc(self) -> Optional[float]:
    """Get uptime from /proc/uptime if available."""
    try:
        if os.path.exists("/proc/uptime"):
            with open("/proc/uptime", encoding="utf-8") as f:
                uptime_seconds = float(f.readline().split()[0])
                return uptime_seconds
    except (ValueError, TypeError, OSError):
        pass
    return None

_get_uptime_from_psutil

_get_uptime_from_psutil()

Get uptime using psutil if available.

Source code in octoprint_uptime/plugin.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
def _get_uptime_from_psutil(self) -> Optional[float]:
    """Get uptime using psutil if available."""
    try:
        _ps = importlib.import_module("psutil")
    except ImportError:
        return None
    try:
        boot = _ps.boot_time()
        uptime = time.time() - boot
        if isinstance(uptime, (int, float)) and 0 <= uptime < 10 * 365 * 24 * 3600:
            return uptime
    except (AttributeError, TypeError, ValueError, OSError):
        return None
    return None

_get_octoprint_uptime

_get_octoprint_uptime()

Get OctoPrint process uptime using psutil if available.

Source code in octoprint_uptime/plugin.py
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
def _get_octoprint_uptime(self) -> Optional[float]:
    """Get OctoPrint process uptime using psutil if available."""
    try:
        _ps = importlib.import_module("psutil")
    except ImportError:
        return None
    psutil_base_error = getattr(_ps, "Error", Exception)
    try:
        # Get current process
        current_process = _ps.Process(os.getpid())
        # Get process creation time
        create_time = current_process.create_time()
        uptime = time.time() - create_time
        if isinstance(uptime, (int, float)) and 0 <= uptime < 10 * 365 * 24 * 3600:
            return uptime
    except (AttributeError, TypeError, ValueError, OSError, psutil_base_error):
        return None
    return None

on_settings_initialized

on_settings_initialized()

Called when OctoPrint has initialized plugin settings.

This updates the plugin's internal state from the settings store and calls a base implementation if provided by OctoPrint.

Source code in octoprint_uptime/plugin.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
def on_settings_initialized(self) -> None:
    """
    Called when OctoPrint has initialized plugin settings.

    This updates the plugin's internal state from the settings store and
    calls a base implementation if provided by OctoPrint.
    """

    self._safe_update_internal_state()

    hook = getattr(super(), "on_settings_initialized", None)
    if not callable(hook):
        hook = getattr(SettingsPluginBase, "on_settings_initialized", None)

    if callable(hook):
        self._invoke_settings_hook(hook)

on_settings_save

on_settings_save(data)

Save plugin settings, validate config values, and update internal state.

Parameters:

Name Type Description Default
data Dict[str, Any]

Settings data to save.

required
Source code in octoprint_uptime/plugin.py
344
345
346
347
348
349
350
351
352
353
354
355
def on_settings_save(self, data: Dict[str, Any]) -> None:
    """
    Save plugin settings, validate config values, and update internal state.

    Args:
        data (Dict[str, Any]): Settings data to save.
    """
    self._validate_and_sanitize_settings(data)
    self._log_settings_save_data(data)
    self._call_base_on_settings_save(data)
    self._update_internal_state()
    self._log_settings_after_save()

_safe_update_internal_state

_safe_update_internal_state()

Helper that updates internal state and logs expected failures.

Source code in octoprint_uptime/plugin.py
357
358
359
360
361
362
363
364
365
366
367
def _safe_update_internal_state(self) -> None:
    """Helper that updates internal state and logs expected failures."""
    logger = getattr(self, "_logger", None)
    try:
        self._update_internal_state()
    except (AttributeError, KeyError, ValueError) as e:
        if logger:
            logger.warning(
                "on_settings_initialized: failed to update internal state: %s",
                e,
            )

_get_hook_positional_param_count

_get_hook_positional_param_count(hook)

Return the number of positional params a callable accepts or None on error.

Uses inspect.signature and logs a warning on failure.

Source code in octoprint_uptime/plugin.py
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
def _get_hook_positional_param_count(self, hook: Any) -> Optional[int]:
    """Return the number of positional params a callable accepts or None on error.

    Uses `inspect.signature` and logs a warning on failure.
    """
    logger = getattr(self, "_logger", None)
    try:
        sig = inspect.signature(hook)
        params = [
            p
            for p in sig.parameters.values()
            if p.kind
            in (
                inspect.Parameter.POSITIONAL_ONLY,
                inspect.Parameter.POSITIONAL_OR_KEYWORD,
            )
        ]
        return len(params)
    except (ValueError, TypeError, AttributeError) as e:
        if logger:
            logger.info(
                "_get_hook_positional_param_count: unable to inspect signature for %r: %s",
                hook,
                e,
            )
        return None

_safe_invoke_hook

_safe_invoke_hook(hook, param_count)

Invoke a hook with either zero or one positional parameter and log failures.

param_count should be 0 or 1; any exception raised by the hook is logged but not propagated.

Source code in octoprint_uptime/plugin.py
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
def _safe_invoke_hook(self, hook: Any, param_count: int) -> None:
    """Invoke a hook with either zero or one positional parameter and log failures.

    `param_count` should be 0 or 1; any exception raised by the hook is logged
    but not propagated.
    """
    logger = getattr(self, "_logger", None)
    try:
        if param_count == 0:
            hook()
        else:
            hook(self)
    except (RuntimeError, AttributeError, TypeError, ValueError):
        if logger:
            logger.exception("_safe_invoke_hook: %r raised", hook)

_invoke_settings_hook

_invoke_settings_hook(hook)

Invoke a settings hook using signature inspection and log call errors.

Delegates signature inspection and the actual call to small helpers to reduce complexity and make failures easier to log/reason about.

Source code in octoprint_uptime/plugin.py
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
def _invoke_settings_hook(self, hook: Any) -> None:
    """Invoke a settings hook using signature inspection and log call errors.

    Delegates signature inspection and the actual call to small helpers to
    reduce complexity and make failures easier to log/reason about.
    """
    logger = getattr(self, "_logger", None)

    param_count = self._get_hook_positional_param_count(hook)
    if param_count is None:
        return
    if param_count not in (0, 1):
        if logger:
            logger.warning(
                "_invoke_settings_hook: unexpected parameter count %s for %r; skipping",
                param_count,
                hook,
            )
        return

    self._safe_invoke_hook(hook, param_count)

_validate_and_sanitize_settings

_validate_and_sanitize_settings(data)

Validate and sanitize plugin settings in the provided data dict.

Source code in octoprint_uptime/plugin.py
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
def _validate_and_sanitize_settings(self, data: Dict[str, Any]) -> None:
    """Validate and sanitize plugin settings in the provided data dict."""
    plugins = data.get("plugins") if isinstance(data, dict) else None
    if not isinstance(plugins, dict):
        return
    uptime_cfg = plugins.get("octoprint_uptime")
    if not isinstance(uptime_cfg, dict):
        return
    for key, default, lo, hi in (
        ("debug_throttle_seconds", 60, 1, 120),
        ("poll_interval_seconds", 5, 1, 120),
        ("compact_toggle_interval_seconds", 5, 5, 60),
    ):
        if key in uptime_cfg:
            raw = uptime_cfg.get(key)
            try:
                if raw is None:
                    raise ValueError()
                val = int(raw)
            except (ValueError, TypeError):
                val = default
            val = max(lo, min(val, hi))
            uptime_cfg[key] = val

_log_settings_save_data

_log_settings_save_data(data)

Logs the data passed to the settings save event for debugging purposes.

Parameters:

Name Type Description Default
data Dict[str, Any]

The data being saved to the settings.

required
Notes

If the logger is not available or an error occurs during logging, the exception is silently ignored.

Source code in octoprint_uptime/plugin.py
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
def _log_settings_save_data(self, data: Dict[str, Any]) -> None:
    """
    Logs the data passed to the settings save event for debugging purposes.

    Args:
        data (Dict[str, Any]): The data being saved to the settings.

    Notes:
        If the logger is not available or an error occurs during logging,
        the exception is silently ignored.
    """
    logger = getattr(self, "_logger", None)
    if logger:
        try:
            logger.debug("on_settings_save data: %r", data)
        except (AttributeError, TypeError, ValueError):
            pass

_call_base_on_settings_save

_call_base_on_settings_save(data)

Calls the base class's on_settings_save method with the provided data if it exists and is callable.

Parameters:

Name Type Description Default
data Dict[str, Any]

The settings data to be saved.

required
Notes
  • Silently ignores AttributeError, TypeError, and ValueError exceptions that may occur during the call.
  • This is typically used to ensure that any base class logic for saving settings is executed.
Source code in octoprint_uptime/plugin.py
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
def _call_base_on_settings_save(self, data: Dict[str, Any]) -> None:
    """
    Calls the base class's `on_settings_save` method with the provided data if it exists
    and is callable.

    Args:
        data (Dict[str, Any]): The settings data to be saved.

    Notes:
        - Silently ignores AttributeError, TypeError, and ValueError exceptions that may
          occur during the call.
        - This is typically used to ensure that any base class logic for saving settings
          is executed.
    """
    method = getattr(SettingsPluginBase, "on_settings_save", None)
    if callable(method):
        try:
            method(self, data)
        except (AttributeError, TypeError, ValueError):
            pass

get_settings_defaults

get_settings_defaults()

Return default settings for the plugin.

OctoPrint populates settings.plugins.<identifier> from this mapping so the frontend can safely bind to settings.plugins.octoprint_uptime.*.

Source code in octoprint_uptime/plugin.py
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
def get_settings_defaults(self) -> Dict[str, Any]:
    """Return default settings for the plugin.

    OctoPrint populates `settings.plugins.<identifier>` from this mapping so the
    frontend can safely bind to `settings.plugins.octoprint_uptime.*`.
    """
    return {
        "debug": False,
        "show_system_uptime": True,
        "show_octoprint_uptime": True,
        "compact_display": False,
        "compact_toggle_interval_seconds": 5,
        "display_format": "full",
        "debug_throttle_seconds": 60,
        "poll_interval_seconds": 5,
    }

_update_internal_state

_update_internal_state()

Updates the plugin's internal state variables based on the current settings.

This method retrieves the latest configuration values from the settings object and updates the following internal attributes: - _debug_enabled: Whether debug mode is enabled. - _display_format: The format string for displaying uptime. - _debug_throttle_seconds: The throttle interval (in seconds) for debug messages.

Returns:

Type Description
None

None

Source code in octoprint_uptime/plugin.py
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
def _update_internal_state(self) -> None:
    """
    Updates the plugin's internal state variables based on the current settings.

    This method retrieves the latest configuration values from the settings object and updates
    the following internal attributes:
    - _debug_enabled: Whether debug mode is enabled.
    - _display_format: The format string for displaying uptime.
    - _debug_throttle_seconds: The throttle interval (in seconds) for debug messages.

    Returns:
        None
    """
    self._debug_enabled = bool(self._settings.get(["debug"]))
    self._display_format = str(self._settings.get(["display_format"]))
    self._debug_throttle_seconds = int(self._settings.get(["debug_throttle_seconds"]) or 60)

_log_settings_after_save

_log_settings_after_save()

Logs the current plugin settings after they have been saved.

This method logs the values of debug mode, display format, and debug throttle seconds.

Returns:

Type Description
None

None

Source code in octoprint_uptime/plugin.py
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
def _log_settings_after_save(self) -> None:
    """
    Logs the current plugin settings after they have been saved.

    This method logs the values of debug mode, display format, and debug
    throttle seconds.

    Returns:
        None
    """
    logger = getattr(self, "_logger", None)
    if not logger:
        return
    try:
        msg = (
            "UptimePlugin: settings after save: debug=%s, "
            "display_format=%s, "
            "debug_throttle_seconds=%s"
        )
        logger.info(
            msg,
            self._debug_enabled,
            self._display_format,
            self._debug_throttle_seconds,
        )
    except (AttributeError, TypeError, ValueError):
        pass

_log_debug

_log_debug(message)

Logs a debug message if debugging is enabled and throttling conditions are met.

This method checks if debugging is enabled via the _debug_enabled attribute. If enabled, it ensures that debug messages are not logged more frequently than the interval specified by _debug_throttle_seconds. The timestamp of the last logged debug message is tracked using _last_debug_time. Any exceptions related to missing or invalid attributes, or logging errors, are silently ignored.

Parameters:

Name Type Description Default
message str

The debug message to log.

required

Returns:

Type Description
None

None

Source code in octoprint_uptime/plugin.py
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
def _log_debug(self, message: str) -> None:
    """
    Logs a debug message if debugging is enabled and throttling conditions are met.

    This method checks if debugging is enabled via the `_debug_enabled` attribute.
    If enabled, it ensures that debug messages are not logged more frequently than
    the interval specified by `_debug_throttle_seconds`. The timestamp of the last
    logged debug message is tracked using `_last_debug_time`. Any exceptions related
    to missing or invalid attributes, or logging errors, are silently ignored.

    Args:
        message (str): The debug message to log.

    Returns:
        None
    """
    try:
        if not getattr(self, "_debug_enabled", False):
            return
        now = time.time()
        last_time = getattr(self, "_last_debug_time", 0)
        if (now - last_time) < self._debug_throttle_seconds:
            return
        self._last_debug_time = now
        try:
            self._logger.debug(message)
        except (AttributeError, TypeError, ValueError):
            pass
    except (AttributeError, TypeError, ValueError):
        pass

_fallback_uptime_response

_fallback_uptime_response()

Return system uptime info as a JSON or dict response.

If Flask is available, returns a JSON response with uptime details and settings. Otherwise, returns a basic dictionary. On error, returns 'unknown' uptime.

Source code in octoprint_uptime/plugin.py
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
def _fallback_uptime_response(self) -> Any:
    """
    Return system uptime info as a JSON or dict response.

    If Flask is available, returns a JSON response with uptime details and settings.
    Otherwise, returns a basic dictionary. On error, returns 'unknown' uptime.
    """
    logger = getattr(self, "_logger", None)
    try:
        seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d = self._get_uptime_info()
        uptime_available = (
            isinstance(seconds, (int, float)) and seconds >= 0 and uptime_full != _("unknown")
        )
        if _flask is not None:
            display_format, poll_interval = self._get_api_settings()
            resp = {
                "uptime": uptime_full,
                "uptime_dhm": uptime_dhm,
                "uptime_dh": uptime_dh,
                "uptime_d": uptime_d,
                "seconds": seconds,
                "display_format": display_format,
                "poll_interval_seconds": poll_interval,
                "uptime_available": uptime_available,
            }
            if not uptime_available:
                resp["uptime_note"] = _("Uptime could not be determined on this system.")
            try:
                json_resp = _flask.jsonify(**resp)
            except (TypeError, ValueError, RuntimeError):
                if logger:
                    logger.exception(
                        "_build_flask_uptime_response: flask.jsonify failed, "
                        "falling back to dict"
                    )
                return resp
            else:
                return json_resp

        else:
            resp = {"uptime": uptime_full, "uptime_available": uptime_available}
            if not uptime_available:
                resp["uptime_note"] = _("Uptime could not be determined on this system.")
            return resp
    except (AttributeError, TypeError, ValueError):
        if logger:
            try:
                logger.exception(
                    "_fallback_uptime_response: unexpected error while building response"
                )
            except (AttributeError, TypeError, ValueError):
                pass
        return {"uptime": _("unknown"), "uptime_available": False}

on_api_get

on_api_get(_request=None)

Handle GET requests to the plugin's API endpoint.

Source code in octoprint_uptime/plugin.py
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
def on_api_get(self, _request: Any = None) -> Any:
    """
    Handle GET requests to the plugin's API endpoint.
    """
    permission_result = self._handle_permission_check()
    if permission_result is not None:
        return permission_result

    seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d = self._get_uptime_info()
    (
        octoprint_seconds,
        octoprint_uptime_full,
        octoprint_uptime_dhm,
        octoprint_uptime_dh,
        octoprint_uptime_d,
    ) = self._get_octoprint_uptime_info()
    self._log_debug(_("Uptime API requested, result=%s") % uptime_full)

    if _flask is not None:
        display_format, poll_interval = self._get_api_settings()
        return _flask.jsonify(
            uptime=uptime_full,
            uptime_dhm=uptime_dhm,
            uptime_dh=uptime_dh,
            uptime_d=uptime_d,
            seconds=seconds,
            octoprint_uptime=octoprint_uptime_full,
            octoprint_uptime_dhm=octoprint_uptime_dhm,
            octoprint_uptime_dh=octoprint_uptime_dh,
            octoprint_uptime_d=octoprint_uptime_d,
            octoprint_seconds=octoprint_seconds,
            display_format=display_format,
            poll_interval_seconds=poll_interval,
        )

    return {"uptime": uptime_full, "octoprint_uptime": octoprint_uptime_full}

_handle_permission_check

_handle_permission_check()

Handles permission checking and error handling for API GET requests.

Returns:

Type Description
Optional[Any]

The forbidden response or fallback response if permission is denied or an error occurs,

Optional[Any]

otherwise None if permission is granted.

Source code in octoprint_uptime/plugin.py
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
def _handle_permission_check(self) -> Optional[Any]:
    """
    Handles permission checking and error handling for API GET requests.

    Returns:
        The forbidden response or fallback response if permission is denied or an error occurs,
        otherwise None if permission is granted.
    """
    try:
        if not self._check_permissions():
            try:
                return self._abort_forbidden()
            except (AttributeError, TypeError, ValueError, RuntimeError, OSError):
                return {"error": _("Forbidden"), "uptime_available": False}
    except (AttributeError, TypeError, ValueError):
        if hasattr(self, "_logger") and self._logger is not None:
            self._logger.exception("on_api_get: unexpected error while checking permissions")
        try:
            return self._abort_forbidden()
        except (AttributeError, TypeError, ValueError, RuntimeError, OSError):
            return {"error": _("Forbidden"), "uptime_available": False}
    return None

_check_permissions

_check_permissions()

Checks if the current user has the necessary system permissions.

Returns:

Name Type Description
bool bool

True if the user has system permissions or if permissions are not enforced; otherwise, returns the result of the permission check. If an exception occurs during the check (AttributeError, TypeError, or ValueError), defaults to True.

Source code in octoprint_uptime/plugin.py
704
705
706
707
708
709
710
711
712
713
714
715
716
def _check_permissions(self) -> bool:
    """
    Checks if the current user has the necessary system permissions.

    Returns:
        bool: True if the user has system permissions or if permissions are not enforced;
              otherwise, returns the result of the permission check. If an exception occurs
              during the check (AttributeError, TypeError, or ValueError), defaults to True.
    """
    # Intentionally permissive placeholder: permission enforcement is not implemented
    # in this plugin. Always allow access for now; replace with real checks when
    # permission enforcement is required.
    return True

_abort_forbidden

_abort_forbidden()

Handles forbidden access attempts by aborting the request with a 403 status code if Flask is available, and returns a JSON error message indicating the action is forbidden.

Returns:

Name Type Description
dict Dict[str, str]

A dictionary containing an error message with the key "error" and value

Dict[str, str]

"Forbidden".

Source code in octoprint_uptime/plugin.py
718
719
720
721
722
723
724
725
726
727
728
729
730
def _abort_forbidden(self) -> Dict[str, str]:
    """
    Handles forbidden access attempts by aborting the request with a 403 status code if
    Flask is available, and returns a JSON error message indicating the action is
    forbidden.

    Returns:
        dict: A dictionary containing an error message with the key "error" and value
        "Forbidden".
    """
    if _flask is not None:
        _flask.abort(403)
    return {"error": _("Forbidden")}

_get_uptime_info

_get_uptime_info()

Retrieve uptime information and formatted strings.

Returns:

Name Type Description
Tuple Tuple[Optional[float], str, str, str, str]

(seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d)

Source code in octoprint_uptime/plugin.py
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
def _get_uptime_info(self) -> Tuple[Optional[float], str, str, str, str]:
    """
    Retrieve uptime information and formatted strings.

    Returns:
        Tuple: (seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d)
    """
    try:
        if hasattr(self, "get_uptime_seconds") and callable(self.get_uptime_seconds):
            res = self.get_uptime_seconds()
            if isinstance(res, tuple) and len(res) == 2:
                seconds, _source = res
                self._last_uptime_source = _source
            else:
                seconds = res
                self._last_uptime_source = "custom"
        else:
            seconds, _source = self._get_uptime_seconds()
        uptime_seconds: Optional[float] = (
            seconds if isinstance(seconds, (int, float, type(None))) else None
        )
        return self._format_uptime_tuple(uptime_seconds)
    except (AttributeError, TypeError, ValueError):
        try:
            self._logger.exception(_("Error computing uptime"))
        except (AttributeError, TypeError, ValueError):
            pass
        return self._format_uptime_tuple(None)

_format_uptime_tuple

_format_uptime_tuple(seconds)

Normalize and format an uptime value into display strings.

Source code in octoprint_uptime/plugin.py
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
def _format_uptime_tuple(
    self, seconds: Optional[float]
) -> Tuple[Optional[float], str, str, str, str]:
    """
    Normalize and format an uptime value into display strings.
    """
    if isinstance(seconds, (int, float)):
        seconds = float(seconds)
    else:
        seconds = None

    if seconds is not None:
        uptime_full = format_uptime(seconds)
        uptime_dhm = format_uptime_dhm(seconds)
        uptime_dh = format_uptime_dh(seconds)
        uptime_d = format_uptime_d(seconds)
    else:
        uptime_full = uptime_dhm = uptime_dh = uptime_d = _("unknown")
    return seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d

_get_octoprint_uptime_info

_get_octoprint_uptime_info()

Retrieve OctoPrint process uptime information and formatted strings.

Returns:

Name Type Description
Tuple Tuple[Optional[float], str, str, str, str]

(seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d)

Source code in octoprint_uptime/plugin.py
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
def _get_octoprint_uptime_info(self) -> Tuple[Optional[float], str, str, str, str]:
    """
    Retrieve OctoPrint process uptime information and formatted strings.

    Returns:
        Tuple: (seconds, uptime_full, uptime_dhm, uptime_dh, uptime_d)
    """
    try:
        seconds = self._get_octoprint_uptime()
        return self._format_uptime_tuple(seconds)
    except (AttributeError, TypeError, ValueError):
        try:
            self._logger.exception(_("Error computing OctoPrint uptime"))
        except (AttributeError, TypeError, ValueError):
            pass
        return self._format_uptime_tuple(None)

_get_api_settings

_get_api_settings()

Retrieves and returns the plugin's API settings with appropriate fallbacks.

Attempts to fetch the following settings from the plugin's configuration: - display_format (str): The format to display uptime. Defaults to "full" if not set or invalid. - poll_interval (int): The polling interval in seconds. Defaults to 5 if not set or invalid.

Returns:

Name Type Description
tuple Tuple[str, int]

(display_format, poll_interval)

Source code in octoprint_uptime/plugin.py
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
def _get_api_settings(self) -> Tuple[str, int]:
    """
    Retrieves and returns the plugin's API settings with appropriate fallbacks.

    Attempts to fetch the following settings from the plugin's configuration:
    - display_format (str): The format to display uptime.
        Defaults to "full" if not set or invalid.
    - poll_interval (int): The polling interval in seconds.
        Defaults to 5 if not set or invalid.

    Returns:
        tuple: (display_format, poll_interval)
    """
    logger = getattr(self, "_logger", None)

    try:
        raw_fmt = self._settings.get(["display_format"])
        if raw_fmt is None:
            display_format = _("full")
            if logger:
                logger.debug("_get_api_settings: display_format missing, defaulting to 'full'")
        else:
            display_format = str(raw_fmt)
    except (AttributeError, TypeError, ValueError) as e:
        display_format = _("full")
        if logger:
            logger.exception(
                "_get_api_settings: failed to read display_format, defaulting to 'full': %s",
                e,
            )

    try:
        raw_poll = self._settings.get(["poll_interval_seconds"])
        if raw_poll is None or raw_poll == "":
            poll_interval = 5
            if logger:
                logger.debug(
                    "_get_api_settings: poll_interval_seconds missing, defaulting to 5"
                )
        else:
            try:
                poll_interval = int(raw_poll)
            except (TypeError, ValueError):
                poll_interval = 5
                if logger:
                    logger.debug(
                        "_get_api_settings: poll_interval_seconds invalid (%r), "
                        "defaulting to 5",
                        raw_poll,
                    )

        if poll_interval < 1:
            if logger:
                logger.debug(
                    "_get_api_settings: poll_interval_seconds %s < 1, clamping to 1",
                    poll_interval,
                )
            poll_interval = 1
        elif poll_interval > 120:
            if logger:
                logger.debug(
                    "_get_api_settings: poll_interval_seconds %s > 120, clamping to 120",
                    poll_interval,
                )
            poll_interval = 120
    except (AttributeError, TypeError, ValueError) as e:
        poll_interval = 5
        if logger:
            logger.exception(
                "_get_api_settings: failed to read poll_interval_seconds, defaulting to 5: %s",
                e,
            )

    return display_format, poll_interval

format_uptime

format_uptime(seconds)

Converts a duration in seconds to a human-readable string format.

Parameters:

Name Type Description Default
seconds float

The total number of seconds to format.

required

Returns:

Name Type Description
str str

A string representing the duration in days, hours, minutes, and seconds (e.g., '1d 2h 3m 4s').

Source code in octoprint_uptime/plugin.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
def format_uptime(seconds: float) -> str:
    """
    Converts a duration in seconds to a human-readable string format.

    Args:
        seconds (float): The total number of seconds to format.

    Returns:
        str: A string representing the duration in days, hours, minutes, and seconds
            (e.g., '1d 2h 3m 4s').
    """
    seconds = int(seconds)
    days = seconds // 86400
    hours = (seconds % 86400) // 3600
    minutes = (seconds % 3600) // 60
    secs = seconds % 60
    parts = []
    if days:
        parts.append(f"{days}d")
    if hours or days:
        parts.append(f"{hours}h")
    if minutes or hours or days:
        parts.append(f"{minutes}m")
    parts.append(f"{secs}s")
    return " ".join(parts)

format_uptime_d

format_uptime_d(seconds)

Converts a duration in seconds to a string representing the number of whole days.

Parameters:

Name Type Description Default
seconds float

The duration in seconds.

required

Returns:

Name Type Description
str str

The formatted string showing the number of days followed by 'd'.

Source code in octoprint_uptime/plugin.py
145
146
147
148
149
150
151
152
153
154
155
156
157
def format_uptime_d(seconds: float) -> str:
    """
    Converts a duration in seconds to a string representing the number of whole days.

    Args:
        seconds (float): The duration in seconds.

    Returns:
        str: The formatted string showing the number of days followed by 'd'.
    """
    seconds = int(seconds)
    days = seconds // 86400
    return f"{days}d"

format_uptime_dh

format_uptime_dh(seconds)

Converts a duration in seconds to a human-readable string in days and hours.

Parameters:

Name Type Description Default
seconds float

The total number of seconds to format.

required

Returns:

Name Type Description
str str

A string representing the duration in the format 'Xd Yh' if days are present, otherwise 'Yh' for hours only.

Source code in octoprint_uptime/plugin.py
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def format_uptime_dh(seconds: float) -> str:
    """
    Converts a duration in seconds to a human-readable string in days and hours.

    Args:
        seconds (float): The total number of seconds to format.

    Returns:
        str: A string representing the duration in the format 'Xd Yh' if days are present,
             otherwise 'Yh' for hours only.
    """
    seconds = int(seconds)
    days = seconds // 86400
    rem = seconds - days * 86400
    hours = rem // 3600
    if days:
        return f"{days}d {hours}h"
    return f"{hours}h"

format_uptime_dhm

format_uptime_dhm(seconds)

Converts a duration in seconds to a human-readable string in days, hours, and minutes.

Parameters:

Name Type Description Default
seconds float

The total number of seconds to format.

required

Returns:

Name Type Description
str str

A formatted string representing the duration in the form 'Xd Yh Zm' if days are present, or 'Yh Zm' if days are zero.

Source code in octoprint_uptime/plugin.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def format_uptime_dhm(seconds: float) -> str:
    """
    Converts a duration in seconds to a human-readable string in days, hours, and minutes.

    Args:
        seconds (float): The total number of seconds to format.

    Returns:
        str: A formatted string representing the duration in the form
            'Xd Yh Zm' if days are present,
            or 'Yh Zm' if days are zero.
    """
    seconds = int(seconds)
    days = seconds // 86400
    rem = seconds - days * 86400
    hours = rem // 3600
    rem = rem - hours * 3600
    minutes = rem // 60
    if days:
        return f"{days}d {hours}h {minutes}m"
    return f"{hours}h {minutes}m"

API changes: uptime availability

When uptime cannot be determined the plugin API now includes an uptime_available boolean and an optional uptime_note string that can contain a localized hint. Example response:

{
  "uptime": "unknown",
  "uptime_available": false,
  "uptime_note": "Uptime could not be determined."
}

Frontend callers: when querying the plugin from JavaScript inside the OctoPrint UI prefer the OctoPrint helper and pass the plugin id only, for example:

OctoPrint.simpleApiGet("octoprint_uptime").done(function (data) {
  /* ... */
});