Created
July 2, 2024 16:01
-
-
Save aarnaud/f3b03b69b833f1c6bcbe466b81eefbde to your computer and use it in GitHub Desktop.
MeteoScientific Codecs
This file contains hidden or 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
| function decodeUplink (input) { | |
| const bytes = input['bytes'] | |
| const fport = parseInt(input['fPort']) | |
| const bytesString = bytes2HexString(bytes) | |
| const originMessage = bytesString.toLocaleUpperCase() | |
| const decoded = { | |
| valid: true, | |
| err: 0, | |
| payload: bytesString, | |
| messages: [] | |
| } | |
| if (fport === 199 || fport === 192) { | |
| decoded.messages.push({fport: fport, payload: bytesString}) | |
| return { data: decoded } | |
| } | |
| let measurement = messageAnalyzed(originMessage) | |
| if (measurement.length === 0) { | |
| decoded.valid = false | |
| return { data: decoded } | |
| } | |
| for (let message of measurement) { | |
| if (message.length === 0) { | |
| continue | |
| } | |
| let elements = {} | |
| for (let element of message) { | |
| if (element.errorCode) { | |
| decoded.err = element.errorCode | |
| decoded.errMessage = element.error | |
| } else { | |
| decoded[element.type] = element.measurementValue | |
| } | |
| } | |
| } | |
| // decoded.messages = measurement | |
| return { data: decoded } | |
| } | |
| function messageAnalyzed (messageValue) { | |
| try { | |
| let frames = unpack(messageValue) | |
| let measurementResultArray = [] | |
| for (let i = 0; i < frames.length; i++) { | |
| let item = frames[i] | |
| let dataId = item.dataId | |
| let dataValue = item.dataValue | |
| let measurementArray = deserialize(dataId, dataValue) | |
| measurementResultArray.push(measurementArray) | |
| } | |
| return measurementResultArray | |
| } catch (e) { | |
| return e.toString() | |
| } | |
| } | |
| function unpack (messageValue) { | |
| let frameArray = [] | |
| for (let i = 0; i < messageValue.length; i++) { | |
| let remainMessage = messageValue | |
| let dataId = remainMessage.substring(0, 2).toUpperCase() | |
| let dataValue | |
| let dataObj = {} | |
| let packageLen | |
| switch (dataId) { | |
| case '01': | |
| dataValue = remainMessage.substring(2, 94) | |
| messageValue = remainMessage.substring(94) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '02': | |
| dataValue = remainMessage.substring(2, 32) | |
| messageValue = remainMessage.substring(32) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '03': | |
| dataValue = remainMessage.substring(2, 64) | |
| messageValue = remainMessage.substring(64) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '04': | |
| dataValue = remainMessage.substring(2, 20) | |
| messageValue = remainMessage.substring(20) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '05': | |
| dataValue = remainMessage.substring(2, 10) | |
| messageValue = remainMessage.substring(10) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '06': | |
| dataValue = remainMessage.substring(2, 44) | |
| messageValue = remainMessage.substring(44) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '07': | |
| dataValue = remainMessage.substring(2, 84) | |
| messageValue = remainMessage.substring(84) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '08': | |
| dataValue = remainMessage.substring(2, 70) | |
| messageValue = remainMessage.substring(70) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '09': | |
| dataValue = remainMessage.substring(2, 36) | |
| messageValue = remainMessage.substring(36) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '0A': | |
| dataValue = remainMessage.substring(2, 76) | |
| messageValue = remainMessage.substring(76) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '0B': | |
| dataValue = remainMessage.substring(2, 62) | |
| messageValue = remainMessage.substring(62) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '0C': | |
| break | |
| case '0D': | |
| dataValue = remainMessage.substring(2, 10) | |
| messageValue = remainMessage.substring(10) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '0E': | |
| packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 | |
| dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) | |
| messageValue = remainMessage.substring(packageLen) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '0F': | |
| dataValue = remainMessage.substring(2, 34) | |
| messageValue = remainMessage.substring(34) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '10': | |
| dataValue = remainMessage.substring(2, 26) | |
| messageValue = remainMessage.substring(26) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '11': | |
| dataValue = remainMessage.substring(2, 28) | |
| messageValue = remainMessage.substring(28) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '1A': | |
| dataValue = remainMessage.substring(2, 56) | |
| messageValue = remainMessage.substring(56) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '1B': | |
| dataValue = remainMessage.substring(2, 96) | |
| messageValue = remainMessage.substring(96) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '1C': | |
| dataValue = remainMessage.substring(2, 82) | |
| messageValue = remainMessage.substring(82) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| case '1D': | |
| dataValue = remainMessage.substring(2, 40) | |
| messageValue = remainMessage.substring(40) | |
| dataObj = { | |
| 'dataId': dataId, 'dataValue': dataValue | |
| } | |
| break | |
| default: | |
| return frameArray | |
| } | |
| if (dataValue.length < 2) { | |
| break | |
| } | |
| frameArray.push(dataObj) | |
| } | |
| return frameArray | |
| } | |
| function deserialize (dataId, dataValue) { | |
| let measurementArray = [] | |
| let eventList = [] | |
| let measurement = {} | |
| let collectTime = 0 | |
| let groupId = 0 | |
| let shardFlag = {} | |
| let payload = '' | |
| let motionId = '' | |
| switch (dataId) { | |
| case '01': | |
| measurementArray = getUpShortInfo(dataValue) | |
| measurementArray.push(...getMotionSetting(dataValue.substring(30, 40))) | |
| measurementArray.push(...getStaticSetting(dataValue.substring(40, 46))) | |
| measurementArray.push(...getShockSetting(dataValue.substring(46, 52))) | |
| measurementArray.push(...getTempSetting(dataValue.substring(52, 72))) | |
| measurementArray.push(...getLightSetting(dataValue.substring(72, 92))) | |
| break | |
| case '02': | |
| measurementArray = getUpShortInfo(dataValue) | |
| break | |
| case '03': | |
| measurementArray.push(...getMotionSetting(dataValue.substring(0, 10))) | |
| measurementArray.push(...getStaticSetting(dataValue.substring(10, 16))) | |
| measurementArray.push(...getShockSetting(dataValue.substring(16, 22))) | |
| measurementArray.push(...getTempSetting(dataValue.substring(22, 42))) | |
| measurementArray.push(...getLightSetting(dataValue.substring(42, 62))) | |
| break | |
| case '04': | |
| let interval = 0 | |
| let workMode = getInt(dataValue.substring(0, 2)) | |
| let heartbeatInterval = getMinsByMin(dataValue.substring(4, 8)) | |
| let periodicInterval = getMinsByMin(dataValue.substring(8, 12)) | |
| let eventInterval = getMinsByMin(dataValue.substring(12, 16)) | |
| switch (workMode) { | |
| case 0: | |
| interval = heartbeatInterval | |
| break | |
| case 1: | |
| interval = periodicInterval | |
| break | |
| case 2: | |
| interval = eventInterval | |
| break | |
| } | |
| measurementArray = [ | |
| {measurementId: '3940', type: 'Work Mode', measurementValue: workMode}, | |
| {measurementId: '3942', type: 'Heartbeat Interval', measurementValue: heartbeatInterval}, | |
| {measurementId: '3943', type: 'Periodic Interval', measurementValue: periodicInterval}, | |
| {measurementId: '3944', type: 'Event Interval', measurementValue: eventInterval}, | |
| {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(16, 18))}, | |
| {measurementId: '3900', type: 'Uplink Interval', measurementValue: interval} | |
| ] | |
| break; | |
| case '05': | |
| measurementArray = [ | |
| {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(0, 2))}, | |
| {measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(2, 4))}, | |
| {measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(dataValue.substring(4, 6))}, | |
| {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(6, 8))} | |
| ] | |
| break | |
| case '06': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, | |
| {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, | |
| {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air_temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, | |
| {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} | |
| ] | |
| break | |
| case '07': | |
| eventList = getEventStatus(dataValue.substring(0, 6)) | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '5001', timestamp: collectTime, motionId: motionId, type: 'Wifi_scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, | |
| {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air_temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, | |
| {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} | |
| ] | |
| break | |
| case '08': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '5002', timestamp: collectTime, motionId: motionId, type: 'BLE_scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, | |
| {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air_temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, | |
| {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} | |
| ] | |
| break | |
| case '09': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, | |
| {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} | |
| ] | |
| break | |
| case '0A': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wifi_scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} | |
| ] | |
| break | |
| case '0B': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE_scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, | |
| ] | |
| break | |
| case '0D': | |
| let errorCode = getInt(dataValue) | |
| let error = '' | |
| switch (errorCode) { | |
| case 1: | |
| error = 'FAILED TO OBTAIN THE UTC TIMESTAMP' | |
| break | |
| case 2: | |
| error = 'ALMANAC TOO OLD' | |
| break | |
| case 3: | |
| error = 'DOPPLER ERROR' | |
| break | |
| } | |
| measurementArray.push({errorCode, error}) | |
| break | |
| case '0E': | |
| shardFlag = getShardFlag(dataValue.substring(0, 2)) | |
| groupId = getInt(dataValue.substring(2, 6)) | |
| payload = dataValue.substring(6) | |
| measurement = { | |
| measurementId: '6152', | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'gnss-ng payload', | |
| measurementValue: payload | |
| } | |
| measurementArray.push(measurement) | |
| break | |
| case '0F': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| shardFlag = getShardFlag(dataValue.substring(26, 28)) | |
| groupId = getInt(dataValue.substring(28, 32)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray.push({ | |
| measurementId: '4200', | |
| timestamp: collectTime, | |
| motionId, | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'event_status', | |
| measurementValue: getEventStatus(dataValue.substring(0, 6)) | |
| }) | |
| measurementArray.push({ | |
| measurementId: '4097', | |
| timestamp: collectTime, | |
| motionId, | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'Air_temperature', | |
| measurementValue: getSensorValue(dataValue.substring(16, 20), 10) | |
| }) | |
| measurementArray.push({ | |
| measurementId: '4199', | |
| timestamp: collectTime, | |
| motionId, | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'Light', | |
| measurementValue: getSensorValue(dataValue.substring(20, 24)) | |
| }) | |
| measurementArray.push({ | |
| measurementId: '3000', | |
| timestamp: collectTime, | |
| motionId, | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'Battery', | |
| measurementValue: getBattery(dataValue.substring(24, 26)) | |
| }) | |
| break | |
| case '10': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| shardFlag = getShardFlag(dataValue.substring(18, 20)) | |
| groupId = getInt(dataValue.substring(20, 24)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray.push({ | |
| measurementId: '4200', | |
| timestamp: collectTime, | |
| motionId, | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'event_status', | |
| measurementValue: getEventStatus(dataValue.substring(0, 6)) | |
| }) | |
| measurementArray.push({ | |
| measurementId: '3000', | |
| timestamp: collectTime, | |
| motionId, | |
| groupId: groupId, | |
| index: shardFlag.index, | |
| count: shardFlag.count, | |
| type: 'Battery', | |
| measurementValue: getBattery(dataValue.substring(16, 18)) | |
| }) | |
| break | |
| case '11': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| measurementArray.push({ | |
| measurementId: '3576', | |
| timestamp: collectTime, | |
| type: 'Positioning Status', | |
| measurementValue: getPositingStatus(dataValue.substring(0, 2)) | |
| }) | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4200', | |
| type: 'event_status', | |
| measurementValue: getEventStatus(dataValue.substring(2, 8)) | |
| }) | |
| if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4097', | |
| type: 'Air_temperature', | |
| measurementValue: getSensorValue(dataValue.substring(16, 20), 10) | |
| }) | |
| } | |
| if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4199', | |
| type: 'Light', | |
| measurementValue: getSensorValue(dataValue.substring(20, 24)) | |
| }) | |
| } | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '3000', | |
| type: 'Battery', | |
| measurementValue: getBattery(dataValue.substring(24, 26)) | |
| }) | |
| break | |
| case '1A': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '4197', timestamp: collectTime, motionId, type: 'longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, | |
| {measurementId: '4198', timestamp: collectTime, motionId, type: 'latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, | |
| {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air_temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, | |
| {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, | |
| {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(40, 44))}, | |
| {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(44, 48))}, | |
| {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(48, 52))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(52, 54))}, | |
| ] | |
| break | |
| // WIFI定位数据+sensor+三轴+电量 | |
| case '1B': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wifi_scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, | |
| {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air_temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, | |
| {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, | |
| {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(80, 84))}, | |
| {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(84, 88))}, | |
| {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(88, 92))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(92, 94))} | |
| ] | |
| break | |
| // BLE定位数据+sensor+三轴+电量 | |
| case '1C': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| motionId = getMotionId(dataValue.substring(6, 8)) | |
| measurementArray = [ | |
| {measurementId: '4200', timestamp: collectTime, motionId, type: 'event_status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, | |
| {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE_scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, | |
| {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air_temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, | |
| {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, | |
| {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(66, 70))}, | |
| {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(70, 74))}, | |
| {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(74, 78))}, | |
| {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(78, 80))} | |
| ] | |
| break | |
| // 定位状态 + sensor+三轴数据上报 | |
| case '1D': | |
| collectTime = getUTCTimestamp(dataValue.substring(8, 16)) | |
| measurementArray.push({ | |
| measurementId: '3576', | |
| timestamp: collectTime, | |
| type: 'Positioning Status', | |
| measurementValue: getPositingStatus(dataValue.substring(0, 2)) | |
| }) | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4200', | |
| type: 'event_status', | |
| measurementValue: getEventStatus(dataValue.substring(2, 8)) | |
| }) | |
| if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4097', | |
| type: 'Air_temperature', | |
| measurementValue: getSensorValue(dataValue.substring(16, 20), 10) | |
| }) | |
| } | |
| if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4199', | |
| type: 'Light', | |
| measurementValue: getSensorValue(dataValue.substring(20, 24)) | |
| }) | |
| } | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4210', | |
| type: 'AccelerometerX', | |
| measurementValue: getSensorValue(dataValue.substring(24, 28)) | |
| }) | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4211', | |
| type: 'AccelerometerY', | |
| measurementValue: getSensorValue(dataValue.substring(28, 32)) | |
| }) | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '4212', | |
| type: 'AccelerometerZ', | |
| measurementValue: getSensorValue(dataValue.substring(32, 36)) | |
| }) | |
| measurementArray.push({ | |
| timestamp: collectTime, | |
| measurementId: '3000', | |
| type: 'Battery', | |
| measurementValue: getBattery(dataValue.substring(36, 38)) | |
| }) | |
| break | |
| } | |
| return measurementArray | |
| } | |
| function getMotionId (str) { | |
| return getInt(str) | |
| } | |
| function getPositingStatus (str) { | |
| let status = getInt(str) | |
| switch (status) { | |
| case 0: | |
| return {id:status, statusName:"Positioning successful."} | |
| case 1: | |
| return {id:status, statusName:"The GNSS scan timed out and failed to obtain the location."} | |
| case 2: | |
| return {id:status, statusName:"The Wi-Fi scan timed out and failed to obtain the location."} | |
| case 3: | |
| return {id:status, statusName:"The Wi-Fi + GNSS scan timed out and failed to obtain the location."} | |
| case 4: | |
| return {id:status, statusName:"The GNSS + Wi-Fi scan timed out and failed to obtain the location."} | |
| case 5: | |
| return {id:status, statusName:"The Bluetooth scan timed out and failed to obtain the location."} | |
| case 6: | |
| return {id:status, statusName:"The Bluetooth + Wi-Fi scan timed out and failed to obtain the location."} | |
| case 7: | |
| return {id:status, statusName:"The Bluetooth + GNSS scan timed out and failed to obtain the location."} | |
| case 8: | |
| return {id:status, statusName:"The Bluetooth + Wi-Fi + GNSS scan timed out and failed to obtain the location."} | |
| case 9: | |
| return {id:status, statusName:"Location Server failed to parse the GNSS location."} | |
| case 10: | |
| return {id:status, statusName:"Location Server failed to parse the Wi-Fi location."} | |
| case 11: | |
| return {id:status, statusName:"Location Server failed to parse the Bluetooth location."} | |
| case 12: | |
| return {id:status, statusName:"Failed to parse the GNSS location due to the poor accuracy."} | |
| case 13: | |
| return {id:status, statusName:"Time synchronization failed."} | |
| case 14: | |
| return {id:status, statusName:"Failed to obtain location due to the old Almanac."} | |
| } | |
| return getInt(str) | |
| } | |
| function getUpShortInfo (messageValue) { | |
| return [ | |
| { | |
| measurementId: '3000', type: 'Battery', measurementValue: getBattery(messageValue.substring(0, 2)) | |
| }, { | |
| measurementId: '3502', type: 'Firmware Version', measurementValue: getSoftVersion(messageValue.substring(2, 6)) | |
| }, { | |
| measurementId: '3001', type: 'Hardware Version', measurementValue: getHardVersion(messageValue.substring(6, 10)) | |
| }, { | |
| measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(messageValue.substring(10, 12)) | |
| }, { | |
| measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(messageValue.substring(12, 14)) | |
| }, { | |
| measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getMinsByMin(messageValue.substring(14, 18)) | |
| }, { | |
| measurementId: '3943', type: 'Periodic Interval', measurementValue: getMinsByMin(messageValue.substring(18, 22)) | |
| }, { | |
| measurementId: '3944', type: 'Event Interval', measurementValue: getMinsByMin(messageValue.substring(22, 26)) | |
| }, { | |
| measurementId: '3945', type: 'Sensor Enable', measurementValue: getInt(messageValue.substring(26, 28)) | |
| }, { | |
| measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(messageValue.substring(28, 30)) | |
| } | |
| ] | |
| } | |
| function getMotionSetting (str) { | |
| return [ | |
| {measurementId: '3946', type: 'Motion Enable', measurementValue: getInt(str.substring(0, 2))}, | |
| {measurementId: '3947', type: 'Any Motion Threshold', measurementValue: getSensorValue(str.substring(2, 6), 1)}, | |
| {measurementId: '3948', type: 'Motion Start Interval', measurementValue: getMinsByMin(str.substring(6, 10))}, | |
| ] | |
| } | |
| function getStaticSetting (str) { | |
| return [ | |
| {measurementId: '3949', type: 'Static Enable', measurementValue: getInt(str.substring(0, 2))}, | |
| {measurementId: '3950', type: 'Device Static Timeout', measurementValue: getMinsByMin(str.substring(2, 6))} | |
| ] | |
| } | |
| function getShockSetting (str) { | |
| return [ | |
| {measurementId: '3951', type: 'Shock Enable', measurementValue: getInt(str.substring(0, 2))}, | |
| {measurementId: '3952', type: 'Shock Threshold', measurementValue: getInt(str.substring(2, 6))} | |
| ] | |
| } | |
| function getTempSetting (str) { | |
| return [ | |
| {measurementId: '3953', type: 'Temp Enable', measurementValue: getInt(str.substring(0, 2))}, | |
| {measurementId: '3954', type: 'Event Temp Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, | |
| {measurementId: '3955', type: 'Event Temp Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, | |
| {measurementId: '3956', type: 'Temp ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, | |
| {measurementId: '3957', type: 'Temp ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, | |
| {measurementId: '3958', type: 'Temp Warning Type', measurementValue: getInt(str.substring(18, 20))} | |
| ] | |
| } | |
| function getLightSetting (str) { | |
| return [ | |
| {measurementId: '3959', type: 'Light Enable', measurementValue: getInt(str.substring(0, 2))}, | |
| {measurementId: '3960', type: 'Event Light Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, | |
| {measurementId: '3961', type: 'Event Light Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, | |
| {measurementId: '3962', type: 'Light ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, | |
| {measurementId: '3963', type: 'Light ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, | |
| {measurementId: '3964', type: 'Light Warning Type', measurementValue: getInt(str.substring(18, 20))} | |
| ] | |
| } | |
| function getShardFlag (str) { | |
| let bitStr = getByteArray(str) | |
| return { | |
| count: parseInt(bitStr.substring(0, 4), 2), | |
| index: parseInt(bitStr.substring(4), 2) | |
| } | |
| } | |
| function getBattery (batteryStr) { | |
| return loraWANV2DataFormat(batteryStr) | |
| } | |
| function getSoftVersion (softVersion) { | |
| return `${loraWANV2DataFormat(softVersion.substring(0, 2))}.${loraWANV2DataFormat(softVersion.substring(2, 4))}` | |
| } | |
| function getHardVersion (hardVersion) { | |
| return `${loraWANV2DataFormat(hardVersion.substring(0, 2))}.${loraWANV2DataFormat(hardVersion.substring(2, 4))}` | |
| } | |
| function getSecondsByInt (str) { | |
| return getInt(str) | |
| } | |
| function getMinsByMin (str) { | |
| return getInt(str) | |
| } | |
| function getSensorValue (str, dig) { | |
| if (str === '8000') { | |
| return null | |
| } else { | |
| return loraWANV2DataFormat(str, dig) | |
| } | |
| } | |
| function bytes2HexString (arrBytes) { | |
| var str = '' | |
| for (var i = 0; i < arrBytes.length; i++) { | |
| var tmp | |
| var num = arrBytes[i] | |
| if (num < 0) { | |
| tmp = (255 + num + 1).toString(16) | |
| } else { | |
| tmp = num.toString(16) | |
| } | |
| if (tmp.length === 1) { | |
| tmp = '0' + tmp | |
| } | |
| str += tmp | |
| } | |
| return str | |
| } | |
| function loraWANV2DataFormat (str, divisor = 1) { | |
| let strReverse = bigEndianTransform(str) | |
| let str2 = toBinary(strReverse) | |
| if (str2.substring(0, 1) === '1') { | |
| let arr = str2.split('') | |
| let reverseArr = arr.map((item) => { | |
| if (parseInt(item) === 1) { | |
| return 0 | |
| } else { | |
| return 1 | |
| } | |
| }) | |
| str2 = parseInt(reverseArr.join(''), 2) + 1 | |
| return parseFloat('-' + str2 / divisor) | |
| } | |
| return parseInt(str2, 2) / divisor | |
| } | |
| function bigEndianTransform (data) { | |
| let dataArray = [] | |
| for (let i = 0; i < data.length; i += 2) { | |
| dataArray.push(data.substring(i, i + 2)) | |
| } | |
| return dataArray | |
| } | |
| function toBinary (arr) { | |
| let binaryData = arr.map((item) => { | |
| let data = parseInt(item, 16) | |
| .toString(2) | |
| let dataLength = data.length | |
| if (data.length !== 8) { | |
| for (let i = 0; i < 8 - dataLength; i++) { | |
| data = `0` + data | |
| } | |
| } | |
| return data | |
| }) | |
| return binaryData.toString().replace(/,/g, '') | |
| } | |
| function getSOSMode (str) { | |
| return loraWANV2DataFormat(str) | |
| } | |
| function getMacAndRssiObj (pair) { | |
| let pairs = [] | |
| if (pair.length % 14 === 0) { | |
| for (let i = 0; i < pair.length; i += 14) { | |
| let mac = getMacAddress(pair.substring(i, i + 12)) | |
| if (mac) { | |
| let rssi = getInt8RSSI(pair.substring(i + 12, i + 14)) | |
| pairs.push({mac: mac, rssi: rssi}) | |
| } else { | |
| continue | |
| } | |
| } | |
| } | |
| return pairs | |
| } | |
| function getMacAddress (str) { | |
| if (str.toLowerCase() === 'ffffffffffff') { | |
| return null | |
| } | |
| let macArr = [] | |
| for (let i = 1; i < str.length; i++) { | |
| if (i % 2 === 1) { | |
| macArr.push(str.substring(i - 1, i + 1)) | |
| } | |
| } | |
| let mac = '' | |
| for (let i = 0; i < macArr.length; i++) { | |
| mac = mac + macArr[i] | |
| if (i < macArr.length - 1) { | |
| mac = mac + ':' | |
| } | |
| } | |
| return mac | |
| } | |
| function getInt8RSSI (str) { | |
| return loraWANV2DataFormat(str) | |
| } | |
| function getInt (str) { | |
| return parseInt(str, 16) | |
| } | |
| function getEventStatus (str) { | |
| // return getInt(str) | |
| let bitStr = getByteArray(str) | |
| let bitArr = [] | |
| for (let i = 0; i < bitStr.length; i++) { | |
| bitArr[i] = bitStr.substring(i, i + 1) | |
| } | |
| bitArr = bitArr.reverse() | |
| let event = {} | |
| for (let i = 0; i < bitArr.length; i++) { | |
| if (bitArr[i] !== '1') { | |
| continue | |
| } | |
| switch (i){ | |
| case 0: | |
| event["start_moving_event"] = 1 | |
| break | |
| case 1: | |
| event["end_movement_event"] = 1 | |
| break | |
| case 2: | |
| event["motionless_event"] = 1 | |
| break | |
| case 3: | |
| event["shock_event"] = 1 | |
| break | |
| case 4: | |
| event["temperature_event"] = 1 | |
| break | |
| case 5: | |
| event["light_event"] = 1 | |
| break | |
| case 6: | |
| event["sos_event"] = 1 | |
| break | |
| case 7: | |
| event["press_once_event"] = 1 | |
| break | |
| } | |
| } | |
| return event | |
| } | |
| function getByteArray (str) { | |
| let bytes = [] | |
| for (let i = 0; i < str.length; i += 2) { | |
| bytes.push(str.substring(i, i + 2)) | |
| } | |
| return toBinary(bytes) | |
| } | |
| function getWorkingMode (workingMode) { | |
| return getInt(workingMode) | |
| } | |
| function getPositioningStrategy (strategy) { | |
| return getInt(strategy) | |
| } | |
| function getUTCTimestamp(str){ | |
| return parseInt(loraWANV2PositiveDataFormat(str)) * 1000 | |
| } | |
| function loraWANV2PositiveDataFormat (str, divisor = 1) { | |
| let strReverse = bigEndianTransform(str) | |
| let str2 = toBinary(strReverse) | |
| return parseInt(str2, 2) / divisor | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment