You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

提高ADXL345采样率后向ThingSpeak上传JSON报400错误求助

问题描述

我开发了一款程序,从Adafruit ADXL345加速度计采集数据,按用户定义的采样率写入JSON文件,之后定期上传至ThingSpeak,采样率可通过变量update_interval调整:

  • 设置update_interval = 1时,程序每秒写入一次数据,每5秒能成功上传至ThingSpeak;
  • 设置update_interval = 0.01时,数据可正常写入JSON,但上传至ThingSpeak返回400错误(请求语法错误);
  • 设置update_interval = 0.5时可成功上传,采样率进一步提高则上传失败。

我是首次学习Python的机械工程师,未修改上传相关代码却出现此问题,完整代码如下:

#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)

#Define what channel each of the sensors are plugged into
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])

#Set the sampling rate of the accelerometer to 800 Hz
accelerometer.data_rate = adafruit_adxl34x.DataRate.RATE_100_HZ

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 = 5               #Post data once every 5 seconds
update_interval = 0.01              #Write data to a JSON file in a defined amount of time

#3. Deinfe you ThingSpeak write API key and channel ID settings, along with the ThingSpeak server settings
write_api_key = "Y1S2TKIM4XTQHESF" 
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
        input("Press enter to continue...")
        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, acc_x, acc_y, acc_z
#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
        
        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, acc_x, acc_y, acc_z = getData()
            #message['field1'] = humidity
            #message['field2'] = temperature
            #message['field3'] = pressure
            #message['field4'] = gas_resistance
            message['field5'] = acc_x
            message['field6'] = acc_y
            message['field7'] = acc_z
            #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_update_time >= update_interval:
            updatesJson()
问题原因
  1. delta_t字段不符合要求:ThingSpeak要求delta_t为正整数(代表与上一条数据的间隔秒数),当update_interval小于0.5时,round()会把间隔取为0,服务器直接判定请求语法错误。
  2. 批量数据量超限:当update_interval=0.01时,5秒内会生成500条数据,ThingSpeak的批量更新API对单请求数据量有限制,数据量过大时会触发400错误。
解决方案

1. 修复delta_t计算逻辑

确保delta_t为正整数,修改updatesJson函数中的对应代码:

# 替换原delta_t计算行
elapsed = time.time() - last_update_time
message['delta_t'] = max(1, int(round(elapsed)))  # 强制delta_t至少为1

2. 控制单批次数据量

在上传前拆分超量数据,避免单次请求数据过多:

# 修改updatesJson中的上传判断逻辑
if time.time() - last_connection_time >= posting_interval:
    # 限制单批次最多100条数据(可根据ThingSpeak调整)
    while len(message_buffer) > 100:
        batch = message_buffer[:100]
        # 临时替换缓冲区发送当前批次
        temp_buffer = message_buffer
        message_buffer = batch
        httpRequest()
        message_buffer = temp_buffer[100:]
    # 发送剩余数据
    if message_buffer:
        httpRequest()
    last_update_time = time.time()

3. 优化错误排查

修改httpRequest的异常处理,获取更详细的错误信息:

try:
    print(request_headers)
    response = requests.post(url, headers=request_headers, data=bulk_data)
    print(f"响应状态码: {response.status_code}")
    print(f"响应内容: {response.text}")  # 打印服务器返回的具体错误
except Exception as e:
    print(f"请求异常: {str(e)}")

4. 匹配硬件与平台限制

你的加速度计设置为100Hz采样,可考虑对数据做降采样(比如每10条取平均值)后再上传,既保留数据趋势,又符合ThingSpeak的上传限制。

内容的提问来源于stack exchange,提问作者Nick Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 05:14:54