I have some Abeeway Smart barges and micro trackers, the decoder for them are more the 4k so you can’t utilize the decoder on the “The Things Stack Community Edition”, here I am going to use Node-Red to decode the raw data for me. In the same way you can use the decoder for both small and large packet decoders.
-
Create your application in TTN, add you device to the application.
-
In the integration add MQTT , copy your “Public TLS address”, “Username” and “Generate new API key”
-
Head over to your Node-Red instance and add a MQTT node to your flow, set up using MQTT in Node-RED [HowTo]
-
Add a “function” node and some “debug” nodes (these are just for debug purposes) and wire the lot together. I have an additional “inject” node just to simulate the JSON from TTN.
-
In the “inject” node (Simulate mqtt from TTN) you can past the below (remember this is the JSON from TTN for an Abeeway tracker) in the msg.payload, you also need to change the payload type to JSON. The structure from TTN are the same for all nodes. And then select “Done”.
{"end_device_ids":{"device_id":"sotracking-abeeway-smartbadge-1","application_ids":{"application_id":"smart-badge"},"dev_eui":"ttnPacketSim","join_eui":"ttnPacketSim2","dev_addr":"ttnPacketSim3"},"correlation_ids":["as:up:01FATZDBM2VGCRW537A405259N","gs:conn:01FAT7G51B7H8S9T0QEVGGD3BA","gs:up:host:01FAT7G51H1EMBX5QSFCMJR05S","gs:uplink:01FATZDBD5TRMD7VMF7BMJKDY6","ns:uplink:01FATZDBDK2H1BA0WPZTW3C5B1","rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01FATZDBDK6RVCXGG0J440347E","rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01FATZDBM2EFSJX03FHV7F3E97"],"received_at":"2021-07-17T19:34:40.516171594Z","uplink_message":{"session_key_id":"AXpDcMNiQiGwLWFsBx2pYQ==","f_port":18,"f_cnt":2292,"frm_payload":"BSAUeKBAAgEBAwIC","rx_metadata":[{"gateway_ids":{"gateway_id":"on-the-hill-01","eui":"00800000A000104F"},"timestamp":4101298211,"rssi":-65,"channel_rssi":-65,"snr":10.2,"location":{"latitude":-29.79981320234865,"longitude":30.762821694859166,"source":"SOURCE_REGISTRY"},"uplink_token":"ChwKGgoOb24tdGhlLWhpbGwtMDESCACAAACgABBPEKOw06MPGgwI0OHMhwYQnuz1hgEguJGxw67oBQ==","channel_index":3}],"settings":{"data_rate":{"lora":{"bandwidth":125000,"spreading_factor":7}},"data_rate_index":5,"coding_rate":"4/5","frequency":"867100000","timestamp":4101298211},"received_at":"2021-07-17T19:34:40.307703855Z","consumed_airtime":"0.066816s","version_ids":{"brand_id":"abeeway","model_id":"abeeway-smart-badge","hardware_version":"1.0","firmware_version":"2.1","band_id":"EU_863_870"}},"qos":0,"retain":false,"_msgid":"cb67353f.d8bfa8"}
- In the “function” node, change the name to “Decoder - Abeeway Tracker” and past the bellow in the “On Message” tab.
let bytes = Buffer.from(msg.payload.uplink_message.frm_payload)
let decoded = context.Decoder(bytes, msg.payload.uplink_message.f_port)
msg.payload.uplink_message.decoded_payload = decoded
return msg
7. In the “On Start” tab is where we are pasting our “decoder” (replace with you own decoder for other applications, remember this is for Abeeway and only will work with them) , for the Abeeway is the code below and select done and we can “deploy” the flow
context.Decoder = function(bytes, port) {
function step_size(lo, hi, nbits, nresv) {
return 1.0 / ((((1<<nbits) - 1) - nresv) / (hi - lo));
}
function mt_value_decode(value, lo, hi, nbits, nresv) {
return (value - nresv / 2) * step_size(lo, hi, nbits, nresv) + lo;
}
// Gets the zero-based unsigned numeric value of the given bit(s)
function bits(value, lsb, msb) {
var len = msb - lsb + 1;
var mask = (1<<len) - 1;
return value>>lsb & mask;
}
// Gets the boolean value of the given bit
function bit(value, bit) {
return (value & (1<<bit)) > 0;
}
// Gets a hexadecimal representation ensuring a leading zero for each byte
function hex(bytes, separator) {
return bytes.map(function (b) {
return ("0" + b.toString(16)).substr(-2);
}).join(separator || "");
}
// Decodes 4 bytes into a signed integer, MSB
function int32(bytes) {
// JavaScript bitwise operators always work with 32 bits signed integers
return bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];
}
// Decodes 4 bytes into an unsigned integer, MSB
function uint32(bytes) {
return (bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3])>>>0;
}
// Decodes 1 to 4 MAC addresses and their RSSI
function mac_rssi(bytes) {
var items = [];
for (var offset = 0; offset < bytes.length; offset += 7) {
items.push({
mac_address: hex(bytes.slice(offset, offset + 6), ":"),
// Sign-extend to 32 bits to support negative values; dBm
rssi: bytes[offset + 6]<<24>>24,
});
}
return items;
}
function message(code, descriptions) {
return {
code: code,
description: code < 0 || code >= descriptions.length ? "UNKNOWN" : descriptions[code]
};
}
var decoded = {};
var i;
var type = bytes[0];
// All message types, except for Frame pending messages, share the same header
if (type !== 0x00) {
// Note: the Data Storage Integration stores nested objects as text
decoded.status = {
mode: message(bits(bytes[1], 5, 7), ["Standby", "Motion tracking", "Permanent tracking",
"Motion start/end tracking", "Activity tracking", "OFF"]),
sos: bit(bytes[1], 4),
tracking: bit(bytes[1], 3),
moving: bit(bytes[1], 2),
periodic: bit(bytes[1], 1),
on_demand: bit(bytes[1], 0)
};
// Trackers with a rechargeable battery:the percentage reflects the actual value
decoded.battery = bytes[2]/100;
decoded.battery = bytes[2];
//Temperature
decoded.temperature = Math.round(100 * mt_value_decode(bytes[3], -44, 85, 8, 0)) / 100;
decoded.ack = bits(bytes[4], 4, 7);
decoded.data = bits(bytes[4], 0, 3);
//MCU and BLE fwVersion
decoded.lastResetCause = "lastResetCause: " + bytes[5];
decoded.mcuFirmware = "fwVersion: " + bytes[6] + "." + bytes[7] + "." + bytes[8];
decoded.bleFirmware = "bleFwVersion" + bytes[9] + "." + bytes[10] + "." + bytes[11];
}
switch (type) {
case 0x00:
decoded.type = "FRAME PENDING";
decoded.token = bytes[1];
break;
case 0x03:
decoded.type = "POSITION";
switch (decoded.data) {
case 0:
decoded.position_type = "GPS fix";
decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);
// Signed 32 bits integers; LSB is always zero
decoded.latitude = (bytes[6]<<24 | bytes[7]<<16 | bytes[8]<<8) / 1e7;
decoded.longitude = (bytes[9]<<24 | bytes[10]<<16 | bytes[11]<<8) / 1e7;
// Estimated Horizontal Position Error
decoded.ehpe = mt_value_decode(bytes[12], 0, 1000, 8, 0);
break;
case 1:
decoded.position_type = "GPS timeout";
decoded.timeout_cause = message(bytes[5], ["User timeout cause"]);
for (i = 0; i < 4; i++) {
// Carrier over noise (dBm) for the i-th satellite seen
decoded["cn" + i] = mt_value_decode(bytes[6 + i], 0, 2040, 8, 0);
}
break;
case 2:
// Documented as obsolete
decoded.error = message(0, ["UNSUPPORTED POSITION TYPE " + decoded.data]);
break;
case 3:
decoded.position_type = "WIFI timeout";
for (i = 0; i < 6; i++) {
decoded["v_bat" + (i + 1)] = mt_value_decode(bytes[5 + i], 2.8, 4.2, 8, 2);
}
break;
case 4:
decoded.position_type = "WIFI failure";
for (i = 0; i < 6; i++) {
// Most of time a WIFI timeout occurs due to a low battery condition
decoded["v_bat" + (i + 1)] = mt_value_decode(bytes[5 + i], 2.8, 4.2, 8, 2);
}
decoded.error = message(bytes[11], ["WIFI connection failure", "Scan failure",
"Antenna unavailable", "WIFI not supported on this device"]);
break;
case 5:
case 6:
decoded.position_type = "LP-GPS data";
// Encrypted; not described in the documentation
decoded.error = message(0, ["UNSUPPORTED POSITION TYPE " + decoded.data]);
break;
case 7:
decoded.position_type = "BLE beacon scan";
decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);
// Remaining data: up to 4 beacons
decoded.beacons = mac_rssi(bytes.slice(6));
break;
case 8:
decoded.position_type = "BLE beacon failure";
decoded.error = message(bytes[5], ["BLE is not responding", "Internal error", "Shared antenna not available",
"Scan already on going", "No beacon detected", "Hardware incompatibility"]);
break;
// Test with: 0358D895090EC46E1FF44B9EB76466B3B87454AD500959CA1ED4AD525E67DA14A1AC
// or 032CD1890900C46E1FF44B9EC5C83A355A3898A6
case 9:
decoded.position_type = "WIFI BSSIDs";
decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);
// Remaining data: up to 4 WiFi BSSIDs
decoded.stations = mac_rssi(bytes.slice(6));
break;
default:
decoded.error = message(0, ["UNSUPPORTED POSITION TYPE " + decoded.data]);
}
break;
case 0x04:
decoded.type = "ENERGY STATUS";
break;
case 0x05:
decoded.type = "HEARTBEAT";
break;
case 0x07:
// Activity status message and configuration message share the same identifier
var tag = bytes[5];
switch (tag) {
case 1:
decoded.type = "ACTIVITY STATUS";
decoded.activity_counter = uint32(bytes.slice(6, 10));
break;
case 2:
decoded.type = "CONFIGURATION";
for (i = 0; i < 5; i++) {
var offset = 6 + 5 * i;
decoded["param" + i] = {
type: bytes[offset],
value: uint32(bytes.slice(offset + 1, offset + 5))
};
}
break;
default:
decoded.error = message(0, ["UNSUPPORTED POSITION TYPE " + decoded.data + "/" + tag]);
}
break;
case 0x09:
decoded.type = "SHUTDOWN";
break;
case 0xFF:
decoded.type = "DEBUG";
break;
default:
decoded.error = message(0, ["UNSUPPORTED MESSAGE TYPE " + type]);
}
// Just some redundant debug info
decoded.debug = {
payload: hex(bytes),
length: bytes.length,
port: port,
server_time: new Date().toISOString()
};
return decoded;
}
8. No if we press the button on the “” your test JSON is injected and you date is decoded.
9. If you receive an Uplink from you Abeeway tracker it will also be decoded.
10. The raw data resides in “msg.payload.uplink_message.frm_payload “
- Your decode data resides in “msg.payload.uplink_message.decoded_payload”
[{"id":"d138923.833667","type":"inject","z":"597f54c3.1f3adc","name":"Simulate mqtt from TTN","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"v3/smart-badge@ttn/devices/sotracking-abeeway-smartbadge-1/up","payload":"{\"end_device_ids\":{\"device_id\":\"sotracking-abeeway-smartbadge-1\",\"application_ids\":{\"application_id\":\"smart-badge\"},\"dev_eui\":\"ttnPacketSim\",\"join_eui\":\"ttnPacketSim2\",\"dev_addr\":\"ttnPacketSim3\"},\"correlation_ids\":[\"as:up:01FATZDBM2VGCRW537A405259N\",\"gs:conn:01FAT7G51B7H8S9T0QEVGGD3BA\",\"gs:up:host:01FAT7G51H1EMBX5QSFCMJR05S\",\"gs:uplink:01FATZDBD5TRMD7VMF7BMJKDY6\",\"ns:uplink:01FATZDBDK2H1BA0WPZTW3C5B1\",\"rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01FATZDBDK6RVCXGG0J440347E\",\"rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01FATZDBM2EFSJX03FHV7F3E97\"],\"received_at\":\"2021-07-17T19:34:40.516171594Z\",\"uplink_message\":{\"session_key_id\":\"AXpDcMNiQiGwLWFsBx2pYQ==\",\"f_port\":18,\"f_cnt\":2292,\"frm_payload\":\"BSAUeKBAAgEBAwIC\",\"rx_metadata\":[{\"gateway_ids\":{\"gateway_id\":\"on-the-hill-01\",\"eui\":\"00800000A000104F\"},\"timestamp\":4101298211,\"rssi\":-65,\"channel_rssi\":-65,\"snr\":10.2,\"location\":{\"latitude\":-29.79981320234865,\"longitude\":30.762821694859166,\"source\":\"SOURCE_REGISTRY\"},\"uplink_token\":\"ChwKGgoOb24tdGhlLWhpbGwtMDESCACAAACgABBPEKOw06MPGgwI0OHMhwYQnuz1hgEguJGxw67oBQ==\",\"channel_index\":3}],\"settings\":{\"data_rate\":{\"lora\":{\"bandwidth\":125000,\"spreading_factor\":7}},\"data_rate_index\":5,\"coding_rate\":\"4/5\",\"frequency\":\"867100000\",\"timestamp\":4101298211},\"received_at\":\"2021-07-17T19:34:40.307703855Z\",\"consumed_airtime\":\"0.066816s\",\"version_ids\":{\"brand_id\":\"abeeway\",\"model_id\":\"abeeway-smart-badge\",\"hardware_version\":\"1.0\",\"firmware_version\":\"2.1\",\"band_id\":\"EU_863_870\"}},\"qos\":0,\"retain\":false,\"_msgid\":\"cb67353f.d8bfa8\"}","payloadType":"json","x":500,"y":580,"wires":[["d2487756.518b98","d42ae2de.76043"]]},{"id":"d2487756.518b98","type":"function","z":"597f54c3.1f3adc","name":"Decoder - Abeeway Tracker","func":"let bytes = Buffer.from(msg.payload.uplink_message.frm_payload)\n\nlet decoded = context.Decoder(bytes, msg.payload.uplink_message.f_port)\nmsg.payload.uplink_message.decoded_payload = decoded\nreturn msg","outputs":1,"noerr":0,"initialize":"context.Decoder = function(bytes, port) {\n function step_size(lo, hi, nbits, nresv) {\n return 1.0 / ((((1<<nbits) - 1) - nresv) / (hi - lo));\n }\n\n function mt_value_decode(value, lo, hi, nbits, nresv) {\n return (value - nresv / 2) * step_size(lo, hi, nbits, nresv) + lo;\n }\n\n // Gets the zero-based unsigned numeric value of the given bit(s)\n function bits(value, lsb, msb) {\n var len = msb - lsb + 1;\n var mask = (1<<len) - 1;\n return value>>lsb & mask;\n }\n\n // Gets the boolean value of the given bit\n function bit(value, bit) {\n return (value & (1<<bit)) > 0;\n }\n\n // Gets a hexadecimal representation ensuring a leading zero for each byte\n function hex(bytes, separator) {\n return bytes.map(function (b) {\n return (\"0\" + b.toString(16)).substr(-2);\n }).join(separator || \"\");\n }\n\n // Decodes 4 bytes into a signed integer, MSB\n function int32(bytes) {\n // JavaScript bitwise operators always work with 32 bits signed integers\n return bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];\n }\n\n // Decodes 4 bytes into an unsigned integer, MSB\n function uint32(bytes) {\n \n return (bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3])>>>0; \n }\n\n // Decodes 1 to 4 MAC addresses and their RSSI\n function mac_rssi(bytes) {\n var items = [];\n for (var offset = 0; offset < bytes.length; offset += 7) {\n items.push({\n mac_address: hex(bytes.slice(offset, offset + 6), \":\"),\n // Sign-extend to 32 bits to support negative values; dBm\n rssi: bytes[offset + 6]<<24>>24,\n });\n }\n return items;\n }\n\n function message(code, descriptions) {\n return {\n code: code,\n description: code < 0 || code >= descriptions.length ? \"UNKNOWN\" : descriptions[code]\n };\n }\n\n var decoded = {};\n var i;\n\n var type = bytes[0];\n\n // All message types, except for Frame pending messages, share the same header\n if (type !== 0x00) {\n // Note: the Data Storage Integration stores nested objects as text\n decoded.status = {\n mode: message(bits(bytes[1], 5, 7), [\"Standby\", \"Motion tracking\", \"Permanent tracking\",\n \"Motion start/end tracking\", \"Activity tracking\", \"OFF\"]),\n sos: bit(bytes[1], 4),\n tracking: bit(bytes[1], 3),\n moving: bit(bytes[1], 2),\n periodic: bit(bytes[1], 1),\n on_demand: bit(bytes[1], 0)\n };\n\n // Trackers with a rechargeable battery:the percentage reflects the actual value\n decoded.battery = bytes[2]/100;\n decoded.battery = bytes[2];\n //Temperature\n decoded.temperature = Math.round(100 * mt_value_decode(bytes[3], -44, 85, 8, 0)) / 100;\n \n decoded.ack = bits(bytes[4], 4, 7);\n \n decoded.data = bits(bytes[4], 0, 3);\n //MCU and BLE fwVersion\n decoded.lastResetCause = \"lastResetCause: \" + bytes[5];\n decoded.mcuFirmware = \"fwVersion: \" + bytes[6] + \".\" + bytes[7] + \".\" + bytes[8];\n decoded.bleFirmware = \"bleFwVersion\" + bytes[9] + \".\" + bytes[10] + \".\" + bytes[11];\n\n }\n\n switch (type) {\n case 0x00:\n decoded.type = \"FRAME PENDING\";\n decoded.token = bytes[1];\n break;\n\n case 0x03:\n decoded.type = \"POSITION\";\n switch (decoded.data) {\n case 0:\n decoded.position_type = \"GPS fix\";\n decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);\n // Signed 32 bits integers; LSB is always zero\n decoded.latitude = (bytes[6]<<24 | bytes[7]<<16 | bytes[8]<<8) / 1e7;\n decoded.longitude = (bytes[9]<<24 | bytes[10]<<16 | bytes[11]<<8) / 1e7;\n // Estimated Horizontal Position Error\n decoded.ehpe = mt_value_decode(bytes[12], 0, 1000, 8, 0);\n break;\n\n case 1:\n decoded.position_type = \"GPS timeout\";\n decoded.timeout_cause = message(bytes[5], [\"User timeout cause\"]);\n for (i = 0; i < 4; i++) {\n // Carrier over noise (dBm) for the i-th satellite seen\n decoded[\"cn\" + i] = mt_value_decode(bytes[6 + i], 0, 2040, 8, 0);\n }\n break;\n\n case 2:\n // Documented as obsolete\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data]);\n break;\n\n case 3:\n decoded.position_type = \"WIFI timeout\";\n for (i = 0; i < 6; i++) {\n decoded[\"v_bat\" + (i + 1)] = mt_value_decode(bytes[5 + i], 2.8, 4.2, 8, 2);\n }\n break;\n\n case 4:\n decoded.position_type = \"WIFI failure\";\n for (i = 0; i < 6; i++) {\n // Most of time a WIFI timeout occurs due to a low battery condition\n decoded[\"v_bat\" + (i + 1)] = mt_value_decode(bytes[5 + i], 2.8, 4.2, 8, 2);\n }\n decoded.error = message(bytes[11], [\"WIFI connection failure\", \"Scan failure\",\n \"Antenna unavailable\", \"WIFI not supported on this device\"]);\n break;\n\n case 5:\n case 6:\n decoded.position_type = \"LP-GPS data\";\n // Encrypted; not described in the documentation\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data]);\n break;\n\n case 7:\n decoded.position_type = \"BLE beacon scan\";\n decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);\n // Remaining data: up to 4 beacons\n decoded.beacons = mac_rssi(bytes.slice(6));\n break;\n\n case 8:\n decoded.position_type = \"BLE beacon failure\";\n decoded.error = message(bytes[5], [\"BLE is not responding\", \"Internal error\", \"Shared antenna not available\",\n \"Scan already on going\", \"No beacon detected\", \"Hardware incompatibility\"]);\n break;\n\n // Test with: 0358D895090EC46E1FF44B9EB76466B3B87454AD500959CA1ED4AD525E67DA14A1AC\n // or 032CD1890900C46E1FF44B9EC5C83A355A3898A6\n case 9:\n decoded.position_type = \"WIFI BSSIDs\";\n decoded.age = mt_value_decode(bytes[5], 0, 2040, 8, 0);\n // Remaining data: up to 4 WiFi BSSIDs\n decoded.stations = mac_rssi(bytes.slice(6));\n break;\n\n default:\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data]);\n }\n break;\n\n case 0x04:\n decoded.type = \"ENERGY STATUS\";\n break;\n\n case 0x05:\n decoded.type = \"HEARTBEAT\";\n break;\n\n case 0x07:\n // Activity status message and configuration message share the same identifier\n var tag = bytes[5];\n switch (tag) {\n case 1:\n decoded.type = \"ACTIVITY STATUS\";\n decoded.activity_counter = uint32(bytes.slice(6, 10));\n break;\n\n case 2:\n decoded.type = \"CONFIGURATION\";\n for (i = 0; i < 5; i++) {\n var offset = 6 + 5 * i;\n decoded[\"param\" + i] = {\n type: bytes[offset],\n value: uint32(bytes.slice(offset + 1, offset + 5))\n };\n }\n break;\n\n default:\n decoded.error = message(0, [\"UNSUPPORTED POSITION TYPE \" + decoded.data + \"/\" + tag]);\n }\n break;\n\n case 0x09:\n decoded.type = \"SHUTDOWN\";\n break;\n\n case 0xFF:\n decoded.type = \"DEBUG\";\n break;\n\n default:\n decoded.error = message(0, [\"UNSUPPORTED MESSAGE TYPE \" + type]);\n }\n\n // Just some redundant debug info\n decoded.debug = {\n payload: hex(bytes),\n length: bytes.length,\n port: port,\n server_time: new Date().toISOString()\n };\n\n return decoded;\n}\n","finalize":"","libs":[],"x":800,"y":580,"wires":[["889fa439.67ef48"]]},{"id":"6947df9f.225e8","type":"mqtt in","z":"597f54c3.1f3adc","name":"mqtt from TTN - Smart badge-abeeway","topic":"v3/+/devices/+/up","qos":"2","datatype":"json","broker":"b2606d53.73552","nl":false,"rap":true,"rh":0,"x":470,"y":520,"wires":[["d2487756.518b98","d42ae2de.76043"]]},{"id":"d42ae2de.76043","type":"debug","z":"597f54c3.1f3adc","name":"mqtt","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":770,"y":500,"wires":[]},{"id":"889fa439.67ef48","type":"debug","z":"597f54c3.1f3adc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1010,"y":580,"wires":[]},{"id":"b2606d53.73552","type":"mqtt-broker","name":"smart-badge","broker":"eu1.cloud.thethings.network","port":"8883","tls":"e7d6da8f.c8f9e8","clientid":"","usetls":true,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"e7d6da8f.c8f9e8","type":"tls-config","name":"","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":true}]