(upbeat music) - Well, hello there, Cloud Gurus and welcome to another ACG project. In this project, we're gonna explore AWS
Greengrass and IoT devices. Specifically, we're gonna
turn this pile of parts into an off-grid remote controlled image and data collection device. We'll be using a Raspberry
Pi Zero, a Pi Camera, a cellular modem, and some other bits and pieces along with AWS Greengrass version two. Yes, you heard correctly there is now a Greengrass version two which was released at the end of 2020. AWS still supports Greengrass version one, which they now lovingly refer
to as the classic edition, but they are encouraging new development to use the version two path. And that's the path we're gonna take. No worries if you don't
have a Raspberry Pi, you can still follow along and learn. Turns out that a t4g.nano
EC2 instance does a reasonably good job at standing in for a Raspberry Pi 3 or 4. So I'll first take you
along the path of getting a nano size EC2 instance set up as a Greengrass version 2 core device. And we'll get it to send
and receive some messages. In the second half of the project, we're gonna be working
with this little guy, a Raspberry Pi Zero W, and assembling a solar powered off-grid data collection station. So if you're like me and you have a few of these
little devices lying around, let's go put them to work. Here's the set up for our project. We've got some good news
and I've got some bad news. The good news is that
our scrappy space startup has just won a very lucrative contract to deploy thousands of
data collection sensors on the surface of Mars. The bad news is that virtually
all of our plan budget will be needed to actually launch and land the devices on the red planet. We've been tasked with building
out a device management and data collection system on the cheap. Upon requests, the device
will need to snap a picture and collect environmental readings. Since data connections on
Mars aren't very stable, the solution will need to accommodate intermittent connectivity plus there are no power plugs on Mars, so it will have to be self-powered. Now, before all you space buffs start picking apart this premise, I'm gonna ask you to suspend
disbelief for a little while. Yes, I'm sure that space radiation would ravage our off-the-shelf components. And while I'll be using a
cellular modem for connectivity, I'm quite sure that there's
not a 5G data network on Mars just yet. Heck, we're not really even a
scrappy space startup, are we? But remember when we were kids
and we played make believe, anything could happen in our imagination. Let's go back to that
place for a little while. For our architecture, we're gonna use AWS Greengrass version two as our control plane. We'll outfit our Raspberry
Pi or FakePi EC2 instance with the needed components to turn them into what
Greengrass calls core devices. Core devices can act as data
collection points themselves and they can also act as local
proxies for other devices. Sort of like a collection point or a gateway back to Greengrass. To communicate with our core devices, we're gonna use MQTT. MQTT is a lightweight
messaging protocol used widely in IoT applications. If you're familiar with other message
queuing design patterns, you'll be right at home with MQTT. It's cues are called topics
and devices can subscribe and publish to topics to
send and receive messages. This is how we will send
instructions to our devices and get responses back. We're also going to have our device upload the captured image to an S3 bucket. For our physical device, I'm gonna be using a
Raspberry Pi Zero powered by a lithium ion battery
pack and a solar panel. We'll connect it to the
internet with a cellular modem or as it's called in the
Pi world a cellular hat. Then I'll cram all that
stuff into a waterproof box to see just how long the
thing can stay online in the elements. Let's get started. As I said in the intro I'm
gonna do this demo two ways. The first way will be with an EC2 instance for those that don't happen
to have a Raspberry Pi. The second way will be
with a Raspberry Pi Zero. For the EC2 version, we'll be using a t4g.nano Arm64 instance with a Debian 10 AMI, which is a reasonable stand in for a Raspberry Pi 3 or four. For the Raspberry Pi Zero, it uses an Arm 6 architecture with a very small memory footprint. So it's gonna require a
little special treatment. To get started with our FakePi version, let's spin up a t4g.nano
instance and SSH into it. Note that I'm using a Debian 10 AMI and the default login user is admin. (soft upbeat music) The first thing I always
do with any new instance is to make sure it's up to date. Once that comes back, we'll need to install some components. Unzip python3.pip cmake and a relatively recent
Java virtual machine. AWS will recommend that
you use their Corretto JVM, but I've had good success with OpenJDK and some other more specialized JDKs as we'll see in the Pi Zero version. While that's installing, let's go do some other work. First, we're gonna create an S3 bucket. This bucket will be used for hosting our Greengrass
custom component artifacts as well as our data
that our probe captures. (soft upbeat music) Now let's go do some IAM work. We'll first create some
policies and roles. And since we're gonna be
using auto-provisioning with Greengrass, we need to create a role which will allow our devices enough access to provision themselves. (soft upbeat music) I'll call this policy custom
Greengrass provision policy. Since we're here in policies, let's create another policy we'll need. This policy will allow
our Greengrass devices to access S3, which they'll need to both
download our code components and also upload our captured device data. We'll call this policy
custom Greengrass S3 access. Now, I'm gonna create a user account that we can use for device bootstrapping. I'll call it Greengrass bootstrap, and we're only gonna need this for it's access keys and secret. Save these somewhere as
you're gonna need them later. We also need to assign the custom Greengrass provision
policy to this user account. (soft upbeat music) From the IoT console, go to Greengrass, then core devices. We're gonna set up our
FakePi as a core device. We'll click on setup one core device. And for the device name, let's just call it FakePi. For group, we'll call
our group MarsProbes. Now the group is important in
that we can deploy components to the group and everything in that group
gets the same deployment. Pretty handy if you're dealing
with thousands of devices. The console will generate
two command lines for you. One to download and unzip the
Greengrass core components and the other to install
and provision the device. First, we need to set the access key and secret from our
Greengrass bootstrap account as environment variables on our instance. Now, AWS will tell you a better way is to use STS to generate
temporary credentials and assume the provisioning
role that we set up. In the end you'll
ultimately get an access key and a secret that you can
export as environment variables just the same. These won't be saved by
Greengrass in any way, and we'll go away on the
next log-out or reboot, so this is a pretty low-risk activity. And before anyone freaks out
that I showed access keys and secrets in this video, do know that they are long gone as soon as this video was captured. Copy and paste both lines and execute. After Greengrass installs, you should see it show up in the console under the Greengrass core
devices after a few minutes. (soft upbeat music) You now officially have a
Greengrass IoT core device connected to AWS. Now, because our devices
are pretty light on RAM, we're gonna need to tweak the
default Greengrass settings to let them run a little smoother. You can skip this step, but you might run into lots of swapping when the meager memory
is used up by the JVM. And that slows things way down. To make this adjustment, we need to revise our deployment such that it sends a
specific JVM configuration to the device. The component that we'll be setting is called AWS Greengrass nucleus. We first have to select our deployment that contains our device. Off the list of public components, I'm gonna select AWS
Greengrass nucleus and next. Now here's a key part. Select the radio button
next to the component and click configure component. You'll see on the left-hand
side of the screen the default configuration. And we need to add some extra JVM options, so we're gonna paste
that on the right side of the screen. This bit of configuration is
the recommended configuration for a reduced memory footprint. AWS docs do also have an
absolute minimum version of this command, but I ran into errors when
they tried using that version. This reduced configs seems to work nicely. We confirm our changes and just keep hitting next then deploy. We can watch the deployment
happen over on our device by watching the Greengrass
log or watching the processes using something like top. After things appear to quiet
down on the log activity and our deployment status
changes to completed on the deployment console page, we know that we've deployed
the new memory settings. Now, sometimes I have seen
the deployment get stuck at active when by all indication the deployment actually completed. I didn't pay too much attention to this. But in this case for good measure, I prefer to reboot my device
after that memory change. I've seen cases where the
change didn't take effect even after restarting
the Greengrass service. Rebooting seemed to do the trick. Next we're ready to build our component. For this EC2 example, I created a simple Python
program that uses the AWS IoT SDK to listen to a topic and respond when something appears on that topic. We need to create two parts. The first is the actual Python program, and the second is a
recipe in JSON or a YAML. The recipe describes all the dependencies, access, and artifacts
that our component needs. I put lots of comments in the code, so I'm not gonna step through that here. Now, there are a few important
parts to this recipe. You can do it in JSON or YAML. I just prefer JSON. The version is important here as that will signify the unique
versions of this component. If you start playing
around with this example, you'll probably have several
versions as you debug. This bit here lets us
publish and subscribe to the IoT Core MQTT topics. In production, you'd probably crank these
down to just specific topics, but I left it wildcard here. This dependencies part is really important as it lets our component be
able to get access tokens, to access other AWS services. In our case that will be S3. In fact, let's go handle that
little bit of IAM right now. When you provisioned
your first core device, the process created a few
IAM policies and roles. If you left everything default, you should find a role called GreengrassV2TokenExchangeRoleAlias. This is the role that our
core devices will use. They don't use it directly, but rather that token exchange
service handles the magic behind the scenes. Because we want our devices to be able to get input from S3, we'll add that policy we created earlier, the custom Greengrass S3 access. (soft upbeat music) Let's also copy our Python
artifacts out to S3. Getting back to our recipe, the last part of this
file will tell Greengrass what to install and how
to run our Python code. In our case, we need to use pip to install some dependencies
before we run the command. And our run parameter
contains our show commands to get our program kicked off. Notice the -user parameter on pip and the -u on the Python shell command. Our Greengrass processes will run as a special
Greengrass user account created during provisioning ggc_user. We want to be sure that the dependencies and the Python is being run
within the scope of that user. With our Python code out on S3, we are ready to create our component. From the Greengrass console, select components and create component. Here's where we paste
in our JSON or YAML file that we just created. This JSON file should contain
everything that AWS needs to get your component ready to deploy. (soft upbeat music) We can then click deploy and we're asked if we want to add this to an existing deployment
or create a new one. Let's just add it to our existing one. Proceeding through the screens, we'll then see our new
component under my components. And we'll also see our existing
customized nucleus component under public components. We want to leave that one
checked otherwise Greengrass will think we wanna remove
nucleus from the core device which would be bad. Next, next, next, then deploy. (soft upbeat music) Same scenarios last time. You can watch the deployment
from the Greengrass log and you can also watch the
component being deployed by watching the simple Pub/Sub log file. If you go into your deployments, you'll notice that it also has versions. You can revise deployments to set new parameters or customizations or you can add and remove components. If you wanted to remove the
simple Pub/Sub components, I could just revise my deployment and uncheck that component, it would then be removed. Now, what happens if
your device is offline? Well, that's a strength of Greengrass. It's designed to work with devices that have intermittent connections. The next time your device
gets connected to AWS, it will receive its set of instructions and do whatever it needs to do. You can test this by
stopping your EC2 instance, setting up a deployment
then starting it back up at some time in the future. Same thing goes for MQTT messages as we'll see later with our Pi Zero path. In fact, let's go send some MQTT messages. We can do that from the test console page. First, let's subscribe to some topics. How about all topics so
we can see everything. We'll just enter hash or pound or whatever you call this
thing in the topic filter. Now we can send a message to the topic that our Python code is listening on. We choose marsprobes/request
and enter some message. (soft upbeat music) We should get a response
back with a URL to a file the component placed out on S3. So this is good news. We're able to send and receive data from our IoT core device. Moving on to the Pi zero, ultimately I'm gonna assemble this Pi Zero with some additional components such as a power controller and
a battery and a solar panel and an LTE cellular modem. That detailed installation is
going to be on the GitHub repo for this project. For now, let's just get
it working over wireless. Now I'm not gonna cover
setting up a Pi Zero as there are plenty of
tutorials out there on that. Just remember to use the light version of the Raspberry Pi OS. And remember to set up the
wpa_supplicant.conf file for Wi-Fi and drop an SSH
file into the boot partition if you're running the zero headless. Meaning without a monitor and keyboard. To get the Pi Zero running Greengrass, the setup is pretty much the same except for a few differences. First, I'm gonna do my updates. (soft upbeat music) We need to install some
dependencies except the OpenJDK as we did on our FakePi. Those include unzip if
it's not already installed, pip and CMake. (soft upbeat music) Next, we go into raspi-config. I'm gonna enable the Pi Cam interface. And because I'm using a cellular modem, I'm gonna go ahead and
enable this serial port. I'll also expand the file systems
since I'm already in here. Next, I'm gonna save some
power by turning off audio and turning off the HDMI interface. (soft upbeat music) Now here's a key difference
between using a Pi Zero versus a Pi 3 or a Pi 4. Pi Zero uses an Arm 6 architecture, and the OpenJDK 11 in
the Raspberry Pi OS repo will not work with the Arm6 architecture. So we have to go looking elsewhere. I found a special Zulu
Arm 6 JDK 11 from Azul. Here are the commands to install that. (soft upbeat music) And then we can proceed
with the provisioning of our core device via the console and the copy paste commands. (soft upbeat music) If we place this device
in an existing group, it will automatically
pull down the components from our deployment
including the JVM settings. If you don't place the
device into a group at first, you can do that later and then the device will
automatically download the latest deployment and
component versions for that group. Now, for our Pi Zero, I've created a custom component that will listen on an MQTT topic, snap a picture and upload to S3, and then respond on a different MQTT topic with a URL to that picture. In my testing though, I've noticed that trying to
deploy the new JVM settings and the snap picture
component all at the same time just puts too much stress on the Pi Zero. So I'm gonna leave it out of a group and create a deployment that
steadily rolls things out. I'm gonna send down the
JVM config update by itself and then send down the
custom Python program later. (soft upbeat music) Do be sure that you give
Greengrass plenty of time to finish its deployment especially on the relatively slow Pi Zero. You can keep tabs on
it by watching the logs or watching the processes in top. While we're waiting for
Greengrass to do all that stuff, let's add the GGC user
account to the video group so that it can access the camera device. I also want to add this
user to the GPIO group as I'll have a temperature
and humidity sensor which uses the GPIO pins. Once everything is settled, we can now reboot the Pi just to make sure that the JVM parameters
have been properly applied. While that's happening, let's go back to our console and create our snap picture component. Same method as we used
for our first component. One thing that I discovered is that apparently your
artifacts must be contained within a bucket in the same region as the Greengrass instance you're using. Those eagle-eyed viewers might've noticed that I'm doing this demo in us-west-2 whereas I did the FakePi
demo in another region. To get the component to work, I had to create a new bucket and copy the artifacts out to that bucket. Also, I had to add the new bucket to the custom S3 access policy so the Greengrass process
can reach the bucket for downloading the artifacts. (soft upbeat music) You'll see that in this recipe we're adding the Pi Cam Python library and an Adafruit library for a DHT sensor. When this component is deployed, the device for the first time the pip command will pull down and install all the components. Now downloading and installing
all those components for the first time takes a while. And I have noticed sometimes the Greengrass deployment
process times out waiting for all the components to install. I'm sure we could adjust
the timeout somehow, but we're gonna help things along by pre-installing those components. But we must install those under the Greengrass runtime user account. So now with the first
deployment of our component, pip will notice that
we've already satisfied the dependencies and
shuffle right on along. Now, just a word of caution here. If you still have your
FakePi instance running and you deploy it to that instance, the deployment will fail on that system because Pi camera won't install on a non-Raspberry Pi device. So the pip command will air out and thus make Greengrass report that the installation failed. You can ignore this or remove
that device from the group if you'd like. Once deployed, we can again
go out to our MQTT test bench and send a message. If we're living right, we'll get back at JSON
response with a URL to an image that was captured. Do keep in mind that the little
Pi Zero isn't very powerful. And in my case, it was taking up to a good 10 seconds or so before I got a response back, especially over cellular. Of course this delay would be greater if we had the Pi configured to
only connect to the internet say every 10 minutes for example. But that's the benefit of the
MQTT messaging queue approach. It's designed for those types
of intermittent connections. In the MQTT test console, I can set attributes for the message and I can keep that message in the queue until the device comes back online. We can demonstrate this by shutting down the
Greengrass process on the Pi. Then creating our message with the retain message flag selected. (soft upbeat music) Then when we start back
up the Greengrass process, it will see the new
message and act upon it. As Greengrass comes back up, it sends some status
information on the MQTT queue that you'll see here. And once our snap picture
process is up and running, we should see a response come through. And here it is. Additionally, the core devices
can also act as a local proxy for MQTT messages for other local devices. And this is really
useful for those sensors that don't have the capability or capacity to store
or queue data locally. Now you can have some more
fun with MQTT and Greengrass by using a tool like Node-RED
to build some simulations if you like. But the rest of this video
will focus on building out the hardware components of our MarsProbe. This physical build consists
of a few basic components. We'll start with the brains, the Raspberry Pi Zero W. I've customized this Pi
slightly by soldering on the GPIO pin outs. I'm using a SanDisk ultra
32 gigabyte micro SD card, loaded with Raspberry Pi OS light version. I'm also using a Pi Camera version 2.1 with the special Pi Zero connector ribbon. For power, I have a UUGear
Zero2Go Omini power controller. It's a neat little device that can accept three
different power inputs and switch between them
regulating the voltage for the Pi. It also senses the incoming voltage and gracefully powers down the Pi when the voltage is too
low and powers it back up when the voltage is at a sufficient level. And this is perfect for
solar-powered applications. I also have an Adafruit
solar charge controller which can power the Pi
and charge the battery when the sun is out and
switch over to the battery when there isn't any sun. I did customize this component by adding a 4,700 microfarad capacitor which acts as a sort of electron buffer and allows for a smoother
transition between power sources. Powering the rig is a
4,400 milliamp LiPo battery and a voltaic six volt
3.4 watt solar panel. I also fabricated a little
bracket for the solar panel from some scrap aluminum
angle stock I had on hand. It's not shown here, but you saw it in the intro and you'll see it again in the outro. Playing the part of the
environmental sensor is a DHT22 temperature and humidity sensor connected to the GPIO pins
zero and six for power and to pin 26 for data. For our internet connection, I'm using a Sixfab Cellular IoT HAT with a Twilio Super SIM card. This SIM card is awesome. And then it works pretty
much anywhere in the world. For me, located in the
US it provides access to the AT&T and T-Mobile data networks depending on whoever has
the strongest signal. Now, this modem can use
the UART serial port if stacked on the GPIO pins. But I've found that the
USB connection method had way better data performance. To use the USB cable for both data and power with a cellular hat, I did have to jumper two
pads on the board itself. For the case, I picked up a cheap weatherproof case from my local big-box
store for about $6 US. I spray painted it white
and drilled two holes in it, one for the camera, which I covered by gluing a thin piece of clear plastic over it. The other hole is for the
solar panel connection which I'm gonna seal with silicon. On the inside, I used heavy duty 3M Velcro
to stick the components to the side of the container. And that is my self-contained MarsProbe. So what were some of the
lessons for me on this project? Well, I learned that
there was a decent number of resources out there for
Greengrass version one, but not much at all around version two. Hopefully this project will help fill in some of that empty space for somebody. I also learned that with version two, AWS seems to be de-emphasizing
the use of lambda functions with Greengrass. And this doesn't hurt my feelings at all. With version one, I often found that using lambda was kind of an extra layer of complexity that didn't really seem necessary. And there are still some rough edges in the user interface
and overall experience. The Greengrass CLI is
limited not intuitive at all, and it doesn't seem like we
can delete old deployments and I had phantom
components still associated to core devices that I
had long since deleted and re-provisioned. For someone who likes to keep
a meticulously clean console, these little leave-behinds really bug me. In fact, to keep a clean console for the recording of this video, I had to hop around to different regions so as not to leave you
with a bunch of leftovers on the screen that might
confuse people trying to follow along. Overall, this project was a pretty steep learning curve for me. I ran into many roadblocks and dead ends and I wasn't sure if I
was doing something wrong. Maybe I was running into a platform bug or maybe I was using some outdated documentation or examples. But that's the learning process. We have to keep trying different things until we land on something
that seems to work. So I certainly don't consider this project to represent a reference architecture for a major production IoT deployment, but maybe it helps spark
an interest in the topic for someone somewhere. What's next? How about a Mars Rover. I'm Scott Pletcher, thanks for watching. Stay safe, take care of one another and keep being awesome Cloud Gurus. (soft upbeat music)