Featured image of post Rekuperator Salda przez Gate HTTP

Rekuperator Salda przez Gate HTTP

Integracja rekuperatora Salda z Grentonem przez Gate HTTP - inżynieria wsteczna i implementacja proxy w Go.

Salda http Widok strony internetowej generowanej przez moduł MB-GATEWAY od Salda.

Większość sprzętu można zintegrować z Grentonem przez przekaźniki, część przez Modbus. Ja natomiast, chciałem pokazać jak można się zintegrować z rekuperatorem przez Gate HTTP. W przypadku sprzętów posiadających bramkę HTTP można przeprowadzić prostą inżynierię wsteczną.

W tym przypadku, rekuperator posiada dwa wejścia Modbus i pod jedno podłączona jest bramka http od producenta - Salda. W drugie wejście można wpląć Gate Modbus i sterować rekuperatorem, ale nie o tym jest ten post.

Posiadam “Gateway” od Saldy (link), który pozwala na sterowanie rekuperatorem za pomocą aplikacji na telefon. Dodatkowo moduł MB-GATEWAY udostępnia stronę WWW przez którą można zarządzać samym modułem HTTP jak i podstawowymi parametrami rekuperatora. Komunikacja z telefonem odbywa się za pomocą protokołu opartego o TCP/IP na porcie 502. Jako, że Gate HTTP nie pozwala na operacje na socketach, to już nie sprawdzałem jak wygląda komunikacja dla aplikacji mobilnej.

Sprawdzenie możliwości Gate od Salda

Po wejściu na stronę, za pomocą inspektora można podejrzeć, co jest wysyłane.

Można znaleźć kilka typów wywołań np.:

1) GET http://192.168.0.71/FUNC(4,1,1,0,45)?160909905818

które zwraca:

0;0;1;0;0;0;0;0;0;0;0;0;1;1;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;

2) GET http://192.168.0.71/FUNC(4,1,3,0,111)?1609098962765

zwraca:

1;22;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;0;0;21;53;

Po chwili można namierzyć, że request numer 5 zawiera najwięcej interesujących danych. Stworzyłem, lokalnie na komputerze plik rekuperator.lua, w którym zaczynam pisać wstępną obsługę danych z rekuperatora.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-- funkcja rozdzielająca string na tablicę
local function split(s, delimiter)
    result = {};
    for match in (s..delimiter):gmatch("(.-)" .. delimiter) do
        table.insert(result, match);
    end
    return result;
end

local result = split(response, ";")

local supply_air = result[1]
local exhaust_air = result[7]
local extract_air = result[4]
local outside_air = result[10]
local water_temperature = result[13]
local humidity = result[14]
local supply_fan_speed = result[16]
local extract_fan_speed = result[17]

-- temperatury pomnożone są przez 10
print("supply_air: " .. supply_air / 10)
print("exhaust_air: " .. exhaust_air / 10)
print("extract_air: " .. extract_air / 10)
print("outside_air: " .. outside_air / 10)
print("water_temperature: " ..water_temperature / 10);
print("humidity: " .. humidity);
print("supply_fan_speed: " .. supply_fan_speed);

Problem z Gateway Saldy

Niestety po pierwszych testach okazało się, że moduł Gate nie umie sobie poradzić z response, który zwraca moduł Salda. Problem polega na tym, że po wysłaniu requestu do rekuperatora event OnResponse był wywoływany po 30 sekundach, gdzie normalnie z Postmana czy cURL request trwał jakieś 60ms.

Wydaje mi się, że Gate Http nie rozpoznaje prawidłowo zakończenia zwracanego komunikatu przez Gate Saldy - HTTP 1.0, assume close after body. Po około 20-30 sekundach w Gate Http włączany jest wewnętrzny timeout nad którym nie mam kontroli.

PROXY

Zawiedziony tym, że działa to tak strasznie wolno, postanowiłem napisać proxy, które będzie pośredniczyło w komunikacji między Grentonem a Saldą. Mogłem zrobić to za pomocą Nginx, Pythona, JavaScriptu. Ale w ramach rozrywki napisałem proxy w Go. Takie proxy umieściłem na serwerze, którego używam Grafany, HA i innych mądrości.

Moje API do rekuperatora wygląda następująco:

192.168.0.39:18080/recuperator/getData

1
{"supplyAir":"22.3","exhaustAir":"6.1","extractAir":"0.0","outsideAir":"0.0","humidity":"33","supplyFanSpeed":"30","extractFanSpeed":"30","fanSpeed":"1","temperature":"22"}

Tu zdecydowałem, że większość danych przygotuję po stronie proxy, dodatkowo opakowałem wynik w JSONa, żeby już nie bawić się po stronie Grentona w parsowanie i wyciąganie danych.

192.168.0.39:18080/recuperator/setTemperature?value=22

1
{"temperature":"22.0"}

192.168.0.39:18080/recuperator/setFanSpeed?value=1

1
{"fanSpeed":"1"}

Kod proxy dostępny tutaj: https://github.com/Domktorymysli/HouseProxy (to raczej POC niż produkcyjne rozwiązanie :D)

Implementacja w OM

Tym razem skrypt był dużo prostszy dzięki JSON API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
if (method == 'response') then
    local response = GATE->RecuperatorRequest->ResponseBody

    if response.humidity ~= nil then
        RECUPERATOR_DATA = response
    end

    if response.temperature ~= nil then
        RECUPERATOR_DATA['temperature'] = response.temperature
    end

    if response.fanSpeed ~= nil then
        RECUPERATOR_DATA['fanSpeed'] = response.fanSpeed
    end

    RECUPERATOR_DATA_STR = toString(RECUPERATOR_DATA)
    return
end

if (method == 'getData') then
    doRequest("recuperator/getData")
    return
end

if (method == 'setFanSpeed') then
    doRequest("recuperator/setFanSpeed?value=" .. value)
    return
end

if (method == 'setTemperature') then
    doRequest("recuperator/setTemperature?value=" .. value)
    return
end

Podsumowanie

Z dość prostego przykładu zrobił się całkiem długi post. Prawdopodobnie, gdyby Salda i Grenton lepiej ze sobą współpracowały, to bym uniknął zabawy z pisaniem proxy. Z drugiej strony, może komuś kiedyś się przytrafi podobny błąd.

Zbudowano z Hugo
Motyw Stack zaprojektowany przez Jimmy