FULL-C: MQTT functions: Porovnání verzí

(Založena nová stránka s textem „FULL-C == Síťové funkce: komunikace MQTT (klient) ve FULL-C == Zařízení SDS umožňuje komunikovat s MQTT brokerem, tedy SDS lze provozovat jako M…“)
 
 
(Nejsou zobrazeny 4 mezilehlé verze od stejného uživatele.)
Řádek 2: Řádek 2:
  
 
== Síťové funkce: komunikace MQTT (klient) ve FULL-C ==
 
== Síťové funkce: komunikace MQTT (klient) ve FULL-C ==
−
 
+
__NOTOC__
 
Zařízení SDS umožňuje komunikovat s MQTT brokerem, tedy SDS lze  provozovat jako MQTT klienta.
 
Zařízení SDS umožňuje komunikovat s MQTT brokerem, tedy SDS lze  provozovat jako MQTT klienta.
  
 
Za tímto účelem jsou k dispozici tyto funkce:
 
Za tímto účelem jsou k dispozici tyto funkce:
−
<c>
+
<pre>
 
.
 
.
 
         void mqtt_connect(unsigned int IP0, unsigned int IP1, unsigned int IP2, unsigned int IP3, unsigned int TCPport, char *ClientID, char *username, char *password, unsigned int KeepAliveSec);
 
         void mqtt_connect(unsigned int IP0, unsigned int IP1, unsigned int IP2, unsigned int IP3, unsigned int TCPport, char *ClientID, char *username, char *password, unsigned int KeepAliveSec);
Řádek 14: Řádek 14:
 
         void mqtt_unsubscribe_index(unsigned int TableIndex);
 
         void mqtt_unsubscribe_index(unsigned int TableIndex);
 
         void mqtt_unsubscribe_name(char *FullTopicName);
 
         void mqtt_unsubscribe_name(char *FullTopicName);
−
</c>
+
</pre>
  
 
Proměnné IP0 až IP3 skládají (po částech) dohromady konkrétní IP adresu (IP0.IP1.IP2.IP3), ke které se SDS (MQTT klient) připojí.
 
Proměnné IP0 až IP3 skládají (po částech) dohromady konkrétní IP adresu (IP0.IP1.IP2.IP3), ke které se SDS (MQTT klient) připojí.
Řádek 31: Řádek 31:
  
 
Základní připojení k brokeru, publikování položky a odpojení:
 
Základní připojení k brokeru, publikování položky a odpojení:
−
<c>
+
<pre>
 
.  
 
.  
 
  // *** CONNECT
 
  // *** CONNECT
Řádek 97: Řádek 97:
 
   
 
   
 
   printf("connection to broker - FAILED \n");
 
   printf("connection to broker - FAILED \n");
−
</c>
+
</pre>
  
−
Samozřejmě si z příkladu vyberete jednotlivé části tak, jak zapadají do vašeho programu. Připojení je potřeba provést "jen jednou" na začátku, a SDS automaticky udržuje spojení (MQTT PING, tedy formou protokolového keep alive). Pokud by došlo ke ztrátě spojení (což se může stát), je toto předáno formou chybového hlášení (čtení patřičného indexu pomoci SDS_get funkce).
+
Samozřejmě si z příkladu vyberete jednotlivé části tak, jak zapadají do vašeho programu. Připojení je potřeba provést "jen jednou" na začátku, a SDS automaticky udržuje spojení (MQTT PING, tedy formou protokolového keep alive) až do buď (1.) uzavření spojení nebo (2.) výpadku síťového připojení (např. odpojení ETH kabelu z SDS) nebo (3.) specifické závažné chybě při komunikace mezi SDS a brokerem/serverem. Pokud by došlo ke ztrátě spojení (což se může stát), je toto předáno formou chybového hlášení (čtení patřičného indexu pomoci SDS_get funkce), a celý proces připojení a subscribe je potřeba samozřejmě zopakovat. Je proto nezbytné trvale kontrolovat příslušné systémové indexy.
  
 
Je-li SDS připojeno, lze provádět neomezené publikování hodnot, a také se lze přihlásit k odběru (subscribe).
 
Je-li SDS připojeno, lze provádět neomezené publikování hodnot, a také se lze přihlásit k odběru (subscribe).
Řádek 106: Řádek 106:
  
 
Příklad přihlášení k odběru:
 
Příklad přihlášení k odběru:
−
<c>
+
<pre>
 
   
 
   
 
  // note. SDS shall be connected to a broker, at this point
 
  // note. SDS shall be connected to a broker, at this point
Řádek 179: Řádek 179:
 
  // todo: wait for result !
 
  // todo: wait for result !
 
   
 
   
−
</c>
+
</pre>
  
 
Další příklady budou eventuálně doplněny, požadavky na ně předejte přes forum.
 
Další příklady budou eventuálně doplněny, požadavky na ně předejte přes forum.
  
 +
 +
=== Udržování spojení ===
 +
 +
PŘÍKLAD VE FULL-C:
 +
<syntaxhighlight lang="c">
 +
// MQTT: make sure the broker is connected, reconnect if needed (blocks up to ~20 s)
 +
// returns 1 = connected, 2 = freshly reconnected (subscribe again!), 0 = failed
 +
int mq_link(void)
 +
{
 +
  int st;
 +
  unsigned int t0;
 +
 +
  st = SDS_get_i32(12200);
 +
  if (st == 4) return 1;
 +
 +
  // not connected or status damaged (e.g. -3 after a too-early call): clean up first
 +
  if ((st != 0) && (st != -2))
 +
  {
 +
    mqtt_disconnect();
 +
    t0 = SDS_get_u32(45);
 +
    for (;;)
 +
    {
 +
      st = SDS_get_i32(12200);
 +
      if ((st == 0) || (st == -2)) break;
 +
      if ((SDS_get_u32(45) - t0) > 5000) break;
 +
      wait(10);
 +
    }
 +
    wait(500);
 +
  }
 +
 +
  mqtt_connect(192, 168, 3, 99, 1883, "my-sds", "user", "password", 60);
 +
  t0 = SDS_get_u32(45);
 +
  for (;;)
 +
  {
 +
    st = SDS_get_i32(12200);
 +
    if (st == 4) break;
 +
    if (st < 0) return 0;
 +
    if ((SDS_get_u32(45) - t0) > 15000) return 0;
 +
    wait(10);
 +
  }
 +
  if (SDS_get_i32(12201) != 0) { mqtt_disconnect(); return 0; }
 +
  return 2;
 +
}
 +
</syntaxhighlight>
  
 
== Hodnoty v systémových indexech ==
 
== Hodnoty v systémových indexech ==
  
−
Významy údajů vrácených funkcí SDS_get_i32() pro MQTT klienta:
+
Pomocí SDS_set_u32() lze zapsat následující hodnoty (a pomoci SDS_get_u32() je zpátky přečíst):
 +
 
 +
SDS_get_u32(11198)    hodnota zapsaná do MQTT PUBLISH Fixed Header
 +
--------------------------------------------------------------------------------------------------------------------------------------------
 +
  0b0011dqqr : d=DUP, qq=QOS, r=RETAIN  ( výchozí hodnota je 0b00110001 )
 +
 
 +
 
 +
Významy údajů vrácených funkcí SDS_get_i32() pro MQTT klienta: '''Hodnoty jsou jen pro čtení (read-only).'''
  
 
  SDS_get_i32(12200)    stav průběhu mqtt_connect()
 
  SDS_get_i32(12200)    stav průběhu mqtt_connect()
Řádek 239: Řádek 290:
 
  SDS_get_i32(12203)    počet chyb v přijatých datech MQTT protokolu (data z Brokeru) (chyba způsobí zavření spojení)
 
  SDS_get_i32(12203)    počet chyb v přijatých datech MQTT protokolu (data z Brokeru) (chyba způsobí zavření spojení)
 
  --------------------------------------------------------------------------------------------------------------------------------------------
 
  --------------------------------------------------------------------------------------------------------------------------------------------
 +
 +
 +
=== Známé chyby ve firmware ===
 +
 +
V průběhu provozu řady SDS bylo mnoha uživateli testováno, jak se MQTT v SDS chová. Byly nalezeny různé záležitosti, které se průběžně v nových vydáních firmware řeši a opravují.
 +
 +
Pokud však máte starší firmware, nebo ještě pokud nebyl vůbec opravený firmware vydán, musíte tato omezení znát a použít opravné postupy ve vlastním FULL-C programu.
 +
 +
'''Délka odeslání MQTT dat do brokeru'''
 +
 +
Původní firmware může mít až půl sekundy zpoždění mezi zavoláním funkce mqtt_publish() a skutečným odesláním příslušného paketu do sítě. To je řešeno v novém firmware, ale pokud jej nemáte, musíte svůj FC program psát tak, aby s tímto uměl správně pracovat.
 +
 +
'''Špatné předání chybových stavů'''
 +
 +
Je-li zavoláno mqtt_publish() nebo mqtt_subscribe() nebo mqtt_unsubscribe_*(), zapíše to -3 do indexu [12200] namísto správného indexu [12202].
 +
Takže [12200] zůstane s obsahem -3, i když tam ta hodnota nemá co dělat. Toto má pak důsledek v tom, že pokud váš program testuje [12200] na hodnotu 4 tak ji tam neuvidí a bude si nesprávně myslet, že došlo k odpojení SDS od brokeru.<br>
 +
''Toto je opraveno v novém firmware (11/2026 a novější).''
 +
 +
Správně to má být: <br>
 +
* [12200] a [12201] = pouze pro mqtt_connect a mqtt_disconnect<br>
 +
* [12202] = pouze pro mqtt_publish, mqtt_subscribe, mqtt_unsubscribe_* atd.<br>
 +
 +
Ve starším firmware byla chyba, kdy místo do [12202] se některé chybové stavy (záporné hodnoty např. -3, -5, -7 atd.) zapsaly nesprávně do [12200].
 +
 +
 +
'''Po odpojení přes mqtt_disconnect() občas dojde k předání chyby výpadku TCP spojení'''
 +
 +
Toto je vlastnost, která se týká sítě, a nelze ji vždy vyloučit.
 +
 +
Po zavolání mqtt_disconnect() může postupně dojít k zápisu hodnoty -2 do [12200] (ihned po zavolání je zapsáno 32 do [12200], a pak proběhne ukončení TCP spojení, které může ve svém postupu zapsat -2).
 +
 +
Proto pozor při použití testu <pre>SDS_get_i32(12200) != 4</pre> , protože to může vyhodnotit v podstatě správné ukončení spojení jako chybu.
 +
 +
  
 
Konec stránky.
 
Konec stránky.

Aktuální verze z 31. 10. 2026, 11:08

FULL-C

Síťové funkce: komunikace MQTT (klient) ve FULL-C

Zařízení SDS umožňuje komunikovat s MQTT brokerem, tedy SDS lze provozovat jako MQTT klienta.

Za tímto účelem jsou k dispozici tyto funkce:

.
         void mqtt_connect(unsigned int IP0, unsigned int IP1, unsigned int IP2, unsigned int IP3, unsigned int TCPport, char *ClientID, char *username, char *password, unsigned int KeepAliveSec);
         void mqtt_disconnect(void);
         void mqtt_publish(char *FullTopicName, char *Value);
         void mqtt_subscribe(unsigned int TableIndex, char *FullTopicName);
         void mqtt_unsubscribe_index(unsigned int TableIndex);
         void mqtt_unsubscribe_name(char *FullTopicName);

Proměnné IP0 až IP3 skládají (po částech) dohromady konkrétní IP adresu (IP0.IP1.IP2.IP3), ke které se SDS (MQTT klient) připojí.


Princip

Veškerý popis využití MQTT je na této stránce (odkaz je zde).

Implementace ve FULL-C odpovídá implementaci v SDS-C, jediný rozdíl je popsán zde:


Příklady

Základní připojení k brokeru, publikování položky a odpojení:

. 
 // *** CONNECT
 
 // connect on start
 printf("connecting to MQTT broker...\n");
 
 //           ip   ip   ip ip   port  client-id          username   password    reserved
 mqtt_connect(192, 168, 1, 253, 1883, "sds-client-1234", "sds1234", "password", 0);
 
 // now wait for a complete connection:
 
 // done - connected ?
 while (SDS_get_i32(12200) != 4) 
 {
   // any error - did it fail ?
   if (SDS_get_i32(12200) < 0) goto mqtt_conn_fail;
 }
 
 // OK, done, so now:
 // test the CONNACK result - see "3.2.2.3 Connect Return code"
 
 if (SDS_get_i32(12201) != 0) goto mqtt_conn_fail;
 
 // CONNECTED OK ! (result is 0x00)
 
 printf("connected to broker OK, result in 12200=%d\n", SDS_get_i32(12200));
 
 
 // *** PUBLISH
 
 printf("publishing...");
 
 mqtt_publish("sds/temps/value1", "123456");
 
 // wait until done
 while (SDS_get_i32(12202) == 1)
 {
   // disconnected ?
   if (SDS_get_i32(12200) < 0) goto mqtt_conn_fail;    
 }
  
 // was it success ?
 if (SDS_get_i32(12202) != 2)
 { 
   // it FAILED
   printf("publish error = %d\n", SDS_get_i32(12202)); 
 };
 
 printf("OK\n");
 
 
 // *** DISCONNECT
 
 mqtt_disconnect();
 
 // todo: wait for disconnection result !!!
 
 ...
 
 return;
 
 //
 mqtt_conn_fail:
 
  printf("connection to broker - FAILED \n");

Samozřejmě si z příkladu vyberete jednotlivé části tak, jak zapadají do vašeho programu. Připojení je potřeba provést "jen jednou" na začátku, a SDS automaticky udržuje spojení (MQTT PING, tedy formou protokolového keep alive) až do buď (1.) uzavření spojení nebo (2.) výpadku síťového připojení (např. odpojení ETH kabelu z SDS) nebo (3.) specifické závažné chybě při komunikace mezi SDS a brokerem/serverem. Pokud by došlo ke ztrátě spojení (což se může stát), je toto předáno formou chybového hlášení (čtení patřičného indexu pomoci SDS_get funkce), a celý proces připojení a subscribe je potřeba samozřejmě zopakovat. Je proto nezbytné trvale kontrolovat příslušné systémové indexy.

Je-li SDS připojeno, lze provádět neomezené publikování hodnot, a také se lze přihlásit k odběru (subscribe).

SDS nabízí možnost využít svou tabulku přihlášení (subscribe table), kam si vložíte položky které vás zajímají (každou pod jiným indexem) a SDS bude pro tyto položky trvale udržovat jejich aktuální hodnoty (values), tak jak je bude broker do SDS posílat. Váš program se pak kdykoliv do tabulky může podívat a přečíst si aktuální stav. Samozřejmě použití tabulky není nutnost, ale bez ní můžete přijít o aktualizaci, pokud ji svým programem nezachytíte.

Příklad přihlášení k odběru:

 
 // note. SDS shall be connected to a broker, at this point
 
 // *** let us subscribe to a topic:
 
 printf("subscribing...");
 
 // for this example, we choose index '1':
 mqtt_subscribe(1, "ha/output/q1/state");
 
 // wait for result
 while (SDS_get_i32(12202) == 4)
 {
   // disconnected ?
   if (SDS_get_i32(12200) < 0) goto mqtt_conn_fail;
 }
 
 // success ?
 if (SDS_get_i32(12202) != 8)
 { 
   // failed...
   printf("sub error = %d\n", SDS_get_i32(12202)); 
 };
 
 // OK we ARE subscribed !
 
 printf("OK\n");
 
 
 // *** example: watch for updates coming from broker, and print it to console
 
 unsigned int last1;
 char tn[32+1];
 char tv[32+1];
 
 last1 = 0;
 
 while(1)
 {
 
   // any change ? (any new message from broker, processed by SDS ?)
   if (last1 != SDS_get_u32(12291))  // 12291 is a timestamp for index #1
   {
      // store so we can compare it later, again
      last1 = SDS_get_u32(12291);
 
      // read Topic Name (tn) and the new Value (tv)
      SDS_get_a(12211, &tn, 32);
      SDS_get_a(12251, &tv, 32);
 
      // print to console
      printf("TOPIC #1: %s update to: %s \n", tn, tv);
  };
 
  // always check the connection state
  if (SDS_get_i32(12200) < 0)
  {  
    // disconnected
    printf("disconn\n"); break;
  }
 
 // continue loop
 }
 
 
 ...
 
 // *** unsubscribe
 mqtt_unsubscribe_index(1);
 
 // todo: wait for result !
 

Další příklady budou eventuálně doplněny, požadavky na ně předejte přes forum.


Udržování spojení

PŘÍKLAD VE FULL-C:

// MQTT: make sure the broker is connected, reconnect if needed (blocks up to ~20 s)
// returns 1 = connected, 2 = freshly reconnected (subscribe again!), 0 = failed
int mq_link(void)
{
  int st;
  unsigned int t0;

  st = SDS_get_i32(12200);
  if (st == 4) return 1;

  // not connected or status damaged (e.g. -3 after a too-early call): clean up first
  if ((st != 0) && (st != -2))
  {
    mqtt_disconnect();
    t0 = SDS_get_u32(45);
    for (;;)
    {
      st = SDS_get_i32(12200);
      if ((st == 0) || (st == -2)) break;
      if ((SDS_get_u32(45) - t0) > 5000) break;
      wait(10);
    }
    wait(500);
  }

  mqtt_connect(192, 168, 3, 99, 1883, "my-sds", "user", "password", 60);
  t0 = SDS_get_u32(45);
  for (;;)
  {
    st = SDS_get_i32(12200);
    if (st == 4) break;
    if (st < 0) return 0;
    if ((SDS_get_u32(45) - t0) > 15000) return 0;
    wait(10);
  }
  if (SDS_get_i32(12201) != 0) { mqtt_disconnect(); return 0; }
  return 2;
}

Hodnoty v systémových indexech

Pomocí SDS_set_u32() lze zapsat následující hodnoty (a pomoci SDS_get_u32() je zpátky přečíst):

SDS_get_u32(11198)    hodnota zapsaná do MQTT PUBLISH Fixed Header
--------------------------------------------------------------------------------------------------------------------------------------------
 0b0011dqqr : d=DUP, qq=QOS, r=RETAIN   ( výchozí hodnota je 0b00110001 )


Významy údajů vrácených funkcí SDS_get_i32() pro MQTT klienta: Hodnoty jsou jen pro čtení (read-only).

SDS_get_i32(12200)    stav průběhu mqtt_connect()
--------------------------------------------------------------------------------------------------------------------------------------------
                  -7 = obdrželi jsme CONNACK, ale negativní = nepřipojeno ( výsledek viz 12201 )
                  -6 = timeout při čekání na připojení, nepřipojeno
                  -5 = nespravne parametry (hodnoty např. IP, port), nepřipojeno
                  -4 = nespravne parametry (počet parametrů), nepřipojeno
                  -3 = funkce zavolána dříve (nebo opakovaně) než bylo dokončeno předchozí volání funkce, takže toto volání je ignorováno
                  -2 = pokus o TCP připojení selhal
                  -1 = nepoužito
                   0 = klid, nic se neprovádí, ODPOJENO ! (lze se začít připojovat)
                   1 = bylo zahájeno připojování (otevírá se TCP spojení)
                   2 = TCP připojeno a odeslán CONNECT požadavek
                   4 = obdrželi jsme CONNACK, připojeno ( výsledek viz 12201 )
                   8 = probíhá odpojování, čekáme na výsledek (na odpojení)
SDS_get_i32(12201)    výsledek mqtt_connect() = hodnota "CONNACK Connect Return"
--------------------------------------------------------------------------------------------------------------------------------------------
                  -7 = nepoužito
                  -6 = timeout při čekání na CONNACK, nepřipojeno
                  -5 = nepoužito
                  -4 = nepoužito
                  -3 = nepoužito
                  -2 = probíhá připojování, čekáme na CONNACK (zatím nepřišel)
                  -1 = idle, nepřipojeno
                   0 = (výsledek:) MQTT 0x00: broker akceptoval připojení - LZE POKRAČOVAT (provádět Publish, Subscribe)
                   1 = MQTT 0x01: Connection Refused, unacceptable protocol version
                   2 = MQTT 0x02: Connection Refused, identifier rejected
                   3 = MQTT 0x03: Connection Refused, Server unavailable
                   4 = MQTT 0x04: Connection Refused, bad user name or password
                   5 = MQTT 0x05: Connection Refused, not authorized
SDS_get_i32(12202)    výsledek pro tyto funkce: mqtt_publish(), mqtt_subscribe(), mqtt_unsubscribe_index(), mqtt_unsubscribe_name()
--------------------------------------------------------------------------------------------------------------------------------------------
                  -8 = SUBACK dorazil z Broker ale s indikovanou chybou (Failure Bit), můžete volat další funkci
                  -7 = vybraná položka (řádek) subscribe tabulky je prázdná, není co odhlašovat
                  -6 = timeout (možnosti: publish neprovedeno, nebo: SUBACK vůbec nedorazil, nebo: UNSUBACK vůbec nedorazil), můžete volat další funkci
                  -5 = nespravne parametry (hodnoty, např. index) např. jejich celková délka se nevleze do paketu
                  -4 = nespravne parametry (počet parametrů), nepřipojeno
                  -3 = funkce zavolána dříve (nebo opakovaně) než bylo dokončeno předchozí volání funkce, takže toto volání je ignorováno
                  -2 = SDS není připojeno k brokeru (buď právě ještě probíhá připojování, nebo není vůbec připojeno)
                  -1 = bez aktivity
                   0 = nepoužito
                   1 = mqtt_publish() probíhá
                   2 = mqtt_publish() hotovo (OK - obdržen TCP ACK), můžete volat další funkci
                   4 = mqtt_subscribe() probíhá - čekám na SUBACK
                   8 = SUBACK dorazil z Broker, bez chyby (OK), můžete volat další funkci
                  16 = čekám na UNSUBACK (pouze pro unsubscribe funkce)
                  32 = UNSUBACK dorazil z Brokera, můžete volat další funkce
SDS_get_i32(12203)    počet chyb v přijatých datech MQTT protokolu (data z Brokeru) (chyba způsobí zavření spojení)
--------------------------------------------------------------------------------------------------------------------------------------------


Známé chyby ve firmware

V průběhu provozu řady SDS bylo mnoha uživateli testováno, jak se MQTT v SDS chová. Byly nalezeny různé záležitosti, které se průběžně v nových vydáních firmware řeši a opravují.

Pokud však máte starší firmware, nebo ještě pokud nebyl vůbec opravený firmware vydán, musíte tato omezení znát a použít opravné postupy ve vlastním FULL-C programu.

Délka odeslání MQTT dat do brokeru

Původní firmware může mít až půl sekundy zpoždění mezi zavoláním funkce mqtt_publish() a skutečným odesláním příslušného paketu do sítě. To je řešeno v novém firmware, ale pokud jej nemáte, musíte svůj FC program psát tak, aby s tímto uměl správně pracovat.

Špatné předání chybových stavů

Je-li zavoláno mqtt_publish() nebo mqtt_subscribe() nebo mqtt_unsubscribe_*(), zapíše to -3 do indexu [12200] namísto správného indexu [12202]. Takže [12200] zůstane s obsahem -3, i když tam ta hodnota nemá co dělat. Toto má pak důsledek v tom, že pokud váš program testuje [12200] na hodnotu 4 tak ji tam neuvidí a bude si nesprávně myslet, že došlo k odpojení SDS od brokeru.
Toto je opraveno v novém firmware (11/2026 a novější).

Správně to má být:

  • [12200] a [12201] = pouze pro mqtt_connect a mqtt_disconnect
  • [12202] = pouze pro mqtt_publish, mqtt_subscribe, mqtt_unsubscribe_* atd.

Ve starším firmware byla chyba, kdy místo do [12202] se některé chybové stavy (záporné hodnoty např. -3, -5, -7 atd.) zapsaly nesprávně do [12200].


Po odpojení přes mqtt_disconnect() občas dojde k předání chyby výpadku TCP spojení

Toto je vlastnost, která se týká sítě, a nelze ji vždy vyloučit.

Po zavolání mqtt_disconnect() může postupně dojít k zápisu hodnoty -2 do [12200] (ihned po zavolání je zapsáno 32 do [12200], a pak proběhne ukončení TCP spojení, které může ve svém postupu zapsat -2).

Proto pozor při použití testu

SDS_get_i32(12200) != 4

, protože to může vyhodnotit v podstatě správné ukončení spojení jako chybu.


Konec stránky.