diff --git a/install.sh b/install.sh index 90c01fb1..b7688efe 100755 --- a/install.sh +++ b/install.sh @@ -33,26 +33,55 @@ if [ -f "./installed.txt" ]; then rm /etc/kvmd/nginx/ssl/server.crt rm /etc/kvmd/nginx/ssl/server.key else + #此为危险操作,会覆盖MBR分区,请在没有自行分区前执行,否则会丢失分区数据系统无法启动! + gzip -dc ./patch/Boot_SkipUSBBurning.gz | dd of=/dev/mmcblk1 && echo "One-KVM V0.4" >> installed.txt && echo "覆盖引导成功!" echo kvmd ALL=\(ALL\) NOPASSWD: /usr/bin/long_press_gpio420,/usr/bin/short_press_gpio420 >> /etc/sudoers fi -#此为危险操作,会覆盖MBR分区,请在没有自行分区前执行,否则会丢失分区数据系统无法启动! -gzip -dc ./patch/Boot_SkipUSBBurning.gz | dd of=/dev/mmcblk1 && echo "One-KVM V0.4" >> installed.txt && echo "覆盖引导成功!" -bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh) --source mirrors.tuna.tsinghua.edu.cn --updata-software false --web-protocol http && echo "换源成功!" -echo "正在安装依赖软件nginx tesseract-ocr tesseract-ocr-eng janus libevent-dev libgpiod-dev tesseract-ocr-chi-sim......" -apt install -y nginx tesseract-ocr tesseract-ocr-eng janus libevent-dev libgpiod-dev tesseract-ocr-chi-sim >> ./log.txt -echo "正在安装PiKVM......" -dpkg -i ./fruity-pikvm_0.2_armhf.deb && echo "PiKVM安装成功!" && systemctl enable kvmd-vnc + +if [-f "./installed.txt"]; then + echo "您似乎已经安装One-KVM,是否覆盖安装激活(Y/N)?" + read USERYN + case $USERYN in + N | n) + echo "跳过安装fruity-pikvm_0.2_armhf.deb!" + exit + ;; + *) + echo "正在安装PiKVM......" + dpkg -i ./fruity-pikvm_0.2_armhf.deb >> ./log.txt && systemctl enable kvmd-vnc && echo "PiKVM安装成功!" + ;; + esac +else + bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh) --source mirrors.tuna.tsinghua.edu.cn --updata-software false --web-protocol http && echo "换源成功!" + echo "正在安装依赖软件nginx tesseract-ocr tesseract-ocr-eng janus libevent-dev libgpiod-dev tesseract-ocr-chi-sim......" + apt install -y nginx tesseract-ocr tesseract-ocr-eng janus libevent-dev libgpiod-dev tesseract-ocr-chi-sim >> ./log.txt + echo "正在安装PiKVM......" + dpkg -i ./fruity-pikvm_0.2_armhf.deb >> ./log.txt && systemctl enable kvmd-vnc && echo "PiKVM安装成功!" +fi + + + cd $CURRENTWD cp ./patch/chinese.patch /usr/share/kvmd/web/ && cd /usr/share/kvmd/web/ && patch -s -p0 < chinese.patch cd $CURRENTWD cp ./patch/3.198msd.patch /usr/local/lib/python3.10/kvmd-packages/ && cd /usr/local/lib/python3.10/kvmd-packages/ && patch -s -p0 < 3.198msd.patch +cp -f ./patch/hw.py /usr/local/lib/python3.10/kvmd-packages/kvmd/apps/kvmd/info/ && chmod +x /usr/local/lib/python3.10/kvmd-packages/kvmd/apps/kvmd/info/hw.py echo "补丁应用成功!" cd $CURRENTWD && cp -f ./patch/long_press_gpio420 /usr/bin && cp -f ./patch/short_press_gpio420 /usr/bin && echo "GPIO-420脚本移动成功!" chmod +x /usr/bin/long_press_gpio420 && chmod +x /usr/bin/short_press_gpio420 cp -f ./config/main.yaml /etc/kvmd/ && cp -f ./config/override.yaml /etc/kvmd/ && echo "配置文件修改成功!" -kvmd -m >> ./log.txt -echo "机器已执行重启命令,请手动给玩客云重新上电(拔插电源),然后就可以开始使用One-KVM了!" + +if [-f "./installed.txt"]; then + kvmd -m >> ./log.txt + echo "机器已执行重启命令,稍作等待就可以开始使用One-KVM了!" +else + kvmd -m >> ./log.txt + echo "机器已执行重启命令,请手动给玩客云重新上电(拔插电源),然后就可以开始使用One-KVM了!" +fi + +ipaddr=`ip addr | grep "scope global" | awk '{print $2}' |awk -F/ '{print $1}'` +echo -e "内网访问地址为:\nhttp://$ipaddr\nhttps://$ipaddr" reboot \ No newline at end of file diff --git a/patch/hw.py b/patch/hw.py new file mode 100644 index 00000000..83f5c6c2 --- /dev/null +++ b/patch/hw.py @@ -0,0 +1,143 @@ +# ========================================================================== # +# # +# KVMD - The main PiKVM daemon. # +# # +# Copyright (C) 2018-2022 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +# ========================================================================== # + + +import os +import asyncio + +from typing import Callable +from typing import AsyncGenerator +from typing import TypeVar + +from ....logging import get_logger + +from .... import env +from .... import tools +from .... import aiofs +from .... import aioproc + +from .base import BaseInfoSubmanager + + +# ===== +_RetvalT = TypeVar("_RetvalT") + + +# ===== +class HwInfoSubmanager(BaseInfoSubmanager): + def __init__( + self, + vcgencmd_cmd: list[str], + state_poll: float, + ) -> None: + + self.__vcgencmd_cmd = vcgencmd_cmd + self.__state_poll = state_poll + + self.__dt_cache: dict[str, str] = {} + + async def get_state(self) -> dict: + (model, cpu_temp, throttling) = await asyncio.gather( + self.__read_dt_file("model"), + self.__get_cpu_temp(), + self.__get_throttling(), + ) + return { + "platform": { + "type": "rpi", + "base": model, + "serial": "0000000000000000", + }, + "health": { + "temp": { + "cpu": cpu_temp, + }, + "throttling": throttling, + }, + } + + async def poll_state(self) -> AsyncGenerator[dict, None]: + prev_state: dict = {} + while True: + state = await self.get_state() + if state != prev_state: + yield state + prev_state = state + await asyncio.sleep(self.__state_poll) + + # ===== + + async def __read_dt_file(self, name: str) -> (str | None): + if name not in self.__dt_cache: + path = os.path.join(f"{env.PROCFS_PREFIX}/proc/device-tree", name) + try: + self.__dt_cache[name] = (await aiofs.read(path)).strip(" \t\r\n\0") + except Exception as err: + get_logger(0).error("Can't read DT %s from %s: %s", name, path, err) + return None + return self.__dt_cache[name] + + async def __get_cpu_temp(self) -> (float | None): + temp_path = f"{env.SYSFS_PREFIX}/sys/class/thermal/thermal_zone0/temp" + try: + return int((await aiofs.read(temp_path)).strip()) / 1000 + except Exception as err: + get_logger(0).error("Can't read CPU temp from %s: %s", temp_path, err) + return None + + async def __get_throttling(self) -> (dict | None): + # https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=147781&start=50#p972790 + flags = await self.__parse_vcgencmd( + arg="get_throttled", + parser=(lambda text: int(text.split("=")[-1].strip(), 16)), + ) + if flags is not None: + return { + "raw_flags": flags, + "parsed_flags": { + "undervoltage": { + "now": bool(flags & (1 << 0)), + "past": bool(flags & (1 << 16)), + }, + "freq_capped": { + "now": bool(flags & (1 << 1)), + "past": bool(flags & (1 << 17)), + }, + "throttled": { + "now": bool(flags & (1 << 2)), + "past": bool(flags & (1 << 18)), + }, + }, + } + return None + + async def __parse_vcgencmd(self, arg: str, parser: Callable[[str], _RetvalT]) -> (_RetvalT | None): + cmd = [*self.__vcgencmd_cmd, arg] + try: + text = (await aioproc.read_process(cmd, err_to_null=True))[1] + except Exception: + get_logger(0).exception("Error while executing: %s", tools.cmdfmt(cmd)) + return None + try: + return parser(text) + except Exception as err: + get_logger(0).error("Can't parse [ %s ] output: %r: %s", tools.cmdfmt(cmd), text, tools.efmt(err)) + return None diff --git a/patch/meson8b-onecloud.dtb b/patch/meson8b-onecloud.dtb deleted file mode 100644 index 6567cc52..00000000 Binary files a/patch/meson8b-onecloud.dtb and /dev/null differ