itbrainpower.net
THE ALPHABET PROJECT - professional Arduino, BeagleBone & Raspberry PI shields



Read our last post: Modems and RaspberryPI 5. RaspberryPI OS [Debian 12 bookworm] notes.. Order u-GSM modems.

xyz-mIoT shield - LiveObjects - LTE CATM1 integration how to

 

About this project

Next, I will show you how to integrate our xyz-mIoT shield by itbrainpower.net with ORANGE LiveObjects cloud service. The target goal of the project is to upload the temperature and humidity sensors data, together with xyz-mIoT battery and input voltages into the Live Objects cloud service. At the end, I will show you how to build a graphic reporting tool that retrive the cloud stored data by using NODE RED, REST based web-services and Elasticsearch.

The Arduino code used in this project support the new low power LTE CAT M1 service setup - BG96 version of xyz-mIoT and access to LTE CATM1 service is required. As alternative, if LTE CAT M1 it is not yet available in your area, GPRS data transmission may be used.

Very soon, the this project Arduino code will be updated in order to enable NB IoT socket data upload into Live Objects cloud.

 

temperature and humidity IoT, Live Objects and LTE CAT M1 using xyz-mIOT shield

 

 

Live Objects is a secure and evolutive Cloud-based platform, developed and operated by Orange, which covers the major functionalities required for any professional IoT project. Read about Live Objects here.

 

 

xyz-mIOT shield top side
xyz-mIoT by itbrainpower.net shield is the first and the most compact IoT board that combines the versatility of ARM0 micro-controller with the usage convenience of the embedded sensors and the conectivity provided by Low Power LTE CAT M1 / NB-IoT modems or by legacy 3G / GSM modems. The xyz-mIoT shield was announced on April 08th 2018 and become commercially available in March 2018.

The ARM0 controller used in the xyz-mIoT shield is Microchip/Atmel ATSAMD21G and it is integrated in Arduino Zero compatible design.

The xyz-mIoT shield may have up to 5 integrated sensors, as:
- THS (temperature and humidity sensors) - HDC2010,
- tVOC & eCO2 (air quality sensor - CO2 + total volatile organic compounds as CO2 equivalent) - CCS811,
- HALL (magnetic sensor) - DRV5032 or IR (infrared sensor) KP-2012P3C,
- secondary IR (infrared sensor) - KP-2012P3C,
- TILT (movement/vibration sensor) or REED (magnetic sensor) - SW200D.

More about xyz-mIoT shield sensors and modems variants check the xyz-mIoT shield datasheet.

References used for this project


Required time*

  • Hardware side: around 5 minutes.
  • Live Objects account and device setup: around 10 minutes.
  • Arduino classes install: 5-10 minutes.
  • Arduino software side: 5 minutes.
  • NODE RED install and setup: around 5 minutes.
* The implementation time may vary depending on previous user experience. Difficulty level - intermediate.

 

Bill of materials

  • xyz-mIoT shield equipped with Quectel BG96 modem and HDC2010 sensor, PN: XYZMIOT209#BG96-UFL-1100000
  • nano-size [4FF] LTE CATM1 or 2G SIM card [having data plan enabled]. We used LTE CAT M1 SIM provided by Orange Romania.
  • small LiPo battery
  • GSM embedded antenna with uFL [check xyz-mIoT accesories] or,
  • GSM antenna with SMA plus u.FL to SMA pigtail [check xyz-mIoT accesories]

 

 

Step1 [hardware, soldering and wires]:

Follow the very same hardware directives as described in steps 1 and 2 of this project.

 

 

Step 2 [Arduino software download and install, preliminary settings]

a. Download the "xyz-mIoT shields Arduino class", then download the last version of classes: "IoT REST [transparent socket] support for xyz-mIoT shields" and "xyz-mIoT shields SENSORS support Arduino class" from here.

b. Install the classes. Uncompress the archives and install the classes - in a nutshell:
- copy the "xyz-mIoT shields Arduino class" files in Arduino local hardware folder (mine is: "C:\Users\dragos\Documents\Arduino\hardware"), then
- copy the the support classes folders into your Arduino local user folder [mine is: "C:\Users\dragos\Documents\Arduino\libraries"] and
- restart Arduino environment.
More detail about manual library installing, read Arduino library manual installation.

c. Make a folder named "xyz_mIoT_REST_OrangeLiveObjects_THS".

d. Copy the code bellow, paste it one new file and save the file as "xyz_mIoT_REST_OrangeLiveObjects_THS.ino" in the folder created in previous step. Alternate, you can download from here (right click & save as):
xyz-mIoT shield upload sensor data to Live Objects - Arduino main code

xyz_mIoT_REST_OrangeLiveObjects_THS.ino

1/*
2xyz_mIoT_REST_LiveObjects_THS.ino v 0.1/20181102 - upload data [json packed] via REST to Orange LiveObjects cloud service
3COPYRIGHT (c) 2015-2018 Dragos Iosub / R&D Software Solutions srl
4
5You are legaly entitled to use this SOFTWARE ONLY IN CONJUNCTION WITH xyz-mIoT by itbrainpower.net DEVICE USAGE. Modifications, derivates 
6and redistribution of this software must include unmodified this COPYRIGHT NOTICE. You can redistribute this SOFTWARE and/or modify it under 
7the terms of this COPYRIGHT NOTICE. Any other usage may be permited only after written notice of Dragos Iosub / R&D Software Solutions srl.
8
9This SOFTWARE is distributed is provide "AS IS" in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
10of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
12Dragos Iosub, Bucharest 2018.
13https://itbrainpower.net
14*/
15/*IMPORTANT NOTICE 0: 
16 - goto https://liveobjects.orange-business.com/#/login and create your demo account
17 - Add one new device, MQTT type, having "Namespace" set as "xyz-mIoT" and "Id" set as your modem IMEI and name it as you like. After this, 
18 check the in device detail:
19      * Identifier: "namespace: xyz-mIoT / id: YOUR_MODEM_IMEI"   
20      * Device ID: "urn:lo:nsid:xyz-mIoT:YOUR_MODEM_IMEI"
21  - in Configuration\Api Keys, create a new key type "Customized" and having DATA_R and DATA_W rights. Right down the new created API KEY
22  - observation: nothing is required to setup the sensors. Those will be stored in cloud based on their JSON key names [set in here, in IoT node code].
23  In this demo, the sensors names transmited into cloud are: "tmp", "hum", "Vbat" and "Vin" [for temperature, humidity, battery voltaga and input voltage]
24
25  xyz-mIoT shield PN "XYZMIOT209#BG96-UFL-1100x00" is required for this project. If you use other PN, you must adapt the code.
26
27 - Check for hardware setup as described in: https://itbrainpower.net/a-gsm/xyz-mIoT-LiveObjects-LTE-CATM1_howto
28*/
29/*IMPORTANT NOTICE 1: check itbpGSMdefinition.h for line 45-51 and set "__itbpModem__    xyzmIoT" */
30/*IMPORTANT NOTICE 2: check itbpGSMdefinition.h for line 53&57 and set to "__Qmodule__    CATM1"*/
31/*IMPORTANT NOTICE 3: in itbpGPRSIPdefinition.h  set "SERVER_ADDRESS" with value "liveobjects.orange-business.com" and "SERVER_PORT" with value "443"- LiveObjects server address and port*/
32/*IMPORTANT NOTICE 4: in itbpGSMdefinition.h "MAX_BUFFER_SIZE", "itbpGSMClassDebug" and "atDebug" may help you....*/
33
34#include <String.h>
35
36String message = "";
37
38#define DEVICE_NAMESPACE   "xyz-mIoT"                     //LiveObjects Device namespace, replace it with yours [Eg.: namespace: xyz-mIoT / id: YOUR_DEVICE_IMEI ]
39#define xAPIKEY     "e4e89323aa594c9c9c87f6xyxyxyxyxy"    //LiveObjects Api Key, replace it with your Key ==> HINT: in order to able to upload data, the key must have at least DATA_W rights 
40
41
42int samplingPeriod = 60;                           //interval in seconds between transmissions... keep it > 20 sec 
43
44float Vbat = 0, Vraw = 0;
45
46char IMEI [16];  
47
48/*THS start*/
49double temperature = 0;
50double humidity = 0;
51/*THS end*/
52
53#include <itbpGSMClass_v0_6_02.h>
54
55/*THS start*/
56#include <HDC2010.h>    //I2C THS HDC2010 from Texas [option for xyz-mIoT]
57HDC2010 sensor(I2C_HDC2010_ADDRESS);
58/*THS end*/
59
60
61#define DEBUG(x)    {__itbpDebugPort__.print(millis());__itbpDebugPort__.print(" - ");__itbpDebugPort__.println(x);}
62#define DEBUGP(x,y) {__itbpDebugPort__.print(millis());__itbpDebugPort__.print(" - ");__itbpDebugPort__.print(x);__itbpDebugPort__.println(y);}
63
64#if defined (__AVR_ATmega328P__)
65  int freeRam () {
66    extern int __heap_start, *__brkval; 
67    int v; 
68    return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
69  }
70#endif
71
72
73//some defines for IoT - CLOUD chat interaction
74#define PostSensorSuccess  "HTTP/1.1 202" //used to verify in cloud response if data upload was succeed  
75#define GetActuatorSuccess  "HTTP/1.1 200" //used to verify in cloud response if data upload was succeed  
76
77#define POSTSENSOR 0                      //look for {"request_status":1}
78#define GETACTUATOR 1                     //SERVER SAY: '[{"server_timestamp":"2016-09-10T11:50:21.189Z","timestamp":1473508221.147962,"timestamp_iso":"2016-09-10T11:50:21.147Z","state":25,"meta":{"protocol":"http"},"protocol":"http"}]'
79#define POSTACTUATOR 2                    //look for {"request_status":1}
80
81//#define ActuatorTag     "TBD"      //used for test success and for Actuator value extraction
82//#define ActuatorNextTag   "TBD"     //the actuator value is placed bw: ActuatorTag and ActuatorNextTag
83
84//int c_actuator;  // global actuator value
85
86
87unsigned long startTime = 0;
88
89bool ledState = 0;
90
91
92// initialize the library instance
93aGsmClient client;
94
95
96
97void readVoltages(){
98  //read voltage
99  Vbat=analogRead(VbatPin)*0.0065344650650891/*0.0063636363636364*/;      //8bit read, value in volts
100  Vraw=analogRead(VrawPin)*0.0102016129032258;      //8bit read, value in volts  
101  __itbpDebugPort__.print(F("Vbat: "));
102  __itbpDebugPort__.println(Vbat);
103  __itbpDebugPort__.print(F("Vraw: "));
104  __itbpDebugPort__.println(Vraw);
105}
106
107/*get sensor data and pack data in JSON for LiveObjects*/
108void buildJsonPayload(){ //
109    
110    readVoltages();
111
112    /*THS start*/
113    sensor.triggerMeasurement();
114    delay(100);
115    temperature = /*100**/(double)sensor.readTemp();
116    humidity = /*100**/(double)sensor.readHumidity();
117    DEBUGP(F("Temp: "),temperature);
118    DEBUGP(F("Hum%: "),humidity);
119    /*THS stop*/
120
121    //via bulk DATA
122    //[{"streamId": "xyz-mIoT:YOUR_DEVICE_IMEI", "value": {"Vbat": 4.22,"Vin": 5.05}}]
123    message="";
124    message += "[{";
125    message += "\"streamId\":\"" + String(DEVICE_NAMESPACE) + IMEI + "\","; //Device ID
126    //sensors values next
127    message += "\"value\":{";
128    /*THS start*/
129    message += "\"tmp\":"+ String(temperature); //temperature sensor
130    message += ",";//separator
131    message += "\"hum\":"+ String(humidity); //humidity sensor
132    message += ",";//separator
133    /*THS stop*/
134    message += "\"Vin\":"+ String(Vraw); //first voltage monitor
135    message += ",";//separator
136    message += "\"Vbat\":"+ String(Vbat); //second voltage monitor
137    message += "}";
138    message += "}]";
139
140    /*
141    //or via streams
142    //{"value": {"Vbat": 4.24,"Vin": 5.09}}
143    message="";
144
145    message += "{";
146    message += "\"value\":{";
147    message += "\"tmp\":"+ String(temperature); //temperature sensor
148    message += ",";//separator
149    message += "\"hum\":"+ String(humidity); //humidity sensor
150    message += ",";//separator
151    message += "\"Vin\":"+ String(Vraw); //first voltage monitor
152    message += ",";//separator
153    message += "\"Vbat\":"+ String(Vbat); //second voltage monitor
154    message += "}";
155    message += "}";
156    */
157    __itbpDebugPort__.print(F("JSON data: "));
158    __itbpDebugPort__.println(message);
159}
160
161
162/*
163  Function to parse the LiveObjects REST server reply
164*/
165int readRestServerResponse(int type, int timeout){
166        char actuator [5];
167        char * pch0;
168        char * pch1;
169        memset(actuator, 0x00, sizeof(actuator));
170        int i = 0;
171
172  unsigned long startTime;
173  startTime = millis(); 
174  delay(10);
175  __itbpDebugPort__.println(F("start read..."));
176  while(true){
177    client.readline(1000);//16 linii
178    __itbpDebugPort__.println(client.resp);//just to see the server response
179
180                if (type==POSTSENSOR || type==POSTACTUATOR) ////HTTP/1.1 202
181                {
182                    if (strstr(client.resp, PostSensorSuccess))
183                    {
184                        __itbpDebugPort__.println(F("found confirmation..."));
185                        i = 1;
186                        while (i < 16){
187                          client.readline(1000);
188                          __itbpDebugPort__.println(client.resp);//just to see the server response
189                          i++;
190                        }
191                        return 1;
192                    }
193                }
194                 
195                if (strstr(client.resp, sockDisconnected0)||strstr(client.resp, sockDisconnected1))
196                {
197                    __itbpDebugPort__.println(F("sk disconnected..."));
198                    return 0;
199                }//sockDisconnected0
200                if(millis() - startTime > (unsigned long)timeout*1000 )
201                {
202                    __itbpDebugPort__.println(F("mark to..."));
203                    
204                    return -1;        
205                }  
206  }
207  return -2;//never here
208}
209
210
211/*  
212 *   send sensors data
213 *   via data/bulk
214 *   curl -X POST -k --header 'Content-Type: application/json' --header 'X-API-KEY: e4e89323aa594c9c9c87f6a97e3a0df1' -d '[{"streamId": "xyz-mIoT:YOUR_DEVICE_IMEI", "value": {"Vbat": 4.22,"Vin": 5.05}}]' 'https://liveobjects.orange-business.com/api/v0/data/bulk' -v
215 *   
216 *   success return HTTP/1.1 202
217 *   
218*/
219int liveObjetsSendSensors(){//send all sensor data JSON packed
220    int res = 0;
221
222    __itbpDebugPort__.print(" >>> send data >>> ");
223    __itbpDebugPort__.println(message);    
224    
225    client.print(F("POST "));
226    __itbpDebugPort__.print(F("POST "));
227    
228    //'https://liveobjects.orange-business.com'
229    client.print(F("https://"));
230    __itbpDebugPort__.print(F("https://"));
231    
232    client.print(SERVER_ADDRESS);
233    __itbpDebugPort__.print(SERVER_ADDRESS);
234
235    //next line for bulk mode
236    client.print(F("/api/v0/data/bulk"));
237    __itbpDebugPort__.print(F("/api/v0/data/bulk"));
238
239    /*
240    //next 3 for streams mode api/v0/data/streams/
241    client.print(F("api/v0/data/streams/"));
242    client.print(F(DEVICE_NAMESPACE ":"));
243    client.print(IMEI);
244    __itbpDebugPort__.print(F("api/v0/data/streams/"));
245    __itbpDebugPort__.print(F(DEVICE_NAMESPACE ":"));
246    __itbpDebugPort__.print(IMEI);
247    */
248  
249    client.println(F(" HTTP/1.1"));
250    client.println(F("Host: " SERVER_ADDRESS));    
251    client.println(F("X-API-KEY: " xAPIKEY));
252    
253    __itbpDebugPort__.println(F(" HTTP/1.1"));
254    __itbpDebugPort__.println(F("Host: " SERVER_ADDRESS));
255    __itbpDebugPort__.println(F("X-API-KEY: " xAPIKEY));
256    
257    if(samplingPeriod <= 30){
258      client.println(F("Connection: keep-alive"));
259      __itbpDebugPort__.println(F("Connection: keep-alive"));
260    }else{
261      client.println(F("Connection: close"));
262      __itbpDebugPort__.println(F("Connection: close"));
263    }
264  
265      
266    client.println(F("Content-Type: application/json"));
267    client.print  (F("Content-Length: "));
268    client.println(message.length());
269    
270    __itbpDebugPort__.println(F("Content-Type: application/json"));    
271    __itbpDebugPort__.print  (F("Content-Length: "));
272    __itbpDebugPort__.println(message.length());
273    
274    client.println();
275    __itbpDebugPort__.println();
276    
277    client.println(message);
278    __itbpDebugPort__.println(message);
279    
280    client.println();
281    __itbpDebugPort__.println();
282    
283    res = readRestServerResponse(POSTSENSOR,  20);
284    if(samplingPeriod > 30) client.stop();
285    return res;
286
287}
288
289
290void setup(){
291  #if (__itbpModem__ == xyzmIoT)
292    delay(10000);
293  #endif
294
295  __itbpDebugPort__.begin(115200);      //start debug port connection
296  //configure led
297  pinMode(LED_BUILTIN, OUTPUT);                 //embedded LED status indicator  
298  digitalWrite(LED_BUILTIN, LOW);     
299  ledState = 0;
300
301 /*THS start*/
302  sensor.begin();                     //I2C THS sensor init
303  sensor.reset();                     //reset H2010
304
305  //sensor.setTemperatureOffset(0b11000000);  //-10.32
306  sensor.setTemperatureOffset(0b11010111);    //-6.64
307  
308  // Set up the comfort zone
309  sensor.setHighTemp(28);         // High temperature of 28C
310  sensor.setLowTemp(22);          // Low temperature of 22C
311  sensor.setHighHumidity(55);     // High humidity of 55%
312  sensor.setLowHumidity(40);      // Low humidity of 40%
313
314  // Configure interrupt pin
315  /*
316  sensor.enableInterrupt();                   // Enable the Interrupt/DRDY pin
317  sensor.enableThresholdInterrupt();          // Enable Interrupt triggering based on comfort zone
318  sensor.setInterruptPolarity(ACTIVE_HIGH);   // Set Interrupt pin to Active High
319  sensor.setInterruptMode(COMPARATOR_MODE);   // Set Interrupt to return to inactive state when in bounds
320  */
321    // Configure Measurements
322  sensor.setMeasurementMode(TEMP_AND_HUMID);  // Set measurements to temperature and humidity
323  //sensor.setRate(ONE_HZ);                     // Set measurement frequency to 1 Hz
324  sensor.setRate(MANUAL);                     // Set measurement frequency to 1 Hz
325  sensor.setTempRes(FOURTEEN_BIT);
326  sensor.setHumidRes(FOURTEEN_BIT);
327
328  /*
329  // Configure Measurements
330  //sensor.setRate(ONE_HZ);                     // Set measurement frequency to 1 Hz
331  // Configure THS Interrupt Pin
332  pinMode(HDC2010_INTERRUPT_PIN, INPUT);                   // HDC2010_INTERRUPT_PIN will be the interrupt input
333  attachInterrupt(digitalPinToInterrupt(HDC2010_INTERRUPT_PIN), alertTHS, CHANGE);  //ISR "alertTHS" will be triggered by changes in ALERTTHSPIN
334  // Configure HALL Interrupt Pin
335  pinMode(HALL_IRQ_PIN, INPUT_PULLUP);                   // HALL_IRQ_PIN will be the interrupt input
336  attachInterrupt(digitalPinToInterrupt(HALL_IRQ_PIN), alertHALL, CHANGE);  //ISR "alertHALL" will be triggered by changes in ALERTHALLPIN
337
338  */
339  //begin measuring
340  sensor.triggerMeasurement();
341  temperature = /*100**/(double)sensor.readTemp();
342  humidity = /*100**/(double)sensor.readHumidity();
343 /*THS end*/
344
345
346  #if defined (__AVR_ATmega328P__)
347    DEBUGP(F("Free RAM: "), freeRam());
348  #endif
349
350  __itbpDebugPort__.println(F("Orange LiveObjects cloud REST data upload ...let's rock"));
351  __itbpDebugPort__.flush();
352  
353  client.begin();
354  
355  client.setSSLmode(SSLENABLED);      //enable SLL data exchange mode
356
357
358 #if __Qmodule__ == CATM1 // for BG96 modems
359    //Set bands, scan mode, scan sequence for BG96 only!!! Only just after client.begin()!        
360    client.setScanSequence(SCANSEQ_CATM1, SCANSEQ_GSM, SCANSEQ_NBIOT ); //left to right priority
361    //client.setScanSequence(SCANSEQ_GSM, SCANSEQ_CATM1, SCANSEQ_NBIOT );
362
363    //client.setRegistrationMode(RegisterGSM);                  //GSM only registration mode allowed
364    //client.setRegistrationMode(RegisterCATM1);                //CAT-M1 only registration mode allowed
365    client.setRegistrationMode(RegisterBOTH);                   //CAT-M1 or GSM registration mode allowed
366    
367    client.setBands(GSM_ALL, LTE_CATM1_ALL, LTE_NBIOT_ALL);     //definitions in itbpGSMdefinition.h
368#endif
369
370  client.enableClockUpdate(1); //update available at next modem boot
371
372  client.getIMEI(); //IMEI value in client.resp
373  memset(IMEI,0x00, sizeof(IMEI));
374  strcpy(IMEI,client.resp);
375  DEBUGP(F("IMEI: "), IMEI);
376
377  client.attachGPRS();
378
379  //let's verify the module date&time function
380  delay(1000);
381  client.getRTC();
382  DEBUGP(F("time and date: "), client.resp);
383
384  __itbpDebugPort__.println("connecting...");
385  
386  //client.readServerDatagramReply();
387
388  startTime = millis() + (unsigned long)samplingPeriod*1000;//force send on the spot
389}
390
391void loop(){
392  int res=0;
393  if (millis() - startTime < (unsigned long)samplingPeriod*1000){//waiting period  
394    ledState = ! ledState;
395    if(ledState != 0)
396      digitalWrite(LED_BUILTIN, HIGH);  
397    else
398      digitalWrite(LED_BUILTIN, LOW); 
399    delay(500);
400    
401  }else{//start transmission
402    startTime = millis();
403    digitalWrite(LED_BUILTIN, HIGH);      //show sampling + uploadto cloud
404
405    if (client.connected() || client.connect()){
406      __itbpDebugPort__.println(F("send sensor data"));
407
408      buildJsonPayload(); 
409      res = liveObjetsSendSensors();
410            
411      if(res == 1){
412        __itbpDebugPort__.println(F("data was sent"));
413        //if(samplingPeriod > 30)
414        //    client.stop();
415      }else{//send datagram command report ERROR
416        __itbpDebugPort__.println(F("connectivity error...")); 
417      }
418    }//end connect()
419  }//end tranmission 
420  
421}
422


2020.06.10 update, important! ==> Our pal, Bogdan Calin, doing tests with last version of LiveObjects warned us about some changes in cloud authentication format. In order to be able to upload data to LiveObject cloud, just set #define DEVICE_NAMESPACE "" in above code, line 38. Thank you for your feedback, Bogdan!


e. Make some settings in some files contained inside "IoT REST [transparent socket] support for xyz-mIoT shields" class:
- in "itbpGPRSIPdefinition.h" set the APN value, using the APN value of your GSM provider (Eg: NET for RO Orange)
- in "itbpGPRSIPdefinition.h" set the SERVER_ADDRESS and the SERVER_PORT for LiveObjects cloud
#define SERVER_ADDRESS "liveobjects.orange-business.com"
#define SERVER_PORT "443"

- in "itbpGSMdefinition.h" comment default option for "__itbpModem__" and choose (delete comment sign) option
"#define __itbpModem__ xyzmIoT" (line 51)
- in "itbpGSMdefinition.h" choose the modem type for your xyz-mIoT shield:
"#define __Qmodem__ CATM1" (line 53)

 

 

Step3 [LiveObjects - define new IoT device node and x-API-KEY.]

Access https://liveobjects.orange-business.com/#/login and create a new demo account.

Create new IoT device node. Click on "Devices" tab, then click on "Add device" button. Set the "Namespace" as "xyz-mIoT" and "Id" using the IMEI of your xyz-mIoT device [the IMEI is written on top of the BG 96 module].
LiveObjects create new IoT device node


Create your API KEY Click on "Configuration" tab, then on "Api keys" menu and then select "+Add" button.
LiveObjects create new API KEY

Select "Customized" key type and set "DATA_R" and "DATA_W" rights. Fill other mandatory info. After clicking "Create", a new popup will be shown. Copy the new generated API KEY from the popup at keep it for furter usage.

 

 

Step4 [Arduino - set x-API-KEY, compile and upload IOT code]

Open in Arduino[arduino.cc v >= 1.8.5 required] the xyz_mIoT_REST_OrangeLiveObjects_THS.ino project code.
LiveObjects cloud IoT Arduino set x-API-KEY a. Set the x-API-KEY value with the one retained in previous step [created in the LiveObjects]. The IMEI value required in data upload to the cloud automatically provided.

HINT: You may like to set the network scan sequence, set/restrict the LTE and GSM bands used or to select the network registration mode as "RegisterGSM", "RegisterBOTH" or as "RegisterCATM1" (to be able to access LTE CAT-M1 services the mobile network used and the SIM card must support LTE CATM1*) ...see functions calls at lines 359->367, right after client.begin() in function setup().
* we use for tests RO Orange LTE CATM1 enabled SIM.

b. Press twice (fast) the xyz-mIoT shield RESET button [the board will switch into programming mode]. LiveObjects cloud IoT Arduino set xyz-mIoT board and port Select "itbrainpower.net xyz-mIoT" board and "itbrainpower.net xyz-mIoT" programming port in Arduino menu.

c. Compile and upload the code.

The xyz-mIoT shield will start to sample the temperature, humidity, Vin and Vbat data (at 1min. rate) and to upload sampled values to your LiveObjects cloud account.

LiveObjects cloud IoT Arduino debug output In order to visualize the debug output use the Arduino Serial Monitor or other terminal by selecting the debug port with following settings: 115200bps, 8N, 1.

Logged data can be listed in LiveObject - just access "DATA" section of your account.
LiveObjects cloud list uploaded sensor data

 

 

Step5 [NODE RED - build / set up a graphic visualizing tool for LiveObjects data]

Download NODE RED from here:https://nodejs.org/en/ and install the package.
Having administrator rights, run cmd.exe. In command prompt window, tyoe following commands:
npm install -g --unsafe-perm node-red
npm install node-red-dashboard

You may start NODE RED typing following command:
node-red

HINT: At first NODE RED run, allow NODE RED connections on localhost in your firewall, but be careful about security of your computer.

The NODE RED admin interface will be available at: http://localhost:1880/ and user interface at: http://localhost:1880/ui/

Copy the NODE RED flow bellow:

1[
2    {
3        "id": "cb770acb.c93ed8",
4        "type": "tab",
5        "label": "Flow 3",
6        "disabled": false,
7        "info": ""
8    },
9    {
10        "id": "e460e766.b33ed",
11        "type": "ui_base",
12        "theme": {
13            "name": "theme-light",
14            "lightTheme": {
15                "default": "#0094CE",
16                "baseColor": "#0094CE",
17                "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
18                "edited": true,
19                "reset": false
20            },
21            "darkTheme": {
22                "default": "#097479",
23                "baseColor": "#097479",
24                "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
25                "edited": true,
26                "reset": false
27            },
28            "customTheme": {
29                "name": "Untitled Theme 1",
30                "default": "#4B7930",
31                "baseColor": "#4B7930",
32                "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
33            },
34            "themeState": {
35                "base-color": {
36                    "default": "#0094CE",
37                    "value": "#0094CE",
38                    "edited": false
39                },
40                "page-titlebar-backgroundColor": {
41                    "value": "#0094CE",
42                    "edited": false
43                },
44                "page-backgroundColor": {
45                    "value": "#fafafa",
46                    "edited": false
47                },
48                "page-sidebar-backgroundColor": {
49                    "value": "#ffffff",
50                    "edited": false
51                },
52                "group-textColor": {
53                    "value": "#1bbfff",
54                    "edited": false
55                },
56                "group-borderColor": {
57                    "value": "#ffffff",
58                    "edited": false
59                },
60                "group-backgroundColor": {
61                    "value": "#ffffff",
62                    "edited": false
63                },
64                "widget-textColor": {
65                    "value": "#111111",
66                    "edited": false
67                },
68                "widget-backgroundColor": {
69                    "value": "#0094ce",
70                    "edited": false
71                },
72                "widget-borderColor": {
73                    "value": "#ffffff",
74                    "edited": false
75                },
76                "base-font": {
77                    "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
78                }
79            },
80            "angularTheme": {
81                "primary": "indigo",
82                "accents": "blue",
83                "warn": "red",
84                "background": "grey"
85            }
86        },
87        "site": {
88            "name": "Node-RED Dashboard",
89            "hideToolbar": "false",
90            "allowSwipe": "true",
91            "allowTempTheme": "true",
92            "dateFormat": "DD/MM/YYYY",
93            "sizes": {
94                "sx": 48,
95                "sy": 48,
96                "gx": 6,
97                "gy": 6,
98                "cx": 6,
99                "cy": 6,
100                "px": 0,
101                "py": 0
102            }
103        }
104    },
105    {
106        "id": "d04f9276.cf294",
107        "type": "tls-config",
108        "z": "",
109        "name": "",
110        "cert": "",
111        "key": "",
112        "ca": "",
113        "certname": "",
114        "keyname": "",
115        "caname": "",
116        "servername": "",
117        "verifyservercert": false
118    },
119    {
120        "id": "c3ce6859.25688",
121        "type": "ui_tab",
122        "z": "",
123        "name": "Home-test",
124        "icon": "dashboard"
125    },
126    {
127        "id": "258bd191.04d6ce",
128        "type": "ui_group",
129        "z": "cb770acb.c93ed8",
130        "name": "mine",
131        "tab": "c3ce6859.25688",
132        "disp": true,
133        "width": "6",
134        "collapse": true
135    },
136    {
137        "id": "36053808.0e202",
138        "type": "ui_group",
139        "z": "",
140        "name": "Tensiuni",
141        "tab": "9543e1de.9e12c8",
142        "disp": true,
143        "width": "6",
144        "collapse": true
145    },
146    {
147        "id": "9543e1de.9e12c8",
148        "type": "ui_tab",
149        "z": "",
150        "name": "gauges",
151        "icon": "dashboard"
152    },
153    {
154        "id": "c882381b.af42b",
155        "type": "ui_group",
156        "z": "",
157        "name": "Temp-humid",
158        "tab": "9543e1de.9e12c8",
159        "disp": true,
160        "width": "9",
161        "collapse": false
162    },
163    {
164        "id": "b83b0d93.6054a",
165        "type": "http request",
166        "z": "cb770acb.c93ed8",
167        "name": "",
168        "method": "POST",
169        "ret": "txt",
170        "url": "https://liveobjects.orange-business.com/api/v0/data/search/hits",
171        "tls": "d04f9276.cf294",
172        "x": 430,
173        "y": 40,
174        "wires": [
175            [
176                "c0805c2f.df0e4"
177            ]
178        ],
179        "outputLabels": [
180            "out"
181        ]
182    },
183    {
184        "id": "481bd64f.946bd",
185        "type": "json",
186        "z": "cb770acb.c93ed8",
187        "name": "",
188        "property": "payload",
189        "action": "",
190        "pretty": true,
191        "x": 290,
192        "y": 200,
193        "wires": [
194            [
195                "c162ed0c.287d28",
196                "b0ecc0f.43c0f4",
197                "f48a75b1.235448",
198                "9252f8ff.3db28",
199                "682b38c1.07ca",
200                "ac7f0e7c.0185f8"
201            ]
202        ]
203    },
204    {
205        "id": "5a56f10a.bea118",
206        "type": "inject",
207        "z": "cb770acb.c93ed8",
208        "name": "",
209        "topic": "",
210        "payload": "",
211        "payloadType": "date",
212        "repeat": "15",
213        "crontab": "",
214        "once": true,
215        "onceDelay": "3",
216        "x": 110,
217        "y": 40,
218        "wires": [
219            [
220                "c2a298f7.fd6db"
221            ]
222        ]
223    },
224    {
225        "id": "c2a298f7.fd6db",
226        "type": "function",
227        "z": "cb770acb.c93ed8",
228        "name": "set headers",
229        "func": "msg.payload = {\"size\" : 1, \"sort\" : [{ \"timestamp\" : {\"order\" : \"desc\"}}], \"query\" : {\"match\":{\"streamId\": \"xyz-mIoTREPLACE_ME_WITH_YOUR_IMEI\"}}};\n\nmsg.headers = {};\nmsg.headers['Accept'] = 'application/json';\nmsg.headers['X-API-KEY'] = 'REPLACE_ME_WITH_YOUR_X_API_KEY';\nreturn msg;",
230        "outputs": 1,
231        "noerr": 0,
232        "x": 270,
233        "y": 40,
234        "wires": [
235            [
236                "b83b0d93.6054a"
237            ]
238        ]
239    },
240    {
241        "id": "c162ed0c.287d28",
242        "type": "ui_text",
243        "z": "cb770acb.c93ed8",
244        "group": "36053808.0e202",
245        "order": 3,
246        "width": 0,
247        "height": 0,
248        "name": "",
249        "label": "data",
250        "format": "{{msg.payload.created}}",
251        "layout": "row-left",
252        "x": 610,
253        "y": 180,
254        "wires": []
255    },
256    {
257        "id": "b0ecc0f.43c0f4",
258        "type": "ui_gauge",
259        "z": "cb770acb.c93ed8",
260        "name": "",
261        "group": "36053808.0e202",
262        "order": 1,
263        "width": 0,
264        "height": 0,
265        "gtype": "donut",
266        "title": "Vbat",
267        "label": "V",
268        "format": "{{payload.value.Vbat}}",
269        "min": 0,
270        "max": "8",
271        "colors": [
272            "#00b500",
273            "#e6e600",
274            "#ca3838"
275        ],
276        "seg1": "4.4",
277        "seg2": "5.2",
278        "x": 610,
279        "y": 100,
280        "wires": []
281    },
282    {
283        "id": "c0805c2f.df0e4",
284        "type": "function",
285        "z": "cb770acb.c93ed8",
286        "name": "extrfromArray",
287        "func": "msg.payload = msg.payload.replace(\"[\",\"\");\nmsg.payload = msg.payload.replace(\"]\",\"\");\nreturn msg;",
288        "outputs": 1,
289        "noerr": 0,
290        "x": 140,
291        "y": 160,
292        "wires": [
293            [
294                "481bd64f.946bd"
295            ]
296        ]
297    },
298    {
299        "id": "f48a75b1.235448",
300        "type": "ui_gauge",
301        "z": "cb770acb.c93ed8",
302        "name": "",
303        "group": "36053808.0e202",
304        "order": 2,
305        "width": 0,
306        "height": 0,
307        "gtype": "gage",
308        "title": "Vin",
309        "label": "V",
310        "format": "{{payload.value.Vin}}",
311        "min": 0,
312        "max": 10,
313        "colors": [
314            "#00b500",
315            "#e6e600",
316            "#ca3838"
317        ],
318        "seg1": "",
319        "seg2": "",
320        "x": 610,
321        "y": 140,
322        "wires": []
323    },
324    {
325        "id": "9252f8ff.3db28",
326        "type": "ui_text",
327        "z": "cb770acb.c93ed8",
328        "group": "258bd191.04d6ce",
329        "order": 0,
330        "width": 0,
331        "height": 0,
332        "name": "",
333        "label": "",
334        "format": "{{msg.payload}}",
335        "layout": "row-spread",
336        "x": 630,
337        "y": 20,
338        "wires": []
339    },
340    {
341        "id": "4de3ef4c.91e3a",
342        "type": "ui_chart",
343        "z": "cb770acb.c93ed8",
344        "name": "",
345        "group": "c882381b.af42b",
346        "order": 0,
347        "width": 0,
348        "height": 0,
349        "label": "temperature",
350        "chartType": "line",
351        "legend": "false",
352        "xformat": "HH:mm",
353        "interpolate": "linear",
354        "nodata": "no data",
355        "dot": false,
356        "ymin": "",
357        "ymax": "",
358        "removeOlder": 1,
359        "removeOlderPoints": "",
360        "removeOlderUnit": "3600",
361        "cutout": 0,
362        "useOneColor": false,
363        "colors": [
364            "#1f77b4",
365            "#aec7e8",
366            "#ff7f0e",
367            "#2ca02c",
368            "#98df8a",
369            "#d62728",
370            "#ff9896",
371            "#9467bd",
372            "#c5b0d5"
373        ],
374        "useOldStyle": false,
375        "x": 650,
376        "y": 260,
377        "wires": [
378            [],
379            []
380        ]
381    },
382    {
383        "id": "682b38c1.07ca",
384        "type": "function",
385        "z": "cb770acb.c93ed8",
386        "name": "get temperature",
387        "func": "var msgout =\"\";\nmsgout= msg.payload.value.tmp;\nmsg.payload=msgout;\nmsg.topic=\"Temp\"; \nreturn msg;",
388        "outputs": 1,
389        "noerr": 0,
390        "x": 460,
391        "y": 260,
392        "wires": [
393            [
394                "4de3ef4c.91e3a"
395            ]
396        ]
397    },
398    {
399        "id": "ac7f0e7c.0185f8",
400        "type": "function",
401        "z": "cb770acb.c93ed8",
402        "name": "get humidity",
403        "func": "var msgout =\"\";\nmsgout= msg.payload.value.hum;\nmsg.payload=msgout;\nmsg.topic=\"Humi\"; \nreturn msg;",
404        "outputs": 1,
405        "noerr": 0,
406        "x": 450,
407        "y": 300,
408        "wires": [
409            [
410                "1d061750.3406a1"
411            ]
412        ]
413    },
414    {
415        "id": "1d061750.3406a1",
416        "type": "ui_chart",
417        "z": "cb770acb.c93ed8",
418        "name": "",
419        "group": "c882381b.af42b",
420        "order": 0,
421        "width": 0,
422        "height": 0,
423        "label": "humidity",
424        "chartType": "line",
425        "legend": "false",
426        "xformat": "HH:mm:ss",
427        "interpolate": "linear",
428        "nodata": "no data",
429        "dot": false,
430        "ymin": "",
431        "ymax": "",
432        "removeOlder": 1,
433        "removeOlderPoints": "",
434        "removeOlderUnit": "3600",
435        "cutout": 0,
436        "useOneColor": false,
437        "colors": [
438            "#1f77b4",
439            "#aec7e8",
440            "#ff7f0e",
441            "#2ca02c",
442            "#98df8a",
443            "#d62728",
444            "#ff9896",
445            "#9467bd",
446            "#c5b0d5"
447        ],
448        "useOldStyle": false,
449        "x": 640,
450        "y": 300,
451        "wires": [
452            [],
453            []
454        ]
455    }
456]
457

Save it as "my_LiveObjects_reporting.json". Alternate, you may download it from here (right click & save as):
NODE RED flow definition - aquire and display xyz-mIoT sensor data from Live Objects cloud

Edit the definition file and update :
REPLACE_ME_WITH_YOUR_IMEI using your modem IMEI value
and
REPLACE_ME_WITH_YOUR_X_API_KEY using your LiveObjects API KEY.

Access the NODE RED admin interface and "MENU\Import" "my_LiveObjects_reporting.json" report definition file. The reporting flow will be displayed in NODE RED admin interface.
NODE RED ADMIN INTERFACE Click on "Deploy" button. The reporting flow will start to run by acquiring data from LiveObjects cloud.

Now, the reporting interface is available at http://localhost:1880/ui/.
NODE RED UI INTERFACE - display IoT data stored in LiveObjects

 

ENJOY!

 

 

TUTORIAL PROVIDED WITHOUT ANY WARRANTY!!! USE IT AT YOUR OWN RISK!!!!

 

 

 

Final thoughts

LiveObjects cloud service is really huge! Whith this demo, we just scratch the surface.
Read LiveObjects docs and additional references and start you IoT project.
BTW: NODE RED is based on javascript. A good js reference can be found at: https://www.w3schools.com/js/.

 

 

 

Dragos Iosub & itbrainpower.net team original how to.

 

 

 

 

document version 0.911 / 2020-06-10 © R&D Software Solutions srl