some power control buttons implemented

seven-segment post codes added to webui
other optimizations
This commit is contained in:
rawhide kobayashi 2025-03-04 15:58:47 -06:00
parent 89e8785265
commit f548353fa6
Signed by: rawhide_k
GPG Key ID: E71F77DDBC513FD7
14 changed files with 1092 additions and 98 deletions

View File

@ -11,6 +11,7 @@ void loop() {}
#include <USB.h>
#include <USBHIDMouse.h>
#include <USBHIDKeyboard.h>
#include <USBHIDSystemControl.h>
USBHIDAbsoluteMouse Mouse;
USBHIDKeyboard Keyboard;
@ -19,11 +20,15 @@ HardwareSerial &host_serial = Serial;
HardwareSerial &mobo_serial = Serial1;
JsonDocument mkb_input;
JsonDocument post_codes;
JsonDocument power_status;
// put function declarations here:
int myFunction(int, int);
char buffer[100];
const int8_t pwr_button = 3;
const int8_t cmos_button = 46;
const int8_t pwr_detect = 8;
void setup()
{
@ -32,15 +37,42 @@ void setup()
Mouse.begin();
Keyboard.begin();
USB.begin();
pinMode(pwr_button, OUTPUT);
pinMode(cmos_button, OUTPUT);
pinMode(pwr_detect, INPUT);
}
void loop()
{
static volatile int64_t cur_loop_timestamp = esp_timer_get_time();
cur_loop_timestamp = esp_timer_get_time();
// Immediately check power status!
static volatile int64_t check_power_status_timestamp = -200000;
if (cur_loop_timestamp - check_power_status_timestamp >= 100000)
{
if (analogRead(pwr_detect) > 1000)
{
power_status["pwr"] = "on";
}
else
{
power_status["pwr"] = "off";
}
serializeJson(power_status, host_serial);
host_serial.write('\n');
check_power_status_timestamp = esp_timer_get_time();
}
while (mobo_serial.available())
{
char c = mobo_serial.read();
host_serial.write(c);
post_codes["post_code"] = mobo_serial.read();
serializeJson(post_codes, host_serial);
host_serial.write('\n');
}
if (host_serial.available())
{
DeserializationError error = deserializeJson(mkb_input, host_serial);
@ -54,23 +86,6 @@ void loop()
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>());
//}
if (mkb_input["key_down"].is<JsonVariant>())
{
Keyboard.pressRaw(mkb_input["key_down"].as<uint8_t>());
@ -95,6 +110,16 @@ void loop()
{
Mouse.release(mkb_input["mouse_up"].as<uint8_t>());
}
else if (mkb_input["pwr"].is<JsonVariant>())
{
digitalWrite(pwr_button, mkb_input["pwr"].as<uint8_t>());
}
else if (mkb_input["cmos"].is<JsonVariant>())
{
digitalWrite(cmos_button, mkb_input["cmos"].as<uint8_t>());
}
}
}
}

View File

@ -100,4 +100,4 @@ from ipkvm.util.mkb import Esp32Serial
frame_buffer = feed.FrameBuffer()
esp32_serial = Esp32Serial()
from ipkvm import routes
from ipkvm import routes, events

96
webui/ipkvm/events.py Normal file
View File

@ -0,0 +1,96 @@
from ipkvm import ui
from ipkvm import esp32_serial
from ipkvm.util.mkb import HIDKeyCode, HIDMouseScanCodes, GPIO
import time
def power_switch(delay: float):
msg = {
"pwr": GPIO.HIGH.value
}
esp32_serial.mkb_queue.put(msg)
time.sleep(delay)
msg = {
"pwr": GPIO.LOW.value
}
esp32_serial.mkb_queue.put(msg)
@ui.on("power_on")
def handle_poweron():
if esp32_serial.power_status == "off":
power_switch(0.2)
@ui.on("soft_power_off")
def handle_soft_poweroff():
if esp32_serial.power_status == "on":
power_switch(0.2)
@ui.on("hard_power_off")
def handle_hard_poweroff():
if esp32_serial.power_status == "on":
power_switch(0.5)
@ui.on("reboot_into_bios")
def handle_reboot_bios():
if esp32_serial.power_status == "on": # and OS state = offline
power_switch(5)
time.sleep(2)
power_switch(0.2)
else:
power_switch(0.2)
while time.time() - esp32_serial.bios_timer <= 5 or time.time() - esp32_serial.bios_timer >= 6:
print(time.time() - esp32_serial.bios_timer)
msg = {
"key_down": HIDKeyCode.Delete.value
}
esp32_serial.mkb_queue.put(msg)
time.sleep(0.1)
msg = {
"key_up": HIDKeyCode.Delete.value
}
esp32_serial.mkb_queue.put(msg)
time.sleep(0.1)
@ui.on('key_down')
def handle_keydown(data: str):
msg = {
"key_down": HIDKeyCode[data].value
}
esp32_serial.mkb_queue.put(msg)
@ui.on('key_up')
def handle_keyup(data: str):
msg = {
"key_up": HIDKeyCode[data].value
}
esp32_serial.mkb_queue.put(msg)
@ui.on("mouse_move")
def handle_mousemove(data: list[int]):
msg = {
"mouse_coord": {
"x": data[0],
"y": data[1]
}
}
esp32_serial.mkb_queue.put(msg)
@ui.on('mouse_down')
def handle_mousedown(data: int):
msg = {
"mouse_down": HIDMouseScanCodes[data]
}
esp32_serial.mkb_queue.put(msg)
@ui.on('mouse_up')
def handle_mouseup(data: int):
msg = {
"mouse_up": HIDMouseScanCodes[data]
}
esp32_serial.mkb_queue.put(msg)

View File

@ -6,6 +6,8 @@ from ipkvm import profile
from ipkvm.util import video
from ipkvm import logger
import time
from PIL import Image
import io
class FrameBuffer(threading.Thread):
def __init__(self):
@ -35,8 +37,20 @@ class FrameBuffer(threading.Thread):
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
self.cur_frame = buffer.tobytes()
# ret, buffer = cv2.imencode('.jpg', frame)
# self.cur_frame = buffer.tobytes()
# Convert BGR (OpenCV) to RGB (PIL)
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Convert to PIL Image
img = Image.fromarray(frame_rgb)
# Save to a bytes buffer (for in-memory use)
buffer = io.BytesIO()
img.save(buffer, format="JPEG")
jpeg_bytes = buffer.getvalue() # This contains the JPEG image as bytes
self.cur_frame = jpeg_bytes
self.new_frame.set()

View File

@ -1,7 +1,7 @@
from ipkvm import app, ui
from ipkvm import frame_buffer, esp32_serial
from ipkvm import app
from ipkvm import frame_buffer
from flask import Response, render_template
from ipkvm.util.mkb import HIDKeyCode, HIDMouseScanCodes
def generate_frames():
while True:
@ -9,49 +9,6 @@ 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: str):
msg = {
"key_down": HIDKeyCode[data].value
}
esp32_serial.mkb_queue.put(msg)
@ui.on('key_up')
def handle_keyup(data: str):
msg = {
"key_up": HIDKeyCode[data].value
}
esp32_serial.mkb_queue.put(msg)
@ui.on("mouse_move")
def handle_mousemove(data: list[int]):
msg = {
"mouse_coord": {
"x": data[0],
"y": data[1]
}
}
esp32_serial.mkb_queue.put(msg)
@ui.on('mouse_down')
def handle_mousedown(data: int):
msg = {
"mouse_down": HIDMouseScanCodes[data]
}
esp32_serial.mkb_queue.put(msg)
@ui.on('mouse_up')
def handle_mouseup(data: int):
msg = {
"mouse_up": HIDMouseScanCodes[data]
}
esp32_serial.mkb_queue.put(msg)
@app.route('/video_feed')
def video_feed():

View File

@ -1,8 +1,15 @@
const streamview = document.getElementById('streamview');
var last_mouse_update = Date.now()
var socket = io();
function mkbhandler_load()
{
const streamview = document.getElementById('streamview');
streamview.addEventListener("mouseenter", enable_listener);
streamview.addEventListener("mouseleave", disable_listener);
}
function keydown_handler(event)
{
socket.emit('key_down', event.code);
@ -73,5 +80,4 @@ function disable_listener()
document.removeEventListener('contextmenu', prevent_right_click);
}
streamview.addEventListener("mouseenter", enable_listener);
streamview.addEventListener("mouseleave", disable_listener);
window.addEventListener("load", mkbhandler_load);

View File

@ -0,0 +1,28 @@
var display = new SegmentDisplay("display");
function sevensegment_load()
{
display.pattern = "##";
display.displayAngle = 10;
display.digitHeight = 20;
display.digitWidth = 14;
display.digitDistance = 2.5;
display.segmentWidth = 2;
display.segmentDistance = 0.3;
display.segmentCount = 7;
display.cornerType = 0;
display.colorOn = "#ff0000";
display.colorOff = "#4b1e05";
display.setValue("00");
display.draw();
}
function update_seven_segment(data)
{
console.log(data);
display.setValue(data);
}
socket.on("update_seven_segment", update_seven_segment);
window.addEventListener("load", sevensegment_load);

View File

@ -0,0 +1,558 @@
/*!
* segment-display.js
*
* Copyright 2012, Rüdiger Appel
* http://www.3quarks.com
* Published under Creative Commons 3.0 License.
*
* Date: 2012-02-14
* Version: 1.0.0
*
* Dokumentation: http://www.3quarks.com/de/Segmentanzeige
* Documentation: http://www.3quarks.com/en/SegmentDisplay
*/
// Segment display types
SegmentDisplay.SevenSegment = 7;
SegmentDisplay.FourteenSegment = 14;
SegmentDisplay.SixteenSegment = 16;
// Segment corner types
SegmentDisplay.SymmetricCorner = 0;
SegmentDisplay.SquaredCorner = 1;
SegmentDisplay.RoundedCorner = 2;
function SegmentDisplay(displayId) {
this.displayId = displayId;
this.pattern = '##:##:##';
this.value = '12:34:56';
this.digitHeight = 20;
this.digitWidth = 10;
this.digitDistance = 2.5;
this.displayAngle = 12;
this.segmentWidth = 2.5;
this.segmentDistance = 0.2;
this.segmentCount = SegmentDisplay.SevenSegment;
this.cornerType = SegmentDisplay.RoundedCorner;
this.colorOn = 'rgb(233, 93, 15)';
this.colorOff = 'rgb(75, 30, 5)';
};
SegmentDisplay.prototype.setValue = function(value) {
this.value = value;
this.draw();
};
SegmentDisplay.prototype.draw = function() {
var display = document.getElementById(this.displayId);
if (display) {
var context = display.getContext('2d');
if (context) {
// clear canvas
context.clearRect(0, 0, display.width, display.height);
// compute and check display width
var width = 0;
var first = true;
if (this.pattern) {
for (var i = 0; i < this.pattern.length; i++) {
var c = this.pattern.charAt(i).toLowerCase();
if (c == '#') {
width += this.digitWidth;
} else if (c == '.' || c == ':') {
width += this.segmentWidth;
} else if (c != ' ') {
return;
}
width += first ? 0 : this.digitDistance;
first = false;
}
}
if (width <= 0) {
return;
}
// compute skew factor
var angle = -1.0 * Math.max(-45.0, Math.min(45.0, this.displayAngle));
var skew = Math.tan((angle * Math.PI) / 180.0);
// compute scale factor
var scale = Math.min(display.width / (width + Math.abs(skew * this.digitHeight)), display.height / this.digitHeight);
// compute display offset
var offsetX = (display.width - (width + skew * this.digitHeight) * scale) / 2.0;
var offsetY = (display.height - this.digitHeight * scale) / 2.0;
// context transformation
context.save();
context.translate(offsetX, offsetY);
context.scale(scale, scale);
context.transform(1, 0, skew, 1, 0, 0);
// draw segments
var xPos = 0;
var size = (this.value) ? this.value.length : 0;
for (var i = 0; i < this.pattern.length; i++) {
var mask = this.pattern.charAt(i);
var value = (i < size) ? this.value.charAt(i).toLowerCase() : ' ';
xPos += this.drawDigit(context, xPos, mask, value);
}
// finish drawing
context.restore();
}
}
};
SegmentDisplay.prototype.drawDigit = function(context, xPos, mask, c) {
switch (mask) {
case '#':
var r = Math.sqrt(this.segmentWidth * this.segmentWidth / 2.0);
var d = Math.sqrt(this.segmentDistance * this.segmentDistance / 2.0);
var e = d / 2.0;
var f = (this.segmentWidth - d) * Math.sin((45.0 * Math.PI) / 180.0);
var g = f / 2.0;
var h = (this.digitHeight - 3.0 * this.segmentWidth) / 2.0;
var w = (this.digitWidth - 3.0 * this.segmentWidth) / 2.0;
var s = this.segmentWidth / 2.0;
var t = this.digitWidth / 2.0;
// draw segment a (a1 and a2 for 16 segments)
if (this.segmentCount == 16) {
var x = xPos;
var y = 0;
context.fillStyle = this.getSegmentColor(c, null, '02356789abcdefgiopqrstz@%');
context.beginPath();
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.moveTo(x + s + d, y + s);
context.lineTo(x + this.segmentWidth + d, y);
break;
case SegmentDisplay.SquaredCorner:
context.moveTo(x + s + e, y + s - e);
context.lineTo(x + this.segmentWidth, y);
break;
default:
context.moveTo(x + this.segmentWidth - f, y + this.segmentWidth - f - d);
context.quadraticCurveTo(x + this.segmentWidth - g, y, x + this.segmentWidth, y);
}
context.lineTo(x + t - d - s, y);
context.lineTo(x + t - d, y + s);
context.lineTo(x + t - d - s, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
context.fill();
var x = xPos;
var y = 0;
context.fillStyle = this.getSegmentColor(c, null, '02356789abcdefgiopqrstz@');
context.beginPath();
context.moveTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
context.lineTo(x + t + d + s, y + this.segmentWidth);
context.lineTo(x + t + d, y + s);
context.lineTo(x + t + d + s, y);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
context.lineTo(x + this.digitWidth - s - d, y + s);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
context.lineTo(x + this.digitWidth - s - e, y + s - e);
break;
default:
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y, x + this.digitWidth - this.segmentWidth + f, y + this.segmentWidth - f - d);
}
context.fill();
} else {
var x = xPos;
var y = 0;
context.fillStyle = this.getSegmentColor(c, '02356789acefp', '02356789abcdefgiopqrstz@');
context.beginPath();
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.moveTo(x + s + d, y + s);
context.lineTo(x + this.segmentWidth + d, y);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
context.lineTo(x + this.digitWidth - s - d, y + s);
break;
case SegmentDisplay.SquaredCorner:
context.moveTo(x + s + e, y + s - e);
context.lineTo(x + this.segmentWidth, y);
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
context.lineTo(x + this.digitWidth - s - e, y + s - e);
break;
default:
context.moveTo(x + this.segmentWidth - f, y + this.segmentWidth - f - d);
context.quadraticCurveTo(x + this.segmentWidth - g, y, x + this.segmentWidth, y);
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y, x + this.digitWidth - this.segmentWidth + f, y + this.segmentWidth - f - d);
}
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
context.fill();
}
// draw segment b
x = xPos + this.digitWidth - this.segmentWidth;
y = 0;
context.fillStyle = this.getSegmentColor(c, '01234789adhpy', '01234789abdhjmnopqruwy');
context.beginPath();
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.moveTo(x + s, y + s + d);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
break;
case SegmentDisplay.SquaredCorner:
context.moveTo(x + s + e, y + s + e);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
break;
default:
context.moveTo(x + f + d, y + this.segmentWidth - f);
context.quadraticCurveTo(x + this.segmentWidth, y + this.segmentWidth - g, x + this.segmentWidth, y + this.segmentWidth);
}
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
context.lineTo(x, y + h + this.segmentWidth - d);
context.lineTo(x, y + this.segmentWidth + d);
context.fill();
// draw segment c
x = xPos + this.digitWidth - this.segmentWidth;
y = h + this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, '013456789abdhnouy', '01346789abdghjmnoqsuw@', '%');
context.beginPath();
context.moveTo(x, y + this.segmentWidth + d);
context.lineTo(x + s, y + s + d);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
context.lineTo(x, y + h + this.segmentWidth - d);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x + s + e, y + h + this.segmentWidth + s - e);
context.lineTo(x, y + h + this.segmentWidth - d);
break;
default:
context.quadraticCurveTo(x + this.segmentWidth, y + h + this.segmentWidth + g, x + f + d, y + h + this.segmentWidth + f); //
context.lineTo(x, y + h + this.segmentWidth - d);
}
context.fill();
// draw segment d (d1 and d2 for 16 segments)
if (this.segmentCount == 16) {
x = xPos;
y = this.digitHeight - this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, null, '0235689bcdegijloqsuz_=@');
context.beginPath();
context.moveTo(x + this.segmentWidth + d, y);
context.lineTo(x + t - d - s, y);
context.lineTo(x + t - d, y + s);
context.lineTo(x + t - d - s, y + this.segmentWidth);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
context.lineTo(x + s + d, y + s);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
context.lineTo(x + s + e, y + s + e);
break;
default:
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
context.quadraticCurveTo(x + this.segmentWidth - g, y + this.segmentWidth, x + this.segmentWidth - f, y + f + d);
context.lineTo(x + this.segmentWidth - f, y + f + d);
}
context.fill();
x = xPos;
y = this.digitHeight - this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, null, '0235689bcdegijloqsuz_=@', '%');
context.beginPath();
context.moveTo(x + t + d + s, y + this.segmentWidth);
context.lineTo(x + t + d, y + s);
context.lineTo(x + t + d + s, y);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x + this.digitWidth - s - d, y + s);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x + this.digitWidth - s - e, y + s + e);
context.lineTo(x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
break;
default:
context.lineTo(x + this.digitWidth - this.segmentWidth + f, y + f + d);
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y + this.segmentWidth, x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
}
context.fill();
}
else {
x = xPos;
y = this.digitHeight - this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, '0235689bcdelotuy_', '0235689bcdegijloqsuz_=@');
context.beginPath();
context.moveTo(x + this.segmentWidth + d, y);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x + this.digitWidth - s - d, y + s);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
context.lineTo(x + s + d, y + s);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x + this.digitWidth - s - e, y + s + e);
context.lineTo(x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
context.lineTo(x + s + e, y + s + e);
break;
default:
context.lineTo(x + this.digitWidth - this.segmentWidth + f, y + f + d);
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y + this.segmentWidth, x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
context.quadraticCurveTo(x + this.segmentWidth - g, y + this.segmentWidth, x + this.segmentWidth - f, y + f + d);
context.lineTo(x + this.segmentWidth - f, y + f + d);
}
context.fill();
}
// draw segment e
x = xPos;
y = h + this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, '0268abcdefhlnoprtu', '0268acefghjklmnopqruvw@');
context.beginPath();
context.moveTo(x, y + this.segmentWidth + d);
context.lineTo(x + s, y + s + d);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
context.lineTo(x, y + h + this.segmentWidth - d);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x + s - e, y + h + this.segmentWidth + s - d + e);
context.lineTo(x, y + h + this.segmentWidth);
break;
default:
context.lineTo(x + this.segmentWidth - f - d, y + h + this.segmentWidth + f);
context.quadraticCurveTo(x, y + h + this.segmentWidth + g, x, y + h + this.segmentWidth);
}
context.fill();
// draw segment f
x = xPos;
y = 0;
context.fillStyle = this.getSegmentColor(c, '045689abcefhlpty', '045689acefghklmnopqrsuvwy@', '%');
context.beginPath();
context.moveTo(x + this.segmentWidth, y + this.segmentWidth + d);
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
context.lineTo(x, y + h + this.segmentWidth - d);
switch (this.cornerType) {
case SegmentDisplay.SymmetricCorner:
context.lineTo(x, y + this.segmentWidth + d);
context.lineTo(x + s, y + s + d);
break;
case SegmentDisplay.SquaredCorner:
context.lineTo(x, y + this.segmentWidth);
context.lineTo(x + s - e, y + s + e);
break;
default:
context.lineTo(x, y + this.segmentWidth);
context.quadraticCurveTo(x, y + this.segmentWidth - g, x + this.segmentWidth - f - d, y + this.segmentWidth - f);
context.lineTo(x + this.segmentWidth - f - d, y + this.segmentWidth - f);
}
context.fill();
// draw segment g for 7 segments
if (this.segmentCount == 7) {
x = xPos;
y = (this.digitHeight - this.segmentWidth) / 2.0;
context.fillStyle = this.getSegmentColor(c, '2345689abdefhnoprty-=');
context.beginPath();
context.moveTo(x + s + d, y + s);
context.lineTo(x + this.segmentWidth + d, y);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
context.lineTo(x + this.digitWidth - s - d, y + s);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
context.fill();
}
// draw inner segments for the fourteen- and sixteen-segment-display
if (this.segmentCount != 7) {
// draw segment g1
x = xPos;
y = (this.digitHeight - this.segmentWidth) / 2.0;
context.fillStyle = this.getSegmentColor(c, null, '2345689aefhkprsy-+*=', '%');
context.beginPath();
context.moveTo(x + s + d, y + s);
context.lineTo(x + this.segmentWidth + d, y);
context.lineTo(x + t - d - s, y);
context.lineTo(x + t - d, y + s);
context.lineTo(x + t - d - s, y + this.segmentWidth);
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
context.fill();
// draw segment g2
x = xPos;
y = (this.digitHeight - this.segmentWidth) / 2.0;
context.fillStyle = this.getSegmentColor(c, null, '234689abefghprsy-+*=@', '%');
context.beginPath();
context.moveTo(x + t + d, y + s);
context.lineTo(x + t + d + s, y);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
context.lineTo(x + this.digitWidth - s - d, y + s);
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
context.lineTo(x + t + d + s, y + this.segmentWidth);
context.fill();
// draw segment j
x = xPos + t - s;
y = 0;
context.fillStyle = this.getSegmentColor(c, null, 'bdit+*', '%');
context.beginPath();
if (this.segmentCount == 14) {
context.moveTo(x, y + this.segmentWidth + this.segmentDistance);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + this.segmentDistance);
} else {
context.moveTo(x, y + this.segmentWidth + d);
context.lineTo(x + s, y + s + d);
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
}
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
context.lineTo(x, y + h + this.segmentWidth - d);
context.fill();
// draw segment m
x = xPos + t - s;
y = this.digitHeight;
context.fillStyle = this.getSegmentColor(c, null, 'bdity+*@', '%');
context.beginPath();
if (this.segmentCount == 14) {
context.moveTo(x, y - this.segmentWidth - this.segmentDistance);
context.lineTo(x + this.segmentWidth, y - this.segmentWidth - this.segmentDistance);
} else {
context.moveTo(x, y - this.segmentWidth - d);
context.lineTo(x + s, y - s - d);
context.lineTo(x + this.segmentWidth, y - this.segmentWidth - d);
}
context.lineTo(x + this.segmentWidth, y - h - this.segmentWidth + d);
context.lineTo(x + s, y - h - this.segmentWidth - s + d);
context.lineTo(x, y - h - this.segmentWidth + d);
context.fill();
// draw segment h
x = xPos + this.segmentWidth;
y = this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, null, 'mnx\\*');
context.beginPath();
context.moveTo(x + this.segmentDistance, y + this.segmentDistance);
context.lineTo(x + this.segmentDistance + r, y + this.segmentDistance);
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance - r);
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance);
context.lineTo(x + w - this.segmentDistance - r , y + h - this.segmentDistance);
context.lineTo(x + this.segmentDistance, y + this.segmentDistance + r);
context.fill();
// draw segment k
x = xPos + w + 2.0 * this.segmentWidth;
y = this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, null, '0kmvxz/*', '%');
context.beginPath();
context.moveTo(x + w - this.segmentDistance, y + this.segmentDistance);
context.lineTo(x + w - this.segmentDistance, y + this.segmentDistance + r);
context.lineTo(x + this.segmentDistance + r, y + h - this.segmentDistance);
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance);
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance - r);
context.lineTo(x + w - this.segmentDistance - r, y + this.segmentDistance);
context.fill();
// draw segment l
x = xPos + w + 2.0 * this.segmentWidth;
y = h + 2.0 * this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, null, '5knqrwx\\*');
context.beginPath();
context.moveTo(x + this.segmentDistance, y + this.segmentDistance);
context.lineTo(x + this.segmentDistance + r, y + this.segmentDistance);
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance - r);
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance);
context.lineTo(x + w - this.segmentDistance - r , y + h - this.segmentDistance);
context.lineTo(x + this.segmentDistance, y + this.segmentDistance + r);
context.fill();
// draw segment n
x = xPos + this.segmentWidth;
y = h + 2.0 * this.segmentWidth;
context.fillStyle = this.getSegmentColor(c, null, '0vwxz/*', '%');
context.beginPath();
context.moveTo(x + w - this.segmentDistance, y + this.segmentDistance);
context.lineTo(x + w - this.segmentDistance, y + this.segmentDistance + r);
context.lineTo(x + this.segmentDistance + r, y + h - this.segmentDistance);
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance);
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance - r);
context.lineTo(x + w - this.segmentDistance - r, y + this.segmentDistance);
context.fill();
}
return this.digitDistance + this.digitWidth;
case '.':
context.fillStyle = (c == '#') || (c == '.') ? this.colorOn : this.colorOff;
this.drawPoint(context, xPos, this.digitHeight - this.segmentWidth, this.segmentWidth);
return this.digitDistance + this.segmentWidth;
case ':':
context.fillStyle = (c == '#') || (c == ':') ? this.colorOn : this.colorOff;
var y = (this.digitHeight - this.segmentWidth) / 2.0 - this.segmentWidth;
this.drawPoint(context, xPos, y, this.segmentWidth);
this.drawPoint(context, xPos, y + 2.0 * this.segmentWidth, this.segmentWidth);
return this.digitDistance + this.segmentWidth;
default:
return this.digitDistance;
}
};
SegmentDisplay.prototype.drawPoint = function(context, x1, y1, size) {
var x2 = x1 + size;
var y2 = y1 + size;
var d = size / 4.0;
context.beginPath();
context.moveTo(x2 - d, y1);
context.quadraticCurveTo(x2, y1, x2, y1 + d);
context.lineTo(x2, y2 - d);
context.quadraticCurveTo(x2, y2, x2 - d, y2);
context.lineTo(x1 + d, y2);
context.quadraticCurveTo(x1, y2, x1, y2 - d);
context.lineTo(x1, y1 + d);
context.quadraticCurveTo(x1, y1, x1 + d, y1);
context.fill();
};
SegmentDisplay.prototype.getSegmentColor = function(c, charSet7, charSet14, charSet16) {
if (c == '#') {
return this.colorOn;
} else {
switch (this.segmentCount) {
case 7: return (charSet7.indexOf(c) == -1) ? this.colorOff : this.colorOn;
case 14: return (charSet14.indexOf(c) == -1) ? this.colorOff : this.colorOn;
case 16: var pattern = charSet14 + (charSet16 === undefined ? '' : charSet16);
return (pattern.indexOf(c) == -1) ? this.colorOff : this.colorOn;
default: return this.colorOff;
}
}
};

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,30 @@
<!DOCTYPE html>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<script src="{{ url_for('static', filename='vendor/socket.io.min.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/vendor/socketio/socket.io.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/vendor/SegmentDisplay/segment-display.js') }}"></script>
<script src="{{ url_for('static', filename='js/mkb_handler.js') }}"></script>
<script src="{{ url_for('static', filename='js/seven_segment.js') }}"></script>
<html>
<head>
<title>IP KVM & OC Tuner</title>
</head>
<body>
<div id="streamview" class="stream-container">
<img src="/video_feed" class="stream-view" />
</div>
</body>
</html>
<script src="{{ url_for('static', filename='mkb_handler.js') }}"></script>
<head>
<title>IP KVM & OC Tuner</title>
</head>
<body>
<div id="streamview" class="stream-container">
<img src="/video_feed" class="stream-view" />
</div>
<button type="button" onclick="socket.emit(`power_on`);">Power on</button>
<button type="button" onclick="socket.emit(`soft_power_off`);">Soft power off</button>
<button type="button" onclick="socket.emit(`hard_power_off`);">Hard power off</button>
<button type="button" onclick="socket.emit(`reboot`);">Reboot</button>
<button type="button" onclick="socket.emit(`reboot_into_bios`);">Reboot into BIOS</button>
<button type="button" onclick="socket.emit(`clear_cmos`);">Clear CMOS</button>
<div id="displayView" class="topic" style="background-color: rgb(36, 30, 30); border: 3px solid rgb(153, 153, 153); width: 300px; height: 188px;">
<div style="padding:20px">
<canvas id="display" width="260" height="140">
Your browser is unfortunately not supported.
</canvas>
</div>
</div>
</body>
</html>

View File

@ -5,8 +5,271 @@ from ipkvm import profile
import threading
from queue import Queue
import json
import time
from ipkvm import ui
from collections.abc import Mapping
# python can't use NUMBERS as enum keys?!
POSTHex7Segment = {
0: "00",
1: "01",
2: "02",
3: "03",
4: "04",
5: "05",
6: "06",
7: "07",
8: "08",
9: "09",
10: "0A",
11: "0b",
12: "0C",
13: "0d",
14: "0E",
15: "0F",
16: "10",
17: "11",
18: "12",
19: "13",
20: "14",
21: "15",
22: "16",
23: "17",
24: "18",
25: "19",
26: "1A",
27: "1b",
28: "1C",
29: "1d",
30: "1E",
31: "1F",
32: "20",
33: "21",
34: "22",
35: "23",
36: "24",
37: "25",
38: "26",
39: "27",
40: "28",
41: "29",
42: "2A",
43: "2b",
44: "2C",
45: "2d",
46: "2E",
47: "2F",
48: "30",
49: "31",
50: "32",
51: "33",
52: "34",
53: "35",
54: "36",
55: "37",
56: "38",
57: "39",
58: "3A",
59: "3b",
60: "3C",
61: "3d",
62: "3E",
63: "3F",
64: "40",
65: "41",
66: "42",
67: "43",
68: "44",
69: "45",
70: "46",
71: "47",
72: "48",
73: "49",
74: "4A",
75: "4b",
76: "4C",
77: "4d",
78: "4E",
79: "4F",
80: "50",
81: "51",
82: "52",
83: "53",
84: "54",
85: "55",
86: "56",
87: "57",
88: "58",
89: "59",
90: "5A",
91: "5b",
92: "5C",
93: "5d",
94: "5E",
95: "5F",
96: "60",
97: "61",
98: "62",
99: "63",
100: "64",
101: "65",
102: "66",
103: "67",
104: "68",
105: "69",
106: "6A",
107: "6b",
108: "6C",
109: "6d",
110: "6E",
111: "6F",
112: "70",
113: "71",
114: "72",
115: "73",
116: "74",
117: "75",
118: "76",
119: "77",
120: "78",
121: "79",
122: "7A",
123: "7b",
124: "7C",
125: "7d",
126: "7E",
127: "7F",
128: "80",
129: "81",
130: "82",
131: "83",
132: "84",
133: "85",
134: "86",
135: "87",
136: "88",
137: "89",
138: "8A",
139: "8b",
140: "8C",
141: "8d",
142: "8E",
143: "8F",
144: "90",
145: "91",
146: "92",
147: "93",
148: "94",
149: "95",
150: "96",
151: "97",
152: "98",
153: "99",
154: "9A",
155: "9b",
156: "9C",
157: "9d",
158: "9E",
159: "9F",
160: "A0",
161: "A1",
162: "A2",
163: "A3",
164: "A4",
165: "A5",
166: "A6",
167: "A7",
168: "A8",
169: "A9",
170: "AA",
171: "Ab",
172: "AC",
173: "Ad",
174: "AE",
175: "AF",
176: "b0",
177: "b1",
178: "b2",
179: "b3",
180: "b4",
181: "b5",
182: "b6",
183: "b7",
184: "b8",
185: "b9",
186: "bA",
187: "bb",
188: "bC",
189: "bd",
190: "bE",
191: "bF",
192: "C0",
193: "C1",
194: "C2",
195: "C3",
196: "C4",
197: "C5",
198: "C6",
199: "C7",
200: "C8",
201: "C9",
202: "CA",
203: "Cb",
204: "CC",
205: "Cd",
206: "CE",
207: "CF",
208: "d0",
209: "d1",
210: "d2",
211: "d3",
212: "d4",
213: "d5",
214: "d6",
215: "d7",
216: "d8",
217: "d9",
218: "dA",
219: "db",
220: "dC",
221: "dd",
222: "dE",
223: "dF",
224: "E0",
225: "E1",
226: "E2",
227: "E3",
228: "E4",
229: "E5",
230: "E6",
231: "E7",
232: "E8",
233: "E9",
234: "EA",
235: "Eb",
236: "EC",
237: "Ed",
238: "EE",
239: "EF",
240: "F0",
241: "F1",
242: "F2",
243: "F3",
244: "F4",
245: "F5",
246: "F6",
247: "F7",
248: "F8",
249: "F9",
250: "FA",
251: "Fb",
252: "FC",
253: "Fd",
254: "FE",
255: "FF"
}
# Python can't make number to number enums???
HIDMouseScanCodes = {
0: 1,
2: 2,
@ -15,6 +278,10 @@ HIDMouseScanCodes = {
4: 16
}
class GPIO(IntEnum):
LOW = 0
HIGH = 1
# God Bless CHADGPT
class HIDKeyCode(IntEnum):
"""
@ -152,26 +419,49 @@ class Esp32Serial(threading.Thread):
def __init__(self):
super().__init__()
self.post_code_queue: Queue[str] = Queue()
self.mkb_queue: Queue[dict[str, int | dict[str, int]]] = Queue()
self.mkb_queue: Queue[Mapping[str, int | str | Mapping[str, int]]] = Queue()
self.change_serial_device = threading.Event()
self.device = self.get_device()
self.bios_timer = time.time()
self.power_status = None
self.start()
def run(self):
while True:
if self.change_serial_device.is_set():
self.change_serial_device.clear()
self.device = self.get_device()
with self.device as ser:
while True:
# if self.change_serial_device.is_set():
# self.change_serial_device.clear()
# self.device = self.get_device()
with self.device as ser:
while not self.mkb_queue.empty():
msg = self.mkb_queue.get()
ser.write(json.dumps(msg).encode())
while ser.in_waiting > 0:
print(ser.read().hex())
try:
line = json.loads(ser.readline().decode().strip())
if "pwr" in line:
self.power_status = line["pwr"]
elif "post_code" in line:
# This code is what presents when you are in BIOS, but also... Other times.
# In another part of the script, we'll check to see if it's hung around for a few
# seconds. If so, we are in BIOS.
if POSTHex7Segment[line["post_code"]] != "Ab":
self.bios_timer = time.time()
ui.emit("update_seven_segment", POSTHex7Segment[line["post_code"]])
except json.JSONDecodeError:
continue
except UnicodeDecodeError:
continue
# self.post_code_queue.put(ser.read().hex())
time.sleep(0.01)
def get_device(self):
if name == "posix":

View File

@ -41,16 +41,19 @@ def read_serial(port):
# 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...")
line = ser.readline().decode().strip()
while True:
# Read a line from the serial port
while ser.in_waiting > 0:
line = str(ser.read().hex())
print(f'{datetime.datetime.now()} {line}')
line = ser.readline().decode().strip()
line = json.loads(line)
print(line)
# print(json.loads(ser.read_all()))
# Print the raw data
ser.write(json.dumps(test_json_c).encode())
time.sleep(1)
ser.write(json.dumps(test_json_d).encode())
time.sleep(1)
#ser.write(json.dumps(test_json_c).encode())
#time.sleep(1)
#ser.write(json.dumps(test_json_d).encode())
#time.sleep(1)
except serial.SerialException as e:
print(f"Error: {e}")
except KeyboardInterrupt: