Reprezentacija uređaja

Uređaji imaju dva seta parametara:

  1. tvorničkefactory_device.json

  2. korisničkeuser_device.json

Tvornički parametri određuju hardverske parametre koji se ne mogu mijenjati i koje uređaji posjeduju kada izađu iz fabrike. Korisnički parametri su oni koji su poznati tek prilikom ugradnje uređaja u pametnu kuću i oni predstavljaju ličnu kartu svakog pojedinačnog uređaja.

Tvornički parametri bi se u pravilu trebali nalaziti u centralnoj bazi podataka. Ova baza podataka sadrži opise svih uređaja koji su prepoznati. S druge strane, korisnički parametri se pohranjuju samo u lokalnoj bazi podataka na nivou kuće.

Pošto mikrokontroleri obično posjeduju vrlo ograničene resurse, nezgodno je vršiti procesiranje JSON datoteka na samom mikrokontroleru. Pogodnije je iz JSON datoteka generisati C++ datoteke koje se popunjavaju samo osnovnim deklaracijama koje su specifične za uređaj, dok programer kasnije implementira funkcionalnost.

Generišu se sljedeće datoteke:

  1. main.cpp

  2. iot_device.h.in iot_device.h

  3. Datoteka iot_device.cpp sa praznim implementacijama funkcija

  4. Razne pomoćne datoteke unutar direktorija autogen

JSON datoteke

Datoteka factory_device.json

{
    "name": "TODO",
    "vendorId": "TODO",
    "model": "TODO",
    "functions": [
        {
            "name": "TODO", "friendly": "TODO",
            "valueType": "TODO", "valueRange": [ "TODO" ], "unit": "TODO"
        }
    ],
    "data": [
        {
            "name": "TODO", "friendly": "TODO",
            "valueType": "TODO", "unit": "TODO"
        }
    ]
}

Uputa

Tekst TODO programeru služi kao indikator da odgovarajući atribut nije još uvijek konfigurisan.

Atributi uređaja

Atribut name

Naziv modela uređaja.

Atributi vendorId, model

Ovi atributi predstavljaju identifikaciju uređaja i jedinstveni su za svaki uređaj istog modela, od istog proizvođača.

Niz data

Sadrži podatke koje se mogu zatražiti od uređaja. Ovo su najčešće neka mjerenja, ili trenutno stanje uređaja.

Atribut name
Format: Ispravan naziv C++ funkcije.

Jedinstveni identifikator koji ujedno predstavlja i ime metode u C++ klase Device. Ova metoda je po svom karakteru getter.

Atribut friendly

Naziv pod kojim će korisnik vidjeti ovaj podatak na GUI prikazu.

Atribut valueType
Moguće vrijednosti:

float, int, bool, <ENUM-TYPE>

Default: float

Određuje tip podatka koji se dobija sa uređaja. Ovaj podatak je payload odgovarajućeg topic-a. Može biti float, int, bool, ili naziv korisnički-definiranog enumeriranog tipa. Konkretne vrijednosti ovog enum-a se zadaju putem atributa valueRange koji je opisan u nastavku. U headeru iot_device.h će se generisati definicija ovog enum tipa.

Ako se ne navede atribut valueType, onda će se uzeti da je on void, što znači da ova funkcija ne zahtijeva nikakav ulazni podatak.

Atribut valueRange

Određuje skup vrijednosti koje može uzeti enum čiji je naziv sadržan u atributu valueType.

Atribut unit

Mjerna jedinica ulaznog parametra ove funkcije koja se treba prikazati u GUI. Ako se ne zada ovaj atribut, uzima se da je prazan string. Ako je valueType jednak void, onda ovaj atribut nema nikakvu ulogu.

Niz functions

Niz funkcija uređaja. Funkcija je bilo koja radnja koju uređaj može obavljati. Funkcija može da prima neki parametar, koji predstavlja nešto što korisnik zadaje pritiskom dugmeta, izborom iz menija ili sl. Korisnik ovu komandu u GUI vidi pod imenom koje se zadaje atributom friendly. U klasi Device će se generisati metoda sa nazivom name koju programer treba da implementira za konkretni uređaj. Generisana metoda je po svom karakteru setter.

Alternativno, funkcija može biti specificirana kao niz podfunkcija (multi function). Ovo je korisno ako dvije funkcije konceptualno pripadaju istoj skupini (na primjer funkcije upali i ugasi za neku pametnu lampu utiču na ON/OFF stanje lampe).

Atribut valueType
Moguće vrijednosti:

float, int, bool, void, <ENUM-VALUE>

Default: void

Ima sličnu ulogu kao istoimeni atribut u sklopu podatka uređaja . Jedna razlika je da ovaj atribut može imati dodatnu vrijednost void. Ovaj parametar predstavlja ulaznu vrijednost koja se šalje uređaju da bi izvršio funkciju. To je ujedno i parametar odgovarajuće C++ funkcije. Tip void znači da uređaj ne zahtijeva nikakav parametar za izvršenje funkcije.

Atribut valueRange

U slučaju da je valueType neki brojni tip, ovaj atribut treba biti niz od dva elementa koji sadrži donju i gornju granicu vrijednosti. U slučaju da je valueType korisnički definirani enum tip, ovaj niz sadrži sve moguće vrijednosti ovog enum tipa u obliku stringova.

Atribut unit

Ima istu ulogu kao istoimeni atribut u sklopu funkcija.

Atribut if

Određuje kada je funkcija omogućena za upotrebu. Uvijek je formata <DEVICE_DATA> = <VALUE> pri čemu su <DEVICE_DATA> i <VALUE> zamijenjeni konkretnim vrijednostima. Dakle funkcija je omogućena kada je podatak <DEVICE_DATA> jednak <VALUE>.

Napomena

Unutar atributa if svi razmaci se ignorišu.


Primjer

{
    "name": "setBrightness", "friendly": "Set Brightness",
    "valueType": "float", "valueRange": [ 0.0, 100.0 ], "unit": "%"
}

Ovo je primjer primitivne funkcije koja ne sadrži nikakve podfunkcije. Naziv funkcije je setBrightness i to je ujedno naziv odgovarajuće C++ funkcije i MQTT teme. Korisnik treba da vidi ovu funkciju sa ljepšim imenom “Set Brightness”. Tip vrijednosti koju prima funkcija je float i to je ujedno tip parametra kojeg prima odgovarajuća C++ funkcija. Opseg vrijednosti koje može imati parametar je od 0.0 do 100.0. Mjerna jedinica parametra je %.

Napomena

U slučaju tipa float, atribut valueRange se koristi samo da bi se na GUI ograničio opseg vrijednosti koje korisnik može unijeti. Ovaj atribut se ne koristi prilikom implementacije uređaja na mikrokontroleru.

Primjer

[
    { "name": "turnOn", "friendly": "Turn On", "if": "getState=Off" },
    { "name": "turnOff", "friendly": "Turn Off", "if": "getState=On" }
],

U ovom slučaju funkcija je sastavljena od dvije podfunkcije koje se pojedinačno tumače kao u prethodnom primjeru.

Osnovna zamisao ovakvog zadavanja funkcije je da se na GUI dvije ili više radnji može prikazati korištenjem istog widget-a. U ovom slučaju bi se mogao koristiti widget Button čiji je tekst jednak sadržaju atributa friendly one podfunkcije koja je omogućena. Korisnik može pritisnuti ovo dugme da bi aktivirao onu funkciju čiji je naziv prikazan u tekstu dugmeta.

Stanje omogućenosti funkcije određuje atribut if. Funkcija turnOn je omogućena ako je podatak getState jednak Off, a u suprotnom je omogućena funkcija turnOff.


Datoteka user_device.json

Lična karta svakog konkretnog uređaja.

{
    "serialNo": "TODO",
    "location": "TODO",
    "ip": "192.168.1.TODO",
    "subnetMask": "255.255.255.0 TODO",
    "defaultGateway": "192.168.1.1 TODO",
    "brokerHost": "TODO"
}

Uputa

Tekst TODO programeru služi kao indikator da odgovarajući atribut nije još konfigurisan.

C++ datoteke

Napomena

Ovaj odjeljak je od interesa samo za programere uređaja.

Datoteka device.h.in

#ifndef IOT_DEVICE_H
#define IOT_DEVICE_H

/*** Enums ***/

namespace Device
{

    // Basic device information
    inline const char *getName() { return "$name"; }
    inline const char *getVendorId() { return "$vendorId"; }
    inline const char *getModel() { return "$model"; }

    /*** Function declarations ***/

    /*** Data declarations ***/

    void initialize();
};

#endif // IOT_DEVICE_H

Ova datoteka je predložak za datoteku iot_device.h koja se treba generisati u MBED workspace-u. Gdje god se u datoteci nađu alfanumerički znakovi ispred kojih se nalazi znak $ treba se ubaciti vrijednost odgovarajućeg atributa uređaja. Također, svaka linija omeđena znakovima /*** ***/ će biti zamijenjena automatski generisanim deklaracijama/definicijama odgovarajućih funkcija. Sve što je potrebno za generisanje ove datoteke se nalazi u odgovarajućoj datoteci factory_device.json. Datoteka user_device.json se ovdje ne koristi.


Primjer

Ako je u datoteci factory_device.json definiran sljedeći atribut uređaja:

{
    "...": "...",
    "vendorId": "ETF_SIAU",
    "...": "..."
}

sljedeća linija iz datoteke iot_device.h.in

const char *getVendorId() const { return "$vendorId"; }

će biti zamijenjena sa:

const char *getVendorId() const { return "ETF_SIAU"; }


Datoteka main.cpp

#include <mbed.h>

#include "iot_device.h"
#include "autogen/user_device.h"
#include "autogen/mqtt_wrapper.h"

int main(void)
{
    ethernetConnect(IP_ADDR, SUBNET_MASK, DEFAULT_GW);
    mqttConnect(BROKER_HOST);
    mqttAutoSubscribe();
    Device::initialize();
    while (true) mqttYield(100);
    return 0;
}

Ova datoteka sadrži osnovnu logiku programa. Programer može po potrebi proširiti funkcionalnost ove datoteke. Preprocesorske konstante IP_ADDR, SUBNET_MASK itd. se mogu pronaći u datoteci autogen/user_device.h i generisani su na osnovu datoteke user_device.json.