Reading: None.
In this lab, you will create a software simulation of a temperature sensor and a GPS. This is a common method for developing a system when the hardware is not available.
Your BeaglePlay will not need Internet access for this lab.
The observer program you created in the previous lab writes data to a file in the form of an SQL INSERT statement. It then requires you to manually execute that statement with the psql program. This is not a long-term solution. In this lab, you will start by modifying your observer program so that it connects to the local database and inserts the data directly.
Proceed as follows.
Modify your observer program so that it collects a reading every 15 seconds. You can use
the sleep
function from the time
module to do this:
import time time.sleep(15)
Modify your observer program again so that instead of writing data to a file, it connects to the local database server and inserts one record into the database every 15 seconds. Be sure you connect outside the loop. Connecting and reconnecting to the database server over and over is inefficient.
For this (and future) labs, you will implement a "mock" GPS device. This is a simple software simulation of a GPS that will allow us to collect realistic data without needing to connect to any actual hardware.
In particular, each of you will pretend to be located at a fixed position according to the table in mock_data.txt. You can hard code your coordinates into your program.
Similarly to the mock GPS, for this lab, you will implement a mock temperature sensor. The model we will use will be more complicated. It will account for daily temperature variations and be parameterized by a baseline temperature and variational amplitude. In addition, the model will provide a source of random noise on top of the readings.
The model for the temperature sensor is as follows:
temperature = -amplitude * math.cos( 2 * math.pi * (hours/24.0) ) + baseline + fuzz_value
Where:
For example, with baseline of 15.0 and amplitude of 5.0, the temperature swings from a low of 10.0 degrees to a high of 20.0 degrees. The low temperatures are at night because of the negative cosine function.
Of course, in real life, temperatures do not follow a perfect sinusoidal shape as this model would predict. However, the model is much more realistic than using the same value all the time. To add more realism to the model by simulating measurement noise, we will add a small random value to the temperature.
Proceed as follows.
Modify get_temperature to use the model above. Pass the baseline, amplitude, hours, and fuzz as parameters, with type hints (they should all have type float).
For example, a call such as:
get_temperature( 15.0, 5.0, 12.0, 1.0 );
would return a temperature in the range from 10.0 to 20.0, depending on hours, with a random variation of +/- 1.0 degrees.
Implement the new version of get_temperature. To generate random values, use the random module.
import random fuzz_value = ( 2.0 * fuzz * random.random() ) - fuzz;
For example, with fuzz of 1.0, this generates a random noise value between -1.0 and +1.0.
Modify the observer to use the new function and verify that it works as expected. You will need to use the datetime module to look up the current hour:
import datetime current_datetime = datetime.datetime.now() current_hours = current_datetime.hour + current_datetime.minute / 60.0
In the previous lab, your archivist program uploaded all of the local data without regard for whatever was already in the cloud. Thus, every time the archivist runs, a lot of duplicated data would be uploaded. We want to avoid that.
Proceed as follows:
Modify your archivist program so that it first queries the cloud database to find out the latest record you uploaded. An SQL query such as this should work:
SELECT MAX(reading_time) FROM reading WHERE system_id = your_system_id;
You need to replace your_system_id
with the integer value of your device's
system ID. This is to ensure you get the maximum reading time of your records without
regard to other people's records.
Modify your archivist program again so that it only extracts recent records from your local database. An SQL query such as this should work:
SELECT * FROM reading WHERE reading_time > latest_reading_time;
Zip together observer.py and archivist.py. Submit the zip archive to Canvas.
Last Revised: 2025-03-11
© Copyright 2025 by Peter Chapin <peter.chapin@vermontstate.edu>