From 1049db429c30381dcaacb3760c9d623d5df7782a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 14:17:11 +0100 Subject: [PATCH] UPS over USB: system app "nut" (Network UPS Tools) and shareos-ups Status, messages on power events, clean shutdown on battery (low battery, a percentage or minutes on battery), UPS output switched off afterwards (S05board), NUT server for other computers. NUT without OpenSSL. Services -> UPS in the interface, rpcd shareos.ups, tests/test-ups.sh. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KmfmQxsE59Ms99VrbCi1J1 --- .github/workflows/build.yml | 2 + CHANGELOG.md | 8 + CLAUDE.md | 2 +- README.md | 1 + .../rootfs-overlay/etc/init.d/S05board | 3 + configs/shareos_sysapps_defconfig | 5 + external.mk | 5 + package/shareos-core/shareos-core.mk | 2 + src/shareos-core/etc/config/ups | 17 ++ src/shareos-core/usr/sbin/shareos-ups | 233 ++++++++++++++++++ .../usr/share/rpcd/acl.d/shareos.json | 6 + .../usr/share/rpcd/ucode/shareos.uc | 55 ++++- src/shareos-core/www/app.js | 93 ++++++- src/shareos-core/www/i18n/ar.json | 47 +++- src/shareos-core/www/i18n/bn.json | 47 +++- src/shareos-core/www/i18n/en.json | 47 +++- src/shareos-core/www/i18n/es.json | 47 +++- src/shareos-core/www/i18n/fr.json | 47 +++- src/shareos-core/www/i18n/hi.json | 47 +++- src/shareos-core/www/i18n/pt.json | 47 +++- src/shareos-core/www/i18n/ru.json | 47 +++- src/shareos-core/www/i18n/zh.json | 47 +++- sysapps/nut/app.json | 19 ++ sysapps/nut/icon.svg | 1 + sysapps/nut/pack.json | 1 + tests/mock-ubus.py | 16 ++ tests/test-ups.sh | 86 +++++++ tools/i18n/ar.tsv | 45 ++++ tools/i18n/bn.tsv | 45 ++++ tools/i18n/es.tsv | 45 ++++ tools/i18n/fr.tsv | 45 ++++ tools/i18n/hi.tsv | 45 ++++ tools/i18n/pt.tsv | 45 ++++ tools/i18n/ru.tsv | 45 ++++ tools/i18n/zh.tsv | 45 ++++ 35 files changed, 1325 insertions(+), 13 deletions(-) create mode 100644 src/shareos-core/etc/config/ups create mode 100755 src/shareos-core/usr/sbin/shareos-ups create mode 100644 sysapps/nut/app.json create mode 100644 sysapps/nut/icon.svg create mode 100644 sysapps/nut/pack.json create mode 100755 tests/test-ups.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af781788..b0fec57f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,6 +48,8 @@ jobs: run: tests/test-bootlog.sh - name: Power schedule (shareos-power) run: LD_LIBRARY_PATH="$HOME/hostroot/lib" tests/test-power.sh "$HOME/hostroot/bin" + - name: UPS (shareos-ups with fake NUT programs) + run: LD_LIBRARY_PATH="$HOME/hostroot/lib" tests/test-ups.sh "$HOME/hostroot/bin" - name: Zabbix agent controller (settings, disk/RAID items) run: LD_LIBRARY_PATH="$HOME/hostroot/lib" tests/test-zabbix-items.sh "$HOME/hostroot/bin" - name: SMART evaluation (disk health) diff --git a/CHANGELOG.md b/CHANGELOG.md index faf65fc6..60d7721e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ Changes per release (newest first). The section of a version is added to its GitHub release automatically when the release is built. Test versions are pre-releases for test devices only. +## 0.2.0-beta.18 + +- **UPS over USB** (Dienste → USV, new system app **"nut"** in the store: Network UPS Tools 2.8.5 with the drivers usbhid-ups, nutdrv_qx and blazer_usb – APC, Eaton, CyberPower, most Megatec/Q1 boxes; 0.7 MB, kept on the flash so it works when a disk fails). + - Charge, runtime, load and model of the UPS; a power failure, the power coming back, a low or worn battery and a lost connection become messages (e-mail/push as set up) and are listed under *Ereignisse*. + - The box shuts down cleanly while on battery – when the UPS reports a low battery, below a charge of your choice or after some minutes on battery – and only then; if the power comes back first, nothing happens. Afterwards the UPS switches its output off and on again when the power is back, so the box starts by itself (can be switched off). + - Other computers can read the UPS over the network (NUT, port 3493, user `monitor` with a password) and shut down before the box. + - NUT without OpenSSL (`external.mk`: 4.4 MB of libraries less). `shareos-ups`, rpcd `shareos.ups`, the last step of the shutdown in `S05board`, `tests/test-ups.sh` (20 checks with fake NUT programs). + ## 0.2.0-beta.17 - **SMB 3 with signing about three times as fast: the crypto engine computes the signatures** ([#94](https://github.com/UniqueDroid/ShareOS/issues/94)). Windows 11 signs every SMB connection, and on the 800 MHz Kirkwood the signature limited writing: measured on a DNS-320L, about 35 MB/s without signing (the disks), only 4–10 MB/s with SMB 3.1.1 – ksmbd computes AES-CMAC on the CPU, where AES manages about 12 MB/s. The Kirkwood has a crypto engine (Marvell CESA) that does AES-CBC at about 38 MB/s with DMA, but ksmbd could not use it. A kernel patch (`0001-ksmbd-cmac-via-cbc`) computes the AES-CMAC of messages from 8 KiB through `cbc(aes)` – the engine – (CMAC is a CBC-MAC; the last block and the subkeys on the CPU), checks the first result against the old way and falls back to it on any error. Measured: **19–23 MB/s** signed, the CPU load of ksmbd went from about 64 % to under 10 %. `shareos-shares` loads `marvell-cesa` before ksmbd; module parameter `ksmbd.cbc_cmac=0` switches it off. Tested before on a UML kernel with Samba's smbclient (signing required, checksums equal). Tried as well and dropped: AES-GMAC signing (GHASH in C on ARMv5 is not faster, 3–8 MB/s). diff --git a/CLAUDE.md b/CLAUDE.md index 1fa64556..cd593a29 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ - Tags/releases are created by Jan; prepare the release text and the `CHANGELOG.md` section. - **Every release updates the docs** – see `docs/RELEASE.md` (CHANGELOG, README status/features, TESTEN/TESTING, ENTWICKLUNG/DEVELOPMENT). - Photos for the docs: strip EXIF/GPS and blur serial-number stickers before committing. -- Tests: `tests/` (host: test-update, test-net, test-flash-bin, test-boards, test-raid-wait, test-smart, test-bootlog, test-power, test-notify, test-zabbix-items, check-acl.py, check-i18n.py; ARM emulator with sudo: run-stack-qemu --check, test-users, test-storage, test-cloud-paperless, test-apps, test-firstinstall, test-transmission, test-media, test-dlna, test-vpn, test-tailscale, test-autobrr, test-zabbix – these seven need `make sysapps-pack`, test-snapshots, test-sysperms). UI work: `tests/mock-ubus.py`; app SDK in Chromium: `node tests/sdk-storage.js` (Playwright). ucode plugin: `tests/check-ucode-order.py` (no hoisting in ucode). +- Tests: `tests/` (host: test-update, test-net, test-flash-bin, test-boards, test-raid-wait, test-smart, test-bootlog, test-power, test-notify, test-zabbix-items, test-ups, check-acl.py, check-i18n.py; ARM emulator with sudo: run-stack-qemu --check, test-users, test-storage, test-cloud-paperless, test-apps, test-firstinstall, test-transmission, test-media, test-dlna, test-vpn, test-tailscale, test-autobrr, test-zabbix – these seven need `make sysapps-pack`, test-snapshots, test-sysperms). UI work: `tests/mock-ubus.py`; app SDK in Chromium: `node tests/sdk-storage.js` (Playwright). ucode plugin: `tests/check-ucode-order.py` (no hoisting in ucode). - Never `rm -rf` a chroot that still has mounts below it (it would delete the host's /dev). - Apps live in the separate repository UniqueDroid/ShareOS-Apps. - New UI texts: add them to `i18n/en.json` and to every `tools/i18n/.tsv` (new numbers at the end), then `tools/i18n/build-lang.py`; `tests/check-i18n.py` must pass. diff --git a/README.md b/README.md index 4638001a..abb3ecfc 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Version in brackets = first release with the feature. - **USB sticks and disks:** mounted at `/mnt/usb-` when plugged in (FAT32, exFAT, NTFS, ext4, Btrfs), **Safely remove**, **Format** with exFAT, FAT32, NTFS or ext4 (beta.7) **Shares, users, files** +- UPS over USB: charge and runtime, messages on a power failure, clean shutdown on battery (low battery, a percentage or minutes), other computers over the network (system app "nut", 0.2.0-beta.18) - SMB 2/3 (ksmbd) and NFS v4 shares with read/write permissions per user and group, guest access optional; the crypto engine of the SoC computes the SMB 3 signatures (about three times as fast, 0.2.0-beta.17); compatibility mode up to SMB 2.1 for difficult clients (0.2.0-beta.17) - Users and groups; one account for shares, web interface and apps; storage limit per user (ext4); import of Alt-F users with their passwords - "My ShareOS": users with web access manage their own password, look, shares, storage, cloud and Paperless diff --git a/board/dlink/dns320l/rootfs-overlay/etc/init.d/S05board b/board/dlink/dns320l/rootfs-overlay/etc/init.d/S05board index fbf7b715..985cdf82 100755 --- a/board/dlink/dns320l/rootfs-overlay/etc/init.d/S05board +++ b/board/dlink/dns320l/rootfs-overlay/etc/init.d/S05board @@ -94,6 +94,9 @@ stop() { rm -f "$BUTTONDDPID" start-stop-daemon -K -q -p "$PIDFILE" 2>/dev/null sleep 1 + # shut down on UPS battery: the UPS switches its output off now and on + # again when the power is back – and the box starts with it + [ -f /tmp/.poweroff ] && [ -x /usr/sbin/shareos-ups ] && /usr/sbin/shareos-ups killpower if [ -f /tmp/.poweroff ] && [ "$BOARD_CONTROL" = mcu ]; then # ask the MCU to cut power 3 seconds from now (other boxes: gpio-poweroff in the kernel) sync diff --git a/configs/shareos_sysapps_defconfig b/configs/shareos_sysapps_defconfig index 0d640616..ca73a596 100644 --- a/configs/shareos_sysapps_defconfig +++ b/configs/shareos_sysapps_defconfig @@ -49,6 +49,11 @@ BR2_PACKAGE_SHAREOS_AUTOBRR=y # Zabbix agent, classic C version (system app "zabbix-agent"), see # package/shareos-zabbix-agent BR2_PACKAGE_SHAREOS_ZABBIX_AGENT=y +# UPS (system app "nut"): Network UPS Tools with the USB drivers of most +# UPSs (usbhid-ups: APC, Eaton, CyberPower …; nutdrv_qx/blazer_usb: Megatec) +BR2_PACKAGE_LIBUSB=y +BR2_PACKAGE_NUT=y +BR2_PACKAGE_NUT_DRIVERS="usbhid-ups,nutdrv_qx,blazer_usb" BR2_PACKAGE_HTOP=y BR2_PACKAGE_STRACE=y BR2_PACKAGE_IPERF3=y diff --git a/external.mk b/external.mk index e8f6651f..17472f75 100644 --- a/external.mk +++ b/external.mk @@ -20,3 +20,8 @@ LIBEVENT_CONF_OPTS += --disable-openssl # (post-build.sh); rsync only uses them for faster checksums RSYNC_CONF_OPTS += --disable-openssl RSYNC_DEPENDENCIES := $(filter-out openssl,$(RSYNC_DEPENDENCIES)) + +# Network UPS Tools (system app "nut") without OpenSSL: upsd only talks to +# upsmon on the box and plain NUT clients – 4.4 MB of libraries less +NUT_CONF_OPTS += --without-ssl +NUT_DEPENDENCIES := $(filter-out openssl,$(NUT_DEPENDENCIES)) diff --git a/package/shareos-core/shareos-core.mk b/package/shareos-core/shareos-core.mk index b02e40a6..0adaa2ab 100644 --- a/package/shareos-core/shareos-core.mk +++ b/package/shareos-core/shareos-core.mk @@ -77,6 +77,7 @@ define SHAREOS_CORE_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0644 $(@D)/etc/config/dockerhosts $(TARGET_DIR)/etc/config/dockerhosts $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-dlna $(TARGET_DIR)/usr/sbin/shareos-dlna $(INSTALL) -D -m 0644 $(@D)/etc/config/dlna $(TARGET_DIR)/etc/config/dlna + $(INSTALL) -D -m 0644 $(@D)/etc/config/ups $(TARGET_DIR)/etc/config/ups $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-zabbix $(TARGET_DIR)/usr/sbin/shareos-zabbix $(INSTALL) -D -m 0644 $(@D)/etc/config/zabbix $(TARGET_DIR)/etc/config/zabbix $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-reset-access $(TARGET_DIR)/usr/sbin/shareos-reset-access @@ -89,6 +90,7 @@ define SHAREOS_CORE_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 $(@D)/etc/init.d/rcS $(TARGET_DIR)/etc/init.d/rcS $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-bootlog $(TARGET_DIR)/usr/sbin/shareos-bootlog $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-power $(TARGET_DIR)/usr/sbin/shareos-power + $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-ups $(TARGET_DIR)/usr/sbin/shareos-ups $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-users $(TARGET_DIR)/usr/sbin/shareos-users $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-shares $(TARGET_DIR)/usr/sbin/shareos-shares $(INSTALL) -D -m 0755 $(@D)/usr/sbin/shareos-quota $(TARGET_DIR)/usr/sbin/shareos-quota diff --git a/src/shareos-core/etc/config/ups b/src/shareos-core/etc/config/ups new file mode 100644 index 00000000..05a625fc --- /dev/null +++ b/src/shareos-core/etc/config/ups @@ -0,0 +1,17 @@ +# UPS over USB (system app "nut": Network UPS Tools) – managed by +# shareos-ups (web interface: Services -> UPS). +# +# option shutdown 'low' # low | percent | minutes +# option percent '30' # shutdown percent: below this charge +# option minutes '5' # shutdown minutes: after this long on battery +# option killpower '1' # switch the UPS output off afterwards +# option server '0' # other computers may read it (user monitor) + +config ups 'main' + option enabled '0' + option driver 'auto' + option shutdown 'low' + option percent '30' + option minutes '5' + option killpower '1' + option server '0' diff --git a/src/shareos-core/usr/sbin/shareos-ups b/src/shareos-core/usr/sbin/shareos-ups new file mode 100755 index 00000000..f6663000 --- /dev/null +++ b/src/shareos-core/usr/sbin/shareos-ups @@ -0,0 +1,233 @@ +#!/bin/sh +# +# shareos-ups – uninterruptible power supply over USB (system app "nut") +# +# shareos-ups start | stop | restart +# shareos-ups status key=value lines for the web interface +# shareos-ups boot start at boot when it is switched on +# shareos-ups stop-all stop (system app removed, shutdown) +# shareos-ups event upsmon's NOTIFYCMD (NOTIFYTYPE in the environment) +# shareos-ups timer (internal) minutes on battery are over +# shareos-ups shutdown upsmon's SHUTDOWNCMD: power the box off +# shareos-ups killpower (S05board, last step of a shutdown on battery) +# tell the UPS to switch its output off; it +# switches on again when the power is back, +# and so does the box +# +# shareos-service: boot start stop-all +# +# Settings: UCI ups.main – enabled, driver auto|usbhid-ups|nutdrv_qx| +# blazer_usb, shutdown low|percent|minutes (when the box shuts down while on +# battery: when the UPS reports a low battery / below % / after +# on battery), percent, minutes, killpower '1' (switch the UPS +# output off afterwards, default on), server '1' + password (other computers +# may read the UPS as "monitor" on port 3493 and shut down with the box). +# Network UPS Tools run as root with their files in /tmp/shareos-ups +# (NUT_CONFPATH/NUT_STATEPATH); messages go to shareos-notify. +# SHAREOS_ROOT= fake root (tests) SHAREOS_UPS_BIN= the programs (tests) +# +[ -n "$SHAREOS_ROOT" ] || PATH=/usr/sbin:/usr/bin:/sbin:/bin:/opt/shareos/bin +R=${SHAREOS_ROOT:-} +BIN=${SHAREOS_UPS_BIN:-/opt/shareos/bin} +RUN=$R/tmp/shareos-ups +export NUT_CONFPATH=$RUN/conf NUT_STATEPATH=$RUN/state NUT_ALTPIDPATH=$RUN/state + +die() { echo "error: $*"; exit 1; } +uget() { if [ -n "$SHAREOS_ROOT" ]; then uci -q -c "$R/etc/config" get "$1"; else uci -q get "$1"; fi; } +enabled() { [ "$(uget ups.main.enabled)" = 1 ]; } +installed() { [ -x "$BIN/upsd" ] && [ -x "$BIN/upsmon" ] && [ -x "$BIN/usbhid-ups" ]; } +num() { echo "$1" | grep -qE '^[0-9]+$' && [ "$1" -ge "$2" ] && [ "$1" -le "$3" ] && echo "$1" || echo "$4"; } +notify() { # [ ] + [ -n "$SHAREOS_ROOT" ] && { echo "notify $*" >> $RUN/notify.log; return; } + /usr/sbin/shareos-notify send "$1" ups "$2" "$3" "$4" "${5:-}" "${6:-}" >/dev/null 2>&1 +} +clear_note() { [ -n "$SHAREOS_ROOT" ] && { echo "clear $1" >> $RUN/notify.log; return; }; /usr/sbin/shareos-notify clear "$1" >/dev/null 2>&1; } + +# the USB UPS: of the first one known to usbhid-ups (HID +# power device) or another USB device the driver list names +detect() { + for d in ${SHAREOS_UPS_SYS:-/sys}/bus/usb/devices/*; do + [ -f "$d/idVendor" ] || continue + v=$(cat "$d/idVendor"); p=$(cat "$d/idProduct") + case "$v" in + 051d|0463|0764|09ae|050d|0d9f|06da|2b2d|0665|ffff|0001|0925|10af|047c|1cb0|04d8|2e51|3016) echo "$v:$p"; return ;; + esac + # HID power devices of other makers: interface class 3 with "UPS" in the name + grep -qi 'ups\|usv\|power' "$d/product" 2>/dev/null && ls "$d"/*:*/bInterfaceClass >/dev/null 2>&1 \ + && grep -q 03 "$d"/*:*/bInterfaceClass 2>/dev/null && { echo "$v:$p"; return; } + done +} + +driver() { + d=$(uget ups.main.driver) + case "$d" in usbhid-ups|nutdrv_qx|blazer_usb) echo "$d"; return ;; esac + # auto: Megatec/Q1 boxes (cheap UPSs) use nutdrv_qx, everything else HID + case "$(detect)" in 0665:5161|ffff:0000|0001:0000|0925:1234|06da:0003) echo nutdrv_qx ;; *) echo usbhid-ups ;; esac +} + +secret() { + [ -s $RUN/secret ] || { mkdir -p $RUN; head -c 12 /dev/urandom | od -An -tx1 | tr -d ' \n' > $RUN/secret; chmod 600 $RUN/secret; } + cat $RUN/secret +} + +write_conf() { + mkdir -p $RUN/conf $RUN/state + chmod 700 $RUN/conf $RUN/state + mode=$(uget ups.main.shutdown) + pct=$(num "$(uget ups.main.percent)" 10 90 30) + pw=$(secret) + { + echo "# written by shareos-ups at every start" + echo "maxretry = 3" + echo "user = root" + echo "[ups]" + echo " driver = $(driver)" + echo " port = auto" + echo " desc = \"ShareOS\"" + echo " pollinterval = 5" + echo " offdelay = 30" + echo " ondelay = 40" + if [ "$mode" = percent ]; then + # the driver reports a low battery itself below that charge + echo " ignorelb" + echo " override.battery.charge.low = $pct" + fi + } > $RUN/conf/ups.conf + { + echo "LISTEN 127.0.0.1 3493" + if [ "$(uget ups.main.server)" = 1 ]; then echo "LISTEN 0.0.0.0 3493"; echo "LISTEN :: 3493"; fi + } > $RUN/conf/upsd.conf + { + printf '[shareos]\n password = %s\n upsmon primary\n' "$pw" + mp=$(uget ups.main.password) + [ "$(uget ups.main.server)" = 1 ] && [ -n "$mp" ] && printf '[monitor]\n password = %s\n upsmon secondary\n' "$mp" + } > $RUN/conf/upsd.users + { + echo "RUN_AS_USER root" + echo "MONITOR ups@localhost 1 shareos $pw primary" + echo "MINSUPPLIES 1" + echo "SHUTDOWNCMD \"/usr/sbin/shareos-ups shutdown\"" + echo "NOTIFYCMD /usr/sbin/shareos-ups" + for e in ONLINE ONBATT LOWBATT FSD COMMOK COMMBAD SHUTDOWN REPLBATT NOCOMM; do echo "NOTIFYFLAG $e SYSLOG+EXEC"; done + echo "POLLFREQ 5" + echo "POLLFREQALERT 5" + echo "HOSTSYNC 15" + echo "DEADTIME 25" + echo "FINALDELAY 5" + [ "$(uget ups.main.killpower)" = 0 ] || echo "POWERDOWNFLAG $RUN/killpower" + } > $RUN/conf/upsmon.conf + chmod 600 $RUN/conf/* +} + +# upsd and upsmon keep their pid in /run (as root), the drivers in the state folder +pid() { for f in "$R/run/$1.pid" "$R/var/run/$1.pid" "$RUN/state/$1.pid"; do p=$(cat "$f" 2>/dev/null); [ -n "$p" ] && kill -0 "$p" 2>/dev/null && { echo "$p"; return; }; done; } +drv_pid() { for f in $RUN/state/*-ups.pid; do p=$(cat "$f" 2>/dev/null); [ -n "$p" ] && kill -0 "$p" 2>/dev/null && { echo "$p"; return; }; done; } + +start() { + installed || die "the system app \"nut\" is not installed (store)" + [ -n "$(pid upsmon)" ] && return 0 + write_conf + rm -f $RUN/killpower + d=$(driver) + "$BIN/$d" -a ups -u root >$RUN/driver.log 2>&1 || { + [ "$(uget ups.main.driver)" = auto ] || [ -z "$(uget ups.main.driver)" ] || die "no UPS found ($d): $(tail -n1 $RUN/driver.log)" + # auto: the other driver family + alt=nutdrv_qx; [ "$d" = nutdrv_qx ] && alt=usbhid-ups + sed -i "s/^ driver = .*/ driver = $alt/" $RUN/conf/ups.conf + "$BIN/$alt" -a ups -u root >$RUN/driver.log 2>&1 || die "no UPS found: $(tail -n1 $RUN/driver.log)" + } + "$BIN/upsd" -u root >$RUN/upsd.log 2>&1 || die "upsd did not start: $(tail -n1 $RUN/upsd.log)" + "$BIN/upsmon" >$RUN/upsmon.log 2>&1 || die "upsmon did not start: $(tail -n1 $RUN/upsmon.log)" +} + +stop() { + timer_stop + "$BIN/upsmon" -c stop >/dev/null 2>&1 + "$BIN/upsd" -c stop >/dev/null 2>&1 + p=$(drv_pid); [ -n "$p" ] && kill "$p" 2>/dev/null + i=0; while [ $i -lt 25 ] && { [ -n "$(pid upsmon)" ] || [ -n "$(pid upsd)" ] || [ -n "$(drv_pid)" ]; }; do sleep 0.2; i=$((i + 1)); done + return 0 +} + +timer_stop() { p=$(cat $RUN/timer.pid 2>/dev/null); [ -n "$p" ] && kill "$p" 2>/dev/null; rm -f $RUN/timer.pid; } + +# upsmon calls us with the message as argument, NOTIFYTYPE says what happened +event() { + mkdir -p $RUN + echo "$(date +%s) $NOTIFYTYPE" >> $RUN/events + tail -n 50 $RUN/events > $RUN/events.tmp && mv $RUN/events.tmp $RUN/events + case "$NOTIFYTYPE" in + ONBATT) + m=$(uget ups.main.minutes) + notify warn ups-onbatt "Stromausfall – die Box läuft über die USV" "Power failure – the box runs on the UPS" \ + "$( [ "$(uget ups.main.shutdown)" = minutes ] && echo "Sie fährt nach $(num "$m" 1 120 5) Minuten herunter, wenn der Strom nicht zurückkommt." )" \ + "$( [ "$(uget ups.main.shutdown)" = minutes ] && echo "It shuts down after $(num "$m" 1 120 5) minutes unless the power comes back." )" + if [ "$(uget ups.main.shutdown)" = minutes ]; then + timer_stop + ( sleep $(( $(num "$m" 1 120 5) * 60 )); "$0" timer ) >/dev/null 2>&1 & + echo $! > $RUN/timer.pid + fi ;; + ONLINE) + timer_stop + clear_note ups-onbatt + notify info ups-online "Strom wieder da" "Power is back" ;; + LOWBATT) notify error ups-lowbatt "USV-Akku fast leer – die Box fährt herunter" "UPS battery low – the box shuts down" ;; + FSD|SHUTDOWN) notify error ups-shutdown "Die Box fährt wegen der USV herunter" "The box shuts down because of the UPS" ;; + COMMBAD|NOCOMM) notify warn ups-comm "Keine Verbindung zur USV" "No connection to the UPS" "USB-Kabel prüfen." "Check the USB cable." ;; + COMMOK) clear_note ups-comm ;; + REPLBATT) notify warn ups-replbatt "USV-Akku tauschen" "Replace the UPS battery" "Die USV meldet einen verbrauchten Akku." "The UPS reports a worn battery." ;; + esac +} + +# minutes on battery are over: still on battery? then shut down (all secondaries too) +timer() { + rm -f $RUN/timer.pid + "$BIN/upsc" ups@localhost ups.status 2>/dev/null | grep -qw OB || return 0 + "$BIN/upsmon" -c fsd >/dev/null 2>&1 +} + +shutdown_box() { + logger -t shareos-ups "shutting down on UPS battery" 2>/dev/null + [ -n "$SHAREOS_ROOT" ] && { echo poweroff >> $RUN/notify.log; return; } + # the next switch-on of the power schedule into the wake-up alarm first + /usr/sbin/shareos-power arm >/dev/null 2>&1 + poweroff +} + +killpower() { + [ -f $RUN/killpower ] || return 0 + d=$(sed -n 's/^ driver = //p' $RUN/conf/ups.conf) + [ -n "$d" ] && [ -x "$BIN/$d" ] || return 0 + echo "UPS: output off in 30 s, on again when the power is back" + "$BIN/$d" -a ups -u root -k >/dev/null 2>&1 +} + +status() { + echo "installed=$(installed && echo 1 || echo 0)" + echo "enabled=$(enabled && echo 1 || echo 0)" + echo "running=$([ -n "$(pid upsmon)" ] && echo 1 || echo 0)" + echo "detected=$(detect)" + echo "driver=$(driver)" + [ -n "$(pid upsd)" ] || return 0 + "$BIN/upsc" ups@localhost 2>/dev/null | sed -n \ + -e 's/^ups\.status: /status=/p' -e 's/^battery\.charge: /charge=/p' -e 's/^battery\.runtime: /runtime=/p' \ + -e 's/^ups\.load: /load=/p' -e 's/^device\.mfr: /mfr=/p' -e 's/^device\.model: /model=/p' \ + -e 's/^input\.voltage: /voltage=/p' -e 's/^battery\.charge\.low: /charge_low=/p' -e 's/^battery\.date: /battery_date=/p' + tail -n 10 $RUN/events 2>/dev/null | sed 's/^/event=/' +} + +case "$1" in + start) enabled || die "switched off"; start ;; + boot) enabled && installed && start; exit 0 ;; + stop|stop-all) stop ;; + restart) stop; enabled && start ;; + status) status ;; + event) event ;; + timer) timer ;; + shutdown) shutdown_box ;; + killpower) killpower ;; + *) # upsmon's NOTIFYCMD passes the message text as first argument + if [ -n "$NOTIFYTYPE" ]; then event; exit 0; fi + sed -n '3,30s/^# \{0,1\}//p' "$0"; exit 2 ;; +esac +exit 0 diff --git a/src/shareos-core/usr/share/rpcd/acl.d/shareos.json b/src/shareos-core/usr/share/rpcd/acl.d/shareos.json index 2f1ba435..e4b8c512 100644 --- a/src/shareos-core/usr/share/rpcd/acl.d/shareos.json +++ b/src/shareos-core/usr/share/rpcd/acl.d/shareos.json @@ -107,6 +107,9 @@ ], "shareos.status": [ "chips" + ], + "shareos.ups": [ + "status" ] }, "uci": [ @@ -287,6 +290,9 @@ "set", "test", "telegram_chats" + ], + "shareos.ups": [ + "set" ] }, "uci": [ diff --git a/src/shareos-core/usr/share/rpcd/ucode/shareos.uc b/src/shareos-core/usr/share/rpcd/ucode/shareos.uc index 9a13d8c6..5387f4c2 100644 --- a/src/shareos-core/usr/share/rpcd/ucode/shareos.uc +++ b/src/shareos-core/usr/share/rpcd/ucode/shareos.uc @@ -841,7 +841,7 @@ function default_password() { /* ---------- settings backup ---------- */ const CRYPT = '/usr/sbin/shareos-crypt'; -const BACKUP_CONFIGS = [ 'shareos', 'storage', 'network', 'accounts', 'shares', 'paperless', 'cloud', 'apps', 'snapshots', 'dlna', 'dockerhosts', 'zabbix' ]; +const BACKUP_CONFIGS = [ 'shareos', 'storage', 'network', 'accounts', 'shares', 'paperless', 'cloud', 'apps', 'snapshots', 'dlna', 'dockerhosts', 'zabbix', 'ups' ]; const BACKUP_FILES = [ '/etc/ksmbd/ksmbdpwd.db', '/etc/ssl/shareos/server.crt', '/etc/ssl/shareos/server.key', '/etc/hostname', '/etc/timezone', '/etc/shareos/zabbix.psk' ]; function lines_of(path) { return filter(split(readfile(path) ?? '', '\n'), (l) => l != ''); } @@ -1166,6 +1166,27 @@ function dlna_status() { shares: map(filter(share_list().shares, (x) => x.volume), (x) => x.name) }; } +/* ---------- UPS (system app "nut", shareos-ups) ---------- */ + +const UPS = '/usr/sbin/shareos-ups'; +function ups_status() { + let st = {}, events = []; + for (let l in split(sh(UPS + ' status').out, '\n')) { + let m = match(l, /^([a-z_]+)=(.*)$/); + if (!m) continue; + if (m[1] == 'event') { let f = split(m[2], ' '); push(events, { time: +f[0], type: f[1] }); } + else st[m[1]] = m[2]; + } + let c = cursor(), g = (k, d) => c.get('ups', 'main', k) ?? d; + return { installed: st.installed == '1', enabled: st.enabled == '1', running: st.running == '1', detected: st.detected || null, + driver: st.driver ?? null, status: st.status ?? null, charge: st.charge != null ? +st.charge : null, + runtime: st.runtime != null ? +st.runtime : null, load: st.load != null ? +st.load : null, voltage: st.voltage != null ? +st.voltage : null, + mfr: st.mfr ?? null, model: st.model ?? null, charge_low: st.charge_low != null ? +st.charge_low : null, battery_date: st.battery_date ?? null, + events: reverse(events), + settings: { driver: g('driver', 'auto'), shutdown: g('shutdown', 'low'), percent: +g('percent', '30'), minutes: +g('minutes', '5'), + killpower: g('killpower', '1') != '0', server: g('server', '0') == '1', password_set: !!g('password', '') } }; +} + /* ---------- snapshots (rsync with hard links, shareos-snapshot) ---------- */ const SNAP = '/usr/sbin/shareos-snapshot'; @@ -3688,6 +3709,38 @@ return { } }, + 'shareos.ups': { + status: { call: function() { return ups_status(); } }, + + set: { + args: { enabled: false, driver: '', shutdown: '', percent: 0, minutes: 0, killpower: true, server: false, password: '' }, + call: function(req) { + let a = req.args, c = cursor(); + if (a.driver && !(a.driver in { auto: 1, 'usbhid-ups': 1, nutdrv_qx: 1, blazer_usb: 1 })) return { error: 'invalid driver' }; + if (a.shutdown && !(a.shutdown in { low: 1, percent: 1, minutes: 1 })) return { error: 'invalid shutdown' }; + if (a.percent != null && a.percent != 0 && (a.percent < 10 || a.percent > 90)) return { error: 'percent: 10 … 90' }; + if (a.minutes != null && a.minutes != 0 && (a.minutes < 1 || a.minutes > 120)) return { error: 'minutes: 1 … 120' }; + let pw = a.password ?? ''; + if (pw != '' && !match(pw, /^[A-Za-z0-9._-]{6,64}$/)) return { error: 'password: 6 … 64 letters, digits, . _ -' }; + c.set('ups', 'main', 'ups'); + c.set('ups', 'main', 'enabled', a.enabled === true ? '1' : '0'); + if (a.driver) c.set('ups', 'main', 'driver', a.driver); + if (a.shutdown) c.set('ups', 'main', 'shutdown', a.shutdown); + if (a.percent) c.set('ups', 'main', 'percent', '' + a.percent); + if (a.minutes) c.set('ups', 'main', 'minutes', '' + a.minutes); + if (a.killpower != null) c.set('ups', 'main', 'killpower', a.killpower ? '1' : '0'); + if (a.server != null) c.set('ups', 'main', 'server', a.server ? '1' : '0'); + if (pw != '') c.set('ups', 'main', 'password', pw); + if (a.server && !c.get('ups', 'main', 'password')) return { error: 'the network needs a password' }; + c.commit('ups'); + let r = sh(UPS + (a.enabled === true ? ' restart' : ' stop')); + let m = match(r.out, /error: ([^\n]*)/); + if (m || r.rc != 0) return { error: m ? m[1] : (trim(r.out) || 'failed') }; + return ups_status(); + } + } + }, + // chips in the header of the interface: services and apps of the account 'shareos.status': { chips: { diff --git a/src/shareos-core/www/app.js b/src/shareos-core/www/app.js index eafdb454..f86c4cc9 100644 --- a/src/shareos-core/www/app.js +++ b/src/shareos-core/www/app.js @@ -156,7 +156,7 @@ const TABS = [ ['apps', 'APPS'], ['cloud', 'CLOUD'], ['paperless', 'PAPERLESS'], ['system', 'SYSTEM'] ]; const SYS_SUBS = [['general', 'ALLGEMEIN'], ['appearance', 'DARSTELLUNG'], ['network', 'NETZWERK'], ['notifications', 'MELDUNGEN'], ['logs', 'PROTOKOLLE'], ['terminal', 'TERMINAL'], ['time', 'ZEIT'], ['power', 'ENERGIE & RESET'], ['firmware', 'FIRMWARE']]; -const SVC_SUBS = [['status', 'STATUS'], ['autostart', 'AUTOSTART'], ['dlna', 'MEDIENSERVER']]; +const SVC_SUBS = [['status', 'STATUS'], ['autostart', 'AUTOSTART'], ['dlna', 'MEDIENSERVER'], ['ups', 'USV']]; const SHR_SUBS = [['shares', 'FREIGABEN'], ['files', 'DATEIEN'], ['users', 'BENUTZER'], ['groups', 'GRUPPEN']]; const STO_SUBS = [['volumes', 'LAUFWERKE'], ['health', 'GESUNDHEIT'], ['snapshots', 'SNAPSHOTS']]; const ROLE_TXT = { admin: 'Administrator', user: 'Benutzer', share: 'Nur Freigaben' }; @@ -819,7 +819,7 @@ const VIEWS = { const sub = S.route.sub; return html` - ${sub === 'dlna' ? dlnaView() : sub === 'autostart' ? autostartView() + ${sub === 'dlna' ? dlnaView() : sub === 'ups' ? upsView() : sub === 'autostart' ? autostartView() : html`
${secHead('services', 'DIENSTE', 'Start, Stopp, Neustart')}${serviceCards(true, isTable('services'))}
`}`; }, @@ -1594,6 +1594,93 @@ function dlnaAfter() { }); } +/* ---------- UPS (Services -> UPS, system app "nut") ------------------- */ + +const UPS_EVENTS = { ONBATT: 'Stromausfall – läuft über die USV', ONLINE: 'Strom wieder da', LOWBATT: 'Akku fast leer', FSD: 'Herunterfahren ausgelöst', SHUTDOWN: 'Box fährt herunter', COMMBAD: 'Verbindung zur USV verloren', NOCOMM: 'Keine Verbindung zur USV', COMMOK: 'Verbindung zur USV wieder da', REPLBATT: 'Akku tauschen' }; + +async function loadUps() { + clearTimeout(S.upsTimer); + try { S.ups = await rpc('shareos.ups', 'status'); } catch (e) { toast('USV: ' + e.message, true); } + if (S.route.tab === 'services' && S.route.sub === 'ups') { + if (!document.activeElement?.matches('input,select')) renderMain(); + S.upsTimer = setTimeout(loadUps, S.ups?.running ? 5000 : 15000); + } +} + +function upsView() { + const d = S.ups; + if (!d) return html`
Lade USV …
`; + if (!d.installed) return html`
${svg(I.info)}
+ Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter. +
`; + const st = (d.status || '').split(' '); + const ob = st.includes('OB'), lb = st.includes('LB'); + const s = d.settings, mode = s.shutdown; + const host = location.hostname; + return html`
+
+
+
USV${!d.running ? html`aus` : lb ? html`Akku fast leer` : ob ? html`läuft über Akku` : d.status ? html`am Netz` : html`keine Daten`}
+ ${d.running && d.status ? html`
+
AKKU
${d.charge != null ? d.charge + ' %' : '–'}
+
RESTLAUFZEIT
${d.runtime != null ? Math.round(d.runtime / 60) + ' min' : '–'}
+
LAST
${d.load != null ? d.load + ' %' : '–'}
+
+
Gerät
${[d.mfr, d.model].filter(Boolean).join(' ') || '–'}
+ ${d.voltage != null ? html`
Netzspannung
${d.voltage} V
` : ''} + ${d.battery_date ? html`
Akku seit
${d.battery_date}
` : ''} +
Treiber
${d.driver || '–'}
+
` + : d.running ? html`

Verbinde mit der USV …

` + : html`

${d.detected ? html`Erkannt: ${d.detected}. ` : ''}Unten einschalten.

`} +
+
+
EREIGNISSE
+ ${d.events.length ? html`
${d.events.map((e) => html`
${fmtTime(e.time)} · ${UPS_EVENTS[e.type] || e.type}
`)}
` + : html`

Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.

`} +
+
+
+
+
EINSTELLUNGEN
+ +
+ + + + +
+ + +
+ +
+ ${s.server ? html`

Auf dem anderen Rechner (NUT, upsmon): MONITOR ups@${host} 1 monitor ••• secondary – er fährt dann vor der Box herunter.

` : ''} +

Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.

+
+
`; +} + +function upsAfter() { + if (!S.ups) { loadUps(); return; } + if (!S.upsTimer) S.upsTimer = setTimeout(loadUps, 5000); + $('#ups-mode')?.addEventListener('change', (e) => { $('#ups-pct').hidden = e.target.value !== 'percent'; $('#ups-min').hidden = e.target.value !== 'minutes'; }); + $('#ups-server')?.addEventListener('change', (e) => { $('#ups-net').hidden = !e.target.checked; }); + $('#f-ups')?.addEventListener('submit', async (e) => { + e.preventDefault(); + const f = e.target, b = $('button[type=submit]', f); b.disabled = true; + const v = { enabled: f.enabled.checked, shutdown: f.shutdown.value, driver: f.driver.value, killpower: f.killpower.checked, server: f.server.checked, password: f.password.value }; + if (v.shutdown === 'percent') v.percent = +f.percent.value; + if (v.shutdown === 'minutes') v.minutes = +f.minutes.value; + try { S.ups = await rpc('shareos.ups', 'set', v); toast('USV gespeichert.'); } + catch (err) { toast('USV: ' + err.message, true); } + loadUps(); + }); +} + function snapForm() { const f = $('#f-snap'); const keep = {}; @@ -3159,6 +3246,7 @@ const VIEWS_AFTER = { }, services() { if (S.route.sub === 'dlna') { dlnaAfter(); return; } + if (S.route.sub === 'ups') { upsAfter(); return; } if (!S.services) loadServices(); document.querySelectorAll('.as-toggle').forEach((c) => c.addEventListener('change', async () => { c.disabled = true; @@ -4075,6 +4163,7 @@ window.addEventListener('hashchange', () => { if (S.route.tab !== 'storage' || S.route.sub !== 'snapshots') { clearTimeout(S.snapTimer); if (S.snap) { S.snap.edit = null; S.snap.log = null; } } if (S.route.tab !== 'shares') { S.shEdit = null; S.uEdit = null; } if (S.route.tab !== 'services' || S.route.sub !== 'dlna') clearTimeout(S.dlnaTimer); + if (S.route.tab !== 'services' || S.route.sub !== 'ups') { clearTimeout(S.upsTimer); S.upsTimer = null; } if (S.fb && S.route.sub === 'files') S.fb.roots = null; // volumes may have changed if (S.route.tab !== 'paperless') { S.plEdit = null; S.plLog = null; } else if (S.pl) loadPaperless(); if (S.route.tab !== 'cloud') { clearTimeout(S.cloudTimer); if (S.cloud?.scope === 'admin') { S.cloud.remoteEdit = null; S.cloud.jobEdit = null; S.cloud.log = null; } } diff --git a/src/shareos-core/www/i18n/ar.json b/src/shareos-core/www/i18n/ar.json index f79dcb32..bd0d4776 100644 --- a/src/shareos-core/www/i18n/ar.json +++ b/src/shareos-core/www/i18n/ar.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "لم تُضبط أوقات.", "GERÄT & ZUGANG": "الجهاز والوصول", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "النجمة تجعل التطبيق مفضلاً – تظهر المفضلة أعلى «ShareOS الخاص بي».", - "Alle Hinweise anzeigen": "عرض كل التنبيهات" + "Alle Hinweise anzeigen": "عرض كل التنبيهات", + "USV": "UPS", + "Lade USV …": "جارٍ تحميل UPS …", + "Im Store installieren (Network UPS Tools)": "التثبيت من المتجر (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "دعم UPS تطبيق نظام: يعرض الجهاز الشحن ووقت التشغيل المتبقي، ويبلّغ عن انقطاع الكهرباء ويُغلق بشكل سليم في الوقت المناسب.", + "Akku fast leer": "البطارية شبه فارغة", + "läuft über Akku": "يعمل على البطارية", + "am Netz": "على الكهرباء", + "keine Daten": "لا بيانات", + "AKKU": "البطارية", + "RESTLAUFZEIT": "الوقت المتبقي", + "LAST": "الحِمل", + "Netzspannung": "جهد الشبكة", + "Akku seit": "البطارية منذ", + "Treiber": "برنامج التشغيل", + "Verbinde mit der USV …": "جارٍ الاتصال بـ UPS …", + "Erkannt:": "تم الاكتشاف:", + "Unten einschalten.": "شغّله أدناه.", + "EREIGNISSE": "الأحداث", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "لا شيء بعد – يظهر انقطاع الكهرباء هنا وكرسالة.", + "Stromausfall – läuft über die USV": "انقطاع الكهرباء – يعمل على UPS", + "Strom wieder da": "عادت الكهرباء", + "Herunterfahren ausgelöst": "تم تفعيل الإيقاف", + "Box fährt herunter": "الجهاز يُغلق", + "Verbindung zur USV verloren": "انقطع الاتصال بـ UPS", + "Keine Verbindung zur USV": "لا اتصال بـ UPS", + "Verbindung zur USV wieder da": "عاد الاتصال بـ UPS", + "Akku tauschen": "استبدل البطارية", + "USV überwachen (startet auch nach einem Neustart)": "مراقبة UPS (تبدأ أيضًا بعد إعادة التشغيل)", + "HERUNTERFAHREN": "الإيقاف", + "Wenn die USV „Akku fast leer“ meldet": "عندما يبلّغ UPS عن «بطارية منخفضة»", + "Unter einem Akkustand": "تحت نسبة شحن", + "Nach einer Zeit auf Akku": "بعد مدة على البطارية", + "AKKUSTAND (%)": "شحن البطارية (%)", + "MINUTEN AUF AKKU": "دقائق على البطارية", + "TREIBER": "برنامج التشغيل", + "Automatisch": "تلقائي", + "blazer_usb (ältere Megatec)": "blazer_usb (Megatec الأقدم)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "ثم إيقاف UPS – يبدأ الجهاز مجددًا عند عودة الكهرباء", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "يمكن لأجهزة أخرى قراءة UPS عبر الشبكة (المنفذ 3493)", + "PASSWORT FÜR „MONITOR“": "كلمة المرور لـ «MONITOR»", + "gespeichert – leer lassen behält es": "محفوظة – اتركها فارغة للإبقاء عليها", + "Auf dem anderen Rechner (NUT, upsmon):": "على الحاسوب الآخر (NUT، upsmon):", + "– er fährt dann vor der Box herunter.": "– وعندها يُغلق قبل الجهاز.", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "لا يُغلق الجهاز إلا أثناء عمله على البطارية. إذا عادت الكهرباء قبل ذلك فلا يحدث شيء.", + "USV gespeichert.": "تم حفظ UPS." }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/bn.json b/src/shareos-core/www/i18n/bn.json index b0c402a6..0acbeba8 100644 --- a/src/shareos-core/www/i18n/bn.json +++ b/src/shareos-core/www/i18n/bn.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "কোনো সময় সেট করা নেই।", "GERÄT & ZUGANG": "ডিভাইস ও অ্যাক্সেস", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "তারকা দিয়ে অ্যাপ প্রিয় হয় – প্রিয়গুলি \"আমার ShareOS\"-এর উপরে দেখায়।", - "Alle Hinweise anzeigen": "সব বিজ্ঞপ্তি দেখান" + "Alle Hinweise anzeigen": "সব বিজ্ঞপ্তি দেখান", + "USV": "UPS", + "Lade USV …": "UPS লোড হচ্ছে …", + "Im Store installieren (Network UPS Tools)": "স্টোর থেকে ইনস্টল করুন (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "UPS সাপোর্ট একটি সিস্টেম অ্যাপ: বক্স চার্জ ও বাকি সময় দেখায়, বিদ্যুৎ চলে গেলে জানায় এবং সময়মতো ঠিকভাবে বন্ধ হয়।", + "Akku fast leer": "ব্যাটারি প্রায় শেষ", + "läuft über Akku": "ব্যাটারিতে চলছে", + "am Netz": "বিদ্যুৎ লাইনে", + "keine Daten": "কোনো ডেটা নেই", + "AKKU": "ব্যাটারি", + "RESTLAUFZEIT": "বাকি সময়", + "LAST": "লোড", + "Netzspannung": "লাইন ভোল্টেজ", + "Akku seit": "ব্যাটারি কবে থেকে", + "Treiber": "ড্রাইভার", + "Verbinde mit der USV …": "UPS-এ সংযোগ হচ্ছে …", + "Erkannt:": "শনাক্ত:", + "Unten einschalten.": "নিচে চালু করুন।", + "EREIGNISSE": "ঘটনা", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "এখনো নেই – বিদ্যুৎ গেলে এখানে ও বার্তা হিসেবে দেখাবে।", + "Stromausfall – läuft über die USV": "বিদ্যুৎ বিভ্রাট – UPS-এ চলছে", + "Strom wieder da": "বিদ্যুৎ ফিরে এসেছে", + "Herunterfahren ausgelöst": "শাটডাউন শুরু", + "Box fährt herunter": "বক্স বন্ধ হচ্ছে", + "Verbindung zur USV verloren": "UPS-এর সাথে সংযোগ বিচ্ছিন্ন", + "Keine Verbindung zur USV": "UPS-এর সাথে সংযোগ নেই", + "Verbindung zur USV wieder da": "UPS-এর সাথে সংযোগ ফিরে এসেছে", + "Akku tauschen": "ব্যাটারি বদলান", + "USV überwachen (startet auch nach einem Neustart)": "UPS নজরে রাখুন (রিস্টার্টের পরেও চালু হবে)", + "HERUNTERFAHREN": "শাটডাউন", + "Wenn die USV „Akku fast leer“ meldet": "যখন UPS “ব্যাটারি কম” জানায়", + "Unter einem Akkustand": "একটি চার্জের নিচে", + "Nach einer Zeit auf Akku": "ব্যাটারিতে কিছু সময় পরে", + "AKKUSTAND (%)": "ব্যাটারি চার্জ (%)", + "MINUTEN AUF AKKU": "ব্যাটারিতে মিনিট", + "TREIBER": "ড্রাইভার", + "Automatisch": "স্বয়ংক্রিয়", + "blazer_usb (ältere Megatec)": "blazer_usb (পুরোনো Megatec)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "তারপর UPS বন্ধ করুন – বিদ্যুৎ ফিরলে বক্স আবার চালু হবে", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "অন্য কম্পিউটার নেটওয়ার্কে UPS পড়তে পারবে (পোর্ট 3493)", + "PASSWORT FÜR „MONITOR“": "“MONITOR”-এর পাসওয়ার্ড", + "gespeichert – leer lassen behält es": "সংরক্ষিত – ফাঁকা রাখলে আগেরটাই থাকবে", + "Auf dem anderen Rechner (NUT, upsmon):": "অন্য কম্পিউটারে (NUT, upsmon):", + "– er fährt dann vor der Box herunter.": "– তখন সেটি বক্সের আগে বন্ধ হবে।", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "বক্স কেবল ব্যাটারিতে চলার সময়ই বন্ধ হয়। আগে বিদ্যুৎ ফিরলে কিছুই হয় না।", + "USV gespeichert.": "UPS সংরক্ষিত।" }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/en.json b/src/shareos-core/www/i18n/en.json index 0e9102d6..dd905524 100644 --- a/src/shareos-core/www/i18n/en.json +++ b/src/shareos-core/www/i18n/en.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "No times set up.", "GERÄT & ZUGANG": "DEVICE & ACCESS", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "The star makes an app a favourite – favourites are shown at the top of “My ShareOS”.", - "Alle Hinweise anzeigen": "Show all notices" + "Alle Hinweise anzeigen": "Show all notices", + "USV": "UPS", + "Lade USV …": "Loading UPS …", + "Im Store installieren (Network UPS Tools)": "Install from the store (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "UPS support is a system app: the box then shows charge and runtime, reports a power failure and shuts down cleanly in time.", + "Akku fast leer": "Battery almost empty", + "läuft über Akku": "on battery", + "am Netz": "on mains", + "keine Daten": "no data", + "AKKU": "BATTERY", + "RESTLAUFZEIT": "RUNTIME", + "LAST": "LOAD", + "Netzspannung": "Mains voltage", + "Akku seit": "Battery since", + "Treiber": "Driver", + "Verbinde mit der USV …": "Connecting to the UPS …", + "Erkannt:": "Detected:", + "Unten einschalten.": "Switch it on below.", + "EREIGNISSE": "EVENTS", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "None yet – a power failure is shown here and as a message.", + "Stromausfall – läuft über die USV": "Power failure – running on the UPS", + "Strom wieder da": "Power is back", + "Herunterfahren ausgelöst": "Shutdown triggered", + "Box fährt herunter": "Box shuts down", + "Verbindung zur USV verloren": "Connection to the UPS lost", + "Keine Verbindung zur USV": "No connection to the UPS", + "Verbindung zur USV wieder da": "Connection to the UPS is back", + "Akku tauschen": "Replace the battery", + "USV überwachen (startet auch nach einem Neustart)": "Monitor the UPS (also starts after a restart)", + "HERUNTERFAHREN": "SHUT DOWN", + "Wenn die USV „Akku fast leer“ meldet": "When the UPS reports “battery low”", + "Unter einem Akkustand": "Below a battery charge", + "Nach einer Zeit auf Akku": "After some time on battery", + "AKKUSTAND (%)": "BATTERY CHARGE (%)", + "MINUTEN AUF AKKU": "MINUTES ON BATTERY", + "TREIBER": "DRIVER", + "Automatisch": "Automatic", + "blazer_usb (ältere Megatec)": "blazer_usb (older Megatec)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "Then switch the UPS off – the box starts again when the power is back", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "Other computers may read the UPS over the network (port 3493)", + "PASSWORT FÜR „MONITOR“": "PASSWORD FOR “MONITOR”", + "gespeichert – leer lassen behält es": "saved – leave empty to keep it", + "Auf dem anderen Rechner (NUT, upsmon):": "On the other computer (NUT, upsmon):", + "– er fährt dann vor der Box herunter.": "– it then shuts down before the box.", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "The box only shuts down while it runs on battery. If the power comes back before, nothing happens.", + "USV gespeichert.": "UPS saved." }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/es.json b/src/shareos-core/www/i18n/es.json index 03f6f19b..1e281147 100644 --- a/src/shareos-core/www/i18n/es.json +++ b/src/shareos-core/www/i18n/es.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "No hay horas configuradas.", "GERÄT & ZUGANG": "EQUIPO Y ACCESO", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "La estrella convierte una app en favorita: las favoritas aparecen arriba en «Mi ShareOS».", - "Alle Hinweise anzeigen": "Mostrar todos los avisos" + "Alle Hinweise anzeigen": "Mostrar todos los avisos", + "USV": "SAI", + "Lade USV …": "Cargando SAI …", + "Im Store installieren (Network UPS Tools)": "Instalar desde la tienda (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "El soporte de SAI es una app del sistema: la caja muestra la carga y la autonomía, avisa de un corte de luz y se apaga a tiempo de forma limpia.", + "Akku fast leer": "Batería casi vacía", + "läuft über Akku": "con batería", + "am Netz": "con red eléctrica", + "keine Daten": "sin datos", + "AKKU": "BATERÍA", + "RESTLAUFZEIT": "AUTONOMÍA", + "LAST": "CARGA", + "Netzspannung": "Tensión de red", + "Akku seit": "Batería desde", + "Treiber": "Controlador", + "Verbinde mit der USV …": "Conectando con el SAI …", + "Erkannt:": "Detectado:", + "Unten einschalten.": "Actívalo abajo.", + "EREIGNISSE": "EVENTOS", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "Ninguno aún – un corte de luz se muestra aquí y como mensaje.", + "Stromausfall – läuft über die USV": "Corte de luz – funcionando con el SAI", + "Strom wieder da": "Vuelve la luz", + "Herunterfahren ausgelöst": "Apagado iniciado", + "Box fährt herunter": "La caja se apaga", + "Verbindung zur USV verloren": "Conexión con el SAI perdida", + "Keine Verbindung zur USV": "Sin conexión con el SAI", + "Verbindung zur USV wieder da": "Conexión con el SAI restablecida", + "Akku tauschen": "Cambiar la batería", + "USV überwachen (startet auch nach einem Neustart)": "Supervisar el SAI (también arranca tras reiniciar)", + "HERUNTERFAHREN": "APAGADO", + "Wenn die USV „Akku fast leer“ meldet": "Cuando el SAI avisa de «batería baja»", + "Unter einem Akkustand": "Por debajo de una carga", + "Nach einer Zeit auf Akku": "Tras un tiempo con batería", + "AKKUSTAND (%)": "CARGA DE LA BATERÍA (%)", + "MINUTEN AUF AKKU": "MINUTOS CON BATERÍA", + "TREIBER": "CONTROLADOR", + "Automatisch": "Automático", + "blazer_usb (ältere Megatec)": "blazer_usb (Megatec antiguos)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "Después apagar el SAI – la caja arranca de nuevo al volver la luz", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "Otros ordenadores pueden leer el SAI por la red (puerto 3493)", + "PASSWORT FÜR „MONITOR“": "CONTRASEÑA PARA «MONITOR»", + "gespeichert – leer lassen behält es": "guardada – déjala vacía para conservarla", + "Auf dem anderen Rechner (NUT, upsmon):": "En el otro ordenador (NUT, upsmon):", + "– er fährt dann vor der Box herunter.": "– entonces se apaga antes que la caja.", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "La caja solo se apaga mientras funciona con batería. Si la luz vuelve antes, no pasa nada.", + "USV gespeichert.": "SAI guardado." }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/fr.json b/src/shareos-core/www/i18n/fr.json index 53480eb2..aee8ec62 100644 --- a/src/shareos-core/www/i18n/fr.json +++ b/src/shareos-core/www/i18n/fr.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "Aucune heure définie.", "GERÄT & ZUGANG": "APPAREIL & ACCÈS", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "L’étoile fait d’une app un favori – les favoris apparaissent en haut de « Mon ShareOS ».", - "Alle Hinweise anzeigen": "Afficher toutes les notifications" + "Alle Hinweise anzeigen": "Afficher toutes les notifications", + "USV": "ONDULEUR", + "Lade USV …": "Chargement de l'onduleur …", + "Im Store installieren (Network UPS Tools)": "Installer depuis le store (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "La prise en charge de l'onduleur est une application système : la box affiche alors la charge et l'autonomie, signale une coupure de courant et s'arrête proprement à temps.", + "Akku fast leer": "Batterie presque vide", + "läuft über Akku": "sur batterie", + "am Netz": "sur secteur", + "keine Daten": "pas de données", + "AKKU": "BATTERIE", + "RESTLAUFZEIT": "AUTONOMIE", + "LAST": "CHARGE", + "Netzspannung": "Tension secteur", + "Akku seit": "Batterie depuis", + "Treiber": "Pilote", + "Verbinde mit der USV …": "Connexion à l'onduleur …", + "Erkannt:": "Détecté :", + "Unten einschalten.": "Activez-le ci-dessous.", + "EREIGNISSE": "ÉVÉNEMENTS", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "Aucun pour l'instant – une coupure de courant s'affiche ici et comme message.", + "Stromausfall – läuft über die USV": "Coupure de courant – sur onduleur", + "Strom wieder da": "Courant rétabli", + "Herunterfahren ausgelöst": "Arrêt déclenché", + "Box fährt herunter": "La box s'arrête", + "Verbindung zur USV verloren": "Connexion à l'onduleur perdue", + "Keine Verbindung zur USV": "Pas de connexion à l'onduleur", + "Verbindung zur USV wieder da": "Connexion à l'onduleur rétablie", + "Akku tauschen": "Remplacer la batterie", + "USV überwachen (startet auch nach einem Neustart)": "Surveiller l'onduleur (démarre aussi après un redémarrage)", + "HERUNTERFAHREN": "ARRÊT", + "Wenn die USV „Akku fast leer“ meldet": "Quand l'onduleur signale « batterie faible »", + "Unter einem Akkustand": "Sous un niveau de charge", + "Nach einer Zeit auf Akku": "Après un temps sur batterie", + "AKKUSTAND (%)": "CHARGE DE LA BATTERIE (%)", + "MINUTEN AUF AKKU": "MINUTES SUR BATTERIE", + "TREIBER": "PILOTE", + "Automatisch": "Automatique", + "blazer_usb (ältere Megatec)": "blazer_usb (anciens Megatec)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "Ensuite éteindre l'onduleur – la box redémarre au retour du courant", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "D'autres ordinateurs peuvent lire l'onduleur via le réseau (port 3493)", + "PASSWORT FÜR „MONITOR“": "MOT DE PASSE POUR « MONITOR »", + "gespeichert – leer lassen behält es": "enregistré – laisser vide pour le conserver", + "Auf dem anderen Rechner (NUT, upsmon):": "Sur l'autre ordinateur (NUT, upsmon) :", + "– er fährt dann vor der Box herunter.": "– il s'arrête alors avant la box.", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "La box ne s'arrête que tant qu'elle est sur batterie. Si le courant revient avant, rien ne se passe.", + "USV gespeichert.": "Onduleur enregistré." }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/hi.json b/src/shareos-core/www/i18n/hi.json index 36ed0fd8..2ad8e92e 100644 --- a/src/shareos-core/www/i18n/hi.json +++ b/src/shareos-core/www/i18n/hi.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "कोई समय सेट नहीं है।", "GERÄT & ZUGANG": "डिवाइस और पहुँच", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "स्टार से ऐप पसंदीदा बनता है – पसंदीदा \"मेरा ShareOS\" के ऊपर दिखते हैं।", - "Alle Hinweise anzeigen": "सभी सूचनाएँ दिखाएँ" + "Alle Hinweise anzeigen": "सभी सूचनाएँ दिखाएँ", + "USV": "UPS", + "Lade USV …": "UPS लोड हो रहा है …", + "Im Store installieren (Network UPS Tools)": "स्टोर से इंस्टॉल करें (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "UPS सपोर्ट एक सिस्टम ऐप है: बॉक्स चार्ज और शेष समय दिखाता है, बिजली जाने की सूचना देता है और समय पर ठीक से बंद होता है।", + "Akku fast leer": "बैटरी लगभग खाली", + "läuft über Akku": "बैटरी पर", + "am Netz": "मेन्स पर", + "keine Daten": "कोई डेटा नहीं", + "AKKU": "बैटरी", + "RESTLAUFZEIT": "शेष समय", + "LAST": "लोड", + "Netzspannung": "मेन्स वोल्टेज", + "Akku seit": "बैटरी कब से", + "Treiber": "ड्राइवर", + "Verbinde mit der USV …": "UPS से जुड़ रहा है …", + "Erkannt:": "पहचाना गया:", + "Unten einschalten.": "नीचे चालू करें।", + "EREIGNISSE": "घटनाएँ", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "अभी कोई नहीं – बिजली जाने पर यहाँ और संदेश के रूप में दिखेगा।", + "Stromausfall – läuft über die USV": "बिजली गई – UPS पर चल रहा है", + "Strom wieder da": "बिजली वापस आई", + "Herunterfahren ausgelöst": "शटडाउन शुरू", + "Box fährt herunter": "बॉक्स बंद हो रहा है", + "Verbindung zur USV verloren": "UPS से कनेक्शन टूटा", + "Keine Verbindung zur USV": "UPS से कोई कनेक्शन नहीं", + "Verbindung zur USV wieder da": "UPS से कनेक्शन वापस आया", + "Akku tauschen": "बैटरी बदलें", + "USV überwachen (startet auch nach einem Neustart)": "UPS की निगरानी करें (रीस्टार्ट के बाद भी शुरू होगा)", + "HERUNTERFAHREN": "शटडाउन", + "Wenn die USV „Akku fast leer“ meldet": "जब UPS “बैटरी कम” बताए", + "Unter einem Akkustand": "एक चार्ज स्तर से नीचे", + "Nach einer Zeit auf Akku": "बैटरी पर कुछ समय बाद", + "AKKUSTAND (%)": "बैटरी चार्ज (%)", + "MINUTEN AUF AKKU": "बैटरी पर मिनट", + "TREIBER": "ड्राइवर", + "Automatisch": "स्वचालित", + "blazer_usb (ältere Megatec)": "blazer_usb (पुराने Megatec)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "फिर UPS बंद करें – बिजली लौटने पर बॉक्स फिर शुरू होगा", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "दूसरे कंप्यूटर नेटवर्क से UPS पढ़ सकते हैं (पोर्ट 3493)", + "PASSWORT FÜR „MONITOR“": "“MONITOR” के लिए पासवर्ड", + "gespeichert – leer lassen behält es": "सहेजा गया – खाली छोड़ें तो वही रहेगा", + "Auf dem anderen Rechner (NUT, upsmon):": "दूसरे कंप्यूटर पर (NUT, upsmon):", + "– er fährt dann vor der Box herunter.": "– तब वह बॉक्स से पहले बंद होगा।", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "बॉक्स तभी बंद होता है जब वह बैटरी पर चल रहा हो। बिजली पहले लौट आए तो कुछ नहीं होता।", + "USV gespeichert.": "UPS सहेजा गया।" }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/pt.json b/src/shareos-core/www/i18n/pt.json index 149669b3..79ab9fd5 100644 --- a/src/shareos-core/www/i18n/pt.json +++ b/src/shareos-core/www/i18n/pt.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "Nenhum horário configurado.", "GERÄT & ZUGANG": "EQUIPAMENTO E ACESSO", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "A estrela torna um app favorito – os favoritos aparecem no topo de “Meu ShareOS”.", - "Alle Hinweise anzeigen": "Mostrar todos os avisos" + "Alle Hinweise anzeigen": "Mostrar todos os avisos", + "USV": "UPS", + "Lade USV …": "A carregar UPS …", + "Im Store installieren (Network UPS Tools)": "Instalar a partir da loja (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "O suporte a UPS é uma app de sistema: a caixa mostra a carga e a autonomia, avisa de um corte de energia e desliga-se a tempo de forma limpa.", + "Akku fast leer": "Bateria quase vazia", + "läuft über Akku": "em bateria", + "am Netz": "na rede elétrica", + "keine Daten": "sem dados", + "AKKU": "BATERIA", + "RESTLAUFZEIT": "AUTONOMIA", + "LAST": "CARGA", + "Netzspannung": "Tensão da rede", + "Akku seit": "Bateria desde", + "Treiber": "Controlador", + "Verbinde mit der USV …": "A ligar à UPS …", + "Erkannt:": "Detetado:", + "Unten einschalten.": "Ligue-o abaixo.", + "EREIGNISSE": "EVENTOS", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "Nenhum ainda – um corte de energia aparece aqui e como mensagem.", + "Stromausfall – läuft über die USV": "Corte de energia – a funcionar com a UPS", + "Strom wieder da": "Energia reposta", + "Herunterfahren ausgelöst": "Encerramento iniciado", + "Box fährt herunter": "A caixa está a desligar", + "Verbindung zur USV verloren": "Ligação à UPS perdida", + "Keine Verbindung zur USV": "Sem ligação à UPS", + "Verbindung zur USV wieder da": "Ligação à UPS restabelecida", + "Akku tauschen": "Substituir a bateria", + "USV überwachen (startet auch nach einem Neustart)": "Monitorizar a UPS (também arranca após reiniciar)", + "HERUNTERFAHREN": "ENCERRAR", + "Wenn die USV „Akku fast leer“ meldet": "Quando a UPS indica «bateria fraca»", + "Unter einem Akkustand": "Abaixo de uma carga", + "Nach einer Zeit auf Akku": "Após algum tempo em bateria", + "AKKUSTAND (%)": "CARGA DA BATERIA (%)", + "MINUTEN AUF AKKU": "MINUTOS EM BATERIA", + "TREIBER": "CONTROLADOR", + "Automatisch": "Automático", + "blazer_usb (ältere Megatec)": "blazer_usb (Megatec antigos)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "Depois desligar a UPS – a caixa volta a arrancar quando a energia regressar", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "Outros computadores podem ler a UPS pela rede (porta 3493)", + "PASSWORT FÜR „MONITOR“": "PALAVRA-PASSE PARA «MONITOR»", + "gespeichert – leer lassen behält es": "guardada – deixe vazio para a manter", + "Auf dem anderen Rechner (NUT, upsmon):": "No outro computador (NUT, upsmon):", + "– er fährt dann vor der Box herunter.": "– então desliga-se antes da caixa.", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "A caixa só se desliga enquanto estiver em bateria. Se a energia voltar antes, nada acontece.", + "USV gespeichert.": "UPS guardada." }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/ru.json b/src/shareos-core/www/i18n/ru.json index 7e776ee1..fdb31338 100644 --- a/src/shareos-core/www/i18n/ru.json +++ b/src/shareos-core/www/i18n/ru.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "Время не задано.", "GERÄT & ZUGANG": "УСТРОЙСТВО И ДОСТУП", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "Звёздочка делает приложение избранным – избранные показаны вверху «Мой ShareOS».", - "Alle Hinweise anzeigen": "Показать все уведомления" + "Alle Hinweise anzeigen": "Показать все уведомления", + "USV": "ИБП", + "Lade USV …": "Загрузка ИБП …", + "Im Store installieren (Network UPS Tools)": "Установить из магазина (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "Поддержка ИБП – системное приложение: устройство показывает заряд и время работы, сообщает об отключении питания и вовремя корректно выключается.", + "Akku fast leer": "Батарея почти разряжена", + "läuft über Akku": "от батареи", + "am Netz": "от сети", + "keine Daten": "нет данных", + "AKKU": "БАТАРЕЯ", + "RESTLAUFZEIT": "ВРЕМЯ РАБОТЫ", + "LAST": "НАГРУЗКА", + "Netzspannung": "Напряжение сети", + "Akku seit": "Батарея с", + "Treiber": "Драйвер", + "Verbinde mit der USV …": "Подключение к ИБП …", + "Erkannt:": "Обнаружено:", + "Unten einschalten.": "Включите ниже.", + "EREIGNISSE": "СОБЫТИЯ", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "Пока нет – отключение питания появится здесь и в сообщениях.", + "Stromausfall – läuft über die USV": "Отключение питания – работа от ИБП", + "Strom wieder da": "Питание восстановлено", + "Herunterfahren ausgelöst": "Запущено выключение", + "Box fährt herunter": "Устройство выключается", + "Verbindung zur USV verloren": "Связь с ИБП потеряна", + "Keine Verbindung zur USV": "Нет связи с ИБП", + "Verbindung zur USV wieder da": "Связь с ИБП восстановлена", + "Akku tauschen": "Замените батарею", + "USV überwachen (startet auch nach einem Neustart)": "Следить за ИБП (запускается и после перезагрузки)", + "HERUNTERFAHREN": "ВЫКЛЮЧЕНИЕ", + "Wenn die USV „Akku fast leer“ meldet": "Когда ИБП сообщает «батарея разряжена»", + "Unter einem Akkustand": "Ниже уровня заряда", + "Nach einer Zeit auf Akku": "Через время работы от батареи", + "AKKUSTAND (%)": "ЗАРЯД БАТАРЕИ (%)", + "MINUTEN AUF AKKU": "МИНУТ ОТ БАТАРЕИ", + "TREIBER": "ДРАЙВЕР", + "Automatisch": "Автоматически", + "blazer_usb (ältere Megatec)": "blazer_usb (старые Megatec)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "Затем выключить ИБП – устройство снова запустится при появлении питания", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "Другие компьютеры могут читать данные ИБП по сети (порт 3493)", + "PASSWORT FÜR „MONITOR“": "ПАРОЛЬ ДЛЯ «MONITOR»", + "gespeichert – leer lassen behält es": "сохранён – оставьте пустым, чтобы не менять", + "Auf dem anderen Rechner (NUT, upsmon):": "На другом компьютере (NUT, upsmon):", + "– er fährt dann vor der Box herunter.": "– тогда он выключится раньше устройства.", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "Устройство выключается, только пока работает от батареи. Если питание вернётся раньше, ничего не произойдёт.", + "USV gespeichert.": "ИБП сохранён." }, "patterns": [ [ diff --git a/src/shareos-core/www/i18n/zh.json b/src/shareos-core/www/i18n/zh.json index 7d0e0394..a1b3afaa 100644 --- a/src/shareos-core/www/i18n/zh.json +++ b/src/shareos-core/www/i18n/zh.json @@ -1274,7 +1274,52 @@ "Keine Zeiten eingerichtet.": "未设置时间。", "GERÄT & ZUGANG": "设备与访问", "Mit dem Stern wird eine App zum Favoriten – Favoriten stehen oben auf „Mein ShareOS“.": "星标可将应用设为收藏——收藏显示在“我的 ShareOS”顶部。", - "Alle Hinweise anzeigen": "显示所有提示" + "Alle Hinweise anzeigen": "显示所有提示", + "USV": "UPS", + "Lade USV …": "正在加载 UPS……", + "Im Store installieren (Network UPS Tools)": "从商店安装 (Network UPS Tools)", + "Die USV-Unterstützung ist eine System-App: Die Box zeigt dann Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter.": "UPS 支持是一个系统应用:设备会显示电量和剩余时间,报告停电并及时安全关机。", + "Akku fast leer": "电池电量低", + "läuft über Akku": "电池供电中", + "am Netz": "市电供电", + "keine Daten": "无数据", + "AKKU": "电池", + "RESTLAUFZEIT": "剩余时间", + "LAST": "负载", + "Netzspannung": "市电电压", + "Akku seit": "电池启用于", + "Treiber": "驱动", + "Verbinde mit der USV …": "正在连接 UPS……", + "Erkannt:": "已检测到:", + "Unten einschalten.": "在下方启用。", + "EREIGNISSE": "事件", + "Noch keine – ein Stromausfall wird hier und als Meldung angezeigt.": "暂无——停电会显示在这里并作为消息通知。", + "Stromausfall – läuft über die USV": "停电——由 UPS 供电", + "Strom wieder da": "供电恢复", + "Herunterfahren ausgelöst": "已触发关机", + "Box fährt herunter": "设备正在关机", + "Verbindung zur USV verloren": "与 UPS 的连接中断", + "Keine Verbindung zur USV": "无法连接 UPS", + "Verbindung zur USV wieder da": "与 UPS 的连接已恢复", + "Akku tauschen": "更换电池", + "USV überwachen (startet auch nach einem Neustart)": "监控 UPS(重启后也会启动)", + "HERUNTERFAHREN": "关机", + "Wenn die USV „Akku fast leer“ meldet": "当 UPS 报告“电池电量低”时", + "Unter einem Akkustand": "低于某电量时", + "Nach einer Zeit auf Akku": "电池供电一段时间后", + "AKKUSTAND (%)": "电池电量 (%)", + "MINUTEN AUF AKKU": "电池供电分钟数", + "TREIBER": "驱动", + "Automatisch": "自动", + "blazer_usb (ältere Megatec)": "blazer_usb(旧款 Megatec)", + "Danach die USV ausschalten – die Box startet wieder, wenn der Strom zurück ist": "随后关闭 UPS——供电恢复时设备会重新启动", + "Andere Rechner dürfen die USV über das Netzwerk lesen (Port 3493)": "允许其他电脑通过网络读取 UPS(端口 3493)", + "PASSWORT FÜR „MONITOR“": "“MONITOR”的密码", + "gespeichert – leer lassen behält es": "已保存——留空则保留", + "Auf dem anderen Rechner (NUT, upsmon):": "在另一台电脑上(NUT、upsmon):", + "– er fährt dann vor der Box herunter.": "——它会在本设备之前关机。", + "Die Box fährt nur herunter, solange sie über Akku läuft. Kommt der Strom vorher zurück, passiert nichts.": "只有在电池供电期间设备才会关机。如果在此之前恢复供电,则不会发生任何事。", + "USV gespeichert.": "UPS 设置已保存。" }, "patterns": [ [ diff --git a/sysapps/nut/app.json b/sysapps/nut/app.json new file mode 100644 index 00000000..9f725a1c --- /dev/null +++ b/sysapps/nut/app.json @@ -0,0 +1,19 @@ +{ + "id": "nut", + "name": "Network UPS Tools", + "version": "2.8.5", + "publisher": "UniqueDroid", + "description": { + "de": "USV (unterbrechungsfreie Stromversorgung) über USB: Die Box zeigt Akkustand und Restlaufzeit, meldet einen Stromausfall und fährt rechtzeitig sauber herunter – bei leerem Akku, unter einem Prozentwert oder nach einigen Minuten auf Akku. Danach schaltet die USV ab und mit dem Strom wieder ein. Andere Rechner können die USV über das Netzwerk mitlesen. Für die meisten USVs (APC, Eaton, CyberPower, Megatec …). Einstellungen unter Dienste → USV.", + "en": "UPS (uninterruptible power supply) over USB: the box shows charge and runtime, reports a power failure and shuts down cleanly in time – on a low battery, below a percentage or after some minutes on battery. Then the UPS switches off and on again with the power. Other computers can read the UPS over the network. For most UPSs (APC, Eaton, CyberPower, Megatec …). Settings under Services → UPS." + }, + "type": "system", + "commands": [ "usbhid-ups", "nutdrv_qx", "blazer_usb", "upsd", "upsmon", "upsc" ], + "service": { "control": "ups", "delay": 0 }, + "flash": true, + "icon": "icon.svg", + "category": "system", + "license": "GPL-2.0-or-later", + "homepage": "https://networkupstools.org/", + "min_shareos": "0.2.0-beta.18" +} diff --git a/sysapps/nut/icon.svg b/sysapps/nut/icon.svg new file mode 100644 index 00000000..2c16d0ef --- /dev/null +++ b/sysapps/nut/icon.svg @@ -0,0 +1 @@ + diff --git a/sysapps/nut/pack.json b/sysapps/nut/pack.json new file mode 100644 index 00000000..328619a2 --- /dev/null +++ b/sysapps/nut/pack.json @@ -0,0 +1 @@ +{ "bin": [ "usr/bin/usbhid-ups", "usr/bin/nutdrv_qx", "usr/bin/blazer_usb", "usr/sbin/upsd", "usr/sbin/upsmon", "usr/bin/upsc" ] } diff --git a/tests/mock-ubus.py b/tests/mock-ubus.py index 12f46a4f..9dbb5c34 100644 --- a/tests/mock-ubus.py +++ b/tests/mock-ubus.py @@ -699,6 +699,22 @@ def call(obj, method, args): STATE['led'].update({k: v for k, v in args.items() if v}) return {'fan': STATE['fan'], 'led': STATE['led'], 'temperature': 41000, 'fan_pwm': 100, 'presets': {'quiet': {'off_temp': 40, 'full_temp': 55, 'half_temp': 50}}} + if obj == 'shareos.ups': + u = STATE.setdefault('ups', {'installed': True, 'enabled': False, 'running': False, 'detected': '051d:0002', 'driver': 'usbhid-ups', + 'status': None, 'charge': None, 'runtime': None, 'load': None, 'voltage': None, 'mfr': None, 'model': None, 'charge_low': None, 'battery_date': None, + 'events': [], 'settings': {'driver': 'auto', 'shutdown': 'low', 'percent': 30, 'minutes': 5, 'killpower': True, 'server': False, 'password_set': False}}) + if method == 'set': + u['enabled'] = bool(args.get('enabled')) + for k in ('driver', 'shutdown', 'percent', 'minutes', 'killpower', 'server'): + if args.get(k) not in (None, '', 0): u['settings'][k] = args[k] + u['settings']['killpower'] = bool(args.get('killpower')); u['settings']['server'] = bool(args.get('server')) + if args.get('password'): u['settings']['password_set'] = True + if u['enabled']: + u.update({'running': True, 'status': 'OB DISCHRG', 'charge': 87, 'runtime': 1260, 'load': 18, 'voltage': 0, 'mfr': 'APC', 'model': 'Back-UPS ES 700G', 'battery_date': '2024/03/11', + 'events': [{'time': 1793530000, 'type': 'ONBATT'}, {'time': 1793520000, 'type': 'ONLINE'}, {'time': 1793519000, 'type': 'ONBATT'}]}) + else: + u.update({'running': False, 'status': None}) + return u if obj == 'shareos.web': if method == 'set': STATE.update({k: v for k, v in args.items() if k in ('https', 'redirect')}) diff --git a/tests/test-ups.sh b/tests/test-ups.sh new file mode 100755 index 00000000..7fd06145 --- /dev/null +++ b/tests/test-ups.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# +# Tests shareos-ups (system app "nut") with fake NUT programs: the files it +# writes for each setting, the driver chosen, the events (messages, the timer +# for "minutes on battery"), the status lines and the final UPS power-off. +# +# tests/test-ups.sh [dir with uci] +# +TOP=$(cd "$(dirname "$0")/.." && pwd) +P="$TOP/src/shareos-core/usr/sbin/shareos-ups" +T=$(mktemp -d) +trap 'SHAREOS_ROOT=$T sh "$P" stop-all >/dev/null 2>&1; rm -rf "$T"' EXIT +export PATH="${1:+$1:}$PATH" +mkdir -p $T/etc/config $T/bin $T/run $T/sys/bus/usb/devices/1-1 +echo 051d > $T/sys/bus/usb/devices/1-1/idVendor; echo 0002 > $T/sys/bus/usb/devices/1-1/idProduct +# fake NUT: daemons stay in the background with a pid file, upsc answers from a file +for p in usbhid-ups nutdrv_qx blazer_usb upsd upsmon; do + cat > $T/bin/$p <> $T/calls.log +case "\$*" in *-c\ stop*) kill \$(cat $T/run/$p.pid 2>/dev/null) 2>/dev/null; exit 0 ;; *-c\ fsd*) echo FSD >> $T/calls.log; exit 0 ;; *-k*) exit 0 ;; esac +[ -f $T/fail-$p ] && { echo "no matching device"; exit 1; } +( while :; do sleep 1; done ) & +case $p in upsd|upsmon) echo \$! > $T/run/$p.pid ;; *) echo \$! > \$NUT_STATEPATH/$p-ups.pid ;; esac +EOF + chmod 755 $T/bin/$p +done +printf '#!/bin/sh\ncat %s/upsc.out\n' $T > $T/bin/upsc; chmod 755 $T/bin/upsc +printf 'ups.status: OL\nbattery.charge: 100\nbattery.runtime: 1800\nups.load: 12\ndevice.mfr: APC\ndevice.model: Back-UPS ES 700\n' > $T/upsc.out +export SHAREOS_ROOT=$T SHAREOS_UPS_BIN=$T/bin SHAREOS_UPS_SYS=$T/sys +run() { sh "$P" "$@"; } +pass=0; failed=0 +check() { if eval "$2"; then echo "PASS $1"; pass=$((pass+1)); else echo "FAIL $1"; failed=$((failed+1)); fi; } +conf() { printf "config ups 'main'\n" > $T/etc/config/ups; for kv; do printf "\toption %s '%s'\n" "${kv%%=*}" "${kv#*=}" >> $T/etc/config/ups; done; } +C=$T/tmp/shareos-ups/conf + +conf enabled=1 shutdown=low +run start +check "start: driver, upsd and upsmon run" "grep -q '^usbhid-ups -a ups -u root' $T/calls.log && grep -q '^upsd -u root' $T/calls.log && grep -q '^upsmon' $T/calls.log" +check "APC (051d) is detected, usbhid-ups chosen" "grep -q 'driver = usbhid-ups' $C/ups.conf && run status | grep -qx 'detected=051d:0002'" +check "low battery: no override of the UPS limit" "! grep -q ignorelb $C/ups.conf" +check "upsd only on localhost without the server option" "[ \"\$(cat $C/upsd.conf)\" = 'LISTEN 127.0.0.1 3493' ]" +check "upsmon: primary, our shutdown and event commands, killpower flag" "grep -q 'MONITOR ups@localhost 1 shareos .* primary' $C/upsmon.conf && grep -q 'SHUTDOWNCMD \"/usr/sbin/shareos-ups shutdown\"' $C/upsmon.conf && grep -q 'NOTIFYFLAG ONBATT SYSLOG+EXEC' $C/upsmon.conf && grep -q POWERDOWNFLAG $C/upsmon.conf" +check "config files root only" "[ \$(stat -c %a $C/upsd.users) = 600 ]" +check "status: values of the UPS" "run status | grep -qx 'status=OL' && run status | grep -qx 'charge=100' && run status | grep -qx 'model=Back-UPS ES 700'" +run stop +check "stop: nothing runs" "! run status | grep -qx 'running=1'" + +conf enabled=1 shutdown=percent percent=40 server=1 password=geheim killpower=0 +: > $T/calls.log +run start +check "percent: the driver reports low battery below 40 %" "grep -q ignorelb $C/ups.conf && grep -q 'override.battery.charge.low = 40' $C/ups.conf" +check "server: upsd listens on the network, user monitor" "grep -q 'LISTEN 0.0.0.0 3493' $C/upsd.conf && grep -q -A2 '\\[monitor\\]' $C/upsd.users && grep -q 'password = geheim' $C/upsd.users" +check "killpower off: no flag" "! grep -q POWERDOWNFLAG $C/upsmon.conf" +run stop + +conf enabled=1 driver=auto; touch $T/fail-usbhid-ups; : > $T/calls.log +run start +check "auto: usbhid-ups finds nothing – nutdrv_qx is tried" "grep -q '^nutdrv_qx -a ups' $T/calls.log && grep -q 'driver = nutdrv_qx' $C/ups.conf" +run stop; rm $T/fail-usbhid-ups + +conf enabled=1 shutdown=minutes minutes=1 +run start +NOTIFYTYPE=ONBATT run "UPS ups@localhost on battery" +check "on battery: message and a timer" "grep -q 'notify warn ups-onbatt' $T/tmp/shareos-ups/notify.log && [ -s $T/tmp/shareos-ups/timer.pid ]" +NOTIFYTYPE=ONLINE run "UPS ups@localhost on line power" +check "power back: timer stopped, message cleared" "[ ! -e $T/tmp/shareos-ups/timer.pid ] && grep -q 'clear ups-onbatt' $T/tmp/shareos-ups/notify.log && grep -q 'notify info ups-online' $T/tmp/shareos-ups/notify.log" +printf 'ups.status: OB DISCHRG\n' > $T/upsc.out +run timer +check "timer over and still on battery: forced shutdown" "grep -q FSD $T/calls.log" +: > $T/calls.log; printf 'ups.status: OL\n' > $T/upsc.out +run timer +check "timer over but power back: nothing" "! grep -q FSD $T/calls.log" +check "events listed in the status" "run status | grep -q '^event=[0-9]* ONBATT'" +run shutdown +check "shutdown command powers off" "grep -qx poweroff $T/tmp/shareos-ups/notify.log" +touch $T/tmp/shareos-ups/killpower; : > $T/calls.log +run killpower +check "killpower: the driver tells the UPS to switch off" "grep -q 'usbhid-ups -a ups -u root -k' $T/calls.log" +run stop + +conf enabled=0 +check "boot while switched off: nothing" "run boot && ! [ -s $T/run/upsmon.pid ] || ! kill -0 \$(cat $T/run/upsmon.pid) 2>/dev/null" + +echo "test-ups: $pass passed, $failed failed" +[ $failed = 0 ] diff --git a/tools/i18n/ar.tsv b/tools/i18n/ar.tsv index 50a39b7c..abe0404b 100644 --- a/tools/i18n/ar.tsv +++ b/tools/i18n/ar.tsv @@ -1636,3 +1636,48 @@ P323 إيقاف $1 E1269 الجهاز والوصول E1270 النجمة تجعل التطبيق مفضلاً – تظهر المفضلة أعلى «ShareOS الخاص بي». E1271 عرض كل التنبيهات +E1272 UPS +E1273 جارٍ تحميل UPS … +E1274 التثبيت من المتجر (Network UPS Tools) +E1275 دعم UPS تطبيق نظام: يعرض الجهاز الشحن ووقت التشغيل المتبقي، ويبلّغ عن انقطاع الكهرباء ويُغلق بشكل سليم في الوقت المناسب. +E1276 البطارية شبه فارغة +E1277 يعمل على البطارية +E1278 على الكهرباء +E1279 لا بيانات +E1280 البطارية +E1281 الوقت المتبقي +E1282 الحِمل +E1283 جهد الشبكة +E1284 البطارية منذ +E1285 برنامج التشغيل +E1286 جارٍ الاتصال بـ UPS … +E1287 تم الاكتشاف: +E1288 شغّله أدناه. +E1289 الأحداث +E1290 لا شيء بعد – يظهر انقطاع الكهرباء هنا وكرسالة. +E1291 انقطاع الكهرباء – يعمل على UPS +E1292 عادت الكهرباء +E1293 تم تفعيل الإيقاف +E1294 الجهاز يُغلق +E1295 انقطع الاتصال بـ UPS +E1296 لا اتصال بـ UPS +E1297 عاد الاتصال بـ UPS +E1298 استبدل البطارية +E1299 مراقبة UPS (تبدأ أيضًا بعد إعادة التشغيل) +E1300 الإيقاف +E1301 عندما يبلّغ UPS عن «بطارية منخفضة» +E1302 تحت نسبة شحن +E1303 بعد مدة على البطارية +E1304 شحن البطارية (%) +E1305 دقائق على البطارية +E1306 برنامج التشغيل +E1307 تلقائي +E1308 blazer_usb (Megatec الأقدم) +E1309 ثم إيقاف UPS – يبدأ الجهاز مجددًا عند عودة الكهرباء +E1310 يمكن لأجهزة أخرى قراءة UPS عبر الشبكة (المنفذ 3493) +E1311 كلمة المرور لـ «MONITOR» +E1312 محفوظة – اتركها فارغة للإبقاء عليها +E1313 على الحاسوب الآخر (NUT، upsmon): +E1314 – وعندها يُغلق قبل الجهاز. +E1315 لا يُغلق الجهاز إلا أثناء عمله على البطارية. إذا عادت الكهرباء قبل ذلك فلا يحدث شيء. +E1316 تم حفظ UPS. diff --git a/tools/i18n/bn.tsv b/tools/i18n/bn.tsv index a00225db..de86c7e9 100644 --- a/tools/i18n/bn.tsv +++ b/tools/i18n/bn.tsv @@ -1636,3 +1636,48 @@ P323 বন্ধ $1 E1269 ডিভাইস ও অ্যাক্সেস E1270 তারকা দিয়ে অ্যাপ প্রিয় হয় – প্রিয়গুলি "আমার ShareOS"-এর উপরে দেখায়। E1271 সব বিজ্ঞপ্তি দেখান +E1272 UPS +E1273 UPS লোড হচ্ছে … +E1274 স্টোর থেকে ইনস্টল করুন (Network UPS Tools) +E1275 UPS সাপোর্ট একটি সিস্টেম অ্যাপ: বক্স চার্জ ও বাকি সময় দেখায়, বিদ্যুৎ চলে গেলে জানায় এবং সময়মতো ঠিকভাবে বন্ধ হয়। +E1276 ব্যাটারি প্রায় শেষ +E1277 ব্যাটারিতে চলছে +E1278 বিদ্যুৎ লাইনে +E1279 কোনো ডেটা নেই +E1280 ব্যাটারি +E1281 বাকি সময় +E1282 লোড +E1283 লাইন ভোল্টেজ +E1284 ব্যাটারি কবে থেকে +E1285 ড্রাইভার +E1286 UPS-এ সংযোগ হচ্ছে … +E1287 শনাক্ত: +E1288 নিচে চালু করুন। +E1289 ঘটনা +E1290 এখনো নেই – বিদ্যুৎ গেলে এখানে ও বার্তা হিসেবে দেখাবে। +E1291 বিদ্যুৎ বিভ্রাট – UPS-এ চলছে +E1292 বিদ্যুৎ ফিরে এসেছে +E1293 শাটডাউন শুরু +E1294 বক্স বন্ধ হচ্ছে +E1295 UPS-এর সাথে সংযোগ বিচ্ছিন্ন +E1296 UPS-এর সাথে সংযোগ নেই +E1297 UPS-এর সাথে সংযোগ ফিরে এসেছে +E1298 ব্যাটারি বদলান +E1299 UPS নজরে রাখুন (রিস্টার্টের পরেও চালু হবে) +E1300 শাটডাউন +E1301 যখন UPS “ব্যাটারি কম” জানায় +E1302 একটি চার্জের নিচে +E1303 ব্যাটারিতে কিছু সময় পরে +E1304 ব্যাটারি চার্জ (%) +E1305 ব্যাটারিতে মিনিট +E1306 ড্রাইভার +E1307 স্বয়ংক্রিয় +E1308 blazer_usb (পুরোনো Megatec) +E1309 তারপর UPS বন্ধ করুন – বিদ্যুৎ ফিরলে বক্স আবার চালু হবে +E1310 অন্য কম্পিউটার নেটওয়ার্কে UPS পড়তে পারবে (পোর্ট 3493) +E1311 “MONITOR”-এর পাসওয়ার্ড +E1312 সংরক্ষিত – ফাঁকা রাখলে আগেরটাই থাকবে +E1313 অন্য কম্পিউটারে (NUT, upsmon): +E1314 – তখন সেটি বক্সের আগে বন্ধ হবে। +E1315 বক্স কেবল ব্যাটারিতে চলার সময়ই বন্ধ হয়। আগে বিদ্যুৎ ফিরলে কিছুই হয় না। +E1316 UPS সংরক্ষিত। diff --git a/tools/i18n/es.tsv b/tools/i18n/es.tsv index ed0285d2..2140c49e 100644 --- a/tools/i18n/es.tsv +++ b/tools/i18n/es.tsv @@ -1636,3 +1636,48 @@ P323 apagado $1 E1269 EQUIPO Y ACCESO E1270 La estrella convierte una app en favorita: las favoritas aparecen arriba en «Mi ShareOS». E1271 Mostrar todos los avisos +E1272 SAI +E1273 Cargando SAI … +E1274 Instalar desde la tienda (Network UPS Tools) +E1275 El soporte de SAI es una app del sistema: la caja muestra la carga y la autonomía, avisa de un corte de luz y se apaga a tiempo de forma limpia. +E1276 Batería casi vacía +E1277 con batería +E1278 con red eléctrica +E1279 sin datos +E1280 BATERÍA +E1281 AUTONOMÍA +E1282 CARGA +E1283 Tensión de red +E1284 Batería desde +E1285 Controlador +E1286 Conectando con el SAI … +E1287 Detectado: +E1288 Actívalo abajo. +E1289 EVENTOS +E1290 Ninguno aún – un corte de luz se muestra aquí y como mensaje. +E1291 Corte de luz – funcionando con el SAI +E1292 Vuelve la luz +E1293 Apagado iniciado +E1294 La caja se apaga +E1295 Conexión con el SAI perdida +E1296 Sin conexión con el SAI +E1297 Conexión con el SAI restablecida +E1298 Cambiar la batería +E1299 Supervisar el SAI (también arranca tras reiniciar) +E1300 APAGADO +E1301 Cuando el SAI avisa de «batería baja» +E1302 Por debajo de una carga +E1303 Tras un tiempo con batería +E1304 CARGA DE LA BATERÍA (%) +E1305 MINUTOS CON BATERÍA +E1306 CONTROLADOR +E1307 Automático +E1308 blazer_usb (Megatec antiguos) +E1309 Después apagar el SAI – la caja arranca de nuevo al volver la luz +E1310 Otros ordenadores pueden leer el SAI por la red (puerto 3493) +E1311 CONTRASEÑA PARA «MONITOR» +E1312 guardada – déjala vacía para conservarla +E1313 En el otro ordenador (NUT, upsmon): +E1314 – entonces se apaga antes que la caja. +E1315 La caja solo se apaga mientras funciona con batería. Si la luz vuelve antes, no pasa nada. +E1316 SAI guardado. diff --git a/tools/i18n/fr.tsv b/tools/i18n/fr.tsv index 6b1af109..a52bd5d9 100644 --- a/tools/i18n/fr.tsv +++ b/tools/i18n/fr.tsv @@ -1636,3 +1636,48 @@ P323 arrêt $1 E1269 APPAREIL & ACCÈS E1270 L’étoile fait d’une app un favori – les favoris apparaissent en haut de « Mon ShareOS ». E1271 Afficher toutes les notifications +E1272 ONDULEUR +E1273 Chargement de l'onduleur … +E1274 Installer depuis le store (Network UPS Tools) +E1275 La prise en charge de l'onduleur est une application système : la box affiche alors la charge et l'autonomie, signale une coupure de courant et s'arrête proprement à temps. +E1276 Batterie presque vide +E1277 sur batterie +E1278 sur secteur +E1279 pas de données +E1280 BATTERIE +E1281 AUTONOMIE +E1282 CHARGE +E1283 Tension secteur +E1284 Batterie depuis +E1285 Pilote +E1286 Connexion à l'onduleur … +E1287 Détecté : +E1288 Activez-le ci-dessous. +E1289 ÉVÉNEMENTS +E1290 Aucun pour l'instant – une coupure de courant s'affiche ici et comme message. +E1291 Coupure de courant – sur onduleur +E1292 Courant rétabli +E1293 Arrêt déclenché +E1294 La box s'arrête +E1295 Connexion à l'onduleur perdue +E1296 Pas de connexion à l'onduleur +E1297 Connexion à l'onduleur rétablie +E1298 Remplacer la batterie +E1299 Surveiller l'onduleur (démarre aussi après un redémarrage) +E1300 ARRÊT +E1301 Quand l'onduleur signale « batterie faible » +E1302 Sous un niveau de charge +E1303 Après un temps sur batterie +E1304 CHARGE DE LA BATTERIE (%) +E1305 MINUTES SUR BATTERIE +E1306 PILOTE +E1307 Automatique +E1308 blazer_usb (anciens Megatec) +E1309 Ensuite éteindre l'onduleur – la box redémarre au retour du courant +E1310 D'autres ordinateurs peuvent lire l'onduleur via le réseau (port 3493) +E1311 MOT DE PASSE POUR « MONITOR » +E1312 enregistré – laisser vide pour le conserver +E1313 Sur l'autre ordinateur (NUT, upsmon) : +E1314 – il s'arrête alors avant la box. +E1315 La box ne s'arrête que tant qu'elle est sur batterie. Si le courant revient avant, rien ne se passe. +E1316 Onduleur enregistré. diff --git a/tools/i18n/hi.tsv b/tools/i18n/hi.tsv index 1398ad86..1ee4e477 100644 --- a/tools/i18n/hi.tsv +++ b/tools/i18n/hi.tsv @@ -1636,3 +1636,48 @@ P323 बंद $1 E1269 डिवाइस और पहुँच E1270 स्टार से ऐप पसंदीदा बनता है – पसंदीदा "मेरा ShareOS" के ऊपर दिखते हैं। E1271 सभी सूचनाएँ दिखाएँ +E1272 UPS +E1273 UPS लोड हो रहा है … +E1274 स्टोर से इंस्टॉल करें (Network UPS Tools) +E1275 UPS सपोर्ट एक सिस्टम ऐप है: बॉक्स चार्ज और शेष समय दिखाता है, बिजली जाने की सूचना देता है और समय पर ठीक से बंद होता है। +E1276 बैटरी लगभग खाली +E1277 बैटरी पर +E1278 मेन्स पर +E1279 कोई डेटा नहीं +E1280 बैटरी +E1281 शेष समय +E1282 लोड +E1283 मेन्स वोल्टेज +E1284 बैटरी कब से +E1285 ड्राइवर +E1286 UPS से जुड़ रहा है … +E1287 पहचाना गया: +E1288 नीचे चालू करें। +E1289 घटनाएँ +E1290 अभी कोई नहीं – बिजली जाने पर यहाँ और संदेश के रूप में दिखेगा। +E1291 बिजली गई – UPS पर चल रहा है +E1292 बिजली वापस आई +E1293 शटडाउन शुरू +E1294 बॉक्स बंद हो रहा है +E1295 UPS से कनेक्शन टूटा +E1296 UPS से कोई कनेक्शन नहीं +E1297 UPS से कनेक्शन वापस आया +E1298 बैटरी बदलें +E1299 UPS की निगरानी करें (रीस्टार्ट के बाद भी शुरू होगा) +E1300 शटडाउन +E1301 जब UPS “बैटरी कम” बताए +E1302 एक चार्ज स्तर से नीचे +E1303 बैटरी पर कुछ समय बाद +E1304 बैटरी चार्ज (%) +E1305 बैटरी पर मिनट +E1306 ड्राइवर +E1307 स्वचालित +E1308 blazer_usb (पुराने Megatec) +E1309 फिर UPS बंद करें – बिजली लौटने पर बॉक्स फिर शुरू होगा +E1310 दूसरे कंप्यूटर नेटवर्क से UPS पढ़ सकते हैं (पोर्ट 3493) +E1311 “MONITOR” के लिए पासवर्ड +E1312 सहेजा गया – खाली छोड़ें तो वही रहेगा +E1313 दूसरे कंप्यूटर पर (NUT, upsmon): +E1314 – तब वह बॉक्स से पहले बंद होगा। +E1315 बॉक्स तभी बंद होता है जब वह बैटरी पर चल रहा हो। बिजली पहले लौट आए तो कुछ नहीं होता। +E1316 UPS सहेजा गया। diff --git a/tools/i18n/pt.tsv b/tools/i18n/pt.tsv index 332a4352..8a5ab3dd 100644 --- a/tools/i18n/pt.tsv +++ b/tools/i18n/pt.tsv @@ -1636,3 +1636,48 @@ P323 desliga $1 E1269 EQUIPAMENTO E ACESSO E1270 A estrela torna um app favorito – os favoritos aparecem no topo de “Meu ShareOS”. E1271 Mostrar todos os avisos +E1272 UPS +E1273 A carregar UPS … +E1274 Instalar a partir da loja (Network UPS Tools) +E1275 O suporte a UPS é uma app de sistema: a caixa mostra a carga e a autonomia, avisa de um corte de energia e desliga-se a tempo de forma limpa. +E1276 Bateria quase vazia +E1277 em bateria +E1278 na rede elétrica +E1279 sem dados +E1280 BATERIA +E1281 AUTONOMIA +E1282 CARGA +E1283 Tensão da rede +E1284 Bateria desde +E1285 Controlador +E1286 A ligar à UPS … +E1287 Detetado: +E1288 Ligue-o abaixo. +E1289 EVENTOS +E1290 Nenhum ainda – um corte de energia aparece aqui e como mensagem. +E1291 Corte de energia – a funcionar com a UPS +E1292 Energia reposta +E1293 Encerramento iniciado +E1294 A caixa está a desligar +E1295 Ligação à UPS perdida +E1296 Sem ligação à UPS +E1297 Ligação à UPS restabelecida +E1298 Substituir a bateria +E1299 Monitorizar a UPS (também arranca após reiniciar) +E1300 ENCERRAR +E1301 Quando a UPS indica «bateria fraca» +E1302 Abaixo de uma carga +E1303 Após algum tempo em bateria +E1304 CARGA DA BATERIA (%) +E1305 MINUTOS EM BATERIA +E1306 CONTROLADOR +E1307 Automático +E1308 blazer_usb (Megatec antigos) +E1309 Depois desligar a UPS – a caixa volta a arrancar quando a energia regressar +E1310 Outros computadores podem ler a UPS pela rede (porta 3493) +E1311 PALAVRA-PASSE PARA «MONITOR» +E1312 guardada – deixe vazio para a manter +E1313 No outro computador (NUT, upsmon): +E1314 – então desliga-se antes da caixa. +E1315 A caixa só se desliga enquanto estiver em bateria. Se a energia voltar antes, nada acontece. +E1316 UPS guardada. diff --git a/tools/i18n/ru.tsv b/tools/i18n/ru.tsv index 1db7ab09..457e36c6 100644 --- a/tools/i18n/ru.tsv +++ b/tools/i18n/ru.tsv @@ -1636,3 +1636,48 @@ P323 выкл. $1 E1269 УСТРОЙСТВО И ДОСТУП E1270 Звёздочка делает приложение избранным – избранные показаны вверху «Мой ShareOS». E1271 Показать все уведомления +E1272 ИБП +E1273 Загрузка ИБП … +E1274 Установить из магазина (Network UPS Tools) +E1275 Поддержка ИБП – системное приложение: устройство показывает заряд и время работы, сообщает об отключении питания и вовремя корректно выключается. +E1276 Батарея почти разряжена +E1277 от батареи +E1278 от сети +E1279 нет данных +E1280 БАТАРЕЯ +E1281 ВРЕМЯ РАБОТЫ +E1282 НАГРУЗКА +E1283 Напряжение сети +E1284 Батарея с +E1285 Драйвер +E1286 Подключение к ИБП … +E1287 Обнаружено: +E1288 Включите ниже. +E1289 СОБЫТИЯ +E1290 Пока нет – отключение питания появится здесь и в сообщениях. +E1291 Отключение питания – работа от ИБП +E1292 Питание восстановлено +E1293 Запущено выключение +E1294 Устройство выключается +E1295 Связь с ИБП потеряна +E1296 Нет связи с ИБП +E1297 Связь с ИБП восстановлена +E1298 Замените батарею +E1299 Следить за ИБП (запускается и после перезагрузки) +E1300 ВЫКЛЮЧЕНИЕ +E1301 Когда ИБП сообщает «батарея разряжена» +E1302 Ниже уровня заряда +E1303 Через время работы от батареи +E1304 ЗАРЯД БАТАРЕИ (%) +E1305 МИНУТ ОТ БАТАРЕИ +E1306 ДРАЙВЕР +E1307 Автоматически +E1308 blazer_usb (старые Megatec) +E1309 Затем выключить ИБП – устройство снова запустится при появлении питания +E1310 Другие компьютеры могут читать данные ИБП по сети (порт 3493) +E1311 ПАРОЛЬ ДЛЯ «MONITOR» +E1312 сохранён – оставьте пустым, чтобы не менять +E1313 На другом компьютере (NUT, upsmon): +E1314 – тогда он выключится раньше устройства. +E1315 Устройство выключается, только пока работает от батареи. Если питание вернётся раньше, ничего не произойдёт. +E1316 ИБП сохранён. diff --git a/tools/i18n/zh.tsv b/tools/i18n/zh.tsv index b0768e1d..02526547 100644 --- a/tools/i18n/zh.tsv +++ b/tools/i18n/zh.tsv @@ -1636,3 +1636,48 @@ P323 关 $1 E1269 设备与访问 E1270 星标可将应用设为收藏——收藏显示在“我的 ShareOS”顶部。 E1271 显示所有提示 +E1272 UPS +E1273 正在加载 UPS…… +E1274 从商店安装 (Network UPS Tools) +E1275 UPS 支持是一个系统应用:设备会显示电量和剩余时间,报告停电并及时安全关机。 +E1276 电池电量低 +E1277 电池供电中 +E1278 市电供电 +E1279 无数据 +E1280 电池 +E1281 剩余时间 +E1282 负载 +E1283 市电电压 +E1284 电池启用于 +E1285 驱动 +E1286 正在连接 UPS…… +E1287 已检测到: +E1288 在下方启用。 +E1289 事件 +E1290 暂无——停电会显示在这里并作为消息通知。 +E1291 停电——由 UPS 供电 +E1292 供电恢复 +E1293 已触发关机 +E1294 设备正在关机 +E1295 与 UPS 的连接中断 +E1296 无法连接 UPS +E1297 与 UPS 的连接已恢复 +E1298 更换电池 +E1299 监控 UPS(重启后也会启动) +E1300 关机 +E1301 当 UPS 报告“电池电量低”时 +E1302 低于某电量时 +E1303 电池供电一段时间后 +E1304 电池电量 (%) +E1305 电池供电分钟数 +E1306 驱动 +E1307 自动 +E1308 blazer_usb(旧款 Megatec) +E1309 随后关闭 UPS——供电恢复时设备会重新启动 +E1310 允许其他电脑通过网络读取 UPS(端口 3493) +E1311 “MONITOR”的密码 +E1312 已保存——留空则保留 +E1313 在另一台电脑上(NUT、upsmon): +E1314 ——它会在本设备之前关机。 +E1315 只有在电池供电期间设备才会关机。如果在此之前恢复供电,则不会发生任何事。 +E1316 UPS 设置已保存。