Hubble Network on a Silicon Labs xG24: +20 dBm radio board, Eight Weeks on a Budapest Roof, Zero Packets

Summary

Hubble Network promises satellite connectivity from an ordinary Bluetooth SoC requiring only a firmware change and no additional radio hardware. We brought up its sat-continuous sample application on a +20 dBm Silicon Labs EFR32xG24 radio board, confirmed the Tx bursts near 2.482 GHz with a HackRF SDR, a Signal Hound BB60C and an ESPARGOS receiver, and left the boards on a Budapest roof for roughly eight weeks. The result? Not a single packet appeared on the Dashboard.
The radio, it turned out, wasn't the culprit. During our test, Hubble's satellite service was available only in the US, a limitation that wasn't mentioned in the onboarding documentation we followed. Hubble has since publicly confirmed this restriction and updated its documentation. In this post, we walk through the bring-up process, our measurements, and the first things we'd check if we were to run the experiment again.

Highlights

Item
Result
Condition
Firmware bring-up (xG24, Zephyr)
Works, ~10.33 s send interval
sat-continuous, BRD4187C on WSTK
Carrier observed
2.482578 GHz
Over the air, PCB antenna, no cable
OTA peak at analyser
−12.4 dBm
BB60C, antenna to antenna, short distance, relative only
Burst spectrum (BB60C)
Narrowband, hopping-like; very likely not standard BLE GFSK
Antenna to antenna, qualitative
Satellite packets in Dashboard
0 over ~8 weeks
Budapest, Sandbox account, outside the coverage region
Field runtime, 18650 + LDO
~2 weeks
2800 mAh cell, unmodified test loop
notion image
The transmitter worked from the first day of the roof test: the HackRF next to it saw every burst. The problem was further up the link. (The xG24 used its PCB antenna; the dish at the edge of the frame is unrelated.)

Context: Bluetooth to orbit

A few years ago, we worked on an ESA-funded study of a low-power IoT link via geostationary satellites, so Hubble's claim that an unmodified BLE SoC could reach orbit immediately caught our attention.
GEO and LEO satellites offer very different trade-offs. A GEO satellite remains fixed relative to the ground, providing continuous coverage of the same area and making two-way communication practical. The downside is distance: at 2.48 GHz, the free-space path loss is about 191 dB, roughly 35 dB higher than for a LEO satellite overhead at an altitude of 590 km. That extra path loss makes communication with a GEO satellite much more demanding for a low-power device.
LEO satellites, by contrast, pass much closer to the ground, reducing path loss enough to make Hubble's approach—a +20 dBm transmitter using a PCB antenna—plausible. But these satellites move across the sky, so connectivity is available only during passes. In Hubble's approach, messages are sent one-way and can take up to six hours to be delivered. This makes the technology well suited to telemetry that can tolerate delays, but less suitable for applications that require continuous connectivity or a quick response. Despite these limitations, we found the technology very interesting and wanted to give a test a go.
Hubble runs two networks. The terrestrial network picks up ordinary BLE advertisements through phones and gateways. The satellite network uses the same 2.4 GHz radio hardware, but with a dedicated waveform: according to Hubble's regulatory page it is a frequency-hopping system on 19 channels at the band edge, above 2.481 GHz, with an always-on preamble and a lower bit rate than standard BLE advertising. In other words, a standard BLE advertising sample won't reach the satellites: Hubble's satellite protocol uses its own channel plan and transmission format, rather than standard BLE advertising on channel 39.
The device side needs a supported SoC, the Hubble Device SDK, and at least +20 dBm radiated power. Most BLE chips output 0 to 8 dBm, so the +20 dBm xG24 radio board is one of the simplest ways in. Hubble lists the EFR32xG24 +20 dBm kit as a validated satellite platform on its compatibility page.
The link is one-way. The device transmits and never receives an acknowledgement. Packets come down through Hubble's ground segment and are supposed to appear in the Dashboard within six hours of a pass. The only end-to-end test is to transmit and then check the Dashboard.

Setup

Item
Identity
Role
Radio board
Silicon Labs BRD4187C Rev A00, EFR32MG24B220F1536IM48, +20 dBm, PCB antenna (U.FL connector path not connected)
Satellite transmitter
Mainboard
BRD4001A Rev A01 (WSTK)
J-Link programming, VCOM, bench power
Second board
ESP32-C6 SuperMini (ESP32-C6FH4), ESP-IDF 5.5.5
Comparison transmitter
Receivers
HackRF One (Nooelec case, TCXO) + Android RF analyser app; Signal Hound BB60C + Spike; ESPARGOS
Local OTA verification
Firmware
Hubble Device SDK samples/zephyr/sat-continuous, Zephyr v4.4.0-10782-gcc4eb97a7fd7
Continuous transmit loop
Toolchain
Windows, Python 3.12.10, west 1.5.0, CMake 4.4.2, Zephyr SDK 1.0.1
Build host
Registration
Hubble Dashboard, Sandbox org, DEVICE UPTIME counter, AES-256-CTR
Device credentials
Power supply
Bench: WSTK powered by a RAVPower RP-PB31 power bank, monitored with an FNB58 power meter. Field: radio board powered by an 18650 cell through an ST LDO (marking LL33).
Bench and rooftop power supply chain
Site
Flat roof, Budapest (47.5° N), open sky, board on a 20 to 30 cm non-conductive spacer
ㅤ
We did not record the Hubble Device SDK commit hash used for the test. The SDK was checked out from the main branch as of mid-August 2026. This limits reproducibility and is discussed further in the Limitations section.

How the satellite path works

For a packet to appear in the Dashboard, the entire path must work: the device must transmit successfully, a satellite must receive the burst, and Hubble's ground segment and backend must process the packet correctly.
The device registration and transmission configuration must also agree. According to the configuration used for this test, the relevant parameters include the device key, counter source (DEVICE UPTIME or UNIX_TIME), and key size. A mismatch may prevent successful packet processing even when the RF transmission itself is correct.
This makes an empty Dashboard inherently ambiguous. It does not tell us whether a burst failed to reach a satellite, whether the satellite was listening over the test location, or whether a received packet was rejected during backend processing. Without an acknowledgement or an independent indication of satellite reception, these failure modes can look identical from the device side.

Bring-up on Windows

The full step-by-step procedure is in the Trywest init -m https://github.com/HubbleNetwork/hubble-device-sdk.git . it section. These were the main issues we encountered in order:
  • Python 3.14 lacked compatible wheels for grpcio-tools and hidapi. Python 3.12 resolved the issue. We reported this upstream.
  • Build tools: Installing CMake and Ninja in the virtual environment fixed west zephyr-export.
  • The Zephyr SDK setup.cmd could not find 7z on PATH, even though the archive tool had just used it. Adding C:\Program Files\7-Zip to PATH fixed it.
  • Unknown HUBBLE_* Kconfig symbols appeared because we had cloned the SDK next to an existing Zephyr workspace. Using the SDK as the west manifest (or adding it to the manifest) fixed it.
  • Passing the Base64 key through PowerShell → west → CMake produced malformed string literal … Assignment ignored. The build went through anyway. A key in a separate .conf file avoids the quoting problem.
  • The Silicon Labs radio path links against the RAIL library, which needs west blobs fetch hal_silabs.
Blinky built for xg24_rb4187c (26 400 B flash, 4 136 B RAM) and flashed through the WSTK's J-Link. The sat-continuous sample then booted with:
The fields that matter: E:256 is AES-256, CS:DU is the DEVICE UPTIME counter, and N:S means satellite mode. Consecutive log timestamps are 10.329 s apart. Packet sent means only that the send call returned. It says nothing about whether a satellite received anything.
notion image
The whole field test ran on the on-board PCB antenna (default assembly option of the radio board). The U.FL connector is not in the RF path unless the 0 Ω selector is moved, so a cable on the U.FL alone would have done nothing.

Results: is it actually transmitting?

We checked the transmitter at four levels, and each level proves something different:
Check
Proves
Does not prove
Boot log with N:S and periodic sent
Firmware reaches the TX path
RF output
Spectrum/waterfall bursts near 2.482 GHz
RF at the right place and period
Framing, key, link margin
Burst spectrum
Narrowband bursts at the band edge
That Hubble can decode it
Packet in Dashboard
End-to-end
Reliability over many passes

HackRF: bursts at the band edge

With the HackRF on the roof next to the box, the Android RF analyser app (2482 MHz centre, 20 MHz span) showed a burst every ~10 s just above 2481 MHz, about 10 dB above the noise floor on the averaged trace.
notion image
Every ~10 s a short burst shows up at the 2.4 GHz band edge, above the last BLE advertising channel. That is where Hubble's satellite channels are. The fainter traces to the left were not identified.

BB60C capture

To go beyond a waterfall, we pointed a Signal Hound BB60C signal analyser with a 2.4 GHz antenna at the board (antenna to antenna, short distance, no cable). The marker read −12.4 dBm peak at 2.4825 GHz in one session and −16.5 dBm in another. These are relative numbers: we did not calibrate antenna gains or distance, so they say nothing about EIRP. We also measured a carrier at 2.482578 GHz.
We cannot identify the modulation from these captures. In our view it is a narrowband, frequency-hopping waveform, possibly with an FSK core, rather than standard BLE GFSK. OFDM is a weaker candidate: its peak-to-average power would cost the transmitter efficiency, which a battery-powered endpoint can ill afford.
notion image
notion image
ESPARGOS (the ESP32-based coherent receiver array) also picked up the bursts, which gave us an independent confirmation by a third receiver.

The step we skipped

Hubble's quick start guide describes a more conclusive local test using an ADALM-PLUTO SDR and pyhubblenetwork. This setup can decode captured packets using your device key and associate them with your device ID, helping verify the transmission format and configuration independently of the satellite network.
We did not run this test. In hindsight, it is the first thing we would do next time: verify that our transmissions can be decoded locally before investigating satellite reception or backend delivery.

The field test

We deployed the boards on the rooftop in early August and left them running until late September, with occasional interruptions for reflashing. We tested two EFR32xG24 boards, each with its own registered device key. We later added an also Hubble approved ESP32-C6 kit as a comparison transmitter. All boards were positioned on a 20–30 cm plastic spacer above the roof membrane, with an unobstructed view of the sky.
notion image
The view of the sky was about as open as you can get in a city. At no point was the transmitter's location the limiting factor.
Look4Sat with current TLEs gave plenty of high passes. HUBBLE 6 (NORAD 64562) reached 80.3° at 01:11 local on 8 August, and HUBBLE 7 (NORAD 64592) had regular passes in the 45° to 50° range. The predicted horizon-to-horizon duration was about 12.5 minutes at 590 to 594 km.
notion image
There was no shortage of high passes over Budapest: several per day were recorded, some above 75°. Being able to see a satellite does not mean it is serving your location.
After every pass the Dashboard still showed Recent packet: Never. Over the following weeks we checked everything on our side:
  1. Key. We checked that the Base64 key in the build matched the registration, regenerated keys, and registered a second board separately.
  1. Counter mode. We confirmed CS:DU in the boot log against DEVICE UPTIME in the Dashboard.
  1. Antenna. We kept the PCB antenna away from the roof surface, the battery and the wiring.
  1. Passes. We tried high-elevation passes, at night and during the day.
  1. Waiting time. We waited more than the documented six hours before calling a pass a failure.
  1. A second transmitter. The ESP32-C6 also produced local RF, and its packets did not appear either.
We contacted Hubble support with the hardware, SDK and configuration details. Their first reply asked which reference firmware and dev kit we were using.

What we were missing

In late September we found out, independently and by chance, that Hubble's satellite receivers were only providing service over the US at that point. Over Europe the constellation was effectively deaf to user uplinks. Nothing in the onboarding flow or the documentation we followed (quick start, compatibility page, SDK samples) mentioned a geographic limit. Several weeks of troubleshooting the key, the antenna and the power supply were therefore aimed at a link that could not have worked from Budapest.
We wrote this up on LinkedIn. Apoorva Nori, Head of Product at Hubble Network, replied on 4 October:
"Thanks for your feedback and for being an early adopter of the SDK, Zoltán Dóczi. We're actively rolling out the service outside the US and have updated our documentation to be clearer about geographic coverage. We'll keep you updated!" — Apoorva Nori, Hubble Network, LinkedIn, 4 October 2026
notion image
Hubble's public reply confirms the regional limit and the documentation change. It came after the test, not before.
Since then, the transmission guidance lists the coverage region as North America. That is a useful fix, and we appreciate the quick response.
A second blocker in the current documentation. The updated quick start guide also states that “Sandbox does not have Satellite access.” Satellite access requires a Hubble Live organisation, but our devices were registered under Sandbox.
We don't know whether this restriction was documented when we ran our test in August, as we didn't save a copy of the documentation at the time. Regardless, under the current requirements, our setup would not have worked even within the satellite coverage area.
If you're planning to repeat this experiment, confirm both satellite coverage in your region and satellite access for your account before climbing up to the roof.

Sanity checks

Orbit

The HUBBLE-6 TLE from 21 September 2026 gives a mean motion of 14.937 rev/day, which is a period of 96.4 min and a semi-major axis corresponding to about 594 km altitude. The inclination is 97.78°, a sun-synchronous orbit. This matches the 590 to 594 km that Look4Sat shows. Hubble's guidance quotes "approximately 550 km", which presumably describes the constellation in general rather than these two satellites.
Hubble's documentation gives a 3 to 5 minute useful window per pass, against 12.5 minutes horizon to horizon. That fits a receiver that only covers part of the sky: a phased array with a limited scan angle rather than an omnidirectional antenna. This is our interpretation.

Link budget

Free-space path loss at 2.482 GHz:
Elevation
Slant range
FSPL
Received power at a 0 dBi antenna for +20 dBm EIRP
90°
590 km
155.8 dB
−135.8 dBm
60°
672 km
156.9 dB
−136.9 dBm
45°
802 km
158.4 dB
−138.4 dBm
30°
1059 km
160.8 dB
−140.8 dBm
A 1 MHz receiver bandwidth has a thermal noise floor of −114 dBm. A 0 dBi antenna would therefore leave the signal more than 20 dB below the noise. To close the link, the satellite needs a high-gain array (Hubble's material mentions more than 100 elements, which is roughly 20 dB of gain), processing gain from coding and repetition, and a full +20 dBm actually radiated. That last point is a problem for the radio board. Its small PCB antenna almost certainly has an efficiency well below 100 %, so +20 dBm conducted probably means less than +20 dBm radiated. Hubble's guidance warns that PCB and chip antennas reduce coverage and recommends a dipole. We cannot test this without coverage, but a dipole on the U.FL path would be our first hardware change for a supported-region test.

Doppler

At about 7.57 km/s orbital velocity and 590 km altitude, the largest line-of-sight velocity near the horizon is about 6.9 km/s. At 2.482 GHz this gives a Doppler shift of up to about ±57 kHz. That is not negligible: if the 19 channels share the 2.481–2.4835 GHz edge, the spacing is only about 130 kHz, so the receiver must compensate. It can, because the satellite knows its own ephemeris and the shift follows a predictable curve over the pass. In our view, Doppler combined with crystal tolerance was not a plausible reason for the missing packets, even though it was one of the first theories we considered. Battery life: estimate versus measurement
A first estimate assumed a 50 ms burst at 150 mA every 10 s and a 100 µA sleep current. That gives an average of about 0.85 mA, which would mean around 80 days from a 2800 mAh 18650 cell through a low-dropout LDO. The measured runtime in the field was about two weeks, which means an average of roughly 7 to 8 mA.
The difference is not mysterious. The sat-continuous sample is a bring-up loop, not a low-power application. The board's LED was visibly on at night. The ST LDO has a quiescent current in the hundreds of µA, and we never measured the real TX pulse or the sleep current. The bench setup drew 159 mA at 5.065 V from the power bank, but that number includes the WSTK and its debugger and says nothing about the radio itself. Runtime estimates for this sample are meaningless until you measure the current trace.
notion image
159 mA at 5 V is what the whole WSTK draws, debugger included. Most of that current does not go to the radio, and none of it describes the radio's TX pulse.
notion image
In the standalone field configuration, an 18650 cell feeds an ST LDO that supplies 3.3 V to the radio board. It ran for about two weeks, roughly a tenth of the estimate.

The satellites are alive

A fellow radio amateur pointed out that the Hubble satellites also have FCC-filed frequencies around 400 MHz, and that SatNOGS monitors them. HUBBLE-6 telemetry at 401.1 MHz (GMSK, 4800 Bd, AX.25) was recorded on 13 September 2026 by station 3020, Jim Hutchison, North Carolina and on 19 August 2026 by station 2178, DIYSATELLITE, Uruguay. The AX.25 address fields decode by shifting each byte right by one:
The rest of each frame is binary telemetry, which we did not try to interpret. These frames are the satellite's own downlink. They are not acknowledgements of our 2.4 GHz uplink. They do show that HUBBLE-6 was healthy and on orbit while our packets went nowhere. A nice detail: the Uruguay station received the satellite in mid-August, when nothing we sent from Budapest arrived.

Myths we had to unlearn

During bring-up we used an AI chat assistant. Several of its answers sounded confident and were wrong, and some of them sent us after the wrong problem for days:
  • "If the key were wrong, it wouldn't compile." It compiles. An empty key builds and runs with an all-zero placeholder, and you only get a warning at boot. A valid key from the wrong registration passes every local check. Only the backend can catch it.
  • "It's a BLE advertisement on channel 39." It is not. The satellite mode hops over 19 channels above 2.481 GHz and uses its own framing. A BLE sniffer looking for 0x8E89BED6 will not find it.
  • "Hubble has two satellites, Hubble-1 and -2." That information is out of date. The passes we planned around were HUBBLE 6 and HUBBLE 7, both launched in 2025 (COSPAR 2025-135).
  • "The roof detuned the antenna and 90 % of the power was reflected." Nobody measured that. A spacer is good practice, but it was not the cause.
  • "A high pass means the satellite will hear you." Only if the service covers your location and your account includes satellite access.

Limitations and open questions

  • No end-to-end validation. We never saw a packet delivered, so we cannot vouch for the complete chain. We can only say that our transmitter produced plausible RF.
  • No local decrypt. The Pluto plus pyhubblenetwork test is the missing middle step.
  • No calibrated EIRP. The over-the-air readings are relative. With a PCB antenna, it is possible that the board does not meet Hubble's requirement of at least +20 dBm radiated.
  • SDK commit not recorded. Zephyr is pinned, but the Hubble SDK was main from mid-August.
  • Sandbox vs Live. We do not know what the documentation said about this in August.
  • Power numbers are approximate. We have no current trace, only the field runtime.
  • The ESP32-C6 run produced local RF, but we did not record its PHY library setup completely.
We would repeat the test as soon as coverage reaches Europe, with a Live account, a dipole on the U.FL path, a Pluto decode before the roof, and a current probe.

Try it

Before anything else: confirm with Hubble that your organisation has Hubble Live with Satellite (Sandbox does not include it) and that the service covers your test coordinates. When we checked on 5 October 2026, the coverage region was North America.
1. Workspace (PowerShell, Python 3.12, Git, 7-Zip, SEGGER J-Link installed):
2. Prove that programming works:
3. Register the device in the Dashboard with DEVICE UPTIME and AES-256-CTR. Save the Base64 key right away: it is shown only once, and the UUID shown later is the device ID, not the key.
4. Put the key in a file instead of on the command line. Create samples/zephyr/sat-continuous/local-device.conf and add it to .git/info/exclude:
5. Build, flash and check the boot log for E:256/CS:DU/…/N:S:
6. Decrypt locally before you go up on the roof (ADALM-PLUTO, Docker):
7. Payload: the size must be exactly 0, 4, 9 or 13 bytes. For example:
Troubleshooting by symptom
Symptom
Cause in our case
Fix
pip builds grpcio-tools/hidapi from source and fails
Python 3.14
Python 3.12 venv
CMake is not installed
Not in the venv
pip install cmake ninja
setup.cmd can't find 7z
PATH
Add the 7-Zip directory
Unknown HUBBLE_* Kconfig symbols
SDK not in the west manifest
Use the SDK as the manifest
malformed string literal … Assignment ignored
PowerShell quoting
EXTRA_CONF_FILE
RAIL library missing at link time
Blob not fetched
west blobs fetch hal_silabs
Boot warns about a placeholder key
Key empty
Supply the key, pristine build
RF visible, Dashboard empty
Region, account type, key or counter mismatch
Check region and account first, then decode locally
ESP32-C6: use samples/esp-idf/sat-continuous, run idf.py set-target esp32c6, then menuconfig, then build flash monitor. Here the key option is called CONFIG_HUBBLE_DEVICE_KEY, not CONFIG_SAMPLE_HUBBLE_KEY. Do not overwrite sdkconfig.defaults with the key line alone, because that deletes the satellite and counter settings. The PHY library requirements depend on the ESP-IDF version; see the ESP-IDF integration guide. The ESP32-S3 is not a supported satellite target.

Updated: 5 October 2026. The documentation was rechecked after Hubble's reply; the observations above are from August–September 2026.
Disclosure: all hardware was our own, and Hubble Network, Silicon Labs and Espressif had no involvement in the test. An AI chat assistant was used during bring-up (see "Myths"), and this article was prepared with the help of Claude.
Share this article

Want the next drop?

Join the list for fresh field notes, tools, and agent-ready workflows — no spam, unsubscribe anytime.