BLOG | Technology

Building a Weather App with a Raspberry Pi, Astra DB, and Langflow

Updated: March 14, 2025 · 7 min read
Building a Weather App with a Raspberry Pi, Astra DB, and Langflow

To celebrate PI Day this year, we thought it would be fun to build something with a Raspberry Pi that uses Astra DB and/or Langflow. Fortunately, I have just the project in-mind: A weather application!

To that end, our goal will be to use the National Weather Service’s (NWS) data API. Essentially, we will call this API to get the most recent weather data, store it in Astra DB, and display it on a simple front-end.

Requirements

To build our project, we’re going to need a few things. First of all, our development environment will use the following:

  • Java 17

  • Spring Boot

  • Maven

  • Vaadin

  • An Astra DB account with an active database and Langflow instance.

And of course, we’ll also need a Raspberry Pi. For this project, we used a Cana Kit™ Raspberry Pi 5 Starter Kit PRO Turbine Black (4GB RAM / 128GB Micro SD).

The weather application

The weather application we will use can be found in this GitHub repository: https://github.com/aar0np/weather-app/tree/main

This application originally appeared in Chapter 8 of the book Code with Java 21. The original project was designed to work with DataStax Astra DB, using the CQL protocol. Our fork of it is a bit different, as it can refresh its data view from either the Astra DB Data API or from a Langflow API endpoint.

At its core, the project is a Java Spring Boot application, which has a Vaadin web front end, and also exposes two restful endpoints. The idea behind the endpoints is as much for testing as it is functional. One endpoint pulls the most recent update from the NWS API for a given weather station ID, and stores it in Astra DB. The other endpoint retrieves the most-recent reading from Astra DB for a particular station and year/month combination.

Restful examples

Pulling the latest reading from the NWS for the station KMSP (Minneapolis/St.Paul International Airport), and storing it in Astra DB:

curl -X PUT http://127.0.0.1:8080/weather/astradb/api/latest/station/kmsp

This endpoint returns a response similar to the following:

{"stationId":"https://api.weather.gov/stations/KMSP","monthBucket":202503,"timestamp":"2025-03-07T22:53:00Z","readingIcon":"https://api.weather.gov/icons/land/day/few?size=medium","stationCoordinatesLatitude":-93.22,"stationCoordinatesLongitude":44.88,"temperatureCelsius":5.6,"windDirectionDegrees":310,"windSpeedKMH":20.52,"windGustKMH":0.0,"visibilityM":16090,"precipitationLastHour":0.0,"cloudCover":{"7620":"FEW","1830":"FEW"}}

This endpoint pulls the latest reading for a specific station and year/month combination:

curl -X GET http://127.0.0.1:8080/weather/astradb/api/latest/station/kmsp/month/202503

This endpoint returns a response similar to the following:

{"stationId":"kmsp","monthBucket":202503,"timestamp":"2025-03-07T22:53:00Z","readingIcon":"https://api.weather.gov/icons/land/day/few?size=medium","stationCoordinatesLatitude":-93.22,"stationCoordinatesLongitude":44.88,"temperatureCelsius":5.6,"windDirectionDegrees":310,"windSpeedKMH":0.0,"windGustKMH":0.0,"visibilityM":0,"precipitationLastHour":0.0,"cloudCover":{"7620":"FEW","1830":"FEW"}}

Note: The above restful GET call is also used to populate the web frontend.

The Astra DB Data API

First, create a new Astra DB database. We can also use an existing database, as long as we create the following:

  • Keyspace named: “weatherapp”

  • Non-vector collection named: “weather_data”

There are two primary controller methods that handle the above data calls. The first method is named putLatestAstraAPIData and handles the restful PUT call. First, it performs a GET call on the NWS API endpoint for the stationid that was passed-in. It takes the payload, maps it to an Astra DB Data API Document type named weatherDoc. Then, it saves weatherDoc in Astra DB (via the Data API). Finally, it maps the response to a WeatherReading object named currentReading, and returns it. The code for the putLatestAstraAPIData() method is shown below:

@PutMapping("/astradb/api/latest/station/{stationid}")
public ResponseEntity<WeatherReading> putLatestAstraAPIData(
             @PathVariable(value="stationid") String stationId) {

       LatestWeather response = restTemplate.getForObject(
                    "https://api.weather.gov/stations/" + stationId + 
                    "/observations/latest", LatestWeather.class);

       Document weatherDoc = mapLatestWeatherToDocument(response, stationId);

       // save weather reading
       collection.insertOne(weatherDoc);

       // build response
       WeatherReading currentReading =
                    mapLatestWeatherToWeatherReading(response);

      return ResponseEntity.ok(currentReading);
}

The other controller method is named getLatestAstraAPIData and it handles the RESTful GET call. This method takes the stationid and the monthBucket that were passed-in, and uses the Data API to find any matching documents. As there might be multiple, the results are sorted in descending order by timestamp, and the top document is processed. This ensures that the latest document is mapped and returned.

The code for the getLatestAstraAPIData() method is shown below:

@GetMapping("/astradb/api/latest/station/{stationid}/month/{month}")
public ResponseEntity<WeatherReading> getLatestAstraAPIData(
             @PathVariable(value="stationid") String stationId,
             @PathVariable(value="month") int monthBucket) {

       Filter filters = Filters.and(eq("station_id",(stationId)),
                           (eq("month_bucket",monthBucket)));
       Sort sort = Sorts.descending("timestamp");
       FindOptions findOpts = new FindOptions().sort(sort);
       FindIterable<Document> weatherDocs = collection.find(filters, findOpts);
       List<Document> weatherDocsList = weatherDocs.all();

       if (weatherDocsList.size() > 0) {
              Document weatherTopDoc = weatherDocsList.get(0);
              WeatherReading currentReading =
                           mapDocumentToWeatherReading(weatherTopDoc);
              return ResponseEntity.ok(currentReading);
       }

       return ResponseEntity.ok(new WeatherReading());
}

The Langflow API

This entire process can also work through Langflow. Open up Langflow, create a new flow, and pick the “Simple Agent” template. This simple agent is all that we need.

 A sample flow created by selecting the “Simple Agent” template in Langflow. A sample flow created by selecting the “Simple Agent” template in Langflow.

The agent is built with the URL “tool,” which allows the agent to call out to external web addresses, including APIs. To expose this agent, we simply need to click on the “API” tab and make note of the Langflow endpoint URL. We will add this URL as an environment variable with our application.

Inside our application, our call to Langflow is handled by a method named askAgent. Simply put, this method calls our Langflow API endpoint, maps the result, and returns it to the UI. The code for the askAgent() method can be seen below:

public WeatherReading askAgent (AgentRequest req) {

       String reqJSON = new Gson().toJson(req);
       HttpEntity<String> requestEntity =
                    new HttpEntity<>(reqJSON, langflowHeader);

       ResponseEntity<LangflowResponse> resp =
                    restTemplate.exchange(LANGFLOW_URL,
                    HttpMethod.POST,
                    requestEntity,
                    LangflowResponse.class);

       LangflowResponse lfResp = resp.getBody();
       LangflowOutput1[] outputs = lfResp.getOutputs();

       return mapLangflowResponseToWeatherReading(outputs);
}

The method inside our Vaadin UI code that calls the askAgent() method, is named refreshLangflow() and is triggered by a button on the UI. It composes a message for our Langflow agent, sends it, and uses the data returned to refresh the UI. The code can be seen below:

private void refreshLangflow() {

      String message = "Please retrieve the latest weather data (including the weather icon url) in a text format using this endpoint: "
+ "https://api.weather.gov/stations/" + stationId.getValue() + 
"/observations/latest";
       latestWeather = controller.askAgent(new AgentRequest(message));

       refreshData(latestWeather);
}

After reviewing the code, we should now be ready to build and configure our hardware.

Raspberry Pi

First of all, we will need to assemble the Pi. Fortunately, Cana Kit has a great setup video that walks through the entire process.

Note: I prefer to use Cana Kits, because they come with everything that you need, such as a Micro HDMI cable, a heat sink with fan, and a Micro SD card.

Once the Pi is assembled and running, it will check for updates and reboot. When we get to the Raspberry Pi OS desktop, we will have a few things to install (using the Terminal application).

Java

For our application to run, we need a Java Virtual Machine (JVM). As we will also need to build our application locally, we’ll need a Java Development Kit (JDK) as well. In our case, our Pi had Java 17 installed, and this is sufficient for our purposes.

Note: The Raspberry Pi OS makes it difficult to install and configure newer versions of Java. Fortunately, our project compiles just fine with Java 17.

Maven

Maven is a build- and dependency-management tool for Java. Our project was built with Maven, so we will need to install it as well:

sudo apt install maven

Git

Our Pi also had Git installed. After creating a new SSH key and adding it to your GitHub account, we should be able to clone the project repository:

git clone git@github.com:aar0np/weather-app.git

This will download the code and create a local directory for our application, where we can build and run it.

Putting it all together

First, we will cd into our project directory and then build it with Maven:

cd weather-app
mvn clean install -Pproduction

Next, we need to define three environment variables:

export ASTRA_DB_API_ENDPOINT=https://not-real-us-east1.apps.astra.datastax.com
export ASTRA_DB_APP_TOKEN=AstraCS:wtqNOTglg:725REAL238dEITHER563486d
export ASTRA_LANGFLOW_URL=https://api.langflow.astra.datastax.com/lf/6f-not-real-9493/api/v1/run/060d2-not-real-caef?stream=false

We can now run our application. Maven will create a JAR file in the weather-app/target directory. If we locate this JAR file, we can run it like this:

java -jar target/weatherapp-0.0.1-SNAPSHOT.jar

A successful run should produce several log messages, the last of which should look similar to this:

2025-03-07T20:02:02.259-06:00  INFO 53787 --- [WeatherApp] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-03-07T20:02:02.278-06:00  INFO 53787 --- [WeatherApp] [           main] c.d.weatherapp.WeatherappApplication     : Started WeatherappApplication in 1.795 seconds (process running for 2.147)
2025-03-07T20:02:04.855-06:00  INFO 53787 --- [WeatherApp] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-03-07T20:02:04.855-06:00  INFO 53787 --- [WeatherApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-03-07T20:02:04.856-06:00  INFO 53787 --- [WeatherApp] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms

From another terminal window/tab, let’s add some data to the DB:

curl -X PUT http://127.0.0.1:8080/weather/astradb/api/latest/station/kmsp

Now, navigate to the local IP on port 8080: http://127.0.0.1:8080/

The Station ID is pre-populated with “kmsp” and the current year/month is auto-generated. Clicking either “Astra DB Refresh” or “Langflow Refresh” should produce something similar to this:

Our finished application running on a Raspberry Pi.Our finished application running on a Raspberry Pi.

Note: The Astra DB Refresh will be faster than the Langflow Refresh.

Depending on the intended usage, it might be preferable to add a crontab entry for the PUT call to keep the data recent:

crontab -e
...
15 * * * * curl -X PUT http://127.0.0.1:8080/weather/astradb/api/latest/station/kmsp

With that, we should have a working weather application running on a Raspberry Pi! And without having to mount any pesky sensors in the backyard. Want to try this yourself? Get started with Astra DB and Langflow today!

Happy Pi Day!

 

More Technology

View All
Bridging Retrieval and Generation: How Semantic Testing Strengthens RAG Applications

Bridging Retrieval and Generation: How Semantic Testing Strengthens RAG Applications

Mark Wolters