'k' and 'v' are minimally functional
This commit is contained in:
parent
4b61cdd98f
commit
9726239fe5
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
ArduinoJson/
|
@ -7,40 +7,86 @@ void loop() {}
|
||||
#else
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <USB.h>
|
||||
#include <USBHIDMouse.h>
|
||||
#include <USBHIDKeyboard.h>
|
||||
|
||||
USBHIDMouse Mouse;
|
||||
USBHIDKeyboard Keyboard;
|
||||
|
||||
HardwareSerial &host_serial = Serial;
|
||||
HardwareSerial &mobo_serial = Serial1;
|
||||
|
||||
JsonDocument mkb_input;
|
||||
|
||||
// put function declarations here:
|
||||
int myFunction(int, int);
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
int result = myFunction(2, 3);
|
||||
Serial.begin(115200);
|
||||
Mouse.begin();
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
char buffer[100];
|
||||
|
||||
void setup()
|
||||
{
|
||||
host_serial.begin(115200);
|
||||
mobo_serial.begin(115200, SERIAL_8N1, 18);
|
||||
Mouse.begin();
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//Keyboard.write(0x4C);
|
||||
//Keyboard.pressRaw(HID_KEY_DELETE);
|
||||
//Keyboard.releaseRaw(HID_KEY_DELETE);
|
||||
// put your main code here, to run repeatedly:
|
||||
/*if (Serial.available() > 0) {
|
||||
char inChar = Serial.read();
|
||||
void loop()
|
||||
{
|
||||
// Keyboard.write(0x4C);
|
||||
// Keyboard.pressRaw(HID_KEY_DELETE);
|
||||
// Keyboard.releaseRaw(HID_KEY_DELETE);
|
||||
// put your main code here, to run repeatedly:
|
||||
/*if (Serial.available() > 0) {
|
||||
char inChar = Serial.read();
|
||||
|
||||
|
||||
}*/
|
||||
sleep(1000);
|
||||
|
||||
}*/
|
||||
//while (mobo_serial.available())
|
||||
//{
|
||||
// char c = mobo_serial.read();
|
||||
// host_serial.write(c);
|
||||
//}
|
||||
if (host_serial.available())
|
||||
{
|
||||
DeserializationError error = deserializeJson(mkb_input, host_serial);
|
||||
|
||||
if (error)
|
||||
{
|
||||
host_serial.print("deserializeJson() failed: ");
|
||||
host_serial.println(error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
JsonArray key_down = mkb_input["key_down"];
|
||||
JsonArray key_up = mkb_input["key_up"];
|
||||
//host_serial.println("Hej!");
|
||||
//serializeJsonPretty(key_down, host_serial);
|
||||
//serializeJsonPretty(key_up, host_serial);
|
||||
//host_serial.println("Hej2!");
|
||||
for (JsonVariant key : key_down)
|
||||
{
|
||||
Keyboard.pressRaw(key.as<u8_t>());
|
||||
host_serial.println(key.as<u8_t>());
|
||||
}
|
||||
for (JsonVariant key : key_up)
|
||||
{
|
||||
Keyboard.releaseRaw(key.as<u8_t>());
|
||||
host_serial.println(key.as<u8_t>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// put function definitions here:
|
||||
int myFunction(int x, int y) {
|
||||
return x + y;
|
||||
int myFunction(int x, int y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
#endif /* ARDUINO_USB_MODE */
|
@ -17,6 +17,7 @@ board = rymcu-esp32-s3-devkitc-1
|
||||
framework = arduino
|
||||
build_flags = -DARDUINO_USB_MODE=0
|
||||
monitor_speed = 115200
|
||||
lib_deps = bblanchon/ArduinoJson @ ~7.3.0
|
||||
|
||||
[platformio]
|
||||
src_dir = esp32/src
|
||||
|
@ -1 +1 @@
|
||||
{"video_device": {"friendly_name": "WARRKY USB 3.0", "format": "mjpeg", "resolution": "1920x1080", "fps": "60.000"}, "esp32_serial": "usb-Espressif_USB_JTAG_serial_debug_unit_CC:8D:A2:0F:C0:08-if00"}
|
||||
{"video_device": {"friendly_name": "WARRKY USB 3.0", "format": "mjpeg", "resolution": "1920x1080", "fps": "60.000"}, "esp32_serial": "usb-1a86_USB_Single_Serial_585D015807-if00"}
|
28
serialtest.py
Normal file
28
serialtest.py
Normal file
@ -0,0 +1,28 @@
|
||||
import serial
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
def read_serial(port):
|
||||
try:
|
||||
# Open the serial port
|
||||
with serial.Serial(port, 115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE) as ser:
|
||||
print(f"Listening on {port} at 115200 baud...")
|
||||
while True:
|
||||
# Read a line from the serial port
|
||||
line = ser.read()
|
||||
# Print the raw data
|
||||
print(f'{datetime.datetime.now()} {line}')
|
||||
except serial.SerialException as e:
|
||||
print(f"Error: {e}")
|
||||
except KeyboardInterrupt:
|
||||
print("Exiting...")
|
||||
sys.exit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
#if len(sys.argv) != 2:
|
||||
# print("Usage: python read_serial.py <port>")
|
||||
# print("Example: python read_serial.py COM3 (Windows) or /dev/ttyUSB0 (Linux)")
|
||||
# sys.exit(1)
|
||||
|
||||
#port_name = sys.argv[1]
|
||||
read_serial("/dev/serial/by-id/usb-1a86_USB_Single_Serial_585D015807-if00")
|
62
webui/app.py
Normal file
62
webui/app.py
Normal file
@ -0,0 +1,62 @@
|
||||
import subprocess
|
||||
from flask import Flask, Response
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def generate():
|
||||
# FFmpeg command to capture the MJPEG stream without re-encoding.
|
||||
command = [
|
||||
'ffmpeg',
|
||||
'-f', 'v4l2',
|
||||
'-input_format', 'mjpeg', '-video_size', '1920x1080', '-framerate', '60.00',
|
||||
'-i', '/dev/video0',
|
||||
'-c', 'copy',
|
||||
'-f', 'mjpeg',
|
||||
'pipe:1'
|
||||
]
|
||||
# Start the FFmpeg subprocess.
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=10**8)
|
||||
data = b""
|
||||
while True:
|
||||
# Read raw bytes from FFmpeg's stdout.
|
||||
chunk = process.stdout.read(1024)
|
||||
if not chunk:
|
||||
break
|
||||
data += chunk
|
||||
|
||||
# Look for complete JPEG frames by finding start and end markers.
|
||||
while True:
|
||||
start = data.find(b'\xff\xd8') # JPEG start
|
||||
end = data.find(b'\xff\xd9') # JPEG end
|
||||
if start != -1 and end != -1 and end > start:
|
||||
# Extract the JPEG frame.
|
||||
jpg = data[start:end+2]
|
||||
data = data[end+2:]
|
||||
# Yield the frame with the required multipart MJPEG boundaries.
|
||||
yield (b'--frame\r\n'
|
||||
b'Content-Type: image/jpeg\r\n\r\n' + jpg + b'\r\n')
|
||||
else:
|
||||
break
|
||||
|
||||
@app.route('/video_feed')
|
||||
def video_feed():
|
||||
# Set the MIME type to multipart so browsers render it as an MJPEG stream.
|
||||
return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return """
|
||||
<html>
|
||||
<head>
|
||||
<title>Webcam Stream</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Webcam Stream</h1>
|
||||
<img src="/video_feed">
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000)
|
||||
|
@ -1,10 +1,12 @@
|
||||
from os import name, listdir
|
||||
from flask import Flask
|
||||
from flask_socketio import SocketIO
|
||||
import json
|
||||
import logging
|
||||
|
||||
ui = Flask(__name__)
|
||||
logger = ui.logger
|
||||
app = Flask(__name__)
|
||||
ui = SocketIO(app)
|
||||
logger = app.logger
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
def new_profile():
|
||||
|
@ -21,8 +21,6 @@ class FrameBuffer(threading.Thread):
|
||||
|
||||
def capture_feed(self):
|
||||
device = self.acquire_device()
|
||||
print(device)
|
||||
time.sleep(5)
|
||||
while True:
|
||||
# try:
|
||||
# for frame in device.decode(video=0):
|
||||
@ -72,7 +70,7 @@ class FrameBuffer(threading.Thread):
|
||||
else:
|
||||
raise RuntimeError("We're on something other than Linux, and that's not yet supported!")
|
||||
|
||||
device.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
|
||||
device.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"YUYV"))
|
||||
device.set(cv2.CAP_PROP_FRAME_WIDTH, int(profile["video_device"]["resolution"].split('x')[0]))
|
||||
device.set(cv2.CAP_PROP_FRAME_HEIGHT, int(profile["video_device"]["resolution"].split('x')[1]))
|
||||
device.set(cv2.CAP_PROP_FPS, float(profile["video_device"]["fps"]))
|
||||
|
@ -1,7 +1,10 @@
|
||||
from ipkvm import ui
|
||||
from ipkvm import app, ui
|
||||
from ipkvm import frame_buffer
|
||||
from flask import Response
|
||||
from flask import Response, render_template
|
||||
import time
|
||||
from ipkvm.util.mkb import HIDKeyCode
|
||||
import serial
|
||||
import json
|
||||
|
||||
def generate_frames():
|
||||
while True:
|
||||
@ -9,22 +12,46 @@ def generate_frames():
|
||||
frame_buffer.new_frame.clear()
|
||||
yield (b'--frame\r\n'
|
||||
b'Content-Type: image/jpeg\r\n\r\n' + frame_buffer.cur_frame + b'\r\n')
|
||||
|
||||
@ui.on('key_down')
|
||||
def handle_keydown(data):
|
||||
test_json_a = {
|
||||
"mouseX": 99999,
|
||||
"mouseY": 99999,
|
||||
"mouse_down": ["rbutton", "lbutton"],
|
||||
"mouse_up": ["otherbutton"],
|
||||
"key_up": [],
|
||||
"key_down": [HIDKeyCode[data]]
|
||||
}
|
||||
|
||||
@ui.route('/video_feed')
|
||||
print(HIDKeyCode[data])
|
||||
with serial.Serial('/dev/serial/by-id/usb-1a86_USB_Single_Serial_585D015807-if00', 115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE) as ser:
|
||||
ser.write(json.dumps(test_json_a).encode())
|
||||
|
||||
@ui.on('key_up')
|
||||
def handle_keyup(data):
|
||||
test_json_a = {
|
||||
"mouseX": 99999,
|
||||
"mouseY": 99999,
|
||||
"mouse_down": ["rbutton", "lbutton"],
|
||||
"mouse_up": ["otherbutton"],
|
||||
"key_up": [HIDKeyCode[data]],
|
||||
"key_down": []
|
||||
}
|
||||
|
||||
print(HIDKeyCode[data])
|
||||
with serial.Serial('/dev/serial/by-id/usb-1a86_USB_Single_Serial_585D015807-if00', 115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE) as ser:
|
||||
ser.write(json.dumps(test_json_a).encode())
|
||||
|
||||
@app.route('/video_feed')
|
||||
def video_feed():
|
||||
return Response(generate_frames(),
|
||||
mimetype='multipart/x-mixed-replace; boundary=frame')
|
||||
|
||||
@ui.route('/')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return """
|
||||
<html>
|
||||
<head>
|
||||
<title>Webcam Stream</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Webcam Stream</h1>
|
||||
<img src="/video_feed">
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return render_template('index.html')
|
||||
|
||||
"""@socketio.on("connect")
|
||||
def kvm_client():
|
||||
ui.start_background_task(mkb_handler)"""
|
||||
|
30
webui/ipkvm/static/mkb_handler.js
Normal file
30
webui/ipkvm/static/mkb_handler.js
Normal file
@ -0,0 +1,30 @@
|
||||
const streamview = document.getElementById('streamview');
|
||||
|
||||
var socket = io();
|
||||
|
||||
function keydown_handler(event)
|
||||
{
|
||||
console.log(`Key pressed: ${event.code}`);
|
||||
socket.emit('key_down', event.code);
|
||||
}
|
||||
|
||||
function keyup_handler(event)
|
||||
{
|
||||
console.log(`Key released: ${event.code}`);
|
||||
socket.emit('key_up', event.code);
|
||||
}
|
||||
|
||||
function enable_listener()
|
||||
{
|
||||
document.addEventListener("keydown", keydown_handler);
|
||||
document.addEventListener("keyup", keyup_handler);
|
||||
}
|
||||
|
||||
function disable_listener()
|
||||
{
|
||||
document.removeEventListener("keydown", keydown_handler);
|
||||
document.removeEventListener("keyup", keyup_handler);
|
||||
}
|
||||
|
||||
streamview.addEventListener("mouseenter", enable_listener);
|
||||
streamview.addEventListener("mouseleave", disable_listener);
|
8
webui/ipkvm/static/style.css
Normal file
8
webui/ipkvm/static/style.css
Normal file
@ -0,0 +1,8 @@
|
||||
.stream-container {
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.stream-view {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
7
webui/ipkvm/static/vendor/socket.io.min.js
generated
vendored
Normal file
7
webui/ipkvm/static/vendor/socket.io.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,22 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<script src="{{ url_for('static', filename='vendor/socket.io.min.js') }}"></script>
|
||||
<html>
|
||||
<head>
|
||||
<title>MJPEG Stream Viewer</title>
|
||||
<style>
|
||||
.stream-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.stream-view {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
<title>IP KVM & OC Tuner</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="stream-container">
|
||||
<img src="{{ url_for('video_feed') }}" class="stream-view" />
|
||||
<div id="streamview" class="stream-container">
|
||||
<img src="/video_feed" class="stream-view" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
<script src="{{ url_for('static', filename='mkb_handler.js') }}"></script>
|
134
webui/ipkvm/util/mkb.py
Normal file
134
webui/ipkvm/util/mkb.py
Normal file
@ -0,0 +1,134 @@
|
||||
from enum import IntEnum
|
||||
|
||||
# God Bless CHADGPT
|
||||
class HIDKeyCode(IntEnum):
|
||||
"""
|
||||
Enum that translates modern JS key.code values to HID scancodes.
|
||||
"""
|
||||
# Letter keys (A-Z)
|
||||
KeyA = 4
|
||||
KeyB = 5
|
||||
KeyC = 6
|
||||
KeyD = 7
|
||||
KeyE = 8
|
||||
KeyF = 9
|
||||
KeyG = 10
|
||||
KeyH = 11
|
||||
KeyI = 12
|
||||
KeyJ = 13
|
||||
KeyK = 14
|
||||
KeyL = 15
|
||||
KeyM = 16
|
||||
KeyN = 17
|
||||
KeyO = 18
|
||||
KeyP = 19
|
||||
KeyQ = 20
|
||||
KeyR = 21
|
||||
KeyS = 22
|
||||
KeyT = 23
|
||||
KeyU = 24
|
||||
KeyV = 25
|
||||
KeyW = 26
|
||||
KeyX = 27
|
||||
KeyY = 28
|
||||
KeyZ = 29
|
||||
|
||||
# Number keys (top row)
|
||||
Digit1 = 30
|
||||
Digit2 = 31
|
||||
Digit3 = 32
|
||||
Digit4 = 33
|
||||
Digit5 = 34
|
||||
Digit6 = 35
|
||||
Digit7 = 36
|
||||
Digit8 = 37
|
||||
Digit9 = 38
|
||||
Digit0 = 39
|
||||
|
||||
# Control keys
|
||||
Enter = 40
|
||||
Escape = 41
|
||||
Backspace = 42
|
||||
Tab = 43
|
||||
Space = 44
|
||||
|
||||
Minus = 45
|
||||
Equal = 46
|
||||
BracketLeft = 47
|
||||
BracketRight = 48
|
||||
Backslash = 49
|
||||
|
||||
# Punctuation keys
|
||||
Semicolon = 51
|
||||
Quote = 52
|
||||
Backquote = 53
|
||||
Comma = 54
|
||||
Period = 55
|
||||
Slash = 56
|
||||
|
||||
CapsLock = 57
|
||||
|
||||
# Function keys (F1-F12)
|
||||
F1 = 58
|
||||
F2 = 59
|
||||
F3 = 60
|
||||
F4 = 61
|
||||
F5 = 62
|
||||
F6 = 63
|
||||
F7 = 64
|
||||
F8 = 65
|
||||
F9 = 66
|
||||
F10 = 67
|
||||
F11 = 68
|
||||
F12 = 69
|
||||
|
||||
PrintScreen = 70
|
||||
ScrollLock = 71
|
||||
Pause = 72
|
||||
|
||||
Insert = 73
|
||||
Home = 74
|
||||
PageUp = 75
|
||||
|
||||
Delete = 76
|
||||
End = 77
|
||||
PageDown = 78
|
||||
|
||||
ArrowRight = 79
|
||||
ArrowLeft = 80
|
||||
ArrowDown = 81
|
||||
ArrowUp = 82
|
||||
|
||||
# Numpad keys
|
||||
NumLock = 83
|
||||
NumpadDivide = 84
|
||||
NumpadMultiply = 85
|
||||
NumpadSubtract = 86
|
||||
NumpadAdd = 87
|
||||
NumpadEnter = 88
|
||||
Numpad1 = 89
|
||||
Numpad2 = 90
|
||||
Numpad3 = 91
|
||||
Numpad4 = 92
|
||||
Numpad5 = 93
|
||||
Numpad6 = 94
|
||||
Numpad7 = 95
|
||||
Numpad8 = 96
|
||||
Numpad9 = 97
|
||||
Numpad0 = 98
|
||||
NumpadDecimal = 99
|
||||
|
||||
# Additional keys
|
||||
IntlBackslash = 100
|
||||
ContextMenu = 101
|
||||
Power = 102
|
||||
|
||||
# Modifier keys
|
||||
ControlLeft = 224
|
||||
ShiftLeft = 225
|
||||
AltLeft = 226
|
||||
MetaLeft = 227 # Windows / Command key (left)
|
||||
ControlRight = 228
|
||||
ShiftRight = 229
|
||||
AltRight = 230
|
||||
MetaRight = 231 # Windows / Command key (right)
|
2
webui/ipkvm/util/super_serial.py
Normal file
2
webui/ipkvm/util/super_serial.py
Normal file
@ -0,0 +1,2 @@
|
||||
import serial
|
||||
|
@ -1,4 +1,4 @@
|
||||
from ipkvm import ui
|
||||
from ipkvm import app, ui
|
||||
|
||||
if __name__ == '__main__':
|
||||
ui.run(host='0.0.0.0', port=5000)
|
||||
ui.run(app, host='0.0.0.0', port=5000)
|
||||
|
52
webui/serial_test.py
Normal file
52
webui/serial_test.py
Normal file
@ -0,0 +1,52 @@
|
||||
import serial
|
||||
import sys
|
||||
import datetime
|
||||
import json
|
||||
import time
|
||||
|
||||
test_json_a = {
|
||||
"mouseX": 99999,
|
||||
"mouseY": 99999,
|
||||
"mouse_down": ["rbutton", "lbutton"],
|
||||
"mouse_up": ["otherbutton"],
|
||||
"key_up": [],
|
||||
"key_down": [11, 12]
|
||||
}
|
||||
|
||||
test_json_b = {
|
||||
"mouseX": 99999,
|
||||
"mouseY": 99999,
|
||||
"mouse_down": ["rbutton", "lbutton"],
|
||||
"mouse_up": ["otherbutton"],
|
||||
"key_up": [11, 12],
|
||||
"key_down": []
|
||||
}
|
||||
|
||||
def read_serial(port):
|
||||
try:
|
||||
# Open the serial port
|
||||
with serial.Serial(port, 115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE) as ser:
|
||||
print(f"Listening on {port} at 115200 baud...")
|
||||
while True:
|
||||
# Read a line from the serial port
|
||||
while ser.in_waiting > 0:
|
||||
line = ser.readline()
|
||||
print(f'{datetime.datetime.now()} {line}')
|
||||
# Print the raw data
|
||||
ser.write(json.dumps(test_json_a).encode())
|
||||
ser.write(json.dumps(test_json_b).encode())
|
||||
time.sleep(1)
|
||||
except serial.SerialException as e:
|
||||
print(f"Error: {e}")
|
||||
except KeyboardInterrupt:
|
||||
print("Exiting...")
|
||||
sys.exit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
#if len(sys.argv) != 2:
|
||||
# print("Usage: python read_serial.py <port>")
|
||||
# print("Example: python read_serial.py COM3 (Windows) or /dev/ttyUSB0 (Linux)")
|
||||
# sys.exit(1)
|
||||
|
||||
#port_name = sys.argv[1]
|
||||
read_serial('/dev/serial/by-id/usb-1a86_USB_Single_Serial_585D015807-if00')
|
Loading…
x
Reference in New Issue
Block a user