How do I can connect MQTT BROKER with NODE RED and show the device data in web browser


#1

Hello everyone,

I want to know a possible solution about connect node-red to my lora-app-server to show my data of my sensors.
I already only install node red by this https://nodered.org/docs/getting-started/installation

P.S.: I don have a physic gateway I have a gateway + node simulator with this Simulate message from the Gateway => Gateway Bridge

If someone has try it please teach me.

Thanks everybody :wink:


#2

As I told you, in its latest version lora-app-server already shows live device data, you don’t need anything special here.


#3

But how I can pass that information to web browser? It’s like to show in another page with the information about sensors like temperature and date&time.


#4

The lora-app-server already presents it in your browser, again, in the live device data section. If what you want is to forward the data to another service (e.g.: your own server that exposes it as a web page), ways to integrate data are described here: https://www.loraserver.io/lora-app-server/integrate/sending-receiving/.


#5

So I want to know what is my first step to do? I already installed node-red and saw some docs to learn but in this case particularity I don’t what would do :frowning:


#6

But without node-red what solution do you recommend to use? :confused:


#7

Hi! Could you elaborate on what your exact idea is? Do wou want to serve a separate website that’ll show the lvie data? Do you just need a visualization tool? Please be thorough about it so we can be of help.


#8

Exactly! I want to show in another website my live data and yes I need a visualization tool.


#9

The script that you made can send for example a temperature value?


#10

My package sends a valid lorawan package to a mqtt broker given that you set things up correctly, no more no less.

If you want to show data on a separate website, then you’ll need to build your own infrastructure thet gets the data etiher from the http or mqtt integrations available that were pointed earlier. If you go with http, then your application will probably need to use websockets or something on top of them to push the data to the frontend live. If you go with mqtt, you may subscribe directly from javascript to the data topics that lora-app-server publishes. Consider that to make it work you’ll need to set ssl/tls on your broker to connect directly from the web.

All of these requires work from you and you need to know how to build those things, which are way out of scope of loraserver. So maybe you could give a look to the InfluxDB integration. I haven’t used it, but it seems to have some nice instructions: https://www.loraserver.io/lora-app-server/integrate/sending-receiving/influxdb/.


#11

Thanks for your support :smiley:


#12

But I can use node-red as my infrastructure?


#13

As far as I know, you can subscribe to mqtt topics from node-red, but I’ve never used it, so I really can’t tell.


#14

Yes, this works and you should be able to set this up in a few clicks :slight_smile:


#15

Sorry, I just realized that the topic title mentioned node-red :man_facepalming:. I got confused because you asked me something very similar in a private message.


#16

I’m sorry for not being clear :frowning: So my problem is when I send the package of go programm that you made, I need to send a topic.
I tried this command mosquitto_pub -m "payload" -h 127.0.0.1 -p 1883 -u admin -P admin -t "topic" and it works when I see in node red page.
But how can I publish a topic with the program that you made?


#17

imageedit_1_2130305960



#18

I’ll add what you asked me personally:

Again, my package is able to send a valid lorawan message to a broker. What you do with it is up to you.

That said, it’ll depend on how you encode/decode your data, as a data payload is nothing but an array of bytes. For example, the simplest case is where you take only positive integral temperature, so you can represent from 0 up to 255 degrees on a single byte without any encoding.

But what if you want to be able to send negative temperatures? You could use 2’s complement to represent the sign, which will let you encode from -127 to 127 degrees, again only with one byte. And this is really easy to represent, as all you need to do at loraserver’s side is write a decoding function that checks if the value you got is greater than 127 and in that case convert it like this:

if value > 127 {
  temp = value - 2*127
}

But then maybe you don’t want to be limited to integers, so instead you send your temperature using two bytes: one represents the integral part and the sign, and the other byte gives you 8 bits of precision. How do you use them to represent your value? There’s a lot of ways, so just search a bit, pick your favourite and then implement the encoding on your program that is sending the lorawan message. Just as an example, we’ve used this format to encode arbitrary precision float data (latitude, longitude, temperature, rpessure, etc.).

After that, at lora-app-server go to the application where your device is registered, and at Application configuration select javascript for the payload codec and write a function that decodes the bytes array that you’ll get. This function should do exactly the opposite than the encoding one, so if we take the simple example from before, the original encoding (i.e., at the sending script) function should have done something like this:

if temp < 0 {
  value = temp + 2*127
}

Of course, the payload codec needs to return a JS object, so your decoding function at lora-app-server should resemble this:

function Decode(fPort, bytes) {

  var temp = bytes[0];
  if temp > 127 {
    temp = temp - 2*127;
  }
  var dataout = {
  "temperature": {
      "value":temp,
    },
  };

  return dataout;

}

Finally, at node-red you can subscribe to the topic application/[applicationID]/device/[devEUI]/rx and you’ll get a nice json that’ll contain the key object for your data:

{
...
 "object": {                    
        "temperature": {"value": 30},
    }
...
}

Hope that clears up things.


#19

Thank you very much :slight_smile:
I’m trying another way to send to node-red. In fact, I’m trying to send the values of payload with this

// Publish a message.
err = cli.Publish(&client.PublishOptions{
	QoS:       mqtt.QoS0,
	TopicName: []byte("hello"),
	Message:   []byte("hi"),
})
if err != nil {
	panic(err)
}

But my problem right now is that I can’t convert the payload value to put in the Message.

Also I can’t do this because with the go program https://github.com/dcarva/ubw_go_script_package/blob/master/gateway.go I can’t add this information [https://github.com/yosssi/gmq] do publish the temperature in my topic.

It returns this error:

./gateway.go:240:29: type client.ConnectOptions is not an expression

and this my code:

`package main

import (
	"os"

	"github.com/spf13/cobra"
	
	"fmt"
        "math/rand"
        "time"

        "github.com/brocaar/lorawan"

        MQTT "github.com/eclipse/paho.mqtt.golang"
        lds "github.com/iegomez/loraserver-device-sim"
	
		"os/signal"

	"github.com/yosssi/gmq/mqtt"
	"github.com/yosssi/gmq/mqtt/client"
)

const (
	ipFlag = "ip"
	portFlag="port"

)

func main() {
	cmd := &cobra.Command{
		Use:          "ui",
		Short:        "Bem-vindo",
		SilenceUsage: true,
	}

	cmd.AddCommand(mainCmd())
	cmd.AddCommand(jardimCmd())

	if err := cmd.Execute(); err != nil {
		os.Exit(1)
	}
}

func mainCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use: "sensor",
		RunE: func(cmd *cobra.Command, args []string) error {
			ip, err := cmd.Flags().GetString(ipFlag)
			
			port, err2 := cmd.Flags().GetString(portFlag)
			
			if err != nil || err2 != nil {
				return err
				return err2
			}

			/*cmd.Println("A porta:", port)
			
			cmd.Println("O IP da gateway:", ip)*/

			var end_ip string
			end_ip=ip+":"+port
			
			var end string
			end="tcp://"+end_ip
			
			cmd.Println(end)
			


	//Connect to the broker
	/*opts := MQTT.NewClientOptions()
	opts.AddBroker(end)
	opts.SetUsername("your-username")
	opts.SetPassword("your-password")
	*/

	/* Create an MQTT Client.
	cli := client.New(&client.Options{
	ErrorHandler: func(err error) {
		fmt.Println(err)
		},
	})  */
			
			
		// Set up channel on which to send signal notifications.
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt, os.Kill)

	// Create an MQTT Client.
	cli := client.New(&client.Options{
		// Define the processing of the error handler.
		ErrorHandler: func(err error) {
			fmt.Println(err)
		},
	})

	// Terminate the Client.
	defer cli.Terminate()

	// Connect to the MQTT Server.
	err = cli.Connect(&client.ConnectOptions{
		Network:  "tcp",
		Address:  "127.0.0.1:1883",
		ClientID: []byte("example-client"),
	})
	if err != nil {
		panic(err)
	}

	// Subscribe to topics.
	err = cli.Subscribe(&client.SubscribeOptions{
		SubReqs: []*client.SubReq{
			&client.SubReq{
				TopicFilter: []byte("hello"),
				QoS:         mqtt.QoS0,
				// Define the processing of the message handler.
				Handler: func(topicName, message []byte) {
					fmt.Println(string(topicName), string(message))
				},
			},
		},
	})
	if err != nil {
		panic(err)
	}

	// Publish a message.
	err = cli.Publish(&client.PublishOptions{
		QoS:       mqtt.QoS0,
		TopicName: []byte("hello"),
		Message:   []byte("temp"),
	})
	if err != nil {
		panic(err)
	}
			
			

///******************************//////////////////////
	/*if token := client.Connect(); token.Wait() && token.Error() != nil {
		fmt.Println("Connection error")
		fmt.Println(token.Error())
	} */

	fmt.Println("Connection established.")

	//Build your node with known keys (ABP).
	nwsHexKey := "3bc0ddd455d320a6f36ff6f2a25057d0"
	appHexKey := "00de01b45b59a4df9cc2b3fa5eb0fe7c"
	devHexAddr := "07262b83"
	devAddr, err := lds.HexToDevAddress(devHexAddr)
	if err != nil {
		fmt.Printf("dev addr error: %s", err)
	}

	nwkSKey, err := lds.HexToKey(nwsHexKey)
	if err != nil {
		fmt.Printf("nwkskey error: %s", err)
	}

	appSKey, err := lds.HexToKey(appHexKey)
	if err != nil {
		fmt.Printf("appskey error: %s", err)
	}

	appKey := [16]byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
	appEUI := [8]byte{0, 0, 0, 0, 0, 0, 0, 2}
	devEUI := [8]byte{0, 0, 0, 0, 0, 0, 0, 2}

	device := &lds.Device{
		DevEUI:  devEUI,
		DevAddr: devAddr,
		NwkSKey: nwkSKey,
		AppSKey: appSKey,
		AppKey:  appKey,
		AppEUI:  appEUI,
		UlFcnt:  0,
		DlFcnt:  0,
	}

	/*
		*	Make up some random values.
		*
		*	These should be decoded at lora-app-server with a proper function.
		* 	For this example, the object should look like this:
			obj : {
				"temperature": {
					"value":((bytes[0]*256+bytes[1])/100),"unit":"°C"
				},
				"pressure": {
					"value":((bytes[2]*16*16*16*16+bytes[3]*256+bytes[4])/100),"unit":"hPa"
				},
				"humidity": {
					"value":((bytes[5]*256+bytes[6])/1024),"unit":"%"
				}
			}
		*
	*/
	rand.Seed(time.Now().UnixNano() / 10000)
	temp := [2]byte{uint8(rand.Intn(25)), uint8(rand.Intn(100))}
	pressure := [3]byte{uint8(rand.Intn(2)), uint8(rand.Intn(20)), uint8(rand.Intn(100))}
	humidity := [2]byte{uint8(rand.Intn(100)), uint8(rand.Intn(100))}



	//Create the payload, data rate and rx info.

	payload := []byte{temp[0], temp[1], pressure[0], pressure[1], pressure[2], humidity[0], humidity[1]}


	//Change to your gateway MAC to build RxInfo.
	gwMac := "b827ebfffeb13d1f"

	//Construct DataRate RxInfo with proper values according to your band (example is for US 915).

        dataRate := &lds.DataRate{
        //      Bandwidth:    500,
                Bandwidth: 125,
                Modulation:   "LORA",
                SpreadFactor: 8,
                BitRate:      0}

        rxInfo := &lds.RxInfo{
                Channel:   0,
                CodeRate:  "4/5",
                CrcStatus: 1,
                DataRate:  dataRate,
		Frequency: 869000000,
                LoRaSNR:   7,
                Mac:       gwMac,
                RfChain:   1,
                Rssi:      -57,
                Size:      23,
                Time:      time.Now().Format(time.RFC3339),
                Timestamp: int32(time.Now().UnixNano() / 1000000000),
	 }

	    //Now send an uplink
        err = device.Uplink(&client.ConnectOptions, lorawan.UnconfirmedDataUp, 1, rxInfo, payload)
        if err != nil {
                fmt.Printf("couldn't send uplink: %s\n", err)
        }

			return nil
		},
	}
	cmd.Flags().String(ipFlag, "127.0.0.1", "How to connect")
	cmd.Flags().String(portFlag, "1883", "How to connect")
	return cmd
}

func jardimCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use: "sensorjardim",
		RunE: func(cmd *cobra.Command, args []string) error {
			ip, err := cmd.Flags().GetString(ipFlag)
			
			port, err2 := cmd.Flags().GetString(portFlag)
			
			if err != nil || err2 != nil {
				return err
				return err2
			}

			/*cmd.Println("A porta:", port)
			
			cmd.Println("O IP da gateway:", ip)*/

			var end_ip string
			end_ip=ip+":"+port
			
			var end string
			end="tcp://"+end_ip
			
			cmd.Println(end)
			


	//Connect to the broker
	opts := MQTT.NewClientOptions()
	opts.AddBroker(end)
	opts.SetUsername("your-username")
	opts.SetPassword("your-password")


	client := MQTT.NewClient(opts)

	if token := client.Connect(); token.Wait() && token.Error() != nil {
		fmt.Println("Connection error")
		fmt.Println(token.Error())
	}

	fmt.Println("Connection established.")

	//Build your node with known keys (ABP).
	nwsHexKey := "783f27d6a19e8701c4fcda7fdcba759e"
	appHexKey := "a5fe469807d274392020163c0764c647"
	devHexAddr := "018a1f94"
	devAddr, err := lds.HexToDevAddress(devHexAddr)
	if err != nil {
		fmt.Printf("dev addr error: %s", err)
	}

	nwkSKey, err := lds.HexToKey(nwsHexKey)
	if err != nil {
		fmt.Printf("nwkskey error: %s", err)
	}

	appSKey, err := lds.HexToKey(appHexKey)
	if err != nil {
		fmt.Printf("appskey error: %s", err)
	}

	appKey := [16]byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
	appEUI := [8]byte{0, 0, 0, 0, 0, 0, 0, 3}
	devEUI := [8]byte{0, 0, 0, 0, 0, 0, 0, 3}

	device := &lds.Device{
		DevEUI:  devEUI,
		DevAddr: devAddr,
		NwkSKey: nwkSKey,
		AppSKey: appSKey,
		AppKey:  appKey,
		AppEUI:  appEUI,
		UlFcnt:  0,
		DlFcnt:  0,
	}

	rand.Seed(time.Now().UnixNano() / 10000)
	temp := [2]byte{uint8(rand.Intn(25)), uint8(rand.Intn(100))}
	pressure := [3]byte{uint8(rand.Intn(2)), uint8(rand.Intn(20)), uint8(rand.Intn(100))}
	humidity := [2]byte{uint8(rand.Intn(100)), uint8(rand.Intn(100))}

	//Create the payload, data rate and rx info.
	payload := []byte{temp[0], temp[1], pressure[0], pressure[1], pressure[2], humidity[0], humidity[1]}

	//Change to your gateway MAC to build RxInfo.
	gwMac := "b827ebfffeb13d1f"

	//Construct DataRate RxInfo with proper values according to your band (example is for US 915).

        dataRate := &lds.DataRate{
        //      Bandwidth:    500,
                Bandwidth: 125,
                Modulation:   "LORA",
                SpreadFactor: 8,
                BitRate:      0}

        rxInfo := &lds.RxInfo{
                Channel:   0,
                CodeRate:  "4/5",
                CrcStatus: 1,
                DataRate:  dataRate,
		Frequency: 869000000,
                LoRaSNR:   7,
                Mac:       gwMac,
                RfChain:   1,
                Rssi:      -57,
                Size:      23,
                Time:      time.Now().Format(time.RFC3339),
                Timestamp: int32(time.Now().UnixNano() / 1000000000),
        }

	    //Now send an uplink
        err = device.Uplink(client, lorawan.UnconfirmedDataUp, 1, rxInfo, payload)
        if err != nil {
                fmt.Printf("couldn't send uplink: %s\n", err)
        }
			
			
			return nil
		},
	}
	cmd.Flags().String(ipFlag, "127.0.0.1", "How to connect")
	cmd.Flags().String(portFlag, "1883", "How to connect")
	return cmd
}

#20

You are adding a second mqtt client (why?) to send some direct messages (i.e., not lorawan) to the broker so you may read them at node-red. So all you wanted was to send some data and read it at another end as plain as it was sent? Why are you trying to use loraserver for this?