sigfox-gcloud
v2.1.1
Published
Framework for building a Sigfox server, based on Google Cloud Functions
Downloads
68
Maintainers
Readme
sigfox-gcloud is a software framework for building a Sigfox server with Google Cloud Functions and Google Cloud PubSub message queues:
Modular: Process Sigfox messages in modular steps using simple Node.js (JavaScript) functions.
Extensible: Allows new Sigfox message processing modules to be added on the fly without disrupting or restarting all modules.
Robust: The processing modules are implemented as separate Google Cloud Functions, so one module crashing will not affect others. Google Cloud PubSub message queues are used to pass the Sigfox messages reliably between processing modules.
Read about the architecture here: How To Build Your Sigfox Server
Other sigfox-cloud
modules available:
sigfox-gcloud-ubidots
: Adapter for integrating Sigfox devices with the easy and friendly Ubidots IoT platformsigfox-gcloud-data
: Adapter for writing Sigfox messages into SQL databases like MySQL, Postgres, MSSQL, MariaDB and Oracle
Releases
- Version 1.0.0 (11 Oct 2017): Supports Google Cloud Trace for tracing the Sigfox Callback processing time across Cloud Functions. Supports Google Cloud Debug for capturing Node.js memory snapshots. Supports Ubidots map visualisation of Sigfox Geolocation and other geolocated sensor data points.
Getting Started
For development we support Linux, MacOS and Ubuntu on Windows 10.
Open a command prompt and enter these commands to download the sigfox-cloud
source folder to your computer.
git clone https://github.com/UnaBiz/sigfox-gcloud.git
cd sigfox-gcloud
If you're using Ubuntu on Windows 10, we recommend that you launch "Bash on Ubuntu on Windows" and enter the following
commands to download the source files into the folder /mnt/c/sigfox-gcloud
:
cd /mnt/c
git clone https://github.com/UnaBiz/sigfox-gcloud.git
cd sigfox-gcloud
That's because /mnt/c/sigfox-gcloud
under bash
is a shortcut to c:\sigfox-gcloud
under Windows.
So you could use Windows Explorer and other Windows tools to browse and edit files in the folder.
Remember to use a text editor like Visual Studio Code that can save files using
the Linux line-ending convention (linefeed only: \n
),
instead of the Windows convention (carriage return + linefeed: \r \n
).
Setting up Google Cloud
Create a Google Cloud Platform project. Assume the project ID is
myproject
.Open a bash command prompt. For Windows, open "Bash on Ubuntu on Windows."
Create a file named.env
in thesigfox-gcloud
folder
and populate theGCLOUD_PROJECT
variable with your project ID. To do that, you may use this command (changemyproject
to your project ID):echo GCLOUD_PROJECT=myproject >.env
Enable billing for your project.
Click this special link to enable the Cloud Functions, Cloud Pub/Sub, Compute Engine, Stackdriver Logging APIs for your project.
For Linux and MacOS, click this link to install and initialize the Google Cloud SDK.
For Ubuntu on Windows 10, open "Bash on Ubuntu on Windows" and follow the Ubuntu installation steps here:
https://cloud.google.com/sdk/downloads#apt-get
Update and install
gcloud
components:gcloud components update gcloud components install beta
Switch to the project you have created: (change
myproject
to your project ID)gcloud config set project myproject gcloud config list project
Your project ID should be displayed after
list project
.Add the following
sigfox-route
setting to the Google Cloud Project Metadata store. This route says that all received Sigfox messages will be processed by the two stepsdecodeStructuredMessage
andlogToGoogleSheets
.gcloud compute project-info add-metadata --metadata=^:^sigfox-route=decodeStructuredMessage,logToGoogleSheets
Create the Google PubSub message queues that we will use to route the Sigfox messages between the Cloud Functions:
gcloud beta pubsub topics create sigfox.devices.all gcloud beta pubsub topics create sigfox.types.decodeStructuredMessage gcloud beta pubsub topics create sigfox.types.logToGoogleSheets
Optional: We may create the PubSub message queues for each device ID and device type that we wish to support. For example, to support device ID
1A234
and device typegps
, we would execute:# Optional... gcloud beta pubsub topics create sigfox.devices.1A234 gcloud beta pubsub topics create sigfox.types.gps
The PubSub queues will be used as follows:
sigfox.devices.all
: The queue that will receive Sigfox messages for all devicessigfox.devices.<deviceID>
: The queue that will receive Sigfox messages for a specific device e.g.sigfox.devices.1A234
. Device ID must be in uppercase.sigfox.types.<deviceType>
: The queue that will receive Sigfox messages for a specific device type or a message processing step e.g.sigfox.types.gps
sigfox.types.decodeStructuredMessage
,sigfox.types.logToGoogleSheets
: used for sending messages to be decoded and logged in the Sigfox message processing demo below
If you plan to run the Google Sheets demo below:
Go to the Google Cloud IAM to create a Google Cloud Service Account. Download the JSON credentials into
google-credentials.json
in thesigfox-gcloud
folder.Go to the Google Cloud IAM and ensure the Google Cloud Service Account in
google-credentials.json
has been grantedEditor
rights to your Google Cloud Project
Create a Google Cloud Storage bucket
gs://<projectid>-sigfox-gcloud
to stage our Cloud Functions files during deployment, like this: (changemyproject
to your project ID)gsutil mb gs://myproject-sigfox-gcloud
Deploy all the included Cloud Functions (including the demo functions) with the
deployall.sh
script:chmod +x */*.sh scripts/deployall.sh
Go to the Google Cloud Functions Console
There should 4 Cloud Functions defined Click the
sigfoxCallback
Cloud FunctionClick the
Trigger
tab Copy the URL forsigfoxCallback
The URL should look like:https://us-central1-myproject.cloudfunctions.net/sigfoxCallback
This is the HTTPS URL that will invoke the
sigfoxCallback
Cloud Function. We shall set this as the Sigfox callback URL later.
Setting the Sigfox callback
As a Sigfox device maker you should have access to the Sigfox Backend Portal. We shall use the portal to configure the callback URL for your device.
If you're not a Sigfox device maker yet, you may purchase the UnaShield Sigfox Shield for Arduino to get access to the Sigfox Backend.
https://github.com/UnaBiz/unabiz-arduino/wiki/UnaShield
Log on to the Sigfox Backend Portal Click "Device Type" Click the Device Type that you wish to connect to Google Cloud
Click "Callbacks"
Click "New"
When prompted to select the callback type, select Custom Callback
Fill in the callback details as follows:
Type:
DATA, BIDIR
Channel:
URL
Send duplicate: Unchecked (No)
Custom payload config: (Blank)
URL Pattern: Enter the Sigfox Callback URL that we have copied earlier. It should look like:
https://us-central1-myproject.cloudfunctions.net/sigfoxCallback
Use HTTP Method:
POST
Send SNI: Checked (Yes)
Headers: (Blank)
Content Type:
application/json
Set the Body (Sigfox message payload) as:
{ "device" : "{device}", "data" : "{data}", "time" : "{time}", "duplicate": "{duplicate}", "snr": "{snr}", "station": "{station}", "avgSnr": "{avgSnr}", "lat": "{lat}", "lng": "{lng}", "rssi": "{rssi}", "seqNumber": "{seqNumber}", "ack": "{ack}", "longPolling": "{longPolling}" }
With this setting, the Sigfox cloud will deliver messages to our server in JSON format like this:
{ "device":"1A2345", "data":"920e82002731b01db0512201", "time":"1476980426", "duplicate":"false", "snr":"18.86", "station":"1234", "avgSnr":"15.54", "lat":"1", "lng":"104", "rssi":"-123.00", "seqNumber":"1492", "ack":"false", "longPolling":"false" }
Optional: We may set the callback type in the
sigfoxCallback
URL by passing thetype
parameter in the URL like this:https://us-central1-myproject.cloudfunctions.net/sigfoxCallback?type=gps
It's OK to omit the
type
parameter, we may also use routing rules to define the processing steps.
Optional: Configuring Sigfox downlink
Optional: The sigfox-gcloud
server can be used to return downlink data to the Sigfox device after processing a callback from the Sigfox cloud.
If we plan to use the downlink capability, there are two additional things to configure:
In the Device Type settings, set the Downlink Mode to Callback
In the Callbacks list under Device Type, there is a hollow circle in the Downlink column.
Click the circle and change it to a filled purple circleThe message handling code in
sigfoxCallback
is presently hardcoded to return0123456789abcdef
. This may be changed if necessary.https://github.com/UnaBiz/sigfox-gcloud/blob/master/sigfoxCallback/index.js
function getResponse(req, device0, body /* , msg */) { // Compose the callback response to Sigfox Cloud and return as a promise. // If body.ack is true, then we must wait for the result and return to Sigfox as the downlink data. // Else tell Sigfox we will not be returning any downlink data. ... // Wait for the result. Must be 8 bytes hex. // TODO: We hardcode the result for now. const result = '0123456789abcdef';
To write a program for the UnaShield Sigfox Shield to send a downlink request, refer to https://github.com/UnaBiz/unabiz-arduino/wiki/Downlink
Optional: Defining the Sigfox message processing steps
We define the Sigfox message processing steps as a route in the Google Cloud Common Instance Metadata Store. This metadata store is a key-value store that's shared by all programs running in the same Google Cloud project.
You may inspect and update the route through the Google Cloud Compute Engine Metadata Editor. Look for the key named
sigfox-route
.A route looks like
decodeStructuredMessage, logToGoogleSheets, ...
in which
decodeStructuredMessage
andlogToGoogleSheets
are the Google Cloud Functions to be called sequentially. These Cloud Functions will subscribe to the following Google PubSub queues to listen for Sigfox messages:sigfox.types.decodeStructuredMessage sigfox.types.logToGoogleSheets
Here is an example of a route for Sigfox message processing, as shown in the demo.
Sigfox Cloud
→
sigfoxCallback
cloud function to ingest messages from Sigfox Cloud→
sigfox.devices.all
message queue→
routeMessage
cloud function to route the message→
sigfox.types.decodeStructuredMessage
message queue→
decodeStructuredMessage
cloud function to decode the structured sensor data in the message→
sigfox.types.logToGoogleSheets
message queue→
logToGoogleSheets
cloud function to write the decoded message to Google SheetsHow it works:
Sigfox messages are pushed by the Sigfox Cloud to the Google Cloud Function
sigfoxCallback
Cloud Function
sigfoxCallback
delivers the message to PubSub message queuesigfox.devices.all
, as well as to the device ID and device type queuesCloud Function
routeMessage
listens to PubSub message queuesigfox.devices.all
and picks up the new messageCloud Function
routeMessage
assigns a route to the Sigfox message by reading thesigfox-route
from the Google Compute Metadata Store. The route looks like this:decodeStructuredMessage, logToGoogleSheets
This route sends the message to functions
decodeStructuredMessage
andlogToGoogleSheets
via the queuessigfox.types.decodeStructuredMessage
andsigfox.types.logToGoogleSheets
See this for the definition of structured messages:
https://github.com/UnaBiz/unabiz-arduino/wiki/UnaShield
Also read about the architecture here: How To Build Your Sigfox Server
Viewing sigfox-gcloud
server logs
You may view the logs through the
Google Cloud Logging Console
Select "Cloud Function" as the "Resource"
From the screen above you can see the logs generated as each Sigfox message is processed in stages by sigfox-gcloud
:
Sigfox Device IDs are shown in square brackets e.g.
[ 2C30EB ]
Completed Steps are denoted by
_<<_
sigfoxCallback
is the Google Cloud Function that listens for incoming HTTPS messages delivered by SigfoxrouteMessage
passes the Sigfox message to various Google Cloud Functions to decode and process the messagedecodeStructuredMessage
decodes a compressed Sigfox message that contains multiple field names and field valuessendToUbidots
is a Google Cloud Function that sends the decoded sensor data to Ubidots via the Ubidots API. Seesigfox-gcloud-ubidots
Tracing sigfox-gcloud
server performance
The Google Cloud Trace Console shows you the time taken by each step of the Sigfox message processing pipeline, tracing the message through every Google Cloud Function.
Each message delivered by Sigfox appears as a separate trace timeline. Messages are shown like 2C30EB seq:1913
where 2C30EB
is the Sigfox Device ID and 1913
is the Sigfox Message Sequence Number (seqNumber)
The Google Stackdriver Trace API needs to be enabled manually.
Custom reports may be created in Google Cloud Trace Control to benchmark the performance of each processing step over time.
Understanding and troubleshooting the sigfox-gcloud
server
To understand each processing step in the sigfox-gcloud
server, you may use the
Google Cloud Debug Console
to set breakpoints and capture in-memory variable values for each Google Cloud Function, without stopping or reconfiguring the server.
In the example below, we have set a breakpoint in the sigfoxCallback
Google Cloud Function. The captured in-memory
values are displayed at right - you can see the Sigfox message that was received by the callback.
The Callback Stack appears at the lower right.
Google Cloud Debug is also useful for troubleshooting your custom message processing code without having to insert the debugging code yourself.
Testing the sigfox-gcloud
server
Send some Sigfox messages from the Sigfox devices. Monitor the progress of the processing through the Google Cloud Logging Console.
Select "Cloud Function" as the "Resource"Processing errors will be reported to the Google Cloud Error Reporting Console.
The Google Cloud PubSub Console shows the message queues that have been created and how many Cloud Functions are listening to each queue.
We may configure Google Cloud Stackdriver Monitoring to create incident reports upon detecting any errors. Stackdriver may also be used to generate dashboards for monitoring the PubSub message processing queues.
To check whether the downlink was sent successfully from the server to the device, check the Sigfox Backend. Go to the Device page, click Messages and click the down-arrow circle in the Callbacks column. It should show status "Acked"
If the status is "Pending", the Sigfox network is still attempting to push the downlink message to the device.
Demo
The sample code calls the
decodeStructuredMessage
Cloud Function to decode a structured Sigfox message containing encoded sensor data (counter, light level, temperature). Then it calls thelogToGoogleSheets
Cloud Function to display the decoded Sigfox messages in a Google Sheets spreadsheet in real time.See this for the definition of structured messages:
https://github.com/UnaBiz/unabiz-arduino/wiki/UnaShield
Ensure that the Google Service Account in
google-credentials.json
has been granted these permission scopes for Sheets API, Drive API:https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive
Create a folder in Google Drive and grant write access to the email address specified in
google-credentials.json
.In that folder, create a Google Sheets spreadsheet with the device ID (in uppercase) as the filename, e.g.
1A2345
. Omit any file extensions like.xls
In the spreadsheet, rename the first tab / worksheet as
Log
.Populate the first row with these column headers, one name per column:
timestamp+8 data ctr lig tmp seqNumberCheck rssi duplicate snr station avgSnr lat lng ack longPolling time seqNumber type device
Change
timestamp+8
to indicate your time zone, e.g. for UTC+10 change it totimestamp+10
Refer to the sample Google Sheet here:
https://docs.google.com/spreadsheets/d/1OtlfVx6kibMxnZoSwq76Vod8HhaK5tzBIBAewtZlbXM/edit?usp=sharing
To test the structured message decoding, send a Sigfox message from your Sigfox device with the
data
field set to:920e82002731b01db0512201
We may also use a URL testing tool like Postman to send a POST request to the
sigfoxCallback
URL e.g.https://us-central1-myproject.cloudfunctions.net/sigfoxCallback
Set the
Content-Type
header toapplication/json
. If you're using Postman, clickBody
->Raw
->JSON (application/json)
Set the body to:{ "device":"1A2345", "data":"920e82002731b01db0512201", "time":"1476980426", "duplicate":"false", "snr":"18.86", "station":"0000", "avgSnr":"15.54", "lat":"1", "lng":"104", "rssi":"-123.00", "seqNumber":"1492", "ack":"false", "longPolling":"false" }
where
device
is your device ID.Here's the request in Postman:
We may use the
curl
command as well. Remember to changemyproject
and1A2345
to your project ID and device ID.curl --request POST \ --url https://us-central1-myproject.cloudfunctions.net/sigfoxCallback \ --header 'cache-control: no-cache' \ --header 'content-type: application/json' \ --data '{"device":"1A2345", "data":"920e82002731b01db0512201", "time":"1476980426", "duplicate":"false", "snr":"18.86", "station":"0000", "avgSnr":"15.54", "lat":"1", "lng":"104", "rssi":"-123.00", "seqNumber":"1492", "ack":"false", "longPolling":"false"}'
The response from the callback function should look like this:
{ "1A2345": { "noData": true } }
The test message sent above will be decoded and displayed in the Google Sheet as
ctr (counter): 13 lig (light level): 760 tmp (temperature): 29
Creating a Sigfox message processing module
Create a Google Cloud Function, using
decodeStructuredMessage
as a template:mkdir myfunction cp decodeStructuredMessage/index.js myfunction cp decodeStructuredMessage/package.json myfunction cp decodeStructuredMessage/deploy.sh myfunction cd myfunction
Install
sigfox-gcloud
library:npm install --save sigfox-gcloud
Edit the Cloud Function deployment script
deploy.sh
. Edit thename
parameter and replace the value by the name of your message processing function, e.g.myfunction
.Any message delivered to the queue
sigfox.types.myfunction
will trigger the message processing function.name=myfunction trigger=--trigger-topic topic=sigfox.types.${name}
Create the listen queue in Google PubSub Console, e.g.
sigfox.types.myfunction
Or run this command (change
myfunction
to the function name):gcloud beta pubsub topics create sigfox.types.myfunction
Edit the message processing code in
index.js
.
Every message processing function has 3 sections:if (process.env.FUNCTION_NAME) { require('@google-cloud/trace-agent').start(); require('@google-cloud/debug-agent').start(); } const sgcloud = require('sigfox-gcloud');
The standard declarations here initialise the
sigfox-gcloud
library, Google Cloud Trace and Google Cloud Debug functions. Retain this section without changes.Replace this section with our JavaScript message processing code. We need to expose a function named
task()
that will perform the processing for a Sigfox message that has been delivered.function task(req, device, body, msg)
req
contains info about the message that triggered the taskdevice
is the Sigfox device IDbody
is the body of the Sigfox message, which contains fields like:{ "device":"1A2345", "data":"920e82002731b01db0512201", "time":"1476980426", "duplicate":"false", "snr":"18.86", "station":"0000", "avgSnr":"15.54", "lat":"1", "lng":"104", "rssi":"-123.00", "seqNumber":"1492", "ack":"false", "longPolling":"false" }
msg
contains the complete message delivered by Google Cloud PubSub. This includes thedevice
,body
,history
androute
fields.task()
should return a promise for the updated message after processing the message.To write debug messages to the Google Cloud Logging Console, call
sgcloud.log(req, action, parameters)
like this:sgcloud.log(req, 'decodeMessage', { result, body });
To report errors to the Google Cloud Error Reporting Console, call
sgcloud.log(req, action, parameters)
, whereparameters
includes anerror
field containing the JavaScript error.sgcloud.log(req, 'decodeMessage', { error, body });
exports.main = event => sgcloud.main(event, task);
The
main()
function that will be called upon receiving a message shall always be defined as above. This calls themain()
function in thesigfox-gcloud
library which performs the following:Decode the message received from Google Cloud PubSub (base64 format)
Execute the
task()
function above to process the messageRecord the history of
task()
functions calledDispatch the resulting message to the next step (if any) of the message route contained in the message. The message route was set previously by the
routeMessage
cloud function.
Deploy the module. This creates/updates the Google Cloud Function and listens to the PubSub queue for new messages to be processed by the function.
./deploy.sh
Update the Sigfox message processing route
sigfox-route
in Google Cloud Compute Engine Metadata Editor. Add the new processing step to the list of steps:decodeStructuredMessage, logToGoogleSheets
The new route will take effect in 10 seconds when the route cache is refreshed.
To test, send a Sigfox message from your Sigfox device.
sigfox-gcloud-ubidots
adapter for Ubidots
The sigfox-gcloud-ubidots
adapter is a Google Cloud Function
(developed with the sigfox-gcloud
framework) that integrates with Ubidots to provide a comprehensive IoT
platform for Sigfox.
With Ubidots and sigfox-gcloud-ubidots
, you may easily visualise sensor data from your Sigfox devices and monitor
for alerts. To perform custom processing of your Sigfox device messages before passing to Ubidots,
you may write a Google Cloud Function with the sigfox-gcloud
framework.
sigfox-gcloud-ubidots
also lets you to visualise in real-time the Sigfox Geolocation data from your Sigfox devices,
or other kinds of GPS tracking data. For details, check out:
https://www.npmjs.com/package/sigfox-gcloud-ubidots
https://unabiz.github.io/unashield/ubidots
sigfox-gcloud-data
adapter for databases
The sigfox-gcloud-data
adapter is a Google Cloud Function
(developed with the sigfox-gcloud
framework) that writes decoded Sigfox messages into many types of SQL databases
including MySQL, Postgres, MSSQL, MariaDB and Oracle. For details, check out: