Skip to content

Instantly share code, notes, and snippets.

@fdobrovolny
Created January 14, 2026 02:35
Show Gist options
  • Select an option

  • Save fdobrovolny/012892cd7eb8bd4d44878c35c6f0e052 to your computer and use it in GitHub Desktop.

Select an option

Save fdobrovolny/012892cd7eb8bd4d44878c35c6f0e052 to your computer and use it in GitHub Desktop.
Reverse Engineering Report: Eurocase EA610 USB Protocol

Reverse Engineering Report: Eurocase EA610 /MEC0003 UPS (String-Descriptor Protocol)

All of this has been done with help of LLM I don't understand much of it, but the python script works and returns real data and I provided the data from Wireshark myself.

1. Device Identification

  • Vendor: Eurocase
  • Model: EA610 (1000VA)
  • USB ID: 0001:0000
  • Internal Chip ID: MEC0003 (String Index 1)
  • Firmware: V4.20 (String Index 12)

2. Problem Description

Standard open-source drivers (NUT nutdrv_qx, usbhid-ups, and APCUPSD) fail to communicate with this device.

  • Symptoms: Drivers report "Device not supported", "Connection lost", or crash.
  • Root Cause: The device enumerates as a USB HID device but does not use HID Reports for data. Instead, it utilizes USB String Descriptors to tunnel the legacy Megatec Q1 serial protocol.
  • Quirk: The device requires a specific "handshake" (polling data index) before accepting command indexes.

3. Protocol Specification

Communication is performed strictly via USB Control Transfers using GET_DESCRIPTOR (Request 0x06).

Setup Packet Format:

  • bmRequestType: 0x80 (Device-to-Host, Standard, Device)
  • bRequest: 0x06 (GET_DESCRIPTOR)
  • wValue: 0x03xx (Descriptor Type 0x03 = String, Index = xx)
  • wIndex: 0x0409 (Language ID: English US) or 0x0000

3.1 Command & Data Map (Confirmed)

The following mapping was confirmed via Wireshark sniffing of the official Windows software (UPSSmart) with option Mega(USB) and python-based reproduction.

String Index Type Description Megatec Equivalent
0x01 Static Model Name
Returns: MEC0003
-
0x03 Dynamic Telemetry / Status
Returns: (230.0 ...
Q1
0x04 Command Battery Test (10 seconds)
Sets Status Bit 2 to 1.
T
0x05 Command Battery Test (Timed)
Observed when running 15-min test.
T<n>
0x06 Command Battery Test (Deep / Low Battery)
Observed when running Low Voltage test.
TL
0x07 Command Toggle Buzzer
Toggles Status Bit 0 (0=Off, 1=On).
Q
0x0B (11) Command Cancel Test
Immediately clears Status Bit 2.
CT
0x0C (12) Static Firmware Version
Returns: V4.20
F
0x0D (13) Static Rating Information
Returns: #230.0 3.4 24.00 50.0
I

3.2 Data Format (Index 3)

The device returns status data in UTF-16LE. Example Raw: ( 2 3 6 . 0 0 0 0 . 0 2 3 7 . 0 0 0 9 5 0 . 0 2 5 . 8 2 5 . 0 0 0 0 0 1 0 0 1 Format: (MMM.M NNN.N PPP.P QQQ RR.R SS.S TT.T bbbbbbbb

Field Description Example
MMM.M Input Voltage 236.0
NNN.N Fault Voltage 000.0
PPP.P Output Voltage 237.0
QQQ Load % 009
RR.R Frequency (Hz) 50.0
SS.S Battery Voltage 25.8
TT.T Temperature (deg C) 25.0
bbbbbbbb Status Bits 00001001

Status Bits (Left to Right): 7: Utility Fail, 6: Low Battery, 5: Bypass, 4: Fault, 3: Type, 2: Test Active, 1: Shutdown, 0: Buzzer On


4. Packet Analysis & Evidence

The following raw dumps from Wireshark confirm the protocol. The header 1c... includes the USBPcap/Wireshark pseudo-header; the actual USB Setup Packet starts at offset 0x1C (beginning with 80 06).

4.1 Telemetry / Status (Index 0x03)

Action: Host requests status. Analysis: 80 06 03 03 09 04. wValue = 0x0303 (Type 3, Index 3). Response: (236.0 000.0 237.0 007 49.9 25.8 26.0 00001001

Raw Data:

0000   1c 00 a0 e9 0d e3 0b e5 ff ff 00 00 00 00 0b 00   ................
0010   00 02 00 0b 00 80 02 08 00 00 00 00 80 06 03 03   ................
0020   09 04 66 00                                       ..f.
1c00a0e90de30be5ffff000000000b000002000b00800208000000008006030309046600
---
0000   1c 00 a0 e9 0d e3 0b e5 ff ff 00 00 00 00 08 00   ................
0010   01 02 00 0b 00 80 02 60 00 00 00 03 60 03 28 00   .......`....`.(.
0020   32 00 33 00 36 00 2e 00 30 00 20 00 30 00 30 00   2.3.6...0. .0.0.
0030   30 00 2e 00 30 00 20 00 32 00 33 00 37 00 2e 00   0...0. .2.3.7...
0040   30 00 20 00 30 00 30 00 39 00 20 00 34 00 39 00   0. .0.0.9. .4.9.
0050   2e 00 39 00 20 00 32 00 36 00 2e 00 33 00 20 00   ..9. .2.6...3. .
0060   32 00 35 00 2e 00 30 00 20 00 30 00 30 00 30 00   2.5...0. .0.0.0.
0070   30 00 31 00 30 00 30 00 31 00 0d 00               0.1.0.0.1...
1c00a0e90de30be5ffff0000000008000102000b0080026000000003600328003200330036002e00300020003000300030002e00300020003200330037002e00300020003000300039002000340039002e0039002000320036002e0033002000320035002e0030002000300030003000300031003000300031000d00
Frame 45: Packet, 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:20.276155000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:20.276155000 UTC
    Epoch Arrival Time: 1768352120.276155000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 995.000000 milliseconds]
    [Time delta from previous displayed frame: 995.000000 milliseconds]
    [Time since reference or first frame: 20.289212000 seconds]
    Frame Number: 45
    Frame Length: 36 bytes (288 bits)
    Capture Length: 36 bytes (288 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: host]
    [Destination: 2.11.0]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be30de9a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE (0x000b)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    [Response in: 46]
    Control transfer stage: Setup (0)
Setup Data
    bmRequestType: 0x80
    bRequest: GET DESCRIPTOR (6)
    Descriptor Index: 0x03
    bDescriptorType: STRING (0x03)
    Language Id: English (United States) (0x0409)
    wLength: 102
Frame 46: Packet, 124 bytes on wire (992 bits), 124 bytes captured (992 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:20.277813000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:20.277813000 UTC
    Epoch Arrival Time: 1768352120.277813000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.658000 milliseconds]
    [Time delta from previous displayed frame: 1.658000 milliseconds]
    [Time since reference or first frame: 20.290870000 seconds]
    Frame Number: 46
    Frame Length: 124 bytes (992 bits)
    Capture Length: 124 bytes (992 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: 2.11.0]
    [Destination: host]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be30de9a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 96
    [Request in: 45]
    [Time from request: 1.658000 milliseconds]
    Control transfer stage: Complete (3)
STRING DESCRIPTOR
    bLength: 96
    bDescriptorType: 0x03 (STRING)
    bString: (236.0 000.0 237.0 009 49.9 26.3 25.0 00001001\r

4.2 Toggle Buzzer (Index 0x07)

Action: Host toggles the silence/beeper mode. Analysis: 80 06 07 03 09 04. wValue = 0x0307 (Type 3, Index 7).

Raw Request:

1c00a0f9bae30be5ffff000000000b000002000a00800208000000008006070309046600

Result: Bit 0 in the status string (Index 3) flips between 0 and 1.

4.3 Battery Test - 10 Seconds (Index 0x04)

Action: Host initiates a short standard test. Analysis: 80 06 04 03 09 04. wValue = 0x0304 (Type 3, Index 4).

Raw Request:

1c00107070e20be5ffff000000000b000002000a00800208000000008006040309046600

Result: Output voltage indicates inverter usage; status string shows "Test in Progress".

4.4 Battery Test - Deep / Low Voltage (Index 0x06)

Action: Host initiates a test until battery low. Analysis: 80 06 06 03 09 04. wValue = 0x0306 (Type 3, Index 6).

Raw Request:

1c0020f7c1e30be5ffff000000000b000002000a00800208000000008006060309046500

4.5 Battery Test - Timed (Index 0x05)

Action: Host initiates a timed test in UI there is a setting 1-99 minutes, but the request is the same. Analysis: 80 06 05 03 09 04. wValue = 0x0305 (Type 3, Index 5).

Raw Request:

1c00a049dee00be5ffff000000000b000002000a00800208000000008006050309046600

4.6 Cancel Test (Index 0x0B)

Action: Host aborts a running test immediately. Analysis: 80 06 0b 03 09 04. wValue = 0x030B (Type 3, Index 11).

Raw Request:

1c0020b7a1e30be5ffff000000000b000002000a008002080000000080060b0309046600

4.7 Model Information (Index 0x01)

Action: Host requests Manufacturer/Model. Analysis: 80 06 01 03.... Response: MEC0003

Raw Data:

0000   1c 00 a0 19 d2 e2 0b e5 ff ff 00 00 00 00 0b 00   ................
0010   00 02 00 0b 00 80 02 08 00 00 00 00 80 06 01 03   ................
0020   09 04 02 04                                       ....
1c00a019d2e20be5ffff000000000b000002000b00800208000000008006010309040204
---
0000   1c 00 a0 19 d2 e2 0b e5 ff ff 00 00 00 00 08 00   ................
0010   01 02 00 0b 00 80 02 10 00 00 00 03 10 03 4d 00   ..............M.
0020   45 00 43 00 30 00 30 00 30 00 33 00               E.C.0.0.0.3.
1c00a019d2e20be5ffff0000000008000102000b008002100000000310034d00450043003000300030003300
Frame 39: Packet, 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:18.292226000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:18.292226000 UTC
    Epoch Arrival Time: 1768352118.292226000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 152.245000 milliseconds]
    [Time delta from previous displayed frame: 152.245000 milliseconds]
    [Time since reference or first frame: 18.305283000 seconds]
    Frame Number: 39
    Frame Length: 36 bytes (288 bits)
    Capture Length: 36 bytes (288 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: host]
    [Destination: 2.11.0]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be2d219a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE (0x000b)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    [Response in: 40]
    Control transfer stage: Setup (0)
Setup Data
    bmRequestType: 0x80
    bRequest: GET DESCRIPTOR (6)
    Descriptor Index: 0x01
    bDescriptorType: STRING (0x03)
    Language Id: English (United States) (0x0409)
    wLength: 1026
---
Frame 40: Packet, 44 bytes on wire (352 bits), 44 bytes captured (352 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:18.293528000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:18.293528000 UTC
    Epoch Arrival Time: 1768352118.293528000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.302000 milliseconds]
    [Time delta from previous displayed frame: 1.302000 milliseconds]
    [Time since reference or first frame: 18.306585000 seconds]
    Frame Number: 40
    Frame Length: 44 bytes (352 bits)
    Capture Length: 44 bytes (352 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: 2.11.0]
    [Destination: host]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be2d219a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 16
    [Request in: 39]
    [Time from request: 1.302000 milliseconds]
    Control transfer stage: Complete (3)
STRING DESCRIPTOR
    bLength: 16
    bDescriptorType: 0x03 (STRING)
    bString: MEC0003

4.8 Initialization Quirk (The "Zeros" Issue)

Upon connection or driver attach, the USB bridge resets. For the first few seconds, querying Index 3 returns valid USB packets containing empty data:

Response (Txt): (000.0 000.0 000.0 000 00.0 0.00 00.0 00000000
0000   1c 00 a0 89 ee dd 0b e5 ff ff 00 00 00 00 08 00   ................
0010   01 02 00 0b 00 80 02 60 00 00 00 03 60 03 28 00   .......`....`.(.
0020   30 00 30 00 30 00 2e 00 30 00 20 00 30 00 30 00   0.0.0...0. .0.0.
0030   30 00 2e 00 30 00 20 00 30 00 30 00 30 00 2e 00   0...0. .0.0.0...
0040   30 00 20 00 30 00 30 00 30 00 20 00 30 00 30 00   0. .0.0.0. .0.0.
0050   2e 00 30 00 20 00 30 00 2e 00 30 00 30 00 20 00   ..0. .0...0.0. .
0060   30 00 30 00 2e 00 30 00 20 00 30 00 30 00 30 00   0.0...0. .0.0.0.
0070   30 00 30 00 30 00 30 00 30 00 0d 00               0.0.0.0.0...
1c00a089eedd0be5ffff0000000008000102000b0080026000000003600328003000300030002e00300020003000300030002e00300020003000300030002e00300020003000300030002000300030002e003000200030002e00300030002000300030002e0030002000300030003000300030003000300030000d00
Frame 42: Packet, 124 bytes on wire (992 bits), 124 bytes captured (992 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:18.295335000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:18.295335000 UTC
    Epoch Arrival Time: 1768352118.295335000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.418000 milliseconds]
    [Time delta from previous displayed frame: 1.418000 milliseconds]
    [Time since reference or first frame: 18.308392000 seconds]
    Frame Number: 42
    Frame Length: 124 bytes (992 bits)
    Capture Length: 124 bytes (992 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: 2.11.0]
    [Destination: host]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50bddee89a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 96
    [Request in: 41]
    [Time from request: 1.418000 milliseconds]
    Control transfer stage: Complete (3)
STRING DESCRIPTOR
    bLength: 96
    bDescriptorType: 0x03 (STRING)
    bString: (000.0 000.0 000.0 000 00.0 0.00 00.0 00000000\r

Fix: The driver must ignore zero-filled packets and retry.

Here are the specific missing sections for Firmware and Rating information, formatted exactly like the previous evidence blocks so you can append them to Section 4.

4.9 Firmware Version (Index 0x0C)

Action: Host requests the firmware version string. Analysis: 80 06 0c 03 09 04. wValue = 0x030C (Type 3, Index 12). Response: P# V4.20 (Note: The software often ignores the prefix padding).

Raw Data:

0000   1c 00 a0 f9 8d e1 0b e5 ff ff 00 00 00 00 0b 00   ................
0010   00 02 00 0b 00 80 02 08 00 00 00 00 80 06 0c 03   ................
0020   09 04 66 00                                       ..f.
1c00a0f98de10be5ffff000000000b000002000b008002080000000080060c0309046600
---
0000   1c 00 a0 f9 8d e1 0b e5 ff ff 00 00 00 00 08 00   ................
0010   01 02 00 0b 00 80 02 50 00 00 00 03 50 03 23 00   .......P....P.#.
0020   20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00    . . . . . . . .
0030   20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00    . . . . . . . .
0040   20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00    . . . . . . . .
0050   20 00 20 00 20 00 56 00 34 00 2e 00 32 00 30 00    . . .V.4...2.0.
0060   20 00 20 00 20 00 20 00 20 00 0d 00                . . . . ...
1c00a0f98de10be5ffff0000000008000102000b008002500000000350032300200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000200020002000560034002e0032003000200020002000200020000d00
Frame 131: Packet, 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:56:03.326187000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:56:03.326187000 UTC
    Epoch Arrival Time: 1768352163.326187000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.004265000 seconds]
    [Time delta from previous displayed frame: 1.004265000 seconds]
    [Time since reference or first frame: 1 minute, 3.339244000 seconds]
    Frame Number: 131
    Frame Length: 36 bytes (288 bits)
    Capture Length: 36 bytes (288 bits)
    [Frame is marked: True]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: host]
    [Destination: 2.11.0]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be18df9a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE (0x000b)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    [Response in: 132]
    Control transfer stage: Setup (0)
Setup Data
    bmRequestType: 0x80
    bRequest: GET DESCRIPTOR (6)
    Descriptor Index: 0x0c
    bDescriptorType: STRING (0x03)
    Language Id: English (United States) (0x0409)
    wLength: 102
---
Frame 132: Packet, 108 bytes on wire (864 bits), 108 bytes captured (864 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:56:03.327801000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:56:03.327801000 UTC
    Epoch Arrival Time: 1768352163.327801000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.614000 milliseconds]
    [Time delta from previous displayed frame: 1.614000 milliseconds]
    [Time since reference or first frame: 1 minute, 3.340858000 seconds]
    Frame Number: 132
    Frame Length: 108 bytes (864 bits)
    Capture Length: 108 bytes (864 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: 2.11.0]
    [Destination: host]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be18df9a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 80
    [Request in: 131]
    [Time from request: 1.614000 milliseconds]
    Control transfer stage: Complete (3)
STRING DESCRIPTOR
    bLength: 80
    bDescriptorType: 0x03 (STRING)
    bString: #                           V4.20     \r

4.10 Rating Information (Index 0x0D)

Action: Host requests nominal voltage/current ratings. Analysis: 80 06 0d 03 09 04. wValue = 0x030D (Type 3, Index 13). Response: #230.0 3.4 24.00 50.0 (Format: Nominal Voltage, Max Current, Nominal Battery Voltage, Frequency).

Raw Data:

0000   1c 00 10 a0 5e e7 0b e5 ff ff 00 00 00 00 0b 00   ....^...........
0010   00 02 00 0b 00 80 02 08 00 00 00 00 80 06 0d 03   ................
0020   09 04 66 00                                       ..f.
1c0010a05ee70be5ffff000000000b000002000b008002080000000080060d0309046600
---
0000   1c 00 10 a0 5e e7 0b e5 ff ff 00 00 00 00 08 00   ....^...........
0010   01 02 00 0b 00 80 02 2e 00 00 00 03 2e 03 23 00   ..............#.
0020   32 00 33 00 30 00 2e 00 30 00 20 00 33 00 2e 00   2.3.0...0. .3...
0030   34 00 20 00 32 00 34 00 2e 00 30 00 30 00 20 00   4. .2.4...0.0. .
0040   35 00 30 00 2e 00 30 00 0d 00                     5.0...0...
1c0010a05ee70be5ffff0000000008000102000b0080022e000000032e0323003200330030002e003000200033002e0034002000320034002e00300030002000350030002e0030000d00
Frame 67: Packet, 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:31.300520000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:31.300520000 UTC
    Epoch Arrival Time: 1768352131.300520000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.005531000 seconds]
    [Time delta from previous displayed frame: 1.005531000 seconds]
    [Time since reference or first frame: 31.313577000 seconds]
    Frame Number: 67
    Frame Length: 36 bytes (288 bits)
    Capture Length: 36 bytes (288 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: host]
    [Destination: 2.11.0]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be75ea010
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE (0x000b)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    [Response in: 68]
    Control transfer stage: Setup (0)
Setup Data
    bmRequestType: 0x80
    bRequest: GET DESCRIPTOR (6)
    Descriptor Index: 0x0d
    bDescriptorType: STRING (0x03)
    Language Id: English (United States) (0x0409)
    wLength: 102
---
Frame 68: Packet, 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface \\.\USBPcap2, id 0
    Section number: 1
    Interface id: 0 (\\.\USBPcap2)
    Encapsulation type: USB packets with USBPcap header (152)
    Arrival Time: Jan 14, 2026 01:55:31.301995000 Střední Evropa (běžný čas)
    UTC Arrival Time: Jan 14, 2026 00:55:31.301995000 UTC
    Epoch Arrival Time: 1768352131.301995000
    [Time shift for this packet: 0.000000000 seconds]
    [Time delta from previous captured frame: 1.475000 milliseconds]
    [Time delta from previous displayed frame: 1.475000 milliseconds]
    [Time since reference or first frame: 31.315052000 seconds]
    Frame Number: 68
    Frame Length: 74 bytes (592 bits)
    Capture Length: 74 bytes (592 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: usb]
    Character encoding: ASCII (0)
USB URB
    [Source: 2.11.0]
    [Destination: host]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe50be75ea010
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 2
    Device address: 11
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 46
    [Request in: 67]
    [Time from request: 1.475000 milliseconds]
    Control transfer stage: Complete (3)
STRING DESCRIPTOR
    bLength: 46
    bDescriptorType: 0x03 (STRING)
    bString: #230.0 3.4 24.00 50.0\r

5. Working Implementation (Python)

This script demonstrates a functional driver logic bypassing standard HID reports.

import usb.core
import usb.util
import time
import sys
class UPS:
def __init__(self):
# Eurocase / MEC0003 ID
self.VENDOR_ID = 0x0001
self.PRODUCT_ID = 0x0000
self.dev = usb.core.find(idVendor=self.VENDOR_ID, idProduct=self.PRODUCT_ID)
if not self.dev:
print("Error: UPS not found (Check USB cable or permissions).")
sys.exit(1)
try:
if self.dev.is_kernel_driver_active(0):
self.dev.detach_kernel_driver(0)
self.dev.set_configuration()
except Exception as e:
pass # Ignore errors if driver was already detached
def _get_string(self, index):
"""
Requests a String Descriptor.
Used for getting data (Index 1, 3, 12, 13) and triggering commands.
"""
try:
# 0x80 = Device-to-Host, 0x06 = GET_DESCRIPTOR
# 0x0300 | index = String Descriptor #index
# 0x0409 = English US
ret = self.dev.ctrl_transfer(0x80, 0x06, 0x0300 | index, 0x0409, 255)
if ret:
# Skip first 2 bytes (Length + Type), decode UTF-16LE
return "".join([chr(x) for x in ret[2:] if x != 0]).strip()
except Exception:
return None
return None
def wakeup(self):
"""
Sends 3 status queries to 'wake up' the command parser.
Required before sending active commands.
"""
print("Waking up UPS...", end="", flush=True)
for _ in range(3):
self._get_string(3)
time.sleep(0.1)
print(".", end="", flush=True)
print(" Done.")
def parse_status_bits(self, bit_string):
"""
Parses the 8-character binary string Q1 status.
Format: <7><6><5><4><3><2><1><0>
"""
if len(bit_string) != 8:
return {}
return {
"utility_fail": bit_string[0] == '1', # Power failure (On Battery)
"battery_low": bit_string[1] == '1', # Battery Low
"bypass_avr": bit_string[2] == '1', # AVR Active / Bypass
"ups_failed": bit_string[3] == '1', # UPS Fault
"line_inter": bit_string[4] == '1', # 1=Line Interactive, 0=Standby
"test_active": bit_string[5] == '1', # Test in progress
"shutdown": bit_string[6] == '1', # Shutdown active
"beeper_on": bit_string[7] == '1' # Buzzer is ON
}
def get_data(self):
raw = self._get_string(3) # Index 3 = Telemetry
# Check for the "Zero Data" quirk (Initialization)
if raw and "000.0 000.0 000.0" in raw:
return {"status": "INITIALIZING"}
if raw and raw.startswith('('):
# Format: (MMM.M NNN.N PPP.P QQQ RR.R SS.S TT.T bbbbbbbb
parts = raw[1:].split()
if len(parts) >= 8:
status_dict = self.parse_status_bits(parts[7])
return {
"input_v": float(parts[0]),
"fault_v": float(parts[1]),
"output_v": float(parts[2]),
"load_pct": int(parts[3]),
"freq": float(parts[4]),
"batt_v": float(parts[5]),
"temp": float(parts[6]),
"flags": status_dict,
"raw_bits": parts[7]
}
return None
def execute_command(self, cmd):
# The Map we discovered via Reverse Engineering
mapping = {
"model": 1, # Model Name
"test": 4, # 10s Test
"test_long": 5, # Timed Test
"test_deep": 6, # Low Battery Test
"mute": 7, # Toggle Buzzer
"stop": 11, # Cancel Test
"firmware": 12, # Firmware Version
"rating": 13 # Nominal Ratings
}
if cmd == "info":
# Composite command to show all static info
print(f"Model: {self._clean_text(self._get_string(1))}")
print(f"Firmware: {self._clean_text(self._get_string(12))}")
print(f"Rating: {self._clean_text(self._get_string(13))}")
return
if cmd not in mapping:
print(f"Unknown command: '{cmd}'")
print(f"Available: status, info, {', '.join(mapping.keys())}")
return
if cmd in ["model", "firmware", "rating"]:
# Passive commands (just read)
res = self._get_string(mapping[cmd])
print(f"[{cmd.upper()}]: {self._clean_text(res)}")
else:
# Active commands (need wakeup)
self.wakeup()
self._get_string(mapping[cmd])
print(f"Command '{cmd}' sent (Index {mapping[cmd]}).")
# Verify status change immediately
time.sleep(1)
data = self.get_data()
if data and "flags" in data:
print(f"Current Status: Test={data['flags']['test_active']}, Beeper={data['flags']['beeper_on']}")
def _clean_text(self, text):
if not text: return "N/A"
return text.replace("#", "").replace("P", "").strip()
if __name__ == "__main__":
ups = UPS()
if len(sys.argv) < 2:
print("Usage: python ups_atlas.py <command>")
print("Commands: status, info, model, test, test_long, stop, mute")
sys.exit(0)
cmd = sys.argv[1].lower()
if cmd == "status":
import pprint
data = ups.get_data()
if data:
pprint.pprint(data)
else:
print("Error reading status.")
else:
ups.execute_command(cmd)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment