Skip to content
/ lds Public
forked from iegomez/lds

Loraserver device simulator with a simple GUI.

Notifications You must be signed in to change notification settings

OniremE/lds

 
 

Repository files navigation

Loraserver device simulator

This is an utility program to simulate devices for the loraserver project. Basically, it acts as a lora-gateway-bridge middleman, publishing and receiving messages through MQTT. It supports all bands and configurations LoRaWAN versions 1.0 and 1.1 and is compatible with newest version of loraserver modules (v3 test).

It has a simple but complete GUI built with imgui-go and OpenGL 3.2, that allows to configure everything that's needed, such as MQTT broker and credentials, device keys, LoRaWAN version, message marshaling method, data payload, etc.

Please report any bug or request new features by filing and issue.

This program was also extended to generate raw PACKET FORWARDER UDP-based protocol as alternative transport, to be used with general LoRaWAN network server (e.g. lorawan-server). Use forwarder configuration section to enable.

Requirements

As mentioned, this program needs OpenGL 3.2 to be installed. Also, it uses Redis to store device addres and keys, frame counters and nonces in OTAA mode.

Conf

The GUI allows to modify all options, but they may also be seeded with a conf file for ease of use. An example file is provided to get an idea, but the program will only load a conf file with the name conf.toml located at the same dir as the binary, or if the path is given with the --conf flag:

#Configuration.
log_level = "info"

[provisioner]
	hostname = "https://example.com"
	username = "username"
	password = "password"
	path = "path/to/devices.csv"

[mqtt]
  server = "tcp://localhost:1883"
  user = "username"
  password = "password"
  # Uplink topic. %s will be replaced with the gateway mac.
  uplink_topic="gateway/%s/event/up"
  # Downlink topic. %s will be replaced with the gateway mac.
  downlink_topic="gateway/%s/command/down"

[gateway]
  mac = "b827ebfffe9448d0"

[band]
  name = "AU_915_928"

[device]
  eui="0000000000000000"
  address="000f6e3b"
  network_session_encription_key="dc5351f56794ed3ac17c382927192858"
  serving_network_session_integrity_key="dc5351f56794ed3ac17c382927192858"
  forwarding_network_session_integrity_key="dc5351f56794ed3ac17c382927192858"
  application_session_key="7b14565ba0e30d6ced804393fd6a0dd5"
  marshaler="json"
  nwk_key="00000000000000010000000000000001"
  app_key="00000000000000010000000000000001"
  join_eui="0000000000000002"
  mac_version=1
  profile="OTAA"
  joined=false
  skip_fcnt_check=true

[data_rate]
  bandwith = 125
  spread_factor = 10
  bit_rate = 0

[rx_info]
  channel = 0
  code_rate = "4/5"
  crc_status = 1
  frequency = 916800000
  lora_snr = 7.0
  rf_chain = 1
  rssi = -57

[raw_payload]
  payload = "ff00"
  use_raw = false
	script = "\n// Encode encodes the given object into an array of bytes.\n//  - fPort contains the LoRaWAN fPort number\n//  - obj is an object, e.g. {\"temperature\": 22.5}\n// The function must return an array of bytes, e.g. [225, 230, 255, 0]\nfunction Encode(fPort, obj) {\n\treturn [\n      obj[\"Flags\"],\n      obj[\"Battery\"],\n      obj[\"Light\"],\n    ];\n}\n"
  use_encoder = true
  max_exec_time = 500
  js_object = "{\n \"Flags\": 0,\n \"Battery\": 65,\n \"Light\": 54\n}"
  fport = 2

[[encoded_type]]
  name = "Flags"
  value = 5.0
  max_value = 255.0
  min_value = 0.0
  is_float = false
  num_bytes = 1

[[encoded_type]]
  name = "Batería"
  value = 80.0
  max_value = 255.0
  min_value = 0.0
  is_float = false
  num_bytes = 1

[[encoded_type]]
  name = "Luz"
  value = 50.0
  max_value = 255.0
  min_value = -0.0
  is_float = false
  num_bytes = 1

[redis]
  addr = "localhost:6379"
  password = ""
  db = 10

[window]
  width = 1200
  height = 1000

[forwarder]
  nserver = "192.168.5.71"
  nsport = "1680"

You may also import files located at working-dir/confs and save to the same directory.

When OTAA is set and the device is joined, upon initialization the program will try to load keys and relevant data from Redis, overriding keys from the file.

Data

The data to be sent may be presented as a hex string representation of the raw bytes, using a JS object and a decoding function to extract a bytes array from it, or using our encoding method (which then needs to be decoded accordingly at lora-app-server). As a reference, this is how we encode our data:

func GenerateFloat(originalFloat, maxValue float32, numBytes int32) []byte {
	byteArray := make([]byte, numBytes)
	if numBytes == 4 {
		encodedFloat := uint32((originalFloat / maxValue) * float32(math.Pow(2, 31)))
		binary.BigEndian.PutUint32(byteArray, encodedFloat)
	} else if numBytes == 3 {
		encodedFloat := uint32((originalFloat / maxValue) * float32(math.Pow(2, 23)))
		temp := make([]byte, 4)
		binary.BigEndian.PutUint32(temp, encodedFloat)
		byteArray = temp[1:]
	} else if numBytes == 2 {
		encodedFloat := uint16((originalFloat / maxValue) * float32(math.Pow(2, 15)))
		binary.BigEndian.PutUint16(byteArray, encodedFloat)
	} else if numBytes == 1 {
		byteArray[0] = uint8(originalFloat)
	}
	return byteArray
}

func GenerateInt(originalInt, numBytes int32) []byte {

	bRep := make([]byte, numBytes)
	if numBytes == 4 {
		binary.BigEndian.PutUint32(bRep, uint32(originalInt))
	} else if numBytes == 3 {
		temp := make([]byte, 4)
		binary.BigEndian.PutUint32(temp, uint32(originalInt))
		bRep = temp[1:]
	} else if numBytes == 2 {
		binary.BigEndian.PutUint16(bRep, uint16(originalInt))
	} else if numBytes == 1 {
		bRep[0] = uint8(originalInt)
	}

	return bRep
}

When using our encoding method, values may be added using the Add encoded type button and setting the options.

To use your own custom JS encoder, click the "Use encoder" checkbox and the "Open decoder" button to open the form:

MAC Commands

All lorawan package end-device MAC commands are available to be sent with a message. Check desired mac commands and fill their payloads when needed.

Device provisioning

You may provision devices from a CSV file using the simple https://github.com/iegomez/lsp package. Open the form with File -> Provision, which'll let you input hostname, username and password (click Login to get and store a token for further calls), fill the local path to point to the desired CSV (click Load to retrieve devices from the file) and then click on Provision to provision the devices through lora-app-server's API. See https://github.com/iegomez/lsp/blob/master/devices-example-format.csv to check the required CSV format.

Building

The package is written in Go and tested with Go 1.12, which can be downloaded from https://golang.org/dl/. The GUI is built using imgui-go and OpenGL 3.2. Finally, the program depends on Redis.

Something like this should work for Debian / Ubuntu / Mint, but please check imgui-go and general OpenGL docs to see requirements for your system:

sudo apt install build-essential xorg-dev libgl1 libgl1-mesa-dev libgl1-mesa-glx redis-server

Once those are met, you may build the package like this, which will manage dependencies using Go modules:

make

This will create the gui executable.

About

Loraserver device simulator with a simple GUI.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%