-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial commit for Cors System Organisation #801
Open
patientenvy
wants to merge
20
commits into
TheThingsNetwork:master
Choose a base branch
from
corssystem:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 12 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
672dc42
initial commit for corssystem vendor
patientenvy 6ea1e6a
Merge branch 'TheThingsNetwork:master' into master
patientenvy 469d9ed
updated image for cortu genesis
patientenvy 071a8a2
fixed issues for pull request
patientenvy 323558a
Merge branch 'master' of github.com:CorsSystem/lorawan-devices
patientenvy cedf9e2
Merge branch 'TheThingsNetwork:master' into master
patientenvy 907276b
fixed formatting issues
patientenvy 40d4243
Merge branch 'master' of github.com:CorsSystem/lorawan-devices
patientenvy 90492a4
Merge branch 'TheThingsNetwork:master' into master
patientenvy f8e7f4d
feat: added cortu-genesis decoder
patientenvy 7359e4e
Merge branch 'master' of github.com:CorsSystem/lorawan-devices
patientenvy ab117db
Merge branch 'master' into master
patientenvy 343e2bc
Validation Succesful
Aceallio 0e4cbe8
Ran Validation again
Aceallio ed61eb4
Merge pull request #2 from CorsInterns/master
cors-oreoluwa d73a87f
Pakage.json reverted
Aceallio 92ad52c
Original package.json restored
Aceallio 99f2cd4
Merge pull request #3 from CorsInterns/master
cors-oreoluwa a4e1ec3
package-lock.json rvereted
Aceallio b7efae9
Merge pull request #4 from CorsInterns/master
cors-oreoluwa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
name: CorTU Genesis 2 # Device name can not contain the vendor name | ||
description: Remote Data Acquisition Board with Support for LoRaWAN and RF | ||
|
||
# Hardware versions (optional, use when you have revisions) | ||
hardwareVersions: | ||
- version: '1.0' | ||
numeric: 1 | ||
- version: '1.0-rev-A' | ||
numeric: 2 | ||
|
||
# Firmware versions (at least one is mandatory) | ||
firmwareVersions: | ||
- # Firmware version | ||
version: '1.0' | ||
numeric: 1 | ||
# Corresponding hardware versions (optional) | ||
hardwareVersions: | ||
- '1.0' | ||
|
||
# Firmware features (optional) | ||
# Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how | ||
# often he device sends a message). | ||
features: | ||
- remote rejoin | ||
- transmission interval | ||
|
||
# LoRaWAN Device Profiles per region | ||
# Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867, | ||
# RU864-870 | ||
profiles: | ||
EU863-870: | ||
# Optional identifier of the vendor of the profile. When you specify the vendorID, the profile is loaded from | ||
# the vendorID's folder. This allows you to reuse profiles from module or LoRaWAN end device stack vendors. | ||
# If vendorID is empty, the current vendor ID is used. In this example, the vendorID is the current vendor ID, | ||
# which is verbose. | ||
# vendorID: example | ||
# Identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters) | ||
id: cortugenesis-profile | ||
# lorawanCertified: true | ||
codec: cortugenesis-codec | ||
US902-928: | ||
id: cortugenesis-profile | ||
# lorawanCertified: true | ||
codec: cortugenesis-codec | ||
|
||
# Type of device (optional) | ||
# Valid values are: devkit, module, cots | ||
deviceType: cots | ||
|
||
# Sensors that this device features (optional) | ||
# Valid values are: | ||
# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity, current, digital input, | ||
# digital output, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, hall effect, humidity, iaq, infrared, leaf wetness, level, | ||
# light, lightning, link, magnetometer, moisture, motion, nfc, no, no2, o3, occupancy, optical meter, particulate matter, ph, pir, | ||
# pm2.5, pm10, potentiometer, power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, reed switch, rssi, | ||
# sap flow, smart valve, smoke, snr, so2, solar radiation, sound, strain, surface temperature, switch, temperature, tilt, time, turbidity, | ||
# tvoc, uv, vapor pressure, velocity, vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed. | ||
sensors: | ||
- 4-20 ma | ||
- analog input | ||
- digital input | ||
|
||
# Additional radios that this device has (optional) | ||
# Valid values are: ble, nfc, wifi, cellular. | ||
# additionalRadios: | ||
# - ble | ||
# - cellular | ||
|
||
# Bridge interfaces (optional) | ||
# Valid values are: modbus, m-bus, can bus, rs-485, sdi-12, analog, ethernet. | ||
bridgeInterfaces: | ||
- modbus | ||
- rs-485 | ||
- analog | ||
|
||
# Dimensions in mm (optional) | ||
# Use width, height, length and/or diameter | ||
dimensions: | ||
width: 110 | ||
length: 110 | ||
height: 40 | ||
|
||
# Weight in grams (optional) | ||
weight: 350 | ||
|
||
# Operating conditions (optional) | ||
operatingConditions: | ||
# Temperature (Celsius) | ||
temperature: | ||
min: -30 | ||
max: 85 | ||
# Relative humidity (fraction of 1) | ||
relativeHumidity: | ||
min: 0 | ||
max: 0.97 | ||
|
||
# IP rating (optional) | ||
# ipCode: IP64 | ||
|
||
# Key provisioning (optional) | ||
# Valid values are: custom (user can configure keys), join server and manifest. | ||
keyProvisioning: | ||
- custom | ||
- join server | ||
|
||
# Key programming (optional) | ||
# Valid values are: bluetooth, nfc, wifi, ethernet (via a webpage), serial (when the user has a serial interface to set the keys) | ||
# and firmware (when the user should change the firmware to set the keys). | ||
keyProgramming: | ||
- serial | ||
- firmware | ||
|
||
# Key security (optional) | ||
# Valid values are: none, read protected and secure element. | ||
keySecurity: none | ||
|
||
# Firmware programming (optional) | ||
# Valid values are: serial (when the user has a serial interface to update the firmware), ethernet, fuota lorawan (when the device | ||
# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism). | ||
firmwareProgramming: | ||
- serial | ||
# - fuota lorawan | ||
|
||
# Product and data sheet URLs (optional) | ||
productURL: https://corssystem.com/products/cortu-v1-0/ | ||
|
||
# Photos | ||
photos: | ||
main: cortugenesis.png # Image needs to have a transparent background |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Uplink decoder decodes binary data uplink into a JSON object (optional) | ||
uplinkDecoder: | ||
fileName: cortugenesis.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# LoRaWAN MAC version: 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 or 1.1 | ||
macVersion: '1.0.3' | ||
regionalParametersVersion: 'RP001-1.0.3-RevA' | ||
|
||
# Whether the end device supports join (OTAA) or not (ABP) | ||
supportsJoin: true | ||
|
||
# Maximum EIRP | ||
maxEIRP: 16 | ||
# Whether the end device supports 32-bit frame counters | ||
supports32bitFCnt: false | ||
|
||
# Whether the end device supports class B | ||
supportsClassB: false | ||
|
||
# Whether the end device supports class C | ||
supportsClassC: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
|
||
//CorTU Payload Formatter | ||
function parseIncomingData(data) { | ||
const delimiter = "\n"; | ||
// No need to use TextDecoder as data is already a string | ||
const dataSets = data.split(delimiter).filter(Boolean); | ||
return dataSets.map(dataSet => { | ||
const [huffmanCodesStr, encodedData] = dataSet.split("|"); | ||
const huffmanCodesArray = huffmanCodesStr.trim().split(';'); // Assuming ';' separates the codes | ||
const huffmanCodes = {}; | ||
for (let i = 0; i <(huffmanCodesArray.length)-1; i++) { | ||
const [key, value] = huffmanCodesArray[i].split(':'); | ||
huffmanCodes[key] = value; | ||
} | ||
return { | ||
huffmanCodes, | ||
encodedData | ||
}; | ||
}); | ||
} | ||
// Function to decode a Huffman-encoded bit stream using the provided codes | ||
function decodeHuffman(encodedData, huffmanCodes) { | ||
let decodedMessage = []; | ||
let currentCode = ""; | ||
// Iterate over each bit in the encoded data | ||
for (let bit of encodedData) { | ||
currentCode += bit; | ||
// Check if the current code matches any entry in the Huffman codes | ||
if (currentCode in huffmanCodes) { | ||
// Append the corresponding character to the decoded message | ||
decodedMessage.push(huffmanCodes[currentCode]); | ||
// Reset the current code | ||
currentCode = ""; | ||
} | ||
} | ||
// Return the decoded message as a string | ||
return decodedMessage.join(''); | ||
} | ||
function lppDecode(bytes) { | ||
var sensor_types = { | ||
0 : {'size': 1, 'name': 'digital_in', 'signed': false, 'divisor': 1}, | ||
1 : {'size': 1, 'name': 'digital_out', 'signed': false, 'divisor': 1}, | ||
2 : {'size': 2, 'name': 'analog_in', 'signed': true , 'divisor': 100}, | ||
3 : {'size': 2, 'name': 'analog_out', 'signed': true , 'divisor': 100}, | ||
100: {'size': 4, 'name': 'generic', 'signed': false, 'divisor': 1}, | ||
101: {'size': 2, 'name': 'illuminance', 'signed': false, 'divisor': 1}, | ||
102: {'size': 1, 'name': 'presence', 'signed': false, 'divisor': 1}, | ||
103: {'size': 2, 'name': 'temperature', 'signed': true , 'divisor': 10}, | ||
104: {'size': 1, 'name': 'humidity', 'signed': false, 'divisor': 2}, | ||
113: {'size': 6, 'name': 'accelerometer', 'signed': true , 'divisor': 1000}, | ||
115: {'size': 2, 'name': 'barometer', 'signed': false, 'divisor': 10}, | ||
116: {'size': 2, 'name': 'voltage', 'signed': false, 'divisor': 100}, | ||
117: {'size': 2, 'name': 'current', 'signed': false, 'divisor': 1000}, | ||
118: {'size': 4, 'name': 'frequency', 'signed': false, 'divisor': 1}, | ||
120: {'size': 1, 'name': 'percentage', 'signed': false, 'divisor': 1}, | ||
121: {'size': 2, 'name': 'altitude', 'signed': true, 'divisor': 1}, | ||
125: {'size': 2, 'name': 'concentration', 'signed': false, 'divisor': 1}, | ||
128: {'size': 2, 'name': 'power', 'signed': false, 'divisor': 1}, | ||
130: {'size': 4, 'name': 'distance', 'signed': false, 'divisor': 1000}, | ||
131: {'size': 4, 'name': 'energy', 'signed': false, 'divisor': 1000}, | ||
132: {'size': 2, 'name': 'direction', 'signed': false, 'divisor': 1}, | ||
133: {'size': 4, 'name': 'time', 'signed': false, 'divisor': 1}, | ||
134: {'size': 6, 'name': 'gyrometer', 'signed': true , 'divisor': 100}, | ||
135: {'size': 3, 'name': 'colour', 'signed': false, 'divisor': 1}, | ||
136: {'size': 9, 'name': 'gps', 'signed': true, 'divisor': [10000,10000,100]}, | ||
142: {'size': 1, 'name': 'switch', 'signed': false, 'divisor': 1}, | ||
}; | ||
function arrayToDecimal(stream, is_signed, divisor) { | ||
var value = 0; | ||
for (var i = 0; i < stream.length; i++) { | ||
if (stream[i] > 0xFF) | ||
throw 'Byte value overflow!'; | ||
value = (value << 8) | stream[i]; | ||
} | ||
if (is_signed) { | ||
var edge = 1 << (stream.length) * 8; // 0x1000.. | ||
var max = (edge - 1) >> 1; // 0x0FFF.. >> 1 | ||
value = (value > max) ? value - edge : value; | ||
} | ||
value /= divisor; | ||
return value; | ||
} | ||
var sensors = []; | ||
var i = 0; | ||
while (i < bytes.length) { | ||
var s_no = bytes[i++]; | ||
var s_type = bytes[i++]; | ||
if (typeof sensor_types[s_type] == 'undefined') { | ||
throw 'Sensor type error!: ' + s_type; | ||
} | ||
var s_value = 0; | ||
var type = sensor_types[s_type]; | ||
switch (s_type) { | ||
case 113: // Accelerometer | ||
case 134: // Gyrometer | ||
s_value = { | ||
'x': arrayToDecimal(bytes.slice(i+0, i+2), type.signed, type.divisor), | ||
'y': arrayToDecimal(bytes.slice(i+2, i+4), type.signed, type.divisor), | ||
'z': arrayToDecimal(bytes.slice(i+4, i+6), type.signed, type.divisor) | ||
}; | ||
break; | ||
case 136: // GPS Location | ||
s_value = { | ||
'latitude': arrayToDecimal(bytes.slice(i+0, i+3), type.signed, type.divisor[0]), | ||
'longitude': arrayToDecimal(bytes.slice(i+3, i+6), type.signed, type.divisor[1]), | ||
'altitude': arrayToDecimal(bytes.slice(i+6, i+9), type.signed, type.divisor[2]) | ||
}; | ||
break; | ||
case 135: // Colour | ||
s_value = { | ||
'r': arrayToDecimal(bytes.slice(i+0, i+1), type.signed, type.divisor), | ||
'g': arrayToDecimal(bytes.slice(i+1, i+2), type.signed, type.divisor), | ||
'b': arrayToDecimal(bytes.slice(i+2, i+3), type.signed, type.divisor) | ||
}; | ||
break; | ||
default: // All the rest | ||
s_value = arrayToDecimal(bytes.slice(i, i + type.size), type.signed, type.divisor); | ||
break; | ||
} | ||
sensors.push({ | ||
'channel': s_no, | ||
'type': s_type, | ||
'name': type.name, | ||
'value': s_value | ||
}); | ||
i += type.size; | ||
} | ||
return sensors; | ||
} | ||
// Convert hex string to byte array | ||
function hexStringToByteArray(hexString) { | ||
var bytes = []; | ||
for (var i = 0; i < hexString.length; i += 2) { | ||
bytes.push(parseInt(hexString.substr(i, 2), 16)); | ||
} | ||
return bytes; | ||
} | ||
function decodeUplink(input) | ||
{ | ||
// Convert decimal bytes to ASCII string | ||
var dataString = ''; | ||
for (var i = 0; i < input.bytes.length; i++) { | ||
dataString += String.fromCharCode(input.bytes[i]); | ||
} | ||
//Separate the Huffman codes from the encoded data | ||
let dataset = parseIncomingData(dataString); | ||
// Initialize an object to store all Huffman codes | ||
let allHuffmanCodes = {}; | ||
// Merge all Huffman codes into one object | ||
dataset.forEach(item => { | ||
Object.assign(allHuffmanCodes, item.huffmanCodes); | ||
}); | ||
//String to store encoded (compressed) data | ||
let allencodedData = dataset.map(item => item.encodedData).join(''); | ||
//Decoding the data | ||
let decodedData = decodeHuffman(allencodedData, allHuffmanCodes); | ||
//Converting string data output from Huffman encode to hex byte array hex | ||
let bytes = hexStringToByteArray(decodedData); | ||
// flat output (like original Cayenne lpp decoder): | ||
var response = {}; | ||
lppDecode(bytes, 1).forEach(function(field) { | ||
response[field.name + '_' + field.channel] = field.value; | ||
}); | ||
return { | ||
data: { | ||
bytes: input.bytes, | ||
decoded: { | ||
message: response | ||
} | ||
}, | ||
warnings: [], | ||
errors: [] | ||
}; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
endDevices: | ||
- cortu-gen-2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file contains the decoder for the example wind sensor as well. Do you have your own decoder or?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made all the changes