Kassian's IoT Hour
Presented by: Kassian Rosner Wren
Originally aired on October 9, 2021 @ 1:30 AM - 2:30 AM EDT
Let's dig into how you can use Serverless to supercharge your IoT projects! We'll walk through setting up a remote sensor and LED with Cloudflare Workers, Workers KV, and a Raspberry Pi.
English
Internet of Things
Tutorials
Transcript (Beta)
Hello, I'm Kassian Rosner Wren and this is Kassian's IoT Hour on Cloudflare TV. So what we're going to be doing today is we are going to be working with a Raspberry Pi and I'll actually show you here so we've got a Raspberry Pi 4 and we've got it hooked up to a cobbler and an LED and a temperature and humidity sensor and what we're going to do is we are going to use Argo Tunnel and workers to make these accessible.
So what I've got here is a worker and if I hit refresh here it shows temperature 23.5 which is the last reading that it took from the temperature sensor here in my laboratory and we are going to recreate that and we're also going to recreate IoT.Nodebotanist which is not running right now we will recreate it and so that'll be using Argo Tunnel.
So yeah that's what we're going to do today so let's get started.
We're going to take a look at the GitHub repository. This is at github.com slash nodebotanist slash Kassian's IoT Hour.
Let me just share my screen so you can see what I'm talking about.
Share. Okay so we've got like I said github.com slash nodebotanist slash Kassian's IoT Hour and this is our GitHub repository.
We've got Pi code, worker code, and some you know initial setup files.
What you'll want to do is I've already done all this for you so but you'll want to follow all these instructions which include installing Raspbian using Balena Etcher or some other way of putting an ISO on an SD card.
You'll want the Raspbian Buster zip archive.
I use Buster Lite and you'll burn it to the SD card and then what will happen is you'll you will add a file called SSH extension and then you'll add WPA supplicant.conf.
Oh is the shared screen not coming through? Sorry my producer's letting you know there might be an issue.
Hang on. Okay cool so you can see this that's awesome that's the point.
So setting up Wi-Fi and SSH you'll want to create an SSH file with no extension in your boot drive which will be what shows up when you remove and re-put in the card after you burn the image to it and then you'll also want to add a WPA supplicant.conf which will tell the Raspberry Pi what network to connect to and the reason you do this is that way you don't have to have an HDMI cable and send it manually however you can do it that way this is just one way of doing it.
Then we're gonna SSH in and get started and I've already changed the password online and you'll want to change the password when you get in there and then you'll want to sudo apt-get update and upgrade and that'll make sure you have the newest version of all the packages that are available.
You'll want to install node.js from the node source maintain binaries because this all runs in node and then you'll want to update npm-memories version, change the npm working directory using the instructions in that link and then you'll install some dev dependencies which are forever and node-mon and that will help us run our server.
You'll then want to install the Cloudflare dbaemon. Now what this does is it allows us to use Argo tunnel with our Raspberry Pi.
You'll get the arm build of Cloudflare dbaemon, you'll untar it into a new directory, check that it can be executed, log in, create a config file, then install the daemon with systemctl and then what we'll do is we'll start setting up the code base.
First we'll take a look at our Pi and make sure everything is the way we want it.
So this is SSH into the Pi so when I have an Argo tunnel folder and it's got Cloudflare dbaemon in there so I can say Cloudflare dbaemon version and then I've already installed it so I can say systemctl.
Actually I can make it bigger for you.
So I'll say systemctl status Cloudflare dbaemon and it's running and it's been running so for three hours and 20 minutes and so what I've done is I will go into the browser here and I will go into my Cloudflare account which is nice and separated from everything at work.
I've got nodebotanist which is my personal URL for my portfolio and everything and then yes so Argo tunnel.
So we've got iot .nodebotanist, active requests and uptime three hours so that's that's our tunnel.
So when I go to iot.nodebotanist it's looking at port 8000 of my Raspberry Pi and serving from there.
So let's do something to use that.
So we're going to a directory, we're going to go into my code directory, we're going to create a new folder called test-http-init.
Now we're going to npm init with the defaults.
We're going to npm i restify which is a HTTP server and if you have any questions feel free to ask.
They're being sent to me so I can answer any of your questions about what I'm doing.
Okay now we're going to sudo nano index.js. Now what I'm going to do is because we're live and because I just want to make sure I do this right.
Okay cool got it all right so first we're going to say const restify equals require restify and then we're going to say const server equals restify.createServer and then server .get is the slash and we'll give it an anonymous function.
Actually yes we can still do this.
So we'll say rec which is the request, res which is the response and next which is the next piece of middleware to be run and then we open parentheses and we're going to say res.send typing today hello CloudflareTV and then next.
So what that'll do is it will say hello CloudflareTV and next whenever you get from the server.
Now we're going to say server.listen report 8,000 and the function log server listening.
That's everything.
So we're going to close this out. Yes and we're going to say node next.js.
Oh I forgot a parentheses.
All right no problem we'll fix that. Okay so the server's listening.
So now when I go to we don't want slash temp.
You can see there when I make it bigger hello CloudflareTV. So that's what ArgoTunnel does is ArgoTunnel allows us to access my Raspberry Pi through iot.node botanist without having to you know make the port publicly accessible or anything like that.
Pardon the meowing. My cat has decided to throw a fit.
Anyway so we're gonna make that a little less big and next what we're going to do is set up the robotics to basically be able to go to this URL and we'll say lamp true to turn the LED on and lamp false to turn the LED off.
I'll go into the code for that. First we'll close this server.
We're going to the setup that I have here.
We're going to go into the Pi code and we're going to okay.
So this is where things get a little more complicated than what they were.
So right here what we've got is Raspi.io and Johnny5 and these are libraries that allow us to control robotics with node.
So that's what those are for. We've got Rastify to give us an REST API to deal with this and then we've got bent which we'll use later to make a request to a worker.
So first we create a board with 5 .board and IO is new Raspi.
That's what tells Johnny5 that we're using a Raspberry Pi.
We then create a Rastify server and we create a way to post requests to showtemp .nodebotanist.workers.dev which I'll talk about in a little bit here.
So this is waiting for the board to be ready.
Once the board is ready we let lamp equals 5 LED GPIO 6 and I'll show you where that's hooked up here in a second and then we've got temperature which is a 5.multi because it does temperature and humidity.
The controller is SI 7020 and we're going to have it collect data every three seconds.
We're gonna let Celsius equal 21 which is a pretty standard temperature start because it won't have a temperature for the first three seconds.
Server.getLampOn will set lamp state and server.getTemp will send the temperature.
Function setLampState what we do is we check if the request parameter is true.
If it is we turn the lamp on else we turn the lamp off and then we call the next function.
So let's see how that operates in real time.
So what we'll do is we'll go actually we'll go back to terminal.
We'll quit this and we'll say sudo node index.js. Now this lists servers listening in 48,000 and that's what we talked about earlier.
Okay and that's a normal message so here and resource not found because it does not exist and we're going to say lamp true and then what I'll show you with my camera, okay back to the camera, is the lamp has turned on and if I go to lamp false lamp turns off.
So lamp on and lamp off. So there you go we have full control over an LED remotely via Argo Tunnel and Johnny 5.
So let me put my screen back on. My power cable just fell off.
All right pardon me we're at the reboot my Pi here. Totally normal.
Back to the here and it's going to give me a broken pipe here in a second because we have lost connection to the Pi.
Come on you can do it. Come on buddy. Okay first we'll walk through what the code does.
Actually we can do it this way. That's just the worker code.
Go back here and code and then files, open folder.
Okay why did you not open the folder that I told you to open?
I opened it for you.
I told you to open it. Oh my goodness. Come on buddy. Is it opening in a different window?
No, it's opening in this window.
Let's try one more time from this terminal. Hmm.
Why is code not Okay.
Dealing with a noisy cat.
Anyway all right so we've got that's our function our worker function that we're going to go in with a bit.
Back into the Pi code. Okay so this is, this is a new, what is this?
This will probably make the terminal work correctly.
One more time. Now, sure, why not.
Of course it happened. All right so we're gonna do this and get yanked back and forth.
Okay there we go. So we can go back into the SSH here. So we're back in here.
So let's take, let's go back to looking at the robotics code so okay so the way that worked was again we have a lamp at GPIO 6 and then with the controller for the temperature and again we have params lamp parameter on and so when we set it to true it would lamp on and lamp off.
So what I want to do now is I want to add a strobe function.
So let's set up a function where it'll cause the LED to strobe.
So we're gonna have to kind of retool this code a little bit. What we're gonna do is let state equals rectparams.on and then say if state equals true and then we'll go down here and we'll add an else if and we'll say state equals strobe.
So now we've got our strobe function and we're going to say lamp dot strobe and res dot send strobing lamp strobing.
Okay so we're going to save and then we're going to pseudo node index.
All right now what I'm going to do is I'm going to go back to my browser as we've got lamp and then we'll set it to true and I'll turn on the camera so you can see what's going on there.
Oh that's right stop share.
Okay cool. So we've got lamp on. Okay so that's lamp on and then I'm going to set it to strobe.
Hold it up so that you can see it when it strobes.
There's that and then I'm going to hit enter and you can see it's not strobing.
So we've added a strobe function to our Argo tunnel based application by doing that.
That's cool. Now I want to know how warm it is in my office so to give you a view of what that looks like.
So it's a 24 .8 in here it's getting a little warm but so the way I'm doing this we'll go into right now close this and then we'll so through here what we're doing is we're setting up via Johnny5 and Raspi.io.
We set up the lamp which I showed you earlier and then we set up temperature which is a 5V multisensor which is a controller and with a SI 7020 and again it's going to collect data every three seconds.
Oh right gotta share my screen again. Flipping back and forth back and forth.
Oh I did share screen. No I haven't actually. There we go.
Okay there we go. Now you can see the strobe function we added but also we're working on the temperature sensor.
Let me get back here to chat just in case there's a question.
So now that we have that what we're going to do is we're going to look at the send temp function.
That is just looking for the value of Celsius and sending it as a result.
That is on temp so let's take a look at what that looks like.
Oh it's not running so we can't but I'll show you in a moment.
So I have it set through Argo Tunnel and also through Johnny5 and through workers.
So I have it set through Argo Tunnel to send the immediate Celsius data which I'll show you in a moment and I also have temp .onChange.
It's an asynchronous function console.log this.thermometer at Celsius const response equals await post this thermometer Celsius and then sets the global Celsius variable to this that thermometer at Celsius.
And so what that does is await post uses that bent command that I mentioned earlier and it goes to show temp dot node botanist dot workers dot dev post JSON and so it posts the JSON of temp equals this thermometer dot Celsius.
Now what we're going to do is look at the worker function that takes this in.
So we're going to go to this upper folder and we're going to go to the worker code show temp and then we're going to nano index.js.
Okay so what we've got here is the I used the router template and the way you can do that yourself is you can go into workers manage workers and then workers documentation.
So you go under template gallery and it's the first one.
So you were using Wrangler and we generate a new worker with router and so that's how you get the templates to be your base is you use Wrangler generate with the template.
So now we've got this template we've got the router now we've got async function add temp and what that does is it takes in a request and it takes the JSON of that request console that logs it and then puts the temperature in to the KV store which is created via the Wrangler configuration file.
So the KV store for those who work workers KV for those who haven't worked with it yet is a key value store based on workers so we don't have to worry about an external database or an external KV store.
So yeah we're going to put the temperature in there and then we're going to say temperature added and so we've got an async function to handle the request but this one is the basically the parent function this handles all the requests.
It creates a new router and when you post to just slash it will call the add temp function that we just walked through and when we do r.get it says okay go get the temperature and send it back and return default message for the route.
Then constant response equals await route request and return response.
So it basically gets the response from these r .gets and r.posts and send them back.
So let's take a look at that what that looks like.
What we're going to do here is we're going to go here actually here exit we go into worker code and we're going to say we're going to make this bigger for y'all.
Clear it out and we're going to say Wrangler.
Oh we need one more then Wrangler.
Okay so what this allows us to do a temp 24.7 is we're going to test it so we're going to go in here we're going to say post we're going to change this to application slash JSON and then we're going to give it a body of temp.
We're going to change it to something ridiculous we're going to say 43 just so we know that this works and we're going to say run test.
Temperature added so now when we go to preview and we hit go it returns temperature of 43.
So when we run our server here on the pie.
Now it's listening in and it will send a new temperature so it sent 24.2.
So we're going to go over here and we're going to refresh it.
24.3.
So that is coming from the robot. So the robot is sending a post request to a worker that is then putting that into a workers KB store and then spinning it back out we call it.
So what we want to edit here is I want to add the ability to store multiple temperatures with timestamps and have like a basically eventually turn into a graph of what the temperature looks like in my lab so I can know when the temperature if I'm using my gaming PC for instance does the temperature go up or does it go down or when I'm using multiple laptops I have a lot of computer equipment in here you know what is the temperature like during the course of the day.
So to do that we're going to have to go into the worker code.
Hopefully be able to open up code.
Okay fantastic it worked. Okay so we're going to go under index.js.
Now when we add a temp right now what we're doing is we're putting temperature JSON string body.
So what we want to do instead is take it and turn it into array if it isn't one and add it to the array and then make sure the array doesn't go above a certain number of entries and I don't want it to go too far back and then we're going to want it to add a timestamp as well.
So what we're going to do is we're going to say let current equal awaits temp dot get temperature if not temperature current dot length.
So if current dot length does not exist current equals an empty array.
That way if it's an invalid value or something that will turn into an array.
So then what we want to do is we want to take out this line.
We'll add something back in here.
So what we want to do is we want to current dot push body and then if current dot length.
Let's say it exceeds 50. Then we'll say current equals current dot slice 0, 50 and then we'll do a little bit on here instead of well not just body we'll do body and current and then we'll push current into the temperature.
So this will create an array there and you return your response temperature added.
Now this won't add a timestamp yet but we'll add a timestamp in a moment.
So we're going to save this and we're going to go over here or say Wrangler preview and we're also going to stop our server here so that it will not interfere with this.
So we want to go into testing.
I'm going to say posts. I'm going to say application and we're going to say body is this and we're going to say temp and we'll say before boiling here we'll say.
Oh and that push is not a function.
Okay so oh you know what I know what it is. Hmm.
Let's try this.
Make sure it goes in here.
Body.
Okay it's not going into here.
All right let's see what current dot length is.
Okay.
Well that's that we're going to the terminal and Wrangler preview again. Just iterating on a design until it works.
Posts application and the body is like 13.
Oh because it's a string.
Right. Right. Right. Right. Right. Right. Right. Okay so.
I have an idea.
I don't need it there.
I need it on the line below that. Okay.
Okay.
Justine, that's worse.
This one slash this one. OK. Creating an array, okay, good, good, good, okay, so now we've fixed it, all right, awesome.
Now what we're going to do is attempt to put an incurrent, what we'll say is json.stringify.
Let's save that, let's test it one more time, testing, post, application.json, all right, temp, okay, so temperature added, so I go to preview and I hit go, and it returns an array, which is great, because that means if you do this again, let's change this to 25, and I go over here, preview, and I hit refresh, got two items, now all we need to do is add a timestamp to each one, so go back here, and we'll say, before we current.pushbody, body.time equals time.now, save, go back, a lot of tabs going now, let's close a few, hello cat, you're not supposed to be on the desk, I swear I need to get my door fixed, he can just work his way into the lab whenever he likes, and it's kind of hilarious, and kind of not great at times, okay, so we've got testing, we're going to post, now hopefully what this will do is it will add one with a timestamp, so we have the body with temp, and we'll add whatever temp we want, because it's going to add a timestamp to it, no, time is not defined, you know what, I'm pretty sure it's because it's new, it's been a while since I've used this, I used it in rehearsal, but you know, that's how it goes with these kind of things, we'll have to look it up, okay, so what we're going to do, ah, date, that's what I was, okay, this is in, date.to, okay, we'll use date.toISOString, yes, okay, cool, that's what we're on, I've been using a different language that uses time, toISOString, okay, save, go into here, preview one more time, okay, and then testing, post, application.json, and then temp, date.toISOString is not a constructor, oh, right, you need parentheses in there, right, okay, so, close these tabs, so that I can test it one more time, testing, post, application, json, there we go, and then, so then I go to preview, I hit go, and you can see now this one has a timestamp, fantastic, okay, so from here on out, they'll all have timestamps when they're added, let's test this with the bot, so we're going to take the bot, and we're going to rerun our server, okay, so now when I go here, I hit refresh, oh, oh, you know, I know why, I'm silly, that's because I have not hit Wrangler publish, so I'm going to go back to the browser, there we go, and it's adding new ones every three seconds, so, did it die, let's check, no, it's still running, so we should have more in here, why does it only have two, hmm, let's go into here, and see if, there we go, okay, so every three seconds, it's adding one, and you can see now all of the temperatures, and the timestamps, so our last add-on, before we run out of time here, is going to be adding humidity, so that's going to require changes to the robot, and changes to the worker, so, actually, it's just going to require a change of the robot, because it just, so we're going to close out the server, and then we're going to snow now index, okay, now to look up how we're going to do this, I'm going to pull up Johnny5 website, no, that's not, there we go, Johnny5 website, and we're going to go to the API, and we're going to get a multi, and then a hydrogamer, and we're going to go to the API, si7020, so that's the one that we're using, oh, okay, that's leading us to the Tesla site, the si7020, we're going to go down here to all of them, and we're going to go si7020, okay, so relative humidity is this.hydrogamer .relativehumidity, so I'm just going to copy that statement, we're going to use it, and then we're going to go into our terminal, we're looking in here, and go into, we're at first going to create a function, and then humidity, what I'm doing is I'm allowing it to pass through the argument tunnel to, and we're going to call this plus relative humidity, and we're going to need to create, I'll connect function with that, and so because we set up this relative humidity, we're going to need to set it up here, we'll say 10 just to start, it's going to be much higher once it actually goes through, because this is Texas, so down here, but we need to add our route as well, so server.get humidity, are you sure that's what we called it, yes, okay, so now temp on change, we're going to say relative humidity equals, and both of these will update, and then what we want to do here is we're going to say temp equals this, and relative humidity is this, save it, make sure it doesn't error out right away, okay, so now what we're going to do is we're going to check that it's sending the humidity to show temp, it is, it's 51 in the lab here, around 51, almost 51.1, so that's the relative humidity being sent, now we want to see if there's a humidity route, we'll need to start the server for that, oh, the relative humidity is 10, why does it still say 10 though, shouldn't say 10 anymore, oh, that's strange, let's figure out why that's going on, so here, oh, that's all I need to do, okay, should be working, hmm, that's strange, but under show temp, it is working correctly, you can see we've got relative humidity 51, it's getting a little more humid in here as we speak, but that's what that is, and so let's, with our remaining time, walk through exactly what we did for everything, so the first thing we did was we set up a Pi with Argo Tunnel, and we created that Argo Tunnel to iot.nobotnest, and with that, we're able to do lamp true, that turns an LED on, you've got lamp strobe, which turns a lamp strobing, and we've got lamp off, or false, and that will turn the lamp off, so the way we did that was we set up an Argo Tunnel from my Raspberry Pi to, through Argo Tunnel, so we didn't have to figure out the IP was, or anything like that, we just go straight through Argo Tunnel to do that, the next thing we did was we added in our temperature sensor, no temp, it's 21, so it's not updating either, that's strange, I don't know why those aren't updating, we'll have to look into that, let's look into that now actually, with our remaining time, okay, so we've got, it's on the right window for that, we'll close this, open it back up, I wonder if moving the weight to the bottom, yeah, let's move this to the bottom, I believe it's, okay, no, MU is undo, okay, we're just gonna, we're just gonna move these lines up here, so Celsius, close this, thermometer, Celsius, relative humidity, humidity, this, that, hydrogen, hydrometer, relative humidity, one second, let me check something here, cool, sorry about that, just checking messages that came through, and then we can go down and we can get rid of this line, we can get rid of this line, whoa, and and what we can do here, since we've, this is, we can say this is, save that, let's try running it and make sure it works, okay, got that, so now we go on to our browser, and check, 24.2, okay, so now this is working, and if I go to humidity, 50.78, if I go here, it's also still working, so great, we've now got temperature, timestamps, temperature, relative humidity, all working, all through the system, so to go, to continue on to the walkthrough, this, this worker, we'll walk into the code here, so this worker takes the JSON information from the robot, which gets posted by the robot, to add temp, which we, I guess we should change to add temp and humidity, because that's what it does now, and it also adds a timestamp to it, so we know when that that record was created, according to the worker, so yeah, that's the walkthrough, so if there are any questions, we have a few minutes left, otherwise I will walk through a little more of the setup, and how to set this up for the first time, if you're new to this, so I don't see any questions, so I'm going to walk through how to set up the code base for the last few minutes, so we're going to go on to github, I'm on github, where's my mouse, there you are, I'm going to Cassian's IoT Hour, we're going to clone it, and we're going to want to clone it in two different places, we're going to want to clone it into the Pi, and we're going to want to clone it into our desktop, so pretend we cloned it here, so this is where we clone it, you then say wrangler, who am I, if you don't have wrangler installed, you would say npm i-do wrangler, or at Cloudflare, and then you would say wrangler who am I, and if it didn't show that, oh cool, then my account ID is up there, you can clear that out, you'd say wrangler login, if you haven't logged in yet, so ah, wrangler config, okay, so because I already have them, you would go to dash.api tokens and handle that, yeah, that's how you would get into wrangler, and so once you've got that set up, you go into the worker code and show temp, and you say wrangler publish, now before you did this, you would need to add your ID to wrangler.toml, which is not put in the, the wrangler.toml is not placed in the, oh it is, okay, so I need to change that, so my stuff's not in there, but yeah, and you need to change it to your ID in wrangler.toml, and then you wrangler publish it, and that would put the worker out there, and yeah, three more, three, three and four minutes, so we're going to do the py stuff, so we've got the py code in here, I'm going to close it for a second, and then I'll ask, now you could run it the way I run it, I ran it, or you could say nodemon, well, sudo nodemon, index.js, I might not have minmon installed on this, I do not, so npm i jsh g nodemon, okay, and then I will also npm i dash d forever, because if we want to run it in the background without having to, you know, close it and open it and close it and open it, what we could do here is use forever, so, and this will also work if you want to ssh back out and still have it running, so once this installs, I'll show you how to run it, so we can say forever start index.js, and then forever list, hmm, it's not living very long, so sudo forever, well, first forever stop rev underscore, okay, and then sudo forever start, but one minute left, okay, so with that one minute, I'm just going to say, thank you very much for watching, hopefully we'll have more of these IoT hours, I'm working on a feature, if you're interested in learning more, you can contact me at kas at Cloudflare.com, if you have any questions or want to contact me about, you know, what I did here, you can also access this on github at nodebotanist slash Cassian's IoT hour, and with that, I hope you enjoy our next segment, and I hope you're enjoying Cloudflare TV in general, and have a great day.