Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SkyByte UPS Firmware

Firmware for an ESP32-S3 that acts as a USB host for a Megatec/Q1-protocol UPS, parses its telemetry, and relays it to a remote server over a secure WebSocket connection.

The ESP32 sits between the UPS and the network: it polls the UPS over USB every two seconds, decodes the response, and forwards each reading as JSON over wss://. Wi-Fi credentials are configured at runtime through a captive portal, and each unit's identity is provisioned into NVS flash at the factory.

Hardware

Item Value
Board 4D Systems ESP32-S3 gen4 R8N16 (8 MB PSRAM, 16 MB flash)
UPS Voltronic-based (Cypress/Megatec chipset)
USB Vendor ID 0x0665
USB Product ID 0x5161
Protocol Megatec Q1 status query over a USB HID control pipe

The board must supply USB host power to the UPS. Vendor and product IDs are set in src/include/config.h; other Megatec-compatible units usually work by changing those two values.

Building the firmware

Requires PlatformIO. Dependencies (ArduinoJson, WebSockets, WiFiManager) are declared in platformio.ini and fetched automatically.

pio run                  # build
pio run --target upload  # build and flash
pio device monitor       # serial console at 115200 baud

Provisioning a device

Each unit needs a device secret written to its NVS partition before it can authenticate with the server. provision.py generates a key, compiles it into an NVS image, flashes it, and registers it with the relay server.

Install the tooling and configure your admin secret:

pip install -r requirements.txt
cp .env.example .env

# then fill in UPS_ADMIN_SECRET and UPS_SERVER_HOST

Run the tool against the board's serial port:

python3 provision.py --port /dev/cu.usbmodemXXXXXXX

Useful flags:

Flag Description
--port Serial port of the target board (required)
--host Relay server hostname (overrides UPS_SERVER_HOST)
--key Use a specific secret key instead of generating one
--admin-secret Overrides UPS_ADMIN_SECRET from the environment

The script writes the NVS image to flash offset 0x9000. It prints the generated key on completion — record it, because it is not recoverable afterwards. If no admin secret is available the device is still flashed, but server-side registration is skipped.

The generated nvs_config.csv and nvs_partition.bin contain the device secret in plain text. The script deletes them after a successful run, and both are gitignored.

Wi-Fi setup

On first boot (or whenever saved credentials fail) the firmware opens a captive portal access point named SkyByte-UPS-Setup. Connect to it and choose a network. The portal times out after 180 seconds and the device reboots to retry.

Telemetry format

The device ID is derived from the last three bytes of the Wi-Fi MAC address, formatted as UPS-XXXXXX. Authentication happens via query parameters on the WebSocket handshake to /ws/ingest. Each reading is sent as a JSON frame:

{
  "device_id": "UPS-A1B2C3",
  "input_v": 230.0,
  "output_v": 229.5,
  "load_pct": 34.0,
  "freq_hz": 50.0,
  "batt_v": 13.6,
  "temp_c": 27.4,
  "grid_ok": true,
  "batt_low": false,
  "timestamp": 128394
}

timestamp is the device's uptime in milliseconds from millis(), not a wall-clock time, so the server should apply its own receive timestamp.

Security notes

  • Device secrets live only in NVS flash and are never committed to this repository.
  • The admin secret is read from the environment and must not be hardcoded.
  • .env is gitignored; use .env.example as the template for required variables.

License

Released under the MIT License.

About

Firmware for an ESP32-S3 that acts as a USB host for a Megatec/Q1-protocol UPS, parses its telemetry, and relays it to a remote server over a secure WebSocket connection.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages