-
Notifications
You must be signed in to change notification settings - Fork 8
/
decodeUplink.js
192 lines (163 loc) · 6.48 KB
/
decodeUplink.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* Decoder in javascript for the family of tabs sensors from BROWAN for The Things Stack V3
*
* GNU Affero General Public License v3.0 - look into the LICENSE file please
*
* Created by Caspar Armster (dasdigidings e.V. / The Things Network Rhein-Sieg) - www.dasdigidings.de
* This function is based on the work from Cameron Sharp at Sensational Systems - [email protected]
*/
function decodeUplink(input) {
// create the object to collect the data for returning the decoded payload
var data = {
"bytes": input.bytes, // original payload
"port" : input.fPort // lorawan port
};
// Every device transmits the battery status and the temperature
// Battery measurement
battery = input.bytes[1] & 0x0f;
battery = (25 + battery) / 10;
capacity = input.bytes[1] >> 4;
capacity = (capacity / 15) * 100;
// Temperature measurement
temperature = input.bytes[2] & 0x7f;
temperature = temperature - 32;
data.battery = battery;
data.capacity = capacity;
data.temperature = temperature;
// depending on the lorawan port we know which tabs sensor is delivering the data
if (input.fPort === 100) { // Door & Window Sensor
// Time measurement
openingStatusTime = (input.bytes[4] << 8) | input.bytes[3];
// Count measurement
openingStatusCount = ((input.bytes[7] << 16) | (input.bytes[6] << 8)) | input.bytes[5];
// Status measurement
openingStatus = input.bytes[0] & 0x1;
if (openingStatus === 1) {
openingStatusOpen = true;
} else {
openingStatusOpen = false;
}
data.openingStatusTime = openingStatusTime;
data.openingStatusCount = openingStatusCount;
data.openingStatusOpen = openingStatusOpen;
} else if (input.fPort === 102) { // Motion Sensor (PIR)
// Time measurement
roomStatusTime = (input.bytes[4] << 8) | input.bytes[3];
// Count measurement
roomStatusCount = ((input.bytes[7] << 16) | (input.bytes[6] << 8)) | input.bytes[5];
// Status measurement
roomStatus = input.bytes[0] & 0x1;
if (roomStatus === 1) {
roomStatusOccupied = true;
} else {
roomStatusOccupied = false;
}
data.roomStatusTime = roomStatusTime;
data.roomStatusCount = roomStatusCount;
data.roomStatusOccupied = roomStatusOccupied;
} else if (input.fPort === 103) { // Healthy Home Sensor IAQ & Temperature & Humidity Sensor
if (input.bytes.length > 8) { // Healthy Home Sensor IAQ
// VOC Measurement
voc = (input.bytes[7] << 8) | input.bytes[6];
if (voc === 65535) {
vocError = true;
} else {
vocError = false;
}
// CO2 Measurement
co2 = (input.bytes[5] << 8) | input.bytes[4];
if (co2 === 65535) {
co2Error = true;
} else {
co2Error = false;
}
// IAQ Measurement
iaq = (input.bytes[9] << 9) | input.bytes[8];
// Environment temperature measurement
temperatureEnvironment = input.bytes[10] & 0x7f;
temperatureEnvironment = temperatureEnvironment - 32;
data.voc = voc;
data.vocError = vocError;
data.co2 = co2;
data.co2Error = co2Error;
data.iaq = iaq;
data.temperatureEnvironment = temperatureEnvironment;
}
// Humidity Measurement
humidity = input.bytes[3] &= 0x7f;
if (humidity === 127) {
humidityError = true;
} else {
humidityError = false;
}
data.humidity = humidity;
data.humidityError = humidityError;
} else if (input.fPort === 104) { // Ambient Light Sensor
// Lux measurement
lux = ((input.bytes[5] << 16) | (input.bytes[4] << 8)) | input.bytes[3];
lux = lux / 100;
data.lux = lux;
} else if (input.fPort === 105) { // Sound Level Sensor
// Sound Level measurement
soundLevel = input.bytes[3] & 0xff;
if (soundLevel === 255) {
soundLevelError = true;
} else {
soundLevelError = false;
}
data.soundLevel = soundLevel;
data.soundLevelError = soundLevelError;
} else if (input.fPort === 106) { // Water Leak Sensor
// water leakage status bit
waterLeakageBit = input.bytes[0] & 0x01;
if (waterLeakageBit === 1) {
waterLeakage = true;
} else {
waterLeakage = false;
}
// Environment temperature measurement
temperatureEnvironment = input.bytes[4] & 0x7f;
temperatureEnvironment = temperatureEnvironment - 32;
// Humidity Measurement
humidity = input.bytes[3] &= 0x7f;
if (humidity === 127) {
humidityError = true;
} else {
humidityError = false;
}
data.waterLeakage = waterLeakage;
data.temperatureEnvironment = temperatureEnvironment;
data.humidity = humidity;
data.humidityError = humidityError;
} else if (input.fPort === 136) { // Object Locator
// GNSS Fix?
if ((input.bytes[0] & 0x8) === 0) {
positionGnssFix = true;
} else {
positionGnssFix = false;
}
// Accuracy Measurement
positionAccuracy = input.bytes[10] >> 5;
positionAccuracy = Math.pow(2, parseInt(positionAccuracy) + 2);
// Mask off end of accuracy byte, so longitude doesn't get affected
input.bytes[10] &= 0x1f;
if ((input.bytes[10] & (1 << 4)) !== 0) {
input.bytes[10] |= 0xe0;
}
// Mask off end of latitude byte, RFU
input.bytes[6] &= 0x0f;
// Latitude and Longitude Measurement
positionLatitude = ((input.bytes[6] << 24 | input.bytes[5] << 16) | input.bytes[4] << 8 ) | input.bytes[3];
positionLongitude = ((input.bytes[10] << 24 | input.bytes[9] << 16) | input.bytes[8] << 8 ) | input.bytes[7];
positionLatitude = positionLatitude / 1000000;
positionLongitude = positionLongitude / 1000000;
data.positionGnssFix = positionGnssFix;
data.positionLatitude = positionLatitude;
data.positionLongitude = positionLongitude;
data.positionAccuracy = positionAccuracy;
}
return {
data: data,
warnings: [],
errors: []
};
}