<?xml version="1.0" encoding="utf-8"?>
<Templates format="2" protocolVersion="83">
  <Template id="b3f7c2a1-4e85-4d19-9f0a-7c6d2e8b1a3f" revision="1.0">
    <RevisionHistory>
      <Revision id="1.0">Initial version — community template, tested with a simulator only</Revision>
    </RevisionHistory>
    <Name>Paradox EVO + PRT3</Name>
    <CcuModel>PacketParserCCU</CcuModel>
    <Producer>Paradox</Producer>
    <Model>EVO + PRT3</Model>
    <Description>Paradox EVO alarm panel integration via PRT3 Printer Module ASCII protocol over TCP.</Description>
    <Category>4</Category>
    <ImportParameters>
      <Parameter>
        <Id>converterIp</Id>
        <Name>IP address of the RS-232 to Ethernet converter (TCP server)</Name>
        <Value>192.168.1.100</Value>
      </Parameter>
      <Parameter>
        <Id>converterPort</Id>
        <Name>TCP port of the converter</Name>
        <Value>4001</Value>
      </Parameter>
      <Parameter>
        <Id>areaNum</Id>
        <Name>Area number (3 digits, 001 to 008)</Name>
        <Value>001</Value>
      </Parameter>
      <Parameter>
        <Id>zone1Num</Id>
        <Name>Zone 1 number (3 digits, 001 to 192)</Name>
        <Value>001</Value>
      </Parameter>
      <Parameter>
        <Id>zone2Num</Id>
        <Name>Zone 2 number</Name>
        <Value>002</Value>
      </Parameter>
      <Parameter>
        <Id>zone3Num</Id>
        <Name>Zone 3 number</Name>
        <Value>003</Value>
      </Parameter>
      <Parameter>
        <Id>zone4Num</Id>
        <Name>Zone 4 number</Name>
        <Value>004</Value>
      </Parameter>
      <Parameter>
        <Id>pgmNum</Id>
        <Name>Virtual PGM number (2 digits, 01 to 30)</Name>
        <Value>01</Value>
      </Parameter>
      <Parameter>
        <Id>userCode</Id>
        <Name>User code of a panel user created for TapHome (4 to 6 digits)</Name>
        <Value/>
      </Parameter>
    </ImportParameters>
    <Module>
      <Name>Paradox PRT3</Name>
      <Id>-1</Id>
      <Model>PacketParserModuleTcp</Model>
      <DeviceProperties>
        <IpAddress>$[converterIp]</IpAddress>
        <Port>$[converterPort]</Port>
        <StayConnected>True</StayConnected>
        <InternalPollInterval>5000</InternalPollInterval>
        <MessageFramingDefinition>{&quot;Framing&quot;:1,&quot;Configuration&quot;:&quot;{\&quot;SendMessageBeginDelimiter\&quot;:null,\&quot;SendMessageEndDelimiter\&quot;:\&quot;DQ==\&quot;,\&quot;ReceiveMessageBeginDelimiter\&quot;:null,\&quot;ReceiveMessageEndDelimiter\&quot;:\&quot;DQ==\&quot;}&quot;}</MessageFramingDefinition>
        <CustomVariables>[{&quot;Name&quot;:&quot;AreaNum&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[areaNum]&quot;},{&quot;Name&quot;:&quot;Zone1Num&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone1Num]&quot;},{&quot;Name&quot;:&quot;Zone2Num&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone2Num]&quot;},{&quot;Name&quot;:&quot;Zone3Num&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone3Num]&quot;},{&quot;Name&quot;:&quot;Zone4Num&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone4Num]&quot;},{&quot;Name&quot;:&quot;PgmNum&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[pgmNum]&quot;},{&quot;Name&quot;:&quot;UserCode&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[userCode]&quot;},{&quot;Name&quot;:&quot;CommFail&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0}]</CustomVariables>
        <ReadScriptPacketParser># Poll the area and the four zones; every command ends with CR (framing)
SENDDATA(&quot;RA&quot; + AreaNum);
SENDDATA(&quot;RZ&quot; + Zone1Num);
SENDDATA(&quot;RZ&quot; + Zone2Num);
SENDDATA(&quot;RZ&quot; + Zone3Num);
SENDDATA(&quot;RZ&quot; + Zone4Num);</ReadScriptPacketParser>
        <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
IF INDEXOF(msg, &quot;COMM&amp;fail&quot;) = 0
    CommFail := 1;
END
IF INDEXOF(msg, &quot;COMM&amp;ok&quot;) = 0
    CommFail := 0;
END
IF CommFail = 1
    ADDERROR(1, &quot;PRT3 reports COMM&amp;fail: no communication between the PRT3 module and the panel&quot;);
END</ListenerScriptPacketParser>
      </DeviceProperties>
      <Devices>
        <Device>
          <Name>Area</Name>
          <Id>-2</Id>
          <Model>PacketParserMultiValueSwitch</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <StartupValueSource>ReadFromDevice</StartupValueSource>
            <CustomVariables>[{&quot;Name&quot;:&quot;AreaTrouble&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;AreaMemory&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;CodeFailed&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0}]</CustomVariables>
            <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
# Area status: RA&lt;nnn&gt; + state (D, A, F, S, I) + M T N P A S, each O when OK
IF INDEXOF(msg, &quot;RA&quot; + AreaNum) = 0 AND LENGTH(msg) &gt;= 12
    VAR st := GETAT(RECEIVEDBYTES, 5);
    IF GETAT(RECEIVEDBYTES, 10) = 65
        Mu := 5;
    ELSEIF st = 68
        Mu := 0;
    ELSEIF st = 65
        Mu := 1;
    ELSEIF st = 70
        Mu := 2;
    ELSEIF st = 83
        Mu := 3;
    ELSEIF st = 73
        Mu := 4;
    END
    AreaMemory := IF(GETAT(RECEIVEDBYTES, 6) = 77, 1, 0);
    AreaTrouble := IF(GETAT(RECEIVEDBYTES, 7) = 84, 1, 0);
END
# Answer to an arming or disarming command of this area
IF INDEXOF(msg, &quot;AA&quot; + AreaNum) = 0 OR INDEXOF(msg, &quot;AD&quot; + AreaNum) = 0
    CodeFailed := IF(INDEXOF(msg, &quot;&amp;fail&quot;) &gt; 0, 1, 0);
END
IF CodeFailed = 1
    ADDWARNING(1, &quot;The panel refused the last arming or disarming command (&amp;fail): check the user code&quot;);
END
IF AreaTrouble = 1
    ADDWARNING(2, &quot;Trouble in the area&quot;);
END
IF AreaMemory = 1
    ADDWARNING(3, &quot;Alarm in memory&quot;);
END</ListenerScriptPacketParser>
            <ReadSwitchStateScriptPacketParser>RETURN(Mu);</ReadSwitchStateScriptPacketParser>
            <WriteSwitchStateScriptPacketParser># Alarm (5) is reported by the panel and is never a command
IF Mu = 0
    SENDDATA(&quot;AD&quot; + AreaNum + UserCode);
ELSEIF Mu = 1
    SENDDATA(&quot;AA&quot; + AreaNum + &quot;A&quot; + UserCode);
ELSEIF Mu = 2
    SENDDATA(&quot;AA&quot; + AreaNum + &quot;F&quot; + UserCode);
ELSEIF Mu = 3
    SENDDATA(&quot;AA&quot; + AreaNum + &quot;S&quot; + UserCode);
ELSEIF Mu = 4
    SENDDATA(&quot;AA&quot; + AreaNum + &quot;I&quot; + UserCode);
END
IF Mu &lt; 5
    SENDDATA(&quot;RA&quot; + AreaNum);
END</WriteSwitchStateScriptPacketParser>
            <Value0>0</Value0>
            <Value0Index>0</Value0Index>
            <Value0Name>Disarmed</Value0Name>
            <Value0IconId>85</Value0IconId>
            <Value1>1</Value1>
            <Value1Index>1</Value1Index>
            <Value1Name>Armed</Value1Name>
            <Value1IconId>84</Value1IconId>
            <Value2>2</Value2>
            <Value2Index>2</Value2Index>
            <Value2Name>Force Armed</Value2Name>
            <Value2IconId>45</Value2IconId>
            <Value3>3</Value3>
            <Value3Index>3</Value3Index>
            <Value3Name>Armed Stay</Value3Name>
            <Value3IconId>37</Value3IconId>
            <Value4>4</Value4>
            <Value4Index>4</Value4Index>
            <Value4Name>Armed Instant</Value4Name>
            <Value4IconId>16</Value4IconId>
            <Value5>5</Value5>
            <Value5Index>5</Value5Index>
            <Value5Name>Alarm</Value5Name>
            <Value5IconId>19</Value5IconId>
            <Value6Index>70</Value6Index>
            <Value7Index>71</Value7Index>
            <Value8Index>72</Value8Index>
            <Value9Index>73</Value9Index>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Zone 1</Name>
          <Id>-3</Id>
          <Model>PacketParserReedContact</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <OnStateIconId>87</OnStateIconId>
            <OffStateIconId>88</OffStateIconId>
            <OnStateName>Open</OnStateName>
            <OffStateName>Closed</OffStateName>
            <CustomVariables>[{&quot;Name&quot;:&quot;ZoneNum&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone1Num]&quot;},{&quot;Name&quot;:&quot;ZTamper&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFireLoop&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZAlarm&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFire&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZSupervision&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZBattery&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0}]</CustomVariables>
            <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
# Zone status: RZ&lt;nnn&gt; + C, O, T, F + A F S L, each O when OK
IF INDEXOF(msg, &quot;RZ&quot; + ZoneNum) = 0 AND LENGTH(msg) &gt;= 10
    VAR st := GETAT(RECEIVEDBYTES, 5);
    Rc := IF(st = 67, 0, 1);
    ZTamper := IF(st = 84, 1, 0);
    ZFireLoop := IF(st = 70, 1, 0);
    ZAlarm := IF(GETAT(RECEIVEDBYTES, 6) = 65, 1, 0);
    ZFire := IF(GETAT(RECEIVEDBYTES, 7) = 70, 1, 0);
    ZSupervision := IF(GETAT(RECEIVEDBYTES, 8) = 83, 1, 0);
    ZBattery := IF(GETAT(RECEIVEDBYTES, 9) = 76, 1, 0);
END
# Warnings are rebuilt from the stored zone state on every message
IF ZAlarm = 1
    ADDWARNING(1, &quot;Zone in alarm&quot;);
END
IF ZFire = 1
    ADDWARNING(2, &quot;Fire alarm&quot;);
END
IF ZTamper = 1
    ADDWARNING(3, &quot;Zone tampered&quot;);
END
IF ZFireLoop = 1
    ADDWARNING(4, &quot;Fire loop trouble&quot;);
END
IF ZSupervision = 1
    ADDWARNING(5, &quot;Supervision lost&quot;);
END
IF ZBattery = 1
    ADDWARNING(6, &quot;Low battery&quot;);
END</ListenerScriptPacketParser>
            <ReadStateScriptPacketParser>RETURN(Rc);</ReadStateScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Zone 2</Name>
          <Id>-4</Id>
          <Model>PacketParserReedContact</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <OnStateIconId>87</OnStateIconId>
            <OffStateIconId>88</OffStateIconId>
            <OnStateName>Open</OnStateName>
            <OffStateName>Closed</OffStateName>
            <CustomVariables>[{&quot;Name&quot;:&quot;ZoneNum&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone2Num]&quot;},{&quot;Name&quot;:&quot;ZTamper&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFireLoop&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZAlarm&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFire&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZSupervision&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZBattery&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0}]</CustomVariables>
            <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
# Zone status: RZ&lt;nnn&gt; + C, O, T, F + A F S L, each O when OK
IF INDEXOF(msg, &quot;RZ&quot; + ZoneNum) = 0 AND LENGTH(msg) &gt;= 10
    VAR st := GETAT(RECEIVEDBYTES, 5);
    Rc := IF(st = 67, 0, 1);
    ZTamper := IF(st = 84, 1, 0);
    ZFireLoop := IF(st = 70, 1, 0);
    ZAlarm := IF(GETAT(RECEIVEDBYTES, 6) = 65, 1, 0);
    ZFire := IF(GETAT(RECEIVEDBYTES, 7) = 70, 1, 0);
    ZSupervision := IF(GETAT(RECEIVEDBYTES, 8) = 83, 1, 0);
    ZBattery := IF(GETAT(RECEIVEDBYTES, 9) = 76, 1, 0);
END
# Warnings are rebuilt from the stored zone state on every message
IF ZAlarm = 1
    ADDWARNING(1, &quot;Zone in alarm&quot;);
END
IF ZFire = 1
    ADDWARNING(2, &quot;Fire alarm&quot;);
END
IF ZTamper = 1
    ADDWARNING(3, &quot;Zone tampered&quot;);
END
IF ZFireLoop = 1
    ADDWARNING(4, &quot;Fire loop trouble&quot;);
END
IF ZSupervision = 1
    ADDWARNING(5, &quot;Supervision lost&quot;);
END
IF ZBattery = 1
    ADDWARNING(6, &quot;Low battery&quot;);
END</ListenerScriptPacketParser>
            <ReadStateScriptPacketParser>RETURN(Rc);</ReadStateScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Zone 3</Name>
          <Id>-5</Id>
          <Model>PacketParserReedContact</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <OnStateIconId>87</OnStateIconId>
            <OffStateIconId>88</OffStateIconId>
            <OnStateName>Open</OnStateName>
            <OffStateName>Closed</OffStateName>
            <CustomVariables>[{&quot;Name&quot;:&quot;ZoneNum&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone3Num]&quot;},{&quot;Name&quot;:&quot;ZTamper&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFireLoop&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZAlarm&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFire&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZSupervision&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZBattery&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0}]</CustomVariables>
            <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
# Zone status: RZ&lt;nnn&gt; + C, O, T, F + A F S L, each O when OK
IF INDEXOF(msg, &quot;RZ&quot; + ZoneNum) = 0 AND LENGTH(msg) &gt;= 10
    VAR st := GETAT(RECEIVEDBYTES, 5);
    Rc := IF(st = 67, 0, 1);
    ZTamper := IF(st = 84, 1, 0);
    ZFireLoop := IF(st = 70, 1, 0);
    ZAlarm := IF(GETAT(RECEIVEDBYTES, 6) = 65, 1, 0);
    ZFire := IF(GETAT(RECEIVEDBYTES, 7) = 70, 1, 0);
    ZSupervision := IF(GETAT(RECEIVEDBYTES, 8) = 83, 1, 0);
    ZBattery := IF(GETAT(RECEIVEDBYTES, 9) = 76, 1, 0);
END
# Warnings are rebuilt from the stored zone state on every message
IF ZAlarm = 1
    ADDWARNING(1, &quot;Zone in alarm&quot;);
END
IF ZFire = 1
    ADDWARNING(2, &quot;Fire alarm&quot;);
END
IF ZTamper = 1
    ADDWARNING(3, &quot;Zone tampered&quot;);
END
IF ZFireLoop = 1
    ADDWARNING(4, &quot;Fire loop trouble&quot;);
END
IF ZSupervision = 1
    ADDWARNING(5, &quot;Supervision lost&quot;);
END
IF ZBattery = 1
    ADDWARNING(6, &quot;Low battery&quot;);
END</ListenerScriptPacketParser>
            <ReadStateScriptPacketParser>RETURN(Rc);</ReadStateScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Zone 4</Name>
          <Id>-6</Id>
          <Model>PacketParserReedContact</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <OnStateIconId>87</OnStateIconId>
            <OffStateIconId>88</OffStateIconId>
            <OnStateName>Open</OnStateName>
            <OffStateName>Closed</OffStateName>
            <CustomVariables>[{&quot;Name&quot;:&quot;ZoneNum&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[zone4Num]&quot;},{&quot;Name&quot;:&quot;ZTamper&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFireLoop&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZAlarm&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZFire&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZSupervision&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0},{&quot;Name&quot;:&quot;ZBattery&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0}]</CustomVariables>
            <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
# Zone status: RZ&lt;nnn&gt; + C, O, T, F + A F S L, each O when OK
IF INDEXOF(msg, &quot;RZ&quot; + ZoneNum) = 0 AND LENGTH(msg) &gt;= 10
    VAR st := GETAT(RECEIVEDBYTES, 5);
    Rc := IF(st = 67, 0, 1);
    ZTamper := IF(st = 84, 1, 0);
    ZFireLoop := IF(st = 70, 1, 0);
    ZAlarm := IF(GETAT(RECEIVEDBYTES, 6) = 65, 1, 0);
    ZFire := IF(GETAT(RECEIVEDBYTES, 7) = 70, 1, 0);
    ZSupervision := IF(GETAT(RECEIVEDBYTES, 8) = 83, 1, 0);
    ZBattery := IF(GETAT(RECEIVEDBYTES, 9) = 76, 1, 0);
END
# Warnings are rebuilt from the stored zone state on every message
IF ZAlarm = 1
    ADDWARNING(1, &quot;Zone in alarm&quot;);
END
IF ZFire = 1
    ADDWARNING(2, &quot;Fire alarm&quot;);
END
IF ZTamper = 1
    ADDWARNING(3, &quot;Zone tampered&quot;);
END
IF ZFireLoop = 1
    ADDWARNING(4, &quot;Fire loop trouble&quot;);
END
IF ZSupervision = 1
    ADDWARNING(5, &quot;Supervision lost&quot;);
END
IF ZBattery = 1
    ADDWARNING(6, &quot;Low battery&quot;);
END</ListenerScriptPacketParser>
            <ReadStateScriptPacketParser>RETURN(Rc);</ReadStateScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Virtual PGM</Name>
          <Id>-7</Id>
          <Model>PacketParserReedContact</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <OnStateIconId>87</OnStateIconId>
            <OffStateIconId>88</OffStateIconId>
            <OnStateName>On</OnStateName>
            <OffStateName>Off</OffStateName>
            <ListenerScriptPacketParser>VAR msg := TOSTRING(RECEIVEDBYTES);
IF INDEXOF(msg, &quot;PGM&quot; + PgmNum + &quot;ON&quot;) = 0
    Rc := 1;
END
IF INDEXOF(msg, &quot;PGM&quot; + PgmNum + &quot;OFF&quot;) = 0
    Rc := 0;
END</ListenerScriptPacketParser>
            <ReadStateScriptPacketParser>RETURN(Rc);</ReadStateScriptPacketParser>
          </DeviceProperties>
        </Device>
      </Devices>
    </Module>
  </Template>
</Templates>
