ADENUIS - Lorawan Field Test

Sensor

Codec Description

Codec for ADENUIS - Lorawan-Field-Test (v1.0.0).

Codec Preview

/* eslint-disable no-mixed-operators */ /* eslint-disable no-bitwise */ /* This is an example code for Everynet Parser. ** Everynet send several parameters to TagoIO. The job of this parse is to convert all these parameters into a TagoIO format. ** One of these parameters is the payload of your device. We find it too and apply the appropriate sensor parse. ** ** IMPORTANT: In most case, you will only need to edit the parsePayload function. ** ** Testing: ** You can do manual tests to this parse by using the Device Emulator. Copy and Paste the following code: ** [{ "variable": "everynet_payload", "value": "{ \"params\": { \"payload\": \"0109611395\" } }" }] ** ** The ignore_vars variable in this code should be used to ignore variables ** from the device that you don't want. */ // Add ignorable variables in this array. const ignore_vars = ['device_addr', 'port', 'duplicate', 'network', 'packet_hash', 'application', 'device', 'packet_id']; /** * Convert an object to TagoIO object format. * Can be used in two ways: * toTagoFormat({ myvariable: myvalue , anothervariable: anothervalue... }) * toTagoFormat({ myvariable: { value: myvalue, unit: 'C', metadata: { color: 'green' }} , anothervariable: anothervalue... }) * * @param {Object} object_item Object containing key and value. * @param {String} serie Serie for the variables * @param {String} prefix Add a prefix to the variables name */ function toTagoFormat(object_item, serie, prefix = '') { const result = []; for (const key in object_item) { if (ignore_vars.includes(key)) continue; if (typeof object_item[key] === 'object') { result.push({ variable: object_item[key].variable || `${prefix}${key}`.toLowerCase(), value: object_item[key].value, serie: object_item[key].serie || serie, metadata: object_item[key].metadata, location: object_item[key].location, unit: object_item[key].unit, }); } else { result.push({ variable: `${prefix}${key}`.toLowerCase(), value: object_item[key], serie, }); } } return result; } function Decoder(bytes, port) { // Functions function parseCoordinate(raw_value, coordinate) { // This function parses a coordinate payload part into // dmm and ddd let raw_itude = raw_value; let temp = ''; // Degree section let itude_string = ((raw_itude >> 28) & 0xF).toString(); raw_itude <<= 4; itude_string += ((raw_itude >> 28) & 0xF).toString(); raw_itude <<= 4; coordinate.degrees += itude_string; itude_string += '°'; // Minute section temp = ((raw_itude >> 28) & 0xF).toString(); raw_itude <<= 4; temp += ((raw_itude >> 28) & 0xF).toString(); raw_itude <<= 4; itude_string += temp; itude_string += '.'; coordinate.minutes += temp; // Decimal section temp = ((raw_itude >> 28) & 0xF).toString(); raw_itude <<= 4; temp += ((raw_itude >> 28) & 0xF).toString(); raw_itude <<= 4; itude_string += temp; coordinate.minutes += '.'; coordinate.minutes += temp; return itude_string; } function parseLatitude(raw_latitude, coordinate) { let latitude = parseCoordinate(raw_latitude, coordinate); latitude += ((raw_latitude & 0xF0) >> 4).toString(); coordinate.minutes += ((raw_latitude & 0xF0) >> 4).toString(); return latitude; } function parseLongitude(raw_longitude, coordinate) { let longitude = (((raw_longitude >> 28) & 0xF)).toString(); coordinate.degrees = longitude; longitude += parseCoordinate(raw_longitude << 4, coordinate); return longitude; } function addField(field_no, payload) { switch (field_no) { // Presence of temperature information case 0: payload.temperature = bytes[bytes_pos_] & 0x7F; // Temperature is negative if ((bytes[bytes_pos_] & 0x80) > 0) { payload.temperature -= 128; } bytes_pos_++; break; // Transmission triggered by the accelerometer case 1: payload.trigger = 'accelerometer'; break; // Transmission triggered by pressing pushbutton 1 case 2: payload.trigger = 'pushbutton'; break; // Presence of GPS information case 3: { // GPS Latitude // An object is needed to handle and parse coordinates into ddd notation const coordinate = {}; coordinate.degrees = ''; coordinate.minutes = ''; let raw_value = 0; raw_value |= bytes[bytes_pos_++] << 24; raw_value |= bytes[bytes_pos_++] << 16; raw_value |= bytes[bytes_pos_++] << 8; raw_value |= bytes[bytes_pos_++]; payload.lati_hemisphere = (raw_value & 1) == 1 ? 'South' : 'North'; payload.latitude_dmm = `${payload.lati_hemisphere.charAt(0)} `; payload.latitude_dmm += parseLatitude(raw_value, coordinate); const latitude = (parseFloat(coordinate.degrees) + parseFloat(coordinate.minutes) / 60) * ((raw_value & 1) == 1 ? -1.0 : 1.0); // GPS Longitude coordinate.degrees = ''; coordinate.minutes = ''; raw_value = 0; raw_value |= bytes[bytes_pos_++] << 24; raw_value |= bytes[bytes_pos_++] << 16; raw_value |= bytes[bytes_pos_++] << 8; raw_value |= bytes[bytes_pos_++]; payload.long_hemisphere = (raw_value & 1) == 1 ? 'West' : 'East'; payload.longitude_dmm = `${payload.long_hemisphere.charAt(0)} `; payload.longitude_dmm += parseLongitude(raw_value, coordinate); const longitude = (parseFloat(coordinate.degrees) + parseFloat(coordinate.minutes) / 60) * ((raw_value & 1) == 1 ? -1.0 : 1.0); payload.location = { value: `${latitude},${longitude}`, location: { lat: latitude, lng: longitude } }; // GPS Quality raw_value = bytes[bytes_pos_++]; switch ((raw_value & 0xF0) >> 4) { case 1: payload.gps_quality = 'Good'; break; case 2: payload.gps_quality = 'Average'; break; case 3: payload.gps_quality = 'Poor'; break; default: payload.gps_quality = (raw_value >> 4) & 0xF; break; } payload.hdop = (raw_value >> 4) & 0xF; // Number of satellites payload.sats = raw_value & 0xF; break; // Presence of Uplink frame counter } case 4: payload.ul_counter = bytes[bytes_pos_++]; break; // Presence of Downlink frame counter case 5: payload.dl_counter = bytes[bytes_pos_++]; break; // Presence of battery level information case 6: payload.battery_level = bytes[bytes_pos_++] << 8; payload.battery_level |= bytes[bytes_pos_++]; break; // Presence of RSSI and SNR information case 7: // RSSI payload.rssi_dl = bytes[bytes_pos_++]; payload.rssi_dl *= -1; // SNR payload.snr_dl = bytes[bytes_pos_] & 0x7F; if ((bytes[bytes_pos_] & 0x80) > 0) { payload.snr_dl -= 128; } bytes_pos_++; break; default: // Do nothing break; } } // Declaration & initialization let status_ = bytes[0]; const bytes_len_ = bytes.length; let bytes_pos_ = 1; let i = 0; const payload = {}; // Get raw payload let temp_hex_str = ''; // for (let j = 0; j < bytes_len_; j++) { // temp_hex_str = bytes[j].toString(16).toUpperCase(); // if (temp_hex_str.length == 1) { // temp_hex_str = `0${temp_hex_str}`; // } // payload.payload += temp_hex_str; // } // Get payload values do { // Check status, whether a field is set if ((status_ & 0x80) > 0) { addField(i, payload); } i++; } while (((status_ <<= 1) & 0xFF) > 0); return payload; } // let payload = [{ variable: 'payload', value: '9E1B4515969000553450272020'}] const payload_raw = payload.find(x => x.variable === 'payload' || x.variable === 'payload_raw' || x.variable === 'data'); if (payload_raw) { // Get a unique serie for the incoming data. const serie = payload_raw.serie || new Date().getTime(); let vars_to_tago = []; // Parse the payload from your sensor to function parsePayload try { const decoded = Decoder(Buffer.from(payload_raw.value, 'hex')); console.log(decoded); vars_to_tago = vars_to_tago.concat(toTagoFormat(decoded, serie)); } catch (e) { // Catch any error in the parse code and send to parse_error variable. vars_to_tago = vars_to_tago.concat({ variable: 'parse_error', value: e.message || e }); } payload = payload.concat(vars_to_tago); }

This codec is sourced from TagoIO Github. All rights belong to TagoIO Github.

This codec is licensed under the GNU General Public License v3 (GPL v3). Modifications, if any, are clearly marked. You are free to use, modify, and distribute the codec under the terms of GPL v3.

Community Feedback