Using Twilio Sync with MQTT on an ESP32

In this quickstart, we'll combine the lightweight messaging protocol MQTT with Twilio Sync for IoT, the Arduino IDE, and Espressif's powerful ESP32. We'll walk through the Twilio Device Manager to create a Device Fleet then detail the ESP32 to Sync connection. Last but not least... we'll light up an LED! Let's make some magic and some photons!

Sync for IoT is currently in Developer Preview, which means access is by invite only. If you'd like to try what you see in these docs, sign up for the developer preview and the team at Twilio will get you onboarded as soon as possible.

Sign Into - or Sign Up For - a Twilio Account

Either create a new Twilio account (you can sign up for a free Twilio trial), or sign into an existing Twilio account.

Once you are logged in, click this Device Manager link to go to the Sync for IoT console.

Deploy a Fleet of ESP32 Things

A Device Fleet is a collection of devices, keys, certificates, and configurations inside of Sync.  While you can have multiple fleets, every individual fleet is isolated.  That's perfect for the common use case where you want to keep your thing collections from accidentally interacting.

A default Fleet is already provisioned for you automatically, navigate to it in the Device Management console.

Locating the default Ffleet in the Twilio Console

Note it is also easy to deploy a fleet through the REST API.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);

client.preview.deployed_devices.fleets
  .create({
    friendlyName: 'My Fleet of Devices',
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices;

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        var fleet = FleetResource.Create(
            friendlyName: "My Fleet of Devices"
        );

        Console.WriteLine(fleet.Sid);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($accountSid, $authToken);

$fleet = $client->preview->deployedDevices->fleets->create(
  array(
    'friendlyName' => 'My Fleet of Devices'
  )
);

echo $fleet->sid;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

fleet = client.preview.deployed_devices.fleets.create(
  friendly_name: 'My Fleet of Devices'
)

puts fleet.sid
# Get the Python helper library from https://twilio.com/docs/libraries/python
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet = client.preview.deployed_devices.fleets.create(
    friendly_name='My Fleet of Devices')

print(fleet.sid)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.rest.preview.deployedDevices.Fleet;
import com.twilio.rest.preview.deployedDevices.FleetCreator;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        FleetCreator fleetCreator = new FleetCreator();
        Fleet fleet = fleetCreator
                .setFriendlyName("My Fleet of Devices")
                .create();

        System.out.println(fleet.getSid());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets
{
  "sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": null,
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "default_deployment_sid": "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-08-14T15:25:45Z",
  "date_updated": "2017-08-14T15:25:45Z",
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "links": {
    "certificates": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Certificates",
    "keys": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Keys",
    "devices": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Devices",
    "deployments": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Deployments"
  }
}
Using the API to create a Device Fleet in Sync for IoT.
Create a Device Fleet

Using the API to create a Device Fleet in Sync for IoT.

Fleet created, now it's time to work on the deployment.

Configure the Default Fleet's Deployment

Twilio will automatically configure a default Deployment once the Fleet is created.  The 'Default Deployment' field in your Fleet will be populated similar to the following screenshot:

A default deployment is automatically provisioned for each new Device Fleet.

Click the link labeled 'Configure the Deployment':

Every deployment is configured with a default Service Instance.

Twilio also has automatically created a new Sync Service Instance as you can see above.  An instance is similar to a database; the updates you make on Sync primitives (such as the Document we use today) are stored only in this one Sync instance.

As before, you can also create a Deployment through the API.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);
const fleet = client.preview.deployed_devices.fleets(
  'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
);

fleet
  .deployments('FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({
    friendlyName: 'My New Device Deployment',
    syncServiceSid: 'ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices;

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        const string deploymentSid = "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var deployment = DeploymentResource.Update(
            deploymentSid,
            friendlyName: "My New Device Deployment");

        Console.WriteLine(deploymentSid.FriendlyName);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($accountSid, $authToken);

$deploymentSid = 'DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$deployment = $client->preview->deployedDevices->deployments($deploymentSid)->update(
  array(
    'friendlyName' => 'My New Device Deployment'
  )
);

echo $deployment->friendlyName;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

deployment_sid = 'DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
deployment = client.preview.deployed_devices
                   .deployments(deployment_sid)
                   .update(friendly_name: 'My New Device Deployment')

puts deployment.friendly_name
# Get the Python helper library from https://twilio.com/docs/libraries/python
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
deployment_sid = 'DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
deployment = client.preview\
                   .deployed_devices\
                   .fleets(fleet_sid)\
                   .deployments(sid=deployment_sid)\
                   .update(friendly_name='My New Device Deployment')

print(deployment.friendly_name)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.rest.preview.deployedDevices.Deployment;
import com.twilio.rest.preview.deployedDevices.DeploymentUpdater;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        String deploymentSid = "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        Deployment deployment = new DeploymentUpdater(deploymentSid)
                .setFriendlyName("My New Device Deployment")
                .update();

        System.out.println(deployment.getFriendlyName());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Deployments/DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
  -d 'FriendlyName=My New Device Deployment' \
  -d 'SyncServiceSid=ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
{
  "sid": "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": "My New Device Deployment",
  "fleet_sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "sync_service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-08-14T15:44:05Z",
  "date_updated": "2017-08-14T15:55:25Z",
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Deployments/DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
Update a Device Deployment

Once you've got a handle on the Deployment (and a pointer to the instance), you're ready to create a Device Certificate for authentication.

Create an ESP32 Device and a Device Certificate

A Device refers to a particular piece of hardware and is (appropriately enough) managed through the Device Manager.  When an IoT device connects to Sync, Twilio will identify the device based upon the credentials you supply, either through a key or certificate.  Our ESP32 has the resources to handle a certificate - and we encourage you to use certificate credentialing whenever possible. (See the ESP8266 Sync for IoT guide for an example of device key authentication to Sync).

Now, inside your Fleet, click the 'Devices' link on the left. Enter a clever or memorable Friendly and Unique name - probably something ESP32 related - then hit the 'Create' button.

Creating a Device in the Twilio Console

As seen here, you can also create a Device through the API.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
// Get the Node helper library from https://twilio.com/docs/libraries/node
const fs = require('fs');
const Twilio = require('twilio').Twilio;

// Get your Account SID and Auth Token from https://twilio.com/console
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = new Twilio(accountSid, authToken);

const fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const fleetService = client.preview.deployed_devices.fleets(fleetSid);

fleetService.devices
  .create({
    friendlyName: 'My Device #1',
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices.Fleet

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        var device = DeviceResource.Create(
            pathFleetSid: "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            friendlyName: "My Device #1"
        );

        Console.WriteLine(device.Sid);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($sid, $token);

$fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$fleetService = $client->preview->deployedDevices->fleets($fleetSid);

$device = $fleetService->devices->create([
    'friendlyName' => 'My Device #1'
]);

echo $device->sid;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

device = fleet_service.devices.create(
  friendly_name: 'My Device #1'
)

puts device.sid
# Get the Python helper library from https://twilio.com/docs/libraries/python
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

device = fleet_service.devices.create(friendly_name='My Device #1')

print(device.sid)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.base.ResourceSet;
import com.twilio.rest.preview.deployedDevices.fleet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        Device device = DeviceCreator("FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
            .setFriendlyName("My Device #1")
            .create();

        System.out.println(device.getSid());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Devices \
  -d 'FriendlyName=My Device #1'
{
  "sid": "THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": "My Device #1",
  "unique_name": null,
  "fleet_sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "deployment_sid": "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "identity": null,
  "enabled": true,
  "date_created": "2017-08-14T19:19:30Z",
  "date_updated": "2017-08-14T19:19:30Z",
  "date_authenticated": null,
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Devices/THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
Create a Device

Next, when in your fleet, click the 'Certificate' link in the left sidebar followed by the red plus sign (+) to create a new Device Certificate.  It will automatically link to the ESP32 device you created a second ago.

Enter a friendly name for your certificate and check the 'Self-signed certificate' box.  Next, hit the 'Create' button!

Sync Certificate and Key Download for ESP32

In the success screen (similar to the above), download both the Certificate and Private key, and copy the key decryption password.  Note: you will not have another chance to do this!  You'll have to create a new certificate if you miss this step!

As always, you can also create and delete Device Certificates programmatically using the API.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
// Get the Node helper library from https://twilio.com/docs/libraries/node
const fs = require('fs');
const Twilio = require('twilio').Twilio;

// Get your Account SID and Auth Token from https://twilio.com/console
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = new Twilio(accountSid, authToken);

const fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const fleetService = client.preview.deployed_devices.fleets(fleetSid);

fleetService.certificates
  .create({
    deviceSid: 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    friendlyName: 'Woody',
    certificateData: fs.readFileSync('/path/to/certificate.pem'),
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices.Fleet

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        const string certificatePath = @"C:\path\to\certificate.pem";
        var certificate = CertificateResource.Create(
            pathFleetSid: "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            deviceSid: "THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            friendlyName: "Woody",
            certificateData: System.IO.File.ReadAllText(certificatePath)
        );

        Console.WriteLine(certificate.Sid);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($sid, $token);

$fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$fleetService = $client->preview->deployedDevices->fleets($fleetSid);

$certificateContent = file_get_contents('/path/to/certificate.pem');
$certificate = $fleetService->create($certificateContent, [
    'deviceSid' => 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'friendlyName' => 'Woody',
]);

echo $certificate->sid;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

certificate = fleet_service.certificates.create(
  device_sid: 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
  friendly_name: 'Woody',
  certificate_data: IO.read('/path/to/certificate.pem')
)

puts certificate.sid
# Get the Python helper library from https://twilio.com/docs/libraries/python
from pathlib import Path
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

certificate = fleet_service.certificates.create({
    'device_sid': 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'friendly_name': 'Woody',
    'certificate_data': Path('/path/to/certificate.pem').read_text(),
})

print(certificate.sid)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.base.ResourceSet;
import com.twilio.rest.preview.deployedDevices.fleet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        CertificateCreator certificateCreator = CertificateCreator(
            "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            new String(Files.readAllBytes(Paths.get("/path/to/certificate.pem")))
        );

        Certificate certificate = certificateCreator
            .setFriendlyName("Woody")
            .setDeviceSid("THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
            .create();

        System.out.println(certificate.getSid());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Certificates \
  -d 'DeviceSid=THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \
  -d 'FriendlyName=Woody' \
  --data-urlencode CertificateData@cert-file.pem
{
  "sid": "CYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": null,
  "fleet_sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "device_sid": "THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "thumbprint": "<supplied_certificate_fingerprint>",
  "date_created": "2017-08-14T18:23:12Z",
  "date_updated": "2017-08-14T18:23:12Z",
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Certificates/CYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
Create a Certificate

In the ESP32 C++ Arduino code, you will be copying the certificate as well as a decrypted key to the certificates.hpp file.

Create a Sync Document

A Document is the simplest type of Sync object - great for a small application such as an LED blinker.  You will have to create that document in some way before you connect your ESP32 to Sync; the Document name will directly map to the subscribed topic of the ESP32.  Name your Document 'BoardLED' (case sensitive).

Loading Code Samples...
Language
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);
const service = client.sync.services('default');

service.documents
  .create({
    uniqueName: 'BoardLED',
    data: { led: 'OFF' },
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Download the twilio-csharp library from twilio.com/docs/libraries/csharp
using System;
using Twilio;
using Twilio.Rest.Sync.V1.Service;

public class Example
{
    public static void Main(string[] args)
    {
        // Find your Account SID and Auth Token at twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        const string serviceSid = "default";

        TwilioClient.Init(accountSid, authToken);

        var data = new
        {
            led = "OFF"
        };

        var doc = DocumentResource.Create(serviceSid,
                                          "BoardLED",
                                          data);

        Console.WriteLine(doc.Sid);
    }
}
<?php
// NOTE: This example uses the next generation Twilio helper library - for more
// information on how to download and install this version, visit
// https://www.twilio.com/docs/libraries/php
require_once 'vendor/autoload.php';

use Twilio\Rest\Client;

// Your Account SID from www.twilio.com/console
$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// Your Auth Token from www.twilio.com/console
$token = "your_auth_token";

$client = new Client($sid, $token);

$data = array(
    'led' => "OFF"
);

$doc = $client->sync
    ->services("default")
    ->documents->create(
        array(
            'uniqueName' => "BoardLED",
            'data' => $data
        )
    );

echo $doc->sid, PHP_EOL;
require 'twilio-ruby'

# Initialize the client
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

# Retrieve the service
service = client.sync.v1.services('default')

data = [
  '"led": "OFF"'
]

# Create the Document, data can be any JSON
response = service.documents.create(
  unique_name: 'BoardLED',
  data: "{#{data.join(',')}}"
)

puts response
# Download the Python helper library from twilio.com/docs/python/install
from twilio.rest import Client

# Your Account Sid and Auth Token from twilio.com/user/account
account_sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
auth_token = "your_auth_token"
client = Client(account_sid, auth_token)

data = {
    'led': "OFF"
}

document = client.sync \
    .services("default") \
    .documents \
    .create(unique_name="BoardLED", data=data)

print(document.sid)
// Install the Java helper library from twilio.com/docs/java/install
import java.util.HashMap;
import java.util.Map;

import com.twilio.Twilio;
import com.twilio.rest.sync.v1.service.Document;

public class Example {
  // Find your Account Sid and Token at twilio.com/user/account
  public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  public static final String AUTH_TOKEN = "your_auth_token";

  public static void main(String[] args) {
    Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

    Map<String, Object> data = new HashMap<>();
    data.put("led", "OFF");

    Document document = Document
        .creator("default")
        .setUniqueName("BoardLED")
        .setData(data)
        .create();

    System.out.println(document.getSid());
  }
}
curl -X POST https://sync.twilio.com/v1/Services/default/Documents \
 -d 'UniqueName=BoardLED' \
 -d 'Data={"led":"OFF"}'  \
 -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token'
{
  "unique_name": "BoardLED",
  "url": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "created_by": "system",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-09-06T20:53:38Z",
  "date_updated": "2017-09-06T20:53:38Z",
  "sid": "ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "data": {
    "led": "OFF"
  },
  "revision": "0",
  "links": {
    "permissions": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Permissions"
  }
}
Use the Sync Service SID from the 'Configure Deployment' Screen, as Shown Above.
Create a Sync Document

Use the Sync Service SID from the 'Configure Deployment' Screen, as Shown Above.

While creating it, we also initialize 'led' to 'OFF'.

Prerequisites to Use an ESP32 with Sync

You can grab all of our code on Github, here.

For this guide's development, we used a ESP32 development board (the 'Developer Edition', from Adafruit) with the Arduino IDE.  We connected an LED to pin 23 then through a resistor to ground, so the LED would be active high.  Use a suitable resistor to protect the LED (here is a LED resistor calculator to help).

LED Schematic for Deployed Devices and ESP32

Any other suitable ESP32 with an LED will work fine, just be sure to change the target pin in the code.

Once you are inside the Arduino IDE, install two libraries:

  • ArduinoJSON (by Benoit Blanchon - GitHub)
  • PubSubClient (by Nick O'Leary - GitHub)

On my machine, the Library Manager was found through the menu combination 'Sketch' -> 'Include Library' -> 'Library Manager'.  The libraries are installed and managed directly inside the IDE.

Add Your Credentials to the ESP32

A few steps above, you created a certificate for the ESP32 and downloaded an encrypted key and certificate.  You will now need to add your decrypted client key and your client certificate.

Let's start with the client certificate - it can be used verbatim.  In the Arduino IDE, go to the certificates.hpp file.

  1. Open the CYxxx.pem client certificate file in your choice of text editor and copy everything (including the lines which start with hyphens ['---']).
  2. Paste it all between the () into client_cert inside certificates.hpp:
    const char* client_cert = R"(PASTE_IT_HERE)";​
    
    You can look at the root_cert for a hint if you need help.
  3. Before you can paste the key, you have to decrypt the .key file.  On *NIX, this can be done with:
    openssl rsa -in  CYxxxxxxxxxx.key -out CYxxxxxxxxxx.key.decrypted​
    
    Enter your password to decrypt it.
  4. Open it your choice of text editor and copy the decrypted key (again including the hyphen lines).
  5. Paste it all between the () into client_key inside certificates.hpp:
    const char* client_key = R"(PASTE_IT_HERE)";​
    

 

Loading Code Samples...
Language
/* 
 *  For the certificates and the keys on this page, paste everything
 *  between the 'R"(' and ')"', including any lines with hyphens.
 *  
 *  Ensure you do not add or clip any lines or whitespace when pasting.
 */


/* 
 *  DigiCert Root Certificate.  
 *  
 *  If this certificate does not work, retreive the latest with (*NIX):
 *  
 *  openssl s_client -showcerts -connect mqtt-sync.us1.twilio.com:8883 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 < /dev/null
 *  
 *  ... and pick the last certificate in the chain.
 */
const char* root_cert = R"(-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBT
ZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6g
LGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv
68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0w
EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEE
KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0f
BDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv
YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc
aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/A
buiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ
KoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/6
3qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoB
UEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6
mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3
loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd
Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc=
-----END CERTIFICATE-----)";


/*  Client Key: Unencrypted.
 *  
 *  Download the client key from Twilio after you create the 
 *  certificate, then unencrypt it using the passphrase 
 *  displayed on the screen.  On *NIX, this is:
 *  
 *  openssl rsa -in  CYxxxxxxxxxx.key -out CYxxxxxxxxxx.key.decrypted
 *  
 *  Paste the results below between the '()' inside the double quotes
 *  and make sure there is no whitespace.
 */
const char* client_key = R"()";

/*  Client Certificate
 *  
 *  Paste the certificate below between the '()' inside the 
 *  double quotes, and make sure there is no whitespace.
 */
const char* client_cert = R"()";
In certificates.hpp, paste your decrypted client key and your client certificate you downloaded.
Paste Your Client Key and Certificate

In certificates.hpp, paste your decrypted client key and your client certificate you downloaded.

Once you've added your client key and certificate, we can turn our attention to the .ino file.

Edit the Code with Your WiFi Credentials

Switch tabs to the .ino file now.  You'll need to make edits to the C++ sketch to get it on your network:

  • ssid
  • password
Loading Code Samples...
Language
/* License: MIT */
#include "WiFiClientSecure.h"
#include "certificates.hpp"
#include <PubSubClient.h>
#include <ArduinoJson.h>

/* LED Pin for your ESP32 */
#define LED_PIN 23

/* WiFi SSID and Password */
const char* ssid                        = "YOUR_SSID";
const char* password                    = "WIFI_PASSWORD";

/* 
 *  Sync Settings
 *  
 *  Enter your document's unique name and a device name.
 */
const char* sync_document               = "sync/docs/BoardLED";
const char* sync_device_name            = "ESP32_Dev_Board";

/* Sync server and MQTT setup; you probably don't have to change these. */
const char* mqtt_server                 = "mqtt-sync.us1.twilio.com";
const uint16_t mqtt_port                = 8883;
const uint16_t maxMQTTpackageSize       = 512;

WiFiClientSecure espClient;
PubSubClient client(mqtt_server, mqtt_port, espClient);


/* 
 * Our Twilio Connected Devices message handling callback.  This is passed as a 
 * callback function when we subscribe to the document, and any messages will 
 * appear here.
 */
void callback(char* topic, byte* payload, unsigned int length) 
{
        std::unique_ptr<char []> msg(new char[length+1]());
        memcpy (msg.get(), payload, length);

        Serial.print("Message arrived on topic "); Serial.println(msg.get());
        
        StaticJsonBuffer<maxMQTTpackageSize> jsonBuffer;
        JsonObject& root = jsonBuffer.parseObject(msg.get());
        String led_command           = root["led"];

        if (led_command == "ON") {
                digitalWrite(LED_PIN, HIGH);
                Serial.println("LED turned on!");
        } else {
                digitalWrite(LED_PIN, LOW);
                Serial.println("LED turned off!");
        }
}


/* 
 * This function connects to Sync via MQTT. We connect using the certificates and 
 * device name defined as constants above, and immediately check the server's 
 * certificate fingerprint.
 * 
 * If everything works, we subscribe to the document topic and return.
 */
void connect_mqtt() 
{
        while (!client.connected()) {
                Serial.println("Attempting to connect to Twilio Sync...");
                if (client.connect(sync_device_name)) {
                        Serial.print("Connected!  Subscribing to "); Serial.println(sync_document);
                        client.setCallback(callback);
                        client.subscribe(sync_document);
                } else {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        delay(10000);
                }
        }
}


/* In setup, we configure our LED for output, turn it off, and connect to WiFi */
void setup() 
{
        Serial.begin(115200);
        WiFi.begin(ssid, password);

        pinMode(LED_PIN, OUTPUT);
        digitalWrite(LED_PIN, LOW);

        while (WiFi.status() != WL_CONNECTED) {
                delay(1000);
                Serial.print(".");
        }

        randomSeed(micros());
        Serial.print("\nWiFi connected!  IP address: ");
        Serial.println(WiFi.localIP());

        // Set the root CA (to validate you are talking to Twilio) and the client key and cert
        espClient.setCACert(root_cert);
        espClient.setCertificate(client_cert);
        espClient.setPrivateKey(client_key);
}


/* Our loop constantly checks we are still connected.  On disconnects we try again. */
void loop() 
{
        if (!client.connected()) {
                connect_mqtt();
        }
        client.loop();
                
        // Here's an example of publishing from the ESP32.
        // Uncomment until the end of the function to send a 'msg' back to Sync
        // every 2 minutes!
        /*
        static uint32_t now = millis();
        if (millis() > now + (2*(1000*60))) {
                Serial.println("Sending 2 minute ON message to Twilio!");
                client.publish(
                        sync_document, 
                        "{\"msg\":\"Ahoy!\",\"led\":\"ON\"}\0"
                );
                now = millis();
        }
        */
}
Add your WiFi SSID and password to connect to a friendly WiFi network with the ESP32.
Connect to Sync for IoT with an ESP32

Add your WiFi SSID and password to connect to a friendly WiFi network with the ESP32.

The next two variables may not have to change; if you didn't name your Sync Document BoardLED you will have to change it here though.

  • sync_document
  • sync_device_name

If you are not using an LED on pin 23, be sure to also change LED_PIN.

Once all the variables are set, it's blinky time.  

Upload the code to the ESP.  Open the Arduino Serial Monitor (the menu 'Tools' -> 'Serial Monitor').  You should see something like this streaming over serial:

.......
WiFi connected!  IP address: 192.168.1.169
Attempting to connect to Twilio Sync...
Connected!  Subscribing to sync/docs/BoardLED
Message arrived on topic {"led":"OFF"}
LED turned off!

But wait - there's more!  Let's blink that LED.  Use the following code to send an UPDATE request to Sync and change the state of led.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);
const service = client.sync.services('default');

service
  .documents('BoardLED')
  .update({
    data: { led: 'ON' },
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Download the twilio-csharp library from twilio.com/docs/libraries/csharp
using System;
using Twilio;
using Twilio.Rest.Sync.V1.Service;

public class Example
{
    public static void Main(string[] args)
    {
        // Find your Account SID and Auth Token at twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        const string serviceSid = "default";

        TwilioClient.Init(accountSid, authToken);

        var data = new
        {
            led = "ON"
        };

        var doc = DocumentResource.Update(serviceSid,
                                          "BoardLED",
                                          data);

        Console.WriteLine(doc.Data);
    }
}
<?php
// NOTE: This example uses the next generation Twilio helper library - for more
// information on how to download and install this version, visit
// https://www.twilio.com/docs/libraries/php
require_once 'vendor/autoload.php';

use Twilio\Rest\Client;

// Your Account SID from www.twilio.com/console
$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// Your Auth Token from www.twilio.com/console
$token = "your_auth_token";

$client = new Client($sid, $token);

$data = array(
    'led' => "ON"
);

$doc = $client->sync
    ->services("default")
    ->documents("BoardLED")->update(
        array(
            'led' => $data
        )
    );

print_r($doc->data);
echo PHP_EOL;
require 'twilio-ruby'

# Initialize the client
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

# Retreive the service
service = client.sync.v1.services('default')

# Update the Document, data can be any JSON
response = service.documents('BoardLED').update(
  data: '{ "led": "ON" }'
)

puts response
# Download the Python helper library from twilio.com/docs/python/install
from twilio.rest import Client

# Your Account Sid and Auth Token from twilio.com/user/account
account_sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
auth_token = "your_auth_token"
client = Client(account_sid, auth_token)

new_data = {
    'led': "ON"
}

document = client.sync \
    .services("default") \
    .documents("BoardLED") \
    .update(data=new_data)

print(document.data)
// Install the Java helper library from twilio.com/docs/java/install
import java.util.HashMap;
import java.util.Map;

import com.twilio.Twilio;
import com.twilio.rest.sync.v1.service.Document;

public class Example {
  // Find your Account Sid and Token at twilio.com/user/account
  public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  public static final String AUTH_TOKEN = "your_auth_token";

  public static final String SERVICE_SID = "default";

  public static void main(String[] args) {
    Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

    Map<String, Object> data = new HashMap<>();
    data.put("led", "ON");

    Document document = Document.updater(SERVICE_SID, "BoardLED", data).update();

    System.out.println(document.getData());
  }
}
curl -X POST https://sync.twilio.com/v1/Services/default/Documents/BoardLED \
 -d 'Data={"led":"ON"}'  \
 -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token'
{
  "unique_name": "BoardLED",
  "url": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "created_by": "system",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-09-06T20:53:38Z",
  "date_updated": "2017-09-06T20:55:21Z",
  "sid": "ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "data": {
    "led": "ON"
  },
  "revision": "1",
  "links": {
    "permissions": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Permissions"
  }
}
Update a BoardLED Document

Boom! Light!

You'll see three updates in quick succession:

  • Sync will respond letting you know the command was successful
  • The LED will light up
  • You'll get a happy message from the ESP32 over serial

ESP32 Blinking Over Sync Deployed Devices

Updating Sync from the ESP32

If you look in the code, there are a few commented out lines which show how to send updates back from the ESP32.  Remove the comments to send a msg back to Sync.

Loading Code Samples...
Language
/* License: MIT */
#include "WiFiClientSecure.h"
#include "certificates.hpp"
#include <PubSubClient.h>
#include <ArduinoJson.h>

/* LED Pin for your ESP32 */
#define LED_PIN 23

/* WiFi SSID and Password */
const char* ssid                        = "YOUR_SSID";
const char* password                    = "WIFI_PASSWORD";

/* 
 *  Sync Settings
 *  
 *  Enter your document's unique name and a device name.
 */
const char* sync_document               = "sync/docs/BoardLED";
const char* sync_device_name            = "ESP32_Dev_Board";

/* Sync server and MQTT setup; you probably don't have to change these. */
const char* mqtt_server                 = "mqtt-sync.us1.twilio.com";
const uint16_t mqtt_port                = 8883;
const uint16_t maxMQTTpackageSize       = 512;

WiFiClientSecure espClient;
PubSubClient client(mqtt_server, mqtt_port, espClient);


/* 
 * Our Twilio Connected Devices message handling callback.  This is passed as a 
 * callback function when we subscribe to the document, and any messages will 
 * appear here.
 */
void callback(char* topic, byte* payload, unsigned int length) 
{
        std::unique_ptr<char []> msg(new char[length+1]());
        memcpy (msg.get(), payload, length);

        Serial.print("Message arrived on topic "); Serial.println(msg.get());
        
        StaticJsonBuffer<maxMQTTpackageSize> jsonBuffer;
        JsonObject& root = jsonBuffer.parseObject(msg.get());
        String led_command           = root["led"];

        if (led_command == "ON") {
                digitalWrite(LED_PIN, HIGH);
                Serial.println("LED turned on!");
        } else {
                digitalWrite(LED_PIN, LOW);
                Serial.println("LED turned off!");
        }
}


/* 
 * This function connects to Sync via MQTT. We connect using the certificates and 
 * device name defined as constants above, and immediately check the server's 
 * certificate fingerprint.
 * 
 * If everything works, we subscribe to the document topic and return.
 */
void connect_mqtt() 
{
        while (!client.connected()) {
                Serial.println("Attempting to connect to Twilio Sync...");
                if (client.connect(sync_device_name)) {
                        Serial.print("Connected!  Subscribing to "); Serial.println(sync_document);
                        client.setCallback(callback);
                        client.subscribe(sync_document);
                } else {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        delay(10000);
                }
        }
}


/* In setup, we configure our LED for output, turn it off, and connect to WiFi */
void setup() 
{
        Serial.begin(115200);
        WiFi.begin(ssid, password);

        pinMode(LED_PIN, OUTPUT);
        digitalWrite(LED_PIN, LOW);

        while (WiFi.status() != WL_CONNECTED) {
                delay(1000);
                Serial.print(".");
        }

        randomSeed(micros());
        Serial.print("\nWiFi connected!  IP address: ");
        Serial.println(WiFi.localIP());

        // Set the root CA (to validate you are talking to Twilio) and the client key and cert
        espClient.setCACert(root_cert);
        espClient.setCertificate(client_cert);
        espClient.setPrivateKey(client_key);
}


/* Our loop constantly checks we are still connected.  On disconnects we try again. */
void loop() 
{
        if (!client.connected()) {
                connect_mqtt();
        }
        client.loop();
                
        // Here's an example of publishing from the ESP32.
        // Uncomment until the end of the function to send a 'msg' back to Sync
        // every 2 minutes!
        /*
        static uint32_t now = millis();
        if (millis() > now + (2*(1000*60))) {
                Serial.println("Sending 2 minute ON message to Twilio!");
                client.publish(
                        sync_document, 
                        "{\"msg\":\"Ahoy!\",\"led\":\"ON\"}\0"
                );
                now = millis();
        }
        */
}
Uncomment these lines to send data back to Sync on a timer.
Optionally Send Data Back to Sync

Uncomment these lines to send data back to Sync on a timer.

Note that whatever you send should be in JSON format.  You can generate JSON through the ArduinoJSON library rather simply, or craft it inline like we've done here.

The Internet of Synced Things

It's that simple - blinky lights and a ESP32 all mediated through a Sync Document with the power of Twilio's Sync for IoT and MQTT.  

Now you can take this infrastructure in any direction you desire, sharing the BoardLED Document across many devices - or perhaps using it on your server and creating a dashboard.  Wherever you take it, let us know what you've built on Twitter!

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);

client.preview.deployed_devices.fleets
  .create({
    friendlyName: 'My Fleet of Devices',
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices;

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        var fleet = FleetResource.Create(
            friendlyName: "My Fleet of Devices"
        );

        Console.WriteLine(fleet.Sid);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($accountSid, $authToken);

$fleet = $client->preview->deployedDevices->fleets->create(
  array(
    'friendlyName' => 'My Fleet of Devices'
  )
);

echo $fleet->sid;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

fleet = client.preview.deployed_devices.fleets.create(
  friendly_name: 'My Fleet of Devices'
)

puts fleet.sid
# Get the Python helper library from https://twilio.com/docs/libraries/python
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet = client.preview.deployed_devices.fleets.create(
    friendly_name='My Fleet of Devices')

print(fleet.sid)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.rest.preview.deployedDevices.Fleet;
import com.twilio.rest.preview.deployedDevices.FleetCreator;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        FleetCreator fleetCreator = new FleetCreator();
        Fleet fleet = fleetCreator
                .setFriendlyName("My Fleet of Devices")
                .create();

        System.out.println(fleet.getSid());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets
{
  "sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": null,
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "default_deployment_sid": "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-08-14T15:25:45Z",
  "date_updated": "2017-08-14T15:25:45Z",
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "links": {
    "certificates": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Certificates",
    "keys": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Keys",
    "devices": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Devices",
    "deployments": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Deployments"
  }
}
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);
const fleet = client.preview.deployed_devices.fleets(
  'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
);

fleet
  .deployments('FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({
    friendlyName: 'My New Device Deployment',
    syncServiceSid: 'ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices;

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        const string deploymentSid = "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var deployment = DeploymentResource.Update(
            deploymentSid,
            friendlyName: "My New Device Deployment");

        Console.WriteLine(deploymentSid.FriendlyName);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($accountSid, $authToken);

$deploymentSid = 'DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$deployment = $client->preview->deployedDevices->deployments($deploymentSid)->update(
  array(
    'friendlyName' => 'My New Device Deployment'
  )
);

echo $deployment->friendlyName;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

deployment_sid = 'DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
deployment = client.preview.deployed_devices
                   .deployments(deployment_sid)
                   .update(friendly_name: 'My New Device Deployment')

puts deployment.friendly_name
# Get the Python helper library from https://twilio.com/docs/libraries/python
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
deployment_sid = 'DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
deployment = client.preview\
                   .deployed_devices\
                   .fleets(fleet_sid)\
                   .deployments(sid=deployment_sid)\
                   .update(friendly_name='My New Device Deployment')

print(deployment.friendly_name)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.rest.preview.deployedDevices.Deployment;
import com.twilio.rest.preview.deployedDevices.DeploymentUpdater;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        String deploymentSid = "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        Deployment deployment = new DeploymentUpdater(deploymentSid)
                .setFriendlyName("My New Device Deployment")
                .update();

        System.out.println(deployment.getFriendlyName());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Deployments/DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
  -d 'FriendlyName=My New Device Deployment' \
  -d 'SyncServiceSid=ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
{
  "sid": "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": "My New Device Deployment",
  "fleet_sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "sync_service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-08-14T15:44:05Z",
  "date_updated": "2017-08-14T15:55:25Z",
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Deployments/DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
// Get the Node helper library from https://twilio.com/docs/libraries/node
const fs = require('fs');
const Twilio = require('twilio').Twilio;

// Get your Account SID and Auth Token from https://twilio.com/console
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = new Twilio(accountSid, authToken);

const fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const fleetService = client.preview.deployed_devices.fleets(fleetSid);

fleetService.devices
  .create({
    friendlyName: 'My Device #1',
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices.Fleet

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        var device = DeviceResource.Create(
            pathFleetSid: "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            friendlyName: "My Device #1"
        );

        Console.WriteLine(device.Sid);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($sid, $token);

$fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$fleetService = $client->preview->deployedDevices->fleets($fleetSid);

$device = $fleetService->devices->create([
    'friendlyName' => 'My Device #1'
]);

echo $device->sid;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

device = fleet_service.devices.create(
  friendly_name: 'My Device #1'
)

puts device.sid
# Get the Python helper library from https://twilio.com/docs/libraries/python
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

device = fleet_service.devices.create(friendly_name='My Device #1')

print(device.sid)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.base.ResourceSet;
import com.twilio.rest.preview.deployedDevices.fleet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        Device device = DeviceCreator("FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
            .setFriendlyName("My Device #1")
            .create();

        System.out.println(device.getSid());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Devices \
  -d 'FriendlyName=My Device #1'
{
  "sid": "THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": "My Device #1",
  "unique_name": null,
  "fleet_sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "deployment_sid": "DLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "identity": null,
  "enabled": true,
  "date_created": "2017-08-14T19:19:30Z",
  "date_updated": "2017-08-14T19:19:30Z",
  "date_authenticated": null,
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Devices/THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
// Get the Node helper library from https://twilio.com/docs/libraries/node
const fs = require('fs');
const Twilio = require('twilio').Twilio;

// Get your Account SID and Auth Token from https://twilio.com/console
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = new Twilio(accountSid, authToken);

const fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const fleetService = client.preview.deployed_devices.fleets(fleetSid);

fleetService.certificates
  .create({
    deviceSid: 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    friendlyName: 'Woody',
    certificateData: fs.readFileSync('/path/to/certificate.pem'),
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Get the C# helper library from https://twilio.com/docs/libraries/csharp
using System;
using System.Collections.Generic;
using Twilio;
using Twilio.Rest.Preview.DeployedDevices.Fleet

public class Example
{
    public static void Main(string[] args)
    {
        // Get your Account SID and Auth Token from https://twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        const string certificatePath = @"C:\path\to\certificate.pem";
        var certificate = CertificateResource.Create(
            pathFleetSid: "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            deviceSid: "THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            friendlyName: "Woody",
            certificateData: System.IO.File.ReadAllText(certificatePath)
        );

        Console.WriteLine(certificate.Sid);
    }
}
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library

use Twilio\Rest\Client;

// Get your Account SID and Auth Token from https://twilio.com/console
$accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$authToken = 'your_auth_token';
$client = new Client($sid, $token);

$fleetSid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$fleetService = $client->preview->deployedDevices->fleets($fleetSid);

$certificateContent = file_get_contents('/path/to/certificate.pem');
$certificate = $fleetService->create($certificateContent, [
    'deviceSid' => 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'friendlyName' => 'Woody',
]);

echo $certificate->sid;
# Get the Ruby helper library from https://twilio.com/docs/libraries/ruby
require 'twilio-ruby'

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

certificate = fleet_service.certificates.create(
  device_sid: 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
  friendly_name: 'Woody',
  certificate_data: IO.read('/path/to/certificate.pem')
)

puts certificate.sid
# Get the Python helper library from https://twilio.com/docs/libraries/python
from pathlib import Path
from twilio.rest import Client

# Get your Account SID and Auth Token from https://twilio.com/console
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

fleet_sid = 'FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
fleet_service = client.preview.deployed_devices.fleets(fleet_sid)

certificate = fleet_service.certificates.create({
    'device_sid': 'THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'friendly_name': 'Woody',
    'certificate_data': Path('/path/to/certificate.pem').read_text(),
})

print(certificate.sid)
// Get the Java helper library from https://twilio.com/docs/libraries/java
import com.twilio.Twilio;
import com.twilio.base.ResourceSet;
import com.twilio.rest.preview.deployedDevices.fleet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Example {
    // Get your Account SID and Auth Token from https://twilio.com/console
    public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String AUTH_TOKEN = "your_auth_token";

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

        CertificateCreator certificateCreator = CertificateCreator(
            "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            new String(Files.readAllBytes(Paths.get("/path/to/certificate.pem")))
        );

        Certificate certificate = certificateCreator
            .setFriendlyName("Woody")
            .setDeviceSid("THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
            .create();

        System.out.println(certificate.getSid());
    }
}
curl -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' \
  -X POST https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Certificates \
  -d 'DeviceSid=THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \
  -d 'FriendlyName=Woody' \
  --data-urlencode CertificateData@cert-file.pem
{
  "sid": "CYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "friendly_name": null,
  "fleet_sid": "FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "device_sid": "THXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "thumbprint": "<supplied_certificate_fingerprint>",
  "date_created": "2017-08-14T18:23:12Z",
  "date_updated": "2017-08-14T18:23:12Z",
  "url": "https://preview.twilio.com/DeployedDevices/Fleets/FLXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Certificates/CYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);
const service = client.sync.services('default');

service.documents
  .create({
    uniqueName: 'BoardLED',
    data: { led: 'OFF' },
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Download the twilio-csharp library from twilio.com/docs/libraries/csharp
using System;
using Twilio;
using Twilio.Rest.Sync.V1.Service;

public class Example
{
    public static void Main(string[] args)
    {
        // Find your Account SID and Auth Token at twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        const string serviceSid = "default";

        TwilioClient.Init(accountSid, authToken);

        var data = new
        {
            led = "OFF"
        };

        var doc = DocumentResource.Create(serviceSid,
                                          "BoardLED",
                                          data);

        Console.WriteLine(doc.Sid);
    }
}
<?php
// NOTE: This example uses the next generation Twilio helper library - for more
// information on how to download and install this version, visit
// https://www.twilio.com/docs/libraries/php
require_once 'vendor/autoload.php';

use Twilio\Rest\Client;

// Your Account SID from www.twilio.com/console
$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// Your Auth Token from www.twilio.com/console
$token = "your_auth_token";

$client = new Client($sid, $token);

$data = array(
    'led' => "OFF"
);

$doc = $client->sync
    ->services("default")
    ->documents->create(
        array(
            'uniqueName' => "BoardLED",
            'data' => $data
        )
    );

echo $doc->sid, PHP_EOL;
require 'twilio-ruby'

# Initialize the client
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

# Retrieve the service
service = client.sync.v1.services('default')

data = [
  '"led": "OFF"'
]

# Create the Document, data can be any JSON
response = service.documents.create(
  unique_name: 'BoardLED',
  data: "{#{data.join(',')}}"
)

puts response
# Download the Python helper library from twilio.com/docs/python/install
from twilio.rest import Client

# Your Account Sid and Auth Token from twilio.com/user/account
account_sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
auth_token = "your_auth_token"
client = Client(account_sid, auth_token)

data = {
    'led': "OFF"
}

document = client.sync \
    .services("default") \
    .documents \
    .create(unique_name="BoardLED", data=data)

print(document.sid)
// Install the Java helper library from twilio.com/docs/java/install
import java.util.HashMap;
import java.util.Map;

import com.twilio.Twilio;
import com.twilio.rest.sync.v1.service.Document;

public class Example {
  // Find your Account Sid and Token at twilio.com/user/account
  public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  public static final String AUTH_TOKEN = "your_auth_token";

  public static void main(String[] args) {
    Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

    Map<String, Object> data = new HashMap<>();
    data.put("led", "OFF");

    Document document = Document
        .creator("default")
        .setUniqueName("BoardLED")
        .setData(data)
        .create();

    System.out.println(document.getSid());
  }
}
curl -X POST https://sync.twilio.com/v1/Services/default/Documents \
 -d 'UniqueName=BoardLED' \
 -d 'Data={"led":"OFF"}'  \
 -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token'
{
  "unique_name": "BoardLED",
  "url": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "created_by": "system",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-09-06T20:53:38Z",
  "date_updated": "2017-09-06T20:53:38Z",
  "sid": "ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "data": {
    "led": "OFF"
  },
  "revision": "0",
  "links": {
    "permissions": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Permissions"
  }
}
/* 
 *  For the certificates and the keys on this page, paste everything
 *  between the 'R"(' and ')"', including any lines with hyphens.
 *  
 *  Ensure you do not add or clip any lines or whitespace when pasting.
 */


/* 
 *  DigiCert Root Certificate.  
 *  
 *  If this certificate does not work, retreive the latest with (*NIX):
 *  
 *  openssl s_client -showcerts -connect mqtt-sync.us1.twilio.com:8883 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 < /dev/null
 *  
 *  ... and pick the last certificate in the chain.
 */
const char* root_cert = R"(-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBT
ZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6g
LGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv
68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0w
EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEE
KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0f
BDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv
YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc
aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/A
buiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ
KoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/6
3qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoB
UEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6
mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3
loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd
Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc=
-----END CERTIFICATE-----)";


/*  Client Key: Unencrypted.
 *  
 *  Download the client key from Twilio after you create the 
 *  certificate, then unencrypt it using the passphrase 
 *  displayed on the screen.  On *NIX, this is:
 *  
 *  openssl rsa -in  CYxxxxxxxxxx.key -out CYxxxxxxxxxx.key.decrypted
 *  
 *  Paste the results below between the '()' inside the double quotes
 *  and make sure there is no whitespace.
 */
const char* client_key = R"()";

/*  Client Certificate
 *  
 *  Paste the certificate below between the '()' inside the 
 *  double quotes, and make sure there is no whitespace.
 */
const char* client_cert = R"()";
/* License: MIT */
#include "WiFiClientSecure.h"
#include "certificates.hpp"
#include <PubSubClient.h>
#include <ArduinoJson.h>

/* LED Pin for your ESP32 */
#define LED_PIN 23

/* WiFi SSID and Password */
const char* ssid                        = "YOUR_SSID";
const char* password                    = "WIFI_PASSWORD";

/* 
 *  Sync Settings
 *  
 *  Enter your document's unique name and a device name.
 */
const char* sync_document               = "sync/docs/BoardLED";
const char* sync_device_name            = "ESP32_Dev_Board";

/* Sync server and MQTT setup; you probably don't have to change these. */
const char* mqtt_server                 = "mqtt-sync.us1.twilio.com";
const uint16_t mqtt_port                = 8883;
const uint16_t maxMQTTpackageSize       = 512;

WiFiClientSecure espClient;
PubSubClient client(mqtt_server, mqtt_port, espClient);


/* 
 * Our Twilio Connected Devices message handling callback.  This is passed as a 
 * callback function when we subscribe to the document, and any messages will 
 * appear here.
 */
void callback(char* topic, byte* payload, unsigned int length) 
{
        std::unique_ptr<char []> msg(new char[length+1]());
        memcpy (msg.get(), payload, length);

        Serial.print("Message arrived on topic "); Serial.println(msg.get());
        
        StaticJsonBuffer<maxMQTTpackageSize> jsonBuffer;
        JsonObject& root = jsonBuffer.parseObject(msg.get());
        String led_command           = root["led"];

        if (led_command == "ON") {
                digitalWrite(LED_PIN, HIGH);
                Serial.println("LED turned on!");
        } else {
                digitalWrite(LED_PIN, LOW);
                Serial.println("LED turned off!");
        }
}


/* 
 * This function connects to Sync via MQTT. We connect using the certificates and 
 * device name defined as constants above, and immediately check the server's 
 * certificate fingerprint.
 * 
 * If everything works, we subscribe to the document topic and return.
 */
void connect_mqtt() 
{
        while (!client.connected()) {
                Serial.println("Attempting to connect to Twilio Sync...");
                if (client.connect(sync_device_name)) {
                        Serial.print("Connected!  Subscribing to "); Serial.println(sync_document);
                        client.setCallback(callback);
                        client.subscribe(sync_document);
                } else {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        delay(10000);
                }
        }
}


/* In setup, we configure our LED for output, turn it off, and connect to WiFi */
void setup() 
{
        Serial.begin(115200);
        WiFi.begin(ssid, password);

        pinMode(LED_PIN, OUTPUT);
        digitalWrite(LED_PIN, LOW);

        while (WiFi.status() != WL_CONNECTED) {
                delay(1000);
                Serial.print(".");
        }

        randomSeed(micros());
        Serial.print("\nWiFi connected!  IP address: ");
        Serial.println(WiFi.localIP());

        // Set the root CA (to validate you are talking to Twilio) and the client key and cert
        espClient.setCACert(root_cert);
        espClient.setCertificate(client_cert);
        espClient.setPrivateKey(client_key);
}


/* Our loop constantly checks we are still connected.  On disconnects we try again. */
void loop() 
{
        if (!client.connected()) {
                connect_mqtt();
        }
        client.loop();
                
        // Here's an example of publishing from the ESP32.
        // Uncomment until the end of the function to send a 'msg' back to Sync
        // every 2 minutes!
        /*
        static uint32_t now = millis();
        if (millis() > now + (2*(1000*60))) {
                Serial.println("Sending 2 minute ON message to Twilio!");
                client.publish(
                        sync_document, 
                        "{\"msg\":\"Ahoy!\",\"led\":\"ON\"}\0"
                );
                now = millis();
        }
        */
}
SDK Version:
  • 5.x
Response Format:
  • json
SDK Version:
  • 7.x
SDK Version:
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 6.x
SDK Version:
  • 5.x
Format:
  • JSON
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const Twilio = require('twilio').Twilio;

const client = new Twilio(accountSid, authToken);
const service = client.sync.services('default');

service
  .documents('BoardLED')
  .update({
    data: { led: 'ON' },
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log(error);
  });
// Download the twilio-csharp library from twilio.com/docs/libraries/csharp
using System;
using Twilio;
using Twilio.Rest.Sync.V1.Service;

public class Example
{
    public static void Main(string[] args)
    {
        // Find your Account SID and Auth Token at twilio.com/console
        const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        const string authToken = "your_auth_token";
        const string serviceSid = "default";

        TwilioClient.Init(accountSid, authToken);

        var data = new
        {
            led = "ON"
        };

        var doc = DocumentResource.Update(serviceSid,
                                          "BoardLED",
                                          data);

        Console.WriteLine(doc.Data);
    }
}
<?php
// NOTE: This example uses the next generation Twilio helper library - for more
// information on how to download and install this version, visit
// https://www.twilio.com/docs/libraries/php
require_once 'vendor/autoload.php';

use Twilio\Rest\Client;

// Your Account SID from www.twilio.com/console
$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// Your Auth Token from www.twilio.com/console
$token = "your_auth_token";

$client = new Client($sid, $token);

$data = array(
    'led' => "ON"
);

$doc = $client->sync
    ->services("default")
    ->documents("BoardLED")->update(
        array(
            'led' => $data
        )
    );

print_r($doc->data);
echo PHP_EOL;
require 'twilio-ruby'

# Initialize the client
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'
client = Twilio::REST::Client.new(account_sid, auth_token)

# Retreive the service
service = client.sync.v1.services('default')

# Update the Document, data can be any JSON
response = service.documents('BoardLED').update(
  data: '{ "led": "ON" }'
)

puts response
# Download the Python helper library from twilio.com/docs/python/install
from twilio.rest import Client

# Your Account Sid and Auth Token from twilio.com/user/account
account_sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
auth_token = "your_auth_token"
client = Client(account_sid, auth_token)

new_data = {
    'led': "ON"
}

document = client.sync \
    .services("default") \
    .documents("BoardLED") \
    .update(data=new_data)

print(document.data)
// Install the Java helper library from twilio.com/docs/java/install
import java.util.HashMap;
import java.util.Map;

import com.twilio.Twilio;
import com.twilio.rest.sync.v1.service.Document;

public class Example {
  // Find your Account Sid and Token at twilio.com/user/account
  public static final String ACCOUNT_SID = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  public static final String AUTH_TOKEN = "your_auth_token";

  public static final String SERVICE_SID = "default";

  public static void main(String[] args) {
    Twilio.init(ACCOUNT_SID, AUTH_TOKEN);

    Map<String, Object> data = new HashMap<>();
    data.put("led", "ON");

    Document document = Document.updater(SERVICE_SID, "BoardLED", data).update();

    System.out.println(document.getData());
  }
}
curl -X POST https://sync.twilio.com/v1/Services/default/Documents/BoardLED \
 -d 'Data={"led":"ON"}'  \
 -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token'
{
  "unique_name": "BoardLED",
  "url": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "created_by": "system",
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2017-09-06T20:53:38Z",
  "date_updated": "2017-09-06T20:55:21Z",
  "sid": "ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "service_sid": "ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "data": {
    "led": "ON"
  },
  "revision": "1",
  "links": {
    "permissions": "https://sync.twilio.com/v1/Services/ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Documents/ETXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Permissions"
  }
}
/* License: MIT */
#include "WiFiClientSecure.h"
#include "certificates.hpp"
#include <PubSubClient.h>
#include <ArduinoJson.h>

/* LED Pin for your ESP32 */
#define LED_PIN 23

/* WiFi SSID and Password */
const char* ssid                        = "YOUR_SSID";
const char* password                    = "WIFI_PASSWORD";

/* 
 *  Sync Settings
 *  
 *  Enter your document's unique name and a device name.
 */
const char* sync_document               = "sync/docs/BoardLED";
const char* sync_device_name            = "ESP32_Dev_Board";

/* Sync server and MQTT setup; you probably don't have to change these. */
const char* mqtt_server                 = "mqtt-sync.us1.twilio.com";
const uint16_t mqtt_port                = 8883;
const uint16_t maxMQTTpackageSize       = 512;

WiFiClientSecure espClient;
PubSubClient client(mqtt_server, mqtt_port, espClient);


/* 
 * Our Twilio Connected Devices message handling callback.  This is passed as a 
 * callback function when we subscribe to the document, and any messages will 
 * appear here.
 */
void callback(char* topic, byte* payload, unsigned int length) 
{
        std::unique_ptr<char []> msg(new char[length+1]());
        memcpy (msg.get(), payload, length);

        Serial.print("Message arrived on topic "); Serial.println(msg.get());
        
        StaticJsonBuffer<maxMQTTpackageSize> jsonBuffer;
        JsonObject& root = jsonBuffer.parseObject(msg.get());
        String led_command           = root["led"];

        if (led_command == "ON") {
                digitalWrite(LED_PIN, HIGH);
                Serial.println("LED turned on!");
        } else {
                digitalWrite(LED_PIN, LOW);
                Serial.println("LED turned off!");
        }
}


/* 
 * This function connects to Sync via MQTT. We connect using the certificates and 
 * device name defined as constants above, and immediately check the server's 
 * certificate fingerprint.
 * 
 * If everything works, we subscribe to the document topic and return.
 */
void connect_mqtt() 
{
        while (!client.connected()) {
                Serial.println("Attempting to connect to Twilio Sync...");
                if (client.connect(sync_device_name)) {
                        Serial.print("Connected!  Subscribing to "); Serial.println(sync_document);
                        client.setCallback(callback);
                        client.subscribe(sync_document);
                } else {
                        Serial.print("failed, rc=");
                        Serial.print(client.state());
                        delay(10000);
                }
        }
}


/* In setup, we configure our LED for output, turn it off, and connect to WiFi */
void setup() 
{
        Serial.begin(115200);
        WiFi.begin(ssid, password);

        pinMode(LED_PIN, OUTPUT);
        digitalWrite(LED_PIN, LOW);

        while (WiFi.status() != WL_CONNECTED) {
                delay(1000);
                Serial.print(".");
        }

        randomSeed(micros());
        Serial.print("\nWiFi connected!  IP address: ");
        Serial.println(WiFi.localIP());

        // Set the root CA (to validate you are talking to Twilio) and the client key and cert
        espClient.setCACert(root_cert);
        espClient.setCertificate(client_cert);
        espClient.setPrivateKey(client_key);
}


/* Our loop constantly checks we are still connected.  On disconnects we try again. */
void loop() 
{
        if (!client.connected()) {
                connect_mqtt();
        }
        client.loop();
                
        // Here's an example of publishing from the ESP32.
        // Uncomment until the end of the function to send a 'msg' back to Sync
        // every 2 minutes!
        /*
        static uint32_t now = millis();
        if (millis() > now + (2*(1000*60))) {
                Serial.println("Sending 2 minute ON message to Twilio!");
                client.publish(
                        sync_document, 
                        "{\"msg\":\"Ahoy!\",\"led\":\"ON\"}\0"
                );
                now = millis();
        }
        */
}