Vai al contenuto

MlsDevice, Milesight device manager

Vai all indice del manuale di programmazione
Tipo: Blocco Funzione
Libreria LogicLab: eLLabMQTTLib
Libreria Codesys: Non disponibile

Questo blocco funzione da eseguire in task Back, esegue la gestione dei dispositivi Milesight. Il FB si connette al gateway LoRaWAN tramite il FB MQTTClient.

Utility “MilesightEDTest”

Per il test dei codecs abbiamo sviluppato l’utility MilesightEDTest, dalla pagina web è possibile eseguire sia il decoding che l’encoding.

Milesight packet decoder

Selezionare il file java per il decoding, è possibile utilizzare un proprio file o salvare sul PC ed utilizzare il ePayloadtDecoder.js riportato sotto. Nella finestra di definizione stringa da decodificare è possibile scrivere il dato esadecimale ricevuto dal sensore. Premendo il tasto di decodifica nella casella risultato apparirà la stringa JSON decodificata.

Milesight packet encoder

Selezionare il file java per l’encoding, è possibile utilizzare un proprio file o salvare sul PC ed utilizzare il ePayloadtEncoder.js riportato sotto. Nella finestra di definizione stringa da codificare è possibile scrivere stringa JSON da inviare al sensore. Premendo il tasto di codifica nella casella risultato apparirà la stringa esadecimale codificata.

Descrizione

Enable (BOOL) Attivandolo viene abilitata l’esecuzione del FB.
SpyOn (BOOL) Se attivo permette di spiare il funzionamento del FB (Vedi articolo).
MQTT (@MQTTClient_v3) Indirizzo allocazione FB MQTTClient di supporto.
DTopic (@STRING) Definizionme topic a cui il device appartiene (Es. application/1/device).
EUI (@STRING]) Definizione 64-bit (Extended Unique Identifier), identificativo univoco del dispositivo.
Timeout (TIME) Tempo controllo dispositivo attivo, se non si ricevono dati in questo tempo viene segnalato errore (Deve essere impostato almeno al doppio del valore di report interval).
Fault (BOOL) Attivo per un loop se errore esecuzione.
DInit (BOOL)Si attiva per un loop alla inizializzazione del dispositivo. E’ possibile eseguire l’invio di comandi in downlink di inizializzazione.
Active (BOOL) Attivo se dispositivo linkato.
OnError (BOOL) Attivo se dispositivo in errore.
RxOTrig (BOOL) Si attiva per un loop alla ricezione di un uplink dal dispositivo.
RSSI (REAL) (Received Signal Strength Indicator), indica la qualità del segnale ricevuto dal dispositivo (dBm).
SNR (REAL) (Signal-to-Noise Ratio), indica il livello del segnale rispetto al rumore di ambiente (dB).
Battery (USINT) Livello batteria (%).
ETime (TIME) Tempo trascorso da ultima ricezione uplink da dispositivo.
RxObject (@STRING) Se attivo RxOTrig ritorna dato ricevuto in uplink da dispositivo.
RxOLength (UDINT) Se attivo RxOTrig ritorna dimensione dato ricevuto in uplink da dispositivo.
RxOTrig (BOOL) Si attiva per un loop alla ricezione di un uplink dal dispositivo.
RxPkts (UDINT) Counter pacchetti dati ricevuti (Uplink) dal dispositivo.
TxPkts (UDINT) Counter pacchetti dati trasmessi (Downlink) al dispositivo.
Errors (UDINT) Counter errori comunicazione con dispositivo.

Immagine FB MlsDevice
RSSI

Il Received Signal Strength Indicator RSSI indica la potenza del segnale ricevuto in milliwatt e viene misurata in dBm. Questo valore è utilizzato come misura della capacità di un ricevitore di “sentire” un segnale proveniente da un mittente. L’RSSI è un valore negativo e quanto più vicino allo 0, migliore è il segnale, i valori RSSI LoRa tipici sono:

  • RSSI minimo = -120 dBm.
  • Se RSSI=-30dBm: il segnale è forte.
  • Se RSSI=-120dBm: il segnale è debole.
SNR

Il Signal-to-Noise Ratio SNR è il rapporto tra il segnale ricevuto ed il livello del rumore di fondo. Il rumore di fondo è costituito da tutte le sorgenti di segnale indesiderate che possono corrompere il segnale trasmesso che ne provocano la ritrasmissione. Se SNR è maggiore di 0, il segnale ricevuto opera al di sopra del rumore di fondo. Se SNR è inferiore a 0, il segnale ricevuto opera al di sotto del rumore di fondo. Anche se normalmente nelle trasmissioni radio il rumore di fondo è il limite fisico della sensibilità, LoRa funziona al di sotto del livello di rumore. I valori SNR LoRa tipici sono:

  • Valore ottimali: SNR > 0 dB
  • Valori in media: -5dB > SNR <= 0dB
  • Valori che indicano un livello di segnale al di sotto del rumore di fondo: SNR < -5dB

Metodi disponibili

DeviceError

Questo metodo permette di segnalare al FB MlsDevice una condizione di errore.

Il metodo ritorna un (BOOL) TRUE.

Immagine metodo MlsDevice.DeviceError
DLinkValue

Questo metodo permette di inviare un payload al dispositivo vedi comandi di downlink. Nei dispositivi in classe A il comando verrà inviato solo in seguito alla ricezione di un uplink, nei dispositivi in classe C il comando viene subito inviato. Il comando definito viene inserito nel registro FIFO di supporto del FB MQTTClien e inviato in publish verso il broker.

Name (@STRING) Definizione nome variabile da inserire nel payload.
VType (VR_TYPE) Tipo variabile da inserire nel payload (Vedi definizione).
VAddress (PVOID) Indirizzo variabile da inserire nel payload.

Il Il metodo ritorna un (BOOL) TRUE.

Immagine metodo MlsDevice.DLinkValue
DLinkJSON

Questo metodo permette di inviare un payload al dispositivo vedi comandi di downlink. Nei dispositivi in classe A il comando verrà inviato solo in seguito alla ricezione di un uplink, nei dispositivi in classe C il comando viene subito inviato. Il comando definito viene inserito nel registro FIFO di supporto del FB MQTTClient e inviato in publish verso il broker.

Payload (@STRING) Definizione payload in formato JSON da inviare in downlink al dispositivo.

Il Il metodo ritorna un (BOOL) TRUE.

Immagine metodo MlsDevice.DLinkJSON

Milesight payload codec

Il Milesight payload codec (Vedi articolo) è un sistema per codificare e decodificare i dati scambiati con i sensori Milesight. Molti codecs sono preinstallati di default nel gateway, è comunque possibile reperirne altri in rete. Il codec presente sul gateway esegue

  • Decodifica (Decoder): Il sensore raccoglie i valori (temperatura, umidità, ecc), li codifica in formato binario e li invia in uplink al gateway. Il gateway li decodifica ritornandoli al programma applicativo in formato JSON.
  • Codifica (Encoder): Il programma applicativo invia i comandi al gateway in formato JSON, il gateway codifica i dati in formato binario e li invia in downlink al sensore che esegue il comando.

Installazione codec Elsist su gateway

Per l’utilizzo con i ns FB consigliamo di utilizzare il codec riportato sotto da installare come codec custom per tutti i dispositivi, per il test utilizzare l’utility MilesightEDTest. Per installare il codec dal menù Network Server->Payload Codec del gateway con il tasto [+] definire un nuovo codec copiando le funzioni sottoriportate nelle rispettive caselle.

Screenshot definizione custom payload encoder/decoder
Sfr115, ePayloadtDecoder.js
// =============================================================================
// Project: SFR115B010
// Milesight payload decoder
// Copyright 2025 Elsist Srl
// =============================================================================
// Reference: https://github.com/Milesight-IoT/SensorDecoders
// Test utility available on: https://utilities.elsist.biz/MilesightEDTest/index.html
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// MAIN FUNCTION
// -----------------------------------------------------------------------------
// Chirpstack v3, v4

function decodeUplink(input) {var decoded = milesightDeviceDecode(input.bytes); return { data: decoded };}
function Decode(fPort, bytes) {return milesightDeviceDecode(bytes);}

// The Things Network

function Decoder(bytes, port) {return milesightDeviceDecode(bytes);}

// =============================================================================
// FUNZIONE "milesightDeviceDecode(bytes)"
// =============================================================================
// Decodifica dati ricevuti dal sensore.
// -----------------------------------------------------------------------------

function milesightDeviceDecode(bytes)
{
    var decoded={}; //Return value
    for (var i=0; i < bytes.length; )
    {
        var IDType=(bytes[i++]*0x100)+bytes[i++]; //Channel ID/Type
        switch (IDType)
        {
            // -----------------------------------------------------------------
            // DECODIFICA DATI
            // -----------------------------------------------------------------
            // EM300: [017550]={"battery":80}

            case 0x0175:
            decoded.battery=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // UC300: [030000]={"gpio_input_1":0}
            // UC50x: [030000]={"gpio_input_1":0}

            case 0x0300:
            decoded.gpio_input_1=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // UC300: [030100]={"gpio_output_1":0}
            // UC50x: [030100]={"gpio_output_1":0}
            // UC51x: [030100]={"valve_1":0}

            case 0x0301:
            decoded.gpio_output_1=bytes[i];
            decoded.valve_1=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // EM300: [03671001]={"temperature":27.2}

            case 0x0367:
            decoded.temperature=readInt16LE(bytes.slice(i, i+2))/10;
            i+=2; break;

            // -----------------------------------------------------------------
            // UC300: [03C810200000]={"gpio_counter_1":8208}
            // UC50x: [03C810200000]={"gpio_counter_1":8208}

            case 0x03C8:
            decoded.gpio_counter_1=readUInt32LE(bytes.slice(i, i+4));
            i+=4; break;

            // -----------------------------------------------------------------
            // UC300: [040000]={"gpio_input_2":0}
            // UC50x: [030000]={"gpio_input_2":0}

            case 0x0400:
            decoded.gpio_input_2=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // UC50x: [040100]={"gpio_output_2":0}

            case 0x0401:
            decoded.gpio_output_2=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // EM300: [046864]={"humidity":50}
            // EM500-SMTC: [046864]={"moisture":50} (old resolution 0.5)

            case 0x0468:
            decoded.humidity=bytes[i]/2;
            decoded.moisture=bytes[i]/2;
            i+=1; break;

            // -----------------------------------------------------------------
            // UC300: [04C810200000]={"gpio_counter_2":8208}
            // UC51x: [04C810200000]={"gpio_counter_2":8208}

            case 0x04C8:
            decoded.gpio_counter_1=readUInt32LE(bytes.slice(i, i+4));
            i+=4; break;

            // -----------------------------------------------------------------
            // EM500-SMTC: [04CA1020]={"moisture":82.08} (new resolution 0.01)

            case 0x04CA:
            decoded.moisture=readUInt16LE(bytes.slice(i, i+2))/100;
            i+=2; break;

            // -----------------------------------------------------------------
            // UC300: [050000]={"gpio_input_3":0}

            case 0x0500:
            decoded.gpio_input_3=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // UC51x: [050100]={"valve_2":0}

            case 0x0501:
            decoded.valve_2=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // EM500-SMTC: [057F2010]={"ec":4128}

            case 0x057F:
            decoded.ec=readUInt16LE(bytes.slice(i, i+2));
            i+=2; break;

            // -----------------------------------------------------------------
            // UC300: [05C810200000]={"gpio_counter_3":8208}
            // EM300-DI:[05C810200000]={"gpio_counter_3":8208} per versioni software fino alla 1.2

            case 0x05C8:
            decoded.gpio_counter_3=readUInt32LE(bytes.slice(i, i+4));
            i+=4; break;

            // -----------------------------------------------------------------
            // EM300-DI per versioni software successive alla 1.2
            // 8 Bytes, water_conv(2B)+pulse_conv(2B)+Water consumption(4B)
            // [05e10a000a0000005b43]={"water_conv":1,"pulse_conv":1,"water":219}

            case 0x05E1:
            decoded.water_conv=readUInt16LE(bytes.slice(i, i+2))/10;
            decoded.pulse_conv=readUInt16LE(bytes.slice(i+2, i+4))/10;
            decoded.water=readFloatLE(bytes.slice(i+4, i+8));
            i+=8; break;

            // -----------------------------------------------------------------
            // UC50x: [05e20000000000000000]={"adc_1":0,"adc_1_min": 0,"adc_1_max": 0,"adc_1_avg": 0}

            case 0x05E2:
            decoded.adc_1=readFloat16LE(bytes.slice(i, i+2));
            decoded.adc_1_min=readFloat16LE(bytes.slice(i+2, i+4));
            decoded.adc_1_max=readFloat16LE(bytes.slice(i+4, i+6));
            decoded.adc_1_avg=readFloat16LE(bytes.slice(i+6, i+8));
            i+=8; break;

            // -----------------------------------------------------------------
            // UC300: [060000]={"gpio_input_4":0}

            case 0x0600:
            decoded.gpio_input_4=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // UC300: [06C810200000]={"gpio_counter_4":8208}
            // UC51x: [06C810200000]={"gpio_counter_4":8208}

            case 0x06C8:
            decoded.gpio_counter_4=readUInt32LE(bytes.slice(i, i+4));
            i+=4; break;

            // -----------------------------------------------------------------
            // UC50x: [06e20000000000000000]={"adc_2":0,"adc_2_min": 0,"adc_2_max": 0,"adc_2_avg": 0}

            case 0x06E2:
            decoded.adc_2=readFloat16LE(bytes.slice(i, i+2));
            decoded.adc_2_min=readFloat16LE(bytes.slice(i+2, i+4));
            decoded.adc_2_max=readFloat16LE(bytes.slice(i+4, i+6));
            decoded.adc_2_avg=readFloat16LE(bytes.slice(i+6, i+8));
            i+=8; break;

            // -----------------------------------------------------------------
            // UC300: [070100]={"gpio_output_1":0}
            // UC51x: [070101]={"gpio_output_1":1}

            case 0x0701:
            decoded.gpio_output_1=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // UC300: [080100]={"gpio_output_2":0}
            // UC51x: [080100]={"gpio_output_2":0}

            case 0x0801:
            decoded.gpio_output_2=bytes[i];
            i+=1; break;

            // -----------------------------------------------------------------
            // Temperature change alarm.
            // EM500-SMTC: [83D71001200001]={"temperature":27.2,"temperature_change":3.2,"temperature_alarm":"threshold alarm release"}

            case 0x83D7:
            decoded.temperature=readInt16LE(bytes.slice(i, i+2))/10;
            decoded.temperature_change=readInt16LE(bytes.slice(i+2, i+4))/10;
            decoded.temperature_alarm=readTemperatureAlarm(bytes[i+4]);
            i+=5; break;

            // -----------------------------------------------------------------
            // EM300-DI:[850000]={"gpio_alarm":"release"}

            case 0x8500:
            decoded.gpio_alarm=(bytes[i] == 0)?"release":"alarm";
            i+=1; break;

            // -----------------------------------------------------------------
            // TUTTI I DISPOSITIVI
            // -----------------------------------------------------------------

            case 0xFE03: decoded.report_interval=readUInt16LE(bytes.slice(i, i+2)); i+=2; break; //[FE031204]={"report_interval":xxxx}
            case 0xFF01: decoded.protocol_version="V"+bytes[i++].toString(); break; //[FF0101]={"protocol_version":"V1"}
            case 0xFF09: decoded.hardware_version="V"+bytes[i++].toString()+bytes[i++].toString(16); break; //[FF090140]={"hardware_version":"V140"}
            case 0xFF0A: decoded.software_version="V"+bytes[i++].toString()+bytes[i++].toString(16); break; //[FF0A0114]={"software_version":"V114"}
            case 0xFF0F: decoded.lorawan_class=readLoRaWANClass(bytes[i++]); break; //[FF0F01]={"lorawan_class":"Class B"}
            case 0xFF16: decoded.sn=readSerialNumber(bytes.slice(i, i+8)); i+=8; break //[FF166136C40091605408]={"sn":"6136c40091605408"}

            // -----------------------------------------------------------------
            // CODICE NON GESTITO
            // -----------------------------------------------------------------
            // Se codice non gestito esco non posso proseguire nella decodifica.

            default: decoded.code_not_managed=IDType.toString(16).toUpperCase().padStart(2, '0'); return decoded;
        }
    }
    return decoded;
}

// -----------------------------------------------------------------------------
// Bytes to number
// -----------------------------------------------------------------------------

function readUInt16LE(bytes) {var value=(bytes[1] << 8)+bytes[0]; return(value&0xffff);}
function readInt16LE(bytes) {var ref=readUInt16LE(bytes); return(ref > 0x7fff ? ref-0x10000 : ref);}
function readUInt32LE(bytes) {var value=(bytes[3] << 24)+(bytes[2] << 16)+(bytes[1] << 8)+bytes[0]; return(value&0xffffffff);}

// Conversione valore float a 16 bits.

function readFloat16LE(bytes) {
    var bits = (bytes[1] << 8) | bytes[0];
    var sign = bits >>> 15 === 0 ? 1.0 : -1.0;
    var e = (bits >>> 10) & 0x1f;
    var m = e === 0 ? (bits & 0x3ff) << 1 : (bits & 0x3ff) | 0x400;
    var f = sign * m * Math.pow(2, e - 25);
    return f;
}

// Conversione valore float a 32 bits.

function readFloatLE(bytes) {
    var bits = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
    var sign = bits >>> 31 === 0 ? 1.0 : -1.0;
    var e = (bits >>> 23) & 0xff;
    var m = e === 0 ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
    var f = sign * m * Math.pow(2, e - 150);
    return f;
}

// -----------------------------------------------------------------------------
// Local decoder functions
// -----------------------------------------------------------------------------

// Funzione che ritorna lo stato del GPIO.
function readGPIOStatus(bytes){switch (bytes){case 0: return "low"; case 1: return "high"; default: return "unknown";}}

// Funzione che ritorna la classe LoRaWAN.
function readLoRaWANClass(bytes){switch (bytes){case 0: return "Class A"; case 1: return "Class B"; case 2: return "Class C"; default: return "unknown";}}

// Funzione che ritorna la condizione di allarme.
function readTemperatureAlarm(type){switch (type){case 0: return "threshold alarm"; case 1: return "threshold alarm release"; case 2:return "mutation alarm"; default: return "unkown";}}

// Funzione che ritorna il numero di serie.
function readSerialNumber(bytes) {var temp = []; for (var idx = 0; idx < bytes.length; idx++) {temp.push(("0" + (bytes[idx] & 0xff).toString(16)).slice(-2));} return temp.join("");}

// [End of file]
Sfr115, ePayloadtEncoder.js
// =============================================================================
// Project: SFR115B010
// Milesight payload encoder
// Copyright 2025 Elsist Srl
// =============================================================================
// Reference: https://github.com/Milesight-IoT/SensorDecoders
// Test utility available on: https://utilities.elsist.biz/MilesightEDTest/index.html
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// MAIN FUNCTION
// -----------------------------------------------------------------------------
// The Things Network

function Encode(fPort, obj){var encoded = milesightDeviceEncoder(obj); return encoded;}

// =============================================================================
// FUNZIONE "milesightDeviceEncoder(payload)"
// =============================================================================
// Codifica i dati da inviare al sensore.
// -----------------------------------------------------------------------------

function milesightDeviceEncoder(payload)
{
    var encoded=[]; //Return value

    // -------------------------------------------------------------------------
    // DEVICE REBOOT
    // -------------------------------------------------------------------------
    // Valore "0" o superiori a "1" non ritornano nulla
    // {"reboot": 1} -> [FF 10 ff]

    if ("reboot" in payload)
    {
        if (payload.reboot == 1) encoded=encoded.concat([0xFF, 0x10, 0xFF]);
    }

    // -------------------------------------------------------------------------
    // COLLECTION INTERVAL
    // -------------------------------------------------------------------------
    // {"collection_interval":600} -> [FF 02 58 02] (uint: second)

    if ("collection_interval" in payload)
    {
        if ((typeof payload.collection_interval === "number") && (payload.collection_interval > 1))
        {
            encoded=encoded.concat([0xFF, 0x02]);
            encoded=encoded.concat(CCUInt16LE(payload.collection_interval));
        }
    }

    // -------------------------------------------------------------------------
    // REPORT INTERVAL
    // -------------------------------------------------------------------------
    // {"report_interval":600} -> [FF 03 58 02]  (uint: second)

    if ("report_interval" in payload)
    {
        if ((typeof payload.report_interval === "number") && (payload.report_interval > 1))
        {
            encoded=encoded.concat([0xFF, 0x03]);
            encoded=encoded.concat(CCUInt16LE(payload.report_interval));
        }
    }

    // -------------------------------------------------------------------------
    // RESPONSE TIME
    // -------------------------------------------------------------------------
    // {"response_time":600} -> [FF1E58020000] (udint: second)

    if ("response_time" in payload)
    {
        if ((typeof payload.response_time === "number") && (payload.response_time > 1))
        {
            encoded=encoded.concat([0xFF, 0x1E]);
            encoded=encoded.concat(CCUInt32LE(payload.response_time));
        }
    }

    // -------------------------------------------------------------------------
    // UC51x, SET VALVE 1
    // -------------------------------------------------------------------------
    // {"valve_1":0} -> [0xFF, 0x1D, 0x00, 0x00] (0: open, 1: close)

    if ("valve_1" in payload)
    {
        switch (payload.valve_1)
        {
            case 0: encoded=encoded.concat([0xFF, 0x1D, 0x00, 0x00]); break;
            case 1: encoded=encoded.concat([0xFF, 0x1D, 0x20, 0x00]); break;
        }
    }

    // -------------------------------------------------------------------------
    // UC51x, SET VALVE 2
    // -------------------------------------------------------------------------
    // {"valve_2":0} -> [0xFF, 0x1D, 0x01, 0x00] (0: open, 1: close)

    if ("valve_2" in payload)
    {
        switch (payload.valve_2)
        {
            case 0: encoded=encoded.concat([0xFF, 0x1D, 0x01, 0x00]); break;
            case 1: encoded=encoded.concat([0xFF, 0x1D, 0x21, 0x00]); break;
        }
    }

    // -------------------------------------------------------------------------
    // UC300, SET GPIO 1
    // -------------------------------------------------------------------------
    // {"gpio_output_1":0} -> [0x07, 0x01, 0xFF] (0: low, 1: high)

    if ("gpio_output_1" in payload)
    {
        switch (payload.gpio_output_1)
        {
            case 0: encoded=encoded.concat([0x07, 0x00, 0xFF]); break;
            case 1: encoded=encoded.concat([0x07, 0x01, 0xFF]); break;
        }
    }

    // -------------------------------------------------------------------------
    // UC300, SET GPIO 2
    // -------------------------------------------------------------------------
    // {"gpio_output_2":0} -> [0x08, 0x01, 0xFF] (0: low, 1: high)

    if ("gpio_output_2" in payload)
    {
        switch (payload.gpio_output_2)
        {
            case 0: encoded=encoded.concat([0x08, 0x00, 0xFF]); break;
            case 1: encoded=encoded.concat([0x08, 0x01, 0xFF]); break;
        }
    }
    return encoded;
}

// -----------------------------------------------------------------------------
// SUPPORT FUNCTIONS
// -----------------------------------------------------------------------------
// Concatena un numero UInt16 (2 Bytes) in little endian.

function CCUInt16LE(DValue)
{
    var bArray=[0x00, 0x00]; //Byte array
    for (var i=(2-1); i >= 0; i--) {bArray[(2-1)-i]=DValue&0xFF; DValue>>=8;}
    return(bArray);
}

// Concatena un numero UInt32 (4 Bytes) in little endian.

function CCUInt32LE(DValue)
{
    var bArray=[0x00, 0x00, 0x00, 0x00]; //Byte array
    for (var i=(3-1); i >= 0; i--) {bArray[(3-1)-i]=DValue&0xFF; DValue>>=8;}
    return(bArray);
}

// [End of file]

Trigger di spy

Se SpyOn attivo è possibile utilizzare utilizzare la console di spionaggio per verificare il funzionamento della FB. Sono previsti vari livelli di triggers.

Livelli di trigger
TriggerDescrizione
16#00000001Rx: Dato ricevuto in uplink.
16#00000002Tx: Dato trasmesso in downlink.
16#10000000Lg: Log di esecuzione.
16#40000000Er: Errore di esecuzione.

Esempi

Come utilizzare gli esempi.

Gestione EM300-TH sensore temperatura ed umidità LoRaWAN della Milesight.

LogicLab (Ptp208, ST_MlsDevice)
PROGRAM ST_MlsDevice
VAR
    Temperature:REAL; (* Temperature (°C) *)
    Humidity:REAL; (* Humidity (%) *)
    SPData : MQTT_TS_DATA; (* MQTT topic subscribe data *)
    TCPClient : SysTCPClient; (* TCP client management *)
    FIFO : FIFOFile_v1; (* FIFO on file *)
    MQTT : MQTTClient_v3; (* MQTT client FB *)
    MDev : MlsDevice; (* Milesight device manager *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_MlsDevice"
// *****************************************************************************
// Is managed a EM300-TH temperature and humidity sensor.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // Initialize the FBs parameters.

    IF (SysFirstLoop) THEN

        // Set FIFO parameters.

        FIFO.FIFOFilename:=eNULL; //Path and name of FIFO file
        FIFO.FIFOSize:=2048; //FIFO file size
        FIFO.FIFOIDx:=eNULL; //FIFO indexes

        // Set TCPClient parameters.

        TCPClient.PeerAdd:=ADR('192.168.1.150'); //Peer address
        TCPClient.PeerPort:=1883; //Peer port
        TCPClient.LocalAdd:=ADR('0.0.0.0'); //Local address
        TCPClient.LocalPort:=0; //Local port
        TCPClient.FlushTm:=0; //Flush time (mS)
        TCPClient.LifeTm:=90; //Life time (S)
        TCPClient.RxSize:=1512; //Rx buffer size
        TCPClient.TxSize:=512; //Tx buffer size

        // Set MQTTClient parameters.

        MQTT.SpyOn:=FALSE; //Spy active
        MQTT.FIFOFile:=ADR(FIFO); //FIFO on file
        MQTT.CFlags:=16#02; //Clean session
        MQTT.Username:=ADR('loraadm'); //Broker username
        MQTT.Password:=ADR('URloraadm123456'); //Broker password
        MQTT.ClientID:=eNULL; //Client identifier
        MQTT.KeepAlive:=T#90s; //Keep alive time
        MQTT.Delay:=T#1s; //Send delay time
        MQTT.Timeout:=T#5s; //Execution timeout

        // Topic subscribe definitions.
        // Subscribe to all applications and all devices rx data.

        MQTT.TSData:=ADR(SPData); //Topic subscribe data
        MQTT.TSNumber:=1; //Topic subscribe number
        eTO_JUNK(MQTT.Subscribe(0, ADR('application/+/device/+/rx'), eNULL, 0, 0));

        // Milesight device definitions.

        MDev.Enable:=TRUE; //FB enable
        MDev.SpyOn:=TRUE; //Spy On
        MDev.MQTT:=ADR(MQTT); //MQTT client
        MDev.DTopic:=ADR('application/1/device'); //Device topic
        MDev.EUI:=ADR('24e124136e313438'); //Device EUI
        MDev.Timeout:=T#10m; //Timeout
    END_IF;

    // -------------------------------------------------------------------------
    // FBs EXECUTION
    // -------------------------------------------------------------------------
    // FBs execution.

    TCPClient(Connect:=MQTT.Connect); //TCPClient management
    MQTT(Enable:=TRUE, File:=TCPClient.File); //MQTTClient management

    // Device management, send the init downlink settings.

    MDev(); //Milesight device manager
    IF (MDev.DInit) THEN
        eTO_JUNK(MDev.DLinkJSON(ADR('{"report_interval":120}'))); //Set reporting interval, 120 (S)
    END_IF;

    // Not needed, is just to show how to spy the complete uplink message.

    // IF (MDev.RxOTrig) THEN eTO_JUNK(SysWrSpyData(SPY_ASCII, 0, 16#00000001, ADR('----'), MQTT.RxValue)); END_IF;

    // The managed device is a EM300-TH so acquire its measures.

    IF NOT(MDev.RxOTrig) THEN RETURN; END_IF;
    eTO_JUNK(JSONDecoder(MDev.RxObject, ADR('temperature'), REAL_TYPE, ADR(Temperature), 1, 0));
    eTO_JUNK(JSONDecoder(MDev.RxObject, ADR('humidity'), REAL_TYPE, ADR(Humidity), 1, 0));

// [End of file]

Was this article helpful?