AWS IoT Greengrass extends cloud capabilities to local devices by enabling them to collect and analyze data closer to the information source, react autonomously to local events, and communicate securely with each other on local networks. In addition, developers can use AWS Lambda functions to create server-less applications that are deployed on devices for local execution. Therefore, it is practical to have AWS IoT Greengrass into MQTT communication circle on Milesight LoRaWAN Gateway and LoRaWAN Controllers.
Besides, data can be transmitted via MQTT provided by Milesight LoRaWAN Gateway. For further details, please refer to the user guide.
The SSH protocol (also referred to as Secure Shell) is a method for secure remote login from one computer to another. It provides several alternative options for strong authentication, and it protects the communications security and integrity with strong encryption. It is a secure alternative to non-protected login protocols (such as telnet, rlogin) and insecure file transfer methods (such as FTP).
As SSH access is not enabled by default, users may enable SSH on Web GUI (System > General Settings > General > Access Service). Please contact our technical support by submitting a ticket with circumstance information for root password.


  • AWS account
  • Root permission to UG6x or UG8x (UG6x is used in this article)
  • Specific greengrass firmware version of Milesight LoRaWAN gateway.( Burn it before leaving the factory)



  1. Create Group in AWS IoT
  2. UG6x Configuration
  3. "Hello World” with Greengrass
  4. Develop a Lambda Function with Embedded MQTT on Gateway
  5. Develop with UG6x PySDK

1. Create Group in AWS IoT

Log into AWS Console and find IoT service with your AWS account, go to Greengrass > Groups, create a group with a preferred name.

It is recommended to setup by easy configuration, and it will automatically name a core with the name of your group.

Ride along the instruction to create group and core until you are asked to download security resources and Greengrass Core software.

Click “download these resources as a tar.gz”, which can be named as hash-setup.tar.gz (for example, 4fee61fbfd-setup.tar.gz).

Then click below link to download the latest Greengrass Core software version for Armv8 (AArch64), distributed by Arch Linux:

Note: In this guide we use Milesight UG6x gateway to test, download version 1.11.0 of Greengrass core software.

2. UG6x Configuration

Below resources are required in this section:

  • greengrass-linux-aarch64-[Greengrass core software version].tar.gz
  • hash-setup.tar.gz
  • SSH Client (Putty / XShell) access to LoRaWAN gateway

To meet the third requirement above, please access to gateway web GUI, go to System > General Settings > General > Access Service, enable SSH Port. Then open terminal tool like PuTTY or Xshell to access Milesight gateway by SSH to ready. Contact Milesight technical support by submitting a ticket to get gateway root password.

Note: In this section, all commands in square are for gateway root permission and Linux system.

2.1. Copy .tar.gz to UG6x

Please use either way to copy greengrass-linux-aarch64-[Greengrass core software version].tar.gz and hash-setup.tar.gz into /mnt/mmcblk0p1:

(1)If you are using Linux, run these commands:

cd [path-to-downloaded-files]
pscp -pw [password to root] greengrass-linux-aarch64-[Greengrass core software version].tar.gz
root@IP- address:/mnt/mmcblk0p1
pscp -pw [password to root] [hash-setup.tar.gz]

(2)Otherwise please use a tool like WinSCP to drag relevant files into /mnt/mmcblk0p1 of gateway.

2.2. Decompress Resource Files

After logging into management tool of UG67/65, you can use any systems to operate the following Commands.

cd /mnt/mmcblk0p1
tar xzvf greengrass-linux-aarch64-[Greengrass core software version].tar.gz -C /mnt/mmcblk0p1
tar xzvf [hash-setup.tar.gz] -C /mnt/mmcblk0p1/greengrass

2.3. Download CA Root File

By using this command, we will download CA root file from Amazon to verify your Greengrass. Please make sure the UG67/65 has Internet access.

cd /mnt/mmcblk0p1/greengrass/certs/
curl -o

2.4. Modify Configuration File

The configuration file (hash-setup.tar.gz) is not written exactly for Milesight Gateway, so we need to modify it. Please enter the configuration file:

cd /mnt/mmcblk0p1/greengrass/config

Replace all “file:///greengrass/” with file:///mnt/mmcblk0p1/greengrass/ to modify certificates directory with “vim”.

vim config.json

2.5. Start Greengrass Core

/mnt/mmcblk0p1/greengrass/ggc/core/greengrassd start

Check if the core has already started, and see if the following script had been printed:

Set up greengrass daemon
Validate hardlink/softlink protection
Wait for up to 1m10s for Daemon to start
Greengrass is successfully started with PID: [PID]

If not, check if config.json has been modified correctly.

3. "Hello World" with Greengrass

This part shows you how to configure a Lambda function and deploy it on your AWS IoT Greengrass core device. It contains information about MQTT messaging, subscriptions, deployments on AWS IoT Greengrass and Lambda function configurations, as well as how to deploy a Lambda function on the AWS IoT Greengrass core that sends Hello World messages to the AWS IoT Greengrass cloud specifically. It may take about 30 min to finish this section.

3.1. Create and Package a Lambda Function

To run Lambda function in Python on an AWS IoT Greengrass core, AWS IoT Greengrass Core SDK for Python is required. You can download it with example python code from GitHub.


Decompress the file and find

Create a Lambda function deployment package named which contains and the greengrasssdk folder. Now you should be ready to create your Lambda function and upload the deployment package.

Open Lambda Console,, create a function choosing Author from Scratch and configure runtime as Python 3.7, and leave Permissions with default setting. This creates an execution role that grants basic Lambda permissions. You can manage roles in IAM console.



Different gateway greengrass firmware is compatible to different Python version.

UG8x: Firmware version 80.0.3000.43.1 (Python 2.7), 80.0.3000.59.1 (Python 3.7)

UG6x: Firmware version 60.0.3000.33 or above (Python 3.7)

On the configuration tab, under Function code, upload code file. (The size of your file might be different from the example here. For files larger than 10 MB, consider uploading using Amazon S3.)

After uploading, here is a file “hello_world_python_lambda” under File “UG_Test_Function”.

Move all subfiles of file hello_world_python_lambda to the root file “UG_Test_Function”,and delete empty file “hello_world_python_lambda”.

Then modify the default Handler name.


For Handler naming, AWS uses filename.handler method. For example, "main.handler" calls the handler method defined in, and in this the defined handler method is greengrassHelloWorld.function_handler.

Click Save and you will be ready to publish a version of function.

The system will create version ID automatically but users can modify the description anytime.

Now we proceed to create alias.

Note: Greengrass groups can reference a Lambda function by alias (recommended) or by version. Using an alias makes it easier to manage code updates because you do not have to change your subscription table or group definition when the function code is updated. Instead, you just reference the alias to the new function.

Name the alias to know the function as quick as you see it, set the version to 1 correspondent to the version that you just published, and then choose Create. In this guide we call the version as “HalloWelt”.

3.2. Configure the Lambda Function for AWS IoT Greengrass

In this step, you need to configure a subscription that allows the Lambda function to communicate with AWS IoT and configure local logging for the Greengrass group. So, go to AWS IoT and enter the group configuration page that you created in Step 1. Find Lambdas in the left and Add Lambda.

Choose “Use existing Lambda” and find the function name, alias configured in 3.1.

As we set in previous step, alias: HalloWelt is connected to version 1, so we can choose either one here. Click “finish” to add the function to group.

Click to choose the ellipsis (…), and then choose “Edit Configuration”.

On the Group-specific Lambda configuration page, set Timeout to 25 seconds to make this Lambda function asleep for 20 seconds before each invocation, set Lambda lifecycle to make this function long-lived and keep it running indefinitely. Keep the default values for all other fields, click “Update”.

Next, go back to group configuration and create a subscription that allows the Lambda to send MQTT messages to AWS IoT. On the left panel, you can find “Subscriptions” and choose “Add your first Subscription”.

A subscription is directed in the sense that messages flow in a specific direction from the source to the target. To allow a two-way communication, you must set up two subscriptions. For one subscription is enough, because the hello world Lambda function sends messages only to the hello/world topic in AWS IoT. You can find the topic defined as follows:

def greengrass_hello_world_run():
if not my_platform:
client.publish(topic='hello/world', payload='Hello world! Sent from Greengrass Core.')
client.publish(topic='hello/world', payload='Hello world! Sent from Greengrass Core running on platform:{}'.format(my_platform))
Timer(5, greengrass_hello_world_run).start()

Since messages flow from the source to the target, and it is Lambda function as content that publishes. Here we set the Lambda function as the source.

AWS IoT has MQTT client embedded in Test feature, and we will use it as the target of flow.

Click “Next” to type in ‘hello/world’ as topic, and Click “Finish”, we have set up a subscription.

One last thing is to disable the Stream manager. Scroll down and find Stream manager, choose Edit, Disable it and Save.

If you would like to see how everything is running on our gateway, then you should configure the group's logging settings so that AWS IoT Greengrass system components and Lambda functions would write logs on the file system of the core device. On the same settings configuration page, scroll down and find Local logs configuration, choose Edit.

On the Configure Group logging page, choose “Add another log type”.

For event source, please choose User Lambdas and Greengrass system, and then choose “Update”.

Keep the default values for logging level and disk space limit, and then choose “Save”.

3.3. Deploy Cloud Configurations to an AWS IoT Greengrass Core Device

In order to set up communication between AWS IoT Cloud and Milesight LoRaWAN Gateway, it is necessary to make sure that the gateway has internet access. Just ping “” on Web GUI to check (Maintenance > Tools > Ping).

Second, the gateway needs AWS IoT Greengrass daemon to run. To check this please enter:

ps w | grep -E 'greengrass.*daemon'

If the output contains a root entry for /mnt/mmcblk0p1/greengrass/ggc/packages/[Greengrass Core Software version]/bin/daemon, then the daemon is running. Output showing as follows means that the daemon has not yet started running.

In this guide we use version 1.11.0 of Greengrass core software. To start the daemon:

cd /mnt/mmcblk0p1/greengrass/ggc/core/
./greengrassd start

Now you are ready to deploy the Lambda function and subscription configurations to your AWS IoT Greengrass core device.

Next, go back to AWS IoT Console and enter the group configuration page, find Actions and choose Deploy.

Choose Automatic detection. This enables devices to automatically acquire connectivity information for the core, such as IP address, DNS, and port number. It is recommended, but AWS IoT Greengrass also supports manually specified endpoints. You will only be prompted for the discovery method the first time the group is deployed.

The first deployment might take a few minutes. When the deployment is complete, you should see “Successfully completed in the Status” message on the page:

3.4. Verify Whether the Lambda Function Is Running on the Device

Go back to AWS IoT home.

Choose “Subscribe to a topic” in blue, and configure “Subscription topic” as hello/world (remember do not click on “Subscribe to topic” button yet.), Quality of Service, MQTT payload display as below.

Take some time to wait for Greengrass core running on UG65/67 to say hello world to AWS IoT.

4.  Develop a Lambda Function with Embedded MQTT on Milesight LoRaWAN Gateway

4.1. Replace Python Code

Here’s a python program to make Lambda function subscribe to LoRa Remote I/O (UC11xx) and publish it to LoRaWAN Gateway (UG6x).

import json
import time

import paho.mqtt.client as mqtt

client_id="[UG6x SN]"
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))

def on_message(client, userdata, msg):
print("Receive topic:"+msg.topic+" message: "+str(msg.payload.decode('utf-8')))

def on_subscribe(client, userdata, mid, granted_qos):
print("On Subscribed: qos = %d" % granted_qos)

def on_disconnect(client, userdata, rc):
if rc != 0: print("Unexpected disconnection %s" % rc)

client = mqtt.Client(client_id)
client.username_pw_set("[MQTT server username]", "[MQTT server password]")
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe
client.on_disconnect = on_disconnect
client.connect(HOST, PORT, 60)

# update timestamp to device (2019-10-31 16:56:18)

data = {

param = json.dumps(data)
client.publish("application/[application ID]/device/[UC11xx SN]/tx", payload=param, qos=0)

def function_handler(event, context):

Replace [UG6x SN] with your gateway’s serial number and [UC11xx SN] with UC11xx’s serial number and save as or replace the content of

Create a .zip file containing and greengrasssdk.

In Lambda Console, enter the Lambda function created in step 3.1, choose Upload a .zip file to upload the and name handler according to handler naming rule.

Publish a new version and create a different alias for it.

Now we have Lambda function version 2 ready.

4.2. AWS IoT Configuration

Find Subscriptions in the group on AWS IoT, choose “Delete subscription”. Then go to Lambdas, in Group-specific Lambda configuration, remove “HalloWelt” and confirm, find “Add another version”. Choose either Alias: MQTT or Version 2 and click “Save”.

Set Timeout to 25 seconds and Lambda lifecycle to make this function long-lived and keep it running indefinitely as version 1. Keep the default values for all other fields, click “Update”.

See if the Lambdas is using MQTT versions; if so, choose Deploy, and wait for it to succeed.

4.3. Enable Log of Lambda Function on Milesight LoRaWAN Gateway (UG6x)

Open a terminal tool and type in the command as below to see how the function is running:

tail -f /mnt/mmcblk0p1/greengrass/ggc/var/log/user/[region]/[user_account_ID]/[UG_Function].log

NOTE: [region] / [user_account_ID] / [UG_Function] should be different in your case, please check before type in.

If you see fatal error concerning unexpected indent, please go to Lambda console and try to convert to spaces/tabs to debug.

If everything runs well you should see something like this:

[2019-11-11T17:53:51.897+08:00][INFO],Connected with result code 0
[2019-11-11T17:53:51.908+08:00][INFO],On Subscribed: qos = 0
[2019-11-11T17:53:51.915+08:00][INFO],On Subscribed: qos = 0
[2019-11-11T17:53:51.923+08:00][INFO],On Subscribed: qos = 0
[2019-11-11T17:53:51.93+08:00][INFO],On Subscribed: qos = 0

With UC11xx added in the network server of UG6x and joined network, we can see the log printed with both UC11xx and UG6x data from

5. Develop with UG6x PySDK

In previous example we leave Lambda function configuration in container mode as default, in which host resource is isolated and forbidden to invoke system commands. But in this case, Milesight python_sdk relies on system resource so we need to alter the configuration.

Find Containerization and choose No container (always).

Scroll down to “Environment variables” and configure as below, and then choose “Update”.

If you wish to include cellular status in each MQTT packet, please add these sentences in the function code.

import URRouterInfo

print status

To run altered program, you will need to publish another version and another alias (according to your need), choose the new version as Lambda function and deploy the group again to put into effect.


Thanks for reading. For authentic guide from AWS please refer to AWS IoT Greengrass Developer Guide and AWS Lambda Developer Guide.