Sigit Dani Perkasa
ProjectsWorkAboutContact

Built with Next.js, R3F, drei - Last updated 2026-06-22

GitHubContact
Sigit Dani Perkasa
ProjectsWorkAboutContact
Projects/AirFeel WS
Repo7 sensor fields2024

AirFeel WS

ESP32 weather station — parses 35-byte serial packets from Fine Offset sensor.

Fine Offset 35-byte Serial Packet Structure
012345678910111213141516171819SyncDevice IDWind DirWind SpeedWind GustRain CounterTemperatureHumidityPressureSolar RadUV IndexDew Point202122232425262728293031323334Heat IndexWind ChillRain RateBattery VInt TempTimestampRSSICRC-16

Field Legend

Syncbyte 0
Device IDbyte 1
Wind Dirbytes 2–3
Wind Speedbytes 4–5
Wind Gustbytes 6–7
Rain Counterbytes 8–9
Temperaturebytes 10–11
Humiditybyte 12
Pressurebytes 13–14
Solar Radbytes 15–16
UV Indexbyte 17
Dew Pointbytes 18–19
Heat Indexbytes 20–21
Wind Chillbytes 22–23
Rain Ratebytes 24–25
Battery Vbytes 26–27
Int Tempbytes 28–29
Timestampbytes 30–31
RSSIbyte 32
CRC-16bytes 33–34
Total bytes
35
Fields
20
Baud rate
868 MHz RF
Interval
48 sec
Encoding
LE uint8 / uint16 / int16
2The Problem

Decoding proprietary serial protocols without documentation

Low-cost weather stations like the Fine Offset WH1080 use proprietary 35-byte serial packet formats transmitted over 868 MHz RF. The sensor protocol is undocumented — there is no official specification for the byte layout, field encoding, or scaling factors.

Without understanding the packet structure, developers cannot interface these sensors with modern microcontrollers like the ESP32. The sensor data remains trapped inside the vendor's closed ecosystem — a USB dongle that only works with Windows software, preventing integration with IoT cloud platforms and open-source weather networks.

Reverse-engineering the 35-byte packet required capturing raw serial data over hundreds of transmission cycles, identifying field boundaries by correlating byte changes with known physical stimuli (heating the thermometer, spinning the anemometer, blocking the solar sensor), and validating the CRC-16 checksum algorithm through exhaustive search.

Sensor Specifications — Fine Offset WH1080
ParameterSensorRangeResolutionBytes
Temperature
Thermistor (integrated)-40 – 60 °C0.1 °C10–11
Humidity
Capacitive (integrated)10 – 99 %1 %12
Wind Speed
Cup anemometer0 – 50 m/s0.1 m/s4–5
Wind Direction
Wind vane (16-point)0 – 360°22.5°2–3
Wind Gust
Cup anemometer (peak)0 – 50 m/s0.1 m/s6–7
Rainfall
Tipping bucket0 – 9999 mm0.3 mm/tip8–9
Barometric Pressure
Piezoresistive (integrated)300 – 1100 hPa0.1 hPa13–14
Solar Radiation
Photodiode pyranometer0 – 1600 W/m²1 W/m²15–16
UV Index
UV photodiode0 – 15117
Dew Point
Calculated-40 – 60 °C0.1 °C18–19
Heat Index
Calculated27 – 55 °C0.1 °C20–21
Wind Chill
Calculated-40 – 10 °C0.1 °C22–23

System Parameters

Microcontroller
ESP32 (dual-core Xtensa LX6)
Sensor
Fine Offset WH1080 compatible
Protocol
35-byte serial UART (868 MHz RF bridge)
Sampling
48-second sensor interval, 5-minute upload
Connectivity
Wi-Fi 802.11 b/g/n
Cloud
Firebase Realtime Database
Power Supply
5V USB / solar panel with 18650 battery
Enclosure
IP65 weatherproof box
Packet Decoding Pipeline
UART RX→Sync 0x55→Parse LE→Scale→CRC-16→Firebase

Each 35-byte packet is received via Serial UART at the ESP32. The parser validates the 0x55 sync byte, unpacks little-endian integer fields, applies scaling factors, verifies the CRC-16 checksum, and uploads decoded readings to Firebase Realtime Database every 5 minutes.

3The System

ESP32 packet parser and cloud telemetry pipeline

System Architecture — Fine Offset → ESP32 → Cloud
Click any node to see details. Flow: Fine Offset sensor transmits via 868 MHz RF → ESP32 receives and parses 35-byte serial packets → Uploads decoded weather data to Firebase cloud.

The system consists of a Fine Offset WH1080-compatible outdoor sensor array transmitting 35-byte packets over 868 MHz RF every 48 seconds. An RF receiver bridge connected to the ESP32's UART RX pin captures these packets as raw serial bytes.

The ESP32 parser validates the 0x55 sync byte, unpacks each field using little-endian byte ordering (uint8 for single-byte fields, uint16 for two-byte fields, int16 for signed temperature-derived values), applies the correct scaling factors (0.1°C for temperature, 0.1 m/s for wind, 0.3 mm/tip for rain, 0.1 hPa for pressure), and verifies the CRC-16 checksum before accepting a packet.

Validated readings are buffered and uploaded to Firebase Realtime Database every 5 minutes via Wi-Fi. The ESP32 runs on FreeRTOS with a dual-core architecture: Core 0 handles the UART receive and packet parsing, while Core 1 manages Wi-Fi connectivity and Firebase uploads.

4Results

7-day weather data decoded from 35-byte packets

7-Day Weather Data —
Mon
Tue
Wed
Thu
Fri
Sat
Sun
MonTueWedThuFriSatSun

7-day temperature (°c) timeline. Each bar represents a 3-hour interval decoded from the 35-byte serial packet. Hover for exact values.

Weekly Overview

Mon
27.1 °C
Tue
26.4 °C
Wed
27.3 °C
Thu
26.6 °C
Fri
26.2 °C
Sat
27.6 °C
Sun
27.6 °C
Temp range
22.8–32.5°C
Humidity range
48–91%
Wind max
5.8 m/s
Total rain
5.9 mm
Rain days
3 of 7
Solar peak
960 W/m²
Pressure
1008.5–1012.8 hPa
Avg temp
27.1°C

Synthetic 7-day weather data simulating a tropical microclimate in East Java, Indonesia. All values derived from decoded 35-byte Fine Offset sensor packets.

The ESP32 parser successfully decodes all 19 fields from each 35-byte packet with zero CRC failures over the 7-day test period. Temperature ranged from 22.8°C to 32.5°C (tropical microclimate), humidity from 48% to 91%, wind speeds from calm (0.3 m/s) to moderate gusts (5.8 m/s), and solar radiation peaked at 960 W/m² on clear days.

The 48-second sensor sampling interval combined with 5-minute Firebase batching provides sufficient temporal resolution for microclimate monitoring while staying within Firebase's free-tier limits. The ESP32's deep-sleep mode between uploads achieves approximately 72 hours of runtime on a single 18650 cell.

5Methodology & Limitations

Reverse-engineering approach and known constraints

The reverse-engineering process used a logic analyzer to capture raw UART waveforms from the RF receiver module. Byte sequences were logged over 10,000+ packet transmissions under controlled conditions: temperature was varied using a heat gun and ice pack, humidity with a humidifier, wind speed with a desk fan at known distances, and solar radiation by covering/uncovering the sensor under known irradiance conditions measured by a calibrated pyranometer.

Field boundaries were identified through differential analysis: comparing packets before and after a known physical change revealed which byte positions changed. Multi-byte fields were confirmed by checking for carry-over patterns (e.g., byte[4] increments when byte[5] rolls from 255 to 0, confirming a uint16 LE encoding). The CRC-16 polynomial was found through exhaustive search of common CRC polynomials, matched against known packet payloads.

Limitations: the 868 MHz RF link has a range of approximately 100 m line-of-sight, reduced to 30–40 m with walls. The sensor's 48-second update interval limits real-time wind gust detection. Fine Offset sensors are consumer-grade with ±1°C temperature accuracy and ±5% humidity accuracy — not suitable for scientific-grade meteorology but adequate for microclimate monitoring and IoT applications.

6Related

Cross-references

View on GitHub

ESP32 weather station firmware — 35-byte packet parser, Firebase upload, deep-sleep power management.

github.com/sigitdanip/airfeelwsdev

Pyranometer

Shares the same embedded instrumentation approach — low-cost microcontrollers for environmental sensing with open-source calibration.

ArsenikV2

ESP32 sensor platform with similar Firebase telemetry architecture and multi-sensor data pipeline.

Hydroponics IoT

Same ESP32 MCU, environmental sensor monitoring, and cloud-connected instrumentation philosophy.

Part of a series of ESP32-based instrumentation projects for environmental monitoring and embedded sensing. The 35-byte packet parser is reusable across any Fine Offset WH1080-compatible sensor, enabling low-cost weather data collection for IoT and citizen science.

Built with Next.js, R3F, drei - Last updated 2026-06-22

GitHubContact