Skip to content

Instantly share code, notes, and snippets.

@liwenyip
Forked from henrikekblad/MySensors log parser
Last active January 31, 2018 02:03

Revisions

  1. liwenyip revised this gist Jan 31, 2018. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion MySensors log parser
    Original file line number Diff line number Diff line change
    @@ -157,7 +157,12 @@ var types = {
    "I_PONG",
    "I_REGISTRATION_REQUEST",
    "I_REGISTRATION_RESPONSE",
    "I_DEBUG"
    "I_DEBUG",
    "I_SIGNAL_REPORT_REQUEST",
    "I_SIGNAL_REPORT_REVERSE",
    "I_SIGNAL_REPORT_RESPONSE",
    "I_PRE_SLEEP_NOTIFICATION",
    "I_POST_SLEEP_NOTIFICATION"
    ],
    "subtype":[
    "V_TEMP",
  2. @henrikekblad henrikekblad revised this gist Jan 29, 2018. 1 changed file with 29 additions and 3 deletions.
    32 changes: 29 additions & 3 deletions MySensors log parser
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Interpreting the logs from your node or gateway can be a bit tedious. On this page you can paste the output and get a more human readable output. [More details about the log messages](https://ci.mysensors.org/job/Verifiers/job/MySensors/branch/development/Doxygen_HTML/group__MyTransportgrp.html#details).
    Interpreting the logs from your node or gateway can be a bit tedious. On this page you can paste the output and get a more human readable output. [More details about the log messages](https://www.mysensors.org/apidocs/group__MyTransportgrp.html#details).

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    @@ -409,6 +409,31 @@ function getQueryVariable(variable)
    return(false);
    }

    var splitWithTail = function(value, separator, limit) {
    var pattern, startIndex, m, parts = [];

    if(!limit) {
    return value.split(separator);
    }

    if(separator instanceof RegExp) {
    pattern = new RegExp(separator.source, 'g' + (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : ''));
    } else {
    pattern = new RegExp(separator.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1'), 'g');
    }

    do {
    startIndex = pattern.lastIndex;
    if(m = pattern.exec(value)) {
    parts.push(value.substr(startIndex, m.index - startIndex));
    }
    } while(m && parts.length < limit - 1);
    parts.push(value.substr(pattern.lastIndex));

    return parts;
    }


    new Vue({
    el: "#parser",
    data: function() {
    @@ -464,7 +489,8 @@ return self.type(cmd, type);
    var self = this;
    var rows = this.source.split("\n");
    this.parsed = _.map(rows, function(r) {
    var p = r.split(";");
    //var p = r.split(";");
    var p = splitWithTail(r, ";", 6);
    if (p.length !== 6) {
    var desc = self.match(r);

    @@ -493,4 +519,4 @@ return self.type(cmd, type);
    }
    }
    });
    </script>
    </script>
  3. @henrikekblad henrikekblad created this gist Jan 29, 2018.
    496 changes: 496 additions & 0 deletions MySensors log parser
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,496 @@
    Interpreting the logs from your node or gateway can be a bit tedious. On this page you can paste the output and get a more human readable output. [More details about the log messages](https://ci.mysensors.org/job/Verifiers/job/MySensors/branch/development/Doxygen_HTML/group__MyTransportgrp.html#details).

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <div id="parser">
    <h4>Paste log from gateway or node here:</h4>
    <textarea class="form-control" @change="parse" rows="10" v-model="source"></textarea>
    <button @click="parse" class="btn btn-primary">Parse</button>
    <button @click="copy" class="btn btn-primary">Copy this log URL to clipboard</button>
    <button @click="source=''" class="btn btn-default">Clear</button>
    <h4>Human readable output:</h4>
    <div class="table-responsive">
    <table class="table table-condensed">
    <tr>
    <th>Node Id</th>
    <th>Child Sensor</th>
    <th>Command Type</th>
    <th>Ack Req/Resp</th>
    <th>Type</th>
    <th>Payload</th>
    <th>Description</th>
    </tr>
    <tr v-for="r in parsed">
    <td v-for="c in r" v-html="c"></td>
    </tr>
    </table>
    </div>
    </div>

    <script>
    function copyTextToClipboard(text) {
    var textArea = document.createElement("textarea");

    //
    // *** This styling is an extra step which is likely not required. ***
    //
    // Why is it here? To ensure:
    // 1. the element is able to have focus and selection.
    // 2. if element was to flash render it has minimal visual impact.
    // 3. less flakyness with selection and copying which **might** occur if
    // the textarea element is not visible.
    //
    // The likelihood is the element won't even render, not even a flash,
    // so some of these are just precautions. However in IE the element
    // is visible whilst the popup box asking the user for permission for
    // the web page to copy to the clipboard.
    //

    // Place in top-left corner of screen regardless of scroll position.
    textArea.style.position = 'fixed';
    textArea.style.top = 0;
    textArea.style.left = 0;

    // Ensure it has a small width and height. Setting to 1px / 1em
    // doesn't work as this gives a negative w/h on some browsers.
    textArea.style.width = '2em';
    textArea.style.height = '2em';

    // We don't need padding, reducing the size if it does flash render.
    textArea.style.padding = 0;

    // Clean up any borders.
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';

    // Avoid flash of white box if rendered for any reason.
    textArea.style.background = 'transparent';


    textArea.value = text;

    document.body.appendChild(textArea);

    textArea.select();

    try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
    } catch (err) {
    console.log('Oops, unable to copy');
    }

    document.body.removeChild(textArea);
    }

    var types = {
    "presentation":[
    "S_DOOR",
    "S_MOTION",
    "S_SMOKE",
    "S_BINARY",
    "S_DIMMER",
    "S_COVER",
    "S_TEMP",
    "S_HUM",
    "S_BARO",
    "S_WIND",
    "S_RAIN",
    "S_UV",
    "S_WEIGHT",
    "S_POWER",
    "S_HEATER",
    "S_DISTANCE",
    "S_LIGHT_LEVEL",
    "S_ARDUINO_NODE",
    "S_ARDUINO_REPEATER_NODE",
    "S_LOCK",
    "S_IR",
    "S_WATER",
    "S_AIR_QUALITY",
    "S_CUSTOM",
    "S_DUST",
    "S_SCENE_CONTROLLER",
    "S_RGB_LIGHT",
    "S_RGBW_LIGHT",
    "S_COLOR_SENSOR",
    "S_HVAC",
    "S_MULTIMETER",
    "S_SPRINKLER",
    "S_WATER_LEAK",
    "S_SOUND",
    "S_VIBRATION",
    "S_MOISTURE",
    "S_INFO",
    "S_GAS",
    "S_GPS",
    "S_WATER_QUALITY"
    ],
    "internal": [
    "I_BATTERY_LEVEL",
    "I_TIME",
    "I_VERSION",
    "I_ID_REQUEST",
    "I_ID_RESPONSE",
    "I_INCLUSION_MODE",
    "I_CONFIG",
    "I_FIND_PARENT_REQUEST",
    "I_FIND_PARENT_RESPONSE",
    "I_LOG_MESSAGE",
    "I_CHILDREN",
    "I_SKETCH_NAME",
    "I_SKETCH_VERSION",
    "I_REBOOT",
    "I_GATEWAY_READY",
    "I_SIGNING_PRESENTATION",
    "I_NONCE_REQUEST",
    "I_NONCE_RESPONSE",
    "I_HEARTBEAT_REQUEST",
    "I_PRESENTATION",
    "I_DISCOVER_REQUEST",
    "I_DISCOVER_RESPONSE",
    "I_HEARTBEAT_RESPONSE",
    "I_LOCKED",
    "I_PING",
    "I_PONG",
    "I_REGISTRATION_REQUEST",
    "I_REGISTRATION_RESPONSE",
    "I_DEBUG"
    ],
    "subtype":[
    "V_TEMP",
    "V_HUM",
    "V_STATUS",
    "V_PERCENTAGE",
    "V_PRESSURE",
    "V_FORECAST",
    "V_RAIN",
    "V_RAINRATE",
    "V_WIND",
    "V_GUST",
    "V_DIRECTION",
    "V_UV",
    "V_WEIGHT",
    "V_DISTANCE",
    "V_IMPEDANCE",
    "V_ARMED",
    "V_TRIPPED",
    "V_WATT",
    "V_KWH",
    "V_SCENE_ON",
    "V_SCENE_OFF",
    "V_HVAC_FLOW_STATE",
    "V_HVAC_SPEED",
    "V_LIGHT_LEVEL",
    "V_VAR1",
    "V_VAR2",
    "V_VAR3",
    "V_VAR4",
    "V_VAR5",
    "V_UP",
    "V_DOWN",
    "V_STOP",
    "V_IR_SEND",
    "V_IR_RECEIVE",
    "V_FLOW",
    "V_VOLUME",
    "V_LOCK_STATUS",
    "V_LEVEL",
    "V_VOLTAGE",
    "V_CURRENT",
    "V_RGB",
    "V_RGBW",
    "V_ID",
    "V_UNIT_PREFIX",
    "V_HVAC_SETPOINT_COOL",
    "V_HVAC_SETPOINT_HEAT",
    "V_HVAC_FLOW_MODE",
    "V_TEXT",
    "V_CUSTOM",
    "V_POSITION",
    "V_IR_RECORD",
    "V_PH",
    "V_ORP",
    "V_EC",
    "V_VAR",
    "V_VA",
    "V_POWER_FACTOR"
    ],
    command: [
    "PRESENTATION",
    "SET",
    "REQ",
    "INTERNAL",
    "STREAM"
    ],
    "payloadtype":[
    "P_STRING",
    "P_BYTE",
    "P_INT16",
    "P_UINT16",
    "P_LONG32",
    "P_ULONG32",
    "P_CUSTOM",
    "P_FLOAT32"
    ]};

    //mysgw: Client 0: 0;0;3;0;18;PING
    var rprefix = "(?:\\d+ )?(?:mysgw: )?(?:Client 0: )?";
    var match = [
    { re: "MCO:BGN:INIT CP=([^,]+)", d: "Core initialization with capabilities $1" },
    { re: "MCO:BGN:INIT (\\w+),CP=([^,]+),VER=(.*)", d: "Core initialization of <b>$1</b>, with capabilities $2, library version $3" },
    { re: "MCO:BGN:BFR", d: "Callback before()" },
    { re: "MCO:BGN:STP", d: "Callback setup()" },
    { re: "MCO:BGN:INIT OK,TSP=(.*)", d: "Core initialized, transport status <b>$1</b>, (1=initialized, 0=not initialized, NA=not available)" },
    { re: "MCO:BGN:NODE UNLOCKED", d: "Node successfully unlocked (see signing chapter)" },
    { re: "!MCO:BGN:TSP FAIL", d: "Transport initialization failed" },
    { re: "MCO:REG:REQ", d: "Registration request" },
    { re: "MCO:REG:NOT NEEDED", d: "No registration needed (i.e. GW)" },
    { re: "!MCO:SND:NODE NOT REG", d: "Node is not registered, cannot send message" },
    { re: "MCO:PIM:NODE REG=(\\d+)", d: "Registration response received, registration status <b>$1</b>" },
    { re: "MCO:PIM:ROUTE N=(\\d+),R=(\\d+)", d: "Routing table, messages to node <b>$1</b> are routed via node <b>$2</b>" },
    { re: "MCO:SLP:MS=(\\d+),SMS=(\\d+),I1=(\\d+),M1=(\\d+),I2=(\\d+),M2=(\\d+)", d: "Sleep node, duration <b>$1</b> ms, SmartSleep=<b>$2</b>, Int1=<b>$3</b>, Mode1=<b>$4</b>, Int2=<b>$5</b>, Mode2=<b>$6</b>" },
    { re: "MCO:SLP:TPD", d: "Sleep node, powerdown transport" },
    { re: "MCO:SLP:WUP=(-?\\d+)", d: "Node woke-up, reason/IRQ=<b>$1</b> (-2=not possible, -1=timer, >=0 IRQ)" },
    { re: "!MCO:SLP:FWUPD", d: "Sleeping not possible, FW update ongoing" },
    { re: "!MCO:SLP:REP", d: "Sleeping not possible, repeater feature enabled" },
    { re: "!MCO:SLP:TNR", d: " Transport not ready, attempt to reconnect until timeout" },
    { re: "MCO:NLK:NODE LOCKED. UNLOCK: GND PIN (\\d+) AND RESET", d: "Node locked during booting, see signing documentation for additional information" },
    { re: "MCO:NLK:TPD", d: "Powerdown transport" },
    { re: "TSM:INIT", d: "Transition to <b>Init</b> state" },
    { re: "TSM:INIT:STATID=(\\d+)", d: "Init static node id <b>$1</b>" },
    { re: "TSM:INIT:TSP OK", d: "Transport device configured and fully operational" },
    { re: "TSM:INIT:GW MODE", d: "Node is set up as GW, thus omitting ID and findParent states" },
    { re: "!TSM:INIT:TSP FAIL", d: "Transport device initialization failed" },
    { re: "TSM:FPAR", d: "Transition to <b>Find Parent</b> state" },
    { re: "TSM:FPAR:STATP=(\\d+)", d: "Static parent <b>$1</b> has been set, skip finding parent" },
    { re: "TSM:FPAR:OK", d: "Parent node identified" },
    { re: "!TSM:FPAR:NO REPLY", d: "No potential parents replied to find parent request" },
    { re: "!TSM:FPAR:FAIL", d: "Finding parent failed" },
    { re: "TSM:ID", d: "Transition to <b>Request Id</b> state" },
    { re: "TSM:ID:OK,ID=(\\d+)", d: "Node id <b>$1</b> is valid" },
    { re: "TSM:ID:REQ", d: "Request node id from controller" },
    { re: "!TSM:ID:FAIL,ID=(\\d+)", d: "Id verification failed, <b>$1</b> is invalid" },
    { re: "TSM:UPL", d: "Transition to <b>Check Uplink</b> state" },
    { re: "TSM:UPL:OK", d: "Uplink OK, GW returned ping" },
    { re: "!TSM:UPL:FAIL", d: "Uplink check failed, i.e. GW could not be pinged" },
    { re: "TSM:READY:NWD REQ", d: "Send transport network discovery request" },
    { re: "TSM:READY:SRT", d: "Save routing table" },
    { re: "TSM:READY:ID=(\\d+),PAR=(\\d+),DIS=(\\d+)", d: "Transport ready, node id <b>$1</b>, parent node id <b>$2</b>, distance to GW is <b>$3</b>" },
    { re: "!TSM:READY:UPL FAIL,SNP", d: "Too many failed uplink transmissions, search new parent" },
    { re: "!TSM:READY:FAIL,STATP", d: "Too many failed uplink transmissions, static parent enforced" },
    { re: "TSM:READY", d: "Transition to <b>Ready</b> state" },
    { re: "TSM:FAIL:CNT=(\\d+)", d: "Transition to <b>Failure</b> state, consecutive failure counter is <b>$1</b>" },
    { re: "TSM:FAIL:PDT", d: "Power-down transport" },
    { re: "TSM:FAIL:RE-INIT", d: "Attempt to re-initialize transport" },
    { re: "TSF:CKU:OK,FCTRL", d: "Uplink OK, flood control prevents pinging GW in too short intervals" },
    { re: "TSF:CKU:OK", d: "Uplink OK" },
    { re: "TSF:CKU:DGWC,O=(\\d+),N=(\\d+)", d: "Uplink check revealed changed network topology, old distance <b>$1</b>, new distance <b>$2</b>" },
    { re: "TSF:CKU:FAIL", d: "No reply received when checking uplink" },
    { re: "TSF:SID:OK,ID=(\\d+)", d: "Node id <b>$1</b> assigned" },
    { re: "!TSF:SID:FAIL,ID=(\\d+)", d: "Assigned id <b>$1</b> is invalid" },
    { re: "TSF:PNG:SEND,TO=(\\d+)", d: "Send ping to destination <b>$1</b>" },
    { re: "TSF:WUR:MS=(\\d+)", d: "Wait until transport ready, timeout <b>$1</b>" },
    { re: "TSF:MSG:ACK REQ", d: "ACK message requested" },
    { re: "TSF:MSG:ACK", d: "ACK message, do not proceed but forward to callback" },
    { re: "TSF:MSG:FPAR RES,ID=(\\d+),D=(\\d+)", d: "Response to find parent request received from node <b>$1</b> with distance <b>$2</b> to GW" },
    { re: "TSF:MSG:FPAR PREF FOUND", d: "Preferred parent found, i.e. parent defined via MY_PARENT_NODE_ID" },
    { re: "TSF:MSG:FPAR OK,ID=(\\d+),D=(\\d+)", d: "Find parent response from node <b>$1</b> is valid, distance <b>$2</b> to GW" },
    { re: "TSF:MSG:FPAR INACTIVE", d: "Find parent response received, but no find parent request active, skip response" },
    { re: "TSF:MSG:FPAR REQ,ID=(\\d+)", d: "Find parent request from node <b>$1</b>" },
    { re: "TSF:MSG:PINGED,ID=(\\d+),HP=(\\d+)", d: "Node pinged by node <b>$1</b> with <b>$2</b> hops" },
    { re: "TSF:MSG:PONG RECV,HP=(\\d+)", d: "Pinged node replied with <b>$1</b> hops" },
    { re: "TSF:MSG:BC", d: "Broadcast message received" },
    { re: "TSF:MSG:GWL OK", d: "Link to GW ok" },
    { re: "TSF:MSG:FWD BC MSG", d: "Controlled broadcast message forwarding" },
    { re: "TSF:MSG:REL MSG", d: "Relay message" },
    { re: "TSF:MSG:REL PxNG,HP=(\\d+)", d: "Relay PING/PONG message, increment hop counter to <b>$1</b>" },
    { re: "!TSF:MSG:LEN,(\\d+)!=(\\d+)", d: "Invalid message length, <b>$1</b> (actual) != <b>$2</b> (expected)" },
    { re: "!TSF:MSG:PVER,(\\d+)!=(\\d+)", d: "Message protocol version mismatch, <b>$1</b> (actual) != <b>$2</b> (expected)" },
    { re: "!TSF:MSG:SIGN VERIFY FAIL", d: "Signing verification failed" },
    { re: "!TSF:MSG:REL MSG,NORP", d: "Node received a message for relaying, but node is not a repeater, message skipped" },
    { re: "!TSF:MSG:SIGN FAIL", d: "Signing message failed" },
    { re: "!TSF:MSG:GWL FAIL", d: "GW uplink failed" },
    { re: "TSF:SAN:OK", d: "Sanity check passed" },
    { re: "!TSF:SAN:FAIL", d: "Sanity check failed, attempt to re-initialize radio" },
    { re: "TSF:CRT:OK", d: "Clearing routing table successful" },
    { re: "TSF:LRT:OK", d: "Loading routing table successful" },
    { re: "TSF:SRT:OK", d: "Saving routing table successful" },
    { re: "!TSF:RTE:FPAR ACTIVE", d: "Finding parent active, message not sent" },
    { re: "!TSF:RTE:DST (\\d+) UNKNOWN", d: "Routing for destination <b>$1</b> unknown, sending message to parent" },
    { re: "!TSF:SND:TNR", d: "Transport not ready, message cannot be sent" },
    { re: "TSF:MSG:READ,(\\d+)-(\\d+)-(\\d+),s=(\\d+),c=(\\d+),t=(\\d+),pt=(\\d+),l=(\\d+),sg=(\\d+):(.*)", d: "<u><b>Received Message</b></u><br><b>Sender</b>: $1<br><b>Last Node</b>: $2<br><b>Destination</b>: $3<br><b>Sensor Id</b>: $4<br><b>Command</b>: {command:$5}<br><b>Message Type</b>: {type:$5:$6}<br><b>Payload Type</b>: {pt:$7}<br><b>Payload Length</b>: $8<br><b>Signing</b>: $9<br><b>Payload</b>: $10" },
    { re: "TSF:MSG:SEND,(\\d+)-(\\d+)-(\\d+)-(\\d+),s=(\\d+),c=(\\d+),t=(\\d+),pt=(\\d+),l=(\\d+),sg=(\\d+),ft=(\\d+),st=(\\w+):(.*)", d: "<u><b>Sent Message</b></u><br><b>Sender</b>: $1<br><b>Last Node</b>: $2<br><b>Next Node</b>: $3<br><b>Destination</b>: $4<br><b>Sensor Id</b>: $5<br><b>Command</b>: {command:$6}<br><b>Message Type</b>:{type:$6:$7}<br><b>Payload Type</b>: {pt:$8}<br><b>Payload Length</b>: $9<br><b>Signing</b>: $10<br><b>Failed uplink counter</b>: $11<br><b>Status</b>: $12 (OK=success, NACK=no radio ACK received)<br><b>Payload</b>: $13" },
    { re: "!TSF:MSG:SEND,(\\d+)-(\\d+)-(\\d+)-(\\d+),s=(\\d+),c=(\\d+),t=(\\d+),pt=(\\d+),l=(\\d+),sg=(\\d+),ft=(\\d+),st=(\\w+):(.*)", d: "<u><b style='color:red'>Sent Message</b></u><br><b>Sender</b>: $1<br><b>Last Node</b>: $2<br><b>Next Node</b>: $3<br><b>Destination</b>: $4<br><b>Sensor Id</b>: $5<br><b>Command</b>: {command:$6}<br><b>Message Type</b>:{type:$6:$7}<br><b>Payload Type</b>: {pt:$8}<br><b>Payload Length</b>: $9<br><b>Signing</b>: $10<br><b>Failed uplink counter</b>: $11<br><b>Status</b>: $12 (OK=success, NACK=no radio ACK received)<br><b>Payload</b>: $13" },

    // Signing backend

    { re: "SGN:INI:BND OK", d: "Backend has initialized ok" },
    { re: "!SGN:INI:BND FAIL", d: "Backend has not initialized ok" },
    { re: "SGN:PER:OK", d: "Personalization data is ok" },
    { re: "!SGN:PER:TAMPERED", d: "Personalization data has been tampered" },
    { re: "SGN:PRE:SGN REQ", d: "Signing required" },
    { re: "SGN:PRE:SGN REQ,TO=(\\d+)", d: "Tell node <b>$1</b> that we require signing" },
    { re: "SGN:PRE:SGN REQ,FROM=(\\d+)", d: " Node <b>$1</b> require signing" },
    { re: "SGN:PRE:SGN NREQ", d: "Signing not required" },
    { re: "SGN:PRE:SGN REQ,TO=(\\d+)", d: "Tell node <b>$1</b> that we do not require signing" },
    { re: "SGN:PRE:SGN NREQ,FROM=(\\d+)", d: "Node <b>$1</b> does not require signing" },
    { re: "!SGN:PRE:SGN NREQ,FROM=(\\d+) REJ", d: "Node <b>$1</b> does not require signing but used to (requirement remain unchanged)" },
    { re: "SGN:PRE:WHI REQ", d: "Whitelisting required" },
    { re: "SGN:PRE:WHI REQ;TO=(\\d+)", d: "Tell <b>$1</b> that we require whitelisting" },
    { re: "SGN:PRE:WHI REQ,FROM=(\\d+)", d: "Node <b>$1</b> require whitelisting" },
    { re: "SGN:PRE:WHI NREQ", d: " Whitelisting not required" },
    { re: "SGN:PRE:WHI NREQ,TO=(\\d+)", d: "Tell node <b>$1</b> that we do not require whitelisting" },
    { re: "SGN:PRE:WHI NREQ,FROM=(\\d+)", d: "Node <b>$1</b> does not require whitelisting" },
    { re: "!SGN:PRE:WHI NREQ,FROM=(\\d+) REJ", d: "Node <b>$1</b> does not require whitelisting but used to (requirement remain unchanged)" },
    { re: "SGN:PRE:XMT,TO=(\\d+)", d: "Presentation data transmitted to node <b>$1</b>" },
    { re: "!SGN:PRE:XMT,TO=(\\d+) FAIL", d: "Presentation data not properly transmitted to node <b>$1</b>" },
    { re: "SGN:PRE:WAIT GW", d: "Waiting for gateway presentation data" },
    { re: "!SGN:PRE:VER=(\\d+)", d: "Presentation version <b>$1</b> is not supported" },
    { re: "SGN:PRE:NSUP", d: "Received signing presentation but signing is not supported" },
    { re: "SGN:PRE:NSUP,TO=(\\d+)", d: "Informing node <b>$1</b> that we do not support signing" },
    { re: "SGN:SGN:NCE REQ,TO=(\\d+)", d: "Nonce request transmitted to node <b>$1</b>" },
    { re: "!SGN:SGN:NCE REQ,TO=(\\d+) FAIL", d: "Nonce request not properly transmitted to node <b>$1</b>" },
    { re: "!SGN:SGN:NCE TMO", d: "Timeout waiting for nonce" },
    { re: "SGN:SGN:SGN", d: "Message signed" },
    { re: "!SGN:SGN:SGN FAIL", d: "Message failed to be signed" },
    { re: "SGN:SGN:NREQ=(\\d+)", d: "Node <b>$1</b> does not require signed messages" },
    { re: "SGN:SGN:(\\d+)!=(\\d+) NUS", d: "Will not sign because <b>$1</b> is not <b>$2</b> (repeater)" },
    { re: "!SGN:SGN:STATE", d: "Security system in a invalid state (personalization data tampered)" },
    { re: "!SGN:VER:NSG", d: "Message was not signed, but it should have been" },
    { re: "!SGN:VER:FAIL", d: "Verification failed" },
    { re: "SGN:VER:OK", d: "Verification succeeded" },
    { re: "SGN:VER:LEFT=(\\d+)", d: "<b>$1</b> number of failed verifications left in a row before node is locked" },
    { re: "!SGN:VER:STATE", d: "Security system in a invalid state (personalization data tampered)" },
    { re: "SGN:SKP:MSG CMD=(\\d+),TYPE=(\\d+)", d: "Message with command <b>$1</b> and type <b>$1</b> does not need to be signed" },
    { re: "SGN:SKP:ACK CMD=(\\d+),TYPE=(\\d+)", d: "ACK messages does not need to be signed" },
    { re: "SGN:NCE:LEFT=(\\d+)", d: "<b>$1</b> number of nonce requests between successful verifications left before node is locked" },
    { re: "SGN:NCE:XMT,TO=(\\d+)", d: "Nonce data transmitted to node <b>$1</b>" },
    { re: "!SGN:NCE:XMT,TO=(\\d+) FAIL", d: "Nonce data not properly transmitted to node <b>$1</b>" },
    { re: "!SGN:NCE:GEN", d: "Failed to generate nonce" },
    { re: "SGN:NCE:NSUP (DROPPED)", d: "Ignored nonce/request for nonce (signing not supported)" },
    { re: "SGN:NCE:FROM=(\\d+)", d: "Received nonce from node <b>$1</b>" },
    { re: "SGN:NCE:(\\d+)!=(\\d+) (DROPPED)", d: "Ignoring nonce as it did not come from the desgination of the message to sign" },
    { re: "!SGN:BND:INIT FAIL", d: "Failed to initialize signing backend" },
    { re: "!SGN:BND:PWD<8", d: "Signing password too short" },
    { re: "!SGN:BND:PER", d: "Backend not personalized" },
    { re: "!SGN:BND:SER", d: "Could not get device unique serial from backend" },
    { re: "!SGN:BND:TMR", d: "Backend timed out" },
    { re: "!SGN:BND:SIG,SIZE,(\\d+)>(\\d+)", d: "Refusing to sign message with length <b>$1</b> because it is bigger than allowed size <b>$2</b> " },
    { re: "SGN:BND:SIG WHI,ID=(\\d+)", d: "Salting message with our id <b>$1</b>" },
    { re: "SGN:BND:SIG WHI,SERIAL=(.*)", d: "Salting message with our serial <b>$1</b>" },
    { re: "!SGN:BND:VER ONGOING", d: "Verification failed, no ongoing session" },
    { re: "!SGN:BND:VER,IDENT=(\\d+)", d: "Verification failed, identifier <b>$1</b> is unknown" },
    { re: "SGN:BND:VER WHI,ID=(\\d+)", d: "Id <b>$1</b> found in whitelist" },
    { re: "SGN:BND:VER WHI,SERIAL=(.*)", d: "Expecting serial <b>$1</b> for this sender" },
    { re: "!SGN:BND:VER WHI,ID=(\\d+) MISSING", d: "Id <b>$1</b> not found in whitelist" },
    { re: "SGN:BND:NONCE=(.*)", d: "Calculating signature using nonce <b>$1</b>" },
    { re: "SGN:BND:HMAC=(.*)", d: "Calculated signature is <b>$1</b>" },
    ];



    // Init regexes
    for (var i=0, len=match.length;i<len; i++) {
    match[i].re = new RegExp("^" + rprefix + match[i].re);
    }
    var stripPrefix = new RegExp("^" + rprefix + "(.*)");

    function getQueryVariable(variable)
    {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i=0;i<vars.length;i++) {
    var pair = vars[i].split("=");
    if(pair[0] == variable){return pair[1];}
    }
    return(false);
    }

    new Vue({
    el: "#parser",
    data: function() {
    return {
    source: decodeURIComponent(getQueryVariable("log") || ""),
    parsed: []
    };
    },
    mounted: function() {
    this.parse();
    },
    watch: {
    source: function() {
    this.parse();
    }
    },
    methods: {
    selector: function(cmd) {
    switch (cmd) {
    case "0":
    return "presentation";
    break;
    case "1":
    case "2":
    return "subtype";
    break;
    case "3":
    return "internal";
    break;
    }
    },
    type: function(cmd, type) {
    var t = types[this.selector(cmd)]
    return t !== undefined ? t[type] || "Undefined" : "Undefined";
    },
    match: function(msg) {
    var self = this;
    var found = false;
    for (var i=0, len=match.length;!found && i<len; i++) {
    var r = match[i];
    if (r.re.test(msg)) {
    msg = msg.replace(r.re, r.d);
    msg = msg.replace(/{command:(\d+)}/g, function(match, m1) { return types.command[m1] });
    msg = msg.replace(/{pt:(\d+)}/g, function(match, m1) { return types.payloadtype[m1] });
    return msg.replace(/{type:(\d+):(\d+)}/g, function(match, cmd, type) {
    return self.type(cmd, type);
    });
    }
    }
    },
    parse: function() {
    console.log(this.source);
    var self = this;
    var rows = this.source.split("\n");
    this.parsed = _.map(rows, function(r) {
    var p = r.split(";");
    if (p.length !== 6) {
    var desc = self.match(r);

    return ["","","","",desc?"":"Unknown", r, desc];
    }
    var sel = self.selector(p[2]);
    var desc = "";
    if (p[2] == "3" && p[4] == "9") {
    desc = self.match(p[5]);

    }
    var node = stripPrefix.exec(p[0]);
    return [
    node[1],
    p[1],
    types.command[p[2]],
    p[3]=="1"?"true":"false",
    types[sel][p[4]],
    p[5],
    desc
    ];
    });
    },
    copy: function() {
    copyTextToClipboard('https://www.mysensors.org/build/parser?log='+encodeURIComponent(this.source));
    }
    }
    });
    </script>