I have a python program running on a raspberry pi that is taking data from a suite of sensors once a second and writing it to a JSON file and then uploading that JSON file to ThingSpeak once a minute. This program appears to work very well, however, when reviewing the data on ThingSpeak every time a new JSON file is uploaded, certain sensor data “jumps” at the beginning of the next JSON file until it reaches steady state again. This is most apparent with the Adafruit BME680 sensor that records temperature, pressure, humidity, and the voltage organic content (VOC). The data for each of these readings is shown in Figure 1, with temperature being the most clear case of this phenomena.
Figure 1: https://i.sstatic.net/fkhCMu6t.png
While this jump isn’t very large (temperature values only drop 0.05 C from the last data point of a JSON to the first point of the next JSON) and likely won’t impact the final results or what I am trying to accomplish, I would like to know if there is a reason this is happening and how one would fix it? Is the sensor rebooting in between uploads of the JSON file? Can that be fixed by modifying my code? Or is it more involved than that?
#1. Import necessary libraries for the script
import sys
import json
import time
import os
import psutil
import requests
import busio
import board
import adafruit_tca9548a
import adafruit_bme680
import adafruit_adxl34x
import adafruit_sgp40
#import adafruit_ads1x15.ads1015 as ADS
import paho.mqtt.publish as publish
import string
import numpy as np
#from adafruit_ads1x15.analog_in import AnalogIn
i2c = busio.I2C(board.SCL, board.SDA)
tca = adafruit_tca9548a.TCA9548A(i2c)
bme680 = adafruit_bme680.Adafruit_BME680_I2C(tca[0])
accelerometer = adafruit_adxl34x.ADXL345(tca[1])
sgp = adafruit_sgp40.SGP40(tca[2])
#ads = ADS.ADS1015(tca[3])
bme680.oversample_humidity = 2
bme680.oversample_temperature = 2
bme680.oversample_pressure = 2
bme680.oversample_filter = 2
ADC_CHANNEL = 0
GAIN = 1
#2. Define global variabesl that track the last connection time and last update time. Define time intervals to update the data, and post the data to ThingSpeak
last_connection_time = time.time() #Track the last connection time
last_update_time = time.time() #Track the last update time
posting_interval = 60 #Post data once every minute
update_interval = 1 #Update once every 15 seconds
sampling_rate = 100
accel_update_interval = 1/sampling_rate
last_accel_update_time = time.time()
acc_x_sum = 0
acc_y_sum = 0
acc_z_sum = 0
#Set the sampling rate of the accelerometer to 800 Hz
accelerometer.data_rate = adafruit_adxl34x.DataRate.RATE_100_HZ
#3. Deinfe you ThingSpeak write API key and channel ID settings, along with the ThingSpeak server settings
write_api_key = "26LFZRWM1ERWEDX3"
channel_ID = "2729406"
url = "https://api.thingspeak.com/channels/" + channel_ID + "/bulk_update.json" #ThingSpeak server settings
message_buffer = []
#4. Define the function httpRequest that sends data to ThingSpeak and prints the response code from the server.
#The response code 202 indicates that the server has accepted the request and will process it.
def httpRequest():
#Function to send the POST request to ThingSpeak channel for bulk update.
global message_buffer
bulk_data = json.dumps({'write_api_key':write_api_key,'updates':message_buffer}) #Format the json data buffer
request_headers = {"User-Agent":"mw.doc.bulk-update (Raspberry Pi)","Content-Type":"application/json","Content-Length":str(len(bulk_data))}
"""
# Save JSON data to a file before sending
timestamp = int(time.time())
filename = f"data_to_thingspeak_{timestamp}.json"
with open(filename, "w") as file:
file.write(bulk_data)
print(f"Data saved to {filename}")
"""
#Make the request to ThingSpeak
try:
print(request_headers)
response = requests.post(url,headers=request_headers,data=bulk_data)
print (response) #A 202 indicates that the server has accpeted the request
#input("Press enter to continue...")
except e:
print(e.code) #Print the error code
message_buffer = [] #Reinitialize the message buffer
global last_connection_time
last_connection_time = time.time() #Update the connection time
#5. Define the fucntion getData that returns the data
def getData():
#Function that returns the data from the array of sensors
#bme680
humidity = bme680.relative_humidity
temperature = bme680.temperature
pressure = bme680.pressure
gas_resistance = bme680.gas
#sgp40
#voc = sgp.raw
#adxl345
acc_x, acc_y, acc_z = accelerometer.acceleration
#acc_x, acc_y, acc_z = acceleration_rms()
#spw2430 and ADS1015
#channel = AnalogIn(ads, ADS.P0)
#mic_value = channel.value
return humidity,temperature, pressure, gas_resistance
#6. Define the function updatesJson to continuosuly update the message buffer every 15 seconds
def updatesJson():
#Function to update the message buffer every 1 second with data.
#And then call the httpRequest function every 1 minute.
global last_update_time, last_connection_time, acc_x_rms, acc_y_rms, acc_z_rms
if time.time() - last_update_time >= update_interval:
# Create a message with sensor data
message = {}
message['delta_t'] = int(round(time.time() - last_update_time))
humidity, temperature, pressure, gas_resistance = getData()
message['field1'] = humidity
message['field2'] = temperature
message['field3'] = pressure
message['field4'] = gas_resistance
message['field5'] = acc_x_rms
message['field6'] = acc_y_rms
message['field7'] = acc_z_rms
#message['field8'] = mic_value
global message_buffer
message_buffer.append(message) #Add to buffer
#print(f"Data added to buffer: {message}") #Debugging output
last_update_time = time.time() #Update last update time here
# If posting interval time has crossed 2 minutes update the ThingSpeak channel with your data
if time.time() - last_connection_time >= posting_interval:
httpRequest()
last_update_time = time.time()
#7. Run an infinite loop to continously call the function updatesJson every 15 seconds.
if __name__ == "__main__": #To ensure that this is run directly and does not run when imported
while True:
#If update interval time has crossed 1 second upates the message buffer with data
if time.time() - last_accel_update_time >= accel_update_interval:
acc_x, acc_y, acc_z = accelerometer.acceleration
acc_x_sum = acc_x_sum + acc_x**2
acc_y_sum = acc_y_sum + acc_y**2
acc_z_sum = acc_z_sum + acc_z**2
last_accel_update_time = time.time()
#print(acc_x_sum)
#print(acc_y_sum)
#print(acc_z_sum)
if time.time() - last_update_time >= update_interval:
acc_x_rms = np.sqrt((1/sampling_rate)*acc_x_sum)
acc_y_rms = np.sqrt((1/sampling_rate)*acc_y_sum)
acc_z_rms = np.sqrt((1/sampling_rate)*acc_z_sum)
acc_x_sum = 0
acc_y_sum = 0
acc_z_sum = 0
updatesJson()