Kontakt
Dokumentace a software
HELLOS UNI / MODBUS-RTU API

Referenční dokumentace Modbus RTU API

HELLOS-UNI může fungovat jako server Modbus RTU na stejném poloduplexním rozhraní RS-485, které používá HBUS. Implementace je záměrně oddělena od transportní vrstvy HBUS. Změna protokolu se projeví po restartu.

Tento dokument platí pro firmware HELLOS-UNI 4.0 a verzi mapy registrů 1.

Sériová komunikace a chování serveru

  • 8 datových bitů, bez parity, 1 stop bit (8N1).
  • Modbus RTU používá stejnou přenosovou rychlost jako nastavenou pro HBUS.
  • Rozsah adres serveru: 1 až 247.
  • Podporované funkce: 03, 04, 06 a 16.
  • Slova registrů i víceslovné hodnoty používají pořadí big-endian. Bajty Modbus CRC se odesílají od nejméně významného bajtu.
  • 32bitová hodnota zabírá dva po sobě jdoucí registry, nejvýznamnější slovo je první.
  • Při rychlosti 19200 baudů a nižší odpovídá mezera mezi rámci době přenosu 3,5 znaku. Při rychlosti nad 19200 baudů je pevně nastavena na 1,75 ms.
  • Modul nikdy neposílá nevyžádané rámce Modbus. Data událostí HBUS jsou uložena v registrech událostí, odkud je čte klient.
  • Všesměrová adresa nula přijímá běžné zápisy výstupů a PWM bez odpovědi. Nelze ji použít pro servisní příkaz návratu do HBUS.

Níže uvedené adresy jsou adresy Modbus PDU číslované od nuly. Software používající zápis 3xxxx nebo 4xxxx s číslováním od jedné může zobrazovat hodnotu o jednu vyšší než adresa v tomto dokumentu.

Formát a význam hodnot

  • 0xffff znamená nedostupnou hodnotu nebo nevyužitou pozici.
  • 0x8000 znamená nedostupné měření se znaménkem.
  • Hodnoty se znaménkem používají 16bitový dvojkový doplněk.
  • Hodnoty teploty a vlhkosti jsou vynásobené 10.
  • Hodnoty ADC jsou v desetinách procenta, v rozsahu 0 až 1000.
  • Střída PWM je vyjádřena celými procenty od 0 do 100.

Vstupní registry - funkce 04

Systémové registry

Adresa Hodnota
0 Verze mapy registrů, aktuálně 1
1 Stavové příznaky: bit 0 ladění, bit 1 aktualizace souborového systému, bit 2 přetečení událostí, bit 3 překročení kapacity pozic pro čidla
2-3 Doba běhu v sekundách, 32bitová hodnota bez znaménka
4-5 ID zařízení odvozené z hardwaru, 32bitová hodnota bez znaménka
6-7 Přenosová rychlost UART, 32bitová hodnota bez znaménka
8 Adresa Modbus
9 Nastavený režim: 0 HBUS, 1 Modbus RTU
10 Aktivní režim: 0 HBUS, 1 Modbus RTU
11 Obsazené pozice DS18x20, nejvýše 32
12 Obsazené pozice SHT3x, nejvýše 6
13 Obsazené pozice SCD4x, nejvýše 6
14-16 Kód režimu portů A, B a C
17-18 CRC32 úplného řetězce verze softwaru
19-20 CRC32 řetězce verze hardwaru
21 Příznaky překročení kapacity pozic pro čidla: DS bit 0, SHT bit 1, SCD bit 2
22-31 Vyhrazeno, při čtení vrací 0xffff

Kódy režimů portů jsou v rámci verze mapy 1 stabilní:

Kód Režim Kód Režim
0 sensor-autodetect 8 output_safe
1 button_simple 9 pwm_50hz
2 button_double 10 pwm_1khz
3 input 11 pwm_25khz
4 input_safe 12 adc_raw_passive
5 impulse_counter 13 adc_raw_active
6 impulse_counter_safe 14 adc_pullup_passive
7 output 15 adc_pullup_active
16 encoder 17 encoder_reverse

Registry stavů portů

Každý blok 12 registrů používá pořadí kanálů A0 až A3, B0 až B3 a poté C0 až C3.

Adresa Hodnota
100-111 Stav logického vstupu, 0 nebo 1
120-143 Impulzní čítače, 12 hodnot bez znaménka o šířce 32 bitů
150-161 Hodnota ADC v desetinách procenta
170-181 Stav logického výstupu, 0 nebo 1
190-201 Střída PWM v procentech

Kompaktní čtení digitálních vstupů

Kompaktní blok je určen pro instalace s mnoha moduly. Klient jedním požadavkem přečte registry 32 až 46 a porovná čítače stisků s předchozím vzorkem. Díky tomu neztratí krátký stisk mezi dvěma cykly čtení a vystačí s jedním požadavkem na modul.

Bity a pozice čítačů používají pořadí kanálů A0 až A3, B0 až B3 a poté C0 až C3.

Adresa Hodnota
32 Bitová mapa aktuálních stavů logických vstupů, bity 0 až 11
33 Bitová mapa platnosti stavů vstupů pro porty input a input_safe
34 Bitová mapa platnosti čítačů stisků pro tlačítkové a vstupní porty
35-46 16bitový čítač stisků bez znaménka pro každý kanál

Čítače přetékají z 65535 na nulu a po restartu modulu se vynulují. Přechod logického vstupu do aktivního stavu i stisk v režimu button_simple nebo button_double zvýší příslušný čítač. Uvolnění jej nezvyšuje. První hodnoty načtené po připojení určují výchozí stav klienta a nesmějí být vyhodnoceny jako nové stisky.

Diagnostika komunikace

Diagnostické čítače jsou 32bitové hodnoty bez znaménka, uložené s nejvýznamnějším slovem na prvním místě. Při překročení rozsahu přetečou a po restartu modulu se vynulují.

Adresa Hodnota
50-51 Přijaté platné požadavky pro tento modul
52-53 Přijaté neplatné rámce RTU nebo rámce překračující kapacitu bufferu
54-55 Platné rámce RTU adresované jinému modulu
56-57 Odpovědi úspěšně předané UART
58-59 Selhání odesílání odpovědí

Registry událostí

Registry událostí uchovávají poslední událost pro každý fyzický kanál. Klient rozpozná novou událost podle změny sekvenčního registru. Sekvenční čísla přetékají z 65535 na nulu.

Adresa Hodnota
220-231 Sekvenční číslo události pro každý kanál
240-251 Typ poslední události pro každý kanál
260-271 Hodnota poslední události pro každý kanál, 16bitová se znaménkem
280-303 Čas poslední události v milisekundách, 12 hodnot bez znaménka o šířce 32 bitů
320-343 Kumulovaná poloha enkodéru, 12 hodnot se znaménkem o šířce 32 bitů

Kódy typů událostí: 1 stisk tlačítka, 2 uvolnění tlačítka, 3 logický vstup, 4 změna polohy enkodéru a 5 změna ADC. Události tlačítek ukládají hodnotu 1. Hodnoty událostí ADC jsou v desetinách procenta.

Pozice čidel

Pozice DS18x20 jsou seřazeny podle 32bitového identifikátoru čidla v HBUS. Pozice SHT3x a SCD4x jsou seřazeny podle indexu HBUS. Pozice tedy zůstává stejná, dokud se nezmění sada nalezených zařízení a jejich identifikátorů.

Adresa Uspořádání pozic
400-527 32 pozic DS18x20, každá má čtyři registry: vyšší slovo ID, nižší slovo ID, teplota se znaménkem x10, příznaky
600-623 6 pozic SHT3x, každá má čtyři registry: index HBUS, teplota se znaménkem x10, vlhkost x10, příznaky
640-669 6 pozic SCD4x, každá má pět registrů: index HBUS, CO2 v ppm, teplota se znaménkem x10, vlhkost x10, příznaky

Příznaky nyní obsahují hodnotu 1 pro obsazenou pozici. Měření zahrnují nastavenou tabulku kompenzací, stejně jako odpověď HBUS na čtení všech hodnot.

Nedefinované adresy v rozsahu 0 až 669 vracejí 0xffff. Čtení nad adresou 669 vrací výjimku Modbus 02.

Holding registry - funkce 03, 06 a 16

Adresa Přístup Hodnota
1000-1011 čtení/zápis Logické výstupy A0-C3, 0 nebo 1
1020-1031 čtení/zápis Střída PWM A0-C3, celé číslo od 0 do 100
1999 čtení/zápis Servisní příkaz návratu do HBUS

Registry kanálů, které nejsou nastaveny do odpovídajícího výstupního režimu, vracejí 0xffff a odmítají zápis. Funkce 16 ověří celý požadavek před jeho provedením. Jeden požadavek nesmí přecházet z bloku logických výstupů do bloku PWM.

Zápis hexadecimální hodnoty 0x4842 do registru 1999 funkcí 06 uloží HBUS jako nastavený režim, vrátí běžnou odpověď na zápis a restartuje modul. Tento příkaz je na všesměrové adrese nula záměrně odmítán. Při čtení registr jinak vrací nulu.

Konfigurace a obnova

Před přepnutím nastavte režim sběrnice a adresu Modbus prostřednictvím HBUS:

{"device":{"set_bus_mode":{"mode":"modbus","modbus_address":17}}}

Uložený režim se použije při příštím restartu. Zapnutý ladicí DIP přepínač při startu vynutí HBUS pouze pro tento běh a zachová uloženou přenosovou rychlost. Nastavení tak lze opravit bez vymazání modulu. Obnovení továrního nastavení odstraní konfiguraci sběrnice a soubor přenosové rychlosti a obnoví HBUS s rychlostí 19200 baudů.

Praktické příklady pro Node-RED

Následující příklady používají modul s adresou Modbus 1. Změňte unitid na nastavenou adresu cílového modulu.

Požadované nastavení sériové komunikace

V klientu node-red-contrib-modbus použijte:

  • sériové připojení
  • stejnou přenosovou rychlost jako v modulu
  • 8 datových bitů, bez parity a 1 stop bit
  • typ sériového spojení RTU-BUFFERD

Zápis RTU-BUFFERD používá balíček Node-RED. Nejde o stejnou volbu jako bufferování fronty příkazů.

Nebufferovaný sériový ovladač RTU při testování spolehlivě zvládal pouze čtení nejvýše 13 registrů. Odpověď funkce 04 pro 13 registrů má 31 bajtů, zatímco odpověď pro 14 registrů má 33 bajtů. Sériová vrstva operačního systému může delší odpověď rozdělit do více částí a nebufferovaný ovladač může první část považovat za úplný rámec. RTU-BUFFERD shromažďuje části, dokud neobdrží očekávanou délku odpovědi Modbus. Použijte jej pro všechny příklady v této části.

Následující pomocná funkce přijímá oba běžné formáty výstupu uzlu Modbus Flex Getter:

function registerData(msg) {
    if (Array.isArray(msg.payload)) {
        return msg.payload;
    }
    if (msg.payload && Array.isArray(msg.payload.data)) {
        return msg.payload.data;
    }
    throw new Error("Modbus response does not contain a register array");
}

Čtení úplné konfigurace modulu

Použijte uzel Function připojený k uzlu Modbus Flex Getter:

msg.payload = {
    value: 0,
    fc: 4,
    unitid: 1,
    address: 0,
    quantity: 22
};

return msg;

Odpověď dekódujte dalším uzlem Function:

function registerData(msg) {
    if (Array.isArray(msg.payload)) {
        return msg.payload;
    }
    if (msg.payload && Array.isArray(msg.payload.data)) {
        return msg.payload.data;
    }
    throw new Error("Modbus response does not contain a register array");
}

function u32(high, low) {
    return ((high << 16) | low) >>> 0;
}

function hex32(value) {
    return value.toString(16).padStart(8, "0");
}

const portModes = {
    0: "sensor-autodetect",
    1: "button_simple",
    2: "button_double",
    3: "input",
    4: "input_safe",
    5: "impulse_counter",
    6: "impulse_counter_safe",
    7: "output",
    8: "output_safe",
    9: "pwm_50hz",
    10: "pwm_1khz",
    11: "pwm_25khz",
    12: "adc_raw_passive",
    13: "adc_raw_active",
    14: "adc_pullup_passive",
    15: "adc_pullup_active",
    16: "encoder",
    17: "encoder_reverse"
};

const r = registerData(msg);
const flags = r[1];
const sensorOverflow = r[21];

msg.payload = {
    firmware_api: "4.0",
    register_map_version: r[0],
    flags: {
        raw: flags,
        debug: Boolean(flags & 1),
        filesystem_update: Boolean(flags & 2),
        event_overflow: Boolean(flags & 4),
        sensor_slot_overflow: Boolean(flags & 8)
    },
    uptime: u32(r[2], r[3]),
    device_id: hex32(u32(r[4], r[5])),
    baudrate: u32(r[6], r[7]),
    modbus_address: r[8],
    configured_mode: r[9] === 1 ? "modbus" : "hbus",
    active_mode: r[10] === 1 ? "modbus" : "hbus",
    sensors: {
        ds18x20: r[11],
        sht3x: r[12],
        scd4x: r[13]
    },
    ports: {
        A: portModes[r[14]] || `unknown-${r[14]}`,
        B: portModes[r[15]] || `unknown-${r[15]}`,
        C: portModes[r[16]] || `unknown-${r[16]}`
    },
    software_crc32: hex32(u32(r[17], r[18])),
    hardware_crc32: hex32(u32(r[19], r[20])),
    sensor_overflow: {
        raw: sensorOverflow,
        ds18x20: Boolean(sensorOverflow & 1),
        sht3x: Boolean(sensorOverflow & 2),
        scd4x: Boolean(sensorOverflow & 4)
    }
};

return msg;

Tento blok obsahuje úplnou konfiguraci dostupnou přes Modbus. Alias, úprava tabulky kompenzací a další konfigurační operace specifické pro HBUS nejsou ve firmwaru 4.0 dostupné jako registry Modbus.

Zjištění připojených čidel

Výše uvedené čtení úplné konfigurace již vrací počet obsazených pozic čidel v registrech 11 až 13. Chcete-li přečíst pouze tyto počty:

msg.payload = {
    value: 0,
    fc: 4,
    unitid: 1,
    address: 11,
    quantity: 3
};

return msg;

Vrácené pole obsahuje počty čidel DS18x20, SHT3x a SCD4x v tomto pořadí:

[DS18x20 count, SHT3x count, SCD4x count]

Pokud je počet čidel nula, příslušný blok nečtěte. Pro nenulový počet přečtěte přesně tolik registrů, kolik odpovídá obsazeným pozicím:

Čidlo Počáteční adresa Registrů na čidlo Počet čtených registrů
DS18x20 400 4 count * 4
SHT3x 600 4 count * 4
SCD4x 640 5 count * 5

Čtení čidel DS18x20

Tento požadavek přečte jednu pozici DS18x20:

msg.payload = {
    value: 0,
    fc: 4,
    unitid: 1,
    address: 400,
    quantity: 4
};

return msg;

Dekódování jedné nebo více pozic:

function registerData(msg) {
    return Array.isArray(msg.payload) ? msg.payload : msg.payload.data;
}

function u32(high, low) {
    return ((high << 16) | low) >>> 0;
}

function signed16(value) {
    return value & 0x8000 ? value - 0x10000 : value;
}

const r = registerData(msg);
const sensors = [];

for (let offset = 0; offset + 3 < r.length; offset += 4) {
    if (r[offset] === 0xffff && r[offset + 1] === 0xffff) {
        continue;
    }
    sensors.push({
        id: u32(r[offset], r[offset + 1]).toString(16).padStart(8, "0"),
        temperature: signed16(r[offset + 2]) / 10,
        valid: Boolean(r[offset + 3] & 1)
    });
}

msg.payload = sensors;
return msg;

Čtení čidel SHT3x

Pro jednu pozici SHT3x čtěte od adresy 600 s počtem registrů 4. Každá pozice obsahuje index HBUS, teplotu vynásobenou 10, vlhkost vynásobenou 10 a příznaky:

msg.payload = {
    value: 0,
    fc: 4,
    unitid: 1,
    address: 600,
    quantity: 4
};

return msg;
function registerData(msg) {
    return Array.isArray(msg.payload) ? msg.payload : msg.payload.data;
}

function signed16(value) {
    return value & 0x8000 ? value - 0x10000 : value;
}

const r = registerData(msg);
const sensors = [];

for (let offset = 0; offset + 3 < r.length; offset += 4) {
    if (r[offset] === 0xffff) {
        continue;
    }
    sensors.push({
        index: r[offset],
        temperature: signed16(r[offset + 1]) / 10,
        humidity: r[offset + 2] / 10,
        valid: Boolean(r[offset + 3] & 1)
    });
}

msg.payload = sensors;
return msg;

Čtení čidel SCD4x

Pro jednu pozici SCD4x:

msg.payload = {
    value: 0,
    fc: 4,
    unitid: 1,
    address: 640,
    quantity: 5
};

return msg;

Dekódování jedné nebo více pozic:

function registerData(msg) {
    return Array.isArray(msg.payload) ? msg.payload : msg.payload.data;
}

function signed16(value) {
    return value & 0x8000 ? value - 0x10000 : value;
}

const r = registerData(msg);
const sensors = [];

for (let offset = 0; offset + 4 < r.length; offset += 5) {
    if (r[offset] === 0xffff) {
        continue;
    }
    sensors.push({
        index: r[offset],
        co2: r[offset + 1],
        temperature: signed16(r[offset + 2]) / 10,
        humidity: r[offset + 3] / 10,
        valid: Boolean(r[offset + 4] & 1)
    });
}

msg.payload = sensors;
return msg;

Všechna měření čidel zahrnují nastavené kompenzační hodnoty.

Čtení digitálních vstupů a čítačů stisků

Pro získání všech 12 fyzických kanálů jedním požadavkem přečtěte registry 32 až 46:

msg.payload = {
    value: 0,
    fc: 4,
    unitid: 1,
    address: 32,
    quantity: 15
};

return msg;

Pokud je jako input nebo input_safe nastaven pouze port A, stačí počet registrů 7. Přečtou se tři bitové mapy a čítače A0 až A3.

function registerData(msg) {
    return Array.isArray(msg.payload) ? msg.payload : msg.payload.data;
}

const r = registerData(msg);
const stateBitmap = r[0];
const inputValidBitmap = r[1];
const pressValidBitmap = r[2];
const channels = [];

for (let channel = 0; channel < r.length - 3; channel++) {
    const mask = 1 << channel;
    channels.push({
        index: channel,
        port: ["A", "B", "C"][Math.floor(channel / 4)],
        pin: channel % 4,
        input_valid: Boolean(inputValidBitmap & mask),
        active: Boolean(stateBitmap & mask),
        press_counter_valid: Boolean(pressValidBitmap & mask),
        press_counter: r[3 + channel]
    });
}

msg.payload = {
    state_bitmap: stateBitmap,
    input_valid_bitmap: inputValidBitmap,
    press_valid_bitmap: pressValidBitmap,
    channels: channels
};

return msg;

Pro spolehlivé zpracování tlačítek porovnávejte každý čítač stisků s jeho hodnotou z předchozího cyklu čtení. Rozdíl bez znaménka vypočítáte takto:

const delta = (currentCounter - previousCounter) & 0xffff;

První vzorek určuje výchozí stav a nesmí vyvolat události stisků. Tento postup zachytí i krátké stisky, které začnou a skončí mezi dvěma cykly čtení.

Zápis a čtení logických výstupů

Pořadí kanálů je A0-A3, B0-B3 a C0-C3. Například B0 odpovídá holding registru 1004.

Nastavení B0 na logickou 1 pomocí uzlu Modbus Flex Write:

msg.payload = {
    value: 1,
    fc: 6,
    unitid: 1,
    address: 1004,
    quantity: 1
};

return msg;

Nastavení všech čtyř pinů portu B jedním požadavkem funkce 16:

msg.payload = {
    value: [1, 0, 1, 0],
    fc: 16,
    unitid: 1,
    address: 1004,
    quantity: 4
};

return msg;

Zpětné čtení čtyř stavů výstupů pomocí uzlu Modbus Flex Getter:

msg.payload = {
    value: 0,
    fc: 3,
    unitid: 1,
    address: 1004,
    quantity: 4
};

return msg;

Cílový port musí být nastaven jako output nebo output_safe. Zápisy do kanálu v jiném režimu jsou odmítnuty.

Zápis a čtení výstupů PWM

Registry PWM používají celočíselnou střídu od 0 do 100. Například B0 odpovídá holding registru 1024.

Nastavení B0 na 50 procent:

msg.payload = {
    value: 50,
    fc: 6,
    unitid: 1,
    address: 1024,
    quantity: 1
};

return msg;

Nastavení všech čtyř kanálů PWM na portu B:

msg.payload = {
    value: [0, 25, 50, 100],
    fc: 16,
    unitid: 1,
    address: 1024,
    quantity: 4
};

return msg;

Zpětné čtení čtyř hodnot střídy pomocí uzlu Modbus Flex Getter:

msg.payload = {
    value: 0,
    fc: 3,
    unitid: 1,
    address: 1024,
    quantity: 4
};

return msg;

Cílový port musí být nastaven jako pwm_50hz, pwm_1khz nebo pwm_25khz. Hodnoty nad 100 a zápisy do kanálů v jiném režimu jsou odmítnuty.

Návrat modulu do režimu HBUS

Pomocí uzlu Modbus Flex Write zapište servisní hodnotu 0x4842 (18498 v desítkové soustavě) do holding registru 1999:

msg.payload = {
    value: 18498,
    fc: 6,
    unitid: 1,
    address: 1999,
    quantity: 1
};

return msg;

Modul nejprve vrátí běžnou odpověď funkce 06, uloží HBUS jako nastavený režim a poté se restartuje. Nastavená přenosová rychlost zůstane zachována. Všesměrový zápis na adresu nula je pro tuto operaci záměrně odmítán.