Thus far in the book, we have learned that the Raspberry Pi Pico is a great small microcontroller that has a lot of power in such a small package. It’s inexpensive and easy to program. However, there is one thing missing – there is no way to connect it to the Internet. At least, not directly because it doesn’t have WiFi support. We will see how to add WiFi support in this chapter.
In previous chapters, you’ve seen a number of projects, ranging from very basic to advanced in difficulty; it is time to discuss how to make your IoT data viewable by others via the cloud. More specifically, you will get a small glimpse at what is possible with the more popular cloud computing services and solutions.
I say a glimpse because it is not possible to cover all viable solutions available in cloud services solutions for IoT in a single chapter. Once again, this is a case where learning a little bit about something and seeing it in practice will help you get started.
In this chapter, we will get an overview of what the cloud is and how it is used for IoT solutions. The chapter also presents a concise overview of the popular cloud systems for IoT as well as a short example using two of our earlier projects to give you a sense of what is possible and how projects can be modified to use the Internet.
Don’t believe all the hype or sales talk about any product that includes “cloud” in its name. Cloud computing services and resources should be accessible via the Internet from anywhere, available to you via subscription (fee or for free), and permit you to consume or produce and share the data involved. Also, consider the fact that you must have access to the cloud to get to your data. Thus, you have no alternative if the service is unreachable (or down).
Since the technologies presented are quite unique in implementation (but straightforward in concept), I keep the project hardware and programming to a minimal effort.
Overview
Unless you live in a very isolated location, you have been bombarded with talk about the cloud and IoT. You’ve seen advertisements in magazines and on television, or read about it in other books, or attended a seminar or conference. Unless you’ve spent time learning what cloud means, you are wondering what all the fuss is about.
What Is the Cloud?
Simply stated,1 the cloud is a name tagged to services available via the Internet. These can be servers you can access (running as a virtual machine on a larger server), systems that provide access to a specific software or environment, or resources such as disks or IP addresses that you can attach to other resources. The technologies behind the cloud include grid computing (distributed processing), virtualization, and networking. The correct scientific term is cloud computing. Although a deep dive into cloud computing is beyond the scope of this book, it is enough to understand that you can use cloud computing services to store your sensor data.
What Is Cloud Computing Then?
The term cloud computing is sadly overused and has become a marketing term for some. True cloud computing solutions are services that are provided to subscribers (customers) via a combination of virtualization, grid computing (distributed processing and storage), and facilities to support virtualized hardware and software, such as IP addresses that are tied to the subscription rather than a physical device. Thus, you can use and discard resources on the fly to meet your needs.
These resources, services, and features are priced by usage patterns (called subscription plans or tiers), in which you can pay for as little or as much as you need. For example, if you need more processing power, you can move up to a subscription level that offers more CPU cores, more memory, and so forth. Thus, you only pay for what you need, which means that organizations can potentially save a great deal on infrastructure.
A classic example of this benefit is a case where an organization experiences a brief and intense level of work that requires additional resources to keep their products and services viable. Using the cloud, organizations can temporarily increase their infrastructure capability and, once the peak has passed, scale things back to normal. This is a lot better than having to rent or purchase a ton of hardware for that one event.
Sadly, there are some vendors that offer cloud solutions (typically worded as cloud enabled or simply cloud) that fall far short of being a complete solution. In most cases, they are nothing more than yesterday’s Internet-based storage and visualization. Fortunately, Microsoft Azure is authentic: a full cloud computing solution with an impressive array of features to support almost any cloud solution you can dream up.
If you would like to know more about cloud computing and its many facets, see https://en.wikipedia.org/wiki/Cloud_computing.
How Does the Cloud Help IoT?
OK, so now that we know what cloud systems are, how do they help me with my IoT projects? There are a variety of ways, but most common are mechanisms for storing and presenting your data rather than storing it locally or even remotely on another system such as a dedicated database server. That is, you can send the data you collect from your sensors to the cloud for storage and even use additional cloud services to view the data using charts, graphs, or just plain text. The sky is the limit with respect to how you can present your data.
But storing data isn’t the only feature you can leverage in the cloud. There are other services that you can use to link to yet other services to form a solution. For example, most paid IoT cloud systems provide features that can “talk” to each other allowing you to link them together to quickly build a solution. The features are often called components rather than services, but both terms apply.
For example, in Microsoft Azure, you can store your data with one of several components and then link it to others that allow you to modify the data via queries, others to route the data to other places (even to another cloud service vendor), and to one of several components for displaying the data. Yes, it really is a set of building blocks like that.
Now that we’ve had a general overview of cloud systems, let’s look at those that support IoT projects directly.
IoT Cloud Systems
Oracle IoT: www.oracle.com/internet-of-things/
Microsoft Azure IoT Hub: https://azure.microsoft.com/en-us/product-categories/iot/
Google IoT Core: https://cloud.google.com/iot-core
IBM IoT: www.ibm.com/internet-of-things
Arduino IoT Cloud: www.arduino.cc/en/IoT/HomePage
Adafruit IO: https://io.adafruit.com/
If This Then That (IFTTT): https://ifttt.com/
MathWorks ThingSpeak: https://thingspeak.com/
Most of the vendors offer commercial products, but a few like Google, Azure, Arduino, IFTTT, and ThingSpeak offer limited free accounts. A few are free like Adafruit IO and Arduino IoT Cloud but may limit you to a particular platform or a smaller set of features. As you may surmise, some of the offerings are complex solutions with steep learning curve, but the IFTTT and ThingSpeak offerings are simple and easy to use. Since we want a solution that is easy to use (and free!), we will then use ThingSpeak in the next chapter to round out our introduction to IoT cloud systems.
If you want or need to use one of the other vendors, be sure to read all of the tutorials thoroughly before jumping into your code.
Let’s look at some of the types of services available in cloud systems that support IoT projects.
IoT Cloud Services Available
IoT projects offer an amazing opportunity to expand our knowledge of the world around us and to observe events from all over the world no matter where we are located. To address these capabilities, IoT cloud services provide an array of services that you can leverage in your applications.
There are services for collecting data, managing your devices, performing analytics, and even application and processing extensions for you to exploit. For example, some vendors include complete user management where you can provide user accounts for people to log in and use your cloud solution and see your data.
Device management: Allows you to set up, manage, and track what devices are in your IoT network.
Data storage: Permits storage of your IoT data either on a temporary (typically free for a number of days) or permanent (paid) storage.
Data analytics: Allows you to perform analysis on your data to find trends, outliers, or any form of analytical query.
Data query and filters: You can perform queries or filter your IoT data after it has been sent to the cloud service for detailed presentations or transformations.
Big data: Permits you to store vast amounts of data and perform operations on the data (think data warehousing).
Visualization tools: Various dashboards and graphics you can use to help present your data in meaningful ways (spreadsheet, pie charts, etc.).
High availability: Provides features that allow you to operate even if portions of your cloud servers (or the vendor’s) fail or go offline due to network issues.
Third-party integration: Allows you to connect your IoT services to other IoT servers from other vendors. For example, connecting your Adafruit IO data to IFTTT for triggering an SMS message.
Security (data, user): Provides support for managing user accounts, security access, and more for your applications.
Encryption: Allows you to encrypt your data either in the cloud or when transmitting the data from one service to another.
Deployment: Similar to device management, but on a grander scale where you build IoT devices using common profiles, operating systems, configurations, etc.
Scalability: The ability to scale from a small number of devices and services to many devices. This is often only available in the larger, paid vendor services.
APIs (Rest, programming): Allow you to write code to communicate directly with the services instead of issuing web requests. Often part of the larger, paid vendor services.
For our beginning IoT projects, we will be focusing on a subset of these services, which can be grouped into several categories. Let’s look at a few of the most common services you may want to start using right away.
Data Storage
These services allow you to store your data in the cloud rather than on your local device. Some data such as alerts or notices do not need to be stored, and you should think about if you would need the data in the future and will be project dependent. For example, if you wanted to create a weather alert project, you may not care what the temperature was a week or even a month ago. However, if you want to do some amateur weather forecasting, you will want to store data for some time (perhaps years). You may consider storing the data locally, which may be possible for some platforms such as the Raspberry Pi, but the Arduino and similar boards have very limited storage capabilities.
Thus, if you need to store your data for some period and storing it locally is not an option, you should consider this when selecting a cloud vendor. Look for how data will be stored, the mechanisms needed to send the data to the service, and how to get the data out of the service.
Data Transformation (Queries)
These services allow you to perform queries on the data as it flows to or through the cloud services. You may want to show only a subset of the data to your users, or you may want to filter the data so that data from certain devices, dates, etc. are shown for one of several views.
The case where you’d want to consider these are for IoT projects that collect data from multiple sensors and multiple devices, and the data is stored for a period of time. For example, if you have devices geographically distributed over a wide area, you may only want to see data from a subset of those devices. Similarly, if you have data from several time periods, hours, days, and weeks, you may only want to see data from a specific time.
Visualization Tools
These services along with routing and messaging are the most commonly used for beginning IoT projects. These are simply services that allow you to see your data on the Internet. It may be nothing more than a simple list of the data, or it may be an elaborate data dashboard complete with controls that users can use to manipulate the display. Fortunately, most cloud vendors provide a robust set of tools (some more than one) that you can use to present your data to yourself or your users.
Routing and Messaging
These services are the heart or the bones of the IoT cloud. They encompass the glue to bind different services together. More specifically, they provide mechanisms for you to connect your devices to services and those services to other services such as queries, filters, and visualization tools, permitting you to build an IoT solution using several cloud services. We’ll see an example of such a service in the next section.
Now that we’ve had an overview of the IoT cloud services and the most common services we will encounter, let’s jump into a simple example using a web page to control hardware.
But first, let’s talk about basic networking capabilities for the Pico.
Connecting Your Pico to the Internet
At the time when the Pico was launched, there were no options available for you to connect your Pico to the Internet except through connecting your Pico to another microcontroller (or Raspberry Pi) to provide the connectivity. Those options are still available (and valid), but they are not simple to set up and program. What we want is a module that we can connect to our Raspberry Pi to connect it to the Internet and provide basic TCP/IP operability. Fortunately, such a module exists! Before we look at that module, let’s review what modules are available for us today.
Pico WiFi Modules
ESP8266 WiFi Module for Raspberry Pi Pico: https://thepihut.com/collections/pico/products/esp8266-wifi-module-for-raspberry-pi-pico ($9.94)
DiP-Pi WiFi Master for Raspberry Pi Pico: https://thepihut.com/collections/pico/products/dip-pi-wifi-master-for-raspberry-pi-pico ($16.89)
Maker Pi Pico Base: https://thepihut.com/collections/pico/products/maker-pi-pico-base-without-pico ($8.81)
Pico Wireless Pack: https://shop.pimoroni.com/products/pico-wireless-pack ($13.20)
Most are made to work as an external module that you have to program separately and then use either a serial or similar code library to transfer data back and forth. This is the same concept as connecting your Pico to another microcontroller, which isn’t sufficient for getting started quickly or making it easy.
Let’s discover a bit more about each of these options.
ESP8266 WiFi Module for Raspberry Pi Pico
As you can see, we are not using any special libraries; rather, we’re sending AT commands over a UART (think serial) connection to the module. While this helps eliminate GPIO issues (pins used by modules that you need for other modules), it is a bit tedious to program TCP/IP connections this way. Fortunately, there are several working examples on the product website.2
See www.waveshare.com/wiki/Pico-ESP8266 for documentation and more information about using this module.
DiP-Pi WiFi Master for Raspberry Pi Pico
Sadly, while there are WiFi code examples listed on their list of examples (https://dip-pi.com/ready-to-use-examples), the WiFi links are not active, suggesting there may be examples in the future. However, the operating manual for the product has details on the features of the WiFi module as well as links to the AT commands supported.
See https://dip-pi.com/installation-and-operating-manuals to download the documentation for this module.
Maker Pi Pico Base
Like the other modules, this requires programming the ESP-01 via AT commands similar to the ESP8266 WiFi Module. Fortunately, you can load MicroPython on the ESP-01 and write your Python code to connect to the Internet. Sadly, there are no examples on the product website at this time to show you how to do that, but you could follow similar examples from the other modules as a guide.
If you already own a Maker Pi Pico Base and an ESP-01 (or similar module), this may be the least expensive option. So long as you can sort the AT commands, you can make this option work for you.
See https://github.com/CytronTechnologies/MAKER-PI-PICO for documentation and more information about using this module.
Pico Wireless Pack
The Pico Wireless Pack is another excellent product of pimoroni.com. The module has the familiar female header on the bottom so that you can use it to connect directly to your Pico. It also has an SD card! Wow.
This is much easier to understand than using the AT commands, unless, of course, you are proficient in their use.
There is also a user-configurable button, an RGB LED, and an SD card reader on the module, which is a nice touch. See https://shop.pimoroni.com/products/pico-wireless-pack for documentation and more information about using this module.
The documentation for the Pico Wireless Pack states that the library for the SD card is experimental, but so long as you use it for base file reading and writing, you should not have a problem.
So, Which One Do You Choose?
Only one of these modules supports a programming interface other than the UART-based AT commands. That means there is only one choice for those of us who want to connect our Pico to the Internet and use code that resembles how other platforms use networking code. Thus, we will use the one module that allows us to use our Pico to work with TCP/IP connections – the Pico Wireless Pack from pimoroni.com.
Using the Pico Wireless Pack
To use the Pico Wireless Pack, you must download all of the Pimoroni-specific libraries and set up your Pico to use them, which is a potentially time-consuming process. Fortunately, you can avoid all that and simply download their custom Pico boot image and copy it to your Pico.
You can refer to Chapter 1 for how to set up your Pico to use the new boot image, but, briefly, you simply remove the Pico from your PC, press and hold the BOOTSEL button, then connect the Pico to your PC. Once the Pico opens as a drive, you can copy the .uf2 file to the drive and then remove the Pico and reconnect it.
You must use the custom .uf2 from Pimoroni to use the Pico Wireless Pack examples and the projects in this chapter and the next.
Unlike some of the other WiFi offerings for the Pico, the Pico Wireless Pack has several simple examples available on the Pimoroni GitHub site. You can find example WiFi code for the Wireless Pack at https://github.com/pimoroni/pimoroni-pico/tree/main/micropython/examples/pico_wireless.
Let’s look at a couple of simple examples so we can ensure the module is working on our WiFi. One is a simple utility, but the other is a nifty example of how you can build a simple web server and run it on your Pico. Specifically, it is a simple HTTP (hypertext transfer protocol3) listener that accepts commands on a specific port and responds by sending preformatted HTML back to the client.
We won’t go through the code at this time; rather, we will concentrate on the mechanics of getting the examples to work. We will see more about the details of how the HTTP server works in a later section.
Download the entire repo by visiting https://github.com/pimoroni/pimoroni-pico and clicking the Code button and choosing Download Zip. Once downloaded, you can unzip the file and navigate to the folder to see the code for the examples.
We will look at two examples. The first is a simple WiFi scanner that finds the WiFi access points within the area. To use this example, open Thonny and navigate to the <download dir> pimoroni-pico/tree/main/micropython/examples/pico_wireless where <download dir> refers to the location on your PC where you downloaded and unzipped the GitHub code.
Once you determine your Pico can find your wireless network, you can then test it further by running the rgb_http.py example. This example lets you control the RGB LED on the Pico Wireless Pack using your browser. It demonstrates how you can control hardware over the Internet, which is a large part of what the IoT is all about!
Once you run the server, connect to it with the IP address and port shown in the output using your web browser on your PC. Using the information in the preceding example, you would use http://192.168.1.20:80 in the URL box. Your browser would then connect to the HTTP server on the Pico and display the web page.
If you do not see the web page, be sure to double-check that your PC is connected to the same network as your Pico. This can happen if you have multiple WiFi networks, or your PC is hardwired to a networking device on another network.
You can now use the drop-down boxes to change the value for each of the red, green, and blue variables. You can use the drop-down or type in a specific value for each. Let’s try several examples. Just type in the value for each of the boxes and then click Set LED. For example, you could try the base colors such as red (255,0,0), green (0,255,0), and blue (0,0,255). You should see the RGB LED on the Pico Wireless Pack change to match the values you entered.
Once that works, you are ready to start adding networking to your projects. Let’s look at some of the projects in this book and see how we can turn them into simple IoT projects.
IoT Project Examples
Let’s see how to apply what we learned to two of our example projects to complete the IoT portion for each. We are going to use the pedestrian crossing example from Chapter 7 and the soil moisture monitor project from Chapter 8. We will be creating a rudimentary web server for each project running on the Pico. This will allow you to access the project from anywhere on your network (or beyond).
Rather than develop the web server code from scratch, we will be mimicking the code from the Pimoroni example code for the Pico Wireless Pack. If you have not yet downloaded the code, please visit https://github.com/pimoroni/pimoroni-pico and download the code. Once downloaded, we will want to copy the example code files from <download dir> pimoroni-pico/tree/main/micropython/examples/pico_wireless and into your own project folder.
For example, you can create project7 and project8 folders for the next two projects. Then, copy the secrets.py files in the example source code to each of the project folders and modify it for your WiFi. Now you are ready to start working on the following examples.
Example 1: Pedestrian Crossing
In this example, we will use the pedestrian crossing example from Chapter 7. Recall, this project simulates a pedestrian crossing signal where the pedestrian presses a button to request the traffic lights cycle to allow them to cross the street. Instead of a button, we will use a web page to trigger the walk request. Yes, we will see how to remotely control the hardware and our code over the network. Let’s get started!
Set Up the Hardware
Required Components for the Pedestrian Crossing Web Example
Component | Qty | Description | Cost | Links |
---|---|---|---|---|
Red LED | 2 | Pack of 25 | $4.00 | |
Single | $0.35 | |||
Yellow LED | 1 | Pack of 25 | $4.95 | |
Single | $0.35 | |||
Green LED | 2 | Pack of 25 | $4.00 | |
Single | $0.35 | |||
220 or 330 Ohm resistors | 5 | Variety Kit | $7.95 | |
Pack of 25 | $0.75 | |||
Pico Omnibus | 1 | Pico host board | $8.25 | |
Pico Wireless Pack | 1 | WiFi | $13.20 | |
Breadboard | 1 | Prototyping board, full-sized | $5.95 | |
$5.95 | ||||
Jumper wires | 6 | M/F jumper wires, 7" (set of 30) | $2.25 |
Notice the jumper wires need to be the M/F type since the GPIO on the Pico Omnibus has male pins. Go ahead and plug your Pico into the Pico Omnibus and the Pico Wireless Pack onto the right side of the board. We will use the left-side GPIO headers for the LEDs. But use care, because the GPIO header rows are reversed to make it easy to add modules designed to mount to the bottom of the Pico. Thus, you must read the label on the Pico Omnibus carefully to ensure you use the correct pins.
Connections for the Pedestrian Crossing Web Example
Physical Pin | GPIO Num/Function | Connection |
---|---|---|
3 | GND | Breadboard ground (bottom) |
6 | GP5 | Resistor for red LED (stoplight) |
5 | GP4 | Resistor for yellow LED (stoplight) |
4 | GP3 | Resistor for green LED (stoplight) |
1 | GP1 | Resistor for red LED (walk light) |
0 | GP0 | Resistor for green LED (walk light) |
N/A | Breadboard ground | All LED negative side |
N/A | Resistor | All LED positive side |
Once you have the code wired, you are ready to start writing the code.
Write the Code
The code for this example will use the core code from the project in Chapter 7, but we will not be using the main() function. Rather, we will see how to use the Pimoroni library to create a simple HTTP server (also called a listener). The code will send a short HTML-based response (a simple web page) to the client that includes a form containing a single button for the walk request. The listener will listen on port 80.
We will also see an advanced technique using the threading library available on the Pico. As you will see, this library permits us to execute a function in a second core processor on the Pico. It is an excellent way to keep two things going at the same time and get a bit more processing at the same time.
The concept of the HTML server is quite simple. The code listens for a connection on the socket port and then receives the request (in this case, in the form of an HTML GET method) and sends an HTML response (the web page). If the button is pressed, the walk cycle will commence by calling the cycle_lights() function from the Chapter 7 project.
If you’ve never used HTML code before, don’t worry as the example code will provide everything you need. You don’t have to learn HTML for this chapter, but a basic knowledge would be helpful if you want to elaborate on the project or use the HTML server concept for your own projects. A reliable source of information about HTML can be found at www.w3schools.com/html/.
Since this is all new code, we will step through all of the parts so you can see how it works, but we will skip the code for controlling the LEDs. Please refer to Chapter 7 if you have not completed that project.
We will create a new file named pedestrian_crossing_web.py. Go ahead and open a new file in Thonny if you want to follow along.
Let’s begin with the code needed for the import section.
Imports
Let’s look at the global variables we need.
Global Variables
We will also need to create a number of functions to manage the HTML server and control the LEDs.
Functions Needed
cycle_lights(): The same function from Chapter 7. You can copy it from the Chapter 7 project unchanged.
get_home(): A callback function for the HTML server. This function is called when a client connects to the server. It simply returns the web page.
get_walk(): A callback function for the HTML server. This function is called when the client clicks the button on the web page.
server_loop_forever(): A special function that contains the main loop for the HTML server. It is used as a parameter for the threading module enabling the HTML server to run on the other microcontroller core on the Pico.
main(): The main function we will call when the script is loaded and executed.
Let’s look at the code for these functions.
As mentioned, the cycle_lights() function is unchanged from the Chapter 7 project, so we will skip the details.
The key to how these functions work is the decorator before each function. Notice the @ppwhttp.route() decorator. This is used by the pwhttp library to identify functions used to “route” control when a client connects and sends a GET or POST method. The first parameter to the decorator defines the path portion of the URL sent. This is how the route is determined. For example, if the client enters http://192.168.1.20:80, the get_home() function is called. Similarly, if the client enters http://192.168.1.20:80/?WALK=PLEASE, the get_walk() function is called. Finally, notice inside the get_walk() function, we test the method, and if it is a GET operation, we call cycle_lights(). This completes the simple HTML web server!
The port (:80) of the URL is optional since port 80 is the default for HTML.
Recall, we place the SSID and password of our WiFi router in the secrets.py file, which must be uploaded to the Pico. The pwhttp library will open the file and read the values when the start_wifi() function is called.
The main() function is called using the normal mechanism we’ve used in previous projects located at the bottom of the file.
Completed Code for the Pedestrian Crossing Web Example
OK, now we’re ready to execute the project.
Execute
Before executing the project, be sure to upload the pedestrian_crossing_web.py to the root of the Pico onboard drive. You also need to create a project7 folder on the Pico and upload the Pico Wireless Pack library (ppwhttp.py) file into that folder. Finally, you also need to upload the secrets.py file from the Pico Wireless Pack library and modify it to include your WiFi SSID and password. Upload this file to the root of the Pico onboard drive.
Running the Pedestrian Crossing Web Project
Once you enter the URL, you should see a web page like the image shown. If you don’t, be sure to check the HTML in your code to ensure it is exactly like what is shown; otherwise, the page may not display properly. You should also ensure the network your PC is connected to can reach the network to which your board is connected. If your home office is set up like mine, there may be several WiFi networks you can use. It is best if your board and your PC are on the same network (and same subnet).
If your Pico doesn’t connect to your WiFi within a reasonable time, you may need to click Stop in Thonny and rerun the project to reset the Wireless Pack.
Once you get that sorted out, verify the green LED for the stoplight is on and the red LED for the pedestrian crossing is on. All other LEDs are off. If you do not see something similar, go back and check your connections again.
Now go ahead and click the button. Remember, the walk button will engage, and you will see the lights cycle, but you won’t be able to do anything until the walk cycle is complete. This is because we don’t return the response HTML until after the cycle is complete (see the code to convince yourself).
Notice in the output window in Thonny there are debug messages printed for each time the client connects (the code accepts the connection and GET request) as well as a statement about what it is doing. You should see something similar.
Now, let’s look at a second example.
Example 2: Soil Moisture Monitor
In this example, we will use the plant monitoring project from Chapter 8. This project used one or more soil moisture sensors to read the relative moisture in the soil for one or more plants. While the features of the project are the same as we saw in Chapter 8, the code for this example is more complex.
The example is meant to show what is possible rather than a complete project. Suggestions on how to improve the code are presented in a later section.
We will be using more advanced HTML code, but once again will not explain all of the details. If you’d like to know how each of the tags is used, you may want to consult a WWW resource or simply Google “HTML tags.”
Also, while this project is based on the project in Chapter 8, we will not be using an OLED screen because we will be writing code to a file and reading it when a client connects to the web server returning as a table. As you will see, writing data to a file is much easier and uses less complex code.
Let’s look at the hardware for this example.
Set Up the Hardware
Required Components for the Plant Monitoring Example
Component | Qty | Description | Cost | Links |
---|---|---|---|---|
Soil moisture | 1+ | Sensor | $6.95 | |
RTC module | 1 | Pico RTC DS3231 | $14.88 | https://thepihut.com/products/precision-rtc-module-for-raspberry-pi-pico-ds3231 |
CR1220 coin cell | 1 | Battery | $0.88 | https://thepihut.com/products/cr1220-12mm-diameter-3v-lithium-coin-cell-battery |
Pico Omnibus | 1 | Pico host board | $8.25 | |
Pico Wireless Pack | 1 | WiFi | $13.20 | |
Breadboard | 1 | Prototyping board, full-sized | $5.95 | |
$5.95 | ||||
Jumper wires | 6 | F/F jumper wires, 6" (set of 10) | $5.95 | |
Micro-SD card | 1 | Micro-SD card (any size) | Varies | Commonly sourced |
Notice the jumper wires need to be the F/F type since the GPIO on the Pico Omnibus has male pins and the soil moisture sensors also have male pins. Go ahead and plug your Pico into the Pico Omnibus and the Pico Wireless Pack onto the right side of the board like we did in the last example.
Remember, the GPIO header is reversed on the Pico Omnibus. Be sure to read the label on the host board to ensure you have the right pin selected.
Connections for the Plant Monitoring Web Example
Physical Pin | GPIO Num/Function | Connection |
---|---|---|
3 | GND | Ground for Sensor 1 |
8 | GND | Ground for Sensor 2 |
21 | GP18 | Power for Sensor 2 |
22 | GP17 | Power for Sensor 1 |
33 | GP27 | Signal for Sensor 1 |
34 | GP28 | Signal for Sensor 2 |
Once you have the code wired, you are ready to start writing the code.
Write the Code
The code for this example will use some of the code from the project in Chapter 8. We will use the read_timer.py file without changes. We must modify the SoilMoisture class (soil_moisture.py) to work with a file instead of storing the values read in memory. Finally, we will not need the display library.
We will examine the new and changed code in this section. Other code modules used are unchanged from Chapter 8. Refer to Chapter 8 for details on those modules.
However, there are two additional libraries we will need for this project. We will need a library for the SD card and another for the RTC module.
Once again, the SD card support on the Pico Wireless Pack is considered experimental, but the basic operations for file reading and writing work just fine. While Pimoroni does not currently supply a MicroPython library, we can find one elsewhere. The library that works best is found at https://forums.pimoroni.com/t/pico-wireless-how-to-access-sd-card/17751/3. Simply open Thonny and create a new file, then copy the code from the website into the file and name it sdcard.py. You will upload this file to the project8 folder on the Pico later.
The library for the RTC module can be found on the vendor’s website in the form of a zip file (www.waveshare.com/w/upload/2/26/Pico-rtc-ds3231_code.zip). Download the file and unzip it and then locate the file named ds3231.py in the python folder. You will upload this file to the project8 folder on the Pico later.
However, the library function named read_time() prints a string for the time. That won’t work for us since we need to get the time either as a tuple like we did in Chapter 8 or, since the read_time() function already formats the datetime for printing, return the string instead. Thus, you will need to modify this class slightly for use with this project.
Notice we are only changing the print() statement to return the string without the day of the week.
Now that we have the libraries we need and the RTC library modified, let’s start by looking at the main code.
Main Code
The main code is like the code for the last project. However, this time we will use a file to store the HTML code (since it doesn’t change) and a list of HTML-formatted strings for populating an HTML table with the data from the file.
Unlike the last project, the HTML code does not include a button, but we can format a command manually on the URL. We can use this technique to allow access to commands without using buttons or other user interface features. It also helps to make these commands harder to use to prevent overuse. For example, we can provide a clear log command. We would use a URL like http://192.168.42.140/CLEAR, which submits a GET request to the HTML server. We can capture that command and clear the log when it is issued.
The following sections explain the initialization code and the functions needed. We will see the complete code in a later section. Let’s start with the HTML code.
HTML Code (Files)
We will store the HTML code needed in files to save memory. Recall by reading a row at a time, we do not have to take up space with the strings in our code. As your projects grow in complexity, this could become an issue. Thus, this project demonstrates a way to save some memory.
The HTML for this project creates a web page with a simple table that includes all the data in the file at the time of the request. To make things easier, we will use three files. The first file (named part1.html) will contain the HTML code up to the table rows, and the second file (named plant_data.csv), which is populated by the SoilMoisture class, and the third (named part2.html) will contain the remaining HTML code.
HTML Code (part1.html)
Notice the meta tag. Here is an example of how we can add HTML code to automatically refresh the page periodically. In this case, it will refresh every 30 seconds.
Notice the table code. Again, don’t worry if this seems strange. It works and it is very basic. Those familiar with HTML may want to embellish and improve the code. The last line establishes the header for the table.
So, how do we use these files? When we send a response back to the client (the web page), we read the first file sending one row at a time, then read the data file sending one row at a time, then read the last file sending one row at a time. We will use a helper function to read the data file in the SoilMoisture class.
Imports
Imports for main.py
Now let’s look at the constants.
Constants
Now let’s look at the setup code.
Setup Code
Setup Code
Next, we will need three helper functions for the web server operations.
Helper Functions
Web Server Functions
Finally, we will use a function for the main portion of the code.
Main Function
Main Function
Let’s look at the completed code.
Complete Code
Main Code Module
Now that we have the main code module, let’s look at the soil moisture class.
Soil Moisture Class
The SoilMoisture class is based on the class with the same name from Chapter 8, but with some significant changes. Most significantly, the comma-separated file on the SD card to store the data (plant_data.csv) is saved on the SD card on the Wireless Pack, which permits easy removal of the data to transfer it to your PC (you don’t need the Pico powered on and connected to your PC). And, instead of returning only the last value read for each sensor, it returns all rows from the file as well as any recently read values. This way, we can populate a list (table) to show the user all values read.
However, to do so reliably when run with multiple threads, we will need to use a special threading concept called a lock to protect critical portions of the code that change class variables to ensure only one thread can change the value(s) at a time. We will see how this works as we work through the code.
Be sure to refer to Chapter 8 for tips on calibrating the sensors. The code to calibrate the sensors is in Chapter 8.
Other than those changes, the features of the class remain the same, so we will only look at those functions that are removed or changed.
Public Functions
The Chapter 8 implementation used three public methods to clear the log (clear_log()), get the last values read (get_values()), and a long-running function to read the sensors (read_sensors()). The read_sensors( ) function has been simplified, and the changes are easy to see.
We will also use the same private functions except for _format_time( ), which is no longer needed because we modified the read_time() function from the RTC class to return a formatted time string.
The version of the class for this project uses all of these functions and the existing private functions as mentioned but renames the get_values() function to get_html_sensor_data() to describe the new behavior more accurately. The get_html_sensor_data() accepts as a parameter a format string and returns all rows in memory formatted with the format string. This function therefore is used when the user visits the home (or root) of the web service and the get_home() function is called in main.py.
get_html_sensor_data() Function
Notice the use of the lock. Let’s talk about that for a moment before we see the completed code for the class.
Using Locks
Since we are working with two threads, the main execution and a thread we launch periodically to read data from the sensors when the read timer fires, we have the potential for two threads to access the same variables at the same time. More specifically, the self.cached_values variable is read by the get_html_sensor_data() function and written to in the read_sensors() function. If they are accessed at the same time, we could have one of several potentially critical errors or the code may fail, or not. It is completely unpredictable. Fortunately, there is a mechanism we can use to “lock” parts of the code so only one thread can access the critical section (the protected memory or variables) at a time.
We also add the lock to the clear_log() function to ensure data isn’t being read or written when the log is cleared. See the completed code for more details.
The threading library for MicroPython is a much simplified version from the Python base. As such, it may not be as robust and could fail under certain conditions such as high contention. Take care when intentionally designing reentrant code in MicroPython.
Using the SD Card
Now, let’s look at the completed code for the class.
Completed Code
SoilMoisture Class
OK, now it is time to give the code a go and run it.
Execute
Before executing the project, be sure to upload the main.py and secrets.py files to the root of the Pico onboard drive. Remember to modify the secrets.py file to include your WiFi SSID and password. You also need to create a project8 folder on the Pico and upload the Pico Wireless Pack library (ppwhttp.py), the modified library for the RTC (ds3231.py), the soil moisture class (soil_moisture.py), the SD card library (sdcard.py), and the read timer class (read_timer.py) files into that folder. Finally, you also need to upload the secrets.py file from the Pico Wireless Pack library. Upload this file to the root of the Pico onboard drive.
You should insert the soil moisture sensors in the plant soil before powering on your Pico.
Running the Plant Monitor Web Project
Once you enter the URL, you should see a web page like the image shown. If you don’t, be sure to check the HTML in your code to ensure it is exactly like what is shown; otherwise, the page may not display properly.
If your Pico doesn’t connect to your WiFi within a reasonable time, you may need to click Stop in Thonny and rerun the project to reset the Wireless Pack.
If everything is working, you can click refresh in your browser to read all of the values read from the file including those in the cache. Or you can wait until the meta tag refresh fires, which will automatically refresh the page. Neat!
Improving the Code
Change the code to always read data from the SD card (the plant_data.csv file) rather than memory. Hint: You will need to use the read/write lock to protect writing to the file when new values are read from the sensors.
Make the code read all of the rows from the SD card on start, but store all new values read into memory writing them to the file on the SD card only after 20 or more values are read.
Change the code to only display the latest values for the sensors writing all old values to the file on the SD card. This is the easiest and most robust option to consider making the code a long-running project.
Once you have both examples working, congratulations. You have just created your first complete IoT projects. How cool is that?
Summary
When you take a typical electronics project such as a weather station, electronic game, home automation, etc. and connect it to the Internet, you’ve just upped the capabilities of that small project.
We saw two simple examples of this by connecting two of our example projects to the Internet. Each used a simple web server to allow us to control hardware and get information from sensors. The technique demonstrated can help you add Internet capabilities to more of the projects in this book. You are only limited by your imagination!
In this chapter, we learned more about cloud systems and how they can be used in IoT projects. Now that you’ve seen how easy it is to get started and how little code is needed in your projects, you can begin to modify your own projects. But we’ve just scratched the surface here. There is so much more that can be done with another simple, free cloud solution.
In the next chapter, we will expand our tour of cloud systems for IoT by looking at one of the most popular free options: ThingSpeak – a popular, easy-to-use, cloud-based IoT data hosting service from MathWorks. You will learn how to send your data to the cloud and display it using nice, easy-to-use graphics using the previous example projects.