Reverse Engineering & Open Source

MoasureONE E222

A comprehensive technical reference documenting the reverse engineering of the Moasure measurement device—BLE protocol, firmware update system, production API, calibration data—and the design of an open-source measurement platform.

Device Serial 18S1FR521035023
MAC Address 22:E2:0F:8D:83:E6
Module ID 27544
Built April 2022

1. Project Overview

What is the MoasureONE?

The MoasureONE E222 is a handheld IMU-based measurement device that retails for around $150. It uses inertial sensors (accelerometers and gyroscopes) to measure distances, areas, and elevations by tracking its own motion through space. The device communicates via Bluetooth Low Energy with a companion mobile app that performs all computation—the device itself is essentially a dumb IMU sensor with a simple state machine.

Why this project?

Moasure's ecosystem is locked down. The mobile app validates devices against a server-side database (checking serial number and MAC address), firmware images are AES-encrypted, and there's no public API or SDK. This project aims to build open-source measurement software that talks directly to the device over BLE, bypassing the proprietary app entirely.

What we've accomplished

  • Fully mapped the BLE GATT service—all 9 characteristics, their behaviors, and the cmd1 command set
  • Decoded the IMU data format (124 bytes per packet, 5 samples at 100Hz)
  • Reverse-engineered the firmware updater app (.NET MAUI) and its USB serial protocol
  • Discovered and documented the production API (factory test data, calibration matrices, device metadata)
  • Downloaded the full 138KB calibration dataset (48×24 matrix for sensor correction)
  • Built a working Electron BLE explorer with real-time IMU visualization (Madgwick AHRS + dead reckoning)
  • Wrote 12 Python research scripts for protocol probing, MITM proxying, and data capture
  • Designed a next-generation hardware concept (UWB + RTK GPS measurement puck system)

2. Device Hardware

Dual Processor Architecture

The MoasureONE runs two separate processors on a single board, each with independent firmware:

Main Processor
Atmel SAM S70
Role
IMU Sensor Processing
BLE Processor
Nordic nRF52
Role
Bluetooth Communication
S70 Firmware
v0.13
nRF52 Firmware
v0.1
BLE Firmware
v1.27
Model ID
2

Device Identity

Serial Number
18S1FR521035023
MAC Address
22:E2:0F:8D:83:E6
Module ID
27544
Active Sensors
16 (accel + gyro)

Manufacturing History

The device went through 5 manufacturing phases with 41 factory tests, all passing. Data retrieved from the Moasure production API.

Factory Test Results (41 tests, all passed)
TestValueRangeUnit
PCBA Present / Available10 – 1
USB Supply Current40.662.5 – 55mA
Vdd Main PCBA Voltage3.173.1 – 3.26V
Low Power Tap Sensor Voltage2.9942.9 – 3.4V
Battery Charging Voltage (Off Load)4.0964.05 – 4.25V
Battery Charging Voltage (On Load)4.0473.85 – 4.14V
Battery Charging Current-369.28-448 – -240mA
Battery Operation Voltage4.4644.3 – 5.2V
Battery Operation Current43.235 – 55mA
Battery Standby Current (No Tap)0.570 – 2.5mA
Battery Operation (Voltage)5.0394.5 – 5.2V
Battery Charging Current (Moasure-One)-315.22-426 – -196mA
Battery Voltage Monitor Accuracy-0.123-0.45 – 0.2
USB Supply Current (Moasure-ONE)103.624 – 115mA
Programming Atmel S7011 – 1
Programming BLE11 – 1
16 Sensors Active ONE1616 – 16
Sensors Tested Count1616 – 16
BLE Signal Level5617 – 99
BT Debug Communication551 – 99
BLE MAC Serial Number11 – 1
LED Colour & Brightness11 – 1
Double Tap Wake Up On Batt3.173.1 – 3.26V
Manufacturing Phases
PhaseDateDetails
Phase 12022-04-23PCB assembly, 41 electrical tests
Phase 22022-04-23Firmware flash (PRO-ONE-260_v011B0010.img), Nordic 0A
Phase 32022-05-06Enclosure assembly
Phase 42022-05-07Calibration (AWS EC2, MCC ver 2.1.4)
Phase 52022-05-11Distance accuracy validation (1m target, 4 measurements)
Phase 5 — Distance Accuracy Measurements

Phase 5 validation tested distance measurement accuracy against a 1-meter target. The device was iterated twice (May 7 and May 11, 2022), each time performing 4 measurements.

#X (m)Y (m)Z (m)DistanceErrorFlags
0-0.0310.9980.0020.998m-0.2%
10.1880.9910.0031.008m+0.8%
2-0.0551.0040.0041.006m+0.6%
30.2850.9660.0021.007m+0.7%

3. BLE Protocol

GATT Service

The device exposes a single BLE service with UUID 81f61400-3834-4eca-ba7f-845c28a2e453 containing 9 characteristics. All characteristic UUIDs share the same base with only the 16-bit suffix differing.

NameUUID SuffixPropertiesDescription
data0x1401Read / Write / NotifyIMU data buffer. 124 bytes. Writable—first N bytes replaced on write. Notifications deliver IMU packets during streaming.
firmware0x1402ReadLive counter (~5180–5216 range, uint16 LE). Not firmware version. Likely battery voltage or temperature ADC.
sensor0x1403Read96 bytes. Slowly changing calibration/offset data. Pairs of uint16 LE interleaved with 005c spacers.
cmd10x1404WriteCommand register. Single byte only—multi-byte writes are ignored silently.
serial0x1405ReadDevice serial number. First byte 0x00, then ASCII.
config0x1406ReadAlways a0 01 1b. Static. Useful for keepalive reads.
status0x1407Read / Notify2-byte device state. Sends notifications on state changes.
cmd20x1408WriteCompletely inert. No effect from any write in any state.
name0x1409Read / WriteDevice name as null-terminated ASCII. Default: MoasureONE E222\0

Status Codes

StatusMeaningDescription
0x0001IdleDevice is connected but not streaming or measuring
0x0002Streaming100Hz IMU data notifications active on data characteristic
0x0003MeasureMeasurement mode active (no IMU streaming)
0x0103Measure + MarkedMeasurement point marked (~1.7s after entering measure)

State Machine

IDLE
0x0001
0x01 → ← 0x00/0xc0
STREAMING
0x0002
IDLE
0x0001
0x02 → ← 0x60/0x63
MEASURE
0x0003
~1.7s → ← 0x0a
MARKED
0x0103
Streaming and Measure are mutually exclusive. Sending 0x01 from Measure exits to Streaming.

cmd1 Command Map

Commands from IDLE (0x0001)
CommandEffectNotes
0x00No changeStay idle
0x010x0002 StreamingStarts 100Hz IMU data notifications
0x020x0003 MeasureEnters measurement mode
0x0fDANGER Hard-killDevice becomes unresponsive, requires power cycle
0x30One-shot dataReturns one IMU notification, stays idle
0x6dDANGER DisconnectCauses immediate BLE disconnect
Commands from STREAMING (0x0002)
CommandEffectNotes
0x000x0001 IdleStops streaming
0x020x0003 MeasureStops stream, enters measure
0x22, 0x44, 0x6e, 0xb0Stay streamingRe-emits status notification only
0xc00x0001 IdleAlt stop streaming
Commands from MEASURE (0x0003)
CommandEffectNotes
0x00No effectUnlike from streaming—does not exit measure
0x010x0002 StreamingCaution Exits measure mode, starts streaming
0x04Stay / → 0x0103Measurement sub-command (may control LED)
0x08Stay / → 0x0103Measurement sub-command (may control LED)
0x0a0x0003Resets/clears measurement point
0x0dStay / → 0x0103Measurement sub-command (may control LED)
0x30Stay 0x0003Returns sentinel cfcfcfcf... (not real IMU data)
0x600x0001 IdleExit measurement mode
0x630x0001 IdleAlt exit measurement mode
0xc0Stay 0x0003Re-emits status notification only

IMU Data Format

During streaming, the data characteristic delivers 124-byte packets via notifications at ~20 packets/second (100Hz effective sample rate):

Offset  Size   Type        Description
0       4      uint32 LE   Packet counter (increments by 50 per packet)
4       24     6×float32   Sample 0: ax, ay, az, gx, gy, gz
28      24     6×float32   Sample 1: ax, ay, az, gx, gy, gz
52      24     6×float32   Sample 2: ax, ay, az, gx, gy, gz
76      24     6×float32   Sample 3: ax, ay, az, gx, gy, gz
100     24     6×float32   Sample 4: ax, ay, az, gx, gy, gz

5 samples × 6 floats × 4 bytes = 120 + 4 counter = 124 bytes
Accelerometer: m/s² (gravity ≈ 9.81 on vertical axis)
Gyroscope: rad/s (IEEE 754 LE float32)

Key Findings

0x0103 is time-based The 0x0103 (measurement marked) status transition fires approximately 1.7 seconds after entering measurement mode via 0x02. It is not triggered by any specific command—whichever command happens to land at the ~1.7s mark appears to get "credit" for the transition.
Data characteristic is a dumb buffer The data characteristic is a simple 124-byte read/write buffer. Writing N bytes replaces the first N bytes; the rest are unchanged. Maximum write size is 124 bytes. There is no command processing—it's purely a data register.
  • Firmware characteristic is a live counter, not a version number. Values fluctuate in the ~5180–5216 range (uint16 LE). Likely battery voltage ADC or temperature.
  • Sensor characteristic slowly drifts in all states. 96 bytes of what appears to be live calibration offsets or bias readings.
  • Streaming and measure are mutually exclusive. Sending 0x01 from measure mode exits to streaming; the device does not return to measure when streaming stops.
  • The phone app does all computation. The device is just a sensor + state machine. All IMU integration, dead reckoning, and measurement calculation happens on the phone.

Connection Notes

  • Keepalive: Read the config characteristic (0x1406) every 2–5 seconds to prevent disconnect
  • Write mode: Use write-with-response (not withoutResponse) for cmd1
  • Auto-sleep: Device sleeps if not physically moved or tapped. Wake with double-tap.
  • Re-advertise: After disconnect, device takes 5–15 seconds to begin advertising again
  • Single connection: Only one BLE connection at a time, but device continues advertising while connected
  • Noble: Use @stoprocent/noble for macOS Electron compatibility

4. Firmware Update System

Firmware updates use USB (Micro USB cable), not BLE. A dedicated .NET MAUI app communicates with Moasure API servers and flashes firmware over USB serial.

USB Serial Protocol

Transport
USB CDC Serial
Framing
.CMD\r\n
Data Encoding
Hex string byte arrays
Port Pattern
/dev/tty.usbmodem*
Updater App
.NET MAUI
Platform
macOS & Windows

Command Set

All commands use the .CMD\r\n format—a dot prefix, 3-letter command code, and CRLF terminator. Data payloads are hex-encoded.

USB Serial Commands (31 total)
CommandNameDirectionDescription
.BSYBusy← DeviceDevice is busy, wait and retry
.RCFRead Config→ DeviceRequest device configuration
.DIDDevice ID→ DeviceRequest device identifier
.BLIBootloader Info→ DeviceRequest bootloader information
.ULCUnlock→ DeviceUnlock device (requires password)
.UL2Unlock Stage 2→ DeviceSecond unlock stage
.RBLRequest Bootloader→ DeviceEnter bootloader mode
.FERFlash Erase→ DeviceErase flash memory (requires password)
.FADFlash Address→ DeviceSelect flash address for writing
.DTAData→ DeviceSend data chunk to device
.DTPData Page→ DeviceSend firmware data page
.CALCalibration→ DeviceSend/receive calibration data
.FCLFlash Calibration→ DeviceFlash calibration data to device
.RCLRead Calibration→ DeviceRead calibration from device
.GHSGet Hash→ DeviceGet firmware/calibration SHA hash
.NRFNRF Update→ DeviceTrigger nRF52 firmware update
.RSTReset→ DeviceReset device
.SHRSet High Range→ DeviceConfigure high measurement range
.SLRSet Low Range→ DeviceConfigure low measurement range
.NAMName→ DeviceSet/get device name
.SHPShutdown→ DeviceStop current operation (sent 3×)
.MRUUnknown?
.XCUUnknown?Possibly calibration-related
.XCXUnknown?
.XCTUnknown?
.XCSUnknown?
.XCDUnknown?
.XCPUnknown?
.DBSUnknown?
.RDTRead Data?
.RSLUnknown?

Flash Update State Machine

ConnectingToModule
  → AcceptModuleConfig        (get serial, type, firmware version)
  → AcceptUnlock / Unlocked   (with UnlockPassword)
  → ConnectToBootloader       (enter bootloader mode)
  → AcceptBootLoaderInfo
  → FlashErase                (with FlashErasePassword)
  → AcceptFlashDataPage       (repeated for each firmware page)
  → RebootComplete
  → AcceptNrfUpdate           (optional: nRF52 BLE processor)
  → CalibrationUpdateReboot   (optional: calibration update)
Two-password security The flash process requires two separate passwords: UnlockPassword to unlock the device and FlashErasePassword to erase flash. These are likely stored server-side or derived per-device. A watchdog timer must be periodically poked during the update.

Firmware Images

Five encrypted firmware images were extracted from the updater app bundle:

FilenameSizeTypeVersion
PRO-ONE-260_v010B0009.img119,280 BM1 (ancient)
PRO-ONE-260_v011C0011.img124,880 BM1
PRO-ONE-260_v011D0011.img124,880 BM1 (latest)1.29.0.11
AppImg_External_1600Hz_M2P_INT_2.18.img132,160 BM2
AppImg_External_1600Hz_M2P_INT_2.21.img133,280 BM2 (latest)2.21
  • M1 = PRO-ONE-260 (original MoasureONE, S70 processor)
  • M2 = M2P 1600Hz (newer model, higher internal sample rate)
  • All files are AES encrypted (entropy ~7.999 bits/byte, all sizes multiples of 16)
  • Decryption happens on-device in the bootloader (key stored in device flash)
  • No recognizable headers, strings, or magic bytes in the encrypted data

5. Moasure Production API

Overview

The Moasure production API provides access to factory test data, device metadata, and calibration matrices. All endpoints are unauthenticated—only the device serial number and MAC address are required.

Base URL
https://production2.moasure.net/production/
Content Type
application/json; v=2.0

Endpoints

get_tracker_info

GET /production/get_tracker_info?serial_no=18S1FR521035023
Accept: application/json; v=2.0

Returns the full manufacturing history: all 5 phases, 41 factory test results with actual/min/max values, distance accuracy measurements, and user ownership history.

get_the_module

GET /production/get_the_module?serial_no=18S1FR521035023&mac_address=22:E2:0F:8D:83:E6
Accept: application/json; v=2.0

Returns device metadata: serial, MAC, model ID, firmware versions (S70 and nRF52), sensor IDs, calibration state, validation status, and SHA hash for calibration verification.

return_the_calibration

GET /production/return_the_calibration?serial_no=18S1FR521035023&mac_address=22:E2:0F:8D:83:E6
Accept: application/json; v=2.0

Returns the full 138KB calibration dataset including the 48×24 calibration matrix, raw accel/gyro data (20 and 30 orientation captures respectively), and processing metadata.

Calibration Data Structure

The calibration result is a 48×24 matrix representing 8 orientation groups. Each group contains correction parameters for both accelerometer and gyroscope:

  • 48 rows × 24 columns — stored as a JSON-encoded nested array string
  • 8 orientation groups (6 rows each): each with a 3×3 rotation matrix + 3-element bias vector, for both accel and gyro
  • Raw data: 20 accelerometer captures (576 values each) + 30 gyroscope captures (577 values each)
  • Processed on: AWS EC2 instance EC2AMAZ-PFH7AJE running "MCC ver 2.1.4"
  • Processing time: ~0.97s (accel) + ~0.67s (gyro)
  • Scores: accel -13.96, gyro 2.51

API Response Structure

Module metadata fields
  • serial_no, mac_address — Device identifiers
  • module_id (27544), model_id (2) — Internal IDs
  • s70_major_version / s70_minor_version — S70 firmware (0.13)
  • nrf52_major_version / nrf52_minor_version — nRF52 firmware (0.1)
  • passed_all_validation (true) — Factory QA passed
  • primary_sensor_id / secondary_sensor_id — Both 1
  • is_blocked (false) — Device not blacklisted
  • CalibrationState, ShaString — Calibration verification
  • DblTap — Double-tap wake sensitivity
  • measurement_number — Lifetime measurement count

6. Existing Software Architecture

Stack

The current explorer is an Electron desktop application with a BLE manager in the main process, an IPC bridge via preload, and a Canvas 2D renderer for real-time IMU visualization.

Framework
Electron
BLE Library
@stoprocent/noble
Renderer
Canvas 2D
Total Lines
2,408

Source Files

FileLinesRole
src/main/ble.js478BLE manager—scanning, connection, streaming, command dispatch
src/main/index.js35Electron entry point, window creation
src/main/preload.js18IPC bridge—exposes BLE API to renderer via contextBridge
src/renderer/app.js736UI controller—command history, device panel, IMU data decode
src/renderer/imu.js200Madgwick AHRS filter, dead reckoning, zero-velocity updates (ZUPT)
src/renderer/visualizer.js3073D trail visualization + orientation cube (split Canvas 2D)
src/renderer/styles.css486Dark theme UI styles
src/renderer/index.html148Explorer UI layout

Architecture Diagram

┌─────────────────────────────────────────────┐
│  Main Process                               │
│  ┌────────────┐      ┌──────────────────┐   │
│  │  index.js   │─────▶│     ble.js       │   │
│  │  (Electron) │      │  (noble + GATT)  │   │
│  └────────────┘      └───────┬──────────┘   │
│                              │ IPC           │
│  ┌────────────┐              │               │
│  │ preload.js  │◀────────────┘               │
│  │ (bridge)    │                             │
│  └─────┬──────┘                              │
├────────┼────────────────────────────────────┤
│  Renderer Process                           │
│        │ contextBridge                       │
│  ┌─────▼──────┐  ┌──────┐  ┌────────────┐  │
│  │   app.js    │──│imu.js│──│visualizer.js│  │
│  │  (UI ctrl)  │  │(AHRS)│  │  (Canvas)   │  │
│  └────────────┘  └──────┘  └────────────┘  │
└─────────────────────────────────────────────┘

Research Scripts

12 Python scripts were written for protocol research and reverse engineering:

scripts/
  ble_mitm.py BLE MITM proxy (app validates against server DB)
  data_write_probe.py Data char write behavior (256-byte scan)
  decode.py IMU packet decoder
  measure_capture.py Basic measurement flow capture
  measure_deep.py 14-test deep protocol investigation
  probe_all.py Full command space scan (v1)
  probe_all2.py Full command space scan (v2)
  probe_complete.py Complete cmd1/cmd2 scan from all states
  probe_fast.py Quick command probe
  probe_remote.py Remote BLE probe
  probe.py Initial BLE characteristic probe
  remote_cmd.py Remote command dispatch

Current Status

The Electron app is a fully functional BLE explorer and IMU visualizer. It can scan for and connect to the device, send arbitrary commands, stream IMU data, and render real-time 3D orientation and motion trails. It is not yet a measurement application—that's the next phase.

7. Hardware Design Concept

A next-generation measurement system designed for contractors: a universal puck form factor with UWB mesh positioning, RTK GPS, and inertial dead reckoning.

Product Line

Two SKUs sharing a single ~60mm hockey puck enclosure (glass-filled polycarbonate + TPU overmold, IP67, MIL-STD-810H):

Indoor Puck

$149
~$45 BOM
  • ESP32-S3 (dual-core, BLE + Wi-Fi)
  • ICM-42688-P (6-axis IMU)
  • MMC5983MA (magnetometer)
  • BMP390 (barometric altimeter)
  • DW3220 (UWB transceiver)
  • Piezo buzzer (Find My + alerts)

Outdoor Puck

$349
~$112 BOM
  • Everything in Indoor, plus:
  • u-blox ZED-F9P (RTK GNSS)
  • Ceramic patch antenna
  • RTK corrections via NTRIP
  • Multi-constellation (GPS, GLONASS, Galileo, BeiDou)

Positioning System

The puck system combines multiple positioning technologies for centimeter-level accuracy across all environments:

TechnologyAccuracyEnvironmentRole
RTK GPS±2 cm horizontalOutdoor, open skyPrimary outdoor positioning
UWB Mesh±5–10 cmIndoor & outdoorRelative positioning between pucks
Barometric±10–20 cmAll environmentsZ-axis altitude (complements RTK & UWB)
IMU Dead Reckoning±10–30 cm (short term)All environmentsFallback, gap-filling between fixes

Z-Axis Accuracy Targets

  • Outdoor (RTK + baro): ±2–3 cm
  • Holes / Indoor (UWB + baro): ±2–5 cm
  • IMU-only fallback: ±10–30 cm

Multi-Puck Operation

Any puck can be a beacon (fixed reference) or rover (moving measurement point), with roles set in software. Multi-puck modes enable:

  • Distance — point-to-point between any two pucks
  • Area & Perimeter — walk the boundary with rover puck(s)
  • Elevation Profiles — traverse terrain with altitude tracking
  • Volume — walk the surface of dirt piles, excavations
  • Retaining Walls — measure along vertical faces

Charging & Accessories

Each puck has USB-C plus a magnetic pogo-pin interface for station charging:

  • 2-slot station — $69
  • 4-slot station — $99
  • 8-slot crew case — $149 (rugged carry case with integrated charger)

Retail Bundles

  • Single Indoor Puck — $149
  • 2-Pack Indoor + 2-Slot Station — $367
  • 4-Pack Indoor + 4-Slot Station — $695
  • Pro Kit (1 Outdoor + 3 Indoor + 4-Slot) — $945

Find My Integration

Every puck supports Apple Find My and Google Find My Device networks via BLE, UWB precision finding (point-and-locate), and piezo buzzer for audible location.

RTK Corrections

The Outdoor Puck uses the u-blox ZED-F9P GNSS receiver with NTRIP correction sources:

  • Free: State DOT CORS networks, RTK2go community casters
  • Paid: Swift Navigation Skylark, PointOne Navigation
  • Antenna: u-blox ANN-MB-00 (integrated ceramic patch in puck lid)
Comparison: Moasure IMU-Only vs. Puck System
CapabilityMoasure (IMU)Puck System (RTK+UWB+IMU)
Distance Accuracy±1–2% (drift accumulates)±2 cm (absolute)
Max Reliable Range~30 m (drift limit)Unlimited (outdoor GPS)
Z-AxisPoor (IMU drift)±2–3 cm (RTK + baro)
Multi-PointSequential onlySimultaneous (mesh)
IndoorWorks everywhereUWB mesh + IMU
OutdoorWorks but driftsRTK GPS + baro
Price~$150 device$149–$349 per puck

8. Implementation Roadmap

The path from BLE explorer to measurement application, broken into four phases:

Phase 1 — Calibration Module

Apply the factory calibration matrix to raw IMU data. Load the 48×24 matrix from the API, transform accelerometer and gyroscope readings to correct for per-device sensor bias and orientation errors.

New file: calibration.js

Phase 2 — Measurement Engine

Core measurement algorithms: distance (double-integrated acceleration), area (shoelace formula on path), elevation (barometric or Z-integration), and point-to-point. Handle ZUPT detection, drift correction, and coordinate transforms.

New file: measurement.js

Phase 3 — Measurement UI

Dual-mode application: Measure (streamlined measurement workflow with results display) and Explorer (existing debug/protocol interface). Split-view or tab-based, sharing the same BLE connection.

New files: measure-app.js, measure-viz.js, storage.js, export.js

Phase 4 — Polish

Auto-connect to known devices, live measurement overlay during capture, shape detection (rectangle, circle), keyboard shortcuts, measurement history with local storage, CSV/JSON export.

Modified files: imu.js, app.js, index.html, styles.css, index.js, preload.js

Open Moasure · MoasureONE E222 Technical Reference · 2025