---
title: Comprehensive integration with external systems
description: "Description of the configuration using the relay output as an example.  Assume we have a simple system consisting of the following elements: In order to be able to control the relay output from an ext"
---

[Skip to content](https://knowledgebase.grenton.com/en/grenton-gate-http-comprehensive-integration-with-external-systems#main-content)

English

Show submenu for translations

[New ticket](https://knowledgebase.grenton.com/en/kb-tickets/new?hsLang=en) [Customer portal](https://knowledgebase.grenton.com/wsparcie?hsLang=en)

![Logo\_Grenton\_Main\_2020\_RGB\_v1.0-1.png\]](https://knowledgebase.grenton.com/hs-fs/hubfs/Logo_Grenton_Main_2020_RGB_v1.0-1.png?width=200&height=94&name=Logo_Grenton_Main_2020_RGB_v1.0-1.png)

Open main navigation

Close main navigation

- English
  
  Show submenu for translations
- [New ticket](https://knowledgebase.grenton.com/en/kb-tickets/new)
- [Customer portal](https://knowledgebase.grenton.com/wsparcie)
- [Trainings](https://www.grenton.com/cooperation/trainings.html)

[Trainings](https://www.grenton.com/cooperation/trainings.html)

 Hello. How can we help you?

- There are no suggestions because the search field is empty.

1. [Knowledge Base](https://knowledgebase.grenton.com/en?hsLang=en)
2. [Manuals](https://knowledgebase.grenton.com/en/manuals?hsLang=en)
3. [Gate HTTP](https://knowledgebase.grenton.com/en/manuals?hsLang=en#gate-http)

# Comprehensive integration with external systems

Description of the configuration using the relay output as an example. 

### **System**

Assume we have a simple system consisting of the following elements:

- Z-Wave CLU - named *CluZ*
- Relay module - for the purpose of the example we will use one output named *Relay*
- Gate Http - named *GateHttp*

### **Output control**

In order to be able to control the relay output from an external system, we create a new object of type *HttpListener* on *GateHttp* and configure as below:

- Name: RelayControlListener
- Path: /relaycontrol

We leave the remaining parameters as default.

**Script**

In order for the *RelayControlListener* object to work, a script must be created to handle incoming Http requests.

 

Here it is worth noting that from this script we have access to the entire system and all its functionality. This opens virtually unlimited possibilities, but also generates some risks, especially if the Gate's functionality is not well thought out. Therefore, we pay particular attention that the implementation of Gate's functionality should be well planned, the way we want to achieve and how the Gate's action may depend on or affect other elements of the system. Examples of this approach will also be discussed further on.

 

Back to the *Relay* control script. We want to be able to turn *Relay* on or off by sending it the expected state (On/Off) or by executing a switch method. This approach to the implementation allows you to connect both bistable and monostable switch type control.

 

Moving on to action, we create a script on *GateHttp* called *RelayControlOnRequest*, and in the text mode of creating scripts, we enter what follows:

```
-- RelayControlOnRequest()local data = GateHttp->RelayControlListener->QueryStringParamsif data == nil then  CluZ->Relay->Switch(0)else  if data.cmd == "setValue" then    local val = tonumber(data.val)    if(val == 1) then      CluZ->Relay->SwitchOn(0)    elseif(val == 0) then       CluZ->Relay->SwitchOff(0)    end  endendGateHttp->RelayControlListener->StatusCode = 200GateHttp->RelayControlListener->ResponseBody = "OK"GateHttp->RelayControlListener->SendResponse()
```

 

Next, we assign the script to the* OnRequest* event of the* RelayControlListener* object and send the configuration to the system.

 

The above script gets the values of request parameters from the *RelayControlListener* object and - depending on what them contain - performs the appropriate actions. Then it sends back the operation status to the client - in this case *200, OK.*

 

You can easily test the operation using a regular web browser by entering the following URLs (the IP address should be replaced by the real address of your Gate Http):

http://192.168.88.4/relaycontrol?cmd=setValue&val=1 - turn the *Relay *on

http://192.168.88.4/relaycontrol?cmd=setValue&val=0 - turn the* Relay* off

http://192.168.88.4/relaycontrol - switch the *Relay*’s state

As we see, we can use the* Listener* object in two ways. If the parameter "cmd" (command to execute) and "val" (the value to set) are properly defined then they set the specific state of the *Relay*. If we omit these parameters from the URL, the object acts as a switch.

 

The above example can be further extended by adding more commands if there is a need to execute other commands. You can also add more parameters identifying the object on which the commands should be executed.

**Retrieving the state**

In the previous step, we made it possible to control an object in the system from the outside. Very often in the next step there appears a need to provide also a possibility to retrieve the current state of this object.

 

One of the fastest and most intuitive methods (not necessarily the best one) is to define another Listener, which retrieves a *Value* from *Relay* object and sends it to a client. The simplest script that implements this functionality may look like the one below.

```
-- RelayStateOnRequest()GateHttp->RelayState->StatusCode = 200GateHttp->RelayState->ResponseBody = "Relay State: "..CluZ->Relay->ValueGateHttp->RelayState->SendResponse()
```

 

Entering the following URL into the browser you can see that you get the response with the state of the* Relay* object (in a simple text form, but the format of sending the data is not the topic of this example).

[http://192.168.88.4/relaystate](http://192.168.88.4/relaystate)  - returns "Relay State: 0" or "Relay State: 1" depending on the state of the object.

The above example works fine at first glance but let's take a closer look.

**Sequence of events**

We have just build the Http interface (API) two methods:

- /relaycontrol - allows to control the Relay object
- /relaystate - returns the current state (value) of the Relay object

 

After a first testing everything works fine, but as we wrote above, we still need to think about how such methods will be used. It is easy to imagine that in the external system these two methods will be used right after each other: calling the switch action and after receiving the response, reading the state in order to confirm that the action occurred and to synchronize the status.

 

And here an unexpected action of the system may occur,* Relay* is switched on but the returned status is 0, that is incorrect. The reason for this is that these operations are performed asynchronously on two different devices. There is no guarantee that the *Relay*'s state change operation will be performed before its state is queried. Calling the state change action in the *RelayControlOnRequest() *script is called asynchronously, which means that the script does not wait for *CluZ* to perform the task.

 

The considered case is very simple and practically always works, but in case of more complex operations (where different target objects are involved, and in order to perform the operation it is still necessary to exchange data, send user features, etc.) the risk that the status will be collected before the real change of the object(s) state is realized. In complex systems we often observe such effects.

**Event synchronization**

The above problem can be solved by forcing the *RelayControlOnRequest()* script to wait until *CluZ* actually efforts a state change action on the target device. This can be easily achieved using the clu.await() function. E.g.: call:

```
CluZ->Relay->Switch(0)
```

is replaced with:

```
clu.await(CluZ->Relay->Switch(0))
```

After this change, Listener will not send "200, OK" confirmation before the action on *CluZ* is actually executed. Therefore, the client using this interface will not be misled by too fast confirmation of task execution.

 

However, the clu.await() function has a limitation. The timeout for the call execution is 800 ms and if the task is not completed within this time, the script will terminate with a timeout. The Http client will get the following Http error: "500 Internal Server Error".

 

In most cases such timeout is not a problem and the system will work correctly but in case of complex operations and/or when *CluZ* will be loaded with other tasks this may happen. How to solve the problem in such case is described in the next section.

 

**Confirmation back**

In systems where we care about high reliability and stability of the integration operation, the response of the Http Listener should be delayed until it receives a direct confirmation from *CluZ* that the task has been completed.

For this purpose, we split the operation into two stages. Instead of one script performing the whole task, we define two of them: the first one performs the task, the second one sends a Http response after *CluZ* confirms that the task has been completed.

 

For clarity, we define a new script and assign it to the *RelayControlListener*:

- *OnRequest* event: GateHttp-\>SplitSyncOnRequest()

The *SplitSyncOnRequest()*  script looks as follows: 

```
-- SplitSyncOnRequest()local data = GateHttp->RelayControlListener->QueryStringParamsif data == nil then  CluZ->SplitSyncCluzTask("Switch")  returnelse  if data.cmd == "setValue" then    local val = tonumber(data.val)    if(val == 1) then      CluZ->SplitSyncCluzTask("On")      return    elseif(val == 0) then       CluZ->SplitSyncCluzTask("Off")      return    end  endendGateHttp->RelayControlListener->StatusCode = 400GateHttp->RelayControlListener->ResponseBody = "Bad request"GateHttp->RelayControlListener->SendResponse()
```

 

In each place of the script when we delegate a task to *CluZ* (this time through an additional script, which will be discussed in a moment) we finish the operation of our script, without sending Http response to the client. If the script execution comes to the end lines, it means that the request was not interpreted correctly and we send back the error "400, Bad request". Additionally, we have added another level of protection against invalid call parameters.

 

At this moment, the task is not executed directly on the target *Relay* object (as before) but delegated to the script on* CluZ* named *SplitSyncCluzTask*(action: string). The notation used means that the script is called with a parameter named "action", which is of type "string". Notice that this is not LUA notation where we do not define the type of the function call parameter. The "action" parameter defines a specific action to call on the *Relay* object. The action is identical to the previous case.

```
-- SplitSyncCluzTask(action: string)if(action == "On") then  CluZ->Relay->SwitchOn(0)elseif (action == "Off") then  CluZ->Relay->SwitchOff(0)elseif (action == "Switch") then  CluZ->Relay->Switch(0)else  -- Unknown action  GateHttp->SplitSyncRequestCompleted(false)  -- Return to avoid double completion   returnendGateHttp->SplitSyncRequestCompleted(true)
```

 

Depending on the defined action, an appropriate method is executed on the *Relay *object. At the end we inform *GateHttp* that we have completed the task and a response must be sent back to the client. For this purpose, a method has been created in *GateHttp* called *SplitSyncRequestCompleted*(success: boolean) that takes a Boolean value as parameter: true if the action was successful, false otherwise.

```
-- SplitSyncRequestCompleted(success: boolean)if success then  GateHttp->RelayControlListener->StatusCode = 200  GateHttp->RelayControlListener->ResponseBody = "OK"else   GateHttp->RelayControlListener->StatusCode = 405  GateHttp->RelayControlListener->ResponseBody = "Not allowed"endGateHttp->RelayControlListener->SendResponse()
```

 

*GateHttp* through the above method sends a response to the client indicating success or failure depending on the parameter received. In this way we have implemented a fully synchronous Http method that has no time limit on its operation. In more advanced cases it is possible to improve the system operation even more by calling the *SplitSyncRequestCompleted*(success: boolean) function in response to events informing about a change in the value of a particular object. This solution provides reassurance that a change has occurred and further increases the stability of the system.

 

In case of receiving data from external systems, always use the method of limited trust as to its correctness. We recommend not to pass the values directly to methods and scripts inside the system but to use specific actions depending on the values of methods as you can see in the above scripts. If you need to directly use variables received from outside, pass them through user features (which are addressable throughout the Grenton system and can be freely transferred between CLU devices). Additionally, each variable received externally should be validated in the script for correctness, value, range. Lack of proper verification of received values may cause unexpected operation of the system, open access to unwanted functionality and even cause errors and CLU going into emergency mode.

 

**Timeout**

The created Listener already works almost reliably. Why almost? Let's consider what happens if *CluZ* for some reason never calls the *SplitSyncRequestCompleted*(success: boolean) method. *GateHttp* is then left waiting for the current request to complete and stops responding to subsequent requests.

Of course, in a well-configured system, this should not happen. However, an unexpected situation may always occur, and that is why each element of the system should be configured so that it works as independently as possible and is resistant to errors in other areas. Therefore, our Listener should also be fully resist to such situations.

For this purpose, we will define a *Timer* object on *GateHttp* that will make sure that the wait for the *CluZ* response does not go on indefinitely. The parameters of the new object:

- Name: SplitSyncTimeout
- Event OnTimer: GateHttp-\>SplitSyncTimeoutOnTimer()
- Time: 3000 - here the time should be chosen according to the specific situation, for the purpose of the example we assume 3 s (3000 ms)
- Mode: CountDown

 

The script executed after the specified time looks as follows:

```
-- SplitSyncTimeoutOnTimer()GateHttp->RelayControlListener->StatusCode = 408GateHttp->RelayControlListener->ResponseBody = "Timeout"GateHttp->RelayControlListener->SendResponse()
```

 

The operation of the script is quite simple, it returns a "408, Timeout" error.

 

To make it work you need to modify the *SplitSyncOnRequest()* and *SplitSyncRequestCompleted*(success: boolean) scripts accordingly.

```
-- SplitSyncOnRequest()local data = GateHttp->RelayControlListener->QueryStringParamsif data == nil then  CluZ->SplitSyncCluzTask("Switch")  GateHttp->SplitSyncTimeout->Start()  returnelse  if data.cmd == "setValue" then    local val = tonumber(data.val)    if(val == 1) then      CluZ->SplitSyncCluzTask("On")      GateHttp->SplitSyncTimeout->Start()      return    elseif(val == 0) then       CluZ->SplitSyncCluzTask("Off")      GateHttp->SplitSyncTimeout->Start()      return    end  endendGateHttp->RelayControlListener->StatusCode = 400GateHttp->RelayControlListener->ResponseBody = "Bad request"GateHttp->RelayControlListener->SendResponse()
```

Each time we delegate a task to *CluZ *we start the *SplitSyncTimeout* timer.

```
-- SplitSyncRequestCompleted(success: boolean)if(GateHttp->SplitSyncTimeout->State == 1) then  GateHttp->SplitSyncTimeout->Stop()  if success then    GateHttp->RelayControlListener->StatusCode = 200    GateHttp->RelayControlListener->ResponseBody = "OK"  else     GateHttp->RelayControlListener->StatusCode = 405    GateHttp->RelayControlListener->ResponseBody = "Not allowed"  end  GateHttp->RelayControlListener->SendResponse()end
```

 

In the *SplitSyncRequestCompleted*(success: boolean) script we first check if the timer is still in state "1" (enabled). This prevents unnecessary sending of the response in the situation, when the timeout has already occurred - the response time is over and the response informing about the error "408, Timeout" has been sent. If the timer is still running (normal situation, response timeout has not run out) we stop the timer and continue as before.

 

**Multiple objects**

Let's return for a moment to the method that retrieves *Relay*'s state. In particular, let's take another look at the following line:

```
GateHttp->RelayStateListener->ResponseBody = "Relay State: "..CluZ->Relay->Value
```

 

The key point here is to retrieve the value of the *Relay* object's *Value* property:

```
CluZ->Relay->Value
```

 

This method works well but you should be aware that the value of this variable is retrieved when the script is executed. It results in communication between* GateHttp* and *CluZ* via the network. It is a synchronous call, i.e. the method waits for the response with the value of the* Relay* object. We already know about some limitations of such call. In this particular case there are even more threats. The value of this property is retrieved each time the client asks for its value through the Http interface, which generates unnecessary traffic in the system. Additionally, it causes unnecessary delay in the system. If there are many such queries, it may affect the system performance. In some especially simple cases it is acceptable and the system will cope with it well. But not always.

 

Let's imagine that there are many objects in the system and we need to provide in response the statuses of all of them (in JSON or CSV form). If in such a case we use the same method, the script performing such a task may look more or less like the one below:

```
GateHttp->RelayState->StatusCode = 200local response = CluZ->Relay01->Valueresponse = response .. "," .. CluZ->Relay02->Valueresponse = response .. "," .. CluZ->Relay03->Valueresponse = response .. "," .. CluZ->Relay04->Valueresponse = response .. "," .. CluZ->Relay05->Valueresponse = response .. "," .. CluZ->Relay06->Valueresponse = response .. "," .. CluZ->Relay07->Valueresponse = response .. "," .. CluZ->Relay08->Valueresponse = response .. "," .. CluZ->Relay09->Valueresponse = response .. "," .. CluZ->Relay10->Valueresponse = response .. "," .. CluZ->Relay11->ValueGateHttp->RelayState->ResponseBody = "System State: ".. responseGateHttp->RelayState->SendResponse()
```

 

In a real system, there may be many more relay objects. Each line makes a request to *CluZ* for the state of the *Value* feature over the network. Collecting the state of all objects can take quite a while. This situation delays the response significantly and blocks *GateHttp* for the duration of the operation.

 

A series of requests occurs each time a client queries about the system state. In most cases, the value of a variable between queries only changes for one object (for the one just changed object). All this causes a lot of unnecessary traffic and negatively affects the speed of the system. From the point of view of the end user, the system may in such cases work unstably, have unexpected delays, freeze for a short or longer period of time and even omit some events.

 

**State for a complex system**

In order to solve the above problem, it is necessary to approach the task of retrieving device state a little differently. Further in this section, for simplicity of examples, we will return to a single *Relay* object, but the provided method will work for practically any number of objects.

 

Let's consider that instead of querying the remote *CluZ* for the state of a *Relay* object every time when the client asks for it, we could keep its value locally in a *GateHttp* user feature. That way when the client queries without any delay we return its value immediately without any delay. Let's call it *RelayValueOnGateHttp*. What is more, we would like to eliminate all the queries that synchronize its value and get information only when it is needed, that is when the value of the CluZ-\>Relay-\>Value  property changes. To achieve this we assign the following command to the *OnValueChange *event of the *Relay* object:

```
GateHttp->RelayValueOnGateHttp=CluZ->Relay->Value
```

 

Which means: Every time the state of the *Value* feature changes, assign that new value to the* RelayValueOnGateHttp* user feature on *GateHttp*. From now we will always have the current value of the *Relay* object on the* GateHttp* side. At the time of the request, we simply send this value to the client. To do this we modify the *RelayStateOnRequest*() script as follows:

```
-- RelayStateOnRequest()GateHttp->RelayState->StatusCode = 200GateHttp->RelayState->ResponseBody = "Relay State: "..GateHttp->RelayValueOnGateHttpGateHttp->RelayState->SendResponse()
```

 

As mentioned earlier, this can be used for any number of objects and does not cause any negative impact on system performance because only changes to individual values are communicated when they occur.

 

**Push notifications**

Going a step further on the road to perfect integration, let us implement one more improvement. Until now, the customer himself had to ask every now and then whether anything had changed in the system. If the system is to be responsive, such queries must take place frequently. Frequent queries generate unnecessary traffic and increase the risk of delays, especially in the handling of events very sensitive to delays, such as switching on lights, where the user immediately feels that the action did not take place immediately after touching the button.

 

In addition, the customer is not immediately notified of a change in the system, but only when he asks if anything has changed.

 

The solution is the state push method, where the system itself actively sends notification about a change in the state of a device in the system. In order to implement such a mechanism, we create a new *GateHttp* object of the *HttpRequest* type:

- Name: StatePushNotification
- Host: IP:Port serwera http nasłuchującego informacji o zmianach stanu
- Path: /statechanged
- Method: PUT

The rest of the settings remains unchanged.

 

Then we add a new script *SendStatePushNotification*(newValue: number):

```
-- SendStatePushNotification(newValue: number)GateHttp->StatePushNotification->SetQueryStringParams("val="..newValue)GateHttp->StatePushNotification->SendRequest()
```

 

To inform the client about the new status we need to call the script passing the new value of the* Value* feature as a parameter. The best way of it is to make a change in *OnValueChange *event of the *Relay* object. Since we assigned the value a step earlier to the GateHttp-\>RelayValueOnGateHttp user feature, we can use it to avoid unnecessary resending of this value. So the assignment would look as follows:

GateHttp-\>SendStatePushNotification(GateHttp-\>RelayValueOnGateHttp)

Note that the copying of the value to the *RelayValueOnGateHttp* variable must occur first.

 

From now, whenever the state of the *Relay* object's *Value* feature changes, a notification with the new value will automatically be sent.

 

The selected method sends the new value as a URL parameter but you can format the response any way you like and send it in the message body by setting the value using the *SetRequestBody*(value) method.

 

 

**Summary**

We have discussed the basic aspects of integrating the Grenton system using Http Gate. We discussed typical problems that may occur with such configurations and methods for solving them. By following these guidelines, you can meet any complex requirements and implement a complex system to make it stable, reliable and fast. It should be remembered that the Gate Http module opens unlimited possibilities of cooperation with the system, and you can use it to perform any operation, even disadvantageous. Therefore, it is important that the Gate Http configuration is carefully considered and performed with the utmost care. 

![](https://knowledgebase.grenton.com/hubfs/Knowledge%20Base%20Import/support.grenton.plensupportsolutionsarticles35000137558-grenton-gate-http-comprehensive-integration-with-external-systemshit-2.gif)

- [Installation guidelines](https://knowledgebase.grenton.com/en/installation-guidelines?hsLang=en#main-content)

    - [How to Prepare Electrical Installation](https://knowledgebase.grenton.com/en/installation-guidelines?hsLang=en#how-to-prepare-electrical-installation)
- [Reference devices](https://knowledgebase.grenton.com/en/reference-devices?hsLang=en#main-content)

    - [Integrated Device](https://knowledgebase.grenton.com/en/reference-devices?hsLang=en#integrated-device)
- [Most Common Mistakes](https://knowledgebase.grenton.com/en/most-common-mistakes?hsLang=en)
- [Electrical Installation](https://knowledgebase.grenton.com/en/electrical-installation?hsLang=en)
- [Manuals](https://knowledgebase.grenton.com/en/manuals?hsLang=en#main-content)

    - [Gate Modbus](https://knowledgebase.grenton.com/en/manuals?hsLang=en#gate-modbus)
    - [Training](https://knowledgebase.grenton.com/en/manuals?hsLang=en#training)
    - [SW Applications](https://knowledgebase.grenton.com/en/manuals?hsLang=en#sw-applications)
    - [Gate HTTP](https://knowledgebase.grenton.com/en/manuals?hsLang=en#gate-http)
    - [Smart Panel](https://knowledgebase.grenton.com/en/manuals?hsLang=en#smart-panel)
    - [Configuration](https://knowledgebase.grenton.com/en/manuals?hsLang=en#configuration)
    - [myGrenton interfaces](https://knowledgebase.grenton.com/en/manuals?hsLang=en#mygrenton-interfaces)
    - [Virtual Objects](https://knowledgebase.grenton.com/en/manuals?hsLang=en#virtual-objects)
    - [Gate Alarm](https://knowledgebase.grenton.com/en/manuals?hsLang=en#gate-alarm)
- [Intercom](https://knowledgebase.grenton.com/en/intercom?hsLang=en)
- [FAQ](https://knowledgebase.grenton.com/en/faq?hsLang=en#main-content)

    - [FAQ](https://knowledgebase.grenton.com/en/faq?hsLang=en#faq)
    - [About Grenton](https://knowledgebase.grenton.com/en/faq?hsLang=en#about-grenton)
- [Price list and documents](https://knowledgebase.grenton.com/en/price-list-and-documents?hsLang=en)

[![Grenton logo](https://knowledgebase.grenton.com/hs-fs/hubfs/Logo_Grenton_variants_BIG_2020_plus_RGB_v0.2-02.png?width=400&height=100&name=Logo_Grenton_variants_BIG_2020_plus_RGB_v0.2-02.png "Grenton logo")](http://grenton.com)

<https://www.facebook.com/grenton.smart.home> <https://www.instagram.com/grenton_smart_home/> <https://www.youtube.com/channel/UCFNNI-dgO1cm81kCrSr1bzg> <https://www.linkedin.com/company/grenton>

Copyright © 2026, Grenton Sp.z o.o.