The site opens on a device picker:
| Route | Device | Transport | What it does |
|---|---|---|---|
/ |
— | — | Pick WG1200 or WS1300; shows whether this browser supports each |
/wg1200 |
WG1200 / D1 gateway | USB (Web Serial) | Switch between WeatherXM and Meshtastic firmware (below) |
/ws1300 |
WS1300 weather station | Bluetooth (Web Bluetooth) | Update to the latest published firmware, or install a -dfu.zip / signed .bin |
/ws1300/dev |
WS1300 | Bluetooth | Staff tools: Zephyr shell console, any published release, file installs, MCUboot slots. Not linked, noindex |
/ws2001 |
WS2001 (H2) station | Bluetooth | Connect the station to TTN / ChirpStack (keeps the WeatherXM keys on firmware V4.5+) or switch it back |
Web-based firmware switcher for the WeatherXM WG1200 / D1 Gateway, with two deliberately different operating modes:
- WeatherXM Tri-Protocol Gateway — keeps normal WeatherXM gateway/cloud operation and can republish the paired station's weather observations as Meshtastic environmental telemetry and MeshCore sensor-node telemetry. This is the mode to use when you want the weather station visible in mesh ecosystems without giving up WeatherXM.
- Full Meshtastic Node — replaces the active gateway application with native Meshtastic firmware so the WG1200 itself becomes a Meshtastic router/repeater/client using its onboard SX1262 and TFT.
The entire operation happens in the browser over USB using the Web Serial API.
WeatherXM tri-protocol mode adds mesh-compatible weather telemetry; Full Meshtastic mode turns the gateway itself into a Meshtastic node. Your WeatherXM device identity, credentials and factory recovery image stay intact, so you can switch back at any time.
This is not a generic ESP32 flasher. It is purpose-built with strict hardware write guards:
- Zero Cloud Credential Risk: The device credentials partition (
esp_secure_certat0x00D000) is never erased or written. - Factory Fallback Preserved: The
factorypartition (0x020000) remains protected as the immutable stock recovery image. - Strict Write Guard: Firmware application payload writes are strictly confined to
ota_0(0x420000) orota_1(0x820000). Slot activation uses guarded, CRC-verified atomic updates tootadata(0x013000). All other partitions are hardware/logic write-protected. - Chip Erase Disabled:
eraseAll: falseis permanently enforced. Full flash erase APIs are stripped out. - Pre/Post Verification: Cryptographic SHA-256 snapshots verify that protected partitions remain byte-for-byte identical before and after flashing.
- Hardware MD5 Check: Uses on-chip ESP32-S3 SPI flash MD5 calculation to guarantee image integrity.
| Offset | Size | Name | Purpose |
|---|---|---|---|
0x00C000 |
4 KB | partition_table |
ESP-IDF partition table |
0x00D000 |
8 KB | esp_secure_cert |
Device cloud credentials & certificates (TLV 0xBA5EBA11) |
0x00F000 |
16 KB | nvs |
Non-volatile storage |
0x013000 |
8 KB | otadata |
Active OTA boot pointer & CRC32 |
0x015000 |
4 KB | phy_init |
RF calibration data |
0x020000 |
4 MB | factory |
Stock WeatherXM factory fallback |
0x420000 |
4 MB | ota_0 |
Application Slot 0 |
0x820000 |
4 MB | ota_1 |
Application Slot 1 |
0xC20000 |
4 KB | nvs_key |
NVS encryption key |
0xC21000 |
3 MB | spiffs |
File storage |
npm run manifest refreshes the manifests of both devices (WG1200 and WS1300). A file argument is routed by name: *.bin to WG1200, *-dfu.zip to WS1300. Use npm run manifest:wg1200 or npm run manifest:ws1300 to run just one.
To add a new firmware release:
# Option 1: Provide the new binary file directly
npm run manifest -- path/to/fw_release_0.8.27-gceee14f-signed.bin
# Option 2: Place binary in public/firmware/weatherxm/ or public/firmware/meshtastic/ and run:
npm run manifestThe script will automatically:
- Verify the binary size, ESP-IDF app descriptor, and ESP32-S3 Secure Boot V2 signature (0xE7 magic).
- Calculate the exact SHA-256 checksum.
- Sort versions semantically and set the newest as the default
weatherxmrelease. - Update
public/firmware/manifest.jsonand sync withdist/firmware/manifest.json.
Wireless in-browser Device Firmware Update (DFU) for the WeatherXM WS1300 outdoor weather station, powered by Web Bluetooth and Zephyr MCUmgr SMP. No cables, no proprietary desktop software, and no mobile app required—you can update the station in the field directly from a laptop or an Android phone standing next to the unit.
The WS1300 is built on the dual-core Nordic nRF5340 SoC. The web flasher orchestrates updates across both hardware cores sequentially from standard nRF Connect SDK -dfu.zip distribution packages:
- Application Core (Image 0): Weather sensor acquisition, power management, local calibration, and telemetry formatting.
- Network Core (Image 1): 2.4 GHz Bluetooth Low Energy controller, radio protocol stack, and Zephyr BLE subsystem.
The flashing pipeline guarantees zero risk of bricking:
- Integrity Pre-Checks: The web client verifies the MCUboot header magic (
0x96f3b83d), image vector table, and cryptographic SHA-256 checksums of the release package before initiating transfer. - Secondary Slot Staging: New images are uploaded chunk-by-chunk into the station's inactive secondary flash slot via MCUmgr SMP. The running firmware remains completely untouched.
- Test-Mode Boot: Upon transfer completion, the web flasher marks the new slot for
testexecution and requests a controlled reboot. - Self-Confirming Verification: On boot, the updated firmware runs hardware self-tests and confirms its own image (
imgswap_confirm()inapp/src/main.cpp). - Automatic Rollback: If the new firmware fails to boot, crashes, or hangs, the MCUboot hardware watchdog triggers a reboot and automatically rolls back to the previously confirmed image.
smp.ts/cbor.ts: Zephyr MCUmgr Simple Management Protocol (SMP) client over Web Bluetooth (SMP Service8D53DC1D-1DB7-4CD3-868B-8A527460AA84). Implements CBOR payload encoding, multi-notification reassembly, image state queries (ImageStatesRead), chunked image streaming (ImageUploadWrite), test marking (ImageStatesWrite), and OS reset.- ATT MTU Fragmentation: Data writes are dynamically packetized into 180-byte ATT fragments, preventing packet drops and buffer overflows across macOS, Windows, Linux, and Android Bluetooth stacks.
dfuPackage.ts: High-performance in-memory ZIP parser usingfflatethat extracts and validatesmanifest.json,app_update.bin(Image 0), andnet_core_app_update.bin(Image 1).ws1300Manifest.ts: Remote manifest resolver with strict SHA-256 validation against/firmware/ws1300/manifest.json.dfu.ts/updateFlow.ts: Multi-phase state machine managing connection, pre-flight queries, dual-core uploads, progress metrics (throughput in KB/s, ETA), reboot sequencing, and post-update verification.nus.ts: Nordic UART Service client providing terminal stream access to the embedded Zephyr shell.
- Open the WS1300 Flasher: Navigate to
/ws1300in Chrome or Edge on a laptop or Android phone. - Wake Bluetooth Advertising: Stand next to the station and press the physical button once briefly (do not hold for 15+ seconds, as that clears paired network settings). The station will advertise over Bluetooth for 15 minutes.
- Connect: Click Connect WS1300 and select your station from the browser's Bluetooth chooser.
- Start Update: The flasher compares the installed firmware version against the latest release. Click Install update.
- Automatic Dual-Core Flashing: The flasher streams both application and network images with live throughput telemetry, prompts the reboot, and confirms the new version once the station boots.
For engineering diagnostics, testing custom firmware builds, or debugging MCUboot states, the unlisted developer portal provides:
- Interactive Zephyr Shell: Real-time console over Nordic UART Service (NUS) to run Zephyr shell commands, inspect logs, and debug sensor hardware.
- Live MCUboot Slot Inspector: Queries active vs. secondary slot versions, image hashes, and slot flags (
pending,confirmed,active,permanent). - Custom File / Release Installer: Flash custom
-dfu.zippackages or standalone signed.binfiles directly from disk. - Manual Slot Controls: Force slot test marking, manual image confirmation, or slot erasing.
# Validate package, generate SHA-256 hashes, and update manifest
npm run manifest -- path/to/ws1300_release_v22.6-dfu.zip
# Or inspect/refresh existing packages in public/firmware/ws1300/
npm run manifest:ws1300The manifest generator validates that:
- The package is a valid nRF Connect SDK DFU zip.
- Every contained image targets the WS1300 board and contains a valid MCUboot header (
0x96f3b83d). - Hashes are calculated and stored in
public/firmware/ws1300/manifest.jsonand mirrored todist/firmware/ws1300/manifest.json.
/ws2001 points a WS2001 at The Things Network, ChirpStack or any LoRaWAN network server over Web Bluetooth (AT
commands on the station's transparent-UART service). The hardware is the same as the SenseCAP S2120, but the station
runs WeatherXM's own firmware: one signed 24-byte frame on FPort 99 with wind gust, rain total and max rain rate
(1 Helium data credit per uplink).
- Keys are kept (firmware V4.5+). The page uses
AT+NETPROFILE: the customer JoinEUI/AppKey go into profile 1, the WeatherXM keys stay in profile 0, and Switch back to WeatherXM reactivates them. On older firmware the page warns that the single key set will be replaced. - Payload stays the WeatherXM frame (
AT+TESTMODE_TYPE=0). The legacy TLV format (FPort 3) is no longer selected. - Upload interval defaults to 5 minutes on your network: a 24-byte SF7 uplink is ~82 ms, so 3 minutes exceeds TTN's 30 s/day fair use. The WeatherXM profile keeps its own 3 minutes (firmware V4.5+ stores the interval per profile).
- Decoder: one script for TTN v3, ChirpStack v4 and ChirpStack v3, at
public/decoders/ws2001_uplink_decoder.js(served at/decoders/ws2001_uplink_decoder.js). The source of truth isws2001-firmware/tools/decoders/ws2001_uplink_decoder.js. Update it withnode scripts/sync-ws2001-decoder.mjs <path-to-firmware-repo>/tools/decoders/ws2001_uplink_decoder.js, which also regeneratessrc/lib/ble/ws2001UplinkDecoder.ts. A test keeps the two copies identical.
/ws2001 keeps stations on the latest WeatherXM firmware, so a customer who connects an older station is brought to
the current release (V4.5 adds the network profiles that keep the WeatherXM keys).
- Automatic (on by default): with "Update the station firmware automatically" ticked (the choice is remembered per
browser), connecting a station older than the published
lateststarts the update straight away. - Manual: the device card shows Update to Vx.y, or Reinstall Vx.y when the station is already current (the bootloader accepts the same version).
- How it works (
src/lib/ble/ws2001Dfu.ts, port ofws2001-firmware/tools/ws2001_dfu.py): the package is downloaded and checked first (SHA-256 against the manifest, image hash against the init packet, ECDSA P-256 signature against the WS2001 bootloader public key, HW 52 / S140 7.2.0). Then the station is sent into its bootloader over the bonded link (buttonless DFU) under a unique nameDfuWX……. Browsers need a click to connect to that new device, so the page asks the user to pickDfuWX……in the Bluetooth list (not "WeatherXM WS2001 …"). The Secure DFU transfer checks a CRC32 per 4 KB object, retries, and resumes if the link drops. The bootloader waits about 2 minutes in update mode and keeps the old firmware until the new one validates. - Publishing a release: build and sign it in
ws2001-firmware(scripts/build_ble_dfu.sh --application-version <major*10+minor>), thennpm run manifest:ws2001 -- <path>/dist/ws2001-application-v<NN>-ble-dfu.zip --commit <sha>. This verifies the package and writespublic/firmware/ws2001/ws2001-application-v<x.y>-ble-dfu.zipplusmanifest.json; the newestfw_versionbecomeslatest.
| Browser | OS | WG1200 (Web Serial) | WS1300 (Web Bluetooth) |
|---|---|---|---|
| Google Chrome | macOS, Windows, Linux, ChromeOS | Full | Full |
| Microsoft Edge | macOS, Windows, Linux | Full | Full |
| Chrome for Android | Android | Not supported by OS | Full (ideal for outdoor updates!) |
| Brave / Opera | Desktop | Full | Full |
| Safari / WebKit | macOS, iOS | Unsupported (No Web Serial) | Unsupported by Safari* |
*On iOS, Apple restricts the Web Bluetooth API in Safari. iOS users can use specialized Web Bluetooth browsers like Bluefy.
# Install dependencies
npm install
# Run unit & safety tests
npm test
# Run typecheck
npm run typecheck
# Start local development server
npm run dev
# Build production static site
npm run buildThis site is 100% static and deploys to Cloudflare Pages:
- Build command:
npm run build - Build output directory:
dist - Node version:
20or22 - Custom domain:
flasher.weatherxm.com - Permissions policy header in
public/_headers:Permissions-Policy: serial=(self), bluetooth=(self)allows Web Serial and Web Bluetooth.