cancel
Showing results for 
Search instead for 
Did you mean: 

How to create a LoRaWAN server on local PC(2/2) - Application server

Filip SCHWANK
ST Employee
How to create a LoRaWAN server on local PC(2/2) - Application serverLoRaWAN with custom server
This is the second part of a custom LoRaWAN server tutorial. For the first part - setting up the Network server, please refer to:
How to create a LoRaWAN server on local PC(1/2) - Network server
 

Application server

Now that the network server is up and running, we can move to creating an Application server. In this case it is a Node-Red server running again on localhost with a simple application. It receives frame and based on the value, sends answer back to the Nwk server.

Node-Red installation

  1. The installation of Node-Red is again quite an easy task. Follow link: https://nodered.org/docs/getting-started/local
  2. Download Node.js for your platform:
https://nodejs.org/en/download/
  1. After Node.js installation you should be able to run:
npm install -g --unsafe-perm node-red
  1. Now open Windows command line (cmd.exe) and start up Node-red server by calling:
node-red
  1. The server should be available at:
http://localhost:1880/
49.png

Adding a flow

The Node Red server works with flows, so that it is easy to use, because it is almost like an application flow chart. The included flow is ready to handle our application, just click top right, Import and link the json file. You will get a pop up with non-recognized package, which is the MQTT broker used in the application. Install it from Manage palette in the top right corner menu, Install tab, find node-red-contrib-mqtt-broker. Once the installation is done, it is needed to fill out the authentication for each http request with username admin, psw admin, otherwise it will return Unauthorized status. Lastly just click the red button Deploy to run the server.

Connecting the App server with Nwk server

Now we have an Application server and a Network server running, but they do not know about each other. In the App server there is also a MQTT broker which provides connection to the App server, so that it can read the coming data – subscribe and post new data coming back to the Nwk server. So now we must define a MQTT connection for the Nwk server to the MQTT broker.
  1. Add a handler in the Nwk server. 50.png
  2. Create a connector
51.png
  1. If everything is successful, connection status should be in green and we can move to the last step and that is changing the application in the device profile. 52.png
 

The application flow

The flow used in this tutorial is quite simple.
53.png

There are two mqtt brokers to receive and send data from and to the server.
54.png
55.png
 The received data is in JSON format, so a converter is used to get the actual data to a JavaScript object.
56.png
Then, in the payload.text attribute there is the data sent from our node, so it is compared as a number with a threshold.
57.png
The comparison decides which path is taken (increase, decrease, equal) and each path inserts I,D,E character in hexadecimal to the payload.
58.png
The original text is deleted, the object converted again to JSON and sent over the mqtt broker.
59.png
This was the main part of the application, but because the network server does not have any option to accept all devices, it is either necessary to register the end devices manually (which for a larger amount of devices would be quite tiresome to achieve), or with predefined information (which is in case of larger amount of devices again more complicated to maintain and not human error proof). So, the only easy solution is that the application server will also take care of the registration. Unfortunately, there is no API to react on the event of connection of a new device, but there is at least REST API, which can give out a list of unregistered devices. This list is checked each minute to obtain new devices.
First, and to keep it simple, we need a storage for our devices. A simple function, that will set a global variable to store the devEUI.
60.png
To register a node, we need the mentioned list of unregistered devices, which is accessible using GET on the following url: http://localhost:8080/api/events?_filters={"text":"unknown_deveui"}
61.png
Then the payload is processed by JSON converter and then a function follows to store the information into the storage variable created before and to prepare the data for the registration request, again using REST API.
62.png
The information is converted to JSON, http headers are added and a POST is generated to the following url: http://localhost:8080/api/devices63.png
Just to note, this process does not clear the unknown_deveui event list, so that must be done manually in the server dashboard.
64.png
It is possible to filter by the specific event and clear just the registered devices. This will prevent the JSON list of devices to be too long in case of many devices joining. If a device not registered yet has been cleared from the list, it is not an issue, as the device will try to join again, or one can push the reset button on the device to make the device appear again in the list.
 

The final flow

You can simply import the flow used in this tutorial by clicking the top right corner -> Import and paste the JSON encoded flow below.
65.png

 
[{"id":"d9da327e.4ef12","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"c16ffb2a.e37088","type":"debug","z":"d9da327e.4ef12","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":870,"y":760,"wires":[]},{"id":"8924618b.cf3b9","type":"mqtt in","z":"d9da327e.4ef12","name":"","topic":"data","qos":"2","datatype":"auto","broker":"8de7932d.d610d","x":690,"y":680,"wires":[["c16ffb2a.e37088","167d6db.1a71892"]]},{"id":"9215b618.66a9f8","type":"switch","z":"d9da327e.4ef12","name":"COMPARE","property":"payload.text","propertyType":"msg","rules":[{"t":"lt","v":"7","vt":"num"},{"t":"gt","v":"7","vt":"num"},{"t":"eq","v":"7","vt":"num"}],"checkall":"true","repair":false,"outputs":3,"x":870,"y":600,"wires":[["3c8f1b7d.71c204"],["8b05244b.b4b798"],["ef29c2b1.5823"]]},{"id":"3c8f1b7d.71c204","type":"change","z":"d9da327e.4ef12","name":"INCREASE","rules":[{"t":"set","p":"payload.data","pt":"msg","to":"49","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":520,"wires":[["d1a23cc6.0c9b3"]]},{"id":"8b05244b.b4b798","type":"change","z":"d9da327e.4ef12","name":"DECREASE","rules":[{"t":"set","p":"payload.data","pt":"msg","to":"44","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":600,"wires":[["d1a23cc6.0c9b3"]]},{"id":"ef29c2b1.5823","type":"change","z":"d9da327e.4ef12","name":"EQUAL","rules":[{"t":"set","p":"payload.data","pt":"msg","to":"45","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":680,"wires":[["d1a23cc6.0c9b3"]]},{"id":"de40a174.faaaa","type":"debug","z":"d9da327e.4ef12","name":"","active":false,"console":"false","complete":"false","x":1530,"y":680,"wires":[]},{"id":"b22aad06.d581d","type":"mqtt out","z":"d9da327e.4ef12","name":"","topic":"tx","qos":"","retain":"","broker":"8de7932d.d610d","x":1510,"y":760,"wires":[]},{"id":"167d6db.1a71892","type":"json","z":"d9da327e.4ef12","name":"","property":"payload","action":"","pretty":false,"x":850,"y":680,"wires":[["9215b618.66a9f8"]]},{"id":"d1a23cc6.0c9b3","type":"change","z":"d9da327e.4ef12","name":"","rules":[{"t":"delete","p":"payload.text","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1370,"y":600,"wires":[["821d13af.e85fc"]]},{"id":"821d13af.e85fc","type":"json","z":"d9da327e.4ef12","name":"","property":"payload","action":"","pretty":false,"x":1310,"y":700,"wires":[["b22aad06.d581d","de40a174.faaaa"]]},{"id":"9627abbf.0d1678","type":"http request","z":"d9da327e.4ef12","name":"","method":"GET","ret":"txt","paytoqs":false,"url":"http://localhost:8080/api/events?_filters={\"text\":\"unknown_deveui\"}","tls":"","persist":false,"proxy":"","authType":"basic","x":670,"y":940,"wires":[["7717d48d.2dd22c"]]},{"id":"2673ac65.6bc8e4","type":"debug","z":"d9da327e.4ef12","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1230,"y":1060,"wires":[]},{"id":"1736154f.ad5f4b","type":"inject","z":"d9da327e.4ef12","name":"GET new devices","topic":"","payload":"","payloadType":"date","repeat":"60","crontab":"","once":true,"onceDelay":0.1,"x":630,"y":860,"wires":[["9627abbf.0d1678"]]},{"id":"7717d48d.2dd22c","type":"json","z":"d9da327e.4ef12","name":"","property":"payload","action":"","pretty":false,"x":850,"y":940,"wires":[["ffbc473f.3bb198"]]},{"id":"ffbc473f.3bb198","type":"function","z":"d9da327e.4ef12","name":"Register node","func":"var msgIn = msg.payload;\nvar devEUIs = global.get(\"devEUIs\");\nmsg.payload = [];\nfor(var item of msgIn){\n    console.log(item.eid);\n    if(devEUIs.indexOf(item.eid)==-1){\n    msg.payload.push({\n        \"appeui\":\"0101010101010101\",\n        \"appkey\":\"2B7E151628AED2A6ABF7158809CF4F3C\",\n        \"deveui\":item.eid,\n        \"profile\":\"TestProfile\"\n        \n    });\n    devEUIs.push(item.eid);\n    }\n}\nglobal.set(\"devEUIs\",devEUIs);\n\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":940,"wires":[["f0f5b0f2.dbc27"]]},{"id":"dc3e2aa9.4fbcb8","type":"inject","z":"d9da327e.4ef12","name":"List registered devices","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":640,"y":1060,"wires":[["7d4eaabe.1c5f04"]]},{"id":"7d4eaabe.1c5f04","type":"http request","z":"d9da327e.4ef12","name":"","method":"GET","ret":"txt","paytoqs":false,"url":"http://localhost:8080/api/devices","tls":"","persist":false,"proxy":"","authType":"basic","x":870,"y":1060,"wires":[["2673ac65.6bc8e4"]]},{"id":"f4dd02ab.66c73","type":"debug","z":"d9da327e.4ef12","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1290,"y":920,"wires":[]},{"id":"f0f5b0f2.dbc27","type":"json","z":"d9da327e.4ef12","name":"","property":"payload","action":"","pretty":false,"x":1090,"y":860,"wires":[["26aaa1c0.a5493e","f4dd02ab.66c73"]]},{"id":"9ba941c.1a8e3c","type":"http request","z":"d9da327e.4ef12","name":"","method":"POST","ret":"txt","paytoqs":false,"url":"http://localhost:8080/api/devices","tls":"","persist":false,"proxy":"","authType":"basic","x":1510,"y":860,"wires":[[]]},{"id":"26aaa1c0.a5493e","type":"change","z":"d9da327e.4ef12","name":"","rules":[{"t":"set","p":"headers","pt":"msg","to":"{\"Content-Type\": \"application/json\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1300,"y":860,"wires":[["9ba941c.1a8e3c"]]},{"id":"405d62df.5a248c","type":"comment","z":"d9da327e.4ef12","name":"The AppKey is inside this function","info":"","x":1050,"y":980,"wires":[]},{"id":"9d9327f7.2c1cc8","type":"inject","z":"d9da327e.4ef12","name":"Initiate storage of devEUIs","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":640,"y":1180,"wires":[["d12d6219.f5668"]]},{"id":"d12d6219.f5668","type":"function","z":"d9da327e.4ef12","name":"Init devEUIs","func":"var devEUIs = [];\nglobal.set(\"devEUIs\",devEUIs);\nreturn msg;","outputs":1,"noerr":0,"x":890,"y":1180,"wires":[[]]},{"id":"10cdc4b1.fc265b","type":"mosca in","z":"d9da327e.4ef12","mqtt_port":1883,"mqtt_ws_port":"8081","name":"","username":"","password":"","dburl":"","x":650,"y":440,"wires":[[]]},{"id":"8de7932d.d610d","type":"mqtt-broker","z":"","name":"LoraMQTT","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

 
Comments
LProj.1
Associate

Dear Laura, I could not understand well about the "Adding a flow part" section and how to import json file. When I select the import from top right, I can not find a json file to import. Can you explain how to do it ?

Version history
Last update:
‎2020-11-25 12:35 AM
Updated by: