MQTT - Hva er det?

Fredrik om Mqtt og IoT

Publisert 06.05.2020

MQTT står for Message Queueing Telemetry Transport. Det er et lettvekts publish-subcribe meldingssystem. Det ble opprinnelig laget av to duder i 1999, for å overføre telemetri-data fra oljeledninger over satelitt. Det har senere blitt en ISO-standard.

Det er veldig enkelt og lettvekts, designet for lav båndbredde og ustabile nettverk, og det er laget for at klientene skal kunne kjøre på svak hardware og bruke lite strøm.

Hva kan det brukes til

Selv bruker jeg MQTT hjemme for å sende meldinger fra arduino-dingser til hjemmeautomasjonssystemet Openhab, så Openhab får vite hva stuetemperaturen er eller om noen ringer på døra. Et annet eksempel på virksomhetskritisk bruk av MQTT; i Storbritannia brukes MQTT i et signalsystem for togfremføring. Men de kanskje mest kjente produktene som bruker MQTT, i alle fall inntil nylig, er Facebook-appen og Facebook Messenger. De bruker det for å levere meldinger til telefonen din. Også den mest omtalte appen i Norge den siste tiden; Smittestopp, bruker MQTT for å sende informasjon til skyen. Så MQTT er altså godt egnet til å skjende personvern.

Men det er innen IoT at MQTT har oppnådd størst popularitet.

Hvordan fungerer det

La oss ta en titt på hvordan MQTT fungerer. Man trenger en MQTT-server (også kjent som en Broker), som tar i mot og sender meldinger til klientene. En klient sender meldinger til en topic på serveren, f.eks. til topicen hus/soverom/temperatur. Når MQTT-serveren mottar meldingen vil den videresendes til alle klientene som lytter til denne topicen.

MQTT SERVERPublisherhus/soverom/temperatur23.4Subscriber23.4hus/soverom/temperatur

I dette eksempelet sender en Arduino-dings med temperaturføler soveromstemperaturen til en topic på MQTT-serveren, og så mottas denne meldingen av Openhab, som lytter på denne topicen.

Dette er ikke bare MQTTs svar på hello-world, men et helt realistisk eksempel fra «produksjon». Når man bruker MQTT, i allefall i IoT-verdenen, er det vanlig med fin-granulerte topics og meldinger med små payloads. Dersom det finnes flere sensorer, f.eks. en luftfuktighetsmåler, på Arduino-dingsen, vil den typisk publisere luftfuktighet til en annen topic. En topic opprettes automatisk på MQTT-serveren når en melding publiseres på den, og «forsvinner» når det ikke ligger meldinger på den.

MQTT SERVERPublisher1hus/soverom/temperatur23.4hus/soverom/luftfuktighethus/soverom/onlinehus/stue/temperaturhus/stue/luftfuktighethus/stue/online60truePublisher221.354true

I dette eksempelet så har vi altså to temperatur- og luftfuktighetssensor, en på soverommet, og en på stua. Begge to publiserer til tre topics hver, en for å angi temperatur og en for luftfuktighet og til slutt online som, ganske riktig, sier om enheten er online eller ikke.

Abonnere på topics

Skråstreken(/) i topicene kalles for en topic level separator. Når man abonnerer på en topic, så kan man lytte på en bestemt topic som vi så i et tidligere eksempel. Eller man kan bruke wildcards, hvor vi kan velge blant # eller +.

MQTT SERVERPublisher1hus/soverom/temperatur23.4hus/soverom/luftfuktighethus/soverom/onlinehus/stue/temperaturhus/stue/luftfuktighethus/stue/online60truePublisher221.354trueSubscriber23.4hus/soverom/#60true

# kalles multilevel wildcard, og betyr alle subtopics. Dette må alltid være til slutt når du tegner abonnement. Du kan f.eks. abonnere på hus/soverom/#, og få alle meldinger som publiseres på subtopics til hus/soverom. I vårt eksempel er det altså hus/soverom/luftfuktighet, hus/soverom/temperatur og hus/soverom/online.

MQTT SERVERPublisher1hus/soverom/temperatur23.4hus/soverom/luftfuktighethus/soverom/onlinehus/stue/temperaturhus/stue/luftfuktighethus/stue/online60truePublisher221.354trueSubscriber23.4hus/#60true21.354true

Ved å abonnere på hus/# får man alle meldinger som publiseres på subtopics av hus. Man kan også abonnere på bare #, og få alle meldingene som publiseres på MQTT-severen. Men det er ikke sikkert det alltid er en god idé.

MQTT SERVERPublisher1hus/soverom/temperatur23.4hus/soverom/luftfuktighethus/soverom/onlinehus/stue/temperaturhus/stue/luftfuktighethus/stue/online60truePublisher221.354trueSubscriber23.4hus/+/temperatur21.3

+ kalles single-level wildcard, og brukes da som et wildcard for ett topic-nivå. Så hvis du for eksempel ønsker å regne ut gjennomsnittstemperaturen i alle rom i huset ditt kan du abonnere på hus/+/temperatur, og få alle meldinger som publiserer på en topic som har hus på første nivå, og temperatur på tredje nivå.

Hva består en mqtt-melding av

En melding inneholder naturligvis hvilken topic den skal til, samt payloaden til meldingen (som forøvrig kan være på max 256MB). I MQTT er payload alltid binær. Publisher og Subscriber må på forhånd være enige om hvordan disse binære dataene skal tolkes. Veldig ofte er man enige om at dataene skal leses som UTF-8 encoded tekst.

Quality of service

I tillegg setter man Quality of Service (QoS). MQTT har tre nivåer av QoS, level 0 er at most once, og level 1 er at least once, mens level 2 er exactly once. Default er level 0, som betyr at man sender av gårde meldingen og håper det går bra. Stort sett gjør det det, men det er ingen garantier. level 1 garanterer at meldingen blir levert, men den samme meldingen kan bli levert flere ganger. Bruker man level 1 kan man altså få duplikat-meldinger (selv om det ikke er vanlig, så må man ta høyde for at det kan skje). Mens level 2 garanterer at meldingen blir levert, og at det kun skjer en gang. Det blir litt mer nettverkets-overhead jo høyere nivå av quality of service.

Retainflagget

Hvis temperatursensoren din sender ny melding kun når temperaturen endrer seg, så vil en ny subscriber måtte vente ganske lenge fra den begynner å subscribe på en topic til den får vite hva soveromstemperaturen er. Med mindre temperatursensoren setter retain-flagget i meldingen. Da blir den siste meldingen som er sendt til topicen lagret på MQTT-serveren, og gitt til nye subscribers når de begynner å abonnere. Hvis man bruker MQTT med retain message så blir en MQTT-server nærmest en key-value store hvor man kan abonnere på endringene man er interessert i.

Våre tanker går til de etterlatte

Det er alltid trist når en publisher dør. Og de etterlatte subcriberne sitter ofte igjen med mange ubesvarte spørsmål. Er den virkelig død? Hva ville den skulle skje etter dens død? MQTT kan hjelpe deg med å få svar på noen av disse spørsmålene. En MQTT-klient kan skrive testament når den kobler seg opp til MQTT-serveren. Hvis klienten dør sørger serveren for å gjennomføre klients siste ønske. Hvis f.eks. temperatursensoren går tom for batteri, og dermed slutter å sende meldinger, så er det kjedelig hvis subscriberene fortsatt tror de får en ny melding når temperaturen endrer seg. Det kan Last Will and Testament (LWT) forhindre.

MQTT SERVERPublisherhus/soverom/onlineSubscribertruehus/soverom/onlineLast Will and Testament (LWT) lastWillTopic: hus/soverom/online lastWillMessage false keepAlive 600 lastWillRetain truetrue

I dette eksempelet er det en topic som heter hus/soverom/online. Klienten registerer seg med en last will and testament hvor klienten sier at sitt siste ønske er at det skal sendes en melding til topicen hus/soverom/online, med verdien false.

Rett etter at klienten har koblet seg til serveren publiserer den så en retained message med innholdet true på denne topicen. Da får alle nåværende og fremtidige klienter vite at temperatursensoren er online.

MQTT SERVERPublisherhus/soverom/onlineSubscriberfalsehus/soverom/onlineLast Will and Testament (LWT) lastWillTopic: hus/soverom/online lastWillMessage false keepAlive 600 lastWillRetain true

Men når klienten mister connection til MQTT-serveren av en eller annen grunn, så vil LWT-meldingen bli publisert av MQTT-serveren. Og alle subskribere får vite at temperatursensoren er offline.

Serveren publiserer LWT-meldingen kun hvis klientens oppkobling blir brutt. Kobler du deg av MQTT-serveren på vanlig måte ved å sende en disconnect kommando trer ikke testamentet i kraft. Så da er du selv ansvarlig for å sende offline-meldingen før du kobler deg fra.

Abonnement

Når du subscriber kan du velge om du vil være en non-persistent subscriber eller en persistent subscriber. Hvis du mister connection og er en non-persistent subscriber så vil du gå glipp av alle meldingene som matcher dine abonnement mens du er frakoblet (med unntak av den siste meldingen på en topic som har retainflagget satt, da). Hvis du er en persistent subscriber tar MQTT-serveren vare på alle meldingene som matcher dine abonnement og som har QoS level 1 eller høyere, og gir de til deg når du kobler på igjen.

Du kan også sette QoS level på subscription, og serveren kan da nedgradere QoS til et lavere nivå når den sender meldingen til subscriberen. Hvis en melding har level 2, og du subscriber med level 1 så vil serveren bruke level 2 når den mottar meldingen fra publisheren, men level 1 når den leverer til meldingen til deg. Men du kan ikke oppgradere QoS. Hvis meldingen har level 1 og du subscriber med level 2 så blir meldingen levert til deg med level 1.

Hva finnes der ute?

Det finnes mange implementasjoner av både MQTT-serverer og MQTT klientbiblioteker. Den kanskje mest kjente MQTT-servereren er Apache Mosquitto. Den finnes tilgjengelig i de fleste pakkebrønner, og er den jeg bruker hjemme. Ellers tilbyr sky-leverandørene også MQTT as a service, men da gjerne med noen begrensninger.

Det finnes (minst ett) MQTT-klientbibliotek tilgjengelig i de fleste programmeringsspråk, inkludert javascript (Ja du kan sende MQTT-meldinger fra og til nettleseren med MQTT over websockets).

Oppsummering

MQTT har noen fine egenskaper som gjør det til et godt valg hvis du har behov for å utveksle meldinger, og du ønsker å bruke så lite resurser som mulig. MQTT kan være verdt å se nærmere på neste gang du skal lage en mobilapp eller i ditt neste IoT-prosjekt.

Diskusjon

Vi diskuterer gjerne hvor enn du finner oss. Ta kontakt!

Mer fra bloggen