Skip to content

Data Formats

This page provides a complete technical specification of all data formats used in the Multiflexmeter firmware.

The current firmware operates as a sensor passthrough:

  1. Sends measurement trigger command to sensor module at I²C address 0x36
  2. Waits 10 seconds for measurement completion
  3. Reads raw sensor data via SMBus Block Read (up to 32 bytes)
  4. Transmits raw sensor data without firmware-level interpretation via LoRaWAN FPort 1

Passthrough Architecture: The firmware does not decode or interpret sensor data. The data format depends entirely on the sensor module connected at address 0x36. All data interpretation happens at the application layer (TTN decoder + backend).

Future firmware will implement structured data handling:

struct tx_pkt_t {
uint8_t flags; // Bit 0: spinning, Bit 1: pumping
uint32_t revolutions; // Total revolution counter
};

This structured format will standardize sensor data transmission and enable firmware-level validation.

The flags byte encodes the poldermill operational state:

BitNameDescription
0spinningPoldermill rotor is rotating (wind-powered)
1pumpingWater pumping mechanism is active

Operational Modes:

  • spinning=1, pumping=0: Wind-powered rotation only (no pumping load)
    • Revolutions counted normally
  • spinning=1, pumping=1: Wind-powered pumping
    • Revolutions counted (may be slower due to pumping load)
  • spinning=0, pumping=1: Electric motor pumping
    • No wind-driven rotation
    • Revolutions should be 0 (no wind power)
  • spinning=0, pumping=0: Idle poldermill
    • Revolutions should be 0

The device stores its configuration in EEPROM starting at address 0x00.

Offset Size Field Endianness
------ ---- ----- ----------
0x00 4 MAGIC ("MFM\0") N/A
0x04 1 HW_VERSION.MSB Big-endian
0x05 1 HW_VERSION.LSB Big-endian
0x06 8 APP_EUI Little-endian
0x0E 8 DEV_EUI Little-endian
0x16 16 APP_KEY Big-endian
0x26 2 MEASUREMENT_INTERVAL Little-endian
0x28 1 USE_TTN_FAIR_USE_POLICY N/A
------
Total: 41 bytes
FieldTypeRangeDescription
MAGICchar[4]“MFM\0”Magic bytes for validation (0x4D 0x46 0x4D 0x00)
HW_VERSIONuint16_t0x0000-0xFFFFHardware version (encoded, see below)
APP_EUIuint8_t[8]-LoRaWAN Application EUI
DEV_EUIuint8_t[8]-LoRaWAN Device EUI
APP_KEYuint8_t[16]-LoRaWAN Application Key (AES-128)
MEASUREMENT_INTERVALuint16_t20-4270Measurement interval in seconds
USE_TTN_FAIR_USE_POLICYuint8_t0-1Fair use policy (0=disabled, 1=enabled)

Both firmware and hardware versions use a 16-bit encoding scheme:

┌──────┬────────────┬────────────┬────────────┐
│ Bit │ 15 │ 14-10 │ 9-5 │ 4-0 │
├──────┼────────────┼────────────┼────────────┼────────────┤
│ Field│ Proto │ Major │ Minor │ Patch │
│ Bits │ 1 bit │ 5 bits │ 5 bits │ 5 bits │
│ Range│ 0-1 │ 0-31 │ 0-31 │ 0-31 │
└──────┴────────────┴────────────┴────────────┴────────────┘
Proto: 0 = development, 1 = release

Example: Version 3.7.0 (release)

  • Proto: 1, Major: 3, Minor: 7, Patch: 0
  • Binary: 1 00011 00111 00000
  • Encoded: 0x8E00

Raw sensor measurement data transmitted after each measurement cycle.

Properties:

  • FPort: 1
  • Maximum Size: 32 bytes
  • Frequency: Based on MEASUREMENT_INTERVAL (20-4270 seconds)
  • Content: Raw sensor module response (passthrough)

Measurement Flow:

  1. Trigger: Send CMD_PERFORM (0x10) to sensor at address 0x36
  2. Wait: 10 seconds for measurement completion
  3. Read: Send CMD_READ (0x11) to sensor, receive data via SMBus Block Read
  4. Transmit: Send raw sensor response via LoRaWAN FPort 1 (no interpretation)

Data Format:

The payload contains unmodified bytes from the sensor module. The firmware does not validate, decode, or structure this data.

┌──────────────────────────────────────────┐
│ Raw sensor module data (0-32 bytes) │
│ Format determined by sensor module │
└──────────────────────────────────────────┘

Poldermill Sensor Module Format (Type 0x01)

Section titled “Poldermill Sensor Module Format (Type 0x01)”

According to the firmware specification (readme.md:64-66), all sensor modules follow this format:

<Module Address> <Module Type> <Module Data Blob>

For the poldermill monitoring sensor at I²C address 0x36, the complete payload is 7 bytes:

┌────────┬────────┬────────┬──────────────────────────┐
│ Byte 0 │ Byte 1 │ Byte 2 │ Bytes 3-6 │
├────────┼────────┼────────┼──────────────────────────┤
│ 0x36 │ 0x01 │ Flags │ Revolutions (uint32 BE) │
└────────┴────────┴────────┴──────────────────────────┘
FieldByte(s)TypeDescription
Module Address0uint8_tI²C address (0x36)
Module Type1uint8_tSensor type (0x01 = poldermill)
Flags2uint8_tOperational status (spinning, pumping)
Revolutions3-6uint32_tRevolution count for this period (big-endian)

Flags Byte:

  • Bit 0: 1 = Spinning, 0 = Idle
  • Bit 1: 1 = Pumping, 0 = Not pumping
  • Bits 2-7: Reserved (set to 0)

Example Payload: 36 01 03 00 00 00 32

Decoded:

  • Module Address: 0x36 (poldermill sensor)
  • Module Type: 0x01 (poldermill)
  • Flags: 0x03 (0b00000011 = spinning + pumping)
  • Revolutions: 0x00000032 (50 revolutions this period)

Device version information sent after OTAA join or device reset.

Properties:

  • FPort: 2
  • Size: 5 bytes (fixed)
  • Sent: After join, or on reset

Message Format:

┌────────┬─────────┬─────────┬─────────┬─────────┐
│ Byte 0 │ Byte 1 │ Byte 2 │ Byte 3 │ Byte 4 │
├────────┼─────────┼─────────┼─────────┼─────────┤
│ 0x10 │ FW_MSB │ FW_LSB │ HW_MSB │ HW_LSB │
└────────┴─────────┴─────────┴─────────┴─────────┘
FieldByte(s)TypeEndiannessDescription
Command0uint8_tN/AVersion indicator (always 0x10)
FW_VERSION1-2uint16_tBig-endianFirmware version (encoded)
HW_VERSION3-4uint16_tBig-endianHardware version (encoded)

Example Payload: 10 8E 00 84 40

Decoded:

  • Command: 0x10
  • Firmware: 0x8E00 = v3.7.0 (release)
  • Hardware: 0x8440 = v1.2.0 (release)

All downlink commands can be sent on any FPort. The first byte determines the command type.

Update the device measurement interval.

Format:

┌────────┬──────────┬──────────┐
│ Byte 0 │ Byte 1 │ Byte 2 │
├────────┼──────────┼──────────┤
│ 0x10 │ Interval │ Interval │
│ │ MSB │ LSB │
└────────┴──────────┴──────────┘
FieldByte(s)TypeEndiannessRangeDescription
Command0uint8_tN/A0x10Command identifier
Interval1-2uint16_tBig-endian20-4270New interval in seconds

Behavior:

  • Interval is clamped to valid range (20-4270 seconds)
  • New value is saved to EEPROM
  • Next measurement is rescheduled immediately

Example: Set interval to 1800 seconds (30 minutes)

Downlink: 10 07 08

Forward a command to the sensor module via SMBus.

Format:

┌────────┬────────────┬────────────┬────────────────┐
│ Byte 0 │ Byte 1 │ Byte 2 │ Bytes 3-N │
├────────┼────────────┼────────────┼────────────────┤
│ 0x11 │ Module │ Module │ Command │
│ │ Address │ Command │ Arguments │
└────────┴────────────┴────────────┴────────────────┘
FieldByte(s)TypeDescription
Command0uint8_tCommand identifier (0x11)
Module Address1uint8_tI2C/SMBus address (7-bit)
Module Command2uint8_tCommand byte for sensor
Arguments3-Nuint8_t[]Optional parameters (0-29 bytes)

SMBus Transaction:

[START][ADDR+W][CMD][LENGTH][DATA...][STOP]

Example: Send command 0x20 with arguments [0x01, 0xFF] to module at 0x36

Downlink: 11 36 20 01 FF

Results in SMBus transaction:

[START][0x36+W][0x20][0x02][0x01][0xFF][STOP]

Force the device to reset and rejoin the LoRaWAN network.

Format:

┌────────┬────────┐
│ Byte 0 │ Byte 1 │
├────────┼────────┤
│ 0xDE │ 0xAD │
└────────┴────────┘
FieldByteValueDescription
Command00xDEFirst magic byte
Validation10xADSecond magic byte (required)

Behavior:

  1. Validates second byte is exactly 0xAD
  2. Schedules reset after 5 seconds
  3. Watchdog timer triggers MCU reset
  4. Device reboots and performs OTAA rejoin

Example:

Downlink: DE AD

The device communicates with sensor modules using SMBus (I2C) protocol.

ParameterValue
ProtocolSMBus/I2C (TWI)
Clock Speed80 kHz
Pull-upsExternal 4.7kΩ required on SDA/SCL
Default Address0x36 (7-bit)
CommandValueProtocolDescription
CMD_PERFORM0x10SMBus Send ByteTrigger sensor measurement
CMD_READ0x11SMBus Block ReadRead measurement results

SMBus Transaction:

[START][0x36+W][0x10][STOP]

Timing: Wait 10 seconds before reading results

SMBus Transaction:

[START][0x36+W][0x11][RESTART][0x36+R][LENGTH][DATA...][STOP]

Response Format:

  1. First byte: Data length (N, max 32)
  2. Next N bytes: Measurement data
  3. Data format depends on sensor module implementation
ParameterValueUnitDescription
MIN_INTERVAL20secondsMinimum measurement interval
MAX_INTERVAL4270secondsMaximum measurement interval (71 minutes)
PERFORM_DELAY10secondsWait time after triggering measurement
PING_DELAY45secondsDelay after version ping before first measurement

When enabled, the device enforces The Things Network fair use policy (maximum 30 seconds airtime per day).

Calculation:

uint32_t airtime_ms = calculateAirtime(spreading_factor, payload_size);
uint32_t tx_per_day = 30000 / airtime_ms;
uint16_t min_interval = 86400 / (tx_per_day + 1);

Typical Minimum Intervals:

  • SF7 (fastest): approximately 173 seconds (3 minutes)
  • SF12 (slowest): approximately 5760 seconds (96 minutes)

If the configured interval is less than the calculated minimum, the minimum is enforced.

BufferSizeDescription
dataBuf32 bytesMain data buffer for sensor readings
LMIC Payload32 bytesMaximum LoRaWAN payload size
SMBus Block32 bytesMaximum SMBus block read size
FieldBitsRangeDescription
Proto10-10=development, 1=release
Major50-31Major version number
Minor50-31Minor version number
Patch50-31Patch version number

For fair use policy calculations:

ParameterValueDescription
Average Payload12 bytesAssumed sensor data size
MAC Overhead12 bytesLoRaWAN frame overhead
Total Frame24 bytesUsed for airtime calculation

The firmware uses the following error codes for SMBus operations:

typedef enum {
ERR_NONE, // 0: Success
ERR_SMBUS_SLAVE_NACK, // 1: Slave did not acknowledge
ERR_SMBUS_ARB_LOST, // 2: Arbitration lost
ERR_SMBUS_NO_ALERT, // 3: No alert pending
ERR_SMBUS_ERR, // 4: General communication error
} error_t;

The firmware operates as a sensor passthrough:

  • No data interpretation or validation
  • Direct transmission of sensor module responses
  • Flexible but requires application-level decoding

The firmware will implement structured data handling:

  • Defined tx_pkt_t structure for standardized data
  • Firmware-level validation and encoding
  • Standardized payload format across all devices
  • Support for poldermill status monitoring (spinning, pumping, revolutions)