@pamoja/lora 0.1.15 → 0.1.16

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.
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Ergonomic facade over the generated LoRa binding.
3
+ *
4
+ * LoRa buys kilometres of range on license-free bands at tiny power, and the
5
+ * price is time: a transmission occupies the channel for a duration the radio
6
+ * settings fix, and the regional rules cap how much of the time a node may
7
+ * transmit. This is the arithmetic that keeps a node inside that budget, with no
8
+ * radio and no floating point in the answer.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import { type LoraLink } from '@pamoja/native';
13
+ import { LoraChannelPlan, LoraPlanBuilder, type LoraBeacon, type LoraChannelBlock, type LoraChannelSet as NativeLoraChannelSet, type LoraDataRate, type LoraDirection as NativeLoraDirection, type LoraMaxPayload, type LoraModulation as NativeLoraModulation, type LoraPayloadTable as NativeLoraPayloadTable, type LoraPlanInfo, type LoraRegion as NativeLoraRegion, type LoraRx2, type LoraSubBand } from '@pamoja/native';
14
+ export { type LoraLink };
15
+ export { LoraChannelPlan, LoraPlanBuilder, type LoraBeacon, type LoraChannelBlock, type LoraDataRate, type LoraMaxPayload, type LoraPlanInfo, type LoraRx2, type LoraSubBand, };
16
+ /**
17
+ * A band with a published channel plan.
18
+ *
19
+ * Provided as a runtime object, as the generated string enum is erased at
20
+ * compile time and so has no value a JavaScript caller can reach. Members carry
21
+ * the generated enum's type as well, so they pass straight into the native
22
+ * methods.
23
+ */
24
+ export declare const LoraRegion: {
25
+ /** Europe, 863-870 MHz. */
26
+ readonly Eu868: NativeLoraRegion;
27
+ /** North America, 902-928 MHz. */
28
+ readonly Us915: NativeLoraRegion;
29
+ /** Europe, 433 MHz. */
30
+ readonly Eu433: NativeLoraRegion;
31
+ /** Australia, 915-928 MHz. */
32
+ readonly Au915: NativeLoraRegion;
33
+ /** China, 470-510 MHz. */
34
+ readonly Cn470: NativeLoraRegion;
35
+ /** Asia, 923 MHz. */
36
+ readonly As923: NativeLoraRegion;
37
+ /** South Korea, 920-923 MHz. */
38
+ readonly Kr920: NativeLoraRegion;
39
+ /** India, 865-867 MHz. */
40
+ readonly In865: NativeLoraRegion;
41
+ /** Russia, 864-870 MHz. */
42
+ readonly Ru864: NativeLoraRegion;
43
+ };
44
+ /** One of the {@link LoraRegion} values. */
45
+ export type LoraRegion = NativeLoraRegion;
46
+ /** Which direction a data-rate table describes. */
47
+ export declare const LoraDirection: {
48
+ /** From the device to the network. */
49
+ readonly Uplink: NativeLoraDirection;
50
+ /** From the network to the device. */
51
+ readonly Downlink: NativeLoraDirection;
52
+ };
53
+ /** One of the {@link LoraDirection} values. */
54
+ export type LoraDirection = NativeLoraDirection;
55
+ /** Which of a plan's payload tables to read. */
56
+ export declare const LoraPayloadTable: {
57
+ /** Uplink, for a device that may sit behind a repeater. */
58
+ readonly UplinkRepeater: NativeLoraPayloadTable;
59
+ /** Uplink, for a device that will not. */
60
+ readonly UplinkDirect: NativeLoraPayloadTable;
61
+ /** Downlink, for a device that may sit behind a repeater. */
62
+ readonly DownlinkRepeater: NativeLoraPayloadTable;
63
+ /** Downlink, for a device that will not. */
64
+ readonly DownlinkDirect: NativeLoraPayloadTable;
65
+ /** The limits that apply under a dwell-time limit. */
66
+ readonly DwellLimited: NativeLoraPayloadTable;
67
+ };
68
+ /** One of the {@link LoraPayloadTable} values. */
69
+ export type LoraPayloadTable = NativeLoraPayloadTable;
70
+ /** Which channels of a plan to read. */
71
+ export declare const LoraChannelSet: {
72
+ /** The channels a device must use to send a join request. */
73
+ readonly Join: NativeLoraChannelSet;
74
+ /** The channels a device starts with before a network adds any. */
75
+ readonly Default: NativeLoraChannelSet;
76
+ };
77
+ /** One of the {@link LoraChannelSet} values. */
78
+ export type LoraChannelSet = NativeLoraChannelSet;
79
+ /** How a data rate is carried on the air. */
80
+ export declare const LoraModulation: {
81
+ /** LoRa modulation, described by a spreading factor and bandwidth. */
82
+ readonly Lora: NativeLoraModulation;
83
+ /** Frequency-shift keying, described by its bitrate alone. */
84
+ readonly Fsk: NativeLoraModulation;
85
+ /** Long-range frequency-hopping spread spectrum. */
86
+ readonly LrFhss: NativeLoraModulation;
87
+ /** A data-rate number the region reserves, which carries nothing. */
88
+ readonly Reserved: NativeLoraModulation;
89
+ };
90
+ /** One of the {@link LoraModulation} values. */
91
+ export type LoraModulation = NativeLoraModulation;
92
+ /**
93
+ * Returns the settings for a spreading factor and bandwidth, with LoRa defaults.
94
+ *
95
+ * The defaults are coding rate 4/5, an eight-symbol preamble, an explicit header,
96
+ * and CRC on, which is a typical uplink. Adjust the returned object to change any
97
+ * of them.
98
+ *
99
+ * @param spreadingFactor - The spreading factor, clamped to 5 (fastest) to 12
100
+ * (longest range).
101
+ * @param bandwidthHz - The channel bandwidth in hertz, such as 125000.
102
+ * @returns The link settings.
103
+ */
104
+ export declare function link(spreadingFactor: number, bandwidthHz: number): LoraLink;
105
+ /**
106
+ * Returns the duration of one symbol on a link, in microseconds.
107
+ *
108
+ * @param settings - The link settings.
109
+ * @returns The symbol time in microseconds.
110
+ */
111
+ export declare function symbolTimeUs(settings: LoraLink): number;
112
+ /**
113
+ * Returns the time on air of a payload, in microseconds.
114
+ *
115
+ * This is the channel occupancy a transmission costs: how long the radio holds
116
+ * the air, which sets both the duty-cycle budget and most of the energy the
117
+ * transmission spends.
118
+ *
119
+ * @param settings - The link settings.
120
+ * @param payloadLength - The payload length in bytes.
121
+ * @returns The time on air in microseconds.
122
+ */
123
+ export declare function airtimeUs(settings: LoraLink, payloadLength: number): number;
124
+ /**
125
+ * Returns the minimum silence after a transmission to honor a duty-cycle limit.
126
+ *
127
+ * @param settings - The link settings.
128
+ * @param payloadLength - The payload length in bytes.
129
+ * @param dutyCyclePermille - The limit in parts per thousand, so 10 is 1%.
130
+ * @returns The required off time in microseconds, or `null` when the limit is
131
+ * zero, which forbids transmitting at all.
132
+ */
133
+ export declare function minOffTimeUs(settings: LoraLink, payloadLength: number, dutyCyclePermille: number): number | null;
134
+ /**
135
+ * Returns how many transmissions of a payload fit in an hour under a duty-cycle
136
+ * limit.
137
+ *
138
+ * The airtime plus the silence it forces is what one transmission really costs,
139
+ * so this is the message budget a deployment plans against.
140
+ *
141
+ * @param settings - The link settings.
142
+ * @param payloadLength - The payload length in bytes.
143
+ * @param dutyCyclePermille - The limit in parts per thousand, so 10 is 1%.
144
+ * @returns The number of whole transmissions per hour, or 0 when the limit
145
+ * forbids transmitting.
146
+ */
147
+ export declare function messagesPerHour(settings: LoraLink, payloadLength: number, dutyCyclePermille: number): number;
148
+ /**
149
+ * Returns the published channel plan for a region.
150
+ *
151
+ * A channel plan is what a regulator and the LoRa Alliance publish about one
152
+ * band: which data rates exist, what each carries, how much of the time a node
153
+ * may hold a frequency, and where it listens for a downlink. The plan reports
154
+ * those facts and costs a transmission out against them; it never refuses one,
155
+ * because a deployment may hold licensed spectrum or be working under emergency
156
+ * provisions and only the operator knows which.
157
+ *
158
+ * @param region - The band to describe.
159
+ * @returns The plan, which answers every question about that band.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * const plan = planFor(LoraRegion.Eu868)
164
+ * const link = plan.linkSettings(5)
165
+ * const permille = plan.dutyCyclePermille(868_100_000)
166
+ * ```
167
+ */
168
+ export declare function planFor(region: LoraRegion): LoraChannelPlan;
169
+ /**
170
+ * Returns how many transmissions of a payload fit in an hour at a data rate the
171
+ * region defines.
172
+ *
173
+ * This is the budget question a deployment actually asks: not what the radio can
174
+ * do, but how often it may speak on this band at this setting. The duty cycle of
175
+ * the frequency it transmits on decides the answer.
176
+ *
177
+ * @param plan - The channel plan to read.
178
+ * @param dataRate - The uplink data-rate number.
179
+ * @param payloadLength - The payload length in bytes.
180
+ * @param frequencyHz - The frequency the node transmits on.
181
+ * @returns The number of whole transmissions per hour, or `null` when the plan
182
+ * does not describe that data rate or frequency.
183
+ */
184
+ export declare function messagesPerHourAt(plan: LoraChannelPlan, dataRate: number, payloadLength: number, frequencyHz: number): number | null;
package/dist/index.js ADDED
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ /**
3
+ * Ergonomic facade over the generated LoRa binding.
4
+ *
5
+ * LoRa buys kilometres of range on license-free bands at tiny power, and the
6
+ * price is time: a transmission occupies the channel for a duration the radio
7
+ * settings fix, and the regional rules cap how much of the time a node may
8
+ * transmit. This is the arithmetic that keeps a node inside that budget, with no
9
+ * radio and no floating point in the answer.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.LoraModulation = exports.LoraChannelSet = exports.LoraPayloadTable = exports.LoraDirection = exports.LoraRegion = exports.LoraPlanBuilder = exports.LoraChannelPlan = void 0;
15
+ exports.link = link;
16
+ exports.symbolTimeUs = symbolTimeUs;
17
+ exports.airtimeUs = airtimeUs;
18
+ exports.minOffTimeUs = minOffTimeUs;
19
+ exports.messagesPerHour = messagesPerHour;
20
+ exports.planFor = planFor;
21
+ exports.messagesPerHourAt = messagesPerHourAt;
22
+ const native_1 = require("@pamoja/native");
23
+ const native_2 = require("@pamoja/native");
24
+ Object.defineProperty(exports, "LoraChannelPlan", { enumerable: true, get: function () { return native_2.LoraChannelPlan; } });
25
+ Object.defineProperty(exports, "LoraPlanBuilder", { enumerable: true, get: function () { return native_2.LoraPlanBuilder; } });
26
+ /**
27
+ * A band with a published channel plan.
28
+ *
29
+ * Provided as a runtime object, as the generated string enum is erased at
30
+ * compile time and so has no value a JavaScript caller can reach. Members carry
31
+ * the generated enum's type as well, so they pass straight into the native
32
+ * methods.
33
+ */
34
+ exports.LoraRegion = {
35
+ /** Europe, 863-870 MHz. */
36
+ Eu868: 'Eu868',
37
+ /** North America, 902-928 MHz. */
38
+ Us915: 'Us915',
39
+ /** Europe, 433 MHz. */
40
+ Eu433: 'Eu433',
41
+ /** Australia, 915-928 MHz. */
42
+ Au915: 'Au915',
43
+ /** China, 470-510 MHz. */
44
+ Cn470: 'Cn470',
45
+ /** Asia, 923 MHz. */
46
+ As923: 'As923',
47
+ /** South Korea, 920-923 MHz. */
48
+ Kr920: 'Kr920',
49
+ /** India, 865-867 MHz. */
50
+ In865: 'In865',
51
+ /** Russia, 864-870 MHz. */
52
+ Ru864: 'Ru864',
53
+ };
54
+ /** Which direction a data-rate table describes. */
55
+ exports.LoraDirection = {
56
+ /** From the device to the network. */
57
+ Uplink: 'Uplink',
58
+ /** From the network to the device. */
59
+ Downlink: 'Downlink',
60
+ };
61
+ /** Which of a plan's payload tables to read. */
62
+ exports.LoraPayloadTable = {
63
+ /** Uplink, for a device that may sit behind a repeater. */
64
+ UplinkRepeater: 'UplinkRepeater',
65
+ /** Uplink, for a device that will not. */
66
+ UplinkDirect: 'UplinkDirect',
67
+ /** Downlink, for a device that may sit behind a repeater. */
68
+ DownlinkRepeater: 'DownlinkRepeater',
69
+ /** Downlink, for a device that will not. */
70
+ DownlinkDirect: 'DownlinkDirect',
71
+ /** The limits that apply under a dwell-time limit. */
72
+ DwellLimited: 'DwellLimited',
73
+ };
74
+ /** Which channels of a plan to read. */
75
+ exports.LoraChannelSet = {
76
+ /** The channels a device must use to send a join request. */
77
+ Join: 'Join',
78
+ /** The channels a device starts with before a network adds any. */
79
+ Default: 'Default',
80
+ };
81
+ /** How a data rate is carried on the air. */
82
+ exports.LoraModulation = {
83
+ /** LoRa modulation, described by a spreading factor and bandwidth. */
84
+ Lora: 'Lora',
85
+ /** Frequency-shift keying, described by its bitrate alone. */
86
+ Fsk: 'Fsk',
87
+ /** Long-range frequency-hopping spread spectrum. */
88
+ LrFhss: 'LrFhss',
89
+ /** A data-rate number the region reserves, which carries nothing. */
90
+ Reserved: 'Reserved',
91
+ };
92
+ /**
93
+ * Returns the settings for a spreading factor and bandwidth, with LoRa defaults.
94
+ *
95
+ * The defaults are coding rate 4/5, an eight-symbol preamble, an explicit header,
96
+ * and CRC on, which is a typical uplink. Adjust the returned object to change any
97
+ * of them.
98
+ *
99
+ * @param spreadingFactor - The spreading factor, clamped to 5 (fastest) to 12
100
+ * (longest range).
101
+ * @param bandwidthHz - The channel bandwidth in hertz, such as 125000.
102
+ * @returns The link settings.
103
+ */
104
+ function link(spreadingFactor, bandwidthHz) {
105
+ return (0, native_1.loraLinkDefault)(spreadingFactor, bandwidthHz);
106
+ }
107
+ /**
108
+ * Returns the duration of one symbol on a link, in microseconds.
109
+ *
110
+ * @param settings - The link settings.
111
+ * @returns The symbol time in microseconds.
112
+ */
113
+ function symbolTimeUs(settings) {
114
+ return (0, native_1.loraSymbolTimeUs)(settings);
115
+ }
116
+ /**
117
+ * Returns the time on air of a payload, in microseconds.
118
+ *
119
+ * This is the channel occupancy a transmission costs: how long the radio holds
120
+ * the air, which sets both the duty-cycle budget and most of the energy the
121
+ * transmission spends.
122
+ *
123
+ * @param settings - The link settings.
124
+ * @param payloadLength - The payload length in bytes.
125
+ * @returns The time on air in microseconds.
126
+ */
127
+ function airtimeUs(settings, payloadLength) {
128
+ return (0, native_1.loraAirtimeUs)(settings, payloadLength);
129
+ }
130
+ /**
131
+ * Returns the minimum silence after a transmission to honor a duty-cycle limit.
132
+ *
133
+ * @param settings - The link settings.
134
+ * @param payloadLength - The payload length in bytes.
135
+ * @param dutyCyclePermille - The limit in parts per thousand, so 10 is 1%.
136
+ * @returns The required off time in microseconds, or `null` when the limit is
137
+ * zero, which forbids transmitting at all.
138
+ */
139
+ function minOffTimeUs(settings, payloadLength, dutyCyclePermille) {
140
+ return (0, native_1.loraMinOffTimeUs)(settings, payloadLength, dutyCyclePermille);
141
+ }
142
+ /**
143
+ * Returns how many transmissions of a payload fit in an hour under a duty-cycle
144
+ * limit.
145
+ *
146
+ * The airtime plus the silence it forces is what one transmission really costs,
147
+ * so this is the message budget a deployment plans against.
148
+ *
149
+ * @param settings - The link settings.
150
+ * @param payloadLength - The payload length in bytes.
151
+ * @param dutyCyclePermille - The limit in parts per thousand, so 10 is 1%.
152
+ * @returns The number of whole transmissions per hour, or 0 when the limit
153
+ * forbids transmitting.
154
+ */
155
+ function messagesPerHour(settings, payloadLength, dutyCyclePermille) {
156
+ const offTime = (0, native_1.loraMinOffTimeUs)(settings, payloadLength, dutyCyclePermille);
157
+ if (offTime === null) {
158
+ return 0;
159
+ }
160
+ return Math.floor(3600000000 / ((0, native_1.loraAirtimeUs)(settings, payloadLength) + offTime));
161
+ }
162
+ /**
163
+ * Returns the published channel plan for a region.
164
+ *
165
+ * A channel plan is what a regulator and the LoRa Alliance publish about one
166
+ * band: which data rates exist, what each carries, how much of the time a node
167
+ * may hold a frequency, and where it listens for a downlink. The plan reports
168
+ * those facts and costs a transmission out against them; it never refuses one,
169
+ * because a deployment may hold licensed spectrum or be working under emergency
170
+ * provisions and only the operator knows which.
171
+ *
172
+ * @param region - The band to describe.
173
+ * @returns The plan, which answers every question about that band.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * const plan = planFor(LoraRegion.Eu868)
178
+ * const link = plan.linkSettings(5)
179
+ * const permille = plan.dutyCyclePermille(868_100_000)
180
+ * ```
181
+ */
182
+ function planFor(region) {
183
+ return native_2.LoraChannelPlan.forRegion(region);
184
+ }
185
+ /**
186
+ * Returns how many transmissions of a payload fit in an hour at a data rate the
187
+ * region defines.
188
+ *
189
+ * This is the budget question a deployment actually asks: not what the radio can
190
+ * do, but how often it may speak on this band at this setting. The duty cycle of
191
+ * the frequency it transmits on decides the answer.
192
+ *
193
+ * @param plan - The channel plan to read.
194
+ * @param dataRate - The uplink data-rate number.
195
+ * @param payloadLength - The payload length in bytes.
196
+ * @param frequencyHz - The frequency the node transmits on.
197
+ * @returns The number of whole transmissions per hour, or `null` when the plan
198
+ * does not describe that data rate or frequency.
199
+ */
200
+ function messagesPerHourAt(plan, dataRate, payloadLength, frequencyHz) {
201
+ const settings = plan.linkSettings(dataRate);
202
+ const permille = plan.dutyCyclePermille(frequencyHz);
203
+ if (settings == null || permille == null) {
204
+ return null;
205
+ }
206
+ return messagesPerHour(settings, payloadLength, permille);
207
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pamoja/lora",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Time-on-air, duty-cycle off-time, and the regional channel plans a LoRa node must keep to.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -34,6 +34,6 @@
34
34
  "node": ">= 16"
35
35
  },
36
36
  "dependencies": {
37
- "@pamoja/native": "0.1.15"
37
+ "@pamoja/native": "0.1.16"
38
38
  }
39
39
  }