This post is to explore a way to send an SMS to a device with a Soracom SIM on its first connection, using an execute web request or Lambda invocation from the Event Handler service. Soracom Event Handler is a service that provides an automated response to rules set by the operator. We will use a rule to detect when a SIM card is sending its first data and to trigger an event which is to send back specific configuration settings and information to the device, which is being provisioned over SMS.
The reason for this work-around feature is for when a customer needs to send the APN and configuration information to the device once it becomes active. Specifically, a customer is wanting to send AT$GPRS=APF427,1,“soracom.io”,“sora”,“sora”
The Cloud components that will be used in this work-around functionality are:
- Event Handler has the ability to detect the first connection of a SIM and to then either execute a web request or to invoke a service, such as Lambda.
- AWS Lambda which will run the appropriate code to log into the Soracom API and send the parameter from Event Handler (which is provisioning information)
-
Soracom API which will receive the command to send an SMS to the device with a SIM.
STEPS
Configuring Event Handler.
Here I configured the Event Handler for using a Lambda invocation. It requires AWS IAM Access Key and secret which is
configured in the credentials store of the Soracom console.
For Event Handler you will also have to
configure a parameter and value
to send to the Lambda.
Link to the available Variables for Event Handler parameters.
Generate the API Key and Token
You’ll want to create a SAM user that has the right permission for the Soracom API you want to execute, then generate a set of AuthKeys for that SAM user. Then in the Lambda you need to set AUTH_KEY and AUTH_KEY_ID environment variables accordingly. We’ll call the API using our Soracom AUTH_KEY and AUTH_KEY_ID for authentication: Here is a link on how to configure the credential store for accessing the Soracom API.
The auth_keys can also be generated in console
Option 1
If your Event Handler action is to Invoke AWS Lambda, you’ll also need to set up an AWS IAM user with permission to execute Lambda, and then a set of AWS IAM Access Key and Secret, which will be registered to the Event Handler action.
Option 2
You can alternatively use the new AWS Lambda Function URL option to invoke the Lambda via HTTPS call (using Event Handler Webhook action instead), but you have to implement your own authentication to prevent unauthorized parties from arbitrarily executing your function URL.
Link to set up a webhook into Lambda
Notes:
In the production code, you should to avoid passing credentials (i.e. AUTH_KEY and AUTH_KEY_ID) through the environment variables as plain text. We recommend using AWS Secrets Manager instead.
Additionally, here are a couple things you might want to keep in mind whether or not you want to include this in your test.
Users currently do not have any way to know if their SMS was not delivered (such as if the device was offline). If you set up Harvest in Soracom, you can see if the SMS was delivered if your device sends a SMS response back.
The purpose of sending the SMS is to send an APN configuration command to a device, then at a high level this the expected behavior:
- Before sending SMS: No APN is set, so the device can’t create a session, but when it attaches to a network the status changes from Ready to Active, which is what we use to trigger the SMS.
- After sending SMS: The APN is set, so the device should be able to create a session.
There is an alternative way to check the SMS delivery status according to whether or not the device eventually successfully creates a data session (implying the SMS delivery was successful). Basically, instead of checking the delivery status of the SMS (which is a function we do not offer today), you would use the Event Handler Session Status rule (however this is currently only available as private beta, so it’s not enabled for all customers by default).
The Lambda would double in complexity, but this is the general idea:
Using a Lambda, when a SIM status changes from Ready to Active (using Event Handler SIM Status rule), send the SMS and move the SIM to Group 1
- Using another Lambda, when a SIM session status changes from offline to online (using Event Handler SIM Session Status rule), move the SIM to Group 2 (or remove it from Group 1)
- Any SIMs that successfully receive the SMS and create a session will move into and out of Group 1, while SIMs that were sent an SMS but never came online (maybe because the device was offline and never received the SMS) would be stuck in Group 1, which makes it easier to identify which devices need to be fixed.
JavaScript Code for Lambda to log into the Soracom API and send an SMS based on the parameter sent from Event Handler.
/**
* Environment variables:
*
* AUTH_KEY Soracom API auth key
* AUTH_KEY_ID Soracom API auth key ID
*
* Parameters from Event Handler:
* parameter1 SMS message to send to device
*/
const https = require('https')
const soracom = ({
path,
method = 'POST',
headers = { 'Content-Type': 'application/json' },
body = null,
success = 200
}) => {
return new Promise((resolve, reject) => {
const req = https.request({
hostname: 'g.api.soracom.io',
port: 443,
path: `/v1${path}`,
method,
headers
}, (res) => {
if (res.statusCode !== success) reject(`Soracom API ${path} ${res.statusCode} error`)
res.on('data', (data) => { resolve(JSON.parse(data)) })
})
req.on('error', (error) => { reject(error.message) })
if (body !== null) req.write(JSON.stringify(body))
req.end()
})
}
exports.handler = async (event) => {
try {
// auth
const { apiKey, token } = await soracom({
path: '/auth',
body: { authKey: process.env.AUTH_KEY, authKeyId: process.env.AUTH_KEY_ID }
})
const headers = {
'X-Soracom-API-Key': apiKey,
'X-Soracom-Token': token,
'Content-Type': 'application/json'
}
// sendSms
await soracom({
path: `/subscribers/${event.imsi}/send_sms`,
headers,
body: { payload: event.parameter1, encodingType: 1 },
success: 202
})
return `send-SMS for ${event.imsi} completed successfully`
} catch (error) {
return `send-SMS for ${event.imsi} failed with error: ${error}`
}
}