DIY Applications
Update history
| Date | Version | Author | Update content |
|---|---|---|---|
| 2025-11-07 | v1.0 | bugu |
|
NanoKVM-Desk is an IPKVM product launched by Sipeed, featuring an AX630 core (dual-core A53@1.2GHz, with a built-in 3.2Tops NPU@INT8), configured with 1G LPDDR4 memory and 32G eMMC storage, while also supporting TF card expansion. It offers optional wifi and POE configurations. Beyond its powerful remote control capabilities, it includes a 1.47-inch touch display and a rotary knob. Its form factor as a desktop accessory offers limitless possibilities for DIY imagination.
In version 1.2.1, we introduced the APP Hub feature. Through this feature, you can conveniently download all applications from the Open Source Application Repository.
If you have great ideas, you are also welcome to build your own applications based on the documentation below and submit them to the open-source repository. We will conduct a basic functionality review on submitted applications. Once approved, the applications you develop will be available for download and use by all NanoKVM-Desk users!
How to Build Your Own Application
You can send this document to an AI to assist in generating your own application!
Project Folder Introduction
The NanoKVM-Desk UserAPP scans all folders under the /userapp directory; each folder represents an APP, and the folder name is the APP name. Each folder must contain at least main.py and app.toml.
main.py is the code that runs, and app.toml is the configuration file with the following content:
[application]
name = "XXX" # Use the folder name, displayed on startup (must match the directory name)
version = "1.0.0" # Used for version upgrades, displayed on startup (must be a subset of SemVer format MAJOR.MINOR.PATCH)
descriptions = "Example" # Used as a brief description of the App, displayed during download/update (required, helps users quickly understand the app's functionality)
[author]
name = "Sipeed-xxx" # Fill in the author's name, displayed on startup (required)
email = "xxx@sipeed.com" # Allows users to contact the author easily (optional)
[interaction]
requires_user_input = false # Whether touchscreen and rotary knob events need to be enabled; if true, the program must have an active exit mechanism (optional)
Screen Basic Information and Usage
The NanoKVM-Desk screen resolution is 320*172, accessed via /dev/fb0. The device is equipped with a 172x320 pixel RGB565 color display, accessible via the framebuffer device /dev/fb0. Applications can draw directly to this display device.
Display Characteristics
- Resolution: 172x320 pixels (but the logical screen is 320x172 - see rotation note below)
- Color Depth: 16-bit RGB565 format (Red 5 bits, Green 6 bits, Blue 5 bits)
- Framebuffer Device:
/dev/fb0 - Display Orientation: The physical display is in portrait mode, but applications typically create a landscape image (320x172) which is rotated 90 degrees counter-clockwise for display.
Basic Display Usage
Using the display device in Python applications:
Set constants for the physical display dimensions:
PHYSICAL_WIDTH = 172 PHYSICAL_HEIGHT = 320 BPP = 16 # Bits per pixelCreate a display class interfacing with the framebuffer:
import mmap import os import numpy as np from PIL import Image, ImageDraw class RGB565Display: def __init__(self, fb_device="/dev/fb0"): self.physical_width = PHYSICAL_WIDTH self.physical_height = PHYSICAL_HEIGHT self.bpp = BPP self.fb_size = self.physical_width * self.physical_height * (self.bpp // 8) # Open the framebuffer device self.fb_fd = os.open(fb_device, os.O_RDWR) self.fb_mmap = mmap.mmap( self.fb_fd, self.fb_size, mmap.MAP_SHARED, mmap.PROT_WRITE ) self.fb_array = np.frombuffer(self.fb_mmap, dtype=np.uint16).reshape( (self.physical_height, self.physical_width) ) def rgb_to_rgb565(self, r, g, b): """Convert 8-bit RGB to RGB565 format""" return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3) def clear_screen(self, color=0x0000): """Clear the screen with the specified color""" self.fb_array.fill(color) def _display_image(self, logical_img): """Rotate the logical image and display it on the physical screen""" # Rotate the logical image 90 degrees counter-clockwise to get the physical image physical_img = logical_img.rotate(90, expand=True) # Convert to RGB565 and copy to the framebuffer rgb_array = np.array(physical_img) r = (rgb_array[:, :, 0] >> 3).astype(np.uint16) g = (rgb_array[:, :, 1] >> 2).astype(np.uint16) b = (rgb_array[:, :, 2] >> 3).astype(np.uint16) rgb565 = (r << 11) | (g << 5) | b # Copy the entire array directly to the framebuffer self.fb_array[:, :] = rgb565 def close(self): """Close resources""" self.fb_mmap.close() os.close(self.fb_fd)Draw content on the display:
def main(): display = RGB565Display() try: # Create a logical landscape image (320x172) logical_img = Image.new("RGB", (320, 172), (0, 0, 0)) draw = ImageDraw.Draw(logical_img) # Draw content (e.g., rectangle, text) draw.rectangle([10, 10, 100, 100], fill=(255, 0, 0)) # Red rectangle # Display the image display._display_image(logical_img) # Wait for some time import time time.sleep(5) finally: display.close() if __name__ == "__main__": main()
Best Practices for Display Usage
- Always rotate your logical landscape image (320x172) counter-clockwise to match the physical portrait display (172x320)
- Use efficient drawing methods whenever possible to reduce rendering time
- Properly close resources in a
finallyblock or context manager to prevent resource leaks - Consider performance when drawing frequently updated content (e.g., animations)
Input Event Basics and Usage
The NanoKVM-Desk has three types of input events: knob rotation, knob press, and touch.
If you want to use input events, you must declare
requires_user_input = trueinapp.toml, and your program must have a clear, active exit mechanism; otherwise, it cannot exit back to NanoKVM-UI.
If your program does not require touch or knob input events, set the configuration fieldrequires_user_input = falseor omit it. NanoKVM-UI will then exit the program when the screen is touched or the button is pressed.
Input Device Locations
Knob Rotation Event:
/dev/input/event0root@kvm-72d6:~# evtest /dev/input/event0 Input driver version is 1.0.1 Input device ID: bus 0x19 vendor 0x0 product 0x0 version 0x0 Input device name: "rotary@0" Supported events: Event type 0 (EV_SYN) Event type 2 (EV_REL) Event code 0 (REL_X) Properties: Testing ... (interrupt to exit) Event: time 1762504082.820148, type 2 (EV_REL), code 0 (REL_X), value 1 Event: time 1762504082.820148, -------------- SYN_REPORT ------------ Event: time 1762504082.861754, type 2 (EV_REL), code 0 (REL_X), value 1 Event: time 1762504082.861754, -------------- SYN_REPORT ------------ Event: time 1762504084.692300, type 2 (EV_REL), code 0 (REL_X), value -1 Event: time 1762504084.692300, -------------- SYN_REPORT ------------ Event: time 1762504084.714448, type 2 (EV_REL), code 0 (REL_X), value -1 Event: time 1762504084.714448, -------------- SYN_REPORT ------------Knob Press, Hold, Release Events:
/dev/input/event1root@kvm-72d6:~# evtest /dev/input/event1 Input driver version is 1.0.1 Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100 Input device name: "gpio_keys" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 28 (KEY_ENTER) Key repeat handling: Repeat type 20 (EV_REP) Repeat code 0 (REP_DELAY) Value 250 Repeat code 1 (REP_PERIOD) Value 33 Properties: Testing ... (interrupt to exit) Event: time 1762504201.120498, type 1 (EV_KEY), code 28 (KEY_ENTER), value 1 Event: time 1762504201.120498, -------------- SYN_REPORT ------------ Event: time 1762504201.371193, type 1 (EV_KEY), code 28 (KEY_ENTER), value 2 Event: time 1762504201.721202, -------------- SYN_REPORT ------------ Event: time 1762504201.724694, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0 Event: time 1762504201.724694, -------------- SYN_REPORT ------------Touchscreen Event:
/dev/input/event2root@kvm-72d6:~# evtest /dev/input/event2 Input driver version is 1.0.1 Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0 Input device name: "hyn_ts" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 325 (BTN_TOOL_FINGER) Event code 330 (BTN_TOUCH) Event type 3 (EV_ABS) Event code 47 (ABS_MT_SLOT) Value 0 Min 0 Max 5 Event code 48 (ABS_MT_TOUCH_MAJOR) Value 0 Min 0 Max 255 Event code 50 (ABS_MT_WIDTH_MAJOR) Value 0 Min 0 Max 200 Event code 53 (ABS_MT_POSITION_X) Value 0 Min 0 Max 172 Event code 54 (ABS_MT_POSITION_Y) Value 0 Min 0 Max 320 Event code 57 (ABS_MT_TRACKING_ID) Value 0 Min 0 Max 5 Event code 58 (ABS_MT_PRESSURE) Value 0 Min 0 Max 255 Properties: Property type 1 (INPUT_PROP_DIRECT) Testing ... (interrupt to exit) Event: time 1762504306.703328, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1 Event: time 1762504306.703328, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 25 Event: time 1762504306.703328, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0 Event: time 1762504306.703328, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 71 Event: time 1762504306.703328, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 165 Event: time 1762504306.703328, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 1 Event: time 1762504306.703328, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 1 Event: time 1762504306.703328, type 3 (EV_ABS), code 58 (ABS_MT_PRESSURE), value 10 Event: time 1762504306.703328, -------------- SYN_REPORT ------------ Event: time 1762504306.749866, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value -1 Event: time 1762504306.749866, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0 Event: time 1762504306.749866, -------------- SYN_REPORT ------------
Examples
The two examples in the apps directory of the open-source repository might help you better build your own application:
Contributing to the Software Repository
We encourage you to create and upload your own applications to the repository! This serves as the software repository for NanoKVM-Desk, and your contributions make our ecosystem richer.
How to Upload Your Application
- Create a pull request to place your application in the
appsfolder - Your application will go through a simple review process (as an open-source community, we only review basic functionality; security is guaranteed by the developer)
- Once approved, your application will be available in the NanoKVM-Desk APP Hub
How to Report UserAPP Issues
Please report issues under the Issues section of the open-source repository and mention (@) the author specified in the app.toml file of the corresponding app.