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

ESP32软AP模式下WebServer无法执行HTML中的JavaScript文件,实时压力图表不显示

ESP32软AP模式下WebServer无法执行HTML中的JavaScript文件,实时压力图表不显示

你已经精准定位到了核心问题——ESP32软AP模式下无法访问互联网,导致HTML中引用的在线Highcharts图表库脚本加载失败,进而依赖这个库的本地JavaScript代码完全无法启动执行。

虽然你确认了/readings接口能正常返回数据,本地JS文件单独运行时功能正常,但因为在线脚本加载失败,后续的图表初始化、数据绘制逻辑都没有触发的基础。

下面是具体的修复步骤和优化建议:


修复步骤

1. 下载Highcharts本地文件

前往Highcharts官方渠道下载和你之前在线引用版本一致的highcharts.js文件(确保功能兼容)。

2. 上传本地资源到LittleFS

将下载好的highcharts.js,和你的index.html、script.js、style.css、favicon.png等文件一起,通过Arduino IDE的ESP32 Sketch Data Upload插件(需提前安装)上传到ESP32的LittleFS分区中。

3. 修改HTML的脚本引用

把HTML中原来的在线脚本引用替换为本地路径:

<!-- 原在线引用(注释或删除) -->
<!-- <script src="https://code.highcharts.com/highcharts.js"></script> -->
<!-- 替换为本地引用 -->
<script type="text/javascript" src="/highcharts.js"></script>

4. 验证LittleFS文件结构

确保LittleFS根目录下的文件完整:

/
├─ index.html
├─ script.js
├─ highcharts.js
├─ style.css
└─ favicon.png

额外调试建议

  • 连接ESP32软AP后,打开浏览器访问ESP32的IP地址,按F12打开开发者工具,切换到**控制台(Console)**标签,查看是否有Failed to load resource类的加载错误——这是最直接的问题验证方式。
  • 你的AsyncWebServer配置中server.serveStatic("/", LittleFS, "/");已经正确设置了静态资源根路径,无需修改。

整理后的完整代码

Arduino代码(.ino)

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
#include <Arduino_JSON.h>

#define ZERO_SAMPLES 50
#define COUNTS_PER_PSI 735990  // Increased to further scale down PSI values
#define PSI_TO_CMH2O 70.307    // Conversion factor from PSI to cmH2O
#define DRIFT_THRESHOLD 0.1    // PSI threshold to consider as "no pressure"
#define STABLE_TIME 3000       // Time in ms that readings need to be stable for re-zeroing
#define DRIFT_SAMPLES 10 

// SoftAP credentials
const char* ssid = "ESP32";
const char* password = NULL;

long zeroOffset = 8290303;
bool isCalibrated = false;
int sampleCount = 0;
long calibrationSum = 0;

// Drift compensation variables
unsigned long stableStartTime = 0;
bool isStable = false;
float lastPSI = 0;
int stableSampleCount = 0;

const int inputpin = 15;
const int outputpin = 2;
char pressuredata[40];

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create an Event Source on /events
AsyncEventSource events("/events");
// Json Variable to Hold Sensor Readings
JSONVar readings;

// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 750;

// Initialize LittleFS
void initLittleFS() {
  if (!LittleFS.begin()) {
    Serial.println("An error has occurred while mounting LittleFS");
  }
  else{
    Serial.println("LittleFS mounted successfully");
  }
}

void checkAndUpdateZero(long rawPressure, float currentPSI) {
  // Check if current pressure is close to zero
  if (abs(currentPSI - 1) < DRIFT_THRESHOLD) {  // Remember we're applying -1 offset to PSI
    if (!isStable) {
      // Start tracking stable period
      isStable = true;
      stableStartTime = millis();
      stableSampleCount = 1;
    } else {
      stableSampleCount++;
      
      // Check if we've been stable long enough and have enough samples
      if (stableSampleCount >= DRIFT_SAMPLES && 
          (millis() - stableStartTime) >= STABLE_TIME) {
        // Update zero offset
        zeroOffset = rawPressure;
        stableSampleCount = 0;
        isStable = false;
      }
    }
  } else {
    // Reset stable tracking if pressure is not near zero
    isStable = false;
    stableSampleCount = 0;
  }
}

float convertToPSI(long rawValue, long zero) {
  return (float)(rawValue - zero) / COUNTS_PER_PSI;
}

String readPressureRaw() {
  
  while (digitalRead(inputpin)) {}

  long result = 0;
  noInterrupts();
  
  for (int i = 0; i < 24; i++) {
    digitalWrite(outputpin, HIGH);
    digitalWrite(outputpin, LOW);
    result = (result << 1);
    if (digitalRead(inputpin)) {
      result++;
    }
  }
  
  for (char i = 0; i < 3; i++) {
    digitalWrite(outputpin, HIGH);
    digitalWrite(outputpin, LOW);
  }
  
  interrupts();

  long pressure = result ^ 0x800000;
  if (!isCalibrated){
    calibrationSum += pressure;
    sampleCount++;
    readings["sensor1"] = String(0,3);
    if (sampleCount >= 15){
      long zeroOffset = calibrationSum/15;
      isCalibrated = true;
    }
  } else {
    float psi = convertToPSI(pressure , zeroOffset);
    float cmH20 = psi * 70.307;
    checkAndUpdateZero(pressure,psi);
    String pressuredata = String(cmH20,3);
    readings["sensor1"] = pressuredata;
  }
  String jsonresult = JSON.stringify(readings);
  return jsonresult;
}
  
void setup() {
  pinMode(inputpin,INPUT);
  pinMode(outputpin, OUTPUT);
  Serial.begin(115200);
  Serial.println();
  
  // Setting the ESP as an access point
  Serial.print("Setting AP (Access Point)…");
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  
  initLittleFS();
  digitalWrite(outputpin, LOW);
  for(int i = 0; i < 10; i++) {
    digitalWrite(outputpin, HIGH);
    digitalWrite(outputpin, LOW);
  }

  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(LittleFS, "/index.html", "text/html");
  });

  server.serveStatic("/", LittleFS, "/");

  // Request for the latest sensor readings
  server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
    String json = readPressureRaw();
    request->send(200, "application/json", json);
    json = String();
  });

  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);

  // Start server
  server.begin();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    events.send("ping",NULL,millis());
    events.send(readPressureRaw().c_str(),"new_readings" ,millis());
    lastTime = millis();
  }
}

修改后的HTML文件

<!DOCTYPE html>
<html>
  <head>
    <title>DASHBOARD</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/png" href="favicon.png">
    <link rel="stylesheet" type="text/css" href="style.css">
    <!-- 本地Highcharts引用 -->
    <script type="text/javascript" src="/highcharts.js"></script> 
  </head>
  <body>
    <div class="topnav">
      <h1 id="header"> Pressure Waveform and Control Data</h1>
    </div>
    <div class="content">
      <div class="card-grid">
        <div class="card">
          <p id = "id1" class="card-title">Pressure Chart</p>
          <div id="chart-pressure" class="chart-container"></div>
        </div>
      </div>
    </div>
    <script type="text/javascript" src="script.js"></script> 
  </body>
</html>

JavaScript文件(script.js)

window.addEventListener('load', getReadings);

var chartT = new Highcharts.Chart({
  chart:{
    renderTo:'chart-pressure'
  },
  series: [
    {
      name: 'Pressure #21',
      type: 'line',
      color: '#101D42',
    },
  ],
  title: {
    text: undefined
  },
  xAxis: {
    type: 'datetime',
    dateTimeLabelFormats: { second: '%H:%M:%S' }
  },
  yAxis: {
    title: {
      text: 'Pressure '
    }
  },
  credits: {
    enabled: false
  }
});


function plotPressure(jsonValue) {
  var keys = Object.keys(jsonValue);
  var x = (new Date()).getTime();
  const key = keys[0];
  var y = Number(jsonValue[key]);
  
  if(chartT.series[0].data.length > 40) {
    chartT.series[0].addPoint([x, y], true, true, true);
  } else {
    chartT.series[0].addPoint([x, y], true, false, true);
  }
}


function getReadings(){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var myObj = JSON.parse(this.responseText);
      console.log(myObj);
      plotPressure(myObj);
    }
  };
  xhr.open("GET", "/readings", true);
  xhr.send();
}

if (!!window.EventSource) {
  var source = new EventSource('/events');

  source.addEventListener('open', function(e) {
    console.log("Events Connected");
  }, false);

  source.addEventListener('error', function(e) {
    if (e.target.readyState != EventSource.OPEN) {
      console.log("Events Disconnected");
    }
  }, false);

  source.addEventListener('message', function(e) {
    console.log("message", e.data);
  }, false);

  source.addEventListener('new_readings', function(e) {
    console.log("new_readings", e.data);
    var myObj = JSON.parse(e.data);
    plotPressure(myObj);
  }, false);
}

备注:内容来源于stack exchange,提问作者Agasthya Valluri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 03:24:32