feat: custom timeouts for wake and shutdown

This commit is contained in:
Maxi Quoß
2025-03-06 00:49:24 +01:00
parent 07f9bb5c77
commit 2e64e85d4b
20 changed files with 265 additions and 113 deletions

View File

@@ -0,0 +1,43 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("z5lghx2r3tm45n1")
if err != nil {
return err
}
// add field
if err := collection.Fields.AddMarshaledJSONAt(11, []byte(`{
"hidden": false,
"id": "number361076486",
"max": null,
"min": 1,
"name": "wake_timeout",
"onlyInt": true,
"presentable": false,
"required": false,
"system": false,
"type": "number"
}`)); err != nil {
return err
}
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("z5lghx2r3tm45n1")
if err != nil {
return err
}
// remove field
collection.Fields.RemoveById("number361076486")
return app.Save(collection)
})
}

View File

@@ -0,0 +1,43 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("z5lghx2r3tm45n1")
if err != nil {
return err
}
// add field
if err := collection.Fields.AddMarshaledJSONAt(15, []byte(`{
"hidden": false,
"id": "number2068100152",
"max": null,
"min": 1,
"name": "shutdown_timeout",
"onlyInt": true,
"presentable": false,
"required": false,
"system": false,
"type": "number"
}`)); err != nil {
return err
}
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("z5lghx2r3tm45n1")
if err != nil {
return err
}
// remove field
collection.Fields.RemoveById("number2068100152")
return app.Save(collection)
})
}

View File

@@ -48,16 +48,21 @@ func ShutdownDevice(device *core.Record) error {
done <- cmd.Wait() done <- cmd.Wait()
}() }()
// check state every seconds for 2 min shutdownTimeout := device.GetInt("shutdown_timeout")
if shutdownTimeout <= 0 {
shutdownTimeout = 120
}
start := time.Now() start := time.Now()
for { for {
select { select {
case <-time.After(1 * time.Second): case <-time.After(1 * time.Second):
if time.Since(start) >= 2*time.Minute { if time.Since(start) >= time.Duration(shutdownTimeout)*time.Second {
if err := KillProcess(cmd.Process); err != nil { if err := KillProcess(cmd.Process); err != nil {
logger.Error.Println(err) logger.Error.Println(err)
} }
return fmt.Errorf("%s not offline after 2 minutes", device.GetString("name")) return fmt.Errorf("%s not offline after %d seconds", device.GetString("name"), shutdownTimeout)
} }
isOnline, err := PingDevice(device) isOnline, err := PingDevice(device)
if err != nil { if err != nil {

View File

@@ -18,7 +18,7 @@ func SetProcessAttributes(cmd *exec.Cmd) {
// Kills child processes on Linux. Windows doesn't provide a direct way to kill child processes, so we kill just the main process. // Kills child processes on Linux. Windows doesn't provide a direct way to kill child processes, so we kill just the main process.
func KillProcess(process *os.Process) error { func KillProcess(process *os.Process) error {
logger.Warning.Println("Your shutdown cmd didn't finish in 2 minutes. It will be killed.") logger.Warning.Println("Your shutdown cmd didn't finish in time. It will be killed.")
pgid, err := unix.Getpgid(process.Pid) pgid, err := unix.Getpgid(process.Pid)
if err != nil { if err != nil {
return err return err

View File

@@ -15,6 +15,11 @@ import (
func WakeDevice(device *core.Record) error { func WakeDevice(device *core.Record) error {
logger.Info.Println("Wake triggered for", device.GetString("name")) logger.Info.Println("Wake triggered for", device.GetString("name"))
wakeTimeout := device.GetInt("wake_timeout")
if wakeTimeout <= 0 {
wakeTimeout = 120
}
wake_cmd := device.GetString("wake_cmd") wake_cmd := device.GetString("wake_cmd")
if wake_cmd != "" { if wake_cmd != "" {
var shell string var shell string
@@ -46,16 +51,16 @@ func WakeDevice(device *core.Record) error {
done <- cmd.Wait() done <- cmd.Wait()
}() }()
// check state every seconds for 2 min
start := time.Now() start := time.Now()
for { for {
select { select {
case <-time.After(1 * time.Second): case <-time.After(1 * time.Second):
if time.Since(start) >= 2*time.Minute { if time.Since(start) >= time.Duration(wakeTimeout)*time.Second {
if err := KillProcess(cmd.Process); err != nil { if err := KillProcess(cmd.Process); err != nil {
logger.Error.Println(err) logger.Error.Println(err)
} }
return fmt.Errorf("%s not online after 2 minutes", device.GetString("name")) return fmt.Errorf("%s not online after %d seconds", device.GetString("name"), wakeTimeout)
} }
isOnline, err := PingDevice(device) isOnline, err := PingDevice(device)
if err != nil { if err != nil {
@@ -83,10 +88,10 @@ func WakeDevice(device *core.Record) error {
return err return err
} }
// check state every seconds for 2 min
start := time.Now() start := time.Now()
for { for {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
fmt.Println("here")
isOnline, err := PingDevice(device) isOnline, err := PingDevice(device)
if err != nil { if err != nil {
logger.Error.Println(err) logger.Error.Println(err)
@@ -95,10 +100,11 @@ func WakeDevice(device *core.Record) error {
if isOnline { if isOnline {
return nil return nil
} }
if time.Since(start) >= 2*time.Minute { if time.Since(start) >= time.Duration(wakeTimeout)*time.Second {
fmt.Println("over")
break break
} }
} }
return fmt.Errorf(device.GetString("name"), "not online after 2 min") return fmt.Errorf(device.GetString("name"), "not online after %d seconds", wakeTimeout)
} }
} }

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Entfernten Linux PC ausschalten:", "device_shutdown_examples_linux": "Entfernten Linux PC ausschalten:",
"device_shutdown_examples_windows": "Entfernten Windows PC ausschalten:", "device_shutdown_examples_windows": "Entfernten Windows PC ausschalten:",
"device_shutdown_examples": "Beispiele:", "device_shutdown_examples": "Beispiele:",
"device_shutdown_timeout": "Ausschalt-Timeout (Sekunden)",
"device_shutdown": "Ausschalten", "device_shutdown": "Ausschalten",
"device_sol_authorization": "Authorisierung", "device_sol_authorization": "Authorisierung",
"device_sol_desc1": "Du kannst Computer mithilfe des Tools <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> in den Ruhezustand versetzen. Sleep-On-LAN (SOL) ist ein externes Tool/Daemon, das auf den PCs arbeitet, die du in den Ruhezustand versetzen möchtest, und stellt einen REST-Endpunkt bereit. Für Anweisungen zur Einrichtung von Sleep-On-LAN verweise bitte auf den Abschnitt <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a>.", "device_sol_desc1": "Du kannst Computer mithilfe des Tools <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> in den Ruhezustand versetzen. Sleep-On-LAN (SOL) ist ein externes Tool/Daemon, das auf den PCs arbeitet, die du in den Ruhezustand versetzen möchtest, und stellt einen REST-Endpunkt bereit. Für Anweisungen zur Einrichtung von Sleep-On-LAN verweise bitte auf den Abschnitt <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a>.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Aktivieren", "device_wake_cron_enable": "Aktivieren",
"device_wake_cron": "Cron", "device_wake_cron": "Cron",
"device_wake_desc": "Du kannst das Gerät mit einem Cron-Job einschalten.", "device_wake_desc": "Du kannst das Gerät mit einem Cron-Job einschalten.",
"device_wake_timeout": "Einschalt-Timeout (Sekunden)",
"device_wake": "Einschalten", "device_wake": "Einschalten",
"home_add_first_device": "Füge dein erstes Gerät hinzu", "home_add_first_device": "Füge dein erstes Gerät hinzu",
"home_grant_permissions": "Bitte frag den Administrator, dir Berechtigungen für bestehende Geräte zu erteilen oder neue Geräte zu erstellen.", "home_grant_permissions": "Bitte frag den Administrator, dir Berechtigungen für bestehende Geräte zu erteilen oder neue Geräte zu erstellen.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Shutdown remote linux machine:", "device_shutdown_examples_linux": "Shutdown remote linux machine:",
"device_shutdown_examples_windows": "Shutdown remote windows machine:", "device_shutdown_examples_windows": "Shutdown remote windows machine:",
"device_shutdown_examples": "Examples:", "device_shutdown_examples": "Examples:",
"device_shutdown_timeout": "Shutdown Timeout (seconds)",
"device_shutdown": "Shutdown", "device_shutdown": "Shutdown",
"device_sol_authorization": "Authorization", "device_sol_authorization": "Authorization",
"device_sol_desc1": "You can put computers to sleep using the <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> tool. Sleep-On-LAN (SOL) is an external tool/daemon that operates on the PCs you want to put to sleep, providing a REST endpoint. For instructions on setting up Sleep-On-LAN, please refer to the <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a> section.", "device_sol_desc1": "You can put computers to sleep using the <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> tool. Sleep-On-LAN (SOL) is an external tool/daemon that operates on the PCs you want to put to sleep, providing a REST endpoint. For instructions on setting up Sleep-On-LAN, please refer to the <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a> section.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Enable wake cron", "device_wake_cron_enable": "Enable wake cron",
"device_wake_cron": "Wake cron", "device_wake_cron": "Wake cron",
"device_wake_desc": "You can power this device using a scheduled cron job.", "device_wake_desc": "You can power this device using a scheduled cron job.",
"device_wake_timeout": "Wake Timeout (seconds)",
"device_wake": "Wake", "device_wake": "Wake",
"home_add_first_device": "Add your first device", "home_add_first_device": "Add your first device",
"home_grant_permissions": "Please ask the admin to grant you permissions to existing devices or to create new ones.", "home_grant_permissions": "Please ask the admin to grant you permissions to existing devices or to create new ones.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Apagar el dispositivo Linux remoto:", "device_shutdown_examples_linux": "Apagar el dispositivo Linux remoto:",
"device_shutdown_examples_windows": "Apagar el dispositivo Windows remoto:", "device_shutdown_examples_windows": "Apagar el dispositivo Windows remoto:",
"device_shutdown_examples": "Ejemplos:", "device_shutdown_examples": "Ejemplos:",
"device_shutdown_timeout": "Tiempo de espera de apagado (segundos)",
"device_shutdown": "Apagar", "device_shutdown": "Apagar",
"device_sol_authorization": "Autorización", "device_sol_authorization": "Autorización",
"device_sol_desc1": "Puedes poner las computadoras en modo de suspensión usando <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> herramienta. Sleep-On-LAN (SOL) es una herramienta/daemon externo que opera en las PC que desea poner en suspensión y proporciona un punto final REST. Para obtener instrucciones sobre cómo configurar Sleep-On-LAN, consulte <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Uso</a> sección.", "device_sol_desc1": "Puedes poner las computadoras en modo de suspensión usando <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> herramienta. Sleep-On-LAN (SOL) es una herramienta/daemon externo que opera en las PC que desea poner en suspensión y proporciona un punto final REST. Para obtener instrucciones sobre cómo configurar Sleep-On-LAN, consulte <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Uso</a> sección.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Activar wake cron", "device_wake_cron_enable": "Activar wake cron",
"device_wake_cron": "Encender cron", "device_wake_cron": "Encender cron",
"device_wake_desc": "Podrá encender este dispositivo utilizando un scheduled cron job.", "device_wake_desc": "Podrá encender este dispositivo utilizando un scheduled cron job.",
"device_wake_timeout": "Tiempo de espera de encendido (segundos)",
"device_wake": "Encender", "device_wake": "Encender",
"home_add_first_device": "Añade tu primer dispositivo", "home_add_first_device": "Añade tu primer dispositivo",
"home_grant_permissions": "Pídale al administrador que le otorgue permisos para los dispositivos existentes o que cree otros nuevos.", "home_grant_permissions": "Pídale al administrador que le otorgue permisos para los dispositivos existentes o que cree otros nuevos.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Arrêter une machine Linux distante :", "device_shutdown_examples_linux": "Arrêter une machine Linux distante :",
"device_shutdown_examples_windows": "Arrêter une machine Windows distante :", "device_shutdown_examples_windows": "Arrêter une machine Windows distante :",
"device_shutdown_examples": "Exemples :", "device_shutdown_examples": "Exemples :",
"device_shutdown_timeout": "Délai d'arrêt (secondes)",
"device_shutdown": "Arrêt", "device_shutdown": "Arrêt",
"device_sol_authorization": "Autorisation", "device_sol_authorization": "Autorisation",
"device_sol_desc1": "Vous pouvez mettre les ordinateurs en veille à l'aide de l'outil <a class='link' href='https://github.com/SR-G/sleep-on-lan' target='_blank'>Sleep-On-LAN</a>. Sleep-On-LAN (SOL) est un outil/daemon externe qui fonctionne sur les PC que vous souhaitez mettre en veille, fournissant un point de terminaison REST. Pour obtenir des instructions sur la configuration de Sleep-On-LAN, veuillez vous référer à la section <a href='https://github.com/SR-G/sleep-on-lan#usage' class='link' target='_blank'>Usage</a>.", "device_sol_desc1": "Vous pouvez mettre les ordinateurs en veille à l'aide de l'outil <a class='link' href='https://github.com/SR-G/sleep-on-lan' target='_blank'>Sleep-On-LAN</a>. Sleep-On-LAN (SOL) est un outil/daemon externe qui fonctionne sur les PC que vous souhaitez mettre en veille, fournissant un point de terminaison REST. Pour obtenir des instructions sur la configuration de Sleep-On-LAN, veuillez vous référer à la section <a href='https://github.com/SR-G/sleep-on-lan#usage' class='link' target='_blank'>Usage</a>.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Activer le réveil avec cron", "device_wake_cron_enable": "Activer le réveil avec cron",
"device_wake_cron": "Réveil avec cron", "device_wake_cron": "Réveil avec cron",
"device_wake_desc": "Vous pouvez allumer cet appareil en utilisant un job cron planifié.", "device_wake_desc": "Vous pouvez allumer cet appareil en utilisant un job cron planifié.",
"device_wake_timeout": "Délai de réveil (secondes)",
"device_wake": "Réveil", "device_wake": "Réveil",
"home_add_first_device": "Ajoutez votre premier appareil", "home_add_first_device": "Ajoutez votre premier appareil",
"home_grant_permissions": "Veuillez demander à votre administrateur les permissions aux appareils existants ou créez-en de nouveaux.", "home_grant_permissions": "Veuillez demander à votre administrateur les permissions aux appareils existants ou créez-en de nouveaux.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Mematikan Linux jarak jauh:", "device_shutdown_examples_linux": "Mematikan Linux jarak jauh:",
"device_shutdown_examples_windows": "Mematikan Windows jarak jauh:", "device_shutdown_examples_windows": "Mematikan Windows jarak jauh:",
"device_shutdown_examples": "Contoh:", "device_shutdown_examples": "Contoh:",
"device_shutdown_timeout": "Waktu tunggu mati (detik)",
"device_shutdown": "Matikan", "device_shutdown": "Matikan",
"device_sol_authorization": "Otorisasi", "device_sol_authorization": "Otorisasi",
"device_sol_desc1": "Anda dapat membuat tidur komputer menggunakan alat <a class='link' href='https://github.com/SR-G/sleep-on-lan' target='_blank'>Sleep-On-LAN</a>. Sleep-On-LAN (SOL) merupakan alat/daemon eksternal yang berjalan di PC yang ingin Anda tidurkan, dengan menyediakan REST endpoint. Untuk instruksi pemasangan Sleep-On-LAN, silakan merujuk ke bagian <a href='https://github.com/SR-G/sleep-on-lan#usage' class='link' target='_blank'>Penggunaan</a>.", "device_sol_desc1": "Anda dapat membuat tidur komputer menggunakan alat <a class='link' href='https://github.com/SR-G/sleep-on-lan' target='_blank'>Sleep-On-LAN</a>. Sleep-On-LAN (SOL) merupakan alat/daemon eksternal yang berjalan di PC yang ingin Anda tidurkan, dengan menyediakan REST endpoint. Untuk instruksi pemasangan Sleep-On-LAN, silakan merujuk ke bagian <a href='https://github.com/SR-G/sleep-on-lan#usage' class='link' target='_blank'>Penggunaan</a>.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Aktifkan jadwal bangun", "device_wake_cron_enable": "Aktifkan jadwal bangun",
"device_wake_cron": "Jadwal Bangun", "device_wake_cron": "Jadwal Bangun",
"device_wake_desc": "Anda dapat menyalakan perangkat ini menggunakan tugas penjadwalan.", "device_wake_desc": "Anda dapat menyalakan perangkat ini menggunakan tugas penjadwalan.",
"device_wake_timeout": "Waktu tunggu nyala (detik)",
"device_wake": "Bangunkan", "device_wake": "Bangunkan",
"home_add_first_device": "Tambahkan perangkat pertama Anda", "home_add_first_device": "Tambahkan perangkat pertama Anda",
"home_grant_permissions": "Mohon minta admin untuk memberikan izin ke perangkat yang sudah ada atau membuat perangkat baru.", "home_grant_permissions": "Mohon minta admin untuk memberikan izin ke perangkat yang sudah ada atau membuat perangkat baru.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Spegni macchina linux remota:", "device_shutdown_examples_linux": "Spegni macchina linux remota:",
"device_shutdown_examples_windows": "Spegni macchina windows remota:", "device_shutdown_examples_windows": "Spegni macchina windows remota:",
"device_shutdown_examples": "Esempi:", "device_shutdown_examples": "Esempi:",
"device_shutdown_timeout": "Timeout di spegnimento (secondi)",
"device_shutdown": "Spegni", "device_shutdown": "Spegni",
"device_sol_authorization": "Autorizzazione", "device_sol_authorization": "Autorizzazione",
"device_sol_desc1": "Puoi spegnere il tuo dispositivo usando lo strumento <a class='link' href='https://github.com/SR-G/sleep-on-lan' target='_blank'>Sleep-On-LAN</a>. Sleep-On-LAN (SOL) è uno strumento esterno che opera sul dispositivo che vuoi spegnere, il quale rende disponibile un endpoint REST. Puoi riferirti al link <a href='https://github.com/SR-G/sleep-on-lan#usage' class='link' target='_blank'>Uso</a> (in inglese) per le istruzioni.", "device_sol_desc1": "Puoi spegnere il tuo dispositivo usando lo strumento <a class='link' href='https://github.com/SR-G/sleep-on-lan' target='_blank'>Sleep-On-LAN</a>. Sleep-On-LAN (SOL) è uno strumento esterno che opera sul dispositivo che vuoi spegnere, il quale rende disponibile un endpoint REST. Puoi riferirti al link <a href='https://github.com/SR-G/sleep-on-lan#usage' class='link' target='_blank'>Uso</a> (in inglese) per le istruzioni.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Abilita sveglia programmata", "device_wake_cron_enable": "Abilita sveglia programmata",
"device_wake_cron": "Sveglia programmata", "device_wake_cron": "Sveglia programmata",
"device_wake_desc": "Puoi accendere questo dispositivo con una sveglia programmata.", "device_wake_desc": "Puoi accendere questo dispositivo con una sveglia programmata.",
"device_wake_timeout": "Timeout di accensione (secondi)",
"device_wake": "Accendi", "device_wake": "Accendi",
"home_add_first_device": "Aggiungi il tuo primo dispositivo", "home_add_first_device": "Aggiungi il tuo primo dispositivo",
"home_grant_permissions": "Per favore chiedi all'amministratore di darti i permessi necessari per aggiungere un nuovo dispositivo.", "home_grant_permissions": "Per favore chiedi all'amministratore di darti i permessi necessari per aggiungere un nuovo dispositivo.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "リモート Linux マシンのシャットダウン:", "device_shutdown_examples_linux": "リモート Linux マシンのシャットダウン:",
"device_shutdown_examples_windows": "リモート Windows マシンのシャットダウン:", "device_shutdown_examples_windows": "リモート Windows マシンのシャットダウン:",
"device_shutdown_examples": "例:", "device_shutdown_examples": "例:",
"device_shutdown_timeout": "シャットダウンタイムアウト (秒)",
"device_shutdown": "シャットダウン", "device_shutdown": "シャットダウン",
"device_sol_authorization": "認証", "device_sol_authorization": "認証",
"device_sol_desc1": "<a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> ツールを使用してコンピュータをスリープ状態にすることができます。Sleep-On-LANSOLは、スリープ状態にしたい PC で動作する外部ツール/デーモンで、REST エンドポイントを提供します。Sleep-On-LAN のセットアップ方法については、<a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a> セクションを参照してください。", "device_sol_desc1": "<a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> ツールを使用してコンピュータをスリープ状態にすることができます。Sleep-On-LANSOLは、スリープ状態にしたい PC で動作する外部ツール/デーモンで、REST エンドポイントを提供します。Sleep-On-LAN のセットアップ方法については、<a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a> セクションを参照してください。",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "起動スケジュールを有効化", "device_wake_cron_enable": "起動スケジュールを有効化",
"device_wake_cron": "起動スケジュール", "device_wake_cron": "起動スケジュール",
"device_wake_desc": "スケジュールされた cron ジョブを使用してこのデバイスを起動できます。", "device_wake_desc": "スケジュールされた cron ジョブを使用してこのデバイスを起動できます。",
"device_wake_timeout": "ウェイクタイムアウト (秒)",
"device_wake": "起動", "device_wake": "起動",
"home_add_first_device": "最初のデバイスを追加してください", "home_add_first_device": "最初のデバイスを追加してください",
"home_grant_permissions": "既存のデバイスへの権限を付与するか、新しいデバイスを作成するために管理者に依頼してください。", "home_grant_permissions": "既存のデバイスへの権限を付与するか、新しいデバイスを作成するために管理者に依頼してください。",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Afsluiten van een externe Linux-machine:", "device_shutdown_examples_linux": "Afsluiten van een externe Linux-machine:",
"device_shutdown_examples_windows": "Afsluiten van een externe Windows-machine:", "device_shutdown_examples_windows": "Afsluiten van een externe Windows-machine:",
"device_shutdown_examples": "Voorbeelden:", "device_shutdown_examples": "Voorbeelden:",
"device_shutdown_timeout": "Uitschakel-time-out (seconden)",
"device_shutdown": "Afsluiten", "device_shutdown": "Afsluiten",
"device_sol_authorization": "Autorisatie", "device_sol_authorization": "Autorisatie",
"device_sol_desc1": "Je kunt computers in de slaapstand zetten met de <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> tool. Sleep-On-LAN (SOL) is een externe tool/daemon die op de PC's werkt die je in de slaapstand wilt zetten en biedt een REST-endpoint. Voor instructies over het instellen van Sleep-On-LAN, zie de <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Gebruik</a> sectie.", "device_sol_desc1": "Je kunt computers in de slaapstand zetten met de <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> tool. Sleep-On-LAN (SOL) is een externe tool/daemon die op de PC's werkt die je in de slaapstand wilt zetten en biedt een REST-endpoint. Voor instructies over het instellen van Sleep-On-LAN, zie de <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Gebruik</a> sectie.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Wek cron inschakelen", "device_wake_cron_enable": "Wek cron inschakelen",
"device_wake_cron": "Wek cron", "device_wake_cron": "Wek cron",
"device_wake_desc": "Je kunt dit apparaat inschakelen met een geplande cron-taak.", "device_wake_desc": "Je kunt dit apparaat inschakelen met een geplande cron-taak.",
"device_wake_timeout": "Inschakel-time-out (seconden)",
"device_wake": "Wek", "device_wake": "Wek",
"home_add_first_device": "Voeg je eerste apparaat toe", "home_add_first_device": "Voeg je eerste apparaat toe",
"home_grant_permissions": "Vraag de admin om je toestemming te geven voor bestaande apparaten of om nieuwe te creëren.", "home_grant_permissions": "Vraag de admin om je toestemming te geven voor bestaande apparaten of om nieuwe te creëren.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Wyłącz zdalną maszynę Linux:", "device_shutdown_examples_linux": "Wyłącz zdalną maszynę Linux:",
"device_shutdown_examples_windows": "Wyłącz zdalną maszynę Windows:", "device_shutdown_examples_windows": "Wyłącz zdalną maszynę Windows:",
"device_shutdown_examples": "Przykłady:", "device_shutdown_examples": "Przykłady:",
"device_shutdown_timeout": "Limit czasu wyłączenia (sekundy)",
"device_shutdown": "Wyłącz", "device_shutdown": "Wyłącz",
"device_sol_authorization": "Autoryzacja", "device_sol_authorization": "Autoryzacja",
"device_sol_desc1": "Możesz wyłączać urządzenia za pomocą narzędzia <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a>. Sleep-On-LAN (SOL) jest zewnętrznym narzędziem/demonem, działającym na urządzeniach które chcesz wyłączać. Tworzy on endpoint REST. Aby dowiedzieć się jak skonfigurować SOL, zapoznaj się z <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">instrukcją użytkownika</a>.", "device_sol_desc1": "Możesz wyłączać urządzenia za pomocą narzędzia <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a>. Sleep-On-LAN (SOL) jest zewnętrznym narzędziem/demonem, działającym na urządzeniach które chcesz wyłączać. Tworzy on endpoint REST. Aby dowiedzieć się jak skonfigurować SOL, zapoznaj się z <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">instrukcją użytkownika</a>.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Włącz cron do włączania", "device_wake_cron_enable": "Włącz cron do włączania",
"device_wake_cron": "Cron do włączania", "device_wake_cron": "Cron do włączania",
"device_wake_desc": "Możesz włączyć to urządzenie za pomocą zaplanowanego zadania cron.", "device_wake_desc": "Możesz włączyć to urządzenie za pomocą zaplanowanego zadania cron.",
"device_wake_timeout": "Limit czasu wybudzania (sekundy)",
"device_wake": "Włączanie", "device_wake": "Włączanie",
"home_add_first_device": "Utwórz pierwsze urządzenie", "home_add_first_device": "Utwórz pierwsze urządzenie",
"home_grant_permissions": "Poproś administratora o przyznanie uprawnień do istniejących urządzeń lub do tworzenia nowych.", "home_grant_permissions": "Poproś administratora o przyznanie uprawnień do istniejących urządzeń lub do tworzenia nowych.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "Desligar dispositivo linux remoto:", "device_shutdown_examples_linux": "Desligar dispositivo linux remoto:",
"device_shutdown_examples_windows": "Desligar dispositivo windows remoto:", "device_shutdown_examples_windows": "Desligar dispositivo windows remoto:",
"device_shutdown_examples": "Exemplos:", "device_shutdown_examples": "Exemplos:",
"device_shutdown_timeout": "Tempo limite de desligamento (segundos)",
"device_shutdown": "Desligar", "device_shutdown": "Desligar",
"device_sol_authorization": "Autenticação", "device_sol_authorization": "Autenticação",
"device_sol_desc1": "Poderá suspender o seu dispositivo usando a ferramenta <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a>. Sleep-On-LAN (SOL) é uma ferramenta externa que terá de ser executada no dispositivo que quer suspender, facilitando um REST endpoint. Para instruções em como configurar Sleep-On-LAN, veja a secção <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a>.", "device_sol_desc1": "Poderá suspender o seu dispositivo usando a ferramenta <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a>. Sleep-On-LAN (SOL) é uma ferramenta externa que terá de ser executada no dispositivo que quer suspender, facilitando um REST endpoint. Para instruções em como configurar Sleep-On-LAN, veja a secção <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a>.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "Ativar wake cron", "device_wake_cron_enable": "Ativar wake cron",
"device_wake_cron": "Wake cron", "device_wake_cron": "Wake cron",
"device_wake_desc": "Poderá ligar este dispositivo através dum cron job agendado.", "device_wake_desc": "Poderá ligar este dispositivo através dum cron job agendado.",
"device_wake_timeout": "Tempo limite de ativação (segundos)",
"device_wake": "Ligar", "device_wake": "Ligar",
"home_add_first_device": "Adicione o seu primeiro dispositivo", "home_add_first_device": "Adicione o seu primeiro dispositivo",
"home_grant_permissions": "Peça ao administrador para alterar as suas permissões para dispositivos existentes ou para criar novos.", "home_grant_permissions": "Peça ao administrador para alterar as suas permissões para dispositivos existentes ou para criar novos.",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "關閉遠端 Linux 主機:", "device_shutdown_examples_linux": "關閉遠端 Linux 主機:",
"device_shutdown_examples_windows": "關閉遠端 Windows 主機:", "device_shutdown_examples_windows": "關閉遠端 Windows 主機:",
"device_shutdown_examples": "範例:", "device_shutdown_examples": "範例:",
"device_shutdown_timeout": "關機超時(秒)",
"device_shutdown": "關機", "device_shutdown": "關機",
"device_sol_authorization": "認證", "device_sol_authorization": "認證",
"device_sol_desc1": "你可以使用 <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> 工具讓電腦睡眠。 Sleep-On-LAN (SOL) 是一个外部的工具它在你想要進入睡眠的PC上執行並有RestAPI端口. 有關 Sleep-On-LAN 設定的說明, 請見文檔 <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a>", "device_sol_desc1": "你可以使用 <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> 工具讓電腦睡眠。 Sleep-On-LAN (SOL) 是一个外部的工具它在你想要進入睡眠的PC上執行並有RestAPI端口. 有關 Sleep-On-LAN 設定的說明, 請見文檔 <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a>",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "啟用定時喚醒", "device_wake_cron_enable": "啟用定時喚醒",
"device_wake_cron": "唤醒排程", "device_wake_cron": "唤醒排程",
"device_wake_desc": "你可以透過排程来唤醒裝置。", "device_wake_desc": "你可以透過排程来唤醒裝置。",
"device_wake_timeout": "喚醒超時(秒)",
"device_wake": "喚醒", "device_wake": "喚醒",
"home_add_first_device": "添加你的第一台設備", "home_add_first_device": "添加你的第一台設備",
"home_grant_permissions": "請聯絡系統管理員授權現有設備或創建新設備的權限", "home_grant_permissions": "請聯絡系統管理員授權現有設備或創建新設備的權限",

View File

@@ -88,6 +88,7 @@
"device_shutdown_examples_linux": "关闭远程 Linux 主机:", "device_shutdown_examples_linux": "关闭远程 Linux 主机:",
"device_shutdown_examples_windows": "关闭远程 Windows 主机:", "device_shutdown_examples_windows": "关闭远程 Windows 主机:",
"device_shutdown_examples": "示例:", "device_shutdown_examples": "示例:",
"device_shutdown_timeout": "关机超时(秒)",
"device_shutdown": "关机", "device_shutdown": "关机",
"device_sol_authorization": "认证", "device_sol_authorization": "认证",
"device_sol_desc1": "您可以使用 <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> 工具让计算机进入睡眠状态. Sleep-On-LAN (SOL) 是一个外部的工具/守护程序, 它在您想要进入休眠状态的PC上运行并提供RestApi接口. 有关 Sleep-On-LAN 设置的说明, 请参阅文档 <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a> 部分.", "device_sol_desc1": "您可以使用 <a class=\"link\" href=\"https://github.com/SR-G/sleep-on-lan\" target=\"_blank\">Sleep-On-LAN</a> 工具让计算机进入睡眠状态. Sleep-On-LAN (SOL) 是一个外部的工具/守护程序, 它在您想要进入休眠状态的PC上运行并提供RestApi接口. 有关 Sleep-On-LAN 设置的说明, 请参阅文档 <a href=\"https://github.com/SR-G/sleep-on-lan#usage\" class=\"link\" target=\"_blank\">Usage</a> 部分.",
@@ -104,6 +105,7 @@
"device_wake_cron_enable": "启用定时唤醒", "device_wake_cron_enable": "启用定时唤醒",
"device_wake_cron": "唤醒计划任务", "device_wake_cron": "唤醒计划任务",
"device_wake_desc": "您可以通过计划任务来唤醒设备.", "device_wake_desc": "您可以通过计划任务来唤醒设备.",
"device_wake_timeout": "唤醒超时(秒)",
"device_wake": "唤醒", "device_wake": "唤醒",
"home_add_first_device": "添加您的第一台设备", "home_add_first_device": "添加您的第一台设备",
"home_grant_permissions": "请联系管理员授予您相应权限.", "home_grant_permissions": "请联系管理员授予您相应权限.",

View File

@@ -16,7 +16,7 @@
let modalShutdown: HTMLDialogElement; let modalShutdown: HTMLDialogElement;
$: if (device.status === 'pending' && !interval) { $: if (device.status === 'pending' && !interval) {
countdown(Date.parse(device.updated)); countdown(Date.parse(device.updated), 'wake');
} }
$: minutes = Math.floor(timeout / 60); $: minutes = Math.floor(timeout / 60);
$: seconds = timeout % 60; $: seconds = timeout % 60;
@@ -53,7 +53,7 @@
.then((resp) => resp.json()) .then((resp) => resp.json())
.then(async (data) => { .then(async (data) => {
device = data as Device; device = data as Device;
await countdown(Date.parse(device.updated)); await countdown(Date.parse(device.updated), 'wake');
if (device.status === 'online' && device.link && device.link_open !== '') { if (device.status === 'online' && device.link && device.link_open !== '') {
if (device.link_open === 'new_tab') { if (device.link_open === 'new_tab') {
window.open(device.link, '_blank'); window.open(device.link, '_blank');
@@ -76,18 +76,22 @@
.then((resp) => resp.json()) .then((resp) => resp.json())
.then((data) => { .then((data) => {
device = data as Device; device = data as Device;
countdown(Date.parse(device.updated)); countdown(Date.parse(device.updated), 'shutdown');
}) })
.catch((err) => { .catch((err) => {
toast.error(err.message); toast.error(err.message);
}); });
} }
function countdown(updated: number) { function countdown(updated: number, action: 'wake' | 'shutdown') {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
timeout = 120; timeout = action === 'wake' ? device.wake_timeout : device.shutdown_timeout;
const end = updated + 2 * 60 * 1000; if (timeout <= 0) {
timeout = 120;
}
const end = updated + timeout * 1000;
if (interval) { if (interval) {
clearInterval(interval); clearInterval(interval);

View File

@@ -323,12 +323,12 @@
{@html m.device_ping_desc()} {@html m.device_ping_desc()}
</p> </p>
<fieldset class="fieldset"> <fieldset class="fieldset">
<label class="floating-label mt-2"> <label class="input mt-2">
<span>{m.device_ping_cmd()}</span> <span>$:</span>
<input <input
type="text" type="text"
placeholder={m.device_ping_cmd()} placeholder={m.device_ping_cmd()}
class="input" class="grow"
bind:value={device.ping_cmd} bind:value={device.ping_cmd}
/> />
</label> </label>
@@ -343,17 +343,31 @@
<!-- eslint-disable svelte/no-at-html-tags --> <!-- eslint-disable svelte/no-at-html-tags -->
{@html m.settings_ping_interval_desc2()} {@html m.settings_ping_interval_desc2()}
</p> </p>
<fieldset class="fieldset"> <div class="flex flex-row flex-wrap gap-4">
<label class="floating-label mt-2"> <fieldset class="fieldset">
<span>{m.device_wake_cmd()}</span> <label class="floating-label mt-2">
<input <span>{m.device_wake_timeout()}</span>
type="text" <input
placeholder={m.device_wake_cmd()} type="number"
class="input" min="0"
bind:value={device.wake_cmd} placeholder={m.device_wake_timeout()}
/> class="input"
</label> bind:value={device.wake_timeout}
</fieldset> />
</label>
</fieldset>
<fieldset class="fieldset">
<label class="input mt-2">
<span>$:</span>
<input
type="text"
placeholder={m.device_wake_cmd()}
class="grow"
bind:value={device.wake_cmd}
/>
</label>
</fieldset>
</div>
<div class="flex flex-row flex-wrap gap-4"> <div class="flex flex-row flex-wrap gap-4">
<fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4"> <fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4">
<legend class="fieldset-legend">{m.device_wake_cron_enable()}</legend> <legend class="fieldset-legend">{m.device_wake_cron_enable()}</legend>
@@ -399,7 +413,100 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card bg-base-200 mt-6 w-full shadow-sm">
<div class="card-body">
<h2 class="card-title">{m.device_shutdown()}</h2>
<p>
<!-- eslint-disable svelte/no-at-html-tags -->
{@html m.device_shutdown_desc()}
</p>
<div class="flex flex-row flex-wrap gap-4">
<fieldset class="fieldset">
<label class="floating-label mt-2">
<span>{m.device_shutdown_timeout()}</span>
<input
type="number"
min="0"
placeholder={m.device_shutdown_timeout()}
class="input"
bind:value={device.shutdown_timeout}
/>
</label>
</fieldset>
<fieldset class="fieldset">
<label class="input mt-2">
<span>$:</span>
<input
type="text"
placeholder={m.device_shutdown_cmd()}
class="grow"
bind:value={device.shutdown_cmd}
/>
</label>
</fieldset>
</div>
<p class="font-bold">{m.device_shutdown_examples()}</p>
<div class="mockup-code max-w-fit min-w-0 text-sm">
<pre data-prefix="#" class="italic"><code>{m.device_shutdown_examples_windows()}</code
></pre>
<pre data-prefix="$" class="text-warning"><code
>net rpc shutdown -I 192.168.1.13 -U "user%password"</code
></pre>
</div>
<div class="mockup-code max-w-fit min-w-0 text-sm">
<pre data-prefix="#" class="italic"><code>{m.device_shutdown_examples_linux()}</code></pre>
<pre data-prefix="$" class="text-warning"><code
>sshpass -p password ssh -o "StrictHostKeyChecking=no" user@192.168.1.13 "sudo poweroff"</code
></pre>
</div>
<p>
{m.device_shutdown_cron_desc()}
</p>
<div class="flex flex-row flex-wrap gap-4">
<fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4">
<legend class="fieldset-legend">{m.device_shutdown_cron_enable()}</legend>
<label class="fieldset-label">
<input
type="checkbox"
bind:checked={device.shutdown_cron_enabled}
class="toggle toggle-success"
/>
{m.device_shutdown_cron_enable()}
</label>
<label class="floating-label mt-2">
<span
>{m.device_shutdown_cron()}
{#if device.shutdown_cron_enabled}
<span class="text-error">*</span>
{/if}
</span>
<input
type="text"
placeholder={m.device_shutdown_cron()}
class="input validator"
bind:value={device.shutdown_cron}
disabled={!device.shutdown_cron_enabled}
required={device.shutdown_cron_enabled}
/>
{#if device.shutdown_cron_enabled}
<p class="fieldset-label">{parseCron(device.shutdown_cron, Date.now())}</p>
{/if}
</label>
</fieldset>
<fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4">
<legend class="fieldset-legend">{m.device_require_confirmation()}</legend>
<label class="fieldset-label">
<input
type="checkbox"
bind:checked={device.shutdown_confirm}
class="toggle toggle-success"
/>
{m.device_require_confirmation()}
</label>
</fieldset>
</div>
</div>
</div>
<div class="card bg-base-200 mt-6 w-full shadow-sm"> <div class="card bg-base-200 mt-6 w-full shadow-sm">
<div class="card-body"> <div class="card-body">
<h2 class="card-title">Sleep-On-LAN</h2> <h2 class="card-title">Sleep-On-LAN</h2>
@@ -488,88 +595,6 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card bg-base-200 mt-6 w-full shadow-sm">
<div class="card-body">
<h2 class="card-title">{m.device_shutdown()}</h2>
<p>
<!-- eslint-disable svelte/no-at-html-tags -->
{@html m.device_shutdown_desc()}
</p>
<fieldset class="fieldset">
<label class="floating-label mt-2">
<span>{m.device_shutdown_cmd()}</span>
<input
type="text"
placeholder={m.device_shutdown_cmd()}
class="input"
bind:value={device.shutdown_cmd}
/>
</label>
</fieldset>
<p class="font-bold">{m.device_shutdown_examples()}</p>
<div class="mockup-code max-w-fit min-w-0 text-sm">
<pre data-prefix="#" class="italic"><code>{m.device_shutdown_examples_windows()}</code
></pre>
<pre data-prefix="$" class="text-warning"><code
>net rpc shutdown -I 192.168.1.13 -U "user%password"</code
></pre>
</div>
<div class="mockup-code max-w-fit min-w-0 text-sm">
<pre data-prefix="#" class="italic"><code>{m.device_shutdown_examples_linux()}</code></pre>
<pre data-prefix="$" class="text-warning"><code
>sshpass -p password ssh -o "StrictHostKeyChecking=no" user@192.168.1.13 "sudo poweroff"</code
></pre>
</div>
<p>
{m.device_shutdown_cron_desc()}
</p>
<div class="flex flex-row flex-wrap gap-4">
<fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4">
<legend class="fieldset-legend">{m.device_shutdown_cron_enable()}</legend>
<label class="fieldset-label">
<input
type="checkbox"
bind:checked={device.shutdown_cron_enabled}
class="toggle toggle-success"
/>
{m.device_shutdown_cron_enable()}
</label>
<label class="floating-label mt-2">
<span
>{m.device_shutdown_cron()}
{#if device.shutdown_cron_enabled}
<span class="text-error">*</span>
{/if}
</span>
<input
type="text"
placeholder={m.device_shutdown_cron()}
class="input validator"
bind:value={device.shutdown_cron}
disabled={!device.shutdown_cron_enabled}
required={device.shutdown_cron_enabled}
/>
{#if device.shutdown_cron_enabled}
<p class="fieldset-label">{parseCron(device.shutdown_cron, Date.now())}</p>
{/if}
</label>
</fieldset>
<fieldset class="fieldset bg-base-100 border-base-300 rounded-box w-64 border p-4">
<legend class="fieldset-legend">{m.device_require_confirmation()}</legend>
<label class="fieldset-label">
<input
type="checkbox"
bind:checked={device.shutdown_confirm}
class="toggle toggle-success"
/>
{m.device_require_confirmation()}
</label>
</fieldset>
</div>
</div>
</div>
<div class="card bg-base-200 mt-6 w-full shadow-sm"> <div class="card bg-base-200 mt-6 w-full shadow-sm">
<div class="card-body"> <div class="card-body">
<h2 class="card-title">{m.device_password()}</h2> <h2 class="card-title">{m.device_password()}</h2>

View File

@@ -15,10 +15,12 @@ export type Device = RecordModel & {
wake_cron_enabled: boolean; wake_cron_enabled: boolean;
wake_cmd: string; wake_cmd: string;
wake_confirm: boolean; wake_confirm: boolean;
wake_timeout: number;
shutdown_cron: string; shutdown_cron: string;
shutdown_cron_enabled: boolean; shutdown_cron_enabled: boolean;
shutdown_cmd: string; shutdown_cmd: string;
shutdown_confirm: boolean; shutdown_confirm: boolean;
shutdown_timeout: number;
password: string; password: string;
groups: string[]; groups: string[];
expand: { expand: {