Native macOS app for the HM Lab Z-Neo 8K USB Hub. The official web app (hmlab.tech) only supports Chrome/Edge on Windows — this brings full hub control to macOS.
Built by reverse-engineering the 2.8MB minified JavaScript web driver to understand the USB CDC serial protocol.
- Display Mode Switching — Power Monitor, Album (GIFs/images), sRGB
- Image/GIF Upload — Drag and drop images onto the hub's 320x170 display
- Power Style — Mechanical, Dog (paw prints), Flower animations
- Settings — Brightness, screen orientation, transition effects, intervals
- Gesture Config — Knock, double-knock, tilt, shake actions
- Power Monitoring — Live USB bus voltage and per-port current readings
- Auto-detect — Finds hub by USB VID/PID (0xC019:0x0401)
- macOS 14+ (Sonoma)
- Xcode 15+
- HM Lab Z-Neo 8K USB Hub
git clone https://github.com/italkusa/HubController.git
cd HubController
open Package.swiftIn Xcode: select My Mac as build target, then Cmd+R.
The app will auto-detect the hub when plugged in. Make sure the hmlab.tech web app is closed first — only one app can use the serial port at a time.
| Spec | Value |
|---|---|
| Manufacturer | HM Studio |
| Product | Z-Neo 8K USB Hub |
| USB VID:PID | 0xC019:0x0401 |
| Display | 320 x 170 pixels, RGB565 |
| Flash | 8MB SPI (77 frames max) |
| Connection | USB 2.0 (480 Mbps) |
| Protocol | USB CDC Serial, 256-byte packets, CRC32 |
| Firmware | 1.3.6 |
Communication uses USB CDC serial with 256-byte fixed-size packets:
Byte 0: Command type
Bytes 1-251: Payload
Bytes 252-255: CRC32 of bytes 0-251
| Command | ID | Description |
|---|---|---|
| Handshake | 0x01 | Query device info (HW ID, FW version, flash size) |
| Config | 0x03 | Read/write 24-byte device configuration |
| Flash | 0x08 | Upload images to SPI flash |
| Voltage | 0x09 | Read USB bus voltage and port currents |
Images are stored as RGB565 pixel data with a 28-byte header per image:
Bytes 0-3: Magic (0xC0190001, little-endian)
Bytes 4-5: Width (uint16 LE)
Bytes 6-7: Height (uint16 LE)
Bytes 8-9: Frame count (uint16 LE)
Bytes 10-11: Frame delay ms (uint16 LE)
Bytes 12-15: Data offset in flash (uint32 LE)
Bytes 16-19: Data length (uint32 LE)
Bytes 20-23: CRC32 of pixel data
Bytes 24-27: CRC32 of header bytes 0-23
Header area: first 8,192 bytes of flash. Pixel data starts at offset 8,192.
| Value | Mode |
|---|---|
| 1 | Power Monitor |
| 2 | Album (images/GIFs) |
| 3 | sRGB (SignalRGB receiver) |
| Byte | Field | Values |
|---|---|---|
| 0 | Language | 0=CN, 1=EN, 2=JP, 3=KR, 4=TW |
| 1 | Help toggle | 0/1 |
| 2 | Display mode | 1=Power, 2=Album, 3=sRGB |
| 3 | Screen direction | 0-3 (0/90/180/270 deg) |
| 4 | Brightness | 0-100 |
| 5 | Crop to fill | 0/1 |
| 6 | Auto-trim GIF frames | 0/1 |
| 7 | Knock action | 0=None, 1=Toggle UI, 2=Toggle orientation, 3=Open web driver |
| 8 | Double-knock action | Same as above |
| 9 | Tilt action | Same as above |
| 10 | Shake action | Same as above |
| 11 | Shake sensitivity | 0-100 |
| 12 | Screen auto on/off | 0/1 |
| 13-17 | Reserved | 0 |
| 18 | Power style | 0=Mechanical, 1=Dog, 2=Flower |
| 19 | Image shuffle | 0=Sequential, 1=Random |
| 20-21 | Transition effects | Bitmask (uint16 LE) |
| 22 | Transition interval | Seconds (1-60) |
| 23 | sRGB point style | 0-5 |
Sources/HubController/
App.swift SwiftUI app entry point
CRC32.swift CRC32 matching hub firmware
SerialPort.swift POSIX serial + IOKit device discovery
HubProtocol.swift 256-byte packet encode/decode
HubConfig.swift 24-byte config struct
HubDevice.swift Device manager (ObservableObject)
ImageConverter.swift Image/GIF to RGB565 conversion
ContentView.swift SwiftUI views (Album, Settings, Monitor)
- Protocol reverse-engineered from hmlab.tech web driver
- Hardware by HM Studio / Arbiter Studio
- App by Jonathan Davis / Alpha Innovations
MIT