Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Yvonne
Published

Sending Wio-E5 Data to Datacake via TTN

So you want to send data to Datacake via TTN? Great! Because it's easier than you might think right now.

BeginnerWork in progress295
Sending Wio-E5 Data to Datacake via TTN

Things used in this project

Hardware components

Seeed Studio Wio-E5 mini
×1

Software apps and online services

The Things Stack
The Things Industries The Things Stack
Datacake
Datacake

Story

Read more

Code

Payload Decoder

JavaScript
When your devices sends data, the payload will be passed to the payload decoder, alongside the event's name. The payload decoder then transforms it to measurements.
/**
 * Entry, decoder.js
 */
function Decoder(payload, port) {
    var payload_string = bytes2HexString(payload).toLocaleUpperCase();
  
    // var result_list = [
    // //   {
    // //     payload: payload_string,
    // //   },
    // ];
    var decoderArray = [];
    var splitArray = dataSplit(payload_string);
  
    for (var i = 0; i < splitArray.length; i++) {
      var item = splitArray[i];
      var dataId = item.dataId;
      var dataValue = item.dataValue;
      var messages = dataIdAndDataValueJudge(dataId, dataValue);
    //   console.log(messages);
      decoderArray.push(messages);
    }
  
    // var result_list = result_list.concat(decoderArray);
    // var result_list = decoderArray
    var result_list =  Array.prototype.concat.apply([], decoderArray);
    return result_list;
  }
/**
 * data splits
 * @param bytes
 * @returns {*[]}
 */

function dataSplit(bytes) {
    var frameArray = []

    for (var i = 0; i < bytes.length; i++) { // 切分成帧
        var remainingValue = bytes
        var dataId = remainingValue.substring(0, 2)
        var dataValue
        var dataObj = {}
        var cmd_size = 2
        var data_size = 6
        var packet_len = cmd_size + data_size;
        switch (dataId) { // 分割帧
            case '01': // 01 0110 10(6)
                data_size = 6
                packet_len = cmd_size + data_size;
                break
            case '02': // 02 011098(6)
                data_size = 6
                packet_len = cmd_size + data_size;
                break
            case '03': //03 A0320000(8)
                data_size = 8
                packet_len = cmd_size + data_size;
                break
            case '04': //04 11111111(8)
                data_size = 8
                packet_len = cmd_size + data_size;
                break
            case '05': //05 123456(6)
                data_size = 6
                packet_len = cmd_size + data_size;
                break
            default:
                data_size = 6
                packet_len = cmd_size + data_size;
                break
        }
        dataValue = remainingValue.substring(cmd_size, cmd_size+data_size)
        bytes = remainingValue.substring(packet_len)
        dataObj = {
            'dataId': dataId, 'dataValue': dataValue
        }
        if (dataValue.length < 2) {
            break
        }
        frameArray.push(dataObj)
    }
    return frameArray
}
// 01 0110 98530000010210A87A0000AF51

function dataIdAndDataValueJudge(dataId, dataValue) {
    // channel: 01 | , 1 byte, 1 byte, 1 byte
    // 02 1010 00000
    // 02101000000
    var MAP = [
        "Temperature",  //0] 2 bytes = 4
        "Humidity",     //1] 1 bytes = 1
        "Light",        //2] 4 bytes = 8
        "Air pressure", //3] 4 bytes = 8
        "acceleration",  //4] 3*[2] bytes = 6

        "Button", //5] 1 byte
        "LED",    //6] 1 byte
        "Buzzer", //7] 1 byte
        "Rotary", //8] 1 byte
        "Sound"   //9] 1 byte
    ]
    var MAP_Id = {
        "Temperature": "4097",
        "Humidity": "4098",
        "Light": "4099",
        "Air pressure": "4100",
        "acceleration": "4101",

        "Button": "789",
        "LED": "790",
        "Buzzer": "791",
        "Rotary": "792",
        "Sound": "793"
    }
    var messages = []
    switch (dataId) {
        case '01': // remote control | test: 01 01101 -> 0101101 OK 
            // 数据截取
            var id_button = 5
            var id_led = 6
            var id_buzzer = 7
            var id_rotary = 8
            var id_sound = 9

            var button = dataValue.substring(0, 1)
            var led = dataValue.substring(1, 2)
            var buzzer = dataValue.substring(2, 3)
            var rotary = dataValue.substring(3, 4)
            var sound = dataValue.substring(4, 6)[1]

            // // 数据解析
              messages = [{
                // value: MAP_Id[MAP[id_button]], field: MAP[id_button]
                value: button, field: MAP[id_button]

            }, {
                value: led, field: MAP[id_led]
            }, {
                value: buzzer, field: MAP[id_buzzer]
            }, {
                value: rotary, field: MAP[id_rotary]
            }, {
                value: sound, field: MAP[id_sound]
            }]
            break
        case '02': // Temperature & Humidity | test: 02 0110 98 -> 02011098 OK
            var id_temperature = 0
            var id_humidity = 1
            var temperature = dataValue.substring(0, 4) // 0110
            var humidity = dataValue.substring(4, 6)    // 98

            messages = [{
                value: loraWANV2DataFormat(temperature, 10), Id: MAP_Id[MAP[id_temperature]], field: MAP[id_temperature]
            }, {
                value: loraWANV2DataFormat(humidity), Id: MAP_Id[MAP[id_humidity]], field: MAP[id_humidity]
            },]
            break;
        case '03': // Light | 03  A0320000 -> 03A0320000 OK #TODO 数据映射问题
            var id_lgiht = 2
            var illumination = dataValue.substring(0, 8)    // 98
            messages = [{
                value: loraWANV2DataFormat(illumination), Id: MAP_Id[MAP[id_lgiht]], field: MAP[id_lgiht]
            }]
            break;
        case '04': // pressure
            //04 11111111
            var id_pressure = 3
            var pressure = dataValue.substring(0, 8)

            messages = [{
                value: loraWANV2DataFormat(pressure), Id: MAP_Id[MAP[id_pressure]], field: MAP[id_pressure]
            }]
            break;
        case '05': // acceleration
            //05 123456
            var id_acceleration = 4
            var acceleration = dataValue.substring(0, 6)// 10A8

            messages = [{
                value: loraWANV2DataFormat(acceleration), Id: MAP_Id[MAP[id_acceleration]], field: MAP[id_acceleration]
            }]

            break;
        default:
            break
    }
    return messages
}

/**
 *
 * data formatting
 * @param str
 * @param divisor
 * @returns {string|number}
 */
// function loraWANV2DataFormat(str, divisor = 1) {
// function loraWANV2DataFormat(str) {
//     var strReverse = bigEndianTransform(str)
//     var str2 = toBinary(strReverse)
//     if (str2.substring(0, 1) === '1') {
//         var arr = str2.split('')
//         var reverseArr = arr.map((item) => {
//             if (parseInt(item) === 1) {
//                 return 0
//             } else {
//                 return 1
//             }
//         })
//         str2 = parseInt(reverseArr.join(''), 2) + 1
//         return '-' + str2 / divisor
//     }
//     return parseInt(str2, 2) / divisor
// }

function loraWANV2DataFormat(str) {
    var strReverse = bigEndianTransform(str);
    var str2 = toBinary(strReverse);
    var divisor = 1; // 确保定义 divisor 或将其作为参数传递
  
    if (str2.substring(0, 1) === '1') {
      var arr = str2.split('');
      var reverseArr = arr.map(function(item) {
        if (parseInt(item) === 1) {
          return 0;
        } else {
          return 1;
        }
      });
      str2 = parseInt(reverseArr.join(''), 2) + 1;
      return '-' + str2 / divisor;
    }
    return parseInt(str2, 2) / divisor;
  }

/**
 * Handling big-endian data formats
 * @param data
 * @returns {*[]}
 */
function bigEndianTransform(data) {
    var dataArray = []
    for (var i = 0; i < data.length; i += 2) {
        dataArray.push(data.substring(i, i + 2))// Bytes | Two nums
    }
    // array of hex
    return dataArray
}

/**
 * Convert to an 8-digit binary number with 0s in front of the number
 * @param arr
 * @returns {string}
 */
// function toBinary(arr) {
//     var binaryData = arr.map((item) => {
//         var data = parseInt(item, 16)
//             .toString(2)
//         var dataLength = data.length
//         if (data.length !== 8) {
//             for (var i = 0; i < 8 - dataLength; i++) {
//                 data = `0` + data
//             }
//         }
//         return data
//     })
//     var ret = binaryData.toString()
//         .replace(/,/g, '')
//     return ret
// }
function toBinary(arr) {
    var binaryData = arr.map(function(item) {
      var data = parseInt(item, 16).toString(2);
      var dataLength = data.length;
      if (data.length !== 8) {
        for (var i = 0; i < 8 - dataLength; i++) {
          data = '0' + data;
        }
      }
      return data;
    });
  
    var ret = binaryData.join('');
    return ret;
  }
/**
 * sensor
 * @param str
 * @returns {{channel: number, type: number, status: number}}
 */
// function loraWANV2BitDataFormat(str) {
//     var strReverse = bigEndianTransform(str)
//     var str2 = toBinary(strReverse)
//     var channel = parseInt(str2.substring(0, 4), 2)
//     var status = parseInt(str2.substring(4, 5), 2)
//     var type = parseInt(str2.substring(5), 2)
//     return { channel, status, type }
// }
function loraWANV2BitDataFormat(str) {
    var strReverse = bigEndianTransform(str);
    var str2 = toBinary(strReverse);
    var channel = parseInt(str2.substring(0, 4), 2);
    var status = parseInt(str2.substring(4, 5), 2);
    var type = parseInt(str2.substring(5), 2);
    return { channel: channel, status: status, type: type };
}

/**
 * channel info
 * @param str
 * @returns {{channelTwo: number, channelOne: number}}
 */
function loraWANV2ChannelBitFormat(str) {
    var strReverse = bigEndianTransform(str)
    var str2 = toBinary(strReverse)
    var one = parseInt(str2.substring(0, 4), 2)
    var two = parseInt(str2.substring(4, 8), 2)
    var resultInfo = {
        one: one, two: two
    }
    return resultInfo
}

/**
 * data log status bit
 * @param str
 * @returns {{total: number, level: number, isTH: number}}
 */
function loraWANV2DataLogBitFormat(str) {
    var strReverse = bigEndianTransform(str)
    var str2 = toBinary(strReverse)
    var isTH = parseInt(str2.substring(0, 1), 2)
    var total = parseInt(str2.substring(1, 5), 2)
    var left = parseInt(str2.substring(5), 2)
    var resultInfo = {
        isTH: isTH, total: total, left: left
    }
    return resultInfo
}

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
}

Credits

Yvonne

Yvonne

3 projects • 2 followers

Comments