<?xml version="1.0" encoding="utf-8"?>
<Templates format="2" protocolVersion="83">
  <Template id="fd00ef89-917d-40e5-b616-4f39703a451f" revision="1.0">
    <Name>Somfy TaHoma (HTTP)</Name>
    <CcuModel>PacketParserCCU</CcuModel>
    <Producer>Somfy</Producer>
    <Model>TaHoma</Model>
    <Description>Somfy TaHoma gateway — local REST API via Developer Mode. Controls io-homecontrol roller shutters, venetian blinds, and RTS motors.</Description>
    <Category>3</Category>
    <ImportParameters>
      <Parameter>
        <Id>GatewayAddress</Id>
        <Name>Gateway address (IP or hostname, e.g. gateway-1234-5678-9012.local)</Name>
        <Value>192.168.1.100</Value>
      </Parameter>
      <Parameter>
        <Id>BearerToken</Id>
        <Name>Bearer token (from TaHoma By Somfy app → Developer Mode)</Name>
        <Value/>
      </Parameter>
      <Parameter>
        <Id>SlideDeviceUrl</Id>
        <Name>io Roller Shutter / Awning device URL (e.g. io://1234-5678-9012/12345678)</Name>
        <Value>io://1234-5678-9012/12345678</Value>
      </Parameter>
      <Parameter>
        <Id>BlindDeviceUrl</Id>
        <Name>io Venetian Blind device URL (e.g. io://1234-5678-9012/12345678)</Name>
        <Value>io://1234-5678-9012/12345678</Value>
      </Parameter>
      <Parameter>
        <Id>RtsDeviceUrl</Id>
        <Name>RTS Motor device URL (e.g. rts://1234-5678-9012/12345678)</Name>
        <Value>rts://1234-5678-9012/12345678</Value>
      </Parameter>
    </ImportParameters>
    <Module>
      <Name>Somfy TaHoma Gateway</Name>
      <Id>-1</Id>
      <Model>PacketParserModuleHttp</Model>
      <DeviceProperties>
        <IpAddress>$[GatewayAddress]</IpAddress>
        <Port>8443</Port>
        <UseHttps>True</UseHttps>
        <IgnoreSSLErrors>True</IgnoreSSLErrors>
        <HttpAuthentification>0</HttpAuthentification>
        <InternalPollInterval>30000</InternalPollInterval>
        <CustomVariables>[{&quot;Name&quot;:&quot;BearerToken&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[BearerToken]&quot;},{&quot;Name&quot;:&quot;ApiVersion&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;GatewayData&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
        <ReadScriptPacketParser>VAR r := SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/apiVersion&quot;);
IF r.IsSuccess
    ApiVersion := r.Content;
END

r := SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/setup/gateways&quot;, &quot;GET&quot;, &quot;&quot;, &quot;Authorization: Bearer &quot; + BearerToken);
IF r.StatusCode = 401
    ADDERROR(0, &quot;Check Bearer token in TaHoma By Somfy app → Developer Mode&quot;);
ELSEIF r.IsSuccess
    GatewayData := r.Content;
END</ReadScriptPacketParser>
        <ServiceAttributesScriptsPacketParser>[{&quot;AttributeDefinition&quot;:{&quot;Name&quot;:&quot;Protocol Version&quot;},&quot;ReadFormula&quot;:&quot;PARSEJSON(ApiVersion, \&quot;$.protocolVersion\&quot;, true)&quot;},{&quot;AttributeDefinition&quot;:{&quot;Name&quot;:&quot;Gateway ID&quot;},&quot;ReadFormula&quot;:&quot;PARSEJSON(GatewayData, \&quot;[0].gatewayId\&quot;, true)&quot;},{&quot;AttributeDefinition&quot;:{&quot;Name&quot;:&quot;Connectivity Status&quot;},&quot;ReadFormula&quot;:&quot;PARSEJSON(GatewayData, \&quot;[0].connectivity.status\&quot;, true)&quot;}]</ServiceAttributesScriptsPacketParser>
      </DeviceProperties>
      <Devices>
        <Device>
          <Name>io Roller Shutter</Name>
          <Id>-2</Id>
          <Model>PacketParserSlide</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>5000</InternalPollInterval>
            <ShouldDoPeriodicWrite>False</ShouldDoPeriodicWrite>
            <CustomVariables>[{&quot;Name&quot;:&quot;DeviceUrl&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[SlideDeviceUrl]&quot;},{&quot;Name&quot;:&quot;StatesJson&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
            <ReadScriptPacketParser>VAR encodedUrl := REPLACE(REPLACE(DeviceUrl, &quot;:&quot;, &quot;%3A&quot;), &quot;/&quot;, &quot;%2F&quot;);
VAR r := SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/setup/devices/&quot; + encodedUrl + &quot;/states/core%3AClosureState&quot;, &quot;GET&quot;, &quot;&quot;, &quot;Authorization: Bearer &quot; + BearerToken);
IF r.StatusCode = 401
    ADDERROR(0, &quot;Check Bearer token in TaHoma By Somfy app → Developer Mode&quot;);
ELSEIF r.IsSuccess
    StatesJson := r.Content;
ELSE
    ADDERROR(1, &quot;Device unavailable (HTTP &quot; + r.StatusCode + &quot;)&quot;);
END</ReadScriptPacketParser>
            <ReadBlindsLevelScriptPacketParser>VAR closure := PARSEJSON(StatesJson, &quot;$.value&quot;, true);
IF ISNULL(closure)
    ADDERROR(0, &quot;Closure state not available&quot;);
    RETURN(NaN);
END
RETURN(closure / 100);</ReadBlindsLevelScriptPacketParser>
            <WriteBlindsLevelScriptPacketParser>VAR pos := ROUND(Bl * 100);
VAR body := &quot;{\&quot;label\&quot;:\&quot;Set roller shutter\&quot;,\&quot;actions\&quot;:[{\&quot;deviceURL\&quot;:\&quot;&quot; + DeviceUrl + &quot;\&quot;,\&quot;commands\&quot;:[{\&quot;name\&quot;:\&quot;setClosure\&quot;,\&quot;parameters\&quot;:[&quot; + pos + &quot;]}]}]}&quot;;
SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/exec/apply&quot;, &quot;POST&quot;, body, &quot;Authorization: Bearer &quot; + BearerToken, &quot;Content-Type: application/json&quot;);</WriteBlindsLevelScriptPacketParser>
            <StartupValueSource>ReadFromDevice</StartupValueSource>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>io Venetian Blind</Name>
          <Id>-3</Id>
          <Model>PacketParserBlind</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>5000</InternalPollInterval>
            <ShouldDoPeriodicWrite>False</ShouldDoPeriodicWrite>
            <CustomVariables>[{&quot;Name&quot;:&quot;DeviceUrl&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[BlindDeviceUrl]&quot;},{&quot;Name&quot;:&quot;StatesJson&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;LastBody&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;},{&quot;Name&quot;:&quot;LastSentAt&quot;,&quot;ValueTypeId&quot;:1,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;&quot;}]</CustomVariables>
            <ReadScriptPacketParser>VAR encodedUrl := REPLACE(REPLACE(DeviceUrl, &quot;:&quot;, &quot;%3A&quot;), &quot;/&quot;, &quot;%2F&quot;);
VAR r := SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/setup/devices/&quot; + encodedUrl + &quot;/states&quot;, &quot;GET&quot;, &quot;&quot;, &quot;Authorization: Bearer &quot; + BearerToken);
IF r.StatusCode = 401
    ADDERROR(0, &quot;Check Bearer token in TaHoma By Somfy app → Developer Mode&quot;);
ELSEIF r.IsSuccess
    StatesJson := r.Content;
ELSE
    ADDERROR(1, &quot;Device unavailable (HTTP &quot; + r.StatusCode + &quot;)&quot;);
END</ReadScriptPacketParser>
            <ReadBlindLevelScriptPacketParser>VAR closure := PARSEJSON(StatesJson, &quot;$[?(@.name==&apos;core:ClosureState&apos;)].value&quot;, true);
IF ISNULL(closure)
    ADDERROR(0, &quot;Closure state not available&quot;);
    RETURN(NaN);
END
RETURN(closure / 100);</ReadBlindLevelScriptPacketParser>
            <ReadBlindSlopeScriptPacketParser>VAR orientation := PARSEJSON(StatesJson, &quot;$[?(@.name==&apos;core:SlateOrientationState&apos;)].value&quot;, true);
IF ISNULL(orientation)
    RETURN(NaN);
END
RETURN(orientation / 100);</ReadBlindSlopeScriptPacketParser>
            <WriteBlindLevelScriptPacketParser>VAR pos := ROUND(Bl * 100);
VAR ori := ROUND(Bs * 100);
VAR body := &quot;{\&quot;label\&quot;:\&quot;Set venetian blind\&quot;,\&quot;actions\&quot;:[{\&quot;deviceURL\&quot;:\&quot;&quot; + DeviceUrl + &quot;\&quot;,\&quot;commands\&quot;:[{\&quot;name\&quot;:\&quot;setClosureAndOrientation\&quot;,\&quot;parameters\&quot;:[&quot; + pos + &quot;,&quot; + ori + &quot;]}]}]}&quot;;
VAR date := NOW();
IF body != LastBody OR date.UNIXTIME - LastSentAt &gt; 3
    SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/exec/apply&quot;, &quot;POST&quot;, body, &quot;Authorization: Bearer &quot; + BearerToken, &quot;Content-Type: application/json&quot;);
    LastBody := body;
    LastSentAt := date.UNIXTIME;
END</WriteBlindLevelScriptPacketParser>
            <WriteBlindSlopeScriptPacketParser>VAR pos := ROUND(Bl * 100);
VAR ori := ROUND(Bs * 100);
VAR body := &quot;{\&quot;label\&quot;:\&quot;Set venetian blind\&quot;,\&quot;actions\&quot;:[{\&quot;deviceURL\&quot;:\&quot;&quot; + DeviceUrl + &quot;\&quot;,\&quot;commands\&quot;:[{\&quot;name\&quot;:\&quot;setClosureAndOrientation\&quot;,\&quot;parameters\&quot;:[&quot; + pos + &quot;,&quot; + ori + &quot;]}]}]}&quot;;
VAR date := NOW();
IF body != LastBody OR date.UNIXTIME - LastSentAt &gt; 3
    SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/exec/apply&quot;, &quot;POST&quot;, body, &quot;Authorization: Bearer &quot; + BearerToken, &quot;Content-Type: application/json&quot;);
    LastBody := body;
    LastSentAt := date.UNIXTIME;
END</WriteBlindSlopeScriptPacketParser>
            <StartupValueSource>ReadFromDevice</StartupValueSource>
            <OnStateIconId>295</OnStateIconId>
            <OffStateIconId>296</OffStateIconId>
          </DeviceProperties>
        </Device>
        <Device>
          <Name>RTS Motor</Name>
          <Id>-4</Id>
          <Model>PacketParserMultiValueSwitch</Model>
          <DeviceProperties>
            <DeviceType>0</DeviceType>
            <InternalPollInterval>5000</InternalPollInterval>
            <CustomVariables>[{&quot;Name&quot;:&quot;DeviceUrl&quot;,&quot;ValueTypeId&quot;:2,&quot;NumericValue&quot;:0,&quot;StringValue&quot;:&quot;$[RtsDeviceUrl]&quot;}]</CustomVariables>
            <ReadSwitchStateScriptPacketParser>RETURN(0);</ReadSwitchStateScriptPacketParser>
            <WriteSwitchStateScriptPacketParser>VAR cmd := SWITCH(Mu, 1, &quot;open&quot;, 2, &quot;my&quot;, 3, &quot;stop&quot;, 4, &quot;close&quot;, &quot;stop&quot;);
VAR body := &quot;{\&quot;label\&quot;:\&quot;RTS command\&quot;,\&quot;actions\&quot;:[{\&quot;deviceURL\&quot;:\&quot;&quot; + DeviceUrl + &quot;\&quot;,\&quot;commands\&quot;:[{\&quot;name\&quot;:\&quot;&quot; + cmd + &quot;\&quot;,\&quot;parameters\&quot;:[]}]}]}&quot;;
SENDHTTPREQUEST(&quot;/enduser-mobile-web/1/enduserAPI/exec/apply&quot;, &quot;POST&quot;, body, &quot;Authorization: Bearer &quot; + BearerToken, &quot;Content-Type: application/json&quot;);</WriteSwitchStateScriptPacketParser>
            <StartupValueSource>ReadFromDevice</StartupValueSource>
            <Value0>0</Value0>
            <Value0Index>0</Value0Index>
            <Value0Name>Ready</Value0Name>
            <Value0IconId>86</Value0IconId>
            <Value1>1</Value1>
            <Value1Index>1</Value1Index>
            <Value1Name>Open</Value1Name>
            <Value1IconId>260</Value1IconId>
            <Value2>2</Value2>
            <Value2Index>2</Value2Index>
            <Value2Name>My</Value2Name>
            <Value2IconId>218</Value2IconId>
            <Value3>3</Value3>
            <Value3Index>3</Value3Index>
            <Value3Name>Stop</Value3Name>
            <Value3IconId>215</Value3IconId>
            <Value4>4</Value4>
            <Value4Index>4</Value4Index>
            <Value4Name>Close</Value4Name>
            <Value4IconId>261</Value4IconId>
            <Value5Index>69</Value5Index>
            <Value6Index>70</Value6Index>
            <Value7Index>71</Value7Index>
            <Value8Index>72</Value8Index>
            <Value9Index>73</Value9Index>
          </DeviceProperties>
        </Device>
      </Devices>
    </Module>
  </Template>
</Templates>
