Importance of Natural Resources

Connect Thread Devices to the Cloud with IoT Core (Google I/O’19)


CALUM BARNES: Good
morning, everyone. Thanks for joining us
on day three of I/O to talk about Thread
and Google Cloud. My name’s Calum Barnes. I’m a product manager on
Google Cloud IoT Core. JONATHAN HUI: And I’m Jonathan
Hui, principal software engineer at Google Nest and VP
of technology for the Thread group. CALUM BARNES: So we’re super
excited about this session today and to tell
you a little bit about things that are happening
in Thread and IoT Core. Before we get started,
can we just see– maybe show of hands– how many of you here have
heard about Thread before? OK. Most of them. That’s pretty good, Jonathan. And what about IoT Core? Or used Google Cloud
in any way before? Also pretty good. OK. So if you haven’t heard
about them, don’t worry. We’re going to give
a little brief intro when we get started here. If you have, I think we have a
really, really exciting session today, because we are
going to be demoing, for the first time, MQTT and
TCP over a Thread network all the way up to the cloud. And we’re also going to be
showing co-op communication to IoT Core. But before we get
started, I want to talk a little bit about what
our requirements for the device that we’re going to
build and demo today are, and how they differ from,
maybe, some of the current IoT devices, whether they be smart
home or commercial buildings that are on the market. So for the devices we’re
going to build today, we want them to be
very, very low-power. So this means not just
having long battery life, but also being able to work
on very, very small batteries for long amounts of time. Next, we want no proprietary
hubs or gateways. We don’t want to have
proprietary application layers or require users to
install new hardware for every single
device that they buy. And finally, we want IP
all the way to the edge. So we want our devices to work
with the existing internet standards and protocols
that we know are secure and are comfortable
working with. But before we get into how
we’re going to do that, I want to talk about the state
of wireless products today. And I think this is
true whether you’re talking about smart home, smart
buildings, industrial wireless products– I think it really
runs the gamut. So today we have a lot of
devices that are using Wi-Fi, using 802.11. And this works great for
many classes of devices. If you have a camera,
smartphone, or laptop, something where you can
recharge the battery, you need to use a lot of
bandwidth, Wi-Fi is great. But for devices that need
to be very low-power, Wi-Fi isn’t as good. You need to either be able to
recharge the device frequently, like your laptop or phone, or
you need to do a lot of tricks to end up making it be
very low-power over time. The other issue
with Wi-Fi is when you start having lots of nodes. So especially for your average
consumer’s home wireless setup– if you want to connect every
single light bulb or light switch in your
house, you’re going to have an issue doing that
with your traditional router and still have the rest
of your devices work. So we know that
even though there’s a lot of good Wi-Fi
infrastructure in place, it’s probably not
the technology we want to use to build our
next-generation wireless and IoT products. So I know what a lot of
you might be thinking. Well, there are good solutions
out there for this today. We have Bluetooth. We have ZigBee, we have Z-Wave– a number of wireless
technologies that will help us build lower
bandwidth but lower power consumption and also scale
to large numbers of nodes in small spaces. However, while these do
address a number of the issues that we’re looking for, they
have one critical fallback, and that’s that they need
lots of these IoT gateways. So since they depend on their
own radio technologies– usually proprietary application
layers and tightly linked application back ends– you can end up in
situations where, if you have multiple products
from multiple vendors– or even, in some cases, multiple
products from the same vendor– where you end up with a whole
host of these devices connected to your router at
home, or it can be even worse in industrial
or commercial IoT settings. And while this does work
from a technical perspective, I think it hurts user
adoption in a couple of ways. One is it drives up cost. If you need to sell a gateway
with the first light bulb that your customer buys, or the
first whatever your product may be, you’re probably
more than doubling the cost for that very
first entry point. Next is it creates confusing
user setup experiences. Nobody wants to
have a lot of these or go through having to learn
the differences between setting up a Wi-Fi device versus
a Bluetooth device versus a Zigbee device. And finally– and I think
what the largest problem is– is it encourages silos. So the manufacturers
of these gateways want every product to
work with their ecosystem, and so we end up with
silos of functionality as opposed to real network
interoperability like we want to build. So I think these are
some real problems. But luckily, we’re
pretty close to having a solution to help with it. JONATHAN HUI: So we were
facing these exact problems that Calum was talking
about at Nest, where we wanted to build products
for the connected home where we were keeping users
not only comfortable, but also safe and secure. We wanted to build solutions
where our devices could communicate securely with
each other to cloud services and to users via
their mobile devices. We also wanted to have those
devices to be very low-power, because we wanted those
devices to last for years on very small batteries. But as we evaluated existing
communication technologies, we could not find a
single technology that satisfied our requirements. So in 2014, Nest, along with
a number of other companies, founded The Thread Group. The Thread Group is a
non-profit organization with more than 100
member companies from around the world. And The Thread Group is
responsible for defining and maintaining the Thread
protocol specification. it serves as a market
education group for promoting the use of
Thread in connected products. And it ensures a
great user experience through a rigorous
and meaningful product certification program. So in summary, the
thread protocol is an open, IP-based, low-power,
secure mesh networking technology for
connecting IoT devices. It supports the
same IP technology that drives every
internet-connected device, but is designed to support
very low-power applications, including devices that operate
on coin cell batteries. Now, for the radio,
Thread uses IEEE 802.15.4. It’s the same radio that’s been
used in ZigBee for 15 years. Using an existing
widely-deployed radio allows Thread products to
achieve fast time to market, as well as leverage
existing economies of scale to achieve low-cost solutions. Now, at the network
layer, Thread uses existing IETF
standards for supporting the internet protocol version
6, or IPv6, over 802.15.4, radios, a technology
called 6LoWPAN. Now, Thread support for
the internet protocol is a key differentiator, and
most existing technologies do not support IP. So why is IP so powerful? Well, first it means that we
can build solutions that utilize a number of link technologies,
including Wi-Fi, cellular, and Thread, and have all of
those devices communicating with a common single
application layer end-to-end without needing to build and
maintain application protocol gateways. And at the same
time, it means we can have a single
network that can support multiple
applications simultaneously. IP makes it easy to
deploy new applications, and it was a key reason for
the success of the internet. Thread extends that benefit
to low-power devices. Specifically for
this session, it means that we can build
battery-powered devices that communicate securely
end-to-end with Google Cloud IoT Core, without any
application layer in between. CALUM BARNES: OK,
so now we’ve seen how we are going to use
Thread as the radio technology to build these products. And we also know
that Thread is going to give us an underlying
IP layer link, which means we can use just
about any cloud back end that we want to connect
these products and leverage data from them or
interact with them. But let’s talk
about first what we need to think about when
we choose a cloud product or choose a cloud to use. There are a lot of
options out there, and I think a lot of them
will probably satisfy what we’re going to do today. But there are two big things
that you want to think about. First is security, and
the second is scale. So security is always
important in IoT. It’s a very often
written-about topic. I’m sure I don’t need to
tell people at IO about all of the high-profile
leaks that have happened or botnet attacks
that have happened. But what is going to drive
more security in IoT, I think, starts with
identity and having a strong underlying
identity for our products. So we want to make sure
that whatever we choose is going to allow us to
put a cryptographically strong and unique
identity on the boards that we’re going to
use in the demo today. And next is scale. I think there’s a
few things to think about when you are
thinking about scale in the context of IoT. One is we are thinking about
large numbers of devices. So over time, we
think there might be millions or tens
of millions of devices that we might sell
into market and need to connect to this cloud. So we need a
solution that we know can scale up to very
large numbers of devices. But we should also realize
that, at the very beginning, your IoT deployment or
solution might be just like ours is onstage, where you
have just one or two devices. And for this reason,
you want whatever you choose to scale from
an economic perspective when you still have just
a few devices in market. So to do this today, we’re going
to use Google Cloud IoT Core. IoT Core is Google
Cloud’s managed service for connecting IoT devices
to the Google Cloud network. It provides two important things
that we’re going to show today. So first is device identity. It provides a mechanism
for distributing key-based identities to devices. So every device will end up
with its own unique private key, as well as the corresponding
public key trusted in IoT Core. These keys can be used in
a couple of different ways to connect and
authenticate to the system, and Jonathan is going to
talk more about that later. The other thing it offers is
a protocol bridge and support for common IoT protocols
like MQTT and HTTP. But this protocol bridge
is completely serverless and will scale with
our application. So it’s easy to connect
just a few devices to it, and we’ll only have to
pay for the bandwidth used by those couple of devices. But it will also easily
scale up to hundreds of thousands or millions
of devices deployed all over the globe,
without us having to change any code or deal
with managing the back end. But connecting the
devices to the cloud isn’t the whole story. We need to actually communicate
back to the devices or leverage the data that they’re sending
to us if we want to build an actually useful application. And luckily, Google Cloud
can help with this, too. So we’re going to, today, try
to leverage all serverless tools that will scale elastically with
your application the same way that I just talked
about IoT Core doing. So the first thing
that we’re going to use is Google Cloud Pub/Sub. So all data sent from
IoT devices into IoT Core end up as a message on
a Cloud Pub/Sub topic. Pub/Sub, if you’re
not familiar with it, is a scalable message bus to
build event-driven serverless or microservice applications. So you’ll never have to
worry about scaling for peaks or dealing with losing data. The next thing we’re going
to use is Cloud Functions. So a Cloud Function is
a small snippet of code that can be written in a
few different languages that are supported right
now, and it allows you to do event-driven development. So this function can fire
every time an event occurs or at a regular interval. In this case, we’re
going to use it to process each message
in each event that comes into our Pub/Sub stream. This will make it easy to,
again, scale our application, but also build it. And finally, we’re going
to use Cloud Firestore. Firestore is a flexible NoSQL
database hosted and managed by Google Cloud. And you’ll see the query system
and real-time update nature will make it easy for us
to build this application, but also, in the future,
build a mobile application or other application
that leverages that data. Google Cloud has dozens
of other services that can help with
building your application, but these are the few that
we’re going to use for the demo today. JONATHAN HUI: All
right, so let’s get to some of the fun
stuff and actually show you how we can build some of it. As I mentioned,
Thread support for IP makes it possible
for a Thread device to communicate securely and
end-to-end with IoT Core. In the middle, there is
a Thread border router that’s responsible
for forwarding packets between
the Thread network and the public internet. And note that the Thread
border router simply forwards IP packets at the network
layer, and does not need to implement
any application layer logic or proxy. In fact, the Thread
border router has no knowledge
of MQTT or HTTP, making it easy to deploy new
applications without having to update or maintain
application layer proxies in between. Now, three years
ago, here at I/O, we launched the
OpenThread Project. OpenThread is an open-source
implementation of Thread, and it is the same
implementation that’s used in Nest products,
including the Nest Hub Max that was announced here at I/O. The Open Thread Project
is hosted on GitHub and licensed under BSD-3. And it’s seen
widespread adoption. OpenThread has been ported to
more than 10 different 802.15.4 radios, and you can
find example drivers for each of those on GitHub. Now, in today’s demo, we’ll
use the Nordic nRF52840 system on chip. We actually brought a few
of those here with us today for use in our demo, so let’s
take a look at them on stage. You’ll see a couple
dev boards on the right and then a USB dongle attached
to a Raspberry Pi on the left. The nRF52840 is built around
a 32-bit Arm Cortex-M4 with 256k of RAM,
1 meg of flash. And they’re really intended
for low-power, low-cost applications. Now, these dashboards
are publicly available, which means you can go home
and replicate everything we’ve done on stage today. All right, so let’s
get back to the slides. Let’s get started with MQTT. Now, for those of
you that don’t know, MQTT stands for Message
Queuing Telemetry Transport and is one of the most
popular transport protocols used in IoT applications today. MQTT implements a
publish/subscribe model on top of TCP/IP. Now, in this example,
we’ll walk through how to build an MQTT over
Thread endpoint that communicates securely,
end-to-end, with IoT Core. We will leverage
third-party software. For networking, we’ll use
Lightweight IP, or LwIP, allowing us to leverage
application frameworks that have already been built on
top of LwIP, including MQTT. For security, this example
leverages mbedTLS and a JWT C library for security. And for the RTOS,
we’ll use FreeRTOS. Now let’s walk through
some of the code. So here’s the main control loop
that runs on the Thread device. It’s pretty simple. It starts by establishing
an MQTT session to IoT Core, and then it sits in a while
loop, publishing telemetry events every two seconds. So let’s dive into the
connect method first. The first step is to specify
the MQTT connection parameters. MQTT uses TSL for
transport layer security, so we have to set up the
private key and certificates for use for TLS. We also need to
specify other MQTT parameters, such as the client
ID and keep alive values. Now, at the bottom,
the device must also prepare a JSON Web Token. Let’s take a closer look at
what that JSON Web Token is. Now, as Calum
mentioned, IoT Core provides a device
identity system. A JSON Web Token, or JWT,
is a compact URL-safe means of representing claims, and is
used for device authentication with IoT Core. A JWT is composed
of three sections– a header, a payload
that contains a claim set, and a signature. The header and payload
are JSON objects. And the header
consists of two fields that indicate the
signing algorithm and the type of the token. The example here uses
RSA, but IoT Core also supports elliptic curve. Now, the payload contains
a set of claims that is signed using asymmetric keys. IoT Core requires three claims– the Issued At, which is the
timestamp at when the token was created, the Expiration,
that is the timestamp when the token stops becoming
valid, an Audience that contains the
cloud project ID where the device is
registered, and then, finally, the Signature contains a
cryptographic signature of the concatenated
header and payloads. So, in code, creating
a job looks like this. It leverages the JWT C
library when we first create the object, then set the
signing algorithm for the JWT, we add the Issued
At, Expiration, and Audience claims. And finally, we
code jwt_encode_str, which generates the
signature and writes it out in the proper encoding. So, that’s how we generate
a client’s authentication material for IoT Core,
and more generally, the MQTT connection parameters. The next step is
to perform a DNS Lookup for the MQTT endpoint. In this case,
mwtt.googleapis.com. Now, with the IP address
for the MQTT endpoint, we can then initiate
an MQTT connection. So, that was connect. Pretty simple. So, now, let’s take a look at
how to publish telemetry events using MQTT. In this example,
the telemetry events are really simple
temperature data. The first step is to format
the payload, in this case, using JSON, and then we call
MQTT Publish with the payload and specify an MQTT topic of
/devices/mqtt-device/events. MQTT-device specifies
the device ID. And events indicates that
this is a telemetry event. That’s it. Pretty simple. So, now, let’s
take a look at what how this works in a live demo. In this demo, we’ll be
using a Nordic dev board as the MQTT endpoint. The Nordic dev
board communicates securely end-to-end with
IoT Core’s MQTT bridge. Now, the thread border router
will use a Raspberry Pi with the Nordic USB dongle. For the cloud application, we’ll
have a simple Cloud Function that processes telemetry
events and saves them to a Firestore database. So, let’s take a quick look
at the physical devices again. So, the dev board in the
middle will be the one that we use for
the MQTT endpoint, and that’ll communicate
wirelessly via the Raspberry Pi end-to-end with IoT Core. So now let’s switch over
to my laptop and show you some live demos. So first thing
I’ll do is actually pull up on the cloud side. Just kind of show you to
the Cloud Function here. So, the Cloud Function listens
for the topic temperature events. And each time that
it’s triggered, it simply decodes
the payload, which includes the temperature
data, and puts that into a Firestore database. It’s a very simple
Cloud Function. And then, in our
Firestore database here, we have a collection
that’s just for this demo. And then, we have a document
for the MQTT device itself. And of course, we have some
data that’s set to 0 for now. Now, if we go over here,
I have a console open to a Raspberry Pi. So, as you know, the Raspberry
Pi is the Thread border router. If I do an IF config,
you’ll see at the bottom, the wpan0 interface is
the network interface that represents the Thread network. As you can see,
the Thread network itself appears as a standard
Linux network interface, just like Wi-Fi or ethernet. What I’m going to do
next is start a TCP dump on the wpan0 interface so we can
kind of see some traffic that’s going over that Thread network. Now, what I have also
attached to my laptop is the MQTT endpoint, so
I’ll open a terminal there. And it has a very simple– remember, this is
an embedded device, so it doesn’t even
have a proper terminal, but it has a very simple CLI. And I do IP Adder to
list these IP addresses. Of course, nothing’s listed
yet because it’s not connected. So if I bring the interface up
and start the Thread service and wait a moment,
you’ll see now that it has IP addresses
because it’s now connected to the
Thread network and has obtained the necessary
information to configure those IP addresses. And finally, I’ll
start the MQTT service, go back over to the TCP dump. The first thing you’ll see
is an NTP request-response. That’s the device itself
synchronizing with global time. And then, after
some amount of time, you’ll start to see TCP traffic. That TCP traffic is the
MQTT session itself. Of course, we can’t
see the payload because it’s within a
TLS-encrypted session, but this is to show you there’s
actual TCP traffic happening. You’ll see messages pop up
about every two seconds. And you’ll see the actual
data being presented here liv. And every time it
receives a new message, you’ll see that field popping. So that’s it. So that was our first
demo, demonstrating MQTT talking end-to-end
securely with IoT Core. CALUM BARNES: All right,
awesome, Jonathan. [AUDIENCE CLAPPING] Yeah. I believe that is the
first time, publicly, that we’ve demoed any TCP
protocol and MQTT over a Thread network. So, that’s pretty exciting,
going all the way to IoT Core and then up into our very
simple database application. So, that’s really great,
but MQTT and TCP still require a fair amount of power. This would maybe be
good for a device which has mains power, is
connected all the time, but that you still need
low-latency communication back down to, like a light
switch or a lightbulb. But now, let’s think about a
much more constrained device. I talked about,
at the beginning, wanting to be able to power
a device on just a small coin cell battery. So, let’s talk about
using CoAP with IoT Core. So, if you’re not
familiar with CoAP, it’s the Constrained
Application Protocol, and it’s a specialized
web transfer protocol that’s made for, basically,
exactly what we want to do– very constrained
devices and using very small amounts of power. CoAP is designed to
be a lot like HTTP, and it implements the
widely used REST model. So, servers make resources
available under a URL, and clients access
those resources using the familiar REST methods,
like get, put, post, delete. CoAP was intentionally
designed to resemble HTTP to make it
easier for developers to build applications with it,
but there are some differences. So, at the network layer, you
can see it’s exactly the same– IPv4 or IPv6. And that’s exactly
what’s going to make it easy to use with
our Thread network, but the primary difference
is on the transport layer. With CoAP, we’ll be using
UDP as opposed to TCP. And because of that, for
transport layer security, we’ll also need to use DTLS,
or Datagram Transport Layer Security, which is
specifically designed to function similar
to TLS and provide similar levels of security
for UDP connections. And finally, at the
top, we’ll use CoAP, but from a developer’s
standpoint, this should look mostly like
access and HTTP interfaces. Unfortunately, IoT Core does
not natively support CoAP. But because CoAP and
HTTP are so similar, it’s very easy to
build, implement, or use one that’s already out there– stateless CoAP to HP proxies. So, in this case,
what happens is we’ll use the proxy
URI option in CoAP– an option in CoAP is basically
the same as a header in HTTP– and we will include information
about the URI of the address that we would like the
proxy to access for us. And what will happen,
then, is the proxy will initiate and
make the HTTP request, receive the response
from the server, and then return the response
as a CoAP response, which is a little different than HTTP. But this allows the CoAP
endpoint to use a RESTful HTTP service pretty much as if it
was accessing it directly, but still getting the benefits
of low-power design and CoAP. It’s important to note
that the CoAP HTTP proxy– Jonathan will talk more about
code availability later– but the one that we’ll use in
this demo is available for you to go download and run. It’s completely stateless, so
it should scale very easily with any application using CoAP
and the IoT Core HTTP bridge. So, without further
ado, let’s get into it and then, see it happen. JONATHAN HUL: Yeah. Let’s see how we can
build a CoAP endpoint that communicates with IoT Core. Now, as with the MQTT
example, Thread Support for IP makes it possible to
communicate securely end to end. But compared to
the MQTT example, one difference is the
introduction of the CoAP proxy that Calum was talking about. Now, just to remind
everyone, the proxy provides password authentication
passively to IoT Core, relaying device credentials
directly to IoT Core. And the proxy doesn’t do
anything to validate it. The incoming collect
payload is converted to the required format
for IoT Core HTTP bridge. And the responses from
IoT Core’s HTTP bridge will be returned to the client
with an appropriate CoAP response code. Now, here’s the
software architecture. You may note that
this appears much simpler than our MQTT example. This example runs in bare
minimal environments, and does not include an RTOS. This example also does not
include a third-party IP stack and other application
frameworks. The CoAP protocol is actually
used within Thread itself. So this example can actually
leverage the same CoAP implementation that’s
within Open Thread. So, in short, what makes this
example really attractive is the ability to operate in
very constrained devices that have limited memory
and code space. Again, the code has two
high-level functions. The first is to establish
a secure connection, and then followed by
publishing telemetry events via that secure connection. So, let’s take a
look at establishing that secure connection first. For simplicity, this example
uses a hardcoded IP address, but we could have
done that using a DNS lookup as in the MQTT example. We also need to set up
the security credentials for establishing
the secure session. Here, we use a pre-assured
key cipher suite. Finally, we call OT
CoAP Secure Connect to establish the DTLS session. So, let’s take a look at the
CoAP HTTP proxy implementation in this demo. In this example, the CoAP proxy
listens on a specific path– slash GCP. And the proxy URI option
includes the request URI path that the CoAP proxy uses
when translating that request on behalf of the CoAP endpoint. And it includes things like
the project ID, device ID, and the publish event action. So, with CoAP, we
use the POST method to publish telemetry events. The first part of generating
the CoAP POST requests is to set up the CoAP header. This includes specifying
the path, GCP, and the CoAP proxy URI option, along
with the publish event sub path that indicates that
this is a telemetry event. So, let’s dive into that proxy
URI option a little more. First, we format
the proxy URI path that the CoAP proxy uses when
translating this request. Again, including things like
the project ID, registry ID, device ID. And then, we include the JWT,
which includes the claims that specify the Issued
At, Expiration, and Audience claims that
we talked about earlier. We then pass that
proxy URI string to JWT Create for encoding
and signature generation. And once we have
the JWT, we add that to the CoAP header in
the proxy URI option. So, that was generating the CoAP
header with a proxy URI option. Now let’s take a look at
the CoAP payload itself. Again, it’s pretty simple. Here, we format the telemetry
event data in JSON format as we did in the MQTT example. And then, we append that to the
payload of the CoAP message. Pretty simple. So now, with a complete
CoAP request message, we can send that request
to the CoAP proxy. So now, let’s take
a look at, again, how this looks in action. Again, we’ll use a Nordic
dev board that operates up to this CoAP endpoint. And that Nordic dev board
communicates wirelessly, again, via the Raspberry Pi, serving
as the Thread border router. Difference here is that rather
than communicating directly to IoT Core, it is communicating
with the CoAP proxy. The CoAP proxy, then,
statelessly translates that message into something
that IoT Core can understand, which is HTTP. Now, on the cloud
side, again, we use the same exact Cloud
Function and Firestore database as we did with the MQTT demo. So, let’s go back to my laptop. So, here, the same
screen that I left it. You can still see
the MQTT device still publishing data
every two seconds. But I have another
document here, which is for the
CoAP device itself. And, of course, because
I haven’t turned it on, the data is still set to zero. Now, if I move back to
the console real quick, again, TCP traffic flowing
through the Thread border router on the Thread interface. And on the desk here,
if I pick it up, here’s the CoAP endpoint. It’s a Nordic dev board. The difference here, rather
than being plugged in, just to show how low-power
it is, this dev board, actually, is powered
off a coin cell battery. Right, so, all I’m going to
do is turn the dev board on. You’ll see some green
LEDs, hopefully, blinking, and what you start to
see here is, again, an NTP message for this
device to get global time. You start to see some UDP
traffic up in the console. That was the DTLS session
itself being established. And in this case, it
is event-triggered, so, if I push a button here,
you’ll see UDP messages. And those UDP messages
actually are the CoAP messages being transmitted by this
device through the Thread border router. And if I switch back to the
Firestore database, the CoAP device information,
you can see now, that counter value
is being updated each time I press the button. Pretty cool. So, that was the CoAP demo. CALUM BARNES: Now,
what we’ve shown is two Thread devices talking
through the same border router, using standard IP technology. In this case, we are
talking to the same service and the same ultimate database,
but the important thing to note here is we could just as
easily have been talking to two completely different back ends. These could be two devices
from two different vendors, but they are interoperating
at the network level, and going through the
same border router without having to
worry about or have any knowledge of each other. So, I think that pretty
much wraps it up. Hopefully, this shows
how you, as developers, can think about and use Thread. And as border routers
become more prevalent, you can worry about just
building your devices and having them talk to
your back end services, wherever they might be hosted,
using standard IP technologies. So, if you want to see
the tutorials and code, we have it posted for both
the demos at these links. And if you have
questions, Jonathan and I will be right
outside afterwards. So, thanks very much. JONATHAN HUL: Thank you.


Reader Comments

  1. I have a usecase where we track objects using Bluetootj beacons. Where can i get thread devices that just beacons.. Any good thread devices manufacturers?

Leave a Reply

Your email address will not be published. Required fields are marked *