jlong23 / node-red-node-ademco

Ademco Alarm Panel Parser for Node-Red
0 stars 0 forks source link

Ad2usb from a serial port, what to do ? #5

Open PPz1961 opened 2 years ago

PPz1961 commented 2 years ago

I'm a newbie here. I can work a little bit with node-red and I try to obtain messages from my ad2usb unit.

installed NR + serial and ademco palette: OK my computer has a functionnal com3 port working (when plugged the usb cable from ad2usb) on a flow, I added the node com3 input and set at 9600,n,8,1 (connected) connected to this a node com3 request (connected)

I imported the function (labeled as Ademco messages), that begins with "var partition = msg.payload;", etc the ademcolistener node is set to report All data the Ademcostatus is set to Partition1 (because my Vista honeywell unit has 1 partition)

After this, I'm lost. I don't know how to connect all those nodes together and add the proper functions, etc to obtain valid messages

I hope you will read this message ! Thank you

jlong23 commented 2 years ago

image

jlong23 commented 2 years ago

This flow connects the AD2USB / ADSerial Hat to my network mostly via MQTT to spread the load across multiple hosts.

image

[{"id":"425d8b25.bda274","type":"trigger","z":"8e037f86.71fc8","op1":"1","op2":"Alarm Panel Data Guard Failure","op1type":"nul","op2type":"val","duration":"2","extend":"true","units":"min","name":"Alarm Panel Guard","x":270,"y":200,"wires":[["33ba6392.cc459c","3989bbd4.7a6754"]]},{"id":"4a748079.b58b8","type":"comment","z":"8e037f86.71fc8","name":"Translate AD2USB Messages and Route them","info":"","x":190,"y":20,"wires":[]},{"id":"64737e19.9b8c8","type":"serial in","z":"8e037f86.71fc8","name":"AD2USB","serial":"91b4108d.76812","x":84.11111450195312,"y":108.77778148651123,"wires":[["aaa52ca1.555ad","425d8b25.bda274","e500bda8.1aff4","7cea5421.8315ac"]]},{"id":"aaa52ca1.555ad","type":"debug","z":"8e037f86.71fc8","name":"Raw AD2USB","active":false,"console":"false","complete":"payload","x":280,"y":60,"wires":[]},{"id":"e4018f3.f1bfe7","type":"function","z":"8e037f86.71fc8","name":"Alarm State Messaging","func":"var partition = msg.payload;\n\nif( partition !== undefined ) {\n var alarmText = \"\";\n\n // Format for core alarm State\n alarmText += \"Partition \";\n alarmText += partition.partitionNumber;\n alarmText += \" is \";\n var alarmState = \"\";\n switch ( partition.systemState ) {\n case 0:\n alarmState += \"DISARMED\";\n break;\n case 1:\n aalarmState += \"NOT READY\";\n break;\n\t case 2:\n alarmState += \"DISARMED READY\";\n break;\n\t case 3:\n alarmState += \"ARMED AWAY\";\n break;\n\t case 4:\n alarmState += \"ARMED STAY\";\n break;\n\t case 5:\n alarmState += \"ARMED INSTANT\";\n break;\n case 6:\n alarmState += \"ALARM\";\n break;\n\t case 7:\n alarmState += \"FIRE ALARM\";\n break;\n default:\n alarmState += \"UNKNOWN\";\n break;\t\t \n } \n \n alarmText += alarmState;\n \n msg.topic = partition.partitionNumber;\n global.set( \"partion_\" + partition.partitionNumber + \"_state\", alarmState );\n \n // Format for Alarms and Faults\n if( partition.systemState >= 6 || partition.systemState == 1 ) {\n \talarmText += \"; \";\n\t alarmText += partition.messageLine1.trim();\n\t alarmText += \" \";\n\t alarmText += partition.messageLine2.trim();\t\t\t\n }\n\n msg.payload = alarmText;\n \n // Route the Messages to the correct output\n // Critical Events are Sent on Output 2\n if( partition.systemState > 2 ) {\n return [ null, msg ];\n } else {\n // Status Events are sent on Output 1 \n if ( partition.systemState == 2 && partition.lastSystemState > 2 ) {\n // Unless it's transition from Higher States to Ready/Disarmed\n return [ null, msg ];\n } else {\n \t// Non Critical Events are Sent on Output 1\n return [ msg, null ];\n }\n }\n}\n\n// Fail to parse\nreturn [null, null];\n","outputs":"2","noerr":0,"x":530,"y":100,"wires":[["da0def9d.a65e9"],["33ba6392.cc459c","adace4e6.a10cc8"]]},{"id":"99101b77.66efe8","type":"debug","z":"8e037f86.71fc8","name":"Parsed AD2USB","active":false,"console":"false","complete":"payload","x":510,"y":60,"wires":[]},{"id":"e500bda8.1aff4","type":"mqtt out","z":"8e037f86.71fc8","name":"Raw AD2USB Queue","topic":"iot/evt/alarm/fmt/raw","qos":"","retain":"","broker":"f7430315.08bd","x":300,"y":140,"wires":[]},{"id":"7cea5421.8315ac","type":"AdemcoListener","z":"8e037f86.71fc8","report":"state","name":"","x":260,"y":100,"wires":[["99101b77.66efe8","e4018f3.f1bfe7","c2407da3.3dbf8"]]},{"id":"c2407da3.3dbf8","type":"function","z":"8e037f86.71fc8","name":"Alarm Sounding","func":"var partition = msg.payload;\n\nif( partition !== undefined && partition.alarmOccurred !== undefined && partition.alarmOccurred == true ) {\n var alarmText = \"\";\n\n // Format for core alarm State\n alarmText += \"Partition \";\n alarmText += partition.partitionNumber;\n alarmText += \" is \";\n\n switch ( partition.systemState ) {\n case 0:\n alarmText += \"DISARMED\";\n break;\n case 1:\n alarmText += \"NOT READY\";\n break;\n\t case 2:\n alarmText += \"DISARMED READY\";\n break;\n\t case 3:\n alarmText += \"ARMED AWAY\";\n break;\n\t case 4:\n alarmText += \"ARMED STAY\";\n break;\n\t case 5:\n alarmText += \"ARMED INSTANT\";\n break;\n case 6:\n alarmText += \"ALARM\";\n break;\n\t case 7:\n alarmText += \"FIRE ALARM\";\n break;\n default:\n alarmText += \"UNKNOWN\";\n break;\t\t \n } \n\n // Format for Alarms and Faults\n if( partition.systemState >= 6 || partition.systemState == 1 ) {\n \talarmText += \"; \";\n\t alarmText += partition.messageLine1.trim();\n\t alarmText += \" \";\n\t alarmText += partition.messageLine2.trim();\t\t\t\n }\n\n alarmText += \" : \";\n alarmText += new Date().toISOString();\n \n msg.payload = alarmText;\n \n context.loop = context.loop || \"stop\";\n context.loops = context.loops || 0;\n\n switch (partition.alarmOccurred) {\n \tcase \"false\":\n\t\t context.loops = context.loops + 1;\n\t\t msg.payload = \"Alarm Cleared\";\n\t\t context.loop = \"stop\";\n\t\t return [msg,null];\n\t case \"true\":\n \t\tmsg.payload = \"Alarm Occured\";\n\t\t context.loop = \"loop\";\n\t\t context.loops = 1;\n\t\t return [msg,partition];\n\t default:\n \t\tif (context.loop == \"loop\") {\n\t\t\t context.loops = context.loops + 1;\n\t\t\t msg.payload = \"Alarm Occured - \" + context.loops;\n \t\t\treturn [msg,partition];\n\t\t } else {\n \t\t\treturn [null,null]; \n\t\t }\n }\n}\n\n// Fail to parse\nreturn [null, null];\n","outputs":"2","noerr":0,"x":516,"y":151,"wires":[["33ba6392.cc459c"],["c067a6af.3f9858"]]},{"id":"c067a6af.3f9858","type":"delay","z":"8e037f86.71fc8","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"minutes","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":519,"y":205,"wires":[["c2407da3.3dbf8"]]},{"id":"da0def9d.a65e9","type":"debug","z":"8e037f86.71fc8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":810,"y":60,"wires":[]},{"id":"adace4e6.a10cc8","type":"link out","z":"8e037f86.71fc8","name":"","links":["5f79c775.c80ae8"],"x":775,"y":100,"wires":[]},{"id":"91b4108d.76812","type":"serial-port","z":"8e037f86.71fc8","serialport":"/dev/ttyS0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\n","bin":"false","out":"char","addchar":false,"responsetimeout":""},{"id":"f7430315.08bd","type":"mqtt-broker","z":"","name":"ESB","broker":"esb","port":"1883","clientid":"pi-alarmbridge","usetls":false,"compatmode":true,"keepalive":"15","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

jlong23 commented 2 years ago

The Serial Hat from the AD2Serial and Pi2 does have some glitches, if the pi is busy it may get corrupt messages (Nightly upgrades do this) and I get notices of the Partition 2 going from ARM AWAY to ARM STAY and back again. I think if I upgraded that back to a Pi3 or Pi4 with more memory this would go away. the USB version from AD2USB never gave me issues until a lightning strike of the barn that fried it.

jlong23 commented 2 years ago

You can also control the Panel from NodeRed, You need to encode a passcode into it, but it can send the same keypad values back to the panel to change states.

image

[{"id":"ad809ddf.527f6","type":"template","z":"b08a2871.4f75d8","name":"Switch Pannels","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"*{{pannelNum}}","x":160,"y":120,"wires":[["bd914747.426eb8"]]},{"id":"bd914747.426eb8","type":"delay","z":"b08a2871.4f75d8","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":360,"y":120,"wires":[["4a09852d.b5f67c"]]},{"id":"4a09852d.b5f67c","type":"template","z":"b08a2871.4f75d8","name":"Send Command","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{stateNum}}","x":560,"y":120,"wires":[["13ed03d1.7d9abc"]]},{"id":"13ed03d1.7d9abc","type":"serial out","z":"b08a2871.4f75d8","name":"","serial":"e2882477.59de98","x":760,"y":120,"wires":[]},{"id":"e2882477.59de98","type":"serial-port","z":"b08a2871.4f75d8","serialport":"/dev/ttyS0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\n","bin":"false","out":"char","addchar":false,"responsetimeout":""}]

PPz1961 commented 2 years ago

This flow connects the AD2USB / ADSerial Hat to my network mostly via MQTT to spread the load across multiple hosts.

Thank you for the explanation. However, when I try to import this flow, I obtain a syntax error (see screen capture). I'm using node-red v 16.13.2 on a Windows 10 computer (I just set because normally my node-red is working on a NAS machine).

Any idea ? nodered-ademco-import error

jlong23 commented 2 years ago

Looks like GitHub isn't escaping the JavaScript in the JSON, try \"\" in that location. (Quotes should be escaped when embedded by... Quotes.

jlong23 commented 2 years ago

// Content in the first Flow outside JSON

var partition = msg.payload;

if( partition !== undefined ) { var alarmText = "";

// Format for core alarm State
alarmText += "Partition ";
alarmText += partition.partitionNumber;
alarmText += " is ";
var alarmState = "";
switch ( partition.systemState ) {
    case 0:
        alarmState += "DISARMED";
        break;
    case 1:
        aalarmState += "NOT READY";
        break;
    case 2:
        alarmState += "DISARMED READY";
        break;
    case 3:
        alarmState += "ARMED AWAY";
        break;
    case 4:
        alarmState += "ARMED STAY";
        break;
    case 5:
        alarmState += "ARMED INSTANT";
        break;
    case 6:
        alarmState += "ALARM";
        break;
    case 7:
        alarmState += "FIRE ALARM";
        break;
    default:
        alarmState += "UNKNOWN";
        break;          
} 

alarmText += alarmState;

msg.topic = partition.partitionNumber;
global.set( "partion_" + partition.partitionNumber + "_state", alarmState );

// Format for Alarms and Faults
if(  partition.systemState >= 6  ||  partition.systemState == 1 ) {
    alarmText += "; ";
    alarmText += partition.messageLine1.trim();
    alarmText +=  "  ";
    alarmText += partition.messageLine2.trim();         
}

msg.payload = alarmText;

// Route the Messages to the correct output
// Critical Events are Sent on Output 2
if( partition.systemState > 2 ) {
    return [ null, msg ];
} else {
    // Status Events are sent on Output 1 
    if ( partition.systemState == 2 && partition.lastSystemState > 2 ) {
        // Unless it's transition from Higher States to Ready/Disarmed
        return [ null, msg ];
    } else {
        // Non Critical Events are Sent on Output 1
        return [ msg, null ];
    }
}

}

// Fail to parse return [null, null];