{"id":19714,"date":"2026-08-07T11:47:35","date_gmt":"2026-08-07T03:47:35","guid":{"rendered":"https:\/\/www.lansitec.com\/?post_type=docs&#038;p=19714"},"modified":"2026-08-07T11:47:43","modified_gmt":"2026-08-07T03:47:43","password":"","slug":"decoder-lorawan-label-tracker-ttn-chirpstack","status":"publish","type":"docs","link":"https:\/\/www.lansitec.com\/ko\/docs\/decoders\/decoder-lorawan-label-tracker-ttn-chirpstack\/","title":{"rendered":"LoRaWAN \ub514\ucf54\ub354 - \ub808\uc774\ube14 \ucd94\uc801\uae30(TTN\/Chirpstack)"},"content":{"rendered":"<div class=\"wp-block-file\"><a id=\"wp-block-file--media-3aca5e16-7647-4e40-8a3d-0c6cbb1a515c\" href=\"https:\/\/www.lansitec.com\/wp-content\/uploads\/2026\/08\/decode-tracking-label-ttn_chirpstackv4.js.zip\">decode-tracking-label-ttn_chirpstackv4.js<\/a><a href=\"https:\/\/www.lansitec.com\/wp-content\/uploads\/2026\/08\/decode-tracking-label-ttn_chirpstackv4.js.zip\" class=\"wp-block-file__button wp-element-button\" download aria-describedby=\"wp-block-file--media-3aca5e16-7647-4e40-8a3d-0c6cbb1a515c\">\ub2e4\uc6b4\ub85c\ub4dc<\/a><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Below the full decoder code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Decode uplink function.\n\/\/\n\/\/ Input is an object with the following fields:\n\/\/ - bytes = Byte array containing the uplink payload, e.g. &#91;255, 230, 255, 0]\n\/\/ - fPort = Uplink fPort.\n\/\/ - variables = Object containing the configured device variables.\n\/\/\n\/\/ Output must be an object with the following fields:\n\/\/ - data = Object representing the decoded payload.\n\n\/\/ Badge Tracker\nfunction decodeUplink(input) {\n  \/\/ bytes\n  var bytes = input.bytes;\n  \/\/ type\n  var uplinkType = (bytes&#91;0] >> 4) &amp; 0x0f;\n\n  switch (uplinkType) {\n    case 0x01:\n      return { data: decodeRegistration(bytes) };\n\n    case 0x02:\n      return { data: decodeHeartbeat(bytes) };\n\n    case 0x03:\n      return { data: decodeGNSSPosition(bytes) };\n\n    case 0x07:\n      return { data: decodeBeacon(bytes) };\n\n    case 0x08:\n      return { data: decodeAlarm(bytes) };\n\n    default:\n      return null;\n  }\n}\n\n\/\/ type: 0x01 Registration\nfunction decodeRegistration(bytes) {\n  var data = {};\n  data.type = \"Registration\";\n  data.adr = ((bytes&#91;0] >> 3) &amp; 0x1) == 0 ? \"OFF\" : \"ON\";\n  data.power = ((bytes&#91;2] >> 3) &amp; 0x1f) + \"dBm\";\n  data.dr = (bytes&#91;3] >> 4) &amp; 0x0f;\n  data.gnssEnable = ((bytes&#91;3] >> 3) &amp; 0x01) == 0 ? \"Disable\" : \"Enable\";\n  var positionModeValue = (bytes&#91;3] >> 1) &amp; 0x03;\n  if (positionModeValue == 0) {\n    data.positionMode = \"Period\";\n  } else if (positionModeValue == 1) {\n    data.positionMode = \"Autonomous\";\n  } else if (positionModeValue == 2) {\n    data.positionMode = \"Demand\";\n  }\n  data.bleEnable = (bytes&#91;3] &amp; 0x01) == 0 ? \"Disable\" : \"Enable\";\n  data.blePositionReportInterval =\n    (((bytes&#91;4] &lt;&lt; 8) &amp; 0xff00) | (bytes&#91;5] &amp; 0xff)) * 5 + \"s\";\n  data.gnssPositionReportInterval =\n    (((bytes&#91;6] &lt;&lt; 8) &amp; 0xff00) | (bytes&#91;7] &amp; 0xff)) * 5 + \"s\";\n  data.heartbeatReportInterval = (bytes&#91;8] &amp; 0xff) * 30 + \"s\";\n  data.version =\n    (bytes&#91;9] &amp; 0xff).toString(16).toUpperCase() +\n    \".\" +\n    (bytes&#91;10] &amp; 0xff).toString(16).toUpperCase();\n  data.cfmsg = \"1 Confirmed every \" + (bytes&#91;11] &amp; 0xff) + \" Heartbeat\";\n  data.hbCount = \"Disconnect Judgement \" + (bytes&#91;12] &amp; 0xff);\n  data.fallDetection = (bytes&#91;13] &amp; 0xff) * 0.5 + \" meters\";\n  return data;\n}\n\n\/\/ type: 0x02 Heartbeat\nfunction decodeHeartbeat(bytes) {\n  var data = {};\n  data.type = \"Heartbeat\";\n  data.battery = bytes&#91;1] + \"%\";\n  data.rssi = bytes&#91;2] * -1 + \"dBm\";\n  data.snr = (((bytes&#91;3] &lt;&lt; 8) &amp; 0xff00) | (bytes&#91;4] &amp; 0xff)) \/ 100 + \"dB\";\n  var gnssStateValue = (bytes&#91;5] >> 4) &amp; 0x0f;\n  if (gnssStateValue == 0) {\n    data.gnssState = \"Off\";\n  } else if (gnssStateValue == 1) {\n    data.gnssState = \"Boot GNSS\";\n  } else if (gnssStateValue == 2) {\n    data.gnssState = \"Locating\";\n  } else if (gnssStateValue == 3) {\n    data.gnssState = \"Located\";\n  } else if (gnssStateValue == 9) {\n    data.gnssState = \"No signal\";\n  }\n  data.moveState = bytes&#91;5] &amp; 0x0f;\n \n  return data;\n}\n\n\/\/ type: 0x03 GNSSPosition\nfunction decodeGNSSPosition(bytes) {\n  var data = {};\n  data.type = \"GNSSPosition\";\n  \/\/ longitude\n  let longitude =\n    (bytes&#91;1] &lt;&lt; 24) | (bytes&#91;2] &lt;&lt; 16) | (bytes&#91;3] &lt;&lt; 8) | bytes&#91;4];\n  data.longitude = hex2float(longitude);\n\n  \/\/ latitude\n  let latitude =\n    (bytes&#91;5] &lt;&lt; 24) | (bytes&#91;6] &lt;&lt; 16) | (bytes&#91;7] &lt;&lt; 8) | bytes&#91;8];\n  data.latitude = hex2float(latitude);\n\n  \/\/ time\n  let time =\n    (bytes&#91;9] &lt;&lt; 24) | (bytes&#91;10] &lt;&lt; 16) | (bytes&#91;11] &lt;&lt; 8) | bytes&#91;12];\n  data.time = timestampToTime((time + 8 * 60 * 60) * 1000);\n\n  return data;\n}\n\n\/\/ type: 0x07 Beacon\nfunction decodeBeacon(bytes) {\n  const data = {\n    type: \"Beacon\",\n    length: bytes&#91;0] &amp; 0x0f,\n  };\n\n  for (let i = 0; i &lt; data.length; i++) {\n    const index = 6 + 5 * i;\n    const major = ((bytes&#91;index] &lt;&lt; 8) | bytes&#91;index + 1])\n      .toString(16)\n      .toUpperCase()\n      .padStart(4, \"0\");\n    const minor = ((bytes&#91;index + 2] &lt;&lt; 8) | bytes&#91;index + 3])\n      .toString(16)\n      .toUpperCase()\n      .padStart(4, \"0\");\n    const <a href=\"https:\/\/www.lansitec.com\/blogs\/rssi-indoor-positioning\/\">rssi<\/a> = bytes&#91;index + 4] - 256 + \"dBm\";\n\n    data&#91;\"beacon\" + (i + 1)] = major + minor;\n    data&#91;\"<a href=\"https:\/\/www.lansitec.com\/blogs\/rssi-indoor-positioning\/\">rssi<\/a>\" + (i + 1)] = <a href=\"https:\/\/www.lansitec.com\/blogs\/rssi-indoor-positioning\/\">rssi<\/a>;\n  }\n\n  return data;\n}\n\n\/\/ type: 0x08 Alarm\nfunction decodeAlarm(bytes) {\n  var data = {};\n  data.type = \"Alarm\";\n\n  var alarmValue = bytes&#91;1] &amp; 0xff;\n  if (alarmValue === 1) {\n    data.alarm = \"SOS\";\n  } else if (alarmValue === 2) {\n    data.alarm = \"Fall\";\n  } else {\n    data.alarm = \"Unknown\";\n  }\n\n  return data;\n}\n\nfunction hex2float(num) {\n  var sign = num &amp; 0x80000000 ? -1 : 1;\n  var exponent = ((num >> 23) &amp; 0xff) - 127;\n  var mantissa = 1 + (num &amp; 0x7fffff) \/ 0x7fffff;\n  return sign * mantissa * Math.pow(2, exponent);\n}\n\nfunction timestampToTime(timestamp) {\n  const date = new Date(timestamp);\n  const year = date.getFullYear();\n  const month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n  const day = date.getDate().toString().padStart(2, \"0\");\n  const hour = date.getHours().toString().padStart(2, \"0\");\n  const minute = date.getMinutes().toString().padStart(2, \"0\");\n  const second = date.getSeconds().toString().padStart(2, \"0\");\n  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>","protected":false},"excerpt":{"rendered":"<p>Below the full decoder code:<\/p>","protected":false},"author":5,"featured_media":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"doc_category":[338],"doc_tag":[],"class_list":["post-19714","docs","type-docs","status-publish","hentry","doc_category-decoders"],"year_month":"2026-08","word_count":559,"total_views":0,"reactions":{"happy":0,"normal":0,"sad":0},"author_info":{"name":"\ub9c8\uc774\uc9c0","author_nicename":"maizi","author_url":"https:\/\/www.lansitec.com\/ko\/author\/maizi\/"},"doc_category_info":[{"term_name":"Decoders","term_url":"https:\/\/www.lansitec.com\/ko\/doc\/decoders\/"}],"doc_tag_info":[],"knowledge_base_info":[],"knowledge_base_slug":[],"_links":{"self":[{"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/docs\/19714","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/docs"}],"about":[{"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/types\/docs"}],"author":[{"embeddable":true,"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/comments?post=19714"}],"version-history":[{"count":1,"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/docs\/19714\/revisions"}],"predecessor-version":[{"id":19716,"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/docs\/19714\/revisions\/19716"}],"wp:attachment":[{"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/media?parent=19714"}],"wp:term":[{"taxonomy":"doc_category","embeddable":true,"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/doc_category?post=19714"},{"taxonomy":"doc_tag","embeddable":true,"href":"https:\/\/www.lansitec.com\/ko\/wp-json\/wp\/v2\/doc_tag?post=19714"}],"curies":[{"name":"\uc6cc\ub4dc\ud504\ub808\uc2a4","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}