Pair Bluetooth connection (laptop/raspi ) with OBD-II - use passcode 1234
python script.py <sleep_duration>
{
"payload": {
"deviceid": "TestDevice002",
"timestamp": 1666691742,
"location": {
"lat": 12.8796778,
"long": -150.897776
},
"accuracy": {
"Horizontal": 20.5
}
}
}
or Or this simpler format:
{
"deviceid": "TestDevice002",
"timestamp": 1666691742,
"location": {
"lat": 12.8796778,
"long": -150.897776
}
}
list ALL devices in a tracker
aws location list-device-positions --tracker-name GeoSyncTracker
Check if the tracker exists:
aws location describe-tracker --tracker-name GeoSyncTracker
Check current device positions:
aws location get-device-position \
--tracker-name GeoSyncTracker \
--device-id "TestDevice001"
List ALL devices in the tracker: (corrected)
aws location list-device-positions --tracker-name GeoSyncTracker
# Create the IoT rule
aws iot create-topic-rule \
--rule-name DeviceLocationRule \
--topic-rule-payload '{
"sql": "SELECT * FROM \"devices/+/location\"",
"description": "Forward device location data to Location Service tracker",
"actions": [
{
"location": {
"trackerName": "GeoSyncTracker",
"deviceId": "${deviceid}",
"latitude": "${location.lat}",
"longitude": "${location.long}",
"timestamp": {
"value": "${timestamp}",
"unit": "SECONDS"
},
"roleArn": "arn:aws:iam::'$ACCOUNT_ID':role/IoTLocationServiceRole"
}
}
]
}'
Current Date 
date +%s
1. Time-Based Retention: 30 Days Maximum
All position data is automatically deleted after 30 days
This is a hard limit - you cannot extend it
If a device transmits every second for 20 days, all that data will be stored for the full 30 days
2. No Volume Limits on Position Updates
There's no limit on the number of position updates per device beyond the 30-day retention
A device can send position updates every second, minute, or any frequency you need
All updates within the 30-day window are stored
3. Position Filtering (Cost Control) Your tracker has position filtering settings that can reduce storage:
TimeBased (default): Stores maximum 1 position per 30-second interval
DistanceBased: Only stores if device moved >30 meters
AccuracyBased: Only stores if device moved more than measured accuracy
4. API Rate Limits (Not Storage Limits)
BatchUpdateDevicePosition: 50 requests/second (adjustable to 100)
Up to 10 devices per batch request
Your Scenario: If a device transmits every second for 20 days:
With TimeBased filtering: ~57,600 positions stored (1 per 30 seconds × 20 days)
Without filtering: ~1,728,000 positions stored (1 per second × 20 days)
All data retained: For the full 30 days from each timestamp
Cost Implications:
You're charged per position update stored
More frequent updates = higher costs
Position filtering helps control costs by reducing stored updates
Amazon Location Service provides excellent time-based querying capabilities. Here are the different ways to query location data based on time:
1. Time Range Queries (Most Common)
AWS CLI with Time Range:
# Query positions between specific dates/times
aws location get-device-position-history \
--tracker-name GeoSyncTracker \
--device-id "TestDevice002" \
--start-time-inclusive "2025-01-06T10:00:00Z" \
--end-time-exclusive "2025-01-06T18:00:00Z"
Examples of Time-Based Queries:
Last 24 hours:
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
 --device-id "TestDevice002" \
 --start-time-inclusive "$(date -d '24 hours ago' --iso-8601)" \
--end-time-exclusive "$(date --iso-8601)"
Last week:
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
--device-id "TestDevice002" \
 --start-time-inclusive "$(date -d '7 days ago' --iso-8601)" \
 --end-time-exclusive "$(date --iso-8601)"
Specific day (e.g., yesterday):
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
 --device-id "TestDevice002" \
 --start-time-inclusive "2025-01-05T00:00:00Z" \
 --end-time-exclusive "2025-01-06T00:00:00Z"
Business hours only:
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
 --device-id "TestDevice002" \
 --start-time-inclusive "2025-01-06T09:00:00Z" \
--end-time-exclusive "2025-01-06T17:00:00Z"
For large datasets, use pagination:
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
 --device-id "TestDevice002" \
 --start-time-inclusive "2025-01-01T00:00:00Z" \
 --end-time-exclusive "2025-01-06T23:59:59Z" \
 --max-results 100 \
--next-token "your-pagination-token"
API Format (for programmatic access)
REST API Example:
curl -X POST \
"https://tracking.us-east-1.amazonaws.com/tracking/v0/trackers/GeoSyncTracker/devices/TestDevice002/list-positions" \
-H "Content-Type: application/json" \
-d '{
"StartTimeInclusive": "2025-01-06T10:00:00.000Z",
"EndTimeExclusive": "2025-01-06T18:00:00.000Z",
"MaxResults": 100
}'
Supported Time Formats:
ISO 8601: 2025-01-06T14:30:00Z (UTC)
With milliseconds: 2025-01-06T14:30:00.123Z
With timezone: 2025-01-06T14:30:00-05:00
If you don't specify time parameters:
StartTimeInclusive: Defaults to 24 hours ago
EndTimeExclusive: Defaults to current time
The response includes multiple timestamps:
SampleTime: When the device recorded the position
ReceivedTime: When the tracker received the position
This allows you to analyze both device timing and network delays.
Key Points:
Time ranges are inclusive for start time, exclusive for end time
Maximum query range is 30 days (data retention limit)
Use pagination for large datasets
All times should be in UTC for consistency
aws location put-geofence \
--collection-name "explore.geofence-collection" \
--geofence-id "md-derry" \
--geometry '{
"Circle": {
"Center": [-7.313434798642561, 55.01310518738961],
"Radius": 31.971578484915433
}
}'
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=IE
network={
ssid="eir1111111"
psk="xfvgsdgd"
key_mgmt=WPA-PSK
priority=1
}
network={
ssid="Am2222222"
psk="dfhjgdfkjh"
key_mgmt=WPA-PSK
priority=2
}
Restart the network interface to apply the changes:
sudo wpa_cli reconfigure
sudo ifdown wlan0
sudo ifup wlan0
sudo apt-get update
sudo apt-get install python3-pip gpsd gpsd-clients
pip3 install obd gpsd-py3 paho-mqtt
In current set up GPS Module is connected to uart connections that should be read from a serial connection to do this
Remove Serial Console from /boot/cmdline.txt
Ensure that the serial port is available for your GPS module, you should remove the serial console settings from the cmdline.txt file.
sudo nano /boot/cmdline.txt
Find the part that reads console=serial0,115200 and delete it. Make sure not to change any other part of this line.
Save and exit
sudo reboot
Verify changes
dmesg | grep tty
You should not see any references to ttyAMA0 or serial0 being used for the console.
To ensure that your Raspberry Pi uses ttyAMA0 for your GPS module and that all settings are correctly configured, you will need to make adjustments in both /boot/cmdline.txt and /boot/config.txt. Here's a detailed guide on how to do this:
The /boot/cmdline.txt file contains parameters that are passed to the Linux kernel at boot. It's important to remove any references to serial consoles that might be using ttyAMA0 or any UART.
Look for any text that includes console=serial0,115200 or console=ttyAMA0,115200. If found, delete these segments to prevent the kernel from using the UART as a console . this should be already done in previous steps
The /boot/config.txt file is used to set various boot and hardware configuration options. To ensure ttyAMA0 is available for general use, you need to make sure it is not being used by the Bluetooth module on Raspberry Pi models that have Bluetooth (such as the Raspberry Pi 3 and later).
update result
[all]
enable_uart=1
dtoverlay=w1-gpio
gpu_mem=128
dtoverlay=miniuart-bt
This configuration swaps the Bluetooth module to ttyS0, which is less reliable for data transmission but keeps Bluetooth functional.
Use terminal tools like minicom or screen to directly test the serial communication:
sudo apt-get install minicom
sudo minicom -b 9600 -o -D /dev/ttyS0
BN-220 GPS Module Raspberry Pi 3 Model B
----------------- ---------------------
VCC ----------> 5V (Pin 2)
RX ----------> GPIO14 (TXD) (Pin 8)
TX(white) ----------> GPIO15 (RXD) (Pin 10)
GND ----------> GND (Pin 6)
Note : if you swap RX or TX e.g RX of BN-220 connect to GPIO15 , u will see the blue light will stop blinking - NOT CORRECT . make sure the RX and TX for BN is correctly connected to Raspi
import obd
import gpsd
import time
import json
import paho.mqtt.client as mqtt
import sys
# Connect to the OBD-II adapter
obd_connection = obd.OBD() # Auto-connects to USB or Bluetooth
# Connect to the GPS module
gpsd.connect()
# MQTT configuration
MQTT_BROKER = "your_mqtt_broker_address"
MQTT_PORT = 1883
MQTT_TOPIC = "vehicle/data"
client = mqtt.Client()
client.connect(MQTT_BROKER, MQTT_PORT, 60)
def get_obd_data():
rpm = obd_connection.query(obd.commands.RPM)
speed = obd_connection.query(obd.commands.SPEED)
coolant_temp = obd_connection.query(obd.commands.COOLANT_TEMP)
throttle_pos = obd_connection.query(obd.commands.THROTTLE_POS)
intake_temp = obd_connection.query(obd.commands.INTAKE_TEMP)
maf = obd_connection.query(obd.commands.MAF)
return {
'rpm': rpm.value.magnitude if rpm.value else None,
'speed': speed.value.to("mph").magnitude if speed.value else None,
'coolant_temp': coolant_temp.value.magnitude if coolant_temp.value else None,
'throttle_position': throttle_pos.value.magnitude if throttle_pos.value else None,
'intake_temp': intake_temp.value.magnitude if intake_temp.value else None,
'maf': maf.value.magnitude if maf.value else None
}
def get_gps_data():
gps_packet = gpsd.get_current()
return {
'latitude': gps_packet.lat,
'longitude': gps_packet.lon,
'speed': gps_packet.hspeed
}
def main(sleep_duration):
while True:
obd_data = get_obd_data()
gps_data = get_gps_data()
# Combine data
combined_data = {
'obd': obd_data,
'gps': gps_data,
'timestamp': time.time()
}
# Log data to console
print(json.dumps(combined_data, indent=4))
# Send data to MQTT broker
client.publish(MQTT_TOPIC, json.dumps(combined_data))
# Wait before next read
time.sleep(sleep_duration)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python script.py <sleep_duration>")
sys.exit(1)
sleep_duration = int(sys.argv[1])
main(sleep_duration)
Export to JSON file:
# Export specific time period to JSON
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
 --device-id "TestDevice002" \
 --start-time-inclusive "2025-01-01T00:00:00Z" \
 --end-time-exclusive "2025-01-07T23:59:59Z" \
--max-results 1000 > audit_route_jan1-7_2025.json
Export to CSV format:
# Export and convert to CSV for easier analysis
aws location get-device-position-history \
 --tracker-name GeoSyncTracker \
 --device-id "TestDevice002" \
 --start-time-inclusive "2025-01-01T00:00:00Z" \
 --end-time-exclusive "2025-01-07T23:59:59Z" \
--output table > audit_route_jan1-7_2025.csv
Create a bash script for regular exports:
#!/bin/bash
# audit_export.sh
TRACKER_NAME="GeoSyncTracker"
DEVICE_ID="TestDevice002"
START_DATE="2025-01-01T00:00:00Z"
END_DATE="2025-01-07T23:59:59Z"
OUTPUT_DIR="/audit/location_data"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Create output directory
mkdir -p $OUTPUT_DIR
# Export position history
aws location get-device-position-history \
--tracker-name $TRACKER_NAME \
--device-id $DEVICE_ID \
--start-time-inclusive $START_DATE \
--end-time-exclusive $END_DATE \
--max-results 10000 > "$OUTPUT_DIR/route_audit_${DEVICE_ID}_${TIMESTAMP}.json"
# Upload to S3 for long-term storage
aws s3 cp "$OUTPUT_DIR/route_audit_${DEVICE_ID}_${TIMESTAMP}.json" \
s3://your-audit-bucket/location-data/year=2025/month=01/
echo "Audit export completed: $TIMESTAMP"
https://python-obd.readthedocs.io/en/latest/Command%20Tables/
https://github.com/tzebrowski/ObdMetrics