Developing weather display applications
Now that we are experienced IoT application developers, we are ready to take our skills to the next level and create more intricate projects. In this section, we will leverage the capabilities of Raspberry Pi and Sense HAT to create a weather display application and a weather-dependent GO-NO-GO decision-making application.
In Figure 2.13, we see a diagram depicting a call to the OpenWeather API from our Raspberry Pi and Sense HAT, enclosed within its custom case. For our weather display application, we will follow a similar approach to the scrolling stock ticker:
Figure 2.13 – Using the OpenWeather API to get the current weather conditions
We will first acquire an API key from OpenWeather and verify the API call by printing the response to the Shell for testing purposes. We will then utilize the Sense HAT to create a ticker-style display that displays the current weather conditions.
Finally, we will replace the scrolling display with visuals as we build a weather-dependent GO-NO-GO decision-making application.
We will start by obtaining an API key.
Getting an API key
To utilize the OpenWeather web service, it is necessary to obtain an API key. This API key serves as a unique identifier that grants access to the OpenWeather web service. The key is acquired by creating an account on the OpenWeather website and generating an API key by subscribing to the appropriate service. The API key acts as a credential to authenticate and authorize our requests to the OpenWeather web service, enabling us to retrieve weather data for various locations around the world. It’s important to keep the API key confidential and securely store it as it grants access to the OpenWeather API on our behalf.
To obtain a free API key from OpenWeather, we start by navigating to the OpenWeather price page located at https://openweathermap.org/price. We then scroll down to the Current weather and forecasts collection section and click on the Get API key button:
Figure 2.14 – Obtaining an API key from OpenWeather
We follow the instructions for creating a new account. After successfully creating the account, we gain access to our personal dashboard. Inside the personal dashboard, we navigate to the API keys tab and locate the API key in the Key box.
We copy and paste our key into a text editor as we require this key every time we make a call to the OpenWeather web service. As a free user, we are limited to 60 API requests per minute and a total of 1,000,000 API requests per month. This should be more than enough for our application.
With our OpenWeather API key, we can now start to write code to test out the web service.
Creating a scrolling weather information ticker
With our OpenWeather API key, Raspberry Pi, and Sense HAT, we will now create a scrolling weather information device that mimics the functionality of our scrolling stock ticker. We will start by acquiring weather data and display the results in the Shell of Thonny.
After we are satisfied that our API key and web service work, we will integrate the web service data with the Sense HAT, displaying scrolling text that displays the temperature and weather conditions.
Testing the web service
Before integrating the OpenWeather API into our Raspberry Pi and Sense HAT, we will ensure its functionality with a simple program. To create the test code, we do the following:
- We launch Thonny on our Raspberry Pi, activate the
ch2-env
Python virtual environment, and create a new tab. Inside the tab, we write the following code:import requests url = "https://api.openweathermap.org/data/2.5/weather" api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" location = "Toronto" params = { "q": location, "appid": api_key, "units": "metric" } response = requests.get(url, params=params) if response.status_code == 200: data = response.json() temperature = data["main"]["temp"] description = data["weather"][0]["description"] print(f"The current temperature in {location} is {temperature}°C.") print(f"The weather is {description}.") else: print("Error: Failed to retrieve weather information.")
Before we run our code, let’s break it down:
- We start by importing the
requests
module to make HTTP requests. - We then set the
url
variable to the OpenWeather API endpoint. - We set the
api_key
variable with our OpenWeather API key. - We set the
location
variable to the desired location for which we want to retrieve weather information. For our example, this is"Toronto"
. - We then create a dictionary called
params
with the parameters for the API request, including the location, API key, and desired units. - A
GET
request is sent to the OpenWeather API usingrequests.get()
, withurl
andparams
as arguments. - We then check whether the response status code is
200
(indicating a successful request). - If the response is successful, we parse the JSON data from the response using
response.json()
and then do the following:- We extract the temperature and weather description from the parsed data.
- We then print the current temperature and weather information for the specified location.
- If there is an error (response status code other than
200
), we print an error message indicating the failure to retrieve weather information.
- We start by importing the
- We save our code as
weather-api-test.py
and then run it by clicking on the green run button, hitting F5 on the keyboard, or clicking on the Run menu option at the top and then Run current script.
After we execute the code, we should observe a message in the Shell:
Figure 2.15 – OpenWeather API information on the weather in Toronto
As we can see, it is 29.15 °C
and clear in Toronto at the time of this writing. If the web service call did not work, we would’ve seen an Error: Failed to retrieve weather information
error in the console.
With our understanding of how to use the OpenWeather API, we are now ready to use the Sense HAT to create our scrolling weather information ticker. For this, we may reuse much of the code we wrote for our scrolling stock ticker application.
Scrolling weather information on Sense HAT
As we highlighted in our previous project, the versatility of our scrolling stock ticker application allows us to adapt it to display various types of information beyond stocks. In this section, we will leverage this adaptability by integrating the OpenWeather API and our API key to transform our ticker into a dynamic weather display, scrolling real-time weather data such as temperature and current conditions. We will be able to reuse a lot of the code from the scrolling stock ticker. To create the scrolling ticker code, we do the following:
- We launch Thonny on our Raspberry Pi, activate the
ch2-env
Python virtual environment, and create a new tab. We will start with our imports:import requests from sense_hat import SenseHat import time
Important note
As we have already covered these imports with our scrolling stock ticker application, we do not need to cover them again.
- After our imports, we set our variables:
api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' location = 'Toronto' base_url = 'https://api.openweathermap.org/data/2.5/weather' params = { 'q': location, 'appid': api_key, 'units': 'metric' } sense = SenseHat() sense.set_rotation(270) last_call_time = time.time() - 30 last_weather_info = ""
In this code block, we do the following:
- We start by assigning the
api_key
variable to our OpenWeather API key. - We set the
location
variable to the desired location for which we want to retrieve weather information. For our example, this is'Toronto'
. - We then set the
base_url
variable to the OpenWeather API endpoint. - We create a dictionary called
params
with the parameters for the API request, including the location, API key, and desired units. - A
GET
request is sent to the OpenWeather API usingrequests.get()
, withurl
andparams
as arguments. - We then create an instance of the
SenseHat
class and assign it to thesense
variable to interact with the Sense HAT (or emulator). - We set the rotation of the Sense HAT display to 270 degrees using
sense.set_rotation(270)
. This is so that it matches the orientation of the Raspberry Pi in our custom case. We could comment this line out for the emulator. - We set
last_call_time
to the current time minus 30 seconds. - We then add
last_weather_info
, which is a variable that stores the previous weather information.
- We start by assigning the
- Below our variable declarations, we implement an infinite loop to continuously display the weather ticker information; however, to comply with API rate limits of 60 requests per minute and 1,000,000 requests per month, we introduce a time delay of 30 seconds between each web service call. We type the following code below our variable declarations:
while True: current_time = time.time() if current_time - last_call_time >= 30: response = requests.get(base_url, params=params) data = response.json() temperature = data['main']['temp'] description = data['weather'][0]['description'] weather_info = f"{location}: {temperature}°C, {description}" last_weather_info = weather_info sense.show_message(weather_info, scroll_speed=0.05, text_colour=[255, 255, 255]) last_call_time = current_time else: sense.show_message(last_weather_info, scroll_speed=0.05, text_colour=[255, 255, 255]) time.sleep(1)
- As in our scrolling stock ticker application, the heart of our code is wrapped in a
while True
loop, which ensures continuous execution of the main code:- We set the
current_time
variable to the current time usingtime.time()
. - Our code then checks whether the difference between
current_time
andlast_call_time
is greater than or equal to 30 seconds. - If
True
, the following happens:- A
GET
request is sent to the OpenWeather API usingrequests.get()
, withbase_url
andparams
as arguments. - The response is parsed as JSON using
response.json()
and assigned to thedata
variable. - We extract the temperature and weather description from the parsed data and store it as
weather_info.
- The
last_weather_info
variable is updated to store the currentweather_info
value. weather_info
is displayed on the Sense HAT’s dot-matrix display usingsense.show_message()
, with a scrolling speed of 0.05 seconds and white text color (255,255,255
).- The
last_call_time
variable is updated to the current time (current_time
) to mark the timestamp of the last API call.
- A
- If
False
, the previouslast_weather_info
variable is displayed on the Sense HAT display with a scrolling speed of 0.05 seconds and white text color (255,255,255
). - Our program then sleeps for 1 second using
time.sleep(1)
before the next iteration of the loop. This is done to regulate resource consumption and control the update frequency of the Sense HAT’s dot-matrix display.
- We set the
- We save our code as
weather-scroll.py
and then run it by clicking on the green run button, hitting F5 on the keyboard, or clicking on the Run menu option at the top and then Run current script.
After we execute the code, we should observe weather information scrolling across the dot-matrix screen of the Sense HAT. If we are utilizing the emulator, a message will scroll across the simulated dot-matrix display. Figure 2.16 provides a visual representation of how this appears when using the emulator:
Figure 2.16 – Weather information scrolling across the simulated dot-matrix display
One key takeaway is the power of leveraging existing code to create new applications. Despite inherent differences between stock information and weather data, the process of obtaining information for both fields remain remarkably similar. With this realization, we unlock the potential to create a wide range of dynamic and engaging displays using the same underlying code structure.
Here are a few examples of other applications we could build:
- News updates: By modifying the code, we can integrate our device with news APIs to display real-time headlines or updates from popular news sources.
- Social media notifications: By connecting our application to social media APIs, we can configure it to display notifications from popular platforms such as Twitter or Facebook.
- Sports scores: With the integration of sports data APIs, our stock ticker application can be transformed into a real-time sports scoreboard. It can display live scores, game updates, or upcoming game schedules.
- Personalized reminders: By extending the functionality of the code, we can program the stock ticker application to display personalized reminders or to-do lists.
In our next and final project for the chapter, we will replace our scrolling text displays with dot-matrix images and animations. This shift from scrolling text elevates the user experience and will make our projects more visually appealing.
Developing a GO-NO-GO application for decision-making
Consider the role of a youth baseball league convener, responsible for ensuring the safety of playing fields. Critical to this responsibility is making weather-based decisions. If the field is excessively wet, it can impact gameplay, potentially leading to game postponements or cancellations:
Figure 2.17 – Should the game go on?
Another factor to consider is the age of the players. For younger players, playing in the rain raises concerns, as parents are often present and may express dissatisfaction with unfavorable weather conditions. On the other hand, older players, who typically travel to games independently, may be less affected by wet conditions.
These decision-making scenarios represent an opportunity to develop an IoT application that displays a visual indicator, such as a GO or NO-GO graphic, based on weather conditions and player age (Figure 2.17). Imagine a setup with Raspberry Pi and Sense HATs for each baseball diamond, where the Sense HAT display provides real-time guidance on whether the game should proceed as scheduled, be postponed, or be canceled altogether. This IoT application enables efficient decision-making and enhances the overall experience and safety of the youth baseball league.
In our simplified example, we will focus on incorporating basic decision-making into our IoT application. Based on the age of the players and the presence of rain, the Sense HAT will show either a green checkmark or an animated red X sign. While we could introduce additional complexity, the primary objective of this exercise is to demonstrate how decision-making can be integrated into an IoT application. By incorporating these visual indicators, we empower real-time decision-making. Instead of relying solely on the convener, our IoT application takes charge by providing immediate guidance on whether games should proceed or be postponed.
We will start by writing Sense HAT code for indication. For GO, we will show a simple green checkmark against a black background. For NO-GO, we will display a flashing red X. We will run our application using the Sense HAT emulator as it is easier to display screenshots for this book; however, it is strongly encouraged to use the Sense HAT as this makes our application a true IoT device.
We will start by writing code to display a green checkmark.
Creating a checkmark on our Sense HAT
In this section, we will create code that displays a green checkmark against a black background on the Sense HAT emulator. To enhance code implementation and organization, we will encapsulate the functionality within a Python class. This approach simplifies the integration process and promotes code reusability, allowing us to easily incorporate the green checkmark display into our IoT application project.
Prior to writing the code for the GO-NO-GO application, we will create a project directory named GO-NO-GO
on our Raspberry Pi. This dedicated folder will serve as a centralized location for organizing and managing files and resources associated with our project. To create the checkmark code, we do the following:
- We launch Thonny on our Raspberry Pi, activate the
ch2-env
virtual environment, and create a new tab. Inside the tab, we write the following code:from sense_emu import SenseHat class GreenCheck: black = (0, 0, 0) green = (0, 255, 0) check_mark_pixels = [ black, black, black, black, black, black, black, green, black, black, black, black, black, black, green, green, black, black, black, black, black, black, green, green, black, black, black, black, black, green, green, black, green, black, black, black, green, green, black, black, black, green, black, black, green, green, black, black, black, green, green, green, green, black, black, black, black, black, black, green, black, black, black, black ] def __init__(self, rotation=0): self.sense = SenseHat() self.sense.set_rotation(rotation) def display(self): self.sense.set_pixels(self.check_mark_pixels) if __name__ == "__main__": greenCheck = GreenCheck(rotation = 270) greenCheck.display()
In our code, we do the following:
- We start by importing the
SenseHat
class from thesense_hat
module (usesense_emu
for the emulator) - We then define a
GreenCheck
class for displaying a green checkmark on the Sense HAT - We set color values for black and green as RGB tuples.
- We then define a list of pixel values representing the checkmark shape.
- The
GreenCheck
class is initialized with an optional rotation parameter, which defaults to0
. - Inside the
__init__
method, we create a Sense HAT instance and set the rotation to the value ofrotation
. - We define a
display
method that sets the Sense HAT’s pixels to the checkmark pixel values. - We use
if __name__ == "__main__"
to check whether the code is being run directly (not imported). - If
True
, we do the following:- We create an instance of the
GreenCheck
class namedgreenCheck
with a rotation value of270
. - We call the
display()
method to show a green checkmark on the Sense HAT.
- We create an instance of the
- We start by importing the
- We save our code as
green_checkmark.py
in theGO-NO-GO
folder and then run it by clicking on the green run button, hitting F5 on the keyboard, or clicking on the Run menu option at the top and then Run current script. - After we execute the code, we should see a green checkmark against a black background on our Sense HAT emulator:
Figure 2.18 – Green checkmark against black background on Sense HAT’s dot-matrix display
With the completion of the green checkmark code, we will now shift our focus toward creating a NO-GO animation (flashing red X) for our application.
Creating a NO-GO animation on our Sense HAT
The NO-GO animation we have designed consists of a flashing effect on the Sense HAT emulator display, alternating between a red X sign on a black background and a full red display. To create code for the flashing X sign, we do the following:
- We launch Thonny on our Raspberry Pi, activate the
ch2-env
Python virtual environment, and create a new tab. Inside the tab, we start by importing the packages we need:from sense_emu import SenseHat import time
- Once we have our packages defined, we then start to wrap our code up in a Python class:
class RedXAnimation: black = (0, 0, 0) red = (255, 0, 0) frame1 = [ red, black, black, black, black, black, black, red, black, red, black, black, black, black, red, black, black, black, red, black, black, red, black, black, black, black, black, red, red, black, black, black, black, black, black, red, red, black, black, black, black, black, red, black, black, red, black, black, black, red, black, black, black, black, red, black, red, black, black, black, black, black, black, red ] frame2 = [ red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red, red ]
In our code, we do the following:
- We start by defining a
RedXAnimation
class. - We then set color values for black and red as RGB tuples.
- We define
frame1
as a list of pixel values representing a red X sign on a black background. - We define
frame2
as a list of pixel values representing a full red display.
- We start by defining a
- From here, we write code for the initialize method in the class:
def __init__(self, rotation=0): self.sense = SenseHat() self.sense.set_rotation(rotation)
In our code, we do the following:
- We use the
__init__
method to initialize theRedXAnimation
object with an optionalrotation
parameter (defaulted to0
). - Inside
__init__
, aSenseHat
instance is created, and the rotation is set based on the providedrotation
value.
- We use the
- The
display_animation()
method will cycle through the 2 frames for 59 seconds. We do this to align with future client code:def display_animation(self, duration): num_frames = 2 frame_duration = duration / num_frames start_time = time.time() end_time = start_time + 59 while time.time() < end_time: for frame in [self.frame1, self.frame2]: self.sense.set_pixels(frame) time.sleep(frame_duration)
In our code, the following happens:
- Our
display_animation()
method takes a duration parameter. - We set the number of frames to
2.
- We calculate the duration for each frame by dividing the total duration by the number of frames.
- We set the
start_time
variable to the current time usingtime.time()
. - We calculate the
end_time
value by adding 59 seconds to thestart_time
variable. - We create a loop that runs until the current time exceeds the
end_time
value:- Our code iterates over each frame in the list
[
self.frame1, self.frame2]
. - We set the Sense HAT display pixels to the current frame using
self.sense.set_pixels(frame)
. - We then pause the execution for the frame duration using
time.sleep(frame_duration)
.
- Our code iterates over each frame in the list
- Our
- We use the
if __name__ == "__main__":
block to ensure that the test code is executed only when the script is run directly (not imported as a module):if __name__ == "__main__": animation = RedXAnimation(rotation=270) animation.display_animation(duration=1)
In our code, the following happens:
- An instance of the
RedXAnimation
class is created with a rotation value of 270 degrees, assigned to theanimation
variable. - The
display_animation()
method of theanimation
object is called, specifying a duration of 1 second.
- An instance of the
- We save our code as
flashing_x.py
in theGO-NO-GO
folder and then run it by clicking on the green run button, hitting F5 on the keyboard, or clicking on the Run menu option at the top and then Run current script.
After executing the code, we should observe an animation of a red X sign against a black background turn into a full screen of red and back again. In Figure 2.19, we can see what this would look like on the emulator:
Figure 2.19 – NO-GO animation in red screen mode
The NO-GO animation we have created in this section provides a highly effective visual indicator on the Sense HAT display. By alternating between a red X sign on a black background and a full red display, this animation conveys unfavorable conditions that would necessitate the cancellation of a game.
Setting the geolocation for other cities
For finding a city’s geolocation information such as latitude and longitude, websites such as GPS Coordinates (https://gps-coordinates.org/) and Latitude and Longitude Finder (https://www.latlong.net/) are useful. They allow us to input an address or place and receive its precise coordinates.
To finish off our application, we will now write the web service and logic layer, and we will incorporate our green checkmark and red X sign animation.
Writing GO-NO-GO client code
Now, it’s time to dive into the exciting phase (subjective, of course) of writing code to determine whether a game should be a GO or NO-GO based on weather conditions and the age of the players. Our approach will be straightforward: if it’s raining and the players are under 16 years of age, it’s a NO-GO; otherwise, it’s a GO. While we can certainly implement more complex logic, including Machine Learning (ML) if there are multiple parameters to consider, for simplicity, we’ll focus on this basic decision-making process. We do so with the following:
- To create the client code, we launch Thonny on our Raspberry Pi, activate our
ch2-env
Python virtual environment, and create a new tab. Inside the tab, we start by importing the packages we need:import requests import time from green_checkmark import GreenCheck from flashing_x import RedXAnimation
We’ve covered the first three packages already. For the two modules, we do the following:
- We import the
GreenCheck
class from thegreen_checkmark
module to display a green checkmark for the GO decision. - We import the
RedXAnimation
class from theflashing_x
module to display a flashing red X sign animation when the decision is NO-GO.
- We import the
- With our packages and modules in place, we now set our variables:
latitude = '42.346268' longitude = '-71.095764' go = GreenCheck(rotation=270) no_go = RedXAnimation(rotation=270) timer = 1 age = 12 base_url = "https://api.openweathermap.org/data/2.5/weather" api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" params = { 'lat': latitude, 'lon': longitude, 'appid': api_key, 'units': 'metric' }
In our code, we do the following:
- We set
latitude
to'42.346268'
andlongitude
to'-71.095764'
for our baseball diamond. For example, this is the GPS coordinates for Fenway Park in Boston, Massachusetts, US. - We create a
GreenCheck
object namedgo
with a rotation value of 270 degrees. - We create a
RedXAnimation
object namedno_go
with a rotation value of 270 degrees. - We set our
timer
value to 1 second. - We set the age of our players to 12.
- Our code sets the
base_url
value to"https://api.openweathermap.org/data/2.5/weather"
. - Next, we add our OpenWeather
api_key
value. - We then define a
params
dictionary we will use with our web service call (latitude
,longitude
,api_key
, andunits
).
- We set
- We use an infinite loop to check the weather conditions every 60 seconds and update the display on our Sense HAT accordingly:
while True: response = requests.get(base_url, params=params) if response.status_code == 200: data = response.json() temperature = data['main']['temp'] description = data['weather'][0]['main'] print(f"The current temperature is {temperature}°C.") print(f"The weather is {description}.") if description == 'Thunderstorm' or description == 'Rain' and age < 16: print("NO-GO!") no_go.display_animation(duration=1) timer = 1 else: print("GO!") go.display() timer = 60 else: print("Error: Failed to retrieve weather information.") time.sleep(timer)
In our code, we set up an infinite loop using
while True
:- We make a
GET
request to the OpenWeather API usingrequests.get()
and store the response inresponse
. - If the response status code is
200
, we do the following:- We parse the JSON response into a Python dictionary using
response.json()
and assign it todata
. - We then retrieve the current temperature from
data['main']['temp']
and store it intemperature
. - We retrieve a weather description from
data['weather'][0]['main']
and store it indescription
. - We then print the current temperature and weather description. If the weather description is
'Thunderstorm'
or ('Rain'
andage < 16
), we print"NO-GO!"
to the Shell, display the NO-GO animation usingno_go.display_animation(duration=1)
, and set thetimer
variable to 1 second. This is to make the total time before calling the web service 60 seconds, as the animation will go on for 59 seconds. Otherwise, we print"GO!"
to the Shell and display the green checkmark animation usinggo.display()
and then set thetimer
variable to 60 seconds.
- We parse the JSON response into a Python dictionary using
- If the response status code is not
200
, we print an error message. - We pause the execution for the value of
timer
seconds usingtime.sleep(timer)
. This will result in a 60-second delay between calls to the OpenWeather web service.
- We make a
- We save our code as
go-no-go.py
in theGO-NO-GO
folder and then run it by clicking on the green run button, hitting F5 on the keyboard, or clicking on the Run menu option at the top and then Run current script.Upon running the code, we will observe the dot-matrix screen of our Sense HAT (or emulator) displaying either a green checkmark or a flashing red X sign, indicating a GO or NO-GO condition for a game at Fenway Park in Boston. As illustrated in Figure 2.20, the current status is a NO-GO for the game involving our players (under 16 years of age) due to the presence of thunderstorms:
Figure 2.20 – Screenshot of the GO-NO-GO application using the Sense HAT emulator
As mentioned earlier, the flexibility of our code allows for easy expansion of the decision-making logic. In addition to weather data, we can extend our application to consider other factors such as wind speed, humidity, or any on-site sensor readings. By integrating sensors placed directly at the baseball diamond, we can gather real-time data on soil moisture levels or other measurements of interest. This sensor information can then be broadcasted to the internet, enabling us to seamlessly integrate it into our application.
To make our application more dynamic, we can incorporate scheduling information to determine the age of players scheduled to play at a specific baseball diamond at any given time. By extracting this information from a spreadsheet or an online repository, we can automate the process of obtaining player age data and other game-related information such as whether the game is a playoff game. This allows our application to dynamically adjust its decision-making process, ensuring a more accurate GO or NO-GO decision.
Building other GO-NO-GO applications
The GO-NO-GO application marks the last project in the book we will build using the Sense HAT. As we have demonstrated, the combination of the Raspberry Pi and Sense HAT makes for a powerful IoT device. It’s not hard to imagine how we could easily change our baseball GO-NO-GO application for other scenarios. The following are a few examples of other GO-NO-GO applications we could build:
- Flight status checker: By integrating with a flight tracking API, we could build an application that can display a GO or NO-GO status for a specific flight.
- Traffic condition monitor: Utilizing a traffic data API, we could build an application that can assess current traffic conditions on a specific route or at a particular location.
- Event availability indicator: Integrating with an event ticketing API, we could build an application that can determine the availability of tickets for a desired event.
- Public transportation tracker: By connecting to a public transportation API, we could build an application that can provide real-time updates on the status of buses, trains, or other forms of public transportation.
The GO-NO-GO IoT application is but a glimpse into our vast potential in utilizing web services with IoT. With the Raspberry Pi and Sense HAT, our potential expands to diverse IoT applications, monitoring various data and fostering innovation beyond weather-related scenarios.