@bradtech/sensor-lorawan 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HOWTO.md ADDED
@@ -0,0 +1,99 @@
1
+ # HOWTO: Using `@bradtech/sensor-lorawan`
2
+
3
+ This guide explains how to process ChirpStack LoRaWAN uplinks into calibrated DataPoints with `LoRaWanPipeline`.
4
+
5
+ ---
6
+
7
+ ## 🏛️ Architecture: Decoupling Radio Frame from Agronomic Soil Models
8
+
9
+ > [!IMPORTANT]
10
+ > **Payload Agnosticism**: A LoRaWAN uplink packet is strictly hardware and radio-centric (devEUI, FPort, frame counter, RSSI, and raw IEEE 754 Float32 sensor readings). A physical probe **never** knows what parcel or soil type it is installed in.
11
+ >
12
+ > **Backoffice Agronomic Context**: The Backoffice database assigns a physical probe (`devEUI`) to an agricultural parcel (`Plot`), and stores the plot's soil profile (e.g. `clay`, `sand`, `loam`) along with optional laboratory calibration models ($y = a \cdot x + b$).
13
+ >
14
+ > When ingesting an uplink, the Telemetry Worker retrieves the plot's `AgronomicPlotContext` from the database/cache and injects it into `LoRaWanPipeline.process(uplink, agronomicContext)`.
15
+
16
+ ---
17
+
18
+ ## 1. Processing a ChirpStack Uplink Message into DataPoints
19
+
20
+ ```typescript
21
+ import {
22
+ LoRaWanPipeline,
23
+ type PipelineUplinkInput,
24
+ type AgronomicPlotContext,
25
+ } from '@bradtech/sensor-lorawan'
26
+
27
+ // 1. Raw JSON uplink payload received via MQTT from ChirpStack
28
+ const uplinkMessage: PipelineUplinkInput = {
29
+ deviceInfo: {
30
+ deviceName: 'b25s004',
31
+ devEui: '8c1f640000000004',
32
+ },
33
+ fPort: 12, // Soil Moisture @ 10cm depth (Raw Capacitance / Dielectric value)
34
+ fCnt: 142,
35
+ data: 'AAAAQEF', // Base64 encoded Float32 LE (e.g. 25.4)
36
+ rxInfo: [
37
+ {
38
+ gatewayId: '0016c001f1122334',
39
+ rssi: -82,
40
+ snr: 9.2,
41
+ },
42
+ ],
43
+ txInfo: {
44
+ frequency: 868100000,
45
+ dataRate: 0, // SF12 / 125kHz
46
+ },
47
+ publishedAt: '2026-08-30T18:00:00Z',
48
+ }
49
+
50
+ // 2. Agronomic Plot Context resolved from Backoffice / MDM database
51
+ const agronomicContext: AgronomicPlotContext = {
52
+ plot: 'plots/parcelle-saint-emilion-01',
53
+ company: 'companies/chateau-alpha',
54
+ soilTexture: 'clay',
55
+ soilLinearRegression: {
56
+ slope: 1.05,
57
+ intercept: -0.8,
58
+ modelLabel: 'Lab-Pedo-2026',
59
+ },
60
+ }
61
+
62
+ // 3. Ingest and transform
63
+ const dataPoints = LoRaWanPipeline.process(uplinkMessage, agronomicContext)
64
+
65
+ for (const dp of dataPoints) {
66
+ console.log(`[${dp.kind.toUpperCase()}] ${dp.metric}: ${dp.value} ${dp.unit}`)
67
+ console.log(` Device: ${dp.device}, Plot: ${dp.plot}`)
68
+ console.log(` Metadata:`, dp.metadata)
69
+ }
70
+ // Outputs:
71
+ // [MEASURED] okf:radio/lorawan/rssi: -82 dBm
72
+ // [MEASURED] okf:radio/lorawan/snr: 9.2 dB
73
+ // [MEASURED] okf:soil/moisture/10cm: 25.87 % (sensorSource: 'Brad soil sensor', converterClass: 'SoilMoistureConverter', soilTexture: 'clay')
74
+ // [COMPUTED] okf:soil/potential/pf/10cm: 2.82 pF (Derived water retention index based on plot soil texture)
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 2. Using Pre-Instantiated Default Adapters Directly
80
+
81
+ ```typescript
82
+ import { defaultSensorAdapters, registerDefaultSensorAdapters } from '@bradtech/sensor-lorawan'
83
+ import { Sensor } from '@bradtech/sensor'
84
+
85
+ // 1. Direct access without new allocations
86
+ const airConverter = defaultSensorAdapters.canopyAir
87
+ const tempResults = airConverter.convert({ temperatureCelsius: 21.0, relativeHumidityPercent: 70 })
88
+
89
+ // 2. Or register all domain adapters into the global Quatrain Sensor facade in one line
90
+ registerDefaultSensorAdapters()
91
+
92
+ const soilAdapter = Sensor.getAdapter('soilMoisture')
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 📄 License & Copyright
98
+
99
+ GNU AGPL-v3 — Copyright (C) 2026 Olivier Lépine <olivier@lepine.fr>