diff --git a/nodered/README.md b/nodered/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/nodered/decode_locapack_header/decode_locapack_header.html b/nodered/decode_locapack_header/decode_locapack_header.html
new file mode 100644
index 0000000000000000000000000000000000000000..d6c720c6e1e91319bbb59a00d30f6f552266dafc
--- /dev/null
+++ b/nodered/decode_locapack_header/decode_locapack_header.html
@@ -0,0 +1,27 @@
+<script type="text/javascript">
+    RED.nodes.registerType('Decode Header',{
+        category: 'locapack',
+        color: '#a6bbcf',
+        defaults: {
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "file.png",
+        label: function() {
+            return this.name||"Decode Header";
+        }
+    });
+</script>
+
+<script type="text/html" data-template-name="Decode Header">
+    <div class="form-row">
+        <label for="node-input-name"><i class="icon-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/html" data-help-name="Decode Header">
+    <p>A simple node that converts the message payloads...</p>
+</script>
+
diff --git a/nodered/decode_locapack_header/decode_locapack_header.js b/nodered/decode_locapack_header/decode_locapack_header.js
new file mode 100644
index 0000000000000000000000000000000000000000..9e404a4ef3894250d34439bbc08fd077351c2bf0
--- /dev/null
+++ b/nodered/decode_locapack_header/decode_locapack_header.js
@@ -0,0 +1,58 @@
+module.exports = function(RED) {
+    function DecodeLocaPackHeaderNode(config) {
+        RED.nodes.createNode(this,config);
+        var node = this;
+        node.on('input', function(msg) {
+
+            var p = {};
+            var buff = msg.payload.LocaPack.inputBuffer;
+            var len = 0;
+            
+            // Get Header Field (hdr)
+            var hdr = {};
+            var hdr_raw = buff.readUInt16LE(len);
+            hdr.protocol_version = (hdr_raw & 0xF000) >> 12 ;
+            hdr.device_id_size = (hdr_raw & 0x0F00) >> 8;
+            hdr.packet_type = (hdr_raw & 0x00F0) >> 4;
+            hdr.movement_id_presence_flag = (hdr_raw & 0x0008) ? true : false;
+            hdr.timestamp_presence_flag = (hdr_raw & 0x0004) ? true : false;
+            p.header = hdr;
+            len += 2;
+            
+            // Sequence number
+            p.sequence_number = buff.readUInt16LE(len);
+            len += 2;
+            
+            // If the message contains the timestamp field (40 bits)
+            if (p.header.timestamp_presence_flag ) {
+                p.timestamp = buff.readUIntLE(len, 5);
+                len += 5;
+            }
+            
+            // If the message contains the movement_id field (8 bits)
+            if (p.header.movement_id_presence_flag ) {
+                p.movement_id = parseInt(buff[len]);
+                len += 1;
+            }
+            
+            // If the message contains the device_id field (n bytes)
+            if (p.header.device_id_size > 0 ) {
+                var n = p.header.device_id_size;
+                p.device_id = buff.readUIntLE(len, n);
+                len += n;
+            }
+            
+            // Payload_len field (8 bits)
+            var payload_len = parseInt(buff[len]);
+            len += 1;
+            
+            // payload
+            p.payload = buff.subarray(len, len+payload_len)
+            
+            msg.payload["LocaPack"] = p;
+            
+            node.send(msg);
+        });
+    }
+    RED.nodes.registerType("Decode Header",DecodeLocaPackHeaderNode);
+}
diff --git a/nodered/decode_universal_gnss_packet/decode_universal_gnss_packet.html b/nodered/decode_universal_gnss_packet/decode_universal_gnss_packet.html
new file mode 100644
index 0000000000000000000000000000000000000000..482b2c5bfd1c0dc3202477be4d3dadf6d6f13164
--- /dev/null
+++ b/nodered/decode_universal_gnss_packet/decode_universal_gnss_packet.html
@@ -0,0 +1,26 @@
+<script type="text/javascript">
+    RED.nodes.registerType('Decode GNSS',{
+        category: 'locapack',
+        color: '#a6bbcf',
+        defaults: {
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "file.png",
+        label: function() {
+            return this.name||"Decode GNSS";
+        }
+    });
+</script>
+
+<script type="text/html" data-template-name="Decode GNSS">
+    <div class="form-row">
+        <label for="node-input-name"><i class="icon-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/html" data-help-name="Decode GNSS">
+    <p>A simple node that converts the message payloads decode_universal_gnss_packet</p>
+</script>
diff --git a/nodered/decode_universal_gnss_packet/decode_universal_gnss_packet.js b/nodered/decode_universal_gnss_packet/decode_universal_gnss_packet.js
new file mode 100644
index 0000000000000000000000000000000000000000..b6ef6cca2c3b32f8f7e649086aa6c617ec0449d5
--- /dev/null
+++ b/nodered/decode_universal_gnss_packet/decode_universal_gnss_packet.js
@@ -0,0 +1,45 @@
+module.exports = function(RED) {
+    function DecodeUniversalGnssPacketNode(config) {
+        RED.nodes.createNode(this,config);
+        var node = this;
+        node.on('input', function(msg) {
+
+            var p = {};
+            var buff = msg.payload.LocaPack.payload;
+            var len = 0;
+            
+            // Get Header Field (hdr)
+            var hdr = {};
+            var hdr_raw = parseInt(buff[len]);
+            hdr.altitude_presence_flag = (hdr_raw & 0x80) ? true : false;
+            hdr.dop_presence_flag = (hdr_raw & 0x40) ? true : false;
+            p.header = hdr;
+            len += 1;
+            
+            // Latitude
+            p.latitude = buff.readFloatLE(len);
+            len += 4;
+            
+            // Longitude
+            p.longitude = buff.readFloatLE(len);
+            len += 4;
+            
+            // If the message contains the altitude field
+            if (p.header.altitude_presence_flag ) {
+                p.altitude = buff.readFloatLE(len);
+                len += 4;
+            }
+            
+            // If the message contains the dop field
+            if (p.header.dop_presence_flag ) {
+                p.dop = buff.readFloatLE(len);
+                len += 4;
+            }
+            
+            msg.payload.LocaPack["universalGnssPacket"] = p;
+
+            node.send(msg);
+        });
+    }
+    RED.nodes.registerType("Decode GNSS",DecodeUniversalGnssPacketNode);
+}
diff --git a/nodered/package.json b/nodered/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..cbc995546ac51be37d3b14d62920281eced9e3ff
--- /dev/null
+++ b/nodered/package.json
@@ -0,0 +1,17 @@
+{
+  "name": "red-contrib-locapack",
+  "version": "0.0.1",
+  "description": "A node to interact with LocaPack devices using the LocaPack protocol",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "Adrien van den Bossche <vandenbo@univ-tlse2.fr>",
+  "license": "ISC",
+  "node-red" : {
+    "nodes": {
+      "DecodeLocapackHeader": "decode_locapack_header/decode_locapack_header.js",
+      "DecodeUniversalGnssPacket": "decode_universal_gnss_packet/decode_universal_gnss_packet.js"
+    }
+  }
+}