In this video of our Meshtastic for Makers course, we are going to be receiving messages from the Meshtastic network onto our Pico, then using it to control hardware and display sensor information. We're going to be using the exact same setup from the last video, which we used to send information.

Transcript

In this video of our Meshtastic for Makers course, we are going to be receiving messages from the Meshtastic network onto our Pico and doing things with it, like controlling hardware and displaying sensor information. We're going to be using the exact same setup from the last video, which we used to send information. You can find that video and all the others in the playlist below or follow along on our written course also linked down there.

Alright, let's go ahead and start with a really simple example. We are going to control the angle of a servo with messages from the network. Really simple: we're going to plug the power of our servo into ground and vbus, which is going to give us 5 volts, and then we're going to connect the signal to pin zero, which is just what we're going to be using for this demo. We're just going to go through another code-along example in Thonny, and there isn't actually much needed to get this going like last time, but to make it really robust and reliable, that's where a lot of the work and a lot of the code comes from.

First things first, let's ensure we have our MicroPython servo library installed onto our Pico. We're going to go ahead and import our libraries exactly like we did last video, as well as the servo library this time. Then we're going to go ahead and set up the UI peripheral exactly like we did last time as well. Now we're going to create a servo; we're just going to call it test_servo, and that is going to be in pin zero. Then we're going to enter our while true loop and start by checking if `uart.any()`.

When a Pico receives a UART message, it's going to be held in something called the buffer until we do something with it. This `uart.any()` returns true if there is a message waiting in the buffer for us. So if it is true, we're going to say `message = uart.read()` and then print out that message. Easy peasy.

Alright, let's give that a test. Drag that up. I'm just going to send a test message. I'm just going to send the word "test" like so, and you can see there's a bit of a jumbled mess, but our message is in there. So what's going on with this weird format here? Well, the `b` and the quotation marks are something called a byte string; it's just what happens when you use UART. But this weird thing here in the middle with the slashes and the bytes is unfortunately a bug with MicroPython and Meshtastic. The message is meant to be coming through as the four-letter short name of the sending device, a colon, and then the message behind it. But in MicroPython, we get this big jumble instead of the name. If you're using C++ or another device, that four-letter code might come through fine, but for us, we're just going to ignore it completely.

To do so, we're going to paste in this big function here. You don't need to know how it works; it's quite involved. All you need to know is that we can send our message to this function, and it's going to take out the actual text that we send. It's going to remove everything except for the actual message, and I'm going to print "fixed message" this time. If we run this and send a test message, I'm just going to say "test," we can see we're just getting our message through nice and beautifully like so.

From this point, it should be as simple as saying `test_servo.write()` and then the fixed message, which we're going to send a number through. But very importantly, anything coming through UART is going to come through as a string, and we can't put a string as a servo angle, so we need to turn it into an integer before we start using it.

Alright, we should be able to run that, and I'm just going to send a number from my phone, which is connected to our other Meshtastic device. I'm going to send 180, and the servo gets set to 180. If I send zero, it's going to be set to zero. Oh, how awesome is that? I should be able to pretty much set it as frequently as I can send messages.

There's one more thing we should put in this, and that is error handling. This is probably going to be the most difficult part of setting up something like this in the real world because, let's say I set this up on a mountain a kilometer away, and I'm going to send instead of a number, I'm going to send actually a letter and a number like so, and I send that, and it crashes. Now we need to make a trip out to our Pico to fix this or restart it. A really handy tool to help prevent things like this is the try-except function. So we're going to try to do something, and we're going to nest this writing the servo angle in like so. Then we're going to except; this is if we try to do something and it fails, we're going to do something else. We don't actually want it to do anything, so we're just going to say pass, which is do nothing. Now we get our message, we try and write it to the servo. If it works, it works fine; we move on. If it fails, we just don't do anything, and we move on as well.

I run this code, and if I go t5 instead of maybe accidentally writing 45, nothing happens. If I write 45, it gets set to 45. Beautiful. Of course, we used a servo with this example, but this could very easily be a linear actuator or a motor being turned on, a solenoid lock, a relay flipping some other device, a light or LED, whatever your project needs, you can now control it like so.

Now that's great and all for a simple setup with, you know, maybe device A to send data and device B to receive that data. But what if we add some more into this mix? Well, this is where things might start to get a little bit tricky. I have another one of these here; it's exactly the same, just with a smaller screen and a bit of a DIY antenna solution on a pencil there. If I send them both a message with a number, they're both going to receive that and set the servos accordingly because they're both running the exact same code. We probably don't want that, so we're going to need to devise a system to individually control them.

We are going to go through an example of a really simple system for this. We're going to send a sort of topic or identifier before the number. So if we wanted to set the angle of our first device, we might send "servo A" and then a colon and then the actual number. If we want to send data to the other one, we're going to go "servo B" colon and then the number.

With that system in mind, let's go ahead and modify our code to match that. We're going to read the message exactly the same, fix it up exactly the same, but here we're going to say something really cool. We're going to say if `fixed_message.startswith("servo A:")`. This is going to be the bread and butter of most of this. This `startswith` function, we essentially put something in there, and if it starts with it, it's going to do whatever we put inside of it. Really simple and a really helpful tool.

Inside of this if statement, we're going to put our try function. I'm just going to go ahead and move it around. There's something very important we need to do because it's going to have that first bit and then the actual number we need. We're going to need to strip off that first bit, and we can do so with that `split` function here, which is going to take our fixed message, cut it after the colon, and then we're going to grab the second bit of it, which is going to be the actual number we want. Then, just so we can see what's going on, I'm just going to pop in a few print statements here and there just to help with maybe a little bit of debugging.

Where are we? As usual, I have forgotten a colon on an if statement, and we should be able to run this. Then I'm going to send "servo A" followed by an angle, and our servo is going to be set like so. But if I send any other message, any other number, any other even combination of something followed by a colon and then a number, it's going to be ignored like so. I've gone ahead and uploaded the same code to this one, except instead of "servo A," it's looking for the name "servo B." If I send "servo B," that one gets sent, and if I send "servo A," only that one moves like so. You can see from the screens that they are both actually receiving those messages.

Now, this is just the system we're using here. I'm not saying you need to use it; it's just probably the simplest way. You should do whatever your project needs. This whole planning and organizing the messaging system across your network might actually be the fun aspect of your project and, you know, worth overdoing just for the fun of it.

Alright, let's do one more example, something really practical. We are going to build a little dashboard with this giant SSD1306 OLED screen, and this is, of course, going to work with the smaller one you might encounter more often. On the course page, you're going to find the sample code for this. It's a bit too long to code along with and write live, so we're just going to paste it in like so. We're also going to install the required SSD1306 library like so as well, and we're going to go ahead and plug in our OLED screen. Now, you could very easily have another one, but we're just going to repurpose the one from our other Meshtastic Pico and plug it into pins four and five, SDA into four, SCL into pin five.

Now, there is quite a lot going on here, but I've kind of just expanded on what we just wrote beforehand. So we import everything we need, we've got our UI set up, and then we're going to go ahead and set up our screen. Basically, this is just from the SSD1306 library. Now, something this code does is that it remembers how long it's been since we've actually received that message, and that's all stored in this dictionary called `last_updates`. Then we have our `process_ui_message`, which just extracts the actual message, followed by three more functions which are to do with timing and writing on the screen and whatnot. You can kind of just ignore them; they just work.

Then we turn on our screen and start recording time and finally come into our while true loop in our main part of our code. It's actually pretty straightforward. We go if there's anything in the UI, we'll get our message and sort it out nicely exactly like last time. We're going to start by saying does it start with something that we want, and if it does, we're going to take the value behind the colon. Then we're going to start recording time so we know how long it's been since we've retrieved that info, and then we're going to call this function which displays it onto our screen. We've got six different possible rows that we can write to because that's how much text we can fit on this screen. Here we're saying we're going to fill in slot one, we're going to call this reading "soil 1," it could be really whatever you want as long as it fits, and then we're going to put through the value which is what we pulled out after the colon. If you go down here, we just have six of these in a row. Here are the six things we're looking for. We're saying if it starts with "soil 2" or "humidity" or "temperature" or "front gate," whatever we're looking for, we're just gonna send it to the appropriate slot that we want.

I mean, go ahead and test that by sending some dummy messages from our other device. So "soil 1" followed by some number, and it pops up like so. Let's do a "soil 2," beautiful, and a "temperature," easy. Let's do a "humidity." These are just the ones that I said before. That's 89% humidity; it's a really hot day. "Rain," let's say zero millimeters today, and let's simulate a message from the front gate that it is open like so.

Just so we can see our whole system in action, I've gone ahead and plugged in our moisture sensor and run the code that sends that sensor reading again. Very importantly, I've gone ahead and modified it so it's sending "soil 1" followed by the reading, or our receiving Meshtastic isn't gonna know what to do with it. If I hit run, you can see our new data coming through like so. Beautiful.

I think we need to take a step back and appreciate what we actually have here. We have two nodes, one with a sensor that's connected to a Pico, which sends the reading via UART to another Pico, which then transmits that via LoRa. That might jump between strangers' devices through several kilometers to get back to our other node, which is sending that message via UART to another Pico and displaying it on the screen. It's pretty wild that you can make that with off-the-shelf hardware and not much code.

With that, you now have the tools to build some pretty impressive stuff. This could very easily just be a button that turns on a light a kilometer away or something, or 10 gates being monitored whether they're open or closed. You could attach one to a vehicle and a GPS to report its location, or it could be a mailbox sensor on a really large property. Whatever your needs are, we now have a solid method of sending and receiving data wirelessly through the Meshtastic network. From the snippets of code we've given you so far, it's quite easy to paste them into an LLM like ChatGPT, Claude, or DeepSeek and get it to help you write code and organize your system of sending messages.

Well, that about wraps us up for now. If you made something cool with this or you need a hand with anything we covered in this video, head on over to our community forums. We're all makers over there, and we're happy to help. Until next time though, happy making!

Comments


Loading...
Feedback

Please continue if you would like to leave feedback for any of these topics:

  • Website features/issues
  • Content errors/improvements
  • Missing products/categories
  • Product assignments to categories
  • Search results relevance

For all other inquiries (orders status, stock levels, etc), please contact our support team for quick assistance.

Note: click continue and a draft email will be opened to edit. If you don't have an email client on your device, then send a message via the chat icon on the bottom left of our website.

Makers love reviews as much as you do, please follow this link to review the products you have purchased.