Turn OFF Personalize add on
#1
Bonjour à tous et merci pour votre aide, / Hello everyone and thank you for your help,

J'essaie de personnaliser l'addon "Turn Off" pour qu'il exécute un programme en remplacement de l'hibernation.
I'm trying to customize the "Turn Off" addon to run a program as a replacement for hibernation.

Plug in : Turn Off
Kodi : 19.3

Voici le fichier : screensaver.py
Here is the file: screensaver.py

La commande "System.Exec(notepad.exe)" ne fonctionne pas.
The "System.Exec (notepad.exe)" command does not work.

Thanks !

python:
POWER_METHODS = [
    dict(name='do-nothing', title='Do nothing',
         function='log', kwargs_off=dict(level=2, message='Do nothing to power off system')),
    dict(name='suspend-builtin', title='Suspend (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Suspend')),

    dict(name='hibernate-builtin', title='Hibernate (builtt-in)',
        function='jsonrpc', kwargs_off=dict(method='System.Exec(notepad.exe)')
            ),


    dict(name='quit-builtin', title='Quit (built-in)',
         function='jsonrpc', kwargs_off=dict(method='Application.Quit')),
    dict(name='shutdown-builtin', title='ShutDown action (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Shutdown')),
    dict(name='reboot-builtin', title='Reboot (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Reboot')),
    dict(name='powerdown-builtin', title='Powerdown (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Powerdown')),
]
Reply
#2
Full : screensaver.py
python:
# -*- coding: utf-8 -*-
# Copyright: © 2018, Dag Wieers (@dagwieers) <[email protected]>
# GNU General Public License v2.0 (see COPYING or https://www.gnu.org/licenses/gpl-2.0.txt)
''' This Kodi addon turns off display devices when Kodi goes into screensaver-mode '''

from __future__ import absolute_import, division, unicode_literals
import sys
import atexit
from xbmc import Monitor
from xbmcgui import WindowXMLDialog

# NOTE: The below order relates to resources/settings.xml
DISPLAY_METHODS = [
    dict(name='do-nothing', title='Do nothing',
         function='log',
         args_off=[2, 'Do nothing to power off display'],
         args_on=[2, 'Do nothing to power back on display']),
    dict(name='cec-builtin', title='CEC (buil-in)',
         function='run_builtin',
         args_off=['CECStandby'],
         args_on=['CECActivateSource']),
    dict(name='no-signal-rpi', title='No Signal on Raspberry Pi (using vcgencmd)',
         function='run_command',
         args_off=['vcgencmd', 'display_power', '0'],
         args_on=['vcgencmd', 'display_power', '1']),
    dict(name='dpms-builtin', title='DPMS (built-in)',
         function='run_builtin',
         args_off=['ToggleDPMS'],
         args_on=['ToggleDPMS']),
    dict(name='dpms-xset', title='DPMS (using xset)',
         function='run_command',
         args_off=['xset', 'dpms', 'force', 'off'],
         args_on=['xset', 'dpms', 'force', 'on']),
    dict(name='dpms-vbetool', title='DPMS (using vbetool)',
         function='run_command',
         args_off=['vbetool', 'dpms', 'off'],
         args_on=['vbetool', 'dpms', 'on']),
    # TODO: This needs more outside testing
    dict(name='dpms-xrandr', title='DPMS (using xrandr)',
         function='run_command',
         args_off=['xrandr', '--output CRT-0', 'off'],
         args_on=['xrandr', '--output CRT-0', 'on']),
    # TODO: This needs more outside testing
    dict(name='cec-android', title='CEC on Android (kernel)',
         function='run_command',
         args_off=['su', '-c', 'echo 0 >/sys/devices/virtual/graphics/fb0/cec'],
         args_on=['su', '-c', 'echo 1 >/sys/devices/virtual/graphics/fb0/cec']),
    # NOTE: Contrary to what one might think, 1 means off and 0 means on
    dict(name='backlight-rpi', title='Backlight on Raspberry Pi (kernel)',
         function='run_command',
         args_off=['su', '-c', 'echo 1 >/sys/class/backlight/rpi_backlight/bl_power'],
         args_on=['su', '-c', 'echo 0 >/sys/class/backlight/rpi_backlight/bl_power']),
    dict(name='backlight-odroid-c2', title='Backlight on Odroid C2 (kernel)',
         function='run_command',
         args_off=['su', '-c', 'echo 0 >/sys/class/amhdmitx/amhdmitx0/phy'],
         args_on=['su', '-c', 'echo 1 >/sys/class/amhdmitx/amhdmitx0/phy']),
]

POWER_METHODS = [
    dict(name='do-nothing', title='Do nothing',
         function='log', kwargs_off=dict(level=2, message='Do nothing to power off system')),
    dict(name='suspend-builtin', title='Suspend (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Suspend')),




    dict(name='hibernate-builtin', title='Hibernate (builtt-in)',
        function='jsonrpc', kwargs_off=dict(method='System.Exec(notepad.exe)')
            ),




    dict(name='quit-builtin', title='Quit (built-in)',
         function='jsonrpc', kwargs_off=dict(method='Application.Quit')),
    dict(name='shutdown-builtin', title='ShutDown action (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Shutdown')),
    dict(name='reboot-builtin', title='Reboot (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Reboot')),
    dict(name='powerdown-builtin', title='Powerdown (built-in)',
         function='jsonrpc', kwargs_off=dict(method='System.Powerdown')),
]

class SafeDict(dict):
    ''' A safe dictionary implementation that does not break down on missing keys '''
    def __missing__(self, key):
        ''' Replace missing keys with the original placeholder '''
        return '{' + key + '}'


def from_unicode(text, encoding='utf-8'):
    ''' Force unicode to text '''
    if sys.version_info.major == 2 and isinstance(text, unicode):  # noqa: F821; pylint: disable=undefined-variable
        return text.encode(encoding)
    return text


def to_unicode(text, encoding='utf-8'):
    ''' Force text to unicode '''
    return text.decode(encoding) if isinstance(text, bytes) else text


def addon_icon():
    ''' Cache and return VRT NU Add-on icon '''
    if not hasattr(addon_icon, 'cached'):
        from xbmcaddon import Addon
        addon_icon.cached = to_unicode(Addon().getAddonInfo('icon'))
    return getattr(addon_icon, 'cached')


def addon_id():
    ''' Cache and return VRT NU Add-on ID '''
    if not hasattr(addon_id, 'cached'):
        from xbmcaddon import Addon
        addon_id.cached = to_unicode(Addon().getAddonInfo('id'))
    return getattr(addon_id, 'cached')


def addon_name():
    ''' Cache and return VRT NU Add-on name '''
    if not hasattr(addon_name, 'cached'):
        from xbmcaddon import Addon
        addon_name.cached = to_unicode(Addon().getAddonInfo('name'))
    return getattr(addon_name, 'cached')


def addon_path():
    ''' Cache and return VRT NU Add-on path '''
    if not hasattr(addon_path, 'cached'):
        from xbmcaddon import Addon
        addon_path.cached = to_unicode(Addon().getAddonInfo('path'))
    return getattr(addon_path, 'cached')


def log(level=1, message='', **kwargs):
    ''' Log info messages to Kodi '''
    if not hasattr(log, 'debug_logging'):
        log.debug_logging = get_global_setting('debug.showloginfo')  # Returns a boolean
    max_log_level = int(get_setting('max_log_level', 0))
    if not getattr(log, 'debug_logging') and not (level <= max_log_level and max_log_level != 0):
        return
    if kwargs:
        from string import Formatter
        message = Formatter().vformat(message, (), SafeDict(**kwargs))
    message = '[{addon}] {message}'.format(addon=addon_id(), message=message)
    from xbmc import log as xlog
    xlog(from_unicode(message), level % 3 if getattr(log, 'debug_logging') else 2)


def log_error(message, **kwargs):
    ''' Log error messages to Kodi '''
    if kwargs:
        from string import Formatter
        message = Formatter().vformat(message, (), SafeDict(**kwargs))
    message = '[{addon}] {message}'.format(addon=addon_id(), message=message)
    from xbmc import log as xlog
    xlog(from_unicode(message), 4)


def jsonrpc(**kwargs):
    ''' Perform JSONRPC calls '''
    from json import dumps, loads
    from xbmc import executeJSONRPC
    if 'id' not in kwargs:
        kwargs.update(id=1)
    if 'jsonrpc' not in kwargs:
        kwargs.update(jsonrpc='2.0')
    result = loads(executeJSONRPC(dumps(kwargs)))
    if hasattr(log, 'debug_logging'):
        log(3, "Sending JSON-RPC payload: '{payload}' returns '{result}'", payload=kwargs, result=result)
    return result


def get_setting(setting_id, default=None):
    ''' Get an add-on setting '''
    from xbmcaddon import Addon
    value = to_unicode(Addon().getSetting(setting_id))
    if value == '' and default is not None:
        return default
    return value


def get_global_setting(setting):
    ''' Get a Kodi setting '''
    result = jsonrpc(method='Settings.GetSettingValue', params=dict(setting=setting))
    return result.get('result', {}).get('value')


def notification(heading='', message='', icon='', time=4000):
    ''' Show a Kodi notification '''
    from xbmcgui import Dialog
    if not heading:
        heading = addon_name()
    if not icon:
        icon = addon_icon()
    Dialog().notification(heading=heading, message=message, icon=icon, time=time)


def set_mute(toggle=True):
    ''' Set mute using Kodi JSON-RPC interface '''
    jsonrpc(method='Application.SetMute', params=dict(mute=toggle))


def activate_window(window='home'):
    ''' Set mute using Kodi JSON-RPC interface '''
#    result = jsonrpc(method='GUI.ActivateWindow', params=dict(window=window, parameters=['Home']))
    jsonrpc(method='GUI.ActivateWindow', params=dict(window=window))


def run_builtin(builtin):
    ''' Run Kodi builtins while catching exceptions '''
    from xbmc import executebuiltin
    log(2, "Executing builtin '{builtin}'", builtin=builtin)
    executebuiltin(builtin, True)


def run_command(*command, **kwargs):
    ''' Run commands on the OS while catching exceptions '''
    import subprocess
    # TODO: Add options for running using su or sudo
    try:
        cmd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, **kwargs)
        (out, err) = cmd.communicate()
        if cmd.returncode == 0:
            log(2, "Running command '{command}' returned rc={rc}", command=' '.join(command), rc=cmd.returncode)
        else:
            log_error("Running command '{command}' failed with rc={rc}", command=' '.join(command), rc=cmd.returncode)
            if err:
                log_error("Command '{command}' returned on stderr: {stderr}", command=command[0], stderr=err)
            if out:
                log_error("Command '{command}' returned on stdout: {stdout} ", command=command[0], stdout=out)
            notification(message="%s\n%s" % (out, err))
            sys.exit(1)
    except OSError as exc:
        log_error("Exception running '{command}': {exc}", command=command[0], exc=exc)
        notification(message="Exception running '%s': %s" % (command[0], exc))
        sys.exit(2)


def func(function, *args, **kwargs):
    ''' Execute a global function with arguments '''
    return globals()[function](*args, **kwargs)


class TurnOffDialog(WindowXMLDialog, object):
    ''' The TurnOffScreensaver class managing the XML gui '''

    def __init__(self, *args):  # pylint: disable=super-init-not-called,unused-argument
        ''' Initialize dialog '''
        self.display = None
        self.logoff = None
        self.monitor = None
        self.mute = None
        self.power = None
        atexit.register(self.exit)

    def onInit(self):  # pylint: disable=invalid-name
        ''' Perform this when the screensaver is started '''
        self.logoff = get_setting('logoff', 'false')
        self.mute = get_setting('mute', 'true')

        display_method = int(get_setting('display_method', 0))
        self.display = DISPLAY_METHODS[display_method]

        power_method = int(get_setting('power_method', 0))
        self.power = POWER_METHODS[power_method]

        log(3, 'display_method={display}, power_method={power}, logoff={logoff}, mute={mute}',
            display=self.display.get('name'), power=self.power.get('name'), logoff=self.logoff, mute=self.mute)

        # Turn off display
        if self.display.get('name') != 'do-nothing':
            log(1, "Turn display off using method '{name}'", **self.display)
        func(self.display.get('function'), *self.display.get('args_off'))

        # FIXME: Screensaver always seems to lock when started, requires unlock and re-login
        # Log off user
        if self.logoff == 'true':
            log(1, 'Log off user')
#            run_builtin('System.LogOff')
            activate_window('loginscreen')
#            run_builtin('ActivateWindow(loginscreen)')
#            run_builtin('ActivateWindowAndFocus(loginscreen,return)')

        # Mute audio
        if self.mute == 'true':
            log(1, 'Mute audio')
            set_mute(toggle=True)

        self.monitor = TurnOffMonitor(action=self.resume)
        self.monitor.waitForAbort(1)

        # Power off system
        if self.power.get('name') != 'do-nothing':
            log(1, "Turn system off using method '{name}'", **self.power)
        func(self.power.get('function'), **self.power.get('kwargs_off', {}))

    def resume(self):
        ''' Perform this when the Screensaver is stopped '''
        # Unmute audio
        if self.mute == 'true':
            log(1, 'Unmute audio')
            set_mute(toggle=False)

        # Turn on display
        if self.display.get('name') != 'do-nothing':
            log(1, "Turn display back on using method '{name}'", **self.display)
        func(self.display.get('function'), *self.display.get('args_on'))

        # Clean up everything
        self.exit()

    def exit(self):
        ''' Clean up function '''
        self.monitor = None
        self.close()


class TurnOffMonitor(Monitor, object):
    ''' This is the monitor to exit TurnOffScreensaver '''

    def __init__(self, **kwargs):  # pylint: disable=super-init-not-called
        ''' Initialize monitor '''
        self.action = kwargs.get('action')

    def onScreensaverDeactivated(self):  # pylint: disable=invalid-name
        ''' Perform cleanup function '''
        self.action()


def run():
    ''' Runs the screensaver '''
    from xbmc import getCondVisibility

    # If player has media, avoid running
    if getCondVisibility("Player.HasMedia"):
        log(1, 'Screensaver not started because player has media.')
        return

    TurnOffDialog('gui.xml', addon_path(), 'default').doModal()
Reply
#3
Welcome to the forum.

Two things...
- FYI, only English will do fine here.
- Please don't paste long(er) logs or code listings directly into the forum, use pastebin webservices instead. It can be viewed as .. spam, and we prefer a non-clogging forum server.
Reply
#4
Thanks Klojum, for your instructions.
have I posted my question in the correct category?
Reply
#5
(2021-12-27, 12:29)spams83300 Wrote: have I posted my question in the correct category?

Now that you mention it... What does notepad.exe have to do with Kodi's "Look and Feel" ?
And what does notepad have to do with activating a screen saver or turning off a monitor..?
Reply
#6
Hello Klojum,

The "Look and Feel" section seemed to me appropriate.
Notepad.exe is exemple, my objective is start spécific program .exe when the kodi screensaver start.

Thanks for your help
Reply

Logout Mark Read Team Forum Stats Members Help
Turn OFF Personalize add on0