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

@ -11,6 +11,7 @@ void loop() {}
#include <USB.h> #include <USB.h>
#include <USBHIDMouse.h> #include <USBHIDMouse.h>
#include <USBHIDKeyboard.h> #include <USBHIDKeyboard.h>
#include <USBHIDSystemControl.h>
USBHIDAbsoluteMouse Mouse; USBHIDAbsoluteMouse Mouse;
USBHIDKeyboard Keyboard; USBHIDKeyboard Keyboard;
@ -19,11 +20,15 @@ HardwareSerial &host_serial = Serial;
HardwareSerial &mobo_serial = Serial1; HardwareSerial &mobo_serial = Serial1;
JsonDocument mkb_input; JsonDocument mkb_input;
JsonDocument post_codes;
JsonDocument power_status;
// put function declarations here: // put function declarations here:
int myFunction(int, int); 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() void setup()
{ {
@ -32,15 +37,42 @@ void setup()
Mouse.begin(); Mouse.begin();
Keyboard.begin(); Keyboard.begin();
USB.begin(); USB.begin();
pinMode(pwr_button, OUTPUT);
pinMode(cmos_button, OUTPUT);
pinMode(pwr_detect, INPUT);
} }
void loop() 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()) while (mobo_serial.available())
{ {
char c = mobo_serial.read(); post_codes["post_code"] = mobo_serial.read();
host_serial.write(c); serializeJson(post_codes, host_serial);
host_serial.write('\n');
} }
if (host_serial.available()) if (host_serial.available())
{ {
DeserializationError error = deserializeJson(mkb_input, host_serial); DeserializationError error = deserializeJson(mkb_input, host_serial);
@ -54,23 +86,6 @@ void loop()
else 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>()) if (mkb_input["key_down"].is<JsonVariant>())
{ {
Keyboard.pressRaw(mkb_input["key_down"].as<uint8_t>()); Keyboard.pressRaw(mkb_input["key_down"].as<uint8_t>());
@ -95,6 +110,16 @@ void loop()
{ {
Mouse.release(mkb_input["mouse_up"].as<uint8_t>()); 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>());
}
} }
} }
} }

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

96
webui/ipkvm/events.py Normal 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)

@ -6,6 +6,8 @@ from ipkvm import profile
from ipkvm.util import video from ipkvm.util import video
from ipkvm import logger from ipkvm import logger
import time import time
from PIL import Image
import io
class FrameBuffer(threading.Thread): class FrameBuffer(threading.Thread):
def __init__(self): def __init__(self):
@ -35,8 +37,20 @@ class FrameBuffer(threading.Thread):
if not success: if not success:
break break
else: else:
ret, buffer = cv2.imencode('.jpg', frame) # ret, buffer = cv2.imencode('.jpg', frame)
self.cur_frame = buffer.tobytes() # 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() self.new_frame.set()

@ -1,7 +1,7 @@
from ipkvm import app, ui from ipkvm import app
from ipkvm import frame_buffer, esp32_serial from ipkvm import frame_buffer
from flask import Response, render_template from flask import Response, render_template
from ipkvm.util.mkb import HIDKeyCode, HIDMouseScanCodes
def generate_frames(): def generate_frames():
while True: while True:
@ -9,49 +9,6 @@ def generate_frames():
frame_buffer.new_frame.clear() frame_buffer.new_frame.clear()
yield (b'--frame\r\n' yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_buffer.cur_frame + b'\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') @app.route('/video_feed')
def video_feed(): def video_feed():

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

@ -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);

@ -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

@ -1,14 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='vendor/socket.io.min.js') }}"></script> <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> <html>
<head> <head>
<title>IP KVM & OC Tuner</title> <title>IP KVM & OC Tuner</title>
</head> </head>
<body>
<div id="streamview" class="stream-container"> <body>
<img src="/video_feed" class="stream-view" /> <div id="streamview" class="stream-container">
</div> <img src="/video_feed" class="stream-view" />
</body> </div>
</html> <button type="button" onclick="socket.emit(`power_on`);">Power on</button>
<script src="{{ url_for('static', filename='mkb_handler.js') }}"></script> <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>

@ -5,8 +5,271 @@ from ipkvm import profile
import threading import threading
from queue import Queue from queue import Queue
import json 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 = { HIDMouseScanCodes = {
0: 1, 0: 1,
2: 2, 2: 2,
@ -15,6 +278,10 @@ HIDMouseScanCodes = {
4: 16 4: 16
} }
class GPIO(IntEnum):
LOW = 0
HIGH = 1
# God Bless CHADGPT # God Bless CHADGPT
class HIDKeyCode(IntEnum): class HIDKeyCode(IntEnum):
""" """
@ -152,26 +419,49 @@ class Esp32Serial(threading.Thread):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.post_code_queue: Queue[str] = Queue() 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.change_serial_device = threading.Event()
self.device = self.get_device() self.device = self.get_device()
self.bios_timer = time.time()
self.power_status = None
self.start() self.start()
def run(self): def run(self):
while True: with self.device as ser:
if self.change_serial_device.is_set(): while True:
self.change_serial_device.clear() # if self.change_serial_device.is_set():
self.device = self.get_device() # self.change_serial_device.clear()
# self.device = self.get_device()
with self.device as ser:
while not self.mkb_queue.empty(): while not self.mkb_queue.empty():
msg = self.mkb_queue.get() msg = self.mkb_queue.get()
ser.write(json.dumps(msg).encode()) ser.write(json.dumps(msg).encode())
while ser.in_waiting > 0: 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()) # self.post_code_queue.put(ser.read().hex())
time.sleep(0.01)
def get_device(self): def get_device(self):
if name == "posix": if name == "posix":

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