<?xml version="1.0" encoding="utf-8"?>
<Templates format="2" protocolVersion="83">
  <Template id="cf492265-bf84-452b-a0a9-a23cdf0a02dd" revision="1.1">
    <RevisionHistory>
      <Revision id="1.1">Name lists only the heat pump brands EMS-ESP documents (Bosch, Buderus, IVT); Junkers and Nefit removed.</Revision>
    </RevisionHistory>
    <Name>EMS-ESP Heat Pump (Bosch/Buderus/IVT)</Name>
    <CcuModel>PacketParserCCU</CcuModel>
    <Producer>EMS-ESP</Producer>
    <Model>EMS-ESP 3.8.6 Heat Pump</Model>
    <Description>EMS bus heat pump gateway via EMS-ESP 3.8.6 REST API. Supports Bosch/Buderus Compress, Enviline, SupraEco, Geo 5xx, WLW196i/WSW196i and IVT AirX/Geo with RC310/HMC310/Rego 3000/BC400 controller.</Description>
    <Category>1</Category>
    <ImportParameters>
      <Parameter>
        <Id>IpAddress</Id>
        <Name>EMS-ESP IP address</Name>
        <Value/>
      </Parameter>
      <Parameter>
        <Id>AccessToken</Id>
        <Name>EMS-ESP access token (admin user, Settings → Security → Manage Users → key icon)</Name>
        <Value/>
      </Parameter>
    </ImportParameters>
    <Module>
      <Name>EMS-ESP Heat Pump</Name>
      <Id>-1</Id>
      <Model>PacketParserModuleHttp</Model>
      <DeviceProperties>
        <IpAddress>$[IpAddress]</IpAddress>
        <Port>80</Port>
        <UseHttps>False</UseHttps>
        <HttpAuthentification>0</HttpAuthentification>
        <InternalPollInterval>60000</InternalPollInterval>
        <CustomVariables>[{&quot;Name&quot;:&quot;AccessToken&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[AccessToken]&quot;},{&quot;Name&quot;:&quot;SystemInfo&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
        <ReadScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/system/info&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/system/info&quot;);
END
IF r.IsSuccess
    SystemInfo := r.Content;
    IF PARSEJSON(SystemInfo, &quot;$.settings.fahrenheit&quot;, true) = true
        ADDERROR(1, &quot;EMS-ESP reports °F — switch Fahrenheit off in EMS-ESP Settings → Application&quot;);
    END
    IF !ISNULL(PARSEJSON(SystemInfo, &quot;$.system.version&quot;, true))
        VAR ver := TOSTRING(PARSEJSON(SystemInfo, &quot;$.system.version&quot;, true));
        IF INDEXOF(ver, &quot;3.8.&quot;) != 0
            ADDWARNING(0, &quot;Template written for EMS-ESP 3.8.6, gateway reports &quot; + ver);
        END
    END
ELSE
    SystemInfo := &quot;&quot;;
    ADDERROR(0, &quot;system/info: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END</ReadScriptPacketParser>
      </DeviceProperties>
      <Devices>
        <Device>
          <Name>HP Operating Mode hc1</Name>
          <Id>-2</Id>
          <Model>PacketParserMultiValueSwitch</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <IsReadOnly>False</IsReadOnly>
            <ReadSwitchStateScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/hpoperatingmode&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/hpoperatingmode&quot;);
END
IF r.IsSuccess
    VAR idx := PARSEJSON(r.Content, &quot;$.index&quot;, true);
    IF ISNULL(idx)
        ADDERROR(0, &quot;hpoperatingmode: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(TODOUBLE(idx));
ELSE
    ADDERROR(0, &quot;hpoperatingmode: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadSwitchStateScriptPacketParser>
            <WriteSwitchStateScriptPacketParser>VAR opttext := IF(Mu = 0, &quot;off&quot;, IF(Mu = 1, &quot;auto&quot;, IF(Mu = 2, &quot;heating&quot;, &quot;cooling&quot;)));
VAR body := &quot;{\&quot;value\&quot;:\&quot;&quot; + opttext + &quot;\&quot;}&quot;;
VAR r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/hpoperatingmode&quot;, &quot;POST&quot;, body, &quot;Content-Type: application/json&quot;, &quot;Authorization: Bearer &quot; + AccessToken);
IF r.IsSuccess = false
    IF r.StatusCode = 401
        ADDERROR(0, &quot;hpoperatingmode: access token missing or wrong (EMS-ESP Settings → Security → Manage Users → key icon of an admin user)&quot;);
    ELSE
        ADDERROR(0, &quot;hpoperatingmode write: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    END
END</WriteSwitchStateScriptPacketParser>
            <Value0>0</Value0>
            <Value0Index>0</Value0Index>
            <Value0Name>Off</Value0Name>
            <Value0IconId>4</Value0IconId>
            <Value1>1</Value1>
            <Value1Index>1</Value1Index>
            <Value1Name>Auto</Value1Name>
            <Value1IconId>113</Value1IconId>
            <Value2>2</Value2>
            <Value2Index>2</Value2Index>
            <Value2Name>Heating</Value2Name>
            <Value2IconId>1</Value2IconId>
            <Value3>3</Value3>
            <Value3Index>3</Value3Index>
            <Value3Name>Cooling</Value3Name>
            <Value3IconId>2</Value3IconId>
            <Value4Index>68</Value4Index>
            <Value5Index>69</Value5Index>
            <Value6Index>70</Value6Index>
            <Value7Index>71</Value7Index>
            <Value8Index>72</Value8Index>
            <Value9Index>73</Value9Index>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Room Thermostat hc1</Name>
          <Id>-3</Id>
          <Model>PacketParserThermostat</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <ShouldDoPeriodicWrite>False</ShouldDoPeriodicWrite>
            <MinTemperature>0</MinTemperature>
            <MaxTemperature>30</MaxTemperature>
            <ReadScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/currtemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/currtemp&quot;);
END
IF r.IsSuccess
    CurrTempHc1 := r.Content;
ELSE
    CurrTempHc1 := &quot;&quot;;
    ADDERROR(0, &quot;currtemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END
SLEEP(60);
r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/seltemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/seltemp&quot;);
END
IF r.IsSuccess
    SelTempHc1 := r.Content;
ELSE
    SelTempHc1 := &quot;&quot;;
    ADDERROR(1, &quot;seltemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END</ReadScriptPacketParser>
            <CustomVariables>[{&quot;Name&quot;:&quot;CurrTempHc1&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;SelTempHc1&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
            <ReadCurrentTemperatureScriptPacketParser>IF CurrTempHc1 = &quot;&quot;
    RETURN(NaN);
END
VAR v := PARSEJSON(CurrTempHc1, &quot;$.value&quot;, true);
IF ISNULL(v)
    ADDERROR(0, &quot;currtemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
    RETURN(NaN);
END
RETURN(TODOUBLE(v));</ReadCurrentTemperatureScriptPacketParser>
            <ReadTemperatureSetPointScriptPacketParser>IF SelTempHc1 = &quot;&quot;
    RETURN(NaN);
END
VAR v := PARSEJSON(SelTempHc1, &quot;$.value&quot;, true);
IF ISNULL(v)
    ADDERROR(1, &quot;seltemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
    RETURN(NaN);
END
RETURN(TODOUBLE(v));</ReadTemperatureSetPointScriptPacketParser>
            <WriteTemperatureSetPointScriptPacketParser>VAR body := &quot;{\&quot;value\&quot;:&quot; + Se + &quot;}&quot;;
VAR r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/seltemp&quot;, &quot;POST&quot;, body, &quot;Content-Type: application/json&quot;, &quot;Authorization: Bearer &quot; + AccessToken);
IF r.IsSuccess = false
    IF r.StatusCode = 401
        ADDERROR(0, &quot;seltemp: access token missing or wrong (EMS-ESP Settings → Security → Manage Users → key icon of an admin user)&quot;);
    ELSE
        ADDERROR(0, &quot;seltemp write: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    END
END</WriteTemperatureSetPointScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Cooling Temperature hc1</Name>
          <Id>-4</Id>
          <Model>PacketParserVariable</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <IsReadOnly>False</IsReadOnly>
            <ReadStateScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/cooltemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/cooltemp&quot;);
END
IF r.IsSuccess
    VAR v := PARSEJSON(r.Content, &quot;$.value&quot;, true);
    IF ISNULL(v)
        ADDERROR(0, &quot;cooltemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(TODOUBLE(v));
ELSE
    ADDERROR(0, &quot;cooltemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadStateScriptPacketParser>
            <WriteStateScriptPacketParser>VAR body := &quot;{\&quot;value\&quot;:&quot; + Va + &quot;}&quot;;
VAR r := SENDHTTPREQUEST(&quot;/api/thermostat/hc1/cooltemp&quot;, &quot;POST&quot;, body, &quot;Content-Type: application/json&quot;, &quot;Authorization: Bearer &quot; + AccessToken);
IF r.IsSuccess = false
    IF r.StatusCode = 401
        ADDERROR(0, &quot;cooltemp: access token missing or wrong (EMS-ESP Settings → Security → Manage Users → key icon of an admin user)&quot;);
    ELSE
        ADDERROR(0, &quot;cooltemp write: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    END
END</WriteStateScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Compressor Activity</Name>
          <Id>-5</Id>
          <Model>PacketParserMultiValueSwitch</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <IsReadOnly>True</IsReadOnly>
            <ReadSwitchStateScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/hpactivity&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/hpactivity&quot;);
END
IF r.IsSuccess
    VAR idx := PARSEJSON(r.Content, &quot;$.index&quot;, true);
    IF ISNULL(idx)
        ADDERROR(0, &quot;hpactivity: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(TODOUBLE(idx));
ELSE
    ADDERROR(0, &quot;hpactivity: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadSwitchStateScriptPacketParser>
            <Value0>0</Value0>
            <Value0Index>0</Value0Index>
            <Value0Name>Off</Value0Name>
            <Value0IconId>4</Value0IconId>
            <Value1>1</Value1>
            <Value1Index>1</Value1Index>
            <Value1Name>Heating</Value1Name>
            <Value1IconId>1</Value1IconId>
            <Value2>2</Value2>
            <Value2Index>2</Value2Index>
            <Value2Name>Cooling</Value2Name>
            <Value2IconId>2</Value2IconId>
            <Value3>3</Value3>
            <Value3Index>3</Value3Index>
            <Value3Name>Hot Water</Value3Name>
            <Value3IconId>113</Value3IconId>
            <Value4>4</Value4>
            <Value4Index>4</Value4Index>
            <Value4Name>Pool</Value4Name>
            <Value4IconId>6</Value4IconId>
            <Value5>5</Value5>
            <Value5Index>5</Value5Index>
            <Value5Name>Pool Heating</Value5Name>
            <Value5IconId>7</Value5IconId>
            <Value6>6</Value6>
            <Value6Index>6</Value6Index>
            <Value6Name>Defrost</Value6Name>
            <Value6IconId>237</Value6IconId>
            <Value7>7</Value7>
            <Value7Index>7</Value7Index>
            <Value7Name>Compressor Alarm</Value7Name>
            <Value7IconId>57</Value7IconId>
            <Value8Index>72</Value8Index>
            <Value9Index>73</Value9Index>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Compressor Running</Name>
          <Id>-6</Id>
          <Model>PacketParserReedContact</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <OnStateIconId>87</OnStateIconId>
            <OffStateIconId>88</OffStateIconId>
            <OnStateName>Running</OnStateName>
            <OffStateName>Stopped</OffStateName>
            <ReadStateScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/hpcompon&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/hpcompon&quot;);
END
IF r.IsSuccess
    VAR b := PARSEJSON(r.Content, &quot;$.bool&quot;, true);
    IF ISNULL(b)
        ADDERROR(0, &quot;hpcompon: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(b);
ELSE
    ADDERROR(0, &quot;hpcompon: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadStateScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Outdoor Temperature</Name>
          <Id>-7</Id>
          <Model>PacketParserTemperatureSensor</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>60000</InternalPollInterval>
            <ReadTemperatureScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/outdoortemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/outdoortemp&quot;);
END
IF r.IsSuccess
    VAR v := PARSEJSON(r.Content, &quot;$.value&quot;, true);
    IF ISNULL(v)
        ADDERROR(0, &quot;outdoortemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(TODOUBLE(v));
ELSE
    ADDERROR(0, &quot;outdoortemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadTemperatureScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Flow Temperature</Name>
          <Id>-8</Id>
          <Model>PacketParserTemperatureSensor</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <ReadTemperatureScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/curflowtemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/curflowtemp&quot;);
END
IF r.IsSuccess
    VAR v := PARSEJSON(r.Content, &quot;$.value&quot;, true);
    IF ISNULL(v)
        ADDERROR(0, &quot;curflowtemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(TODOUBLE(v));
ELSE
    ADDERROR(0, &quot;curflowtemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadTemperatureScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Return Temperature</Name>
          <Id>-9</Id>
          <Model>PacketParserTemperatureSensor</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <ReadTemperatureScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/rettemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/rettemp&quot;);
END
IF r.IsSuccess
    VAR v := PARSEJSON(r.Content, &quot;$.value&quot;, true);
    IF ISNULL(v)
        ADDERROR(0, &quot;rettemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
        RETURN(NaN);
    END
    RETURN(TODOUBLE(v));
ELSE
    ADDERROR(0, &quot;rettemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    RETURN(NaN);
END</ReadTemperatureScriptPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Electricity Meter (Compressor)</Name>
          <Id>-10</Id>
          <Model>PacketParserElectricityMeter</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>60000</InternalPollInterval>
            <ReadScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/hpcurrpower&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/hpcurrpower&quot;);
END
IF r.IsSuccess
    HpCurrPower := r.Content;
ELSE
    HpCurrPower := &quot;&quot;;
    ADDERROR(0, &quot;hpcurrpower: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END
SLEEP(60);
r := SENDHTTPREQUEST(&quot;/api/boiler/nrgconstotal&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/nrgconstotal&quot;);
END
IF r.IsSuccess
    NrgConsTotal := r.Content;
ELSE
    NrgConsTotal := &quot;&quot;;
    ADDERROR(1, &quot;nrgconstotal: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END
SLEEP(60);
r := SENDHTTPREQUEST(&quot;/api/boiler/nrgtotal&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/nrgtotal&quot;);
END
IF r.IsSuccess
    NrgTotal := r.Content;
    IF ISNULL(PARSEJSON(NrgTotal, &quot;$.value&quot;, true))
        ADDERROR(3, &quot;nrgtotal: no value from the gateway — this unit does not report heat delivered; the attribute stays empty&quot;);
    END
ELSE
    NrgTotal := &quot;&quot;;
    ADDERROR(2, &quot;nrgtotal: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END</ReadScriptPacketParser>
            <CustomVariables>[{&quot;Name&quot;:&quot;HpCurrPower&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;NrgConsTotal&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;NrgTotal&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
            <ReadDemandScriptPacketParser>IF HpCurrPower = &quot;&quot;
    RETURN(NaN);
END
VAR v := PARSEJSON(HpCurrPower, &quot;$.value&quot;, true);
IF ISNULL(v)
    ADDERROR(0, &quot;hpcurrpower: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
    RETURN(NaN);
END
RETURN(TODOUBLE(v) / 1000);</ReadDemandScriptPacketParser>
            <ReadTotalConsumptionScriptPacketParser>IF NrgConsTotal = &quot;&quot;
    RETURN(NaN);
END
VAR v := PARSEJSON(NrgConsTotal, &quot;$.value&quot;, true);
IF ISNULL(v)
    ADDERROR(1, &quot;nrgconstotal: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
    RETURN(NaN);
END
RETURN(TODOUBLE(v));</ReadTotalConsumptionScriptPacketParser>
            <ServiceAttributesScriptsPacketParser>[{&quot;AttributeDefinition&quot;:{&quot;Name&quot;:&quot;Heat delivered [kWh]&quot;},&quot;ReadFormula&quot;:&quot;IF NrgTotal = \&quot;\&quot; RETURN(NaN); END VAR v := PARSEJSON(NrgTotal, \&quot;$.value\&quot;, true); IF ISNULL(v) RETURN(NaN); END RETURN(TODOUBLE(v));&quot;}]</ServiceAttributesScriptsPacketParser>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>Domestic Hot Water</Name>
          <Id>-11</Id>
          <Model>PacketParserThermostat</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>30000</InternalPollInterval>
            <ShouldDoPeriodicWrite>False</ShouldDoPeriodicWrite>
            <MinTemperature>35</MinTemperature>
            <MaxTemperature>70</MaxTemperature>
            <ReadScriptPacketParser>SLEEP(60);
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/dhw/curtemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/dhw/curtemp&quot;);
END
IF r.IsSuccess
    DhwCurTemp := r.Content;
ELSE
    DhwCurTemp := &quot;&quot;;
    ADDERROR(0, &quot;dhw/curtemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END
SLEEP(60);
r := SENDHTTPREQUEST(&quot;/api/boiler/dhw/seltemp&quot;);
IF r.StatusCode = 429
    SLEEP(200);
    r := SENDHTTPREQUEST(&quot;/api/boiler/dhw/seltemp&quot;);
END
IF r.IsSuccess
    DhwSelTemp := r.Content;
ELSE
    DhwSelTemp := &quot;&quot;;
    ADDERROR(1, &quot;dhw/seltemp: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
END</ReadScriptPacketParser>
            <CustomVariables>[{&quot;Name&quot;:&quot;DhwCurTemp&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;DhwSelTemp&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
            <ReadCurrentTemperatureScriptPacketParser>IF DhwCurTemp = &quot;&quot;
    RETURN(NaN);
END
VAR v := PARSEJSON(DhwCurTemp, &quot;$.value&quot;, true);
IF ISNULL(v)
    ADDERROR(0, &quot;dhw/curtemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
    RETURN(NaN);
END
RETURN(TODOUBLE(v));</ReadCurrentTemperatureScriptPacketParser>
            <ReadTemperatureSetPointScriptPacketParser>IF DhwSelTemp = &quot;&quot;
    RETURN(NaN);
END
VAR v := PARSEJSON(DhwSelTemp, &quot;$.value&quot;, true);
IF ISNULL(v)
    ADDERROR(1, &quot;dhw/seltemp: no value from the gateway — this controller or unit does not report it; delete this device&quot;);
    RETURN(NaN);
END
RETURN(TODOUBLE(v));</ReadTemperatureSetPointScriptPacketParser>
            <WriteTemperatureSetPointScriptPacketParser>VAR body := &quot;{\&quot;value\&quot;:&quot; + ROUND(Se) + &quot;}&quot;;
VAR r := SENDHTTPREQUEST(&quot;/api/boiler/dhw/seltemp&quot;, &quot;POST&quot;, body, &quot;Content-Type: application/json&quot;, &quot;Authorization: Bearer &quot; + AccessToken);
IF r.IsSuccess = false
    IF r.StatusCode = 401
        ADDERROR(0, &quot;dhw/seltemp: access token missing or wrong (EMS-ESP Settings → Security → Manage Users → key icon of an admin user)&quot;);
    ELSE
        ADDERROR(0, &quot;dhw/seltemp write: &quot; + r.StatusCode + IF(ISNULL(PARSEJSON(r.Content, &quot;$.message&quot;, true)), &quot;&quot;, &quot; — &quot; + PARSEJSON(r.Content, &quot;$.message&quot;, true)));
    END
END</WriteTemperatureSetPointScriptPacketParser>
          </DeviceProperties>
        </Device>
      </Devices>
    </Module>
  </Template>
</Templates>
