mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-13 01:30:31 +08:00
moved wol to gpio
This commit is contained in:
parent
688ddca549
commit
0c500aa0c9
@ -79,7 +79,6 @@ from ..validators.os import valid_options
|
|||||||
from ..validators.os import valid_command
|
from ..validators.os import valid_command
|
||||||
|
|
||||||
from ..validators.net import valid_ip_or_host
|
from ..validators.net import valid_ip_or_host
|
||||||
from ..validators.net import valid_ip
|
|
||||||
from ..validators.net import valid_net
|
from ..validators.net import valid_net
|
||||||
from ..validators.net import valid_port
|
from ..validators.net import valid_port
|
||||||
from ..validators.net import valid_ports_list
|
from ..validators.net import valid_ports_list
|
||||||
@ -183,7 +182,7 @@ def _init_config(config_path: str, override_options: List[str], **load_flags: bo
|
|||||||
raise SystemExit(f"ConfigError: {err}")
|
raise SystemExit(f"ConfigError: {err}")
|
||||||
|
|
||||||
|
|
||||||
def _patch_raw(raw_config: Dict) -> None:
|
def _patch_raw(raw_config: Dict) -> None: # pylint: disable=too-many-branches
|
||||||
if isinstance(raw_config.get("otg"), dict):
|
if isinstance(raw_config.get("otg"), dict):
|
||||||
for (old, new) in [
|
for (old, new) in [
|
||||||
("msd", "msd"),
|
("msd", "msd"),
|
||||||
@ -195,6 +194,23 @@ def _patch_raw(raw_config: Dict) -> None:
|
|||||||
raw_config["otg"]["devices"] = {}
|
raw_config["otg"]["devices"] = {}
|
||||||
raw_config["otg"]["devices"][new] = raw_config["otg"].pop(old)
|
raw_config["otg"]["devices"][new] = raw_config["otg"].pop(old)
|
||||||
|
|
||||||
|
if isinstance(raw_config.get("kvmd"), dict) and isinstance(raw_config["kvmd"].get("wol"), dict):
|
||||||
|
if not isinstance(raw_config["kvmd"].get("gpio"), dict):
|
||||||
|
raw_config["kvmd"]["gpio"] = {}
|
||||||
|
for section in ["drivers", "scheme"]:
|
||||||
|
if not isinstance(raw_config["kvmd"]["gpio"].get(section), dict):
|
||||||
|
raw_config["kvmd"]["gpio"][section] = {}
|
||||||
|
raw_config["kvmd"]["gpio"]["drivers"]["__wol__"] = {
|
||||||
|
"type": "wol",
|
||||||
|
**raw_config["kvmd"].pop("wol"),
|
||||||
|
}
|
||||||
|
raw_config["kvmd"]["gpio"]["scheme"]["__wol__"] = {
|
||||||
|
"driver": "__wol__",
|
||||||
|
"pin": 0,
|
||||||
|
"mode": "output",
|
||||||
|
"switch": False,
|
||||||
|
}
|
||||||
|
|
||||||
if isinstance(raw_config.get("kvmd"), dict) and isinstance(raw_config["kvmd"].get("streamer"), dict):
|
if isinstance(raw_config.get("kvmd"), dict) and isinstance(raw_config["kvmd"].get("streamer"), dict):
|
||||||
streamer_config = raw_config["kvmd"]["streamer"]
|
streamer_config = raw_config["kvmd"]["streamer"]
|
||||||
|
|
||||||
@ -359,12 +375,6 @@ def _get_config_scheme() -> Dict:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"wol": {
|
|
||||||
"ip": Option("255.255.255.255", type=functools.partial(valid_ip, v6=False)),
|
|
||||||
"port": Option(9, type=valid_port),
|
|
||||||
"mac": Option("", type=_make_ifarg(valid_mac, "")),
|
|
||||||
},
|
|
||||||
|
|
||||||
"hid": {
|
"hid": {
|
||||||
"type": Option("", type=valid_stripped_string_not_empty),
|
"type": Option("", type=valid_stripped_string_not_empty),
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,6 @@ from .. import init
|
|||||||
from .auth import AuthManager
|
from .auth import AuthManager
|
||||||
from .info import InfoManager
|
from .info import InfoManager
|
||||||
from .logreader import LogReader
|
from .logreader import LogReader
|
||||||
from .wol import WakeOnLan
|
|
||||||
from .ugpio import UserGpio
|
from .ugpio import UserGpio
|
||||||
from .streamer import Streamer
|
from .streamer import Streamer
|
||||||
from .snapshoter import Snapshoter
|
from .snapshoter import Snapshoter
|
||||||
@ -86,7 +85,6 @@ def main(argv: Optional[List[str]]=None) -> None:
|
|||||||
),
|
),
|
||||||
info_manager=InfoManager(global_config),
|
info_manager=InfoManager(global_config),
|
||||||
log_reader=LogReader(),
|
log_reader=LogReader(),
|
||||||
wol=WakeOnLan(**config.wol._unpack()),
|
|
||||||
user_gpio=UserGpio(config.gpio, global_config.otg.udc),
|
user_gpio=UserGpio(config.gpio, global_config.otg.udc),
|
||||||
|
|
||||||
hid=hid,
|
hid=hid,
|
||||||
|
|||||||
@ -1,46 +0,0 @@
|
|||||||
# ========================================================================== #
|
|
||||||
# #
|
|
||||||
# KVMD - The main Pi-KVM daemon. #
|
|
||||||
# #
|
|
||||||
# Copyright (C) 2018-2021 Maxim Devaev <mdevaev@gmail.com> #
|
|
||||||
# #
|
|
||||||
# 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 <https://www.gnu.org/licenses/>. #
|
|
||||||
# #
|
|
||||||
# ========================================================================== #
|
|
||||||
|
|
||||||
|
|
||||||
from aiohttp.web import Request
|
|
||||||
from aiohttp.web import Response
|
|
||||||
|
|
||||||
from ..wol import WakeOnLan
|
|
||||||
|
|
||||||
from ..http import exposed_http
|
|
||||||
from ..http import make_json_response
|
|
||||||
|
|
||||||
|
|
||||||
# =====
|
|
||||||
class WolApi:
|
|
||||||
def __init__(self, wol: WakeOnLan) -> None:
|
|
||||||
self.__wol = wol
|
|
||||||
|
|
||||||
# =====
|
|
||||||
|
|
||||||
@exposed_http("GET", "/wol")
|
|
||||||
async def __state_handler(self, _: Request) -> Response:
|
|
||||||
return make_json_response(await self.__wol.get_state())
|
|
||||||
|
|
||||||
@exposed_http("POST", "/wol/wakeup")
|
|
||||||
async def __wakeup_handler(self, _: Request) -> Response:
|
|
||||||
await self.__wol.wakeup()
|
|
||||||
return make_json_response()
|
|
||||||
@ -65,7 +65,6 @@ from ... import aioproc
|
|||||||
from .auth import AuthManager
|
from .auth import AuthManager
|
||||||
from .info import InfoManager
|
from .info import InfoManager
|
||||||
from .logreader import LogReader
|
from .logreader import LogReader
|
||||||
from .wol import WakeOnLan
|
|
||||||
from .ugpio import UserGpio
|
from .ugpio import UserGpio
|
||||||
from .streamer import Streamer
|
from .streamer import Streamer
|
||||||
from .snapshoter import Snapshoter
|
from .snapshoter import Snapshoter
|
||||||
@ -85,7 +84,6 @@ from .api.auth import check_request_auth
|
|||||||
|
|
||||||
from .api.info import InfoApi
|
from .api.info import InfoApi
|
||||||
from .api.log import LogApi
|
from .api.log import LogApi
|
||||||
from .api.wol import WolApi
|
|
||||||
from .api.ugpio import UserGpioApi
|
from .api.ugpio import UserGpioApi
|
||||||
from .api.hid import HidApi
|
from .api.hid import HidApi
|
||||||
from .api.atx import AtxApi
|
from .api.atx import AtxApi
|
||||||
@ -148,7 +146,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
|
|||||||
auth_manager: AuthManager,
|
auth_manager: AuthManager,
|
||||||
info_manager: InfoManager,
|
info_manager: InfoManager,
|
||||||
log_reader: LogReader,
|
log_reader: LogReader,
|
||||||
wol: WakeOnLan,
|
|
||||||
user_gpio: UserGpio,
|
user_gpio: UserGpio,
|
||||||
|
|
||||||
hid: BaseHid,
|
hid: BaseHid,
|
||||||
@ -186,7 +183,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
|
|||||||
for sub in sorted(info_manager.get_subs())
|
for sub in sorted(info_manager.get_subs())
|
||||||
],
|
],
|
||||||
*[
|
*[
|
||||||
_Component("Wake-on-LAN", "wol_state", wol),
|
|
||||||
_Component("User-GPIO", "gpio_state", user_gpio),
|
_Component("User-GPIO", "gpio_state", user_gpio),
|
||||||
_Component("HID", "hid_state", hid),
|
_Component("HID", "hid_state", hid),
|
||||||
_Component("ATX", "atx_state", atx),
|
_Component("ATX", "atx_state", atx),
|
||||||
@ -201,7 +197,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
|
|||||||
AuthApi(auth_manager),
|
AuthApi(auth_manager),
|
||||||
InfoApi(info_manager),
|
InfoApi(info_manager),
|
||||||
LogApi(log_reader),
|
LogApi(log_reader),
|
||||||
WolApi(wol),
|
|
||||||
UserGpioApi(user_gpio),
|
UserGpioApi(user_gpio),
|
||||||
self.__hid_api,
|
self.__hid_api,
|
||||||
AtxApi(atx),
|
AtxApi(atx),
|
||||||
|
|||||||
@ -27,46 +27,69 @@ from typing import Optional
|
|||||||
|
|
||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ...errors import OperationError
|
|
||||||
|
|
||||||
from ... import aiotools
|
from ... import aiotools
|
||||||
|
|
||||||
|
from ...yamlconf import Option
|
||||||
|
|
||||||
# =====
|
from ...validators.net import valid_ip
|
||||||
class WolDisabledError(OperationError):
|
from ...validators.net import valid_port
|
||||||
def __init__(self) -> None:
|
from ...validators.net import valid_mac
|
||||||
super().__init__("WoL is disabled")
|
|
||||||
|
from . import GpioDriverOfflineError
|
||||||
|
from . import BaseUserGpioDriver
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
class WakeOnLan:
|
class Plugin(BaseUserGpioDriver): # pylint: disable=too-many-instance-attributes
|
||||||
def __init__(self, ip: str, port: int, mac: str) -> None:
|
def __init__( # pylint: disable=super-init-not-called
|
||||||
|
self,
|
||||||
|
instance_name: str,
|
||||||
|
notifier: aiotools.AioNotifier,
|
||||||
|
|
||||||
|
ip: str,
|
||||||
|
port: int,
|
||||||
|
mac: str,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
super().__init__(instance_name, notifier)
|
||||||
|
|
||||||
self.__ip = ip
|
self.__ip = ip
|
||||||
self.__port = port
|
self.__port = port
|
||||||
self.__mac = mac
|
self.__mac = mac
|
||||||
self.__magic = b""
|
|
||||||
|
|
||||||
if mac:
|
@classmethod
|
||||||
assert len(mac) == 17, mac
|
def get_plugin_options(cls) -> Dict:
|
||||||
self.__magic = bytes.fromhex("FF" * 6 + mac.replace(":", "") * 16)
|
|
||||||
|
|
||||||
async def get_state(self) -> Dict:
|
|
||||||
return {
|
return {
|
||||||
"enabled": bool(self.__magic),
|
"ip": Option("255.255.255.255", type=(lambda arg: valid_ip(arg, v6=False))),
|
||||||
"target": {
|
"port": Option(9, type=valid_port),
|
||||||
"ip": self.__ip,
|
"mac": Option("", type=(lambda arg: (valid_mac(arg) if arg else ""))),
|
||||||
"port": self.__port,
|
|
||||||
"mac": self.__mac,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@aiotools.atomic
|
def register_input(self, pin: int, debounce: float) -> None:
|
||||||
async def wakeup(self) -> None:
|
_ = pin
|
||||||
if not self.__magic:
|
_ = debounce
|
||||||
raise WolDisabledError()
|
|
||||||
|
|
||||||
logger = get_logger(0)
|
def register_output(self, pin: int, initial: Optional[bool]) -> None:
|
||||||
logger.info("Waking up %s (%s:%s) using Wake-on-LAN ...", self.__mac, self.__ip, self.__port)
|
_ = pin
|
||||||
|
_ = initial
|
||||||
|
|
||||||
|
def prepare(self) -> None:
|
||||||
|
get_logger(0).info("Probing driver %s on MAC %s and %s:%d ...", self, self.__mac, self.__ip, self.__port)
|
||||||
|
|
||||||
|
async def run(self) -> None:
|
||||||
|
await aiotools.wait_infinite()
|
||||||
|
|
||||||
|
async def cleanup(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def read(self, pin: int) -> bool:
|
||||||
|
_ = pin
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def write(self, pin: int, state: bool) -> None:
|
||||||
|
_ = pin
|
||||||
|
if not state:
|
||||||
|
return
|
||||||
|
|
||||||
sock: Optional[socket.socket] = None
|
sock: Optional[socket.socket] = None
|
||||||
try:
|
try:
|
||||||
@ -74,14 +97,18 @@ class WakeOnLan:
|
|||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||||
sock.connect((self.__ip, self.__port))
|
sock.connect((self.__ip, self.__port))
|
||||||
sock.send(self.__magic)
|
sock.send(bytes.fromhex("FF" * 6 + self.__mac.replace(":", "") * 16))
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Can't send Wake-on-LAN packet")
|
get_logger(0).exception("Can't send Wake-on-LAN packet via %s to %s", self, self.__mac)
|
||||||
else:
|
raise GpioDriverOfflineError(self)
|
||||||
logger.info("Wake-on-LAN packet sent")
|
|
||||||
finally:
|
finally:
|
||||||
if sock:
|
if sock:
|
||||||
try:
|
try:
|
||||||
sock.close()
|
sock.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"WakeOnLan({self._instance_name})"
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
@ -121,7 +121,7 @@
|
|||||||
<button class="small" data-force-hide-menu id="open-log-button">• Log</button>
|
<button class="small" data-force-hide-menu id="open-log-button">• Log</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="feature-disabled" id="wol">
|
<td class="feature-disabled" id="wol">
|
||||||
<button class="small" disabled data-force-hide-menu id="wol-wakeup-button">• WoL</button>
|
<button class="gpio-button small" data-force-hide-menu id="gpio-button-__wol__" data-channel="__wol__" data-confirm="Are you sure to send Wake-on-LAN packet to the server?">• WoL</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -12,7 +12,9 @@ li(class="right")
|
|||||||
td(id="webterm" class="feature-disabled") #[button(data-force-hide-menu data-show-window="webterm-window" class="small") • Term]
|
td(id="webterm" class="feature-disabled") #[button(data-force-hide-menu data-show-window="webterm-window" class="small") • Term]
|
||||||
td #[button(data-force-hide-menu data-show-window="about-window" class="small") • About]
|
td #[button(data-force-hide-menu data-show-window="about-window" class="small") • About]
|
||||||
td #[button(data-force-hide-menu id="open-log-button" class="small") • Log]
|
td #[button(data-force-hide-menu id="open-log-button" class="small") • Log]
|
||||||
td(id="wol" class="feature-disabled") #[button(disabled data-force-hide-menu id="wol-wakeup-button" class="small") • WoL]
|
td(id="wol" class="feature-disabled")
|
||||||
|
button(data-force-hide-menu id="gpio-button-__wol__" class="gpio-button small" data-channel="__wol__"
|
||||||
|
data-confirm="Are you sure to send Wake-on-LAN packet to the server?") • WoL
|
||||||
hr
|
hr
|
||||||
table(class="kv" style="width: calc(100% - 20px)")
|
table(class="kv" style="width: calc(100% - 20px)")
|
||||||
tr(id="stream-resolution" class="feature-disabled")
|
tr(id="stream-resolution" class="feature-disabled")
|
||||||
|
|||||||
@ -105,6 +105,7 @@ export function Gpio() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tools.featureSetEnabled($("v3-usb-breaker"), ("__v3_usb_breaker__" in model.scheme.outputs));
|
tools.featureSetEnabled($("v3-usb-breaker"), ("__v3_usb_breaker__" in model.scheme.outputs));
|
||||||
|
tools.featureSetEnabled($("wol"), ("__wol__" in model.scheme.outputs));
|
||||||
|
|
||||||
self.setState(__state);
|
self.setState(__state);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,7 +30,6 @@ import {Hid} from "./hid.js";
|
|||||||
import {Atx} from "./atx.js";
|
import {Atx} from "./atx.js";
|
||||||
import {Msd} from "./msd.js";
|
import {Msd} from "./msd.js";
|
||||||
import {Streamer} from "./stream.js";
|
import {Streamer} from "./stream.js";
|
||||||
import {WakeOnLan} from "./wol.js";
|
|
||||||
import {Gpio} from "./gpio.js";
|
import {Gpio} from "./gpio.js";
|
||||||
|
|
||||||
|
|
||||||
@ -48,7 +47,6 @@ export function Session() {
|
|||||||
var __hid = new Hid(__streamer.getResolution);
|
var __hid = new Hid(__streamer.getResolution);
|
||||||
var __atx = new Atx();
|
var __atx = new Atx();
|
||||||
var __msd = new Msd();
|
var __msd = new Msd();
|
||||||
var __wol = new WakeOnLan();
|
|
||||||
var __gpio = new Gpio();
|
var __gpio = new Gpio();
|
||||||
|
|
||||||
var __init__ = function() {
|
var __init__ = function() {
|
||||||
@ -243,7 +241,6 @@ export function Session() {
|
|||||||
case "info_hw_state": __setAboutInfoHw(data.event); break;
|
case "info_hw_state": __setAboutInfoHw(data.event); break;
|
||||||
case "info_system_state": __setAboutInfoSystem(data.event); break;
|
case "info_system_state": __setAboutInfoSystem(data.event); break;
|
||||||
case "info_extras_state": __setExtras(data.event); break;
|
case "info_extras_state": __setExtras(data.event); break;
|
||||||
case "wol_state": __wol.setState(data.event); break;
|
|
||||||
case "gpio_model_state": __gpio.setModel(data.event); break;
|
case "gpio_model_state": __gpio.setModel(data.event); break;
|
||||||
case "gpio_state": __gpio.setState(data.event); break;
|
case "gpio_state": __gpio.setState(data.event); break;
|
||||||
case "hid_keymaps_state": __hid.setKeymaps(data.event); break;
|
case "hid_keymaps_state": __hid.setKeymaps(data.event); break;
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
# #
|
|
||||||
# KVMD - The main Pi-KVM daemon. #
|
|
||||||
# #
|
|
||||||
# Copyright (C) 2018-2021 Maxim Devaev <mdevaev@gmail.com> #
|
|
||||||
# #
|
|
||||||
# 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 <https://www.gnu.org/licenses/>. #
|
|
||||||
# #
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
|
|
||||||
import {tools, $} from "../tools.js";
|
|
||||||
import {wm} from "../wm.js";
|
|
||||||
|
|
||||||
|
|
||||||
export function WakeOnLan() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
|
|
||||||
var __target = {};
|
|
||||||
|
|
||||||
var __init__ = function() {
|
|
||||||
tools.setOnClick($("wol-wakeup-button"), __clickWakeupButton);
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
|
|
||||||
self.setState = function(state) {
|
|
||||||
if (state) {
|
|
||||||
tools.featureSetEnabled($("wol"), state.enabled);
|
|
||||||
__target = state.target;
|
|
||||||
}
|
|
||||||
wm.setElementEnabled($("wol-wakeup-button"), (state && state.enabled));
|
|
||||||
};
|
|
||||||
|
|
||||||
var __clickWakeupButton = function() {
|
|
||||||
let msg = `
|
|
||||||
Are you sure to send Wake-on-LAN packet to the server?<br>
|
|
||||||
Target: <b>${__target.mac}</b> (${__target.ip}:${__target.port})?
|
|
||||||
`;
|
|
||||||
wm.confirm(msg).then(function(ok) {
|
|
||||||
if (ok) {
|
|
||||||
let http = tools.makeRequest("POST", "/api/wol/wakeup", function() {
|
|
||||||
if (http.readyState === 4) {
|
|
||||||
if (http.status !== 200) {
|
|
||||||
wm.error("Wakeup error:<br>", http.responseText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__init__();
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user