Určitě už jste četli zápisek o propojení Loxone s modulem Quido od Papoucha na vodnickém blogu. Protože jsem ale nakonec nešel cestou Loxone a zvolil pro systém chytré domácnosti TapHome, potřeboval jsem řešit stejný problém v jiném kontextu.

Fyzické zapojení

Modul české výroby nabízí na šíři cca 12 běžných DIN modulů 60+40 digitálních vstupů spolu s volitelným komunikačním rozhraním. Já vybral modul ETH s ethernetem.

Integrace s kabeláží chytré domácnosti je jednoduchá: do vypínače/tlačítka stačí přivést na jednom vodiči napětí a zbytek vodičů z kabelu můžou být vstupy. Pro běžný UTP kabel je to tedy 1+7 vstupů. Já ale nechal v každé místnosti minimálně pod jedním vypínačem pár vodičů pro připojení NTC teploměru.

V rozvaděči stačí pak svorku IGND Quida propojit s - pólem zdroje signálového napětí. Pro zachování galvanického oddělení vstupů je nutné použít jiný zdroj pro napájení Quida a jiný pro signály.

Datové propojení zajišťuje ethernetový kabel zapojený do switche v rozvaděči, který je samozřejmě propojen s routerem s DHCP.

Dokumentace Quida je skvělá. Opravdu by si z ní mnozí mohli brát příklad.

Konfigurace Quida

Po připojení na IP adresu Quida v režimu WEB uživatele přivítá přehled vstupů a jejich stav. Vyzkoušel jsem si tu, že signalizace stavu vstupů funguje a přepnul jsem Quido do režimu UTP. V tomto režimu stačí nastavit cílovou IP adresu a port a Quido tam bude ve výchozím nastavení odesílat packet v protokolu Spinel po každé změně hodnoty jakéhokoliv vstupu.

UDP jsem zvolil proto, že poslání packetu bez TCP handshaku je mnohem rychlejší a zaručuje nižší odezvu.

Tím veškerá konfigurace Quida končí. Není to super?

Packet parser — důvod, proč jsem zvolil Taphome

Ač má TapHome pár slabin (žádné web UI a podprůměrná dokumentace), u mě jasně vyhrál díky packet parseru. Tato funkce dovoluje integraci jakéhokoliv rozumně napsaného API. Cloudového i lokálního. Binárního, v plaintextu, JSONu i XML. Můžete integrovat doslova cokoliv co připojíte k síti. V tomto je síla TapHome. Nemusíte se doprošovat integrace toho, či onoho a prostě si to uděláte sami. Tady zcela válcuje Loxone.

Dokumentace packet parseru pokulhává, ale zkusím sepsat, co jsem zjistil:

Nejvíce informací se dá načerpat z oficiálního repozitáře s templates. Nic sice není zdokumentované, ale příkladů je tam spousta. Z oficiální dokumentace se třeba nedozvíte k čemu přesně dobrý je listener skript.

V rámci struktury packet parseru máte možnost konfigurovat modul, který zastřešuje jedno nebo více zařízení. V mém případě konfiguruji UDP modul a u něj localhost hostname jako IP adresu a port na kterém očekávám UDP packety od Quida. Netuším, jestli vůbec jde v TapHome nakonfigurovat více síťových rozhraní a tak netuším, jaké využití konfigurace IP adresy má. Při nastavení localhost bude packet parser naslouchat na všech rozhraních a zároveň se tím vyhnu závislosti na pevné IP v síti.

U každého modulu lze v servisním nastavení nastavit:

  • Listener script/skript posluchače, který zpracovává jakákoliv data, která v packet parseru přistanou v proměnné RECEIVEDBYTES
  • Read script pro periodické čtení stavu
  • Write script pro jednotlivý nebo periodický zápis hodnoty
  • a dále také servisní atributy a servisní akce, které ale netuším k čemu slouží a nepátral jsem po tom

V detailech modulu lze nastavit proměnné, které chceme sdílet mezi skripty nebo modulem a zařízeními. Při konfiguraci proměnné je zde omezení v podobě typu proměnné, kde lze zvolit jen mezi číslem nebo řetězcem. Složitější struktury jako byte array tedy neuložíte. Nebo aspoň opět nevím jak na to.

V podstatě stejné věci jdou konfigurovat i u každého zařízení. Chápu to tak, že ve skriptech modulu lze provést složitější akci tak, aby se nemusela provádět u každého zařízení zvlášť.

Spinel protokol a listener skript

Spinel protokol je na první pohled proprietární zbytečnost na cestě za výsledkem. Na pohled druhý výrazně tuto cestu zkrátí.

Dobrou zprávou je, že ve výchozím stavu v UDP režimu posílá Quido stav všech vstupů při každé změně. Zpráva ve spinel protokolu vypadá nějak takto:

['0b101010', '0b1100001', '0b0', '0b10010', '0b110001', '0b10011', '0b1101', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b11011', '0b10011001', '0b1011101', '0b1101']

Děsivé, že? Ale kdepak. Prvních (z pohledu TapHome jde o byte array) 8 bytů jsou stavové informace a protokol. Poslední 2 byty to samé. Nás zajímá 104 bitů mezi těmito skupinami.

['0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b0', '0b11011', '0b10011001']

Lepší, že? Teď je tu takový malý trik. Ač TapHome používá indexaci v array klasicky zleva do prava, nejvýznamnější bit je úplně pravo a pozice bitu zprava odpovídá stavu vstupu. V příkladu nám tedy Quido říká, že zapnuté vstupy jsou 1, 4, 5, 8, 9, 10, 12 a 13.

Pokud chceme zjistit stav vstupu 1, naivní kód v TapHome skriptovacím jazyce vypadá takto:

GETBIT(GETAT(RECEIVEDBYTES, LEGTH(RECEIVEDBYTES) - 3), 0)

Nejdříve se podíváme na poslední bajt se stavy a v něm se podíváme na nejvýznamnější bit úplně vpravo. Jako listener skript tento snippet funguje nádherně.

Jedna z limitací je to, že si musíte vybrat předem jaké zařízení je na jakém vstupu. Zpětně měnit nelze. Pokud chci vstup Quida číslo 1 použít jako stavový kontakt, snippet šablony v XML vypadá takto. Navíc oproti třeba tlačítku je přiřazení do proměnné Rc a negace. Kontakt je totiž při stavu 1 uzavřen:

<Device>
    <Name>${bus_module_reed_contact}</Name>
    <Model>PacketParserReedContact</Model>
    <Id>-3</Id>
    <DeviceProperties>
    <DeviceType>0</DeviceType>
    <ReadScriptPacketParser></ReadScriptPacketParser>
    <InternalPollInterval>2500</InternalPollInterval>
    <CustomVariables>[]</CustomVariables>
    <ServiceAttributesScriptsPacketParser></ServiceAttributesScriptsPacketParser>
    <ServiceActionsScriptsPacketParser></ServiceActionsScriptsPacketParser>
    <ListenerScriptPacketParser>Rc := !GETBIT(GETAT(RECEIVEDBYTES,LENGTH(RECEIVEDBYTES) - 3), 0);</ListenerScriptPacketParser>
    <OnStateIconId>87</OnStateIconId>
    <OffStateIconId>88</OffStateIconId>
    <OnStateName>${general_open}</OnStateName>
    <OffStateName>${general_closed}</OffStateName>
    <ReadStateScriptPacketParser></ReadStateScriptPacketParser>
    </DeviceProperties>
</Device>

Celou šablonu teprve dávám dohromady.