分离html并优化
This commit is contained in:
94
data/config.html
Normal file
94
data/config.html
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>ESP32 WiFi 设置</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
background-color: #f0f2f5;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
background-color: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-weight: 500;
|
||||||
|
display: block;
|
||||||
|
margin: 10px 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #1890ff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
background-color: #40a9ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
async function saveWiFiSettings() {
|
||||||
|
const ssid = document.getElementById("ssid").value;
|
||||||
|
const password = document.getElementById("password").value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/saveWiFi", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
body: "ssid=" + encodeURIComponent(ssid) + "&password=" + encodeURIComponent(password)
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
alert(result.message || "WiFi 设置保存成功!");
|
||||||
|
} catch (error) {
|
||||||
|
alert("保存失败,请重试。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>WiFi 设置</h1>
|
||||||
|
<form onsubmit="event.preventDefault(); saveWiFiSettings();">
|
||||||
|
<label for="ssid">SSID</label>
|
||||||
|
<input type="text" id="ssid" name="ssid" required />
|
||||||
|
|
||||||
|
<label for="password">密码</label>
|
||||||
|
<input type="password" id="password" name="password" required />
|
||||||
|
|
||||||
|
<input type="submit" value="保存设置" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
50
data/data_backup/config1.html
Normal file
50
data/data_backup/config1.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ESP32 WiFi Setup</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script>
|
||||||
|
async function saveWiFiSettings() {
|
||||||
|
const ssid = document.getElementById("ssid").value;
|
||||||
|
const password = document.getElementById("password").value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/saveWiFi", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
body: "ssid=" + encodeURIComponent(ssid) + "&password=" + encodeURIComponent(password)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
// 解析JSON响应
|
||||||
|
const result = await response.json();
|
||||||
|
alert(result.message || "WiFi 设置保存成功!");
|
||||||
|
} else {
|
||||||
|
// 尝试解析错误消息
|
||||||
|
try {
|
||||||
|
const errorResult = await response.json();
|
||||||
|
alert(errorResult.message || "保存失败,请重试。");
|
||||||
|
} catch (e) {
|
||||||
|
alert("保存失败,请重试。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
alert("ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>WiFi 设置</h1>
|
||||||
|
<form onsubmit="event.preventDefault(); saveWiFiSettings();">
|
||||||
|
<label for="ssid">SSID:</label><br/>
|
||||||
|
<input type="text" id="ssid" name="ssid"><br/><br/>
|
||||||
|
|
||||||
|
<label for="password">密码:</label><br/>
|
||||||
|
<input type="password" id="password" name="password"><br/><br/>
|
||||||
|
|
||||||
|
<input type="submit" value="保存">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
146
data/data_backup/index1.html
Normal file
146
data/data_backup/index1.html
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ESP32 Data Display</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script>
|
||||||
|
async function fetchData() {
|
||||||
|
const response = await fetch('/data');
|
||||||
|
if (!response.ok) {
|
||||||
|
alert('数据获取失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
document.getElementById('activeDuration').innerText = data.duration;
|
||||||
|
document.getElementById('temperature').innerText = data.temperature;
|
||||||
|
document.getElementById('humidity').innerText = data.humidity;
|
||||||
|
document.getElementById('lightA').innerText = data.lightA;
|
||||||
|
document.getElementById('lightB').innerText = data.lightB;
|
||||||
|
document.getElementById('wiper').innerText = data.wiper;
|
||||||
|
document.getElementById('busVoltage').innerText = data.busVoltage;
|
||||||
|
document.getElementById('shuntVoltage').innerText = data.shuntVoltage;
|
||||||
|
document.getElementById('current').innerText = data.current;
|
||||||
|
document.getElementById('power').innerText = data.power;
|
||||||
|
|
||||||
|
// 获取灯光状态
|
||||||
|
const statusResponse = await fetch('/lightStatus');
|
||||||
|
const statusText = await statusResponse.text();
|
||||||
|
document.getElementById('lightStatus').innerText = statusText === 'on' ? '开启' : '关闭';
|
||||||
|
|
||||||
|
// 获取自动调节状态
|
||||||
|
const autoAdjustStatusResponse = await fetch('/autoAdjustStatus');
|
||||||
|
const autoAdjustStatusText = await autoAdjustStatusResponse.text();
|
||||||
|
document.getElementById('autoAdjustStatus').innerText = autoAdjustStatusText === 'enabled' ? '开启' : '关闭';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setWiper() {
|
||||||
|
const wiperValue = document.getElementById('wiperValue').value;
|
||||||
|
const response = await fetch('/setWiper', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
body: 'value=' + encodeURIComponent(wiperValue)
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
alert('Wiper value set successfully!');
|
||||||
|
} else {
|
||||||
|
alert('Failed to set Wiper value!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resetDuration() {
|
||||||
|
const response = await fetch('/resetDuration', { method: 'POST' });
|
||||||
|
if (response.ok) {
|
||||||
|
alert('累计使用时长已清空');
|
||||||
|
} else {
|
||||||
|
alert('清空失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function turnOnLight() {
|
||||||
|
const response = await fetch('/LightOpen', { method: 'POST' });
|
||||||
|
if (response.ok) {
|
||||||
|
updateLightStatus("开启");
|
||||||
|
} else {
|
||||||
|
alert('打开失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function turnOffLight() {
|
||||||
|
const response = await fetch('/LightClose', { method: 'POST' });
|
||||||
|
if (response.ok) {
|
||||||
|
updateLightStatus("关闭");
|
||||||
|
} else {
|
||||||
|
alert('关闭失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLightStatus(status) {
|
||||||
|
document.getElementById('lightStatus').innerText = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enableAutoAdjust() {
|
||||||
|
const targetLux = document.getElementById('targetLux').value;
|
||||||
|
if (!targetLux || isNaN(targetLux) || parseInt(targetLux) <= 0) {
|
||||||
|
alert('请输入有效的正整数作为目标照度');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch('/startAutoAdjust', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
body: 'target=' + encodeURIComponent(targetLux)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
alert('已开启自动调节');
|
||||||
|
} else {
|
||||||
|
alert('开启失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disableAutoAdjust() {
|
||||||
|
const response = await fetch('/stopAutoAdjust', { method: 'POST' });
|
||||||
|
if (response.ok) {
|
||||||
|
alert('已关闭自动调节');
|
||||||
|
} else {
|
||||||
|
alert('关闭失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(fetchData, 1000);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="fetchData()">
|
||||||
|
<h1>实时数据显示</h1>
|
||||||
|
|
||||||
|
<p>累计使用时长: <span id="activeDuration">加载中...</span></p>
|
||||||
|
<button onclick="resetDuration()">清空累计时长</button>
|
||||||
|
|
||||||
|
<p>温度: <span id="temperature">加载中...</span> °C</p>
|
||||||
|
<p>湿度: <span id="humidity">加载中...</span> %RH</p>
|
||||||
|
<p>光照强度(A): <span id="lightA">加载中...</span> lx</p>
|
||||||
|
<p>光照强度(B): <span id="lightB">加载中...</span> lx</p>
|
||||||
|
<p>电位器Wiper值: <span id="wiper">加载中...</span></p>
|
||||||
|
<p>总线电压: <span id="busVoltage">加载中...</span> V</p>
|
||||||
|
<p>分流电压: <span id="shuntVoltage">加载中...</span> mV</p>
|
||||||
|
<p>电流: <span id="current">加载中...</span> A</p>
|
||||||
|
<p>功率: <span id="power">加载中...</span> W</p>
|
||||||
|
|
||||||
|
<h2>设置Wiper值</h2>
|
||||||
|
<input type="range" id="wiperValue" min="0" max="127" step="1" value="2" />
|
||||||
|
<button onclick="setWiper()">设置</button>
|
||||||
|
|
||||||
|
<h2>灯光控制</h2>
|
||||||
|
<p>灯光状态: <span id="lightStatus">加载中...</span></p>
|
||||||
|
<button onclick="turnOnLight()">开灯</button>
|
||||||
|
<button onclick="turnOffLight()">关灯</button>
|
||||||
|
|
||||||
|
<h2>自动调节</h2>
|
||||||
|
<p>状态: <span id="autoAdjustStatus">加载中...</span></p>
|
||||||
|
<p>目标照度: <input type="number" id="targetLux" min="0" max="100000" step="1" value="2000" /> lux</p>
|
||||||
|
<button onclick="enableAutoAdjust()">开启</button>
|
||||||
|
<button onclick="disableAutoAdjust()">关闭</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
264
data/index.html
Normal file
264
data/index.html
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>ESP32 实时监控面板</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
color: #333;
|
||||||
|
padding: 30px;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
color: #1890ff;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-box {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 140px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-value {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1890ff;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-section {
|
||||||
|
margin-top: 30px;
|
||||||
|
background-color: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #555;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group input[type="range"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group input[type="number"] {
|
||||||
|
width: 100px;
|
||||||
|
padding: 6px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiper-value {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #1890ff;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin: 5px 5px 0 0;
|
||||||
|
background-color: #1890ff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #40a9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-inline {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
async function fetchData() {
|
||||||
|
const res = await fetch('/data');
|
||||||
|
if (!res.ok) return alert('获取数据失败');
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
document.getElementById('duration').innerText = data.duration;
|
||||||
|
document.getElementById('temperature').innerText = data.temperature + ' °C';
|
||||||
|
document.getElementById('humidity').innerText = data.humidity + ' %RH';
|
||||||
|
document.getElementById('lightA').innerText = data.lightA + ' lx';
|
||||||
|
document.getElementById('lightB').innerText = data.lightB + ' lx';
|
||||||
|
document.getElementById('busVoltage').innerText = data.busVoltage + ' V';
|
||||||
|
document.getElementById('current').innerText = data.current + ' A';
|
||||||
|
document.getElementById('power').innerText = data.power + ' W';
|
||||||
|
document.getElementById('wiperNow').innerText = data.wiper;
|
||||||
|
|
||||||
|
const lightStatus = await (await fetch('/lightStatus')).text();
|
||||||
|
document.getElementById('lightStatus').innerText = lightStatus === 'on' ? '开启' : '关闭';
|
||||||
|
|
||||||
|
const autoStatus = await (await fetch('/autoAdjustStatus')).text();
|
||||||
|
document.getElementById('autoAdjustStatus').innerText = autoStatus === 'enabled' ? '开启' : '关闭';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWiperDisplay() {
|
||||||
|
const val = document.getElementById('wiperValue').value;
|
||||||
|
document.getElementById('wiperDisplay').innerText = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setWiper() {
|
||||||
|
const val = document.getElementById('wiperValue').value;
|
||||||
|
const res = await fetch('/setWiper', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
body: 'value=' + encodeURIComponent(val)
|
||||||
|
});
|
||||||
|
alert(res.ok ? 'Wiper 设置成功!' : '设置失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resetDuration() {
|
||||||
|
const res = await fetch('/resetDuration', { method: 'POST' });
|
||||||
|
alert(res.ok ? '已清空累计时长' : '操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function turnOnLight() {
|
||||||
|
const res = await fetch('/LightOpen', { method: 'POST' });
|
||||||
|
if (res.ok) document.getElementById('lightStatus').innerText = '开启';
|
||||||
|
else alert('打开失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function turnOffLight() {
|
||||||
|
const res = await fetch('/LightClose', { method: 'POST' });
|
||||||
|
if (res.ok) document.getElementById('lightStatus').innerText = '关闭';
|
||||||
|
else alert('关闭失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enableAutoAdjust() {
|
||||||
|
const val = document.getElementById('targetLux').value;
|
||||||
|
if (!val || val <= 0 || val > 65535) {
|
||||||
|
alert('请输入合理的照度(1~65535)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await fetch('/startAutoAdjust', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
body: 'target=' + encodeURIComponent(val)
|
||||||
|
});
|
||||||
|
alert(res.ok ? '已开启自动调节' : '开启失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disableAutoAdjust() {
|
||||||
|
const res = await fetch('/stopAutoAdjust', { method: 'POST' });
|
||||||
|
alert(res.ok ? '已关闭自动调节' : '关闭失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(fetchData, 1000);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="fetchData()">
|
||||||
|
|
||||||
|
<h1>📟 ESP32 实时监控面板</h1>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">累计使用时长</div>
|
||||||
|
<div class="data-value" id="duration">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="data-box">
|
||||||
|
<button onclick="resetDuration()">清空累计时长</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 温湿度 -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">温度</div>
|
||||||
|
<div class="data-value" id="temperature">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">湿度</div>
|
||||||
|
<div class="data-value" id="humidity">--</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 光照 -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">光照 A</div>
|
||||||
|
<div class="data-value" id="lightA">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">光照 B</div>
|
||||||
|
<div class="data-value" id="lightB">--</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 电源信息(已去除分流电压) -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">总线电压</div>
|
||||||
|
<div class="data-value" id="busVoltage">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">电流</div>
|
||||||
|
<div class="data-value" id="current">--</div>
|
||||||
|
</div>
|
||||||
|
<div class="data-box">
|
||||||
|
<div class="data-label">功率</div>
|
||||||
|
<div class="data-value" id="power">--</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 控制面板 -->
|
||||||
|
<div class="control-section">
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Wiper 当前值:<span class="status-inline" id="wiperNow">--</span></label>
|
||||||
|
<input type="range" id="wiperValue" min="0" max="100" value="0" oninput="updateWiperDisplay()" />
|
||||||
|
<span class="wiper-value" id="wiperDisplay">0</span>
|
||||||
|
<button onclick="setWiper()">设置</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>灯光状态:<span class="status-inline" id="lightStatus">--</span></label>
|
||||||
|
<button onclick="turnOnLight()">开灯</button>
|
||||||
|
<button onclick="turnOffLight()">关灯</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>自动调节状态:<span class="status-inline" id="autoAdjustStatus">--</span></label>
|
||||||
|
<input type="number" id="targetLux" min="1" max="65535" value="2000" />
|
||||||
|
<button onclick="enableAutoAdjust()">开启</button>
|
||||||
|
<button onclick="disableAutoAdjust()">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -14,7 +14,6 @@ board = esp32-s3-devkitc-1
|
|||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
robtillaart/INA226@^0.6.0
|
robtillaart/INA226@^0.6.0
|
||||||
esphome/ESPAsyncWebServer-esphome@^3.3.0
|
|
||||||
bblanchon/ArduinoJson@^7.4.1
|
bblanchon/ArduinoJson@^7.4.1
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
|
||||||
|
|||||||
240
src/DHT11.cpp
240
src/DHT11.cpp
@ -1,240 +0,0 @@
|
|||||||
/**
|
|
||||||
* DHT11.cpp
|
|
||||||
* Library for reading temperature and humidity from the DHT11 sensor.
|
|
||||||
*
|
|
||||||
* Author: Dhruba Saha
|
|
||||||
* Version: 2.1.0
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "DHT11.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the DHT11 class.
|
|
||||||
* Initializes the pin to be used for communication and sets it to output mode.
|
|
||||||
*
|
|
||||||
* @param pin: Digital pin number on the Arduino board to which the DHT11 sensor is connected.
|
|
||||||
*/
|
|
||||||
DHT11::DHT11(int pin) : _pin(pin)
|
|
||||||
{
|
|
||||||
pinMode(_pin, OUTPUT);
|
|
||||||
digitalWrite(_pin, HIGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the delay between consecutive sensor readings.
|
|
||||||
* If this method is not called, a default delay of 500 milliseconds is used.
|
|
||||||
*
|
|
||||||
* @param delay: Delay duration in milliseconds between sensor readings.
|
|
||||||
*/
|
|
||||||
void DHT11::setDelay(unsigned long delay)
|
|
||||||
{
|
|
||||||
_delayMS = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads raw data from the DHT11 sensor.
|
|
||||||
* This method handles the direct communication with the DHT11 sensor and retrieves the raw data.
|
|
||||||
* It's used internally by the readTemperature, readHumidity, and readTemperatureHumidity methods.
|
|
||||||
*
|
|
||||||
* @param data: An array of bytes where the raw sensor data will be stored.
|
|
||||||
* The array must be at least 5 bytes long, as the DHT11 sensor returns 5 bytes of data.
|
|
||||||
* @return: Returns 0 if the data is read successfully and the checksum matches.
|
|
||||||
* Returns DHT11::ERROR_TIMEOUT if the sensor does not respond or communication times out.
|
|
||||||
* Returns DHT11::ERROR_CHECKSUM if the data is read but the checksum does not match.
|
|
||||||
*/
|
|
||||||
int DHT11::readRawData(byte data[5])
|
|
||||||
{
|
|
||||||
delay(_delayMS);
|
|
||||||
startSignal();
|
|
||||||
unsigned long timeout_start = millis();
|
|
||||||
|
|
||||||
while (digitalRead(_pin) == HIGH)
|
|
||||||
{
|
|
||||||
if (millis() - timeout_start > TIMEOUT_DURATION)
|
|
||||||
{
|
|
||||||
return DHT11::ERROR_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (digitalRead(_pin) == LOW)
|
|
||||||
{
|
|
||||||
delayMicroseconds(80);
|
|
||||||
if (digitalRead(_pin) == HIGH)
|
|
||||||
{
|
|
||||||
delayMicroseconds(80);
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
data[i] = readByte();
|
|
||||||
if (data[i] == DHT11::ERROR_TIMEOUT)
|
|
||||||
{
|
|
||||||
return DHT11::ERROR_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))
|
|
||||||
{
|
|
||||||
return 0; // Success
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return DHT11::ERROR_CHECKSUM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DHT11::ERROR_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a byte of data from the DHT11 sensor during the communication process.
|
|
||||||
*
|
|
||||||
* @return: A byte of data read from the sensor.
|
|
||||||
*/
|
|
||||||
byte DHT11::readByte()
|
|
||||||
{
|
|
||||||
byte value = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
while (digitalRead(_pin) == LOW)
|
|
||||||
;
|
|
||||||
delayMicroseconds(30);
|
|
||||||
if (digitalRead(_pin) == HIGH)
|
|
||||||
{
|
|
||||||
value |= (1 << (7 - i));
|
|
||||||
}
|
|
||||||
while (digitalRead(_pin) == HIGH)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a start signal to the DHT11 sensor to initiate a data read.
|
|
||||||
* This involves setting the data pin low for a specific duration, then high,
|
|
||||||
* and finally setting it to input mode to read the data.
|
|
||||||
*/
|
|
||||||
void DHT11::startSignal()
|
|
||||||
{
|
|
||||||
pinMode(_pin, OUTPUT);
|
|
||||||
digitalWrite(_pin, LOW);
|
|
||||||
delay(18);
|
|
||||||
digitalWrite(_pin, HIGH);
|
|
||||||
delayMicroseconds(40);
|
|
||||||
pinMode(_pin, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the temperature from the DHT11 sensor.
|
|
||||||
* Utilizes the readRawData method to retrieve raw data from the sensor and then extracts
|
|
||||||
* the temperature from the data array.
|
|
||||||
*
|
|
||||||
* @return: Temperature value in Celsius. Returns DHT11::ERROR_TIMEOUT if reading times out,
|
|
||||||
* or DHT11::ERROR_CHECKSUM if checksum validation fails.
|
|
||||||
*/
|
|
||||||
int DHT11::readTemperature()
|
|
||||||
{
|
|
||||||
byte data[5];
|
|
||||||
int error = readRawData(data);
|
|
||||||
if (error != 0)
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
//return data[2];
|
|
||||||
int temp = data[2];
|
|
||||||
if (temp != DHT11::ERROR_CHECKSUM && temp != DHT11::ERROR_TIMEOUT)
|
|
||||||
{
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the humidity from the DHT11 sensor.
|
|
||||||
* Utilizes the readRawData method to retrieve raw data from the sensor and then extracts
|
|
||||||
* the humidity from the data array.
|
|
||||||
*
|
|
||||||
* @return: Humidity value in percentage. Returns DHT11::ERROR_TIMEOUT if reading times out,
|
|
||||||
* or DHT11::ERROR_CHECKSUM if checksum validation fails.
|
|
||||||
*/
|
|
||||||
int DHT11::readHumidity()
|
|
||||||
{
|
|
||||||
byte data[5];
|
|
||||||
int error = readRawData(data);
|
|
||||||
if (error != 0)
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
//return data[0];
|
|
||||||
int humi = data[0];
|
|
||||||
if (humi != DHT11::ERROR_CHECKSUM && humi != DHT11::ERROR_TIMEOUT)
|
|
||||||
{
|
|
||||||
return humi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the temperature and humidity from the DHT11 sensor.
|
|
||||||
* Utilizes the readRawData method to retrieve raw data from the sensor and then extracts
|
|
||||||
* both temperature and humidity from the data array.
|
|
||||||
*
|
|
||||||
* @param temperature: Reference to a variable where the temperature value will be stored.
|
|
||||||
* @param humidity: Reference to a variable where the humidity value will be stored.
|
|
||||||
* @return: An integer representing the status of the read operation.
|
|
||||||
* Returns 0 if the reading is successful, DHT11::ERROR_TIMEOUT if a timeout occurs,
|
|
||||||
* or DHT11::ERROR_CHECKSUM if a checksum error occurs.
|
|
||||||
*/
|
|
||||||
int DHT11::readTemperatureHumidity(int &temperature, int &humidity)
|
|
||||||
{
|
|
||||||
byte data[5];
|
|
||||||
int error = readRawData(data);
|
|
||||||
if (error != 0)
|
|
||||||
{
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
humidity = data[0];
|
|
||||||
temperature = data[2];
|
|
||||||
return 0; // Indicate success
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a human-readable error message based on the provided error code.
|
|
||||||
* This method facilitates easier debugging and user feedback by translating
|
|
||||||
* numeric error codes into descriptive strings.
|
|
||||||
*
|
|
||||||
* @param errorCode The error code for which the description is required.
|
|
||||||
* @return A descriptive string explaining the error.
|
|
||||||
*/
|
|
||||||
String DHT11::getErrorString(int errorCode)
|
|
||||||
{
|
|
||||||
switch (errorCode)
|
|
||||||
{
|
|
||||||
case DHT11::ERROR_TIMEOUT:
|
|
||||||
return "Error 253 Reading from DHT11 timed out.";
|
|
||||||
case DHT11::ERROR_CHECKSUM:
|
|
||||||
return "Error 254 Checksum mismatch while reading from DHT11.";
|
|
||||||
default:
|
|
||||||
return "Error Unknown.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int DHT11::getTempHumi(int &temperature, int &humidity)
|
|
||||||
{
|
|
||||||
// Attempt to read the temperature and humidity values from the DHT11 sensor.
|
|
||||||
int result = readTemperatureHumidity(temperature, humidity);
|
|
||||||
|
|
||||||
// Check the results of the readings.
|
|
||||||
// If the reading is successful, print the temperature and humidity values.
|
|
||||||
// If there are errors, print the appropriate error messages.
|
|
||||||
if (result == 0) {
|
|
||||||
Serial.print("Temperature: ");
|
|
||||||
Serial.print(temperature);
|
|
||||||
Serial.print(" °C\tHumidity: ");
|
|
||||||
Serial.print(humidity);
|
|
||||||
Serial.println(" %");
|
|
||||||
} else {
|
|
||||||
// Print error message based on the error code.
|
|
||||||
Serial.println(DHT11::getErrorString(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
110
src/DHT11.h
110
src/DHT11.h
@ -1,110 +0,0 @@
|
|||||||
/**
|
|
||||||
* DHT11.h
|
|
||||||
* Header file for the DHT11 library, providing functionalities to interface with
|
|
||||||
* the DHT11 temperature & humidity sensor.
|
|
||||||
*
|
|
||||||
* Author: Dhruba Saha
|
|
||||||
* Version: 2.1.0
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DHT11_h
|
|
||||||
#define DHT11_h
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DHT11 Class
|
|
||||||
* Provides methods to read temperature and humidity data from the DHT11 sensor.
|
|
||||||
*/
|
|
||||||
class DHT11
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* Initializes the data pin to be used for communication with the DHT11 sensor.
|
|
||||||
*
|
|
||||||
* @param pin: Digital pin number on the Arduino board to which the DHT11 sensor is connected.
|
|
||||||
*/
|
|
||||||
DHT11(int pin);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the delay between consecutive sensor readings.
|
|
||||||
* If this method is not called, a default delay of 500 milliseconds is used.
|
|
||||||
*
|
|
||||||
* @param delay: Delay duration in milliseconds between sensor readings.
|
|
||||||
*/
|
|
||||||
void setDelay(unsigned long delay);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the humidity from the DHT11 sensor.
|
|
||||||
*
|
|
||||||
* @return: Humidity value in percentage. Returns DHT11_ERROR_TIMEOUT if reading times out.
|
|
||||||
* Returns DHT11_ERROR_CHECKSUM if checksum validation fails.
|
|
||||||
*/
|
|
||||||
int readHumidity();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the temperature from the DHT11 sensor.
|
|
||||||
*
|
|
||||||
* @return: Temperature value in Celsius. Returns DHT11_ERROR_TIMEOUT if reading times out.
|
|
||||||
* Returns DHT11_ERROR_CHECKSUM if checksum validation fails.
|
|
||||||
*/
|
|
||||||
int readTemperature();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and returns the temperature and humidity from the DHT11 sensor.
|
|
||||||
*
|
|
||||||
* @param temperature: Reference to a variable where the temperature value will be stored.
|
|
||||||
* @param humidity: Reference to a variable where the humidity value will be stored.
|
|
||||||
* @return: true if the reading is successful, false if it fails due to timeout or checksum error.
|
|
||||||
*/
|
|
||||||
int readTemperatureHumidity(int &temperature, int &humidity);
|
|
||||||
|
|
||||||
int getTempHumi(int &temperature, int &humidity);
|
|
||||||
|
|
||||||
// Constants to represent error codes.
|
|
||||||
static const int ERROR_CHECKSUM = 254; // Error code indicating checksum mismatch.
|
|
||||||
static const int ERROR_TIMEOUT = 253; // Error code indicating a timeout occurred during reading.
|
|
||||||
static const int TIMEOUT_DURATION = 1000; // Duration (in milliseconds) to wait before timing out.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a human-readable error message based on the provided error code.
|
|
||||||
*
|
|
||||||
* @param errorCode: The error code for which the message is required.
|
|
||||||
* @return: A string describing the error.
|
|
||||||
*/
|
|
||||||
static String getErrorString(int errorCode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _pin; // Pin number used for communication with the DHT11 sensor.
|
|
||||||
unsigned long _delayMS = 500; // Default delay in milliseconds between sensor readings.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private method to read raw data from the DHT11 sensor.
|
|
||||||
* This method encapsulates the communication with the sensor and data reading process,
|
|
||||||
* and is utilized by public methods to get temperature and humidity data.
|
|
||||||
*
|
|
||||||
* @param data: Array to store the raw data read from the sensor.
|
|
||||||
* @return: An integer representing the status of the read operation.
|
|
||||||
* Returns 0 if the reading is successful, DHT11::ERROR_TIMEOUT if a timeout occurs,
|
|
||||||
* or DHT11::ERROR_CHECKSUM if a checksum error occurs.
|
|
||||||
*/
|
|
||||||
int readRawData(byte data[5]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a byte of data from the DHT11 sensor.
|
|
||||||
*
|
|
||||||
* @return: A byte of data read from the sensor.
|
|
||||||
*/
|
|
||||||
byte readByte();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a start signal to the DHT11 sensor to initiate a data read.
|
|
||||||
* This involves setting the data pin low for a specific duration, then high,
|
|
||||||
* and finally setting it to input mode to read the data.
|
|
||||||
*/
|
|
||||||
void startSignal();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
208
src/WebHandlers.cpp
Normal file
208
src/WebHandlers.cpp
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
#include "WebHandlers.h"
|
||||||
|
|
||||||
|
#define LIGHT_CONTROL_PIN 1
|
||||||
|
|
||||||
|
// 全局WebServer指针,用于在处理函数中访问
|
||||||
|
WebServer* webServerPtr = nullptr;
|
||||||
|
|
||||||
|
// 读取SPIFFS文件的辅助函数
|
||||||
|
String readFile(const String& path) {
|
||||||
|
if (!SPIFFS.exists(path)) {
|
||||||
|
return "File not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = SPIFFS.open(path, "r");
|
||||||
|
if (!file) {
|
||||||
|
return "Failed to open file";
|
||||||
|
}
|
||||||
|
|
||||||
|
String content = file.readString();
|
||||||
|
file.close();
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根路径页面处理
|
||||||
|
void handleRoot() {
|
||||||
|
String html = readFile("/index.html");
|
||||||
|
webServerPtr->send(200, "text/html", html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置页面处理
|
||||||
|
void handleConfig() {
|
||||||
|
String html = readFile("/config.html");
|
||||||
|
webServerPtr->send(200, "text/html", html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存WiFi凭证处理
|
||||||
|
void handleSaveWiFi() {
|
||||||
|
if (webServerPtr->hasArg("ssid") && webServerPtr->hasArg("password")) {
|
||||||
|
// 获取 SSID 和密码
|
||||||
|
String ssid = webServerPtr->arg("ssid");
|
||||||
|
String password = webServerPtr->arg("password");
|
||||||
|
|
||||||
|
// 存储到全局变量
|
||||||
|
ssid.toCharArray(user_ssid, sizeof(user_ssid));
|
||||||
|
password.toCharArray(user_pass, sizeof(user_pass));
|
||||||
|
|
||||||
|
// 设置待连接的WiFi信息
|
||||||
|
SSID = ssid;
|
||||||
|
Password = password;
|
||||||
|
shouldConnectWiFi = true;
|
||||||
|
|
||||||
|
Serial.println("Received WiFi credentials:");
|
||||||
|
Serial.print("SSID: ");
|
||||||
|
Serial.println(user_ssid);
|
||||||
|
Serial.print("Password: ");
|
||||||
|
Serial.println(user_pass);
|
||||||
|
|
||||||
|
// 使用ArduinoJson库生成成功响应
|
||||||
|
JsonDocument doc;
|
||||||
|
doc["status"] = "success";
|
||||||
|
doc["message"] = "WiFi设置已保存,正在连接...";
|
||||||
|
|
||||||
|
String jsonResponse;
|
||||||
|
serializeJson(doc, jsonResponse);
|
||||||
|
webServerPtr->send(200, "application/json", jsonResponse);
|
||||||
|
} else {
|
||||||
|
// 使用ArduinoJson库生成错误响应
|
||||||
|
JsonDocument errorDoc;
|
||||||
|
errorDoc["status"] = "error";
|
||||||
|
errorDoc["message"] = "缺少SSID或密码参数";
|
||||||
|
|
||||||
|
String errorResponse;
|
||||||
|
serializeJson(errorDoc, errorResponse);
|
||||||
|
webServerPtr->send(400, "application/json", errorResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 传感器数据API处理
|
||||||
|
void handleData() {
|
||||||
|
JsonDocument doc;
|
||||||
|
doc["temperature"] = sensorData.temperature;
|
||||||
|
doc["humidity"] = sensorData.humidity;
|
||||||
|
doc["lightA"] = sensorData.lightA;
|
||||||
|
doc["lightB"] = sensorData.lightB;
|
||||||
|
doc["wiper"] = ds3502.getWiper();
|
||||||
|
doc["busVoltage"] = sensorData.busVoltage;
|
||||||
|
doc["shuntVoltage"] = sensorData.shuntVoltage_mV;
|
||||||
|
doc["current"] = sensorData.current;
|
||||||
|
doc["power"] = sensorData.power;
|
||||||
|
doc["duration"] = runtime.formatDuration(runtime.getActiveDuration());
|
||||||
|
|
||||||
|
String json;
|
||||||
|
serializeJson(doc, json);
|
||||||
|
webServerPtr->send(200, "application/json", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置Wiper值处理
|
||||||
|
void handleSetWiper() {
|
||||||
|
if (webServerPtr->hasArg("value")) {
|
||||||
|
int wiperValue = webServerPtr->arg("value").toInt();
|
||||||
|
ds3502.setWiper(wiperValue);
|
||||||
|
webServerPtr->send(200, "text/plain", "Wiper value set");
|
||||||
|
} else {
|
||||||
|
webServerPtr->send(400, "text/plain", "Missing value parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置运行时长处理
|
||||||
|
void handleResetDuration() {
|
||||||
|
runtime.resetActiveDuration();
|
||||||
|
webServerPtr->send(200, "text/plain", "Duration reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开灯处理
|
||||||
|
void handleLightOpen() {
|
||||||
|
LightOpen();
|
||||||
|
webServerPtr->send(200, "text/plain", "Light ON");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关灯处理
|
||||||
|
void handleLightClose() {
|
||||||
|
LightClose();
|
||||||
|
webServerPtr->send(200, "text/plain", "Light OFF");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取灯光状态处理
|
||||||
|
void handleLightStatus() {
|
||||||
|
bool isOn = (digitalRead(LIGHT_CONTROL_PIN) == HIGH); // 高电平为开灯
|
||||||
|
webServerPtr->send(200, "text/plain", isOn ? "on" : "off");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动自动调节处理
|
||||||
|
void handleStartAutoAdjust() {
|
||||||
|
if (webServerPtr->hasArg("target")) {
|
||||||
|
int targetLux = webServerPtr->arg("target").toInt();
|
||||||
|
if (targetLux > 0) {
|
||||||
|
lightCtrl.setTargetLight(targetLux);
|
||||||
|
lightCtrl.adjustToTarget();
|
||||||
|
isAutoAdjustEnabled = true;
|
||||||
|
webServerPtr->send(200, "text/plain", "Auto adjust started");
|
||||||
|
} else {
|
||||||
|
webServerPtr->send(400, "text/plain", "Invalid target lux");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webServerPtr->send(400, "text/plain", "Missing target parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止自动调节处理
|
||||||
|
void handleStopAutoAdjust() {
|
||||||
|
isAutoAdjustEnabled = false;
|
||||||
|
webServerPtr->send(200, "text/plain", "Auto adjust stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取自动调节状态处理
|
||||||
|
void handleAutoAdjustStatus() {
|
||||||
|
webServerPtr->send(200, "text/plain", isAutoAdjustEnabled ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 404处理
|
||||||
|
void handleNotFound() {
|
||||||
|
webServerPtr->send(404, "text/plain", "404 Not Found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Web服务器初始化函数
|
||||||
|
void WebServer_Init(WebServer& server) {
|
||||||
|
// 设置全局指针
|
||||||
|
webServerPtr = &server;
|
||||||
|
|
||||||
|
// 初始化SPIFFS
|
||||||
|
if (!SPIFFS.begin(true)) {
|
||||||
|
Serial.println("An Error has occurred while mounting SPIFFS");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用CORS
|
||||||
|
server.enableCORS(true);
|
||||||
|
|
||||||
|
// 根路径页面
|
||||||
|
server.on("/", HTTP_GET, handleRoot);
|
||||||
|
|
||||||
|
// AP配网相关
|
||||||
|
server.on("/config", HTTP_GET, handleConfig);
|
||||||
|
server.on("/saveWiFi", HTTP_POST, handleSaveWiFi);
|
||||||
|
|
||||||
|
// 数据API
|
||||||
|
server.on("/data", HTTP_GET, handleData);
|
||||||
|
|
||||||
|
// 设备控制API
|
||||||
|
server.on("/setWiper", HTTP_POST, handleSetWiper);
|
||||||
|
server.on("/resetDuration", HTTP_POST, handleResetDuration);
|
||||||
|
|
||||||
|
// 灯光控制API
|
||||||
|
server.on("/LightOpen", HTTP_POST, handleLightOpen);
|
||||||
|
server.on("/LightClose", HTTP_POST, handleLightClose);
|
||||||
|
server.on("/lightStatus", HTTP_GET, handleLightStatus);
|
||||||
|
|
||||||
|
// 自动调节API
|
||||||
|
server.on("/startAutoAdjust", HTTP_POST, handleStartAutoAdjust);
|
||||||
|
server.on("/stopAutoAdjust", HTTP_POST, handleStopAutoAdjust);
|
||||||
|
server.on("/autoAdjustStatus", HTTP_GET, handleAutoAdjustStatus);
|
||||||
|
|
||||||
|
// 404处理
|
||||||
|
server.onNotFound(handleNotFound);
|
||||||
|
|
||||||
|
// 启动服务器
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
55
src/WebHandlers.h
Normal file
55
src/WebHandlers.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef WEBHANDLERS_H
|
||||||
|
#define WEBHANDLERS_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WebServer.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <FS.h>
|
||||||
|
#include "SPIFFS.h"
|
||||||
|
#include "TJC_Show.h"
|
||||||
|
#include "LightControl.h"
|
||||||
|
#include "RunTime.h"
|
||||||
|
#include "DS3502.h"
|
||||||
|
#include "WiFiControl.h"
|
||||||
|
|
||||||
|
// 声明外部变量
|
||||||
|
extern SensorData sensorData;
|
||||||
|
extern DS3502 ds3502;
|
||||||
|
extern RunTime runtime;
|
||||||
|
extern LightControl lightCtrl;
|
||||||
|
extern bool isAutoAdjustEnabled;
|
||||||
|
extern char user_ssid[64];
|
||||||
|
extern char user_pass[64];
|
||||||
|
|
||||||
|
// WiFi连接相关变量
|
||||||
|
extern bool shouldConnectWiFi;
|
||||||
|
extern String SSID;
|
||||||
|
extern String Password;
|
||||||
|
|
||||||
|
// 声明外部函数
|
||||||
|
extern void LightOpen();
|
||||||
|
extern void LightClose();
|
||||||
|
extern void connectToWiFi(String ssid, String password);
|
||||||
|
|
||||||
|
// Web处理函数声明
|
||||||
|
void handleRoot();
|
||||||
|
void handleConfig();
|
||||||
|
void handleSaveWiFi();
|
||||||
|
void handleData();
|
||||||
|
void handleSetWiper();
|
||||||
|
void handleResetDuration();
|
||||||
|
void handleLightOpen();
|
||||||
|
void handleLightClose();
|
||||||
|
void handleLightStatus();
|
||||||
|
void handleStartAutoAdjust();
|
||||||
|
void handleStopAutoAdjust();
|
||||||
|
void handleAutoAdjustStatus();
|
||||||
|
void handleNotFound();
|
||||||
|
|
||||||
|
// 辅助函数
|
||||||
|
String readFile(const String& path);
|
||||||
|
|
||||||
|
// Web服务器初始化函数
|
||||||
|
void WebServer_Init(WebServer& server);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,94 +0,0 @@
|
|||||||
// #include "WebServer.h"
|
|
||||||
|
|
||||||
|
|
||||||
// extern RunTime runtime;
|
|
||||||
// extern MCP45HVX1 digiPot;
|
|
||||||
// extern INA226 INA;
|
|
||||||
// extern DS18B20 ds18b20;
|
|
||||||
// extern BH1750 bh1750_a;
|
|
||||||
// extern BH1750 bh1750_b;
|
|
||||||
|
|
||||||
// AsyncWebServer server(80);
|
|
||||||
|
|
||||||
// void WebServer_Init(const char* ssid, const char* password) {
|
|
||||||
// WiFi.begin(ssid, password); // WiFi
|
|
||||||
// while (WiFi.status() != WL_CONNECTED) {
|
|
||||||
// delay(1000);
|
|
||||||
// Serial.println("Connecting to WiFi...");
|
|
||||||
// }
|
|
||||||
// Serial.print("Address: ");
|
|
||||||
// Serial.println(WiFi.localIP());
|
|
||||||
|
|
||||||
// // 根路径的页面
|
|
||||||
// server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// request->send_P(200, "text/html", index_html);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 温度接口
|
|
||||||
// server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String temp = String(ds18b20.getTempC());
|
|
||||||
// request->send(200, "text/plain", temp);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 光照强度(传感器A)
|
|
||||||
// server.on("/lightA", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String lightA = String(bh1750_a.readLightLevel());
|
|
||||||
// request->send(200, "text/plain", lightA);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 光照(传感器B)
|
|
||||||
// server.on("/lightB", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String lightB = String(bh1750_b.readLightLevel());
|
|
||||||
// request->send(200, "text/plain", lightB);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 配置Wiper接口
|
|
||||||
// server.on("/wiper", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String wiper = String(digiPot.readWiper());
|
|
||||||
// request->send(200, "text/plain", wiper);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// server.on("/busVoltage", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String busVoltage = String(INA.getBusVoltage(), 3);
|
|
||||||
// request->send(200, "text/plain", busVoltage);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// server.on("/shuntVoltage", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String shuntVoltage = String(INA.getShuntVoltage_mV(), 3);
|
|
||||||
// request->send(200, "text/plain", shuntVoltage);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// server.on("/current", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String current = String(INA.getCurrent_mA(), 3);
|
|
||||||
// request->send(200, "text/plain", current);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// server.on("/power", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// String power = String(INA.getPower_mW(), 3);
|
|
||||||
// request->send(200, "text/plain", power);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 获取累计时长接口
|
|
||||||
// server.on("/duration", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
||||||
// request->send(200, "text/plain", runtime.formatDuration(runtime.getActiveDuration()));
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 清空累计时长接口
|
|
||||||
// server.on("/resetDuration", HTTP_POST, [](AsyncWebServerRequest *request) {
|
|
||||||
// runtime.resetActiveDuration();
|
|
||||||
// request->send(200, "text/plain", "Duration reset");
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 接收设置Wiper的请求
|
|
||||||
// server.on("/setWiper", HTTP_POST, [](AsyncWebServerRequest *request) {
|
|
||||||
// if (request->hasParam("value", true)) {
|
|
||||||
// int wiperValue = request->getParam("value", true)->value().toInt();
|
|
||||||
// digiPot.writeWiper(wiperValue);
|
|
||||||
// request->send(200, "text/plain", "Wiper value set");
|
|
||||||
// } else {
|
|
||||||
// request->send(400, "text/plain", "Missing value parameter");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// server.begin();
|
|
||||||
// }
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#ifndef WEBSERVER_H
|
|
||||||
#define WEBSERVER_H
|
|
||||||
|
|
||||||
#include "webpages.h" // 包含 HTML 页面内容
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
#include "BH1750.h"
|
|
||||||
#include "Wire.h"
|
|
||||||
//#include "MCP45HVX1.h"
|
|
||||||
#include "INA226.h"
|
|
||||||
#include "RunTime.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void WebServer_Init(void);
|
|
||||||
|
|
||||||
#endif // WEBSERVER_H
|
|
||||||
@ -1,6 +1,8 @@
|
|||||||
#include "WiFiControl.h"
|
#include "WiFiControl.h"
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <FS.h>
|
||||||
|
#include "SPIFFS.h"
|
||||||
|
#include "mywebserver.h"
|
||||||
|
|
||||||
// AP 模式下的 SSID 和密码
|
// AP 模式下的 SSID 和密码
|
||||||
const char* AP_SSID = "LampController_AP";
|
const char* AP_SSID = "LampController_AP";
|
||||||
@ -10,42 +12,7 @@ const char* AP_PASSWORD = "12345678";
|
|||||||
char user_ssid[64] = "";
|
char user_ssid[64] = "";
|
||||||
char user_pass[64] = "";
|
char user_pass[64] = "";
|
||||||
|
|
||||||
|
extern mywebserver* webServer;
|
||||||
//extern AsyncWebServer server(80); // 创建 Web 服务器实例
|
|
||||||
|
|
||||||
// 简单的 HTML 表单页面
|
|
||||||
const char html_form[] PROGMEM = R"rawliteral(
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>WiFi Configuration</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial; margin: 30px; background-color: #f2f2f2; }
|
|
||||||
h2 { color: #333; }
|
|
||||||
input[type=text], input[type=password] {
|
|
||||||
width: 100%; padding: 12px 20px; margin: 8px 0; display: inline-block; border: 1px solid #ccc; box-sizing: border-box;
|
|
||||||
}
|
|
||||||
button { background-color: #4CAF50; color: white; padding: 14px 20px; margin: 8px 0; border: none; cursor: pointer; width: 100%; }
|
|
||||||
button:hover { opacity: 0.8; }
|
|
||||||
.container { background-color: #fff; padding: 20px; border-radius: 8px; max-width: 400px; margin: auto; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h2>Connect to WiFi</h2>
|
|
||||||
<form action="/connect" method="POST">
|
|
||||||
<label for="ssid"><b>SSID</b></label>
|
|
||||||
<input type="text" placeholder="Enter WiFi Name" name="ssid" required>
|
|
||||||
|
|
||||||
<label for="password"><b>Password</b></label>
|
|
||||||
<input type="password" placeholder="Enter Password" name="password" required>
|
|
||||||
|
|
||||||
<button type="submit">Save and Connect</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)rawliteral";
|
|
||||||
|
|
||||||
void WiFi_Init()
|
void WiFi_Init()
|
||||||
{
|
{
|
||||||
@ -56,14 +23,12 @@ void WiFi_Init()
|
|||||||
Serial.println("AP Mode started");
|
Serial.println("AP Mode started");
|
||||||
Serial.print("AP IP address: ");
|
Serial.print("AP IP address: ");
|
||||||
Serial.println(WiFi.softAPIP());
|
Serial.println(WiFi.softAPIP());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void connectToWiFi(String ssid, String password)
|
||||||
void connectToWiFi()
|
|
||||||
{
|
{
|
||||||
WiFi.mode(WIFI_STA); // 切换为 Station 模式
|
WiFi.mode(WIFI_STA); // 切换为 Station 模式
|
||||||
WiFi.begin(user_ssid, user_pass);
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
Serial.println("Connecting to WiFi...");
|
Serial.println("Connecting to WiFi...");
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
void WiFi_Init();
|
void WiFi_Init();
|
||||||
void connectToWiFi();
|
void connectToWiFi(String ssid, String password);
|
||||||
void setupWebServer();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
180
src/main.cpp
180
src/main.cpp
@ -2,26 +2,32 @@
|
|||||||
#include "BH1750.h"
|
#include "BH1750.h"
|
||||||
#include "Wire.h"
|
#include "Wire.h"
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <WebServer.h>
|
||||||
#include "INA226.h"
|
#include "INA226.h"
|
||||||
#include <Ticker.h>
|
#include <Ticker.h>
|
||||||
#include <Preferences.h> // 用于存储非易失性数据
|
#include <Preferences.h> // 用于存储非易失性数据
|
||||||
#include "TJC_Show.h"
|
#include "TJC_Show.h"
|
||||||
#include "RunTime.h"
|
#include "RunTime.h"
|
||||||
#include "WebServer.h"
|
|
||||||
#include "WiFiControl.h"
|
#include "WiFiControl.h"
|
||||||
#include "DS3502.h"
|
#include "DS3502.h"
|
||||||
#include "LightControl.h"
|
#include "LightControl.h"
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
//#include "mywebserver.h"
|
||||||
|
#include "WebHandlers.h"
|
||||||
|
|
||||||
|
|
||||||
// #include <esp_task_wdt.h>
|
// #include <esp_task_wdt.h>
|
||||||
// 全局变量用于存储 WiFi 凭据
|
// 全局变量用于存储 WiFi 凭据
|
||||||
extern char user_ssid[64]; // 存储 SSID
|
extern char user_ssid[64]; // 存储 SSID
|
||||||
extern char user_pass[64]; // 存储密码
|
extern char user_pass[64]; // 存储密码
|
||||||
|
|
||||||
|
String SSID;
|
||||||
|
String Password;
|
||||||
|
bool shouldConnectWiFi = false;
|
||||||
|
|
||||||
// Ticker 用于定时检查电流状态
|
// Ticker 用于定时检查电流状态
|
||||||
Ticker currentCheckTicker;
|
Ticker currentCheckTicker;
|
||||||
|
|
||||||
@ -31,7 +37,7 @@ DS3502 ds3502(0x28);
|
|||||||
// INA226 电流监控器
|
// INA226 电流监控器
|
||||||
INA226 INA(0x40);
|
INA226 INA(0x40);
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
WebServer server(80);
|
||||||
|
|
||||||
|
|
||||||
// DHT11 温湿度传感器
|
// DHT11 温湿度传感器
|
||||||
@ -162,162 +168,6 @@ void LightClose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WebServer_Init(void) {
|
|
||||||
// 根路径页面
|
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
request->send_P(200, "text/html", index_html);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// /*************************** AP配网 ***************** */
|
|
||||||
server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
request->send_P(200, "text/html", config_html);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
server.on("/saveWiFi", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
if (request->hasParam("ssid", true) && request->hasParam("password", true)) {
|
|
||||||
// 获取 SSID 和密码
|
|
||||||
String ssid = request->getParam("ssid", true)->value();
|
|
||||||
String password = request->getParam("password", true)->value();
|
|
||||||
|
|
||||||
// 存储到全局变量
|
|
||||||
ssid.toCharArray(user_ssid, sizeof(user_ssid));
|
|
||||||
password.toCharArray(user_pass, sizeof(user_pass));
|
|
||||||
|
|
||||||
Serial.println("Received WiFi credentials:");
|
|
||||||
Serial.print("SSID: ");
|
|
||||||
Serial.println(user_ssid);
|
|
||||||
Serial.print("Password: ");
|
|
||||||
Serial.println(user_pass);
|
|
||||||
|
|
||||||
connectToWiFi(); // 连接目标 WiFi
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回确认页面
|
|
||||||
String response = "<!DOCTYPE html><html><body><h2>Configuration Received</h2><p>Please wait while the device connects to WiFi...</p></body></html>";
|
|
||||||
request->send(200, "text/html", response);
|
|
||||||
});
|
|
||||||
// int32_t IRIS_Protocol_Pack(uint8_t Command,uint16_t LenthofIn, uint8_t *BufferIn, uint8_t *PackData);
|
|
||||||
// 合并数据接口
|
|
||||||
server.on("/data", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
//StaticJsonDocument<256> doc;
|
|
||||||
JsonDocument doc;
|
|
||||||
doc["temperature"] = sensorData.temperature;
|
|
||||||
doc["humidity"] = sensorData.humidity;
|
|
||||||
doc["lightA"] = sensorData.lightA;
|
|
||||||
doc["lightB"] = sensorData.lightB;
|
|
||||||
doc["wiper"] = ds3502.getWiper();
|
|
||||||
doc["busVoltage"] = sensorData.busVoltage;
|
|
||||||
doc["shuntVoltage"] = sensorData.shuntVoltage_mV;
|
|
||||||
doc["current"] = sensorData.current;
|
|
||||||
doc["power"] = sensorData.power;
|
|
||||||
doc["duration"] = runtime.formatDuration(runtime.getActiveDuration());
|
|
||||||
|
|
||||||
String json;
|
|
||||||
serializeJson(doc, json);
|
|
||||||
request->send(200, "application/json", json);
|
|
||||||
// uint8_t *bufferfosend;
|
|
||||||
// int lentofpack=IRIS_Protocol_Pack(0x00, json.length(), (uint8_t*)json.c_str(),bufferfosend);
|
|
||||||
// Serial1.write(bufferfosend,lentofpack);
|
|
||||||
// delete[] bufferfosend;
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// 设置Wiper值
|
|
||||||
server.on("/setWiper", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
if (request->hasParam("value", true)) {
|
|
||||||
int wiperValue = request->getParam("value", true)->value().toInt();
|
|
||||||
ds3502.setWiper(wiperValue);
|
|
||||||
request->send(200, "text/plain", "Wiper value set");
|
|
||||||
} else {
|
|
||||||
request->send(400, "text/plain", "Missing value parameter");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 清空累计时长
|
|
||||||
server.on("/resetDuration", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
runtime.resetActiveDuration();
|
|
||||||
request->send(200, "text/plain", "Duration reset");
|
|
||||||
});
|
|
||||||
|
|
||||||
// 灯光控制接口
|
|
||||||
server.on("/LightOpen", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
LightOpen();
|
|
||||||
request->send(200, "text/plain", "Light ON");
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/LightClose", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
LightClose();
|
|
||||||
request->send(200, "text/plain", "Light OFF");
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取灯光状态接口
|
|
||||||
server.on("/lightStatus", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
bool isOn = (digitalRead(LIGHT_CONTROL_PIN) == HIGH); // 高电平为开灯
|
|
||||||
request->send(200, "text/plain", isOn ? "on" : "off");
|
|
||||||
});
|
|
||||||
|
|
||||||
// 启动自动调节
|
|
||||||
server.on("/startAutoAdjust", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
if (request->hasParam("target", true)) {
|
|
||||||
int targetLux = request->getParam("target", true)->value().toInt();
|
|
||||||
if (targetLux > 0) {
|
|
||||||
lightCtrl.setTargetLight(targetLux);
|
|
||||||
//lightCtrl.runUntilTargetReached(targetLux, 150);
|
|
||||||
lightCtrl.adjustToTarget();
|
|
||||||
isAutoAdjustEnabled = true;
|
|
||||||
request->send(200, "text/plain", "Auto adjust started");
|
|
||||||
} else {
|
|
||||||
request->send(400, "text/plain", "Invalid target lux");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
request->send(400, "text/plain", "Missing target parameter");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 停止自动调节
|
|
||||||
server.on("/stopAutoAdjust", HTTP_POST, [](AsyncWebServerRequest *request){
|
|
||||||
isAutoAdjustEnabled = false;
|
|
||||||
request->send(200, "text/plain", "Auto adjust stopped");
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取自动调节状态
|
|
||||||
server.on("/autoAdjustStatus", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
request->send(200, "text/plain", isAutoAdjustEnabled ? "enabled" : "disabled");
|
|
||||||
});
|
|
||||||
|
|
||||||
// 启动服务器
|
|
||||||
server.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//usb串口打印信息
|
|
||||||
// void SerialPrintInfo(void) {
|
|
||||||
// // 获取温湿度数据
|
|
||||||
// dht11.readTemperatureHumidity(temperature, humidity);
|
|
||||||
|
|
||||||
// // 获取光照数据
|
|
||||||
// float lightA = bh1750_a.readLightLevel();
|
|
||||||
// float lightB = bh1750_b.readLightLevel();
|
|
||||||
|
|
||||||
// // 获取电流监控数据
|
|
||||||
// float busVoltage = INA.getBusVoltage();
|
|
||||||
// float shuntVoltage_mV = INA.getShuntVoltage_mV();
|
|
||||||
// float current = INA.getCurrent();
|
|
||||||
// float power = INA.getPower();
|
|
||||||
|
|
||||||
// // 打印信息(只使用变量)
|
|
||||||
// Serial.printf("Temperature: %dC, Humidity: %d%%\n", temperature, humidity);
|
|
||||||
// Serial.printf("A: %.0f lux :: B: %.0f lux \n", lightA, lightB);
|
|
||||||
|
|
||||||
// Serial.println("\nBUS\tSHUNT\tCURRENT\tPOWER");
|
|
||||||
// Serial.printf("%.2f\t%.2f\t%.2f\t%.2f\n", busVoltage, shuntVoltage_mV, current, power);
|
|
||||||
// }
|
|
||||||
|
|
||||||
void SerialPrintInfo(void) {
|
void SerialPrintInfo(void) {
|
||||||
UpdateSensorData(sensorData);
|
UpdateSensorData(sensorData);
|
||||||
|
|
||||||
@ -373,7 +223,7 @@ void setup(void)
|
|||||||
WiFi_Init();
|
WiFi_Init();
|
||||||
|
|
||||||
//WebServer 初始化
|
//WebServer 初始化
|
||||||
WebServer_Init();
|
WebServer_Init(server);
|
||||||
|
|
||||||
// 初始化 runtime NVS
|
// 初始化 runtime NVS
|
||||||
runtime.begin();
|
runtime.begin();
|
||||||
@ -415,7 +265,6 @@ void loop(void)
|
|||||||
lastSensorRead = millis();
|
lastSensorRead = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//串口解析tjc控制指令
|
//串口解析tjc控制指令
|
||||||
tjcShow.processSerial();
|
tjcShow.processSerial();
|
||||||
|
|
||||||
@ -427,6 +276,13 @@ void loop(void)
|
|||||||
if (isAutoAdjustEnabled) {
|
if (isAutoAdjustEnabled) {
|
||||||
lightCtrl.adjustToTarget(); // 使用新的持续调节函数
|
lightCtrl.adjustToTarget(); // 使用新的持续调节函数
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.handleClient(); // 替换webServer->loop()
|
||||||
|
|
||||||
|
if (shouldConnectWiFi) {
|
||||||
|
connectToWiFi(SSID, Password);
|
||||||
|
shouldConnectWiFi = false; // 重置标志位
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
151
src/mywebserver.cpp
Normal file
151
src/mywebserver.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include "mywebserver.h"
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
#include "SPIFFS.h"
|
||||||
|
|
||||||
|
String getContentType(String filename)
|
||||||
|
{
|
||||||
|
if (filename.endsWith(".htm"))
|
||||||
|
return "text/html";
|
||||||
|
else if (filename.endsWith(".html"))
|
||||||
|
return "text/html";
|
||||||
|
else if (filename.endsWith(".css"))
|
||||||
|
return "text/css";
|
||||||
|
else if (filename.endsWith(".js"))
|
||||||
|
return "application/javascript";
|
||||||
|
else if (filename.endsWith(".png"))
|
||||||
|
return "image/png";
|
||||||
|
else if (filename.endsWith(".gif"))
|
||||||
|
return "image/gif";
|
||||||
|
else if (filename.endsWith(".jpg"))
|
||||||
|
return "image/jpeg";
|
||||||
|
else if (filename.endsWith(".ico"))
|
||||||
|
return "image/x-icon";
|
||||||
|
else if (filename.endsWith(".xml"))
|
||||||
|
return "text/xml";
|
||||||
|
else if (filename.endsWith(".pdf"))
|
||||||
|
return "application/x-pdf";
|
||||||
|
else if (filename.endsWith(".zip"))
|
||||||
|
return "application/x-zip";
|
||||||
|
else if (filename.endsWith(".gz"))
|
||||||
|
return "application/x-gzip";
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool handleFileRead(String path)
|
||||||
|
{ // 处理浏览器HTTP访问
|
||||||
|
|
||||||
|
if (path.endsWith("/"))
|
||||||
|
{ // 如果访问地址以"/"为结尾
|
||||||
|
path = "/index.html"; // 则将访问地址修改为/index.html便于SPIFFS访问
|
||||||
|
}
|
||||||
|
|
||||||
|
String contentType = getContentType(path); // 获取文件类型
|
||||||
|
|
||||||
|
if (SPIFFS.exists(path))
|
||||||
|
{ // 如果访问的文件可以在SPIFFS中找到
|
||||||
|
File file = SPIFFS.open(path, "r"); // 则尝试打开该文件
|
||||||
|
MYSERVER->streamFile(file, contentType); // 并且将该文件返回给浏览器
|
||||||
|
file.close(); // 并且关闭文件
|
||||||
|
return true; // 返回true
|
||||||
|
}
|
||||||
|
return false; // 如果文件未找到,则返回false
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleUserRequet()
|
||||||
|
{
|
||||||
|
|
||||||
|
// 获取用户请求网址信息
|
||||||
|
String webAddress = MYSERVER->uri();
|
||||||
|
|
||||||
|
// 通过handleFileRead函数处处理用户访问
|
||||||
|
bool fileReadOK = handleFileRead(webAddress);
|
||||||
|
|
||||||
|
// 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
|
||||||
|
if (!fileReadOK)
|
||||||
|
{
|
||||||
|
MYSERVER->send(404, "text/plain", "404 Not Found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件类型
|
||||||
|
|
||||||
|
void founddate(){
|
||||||
|
Serial.println("sdfasdfasdf");
|
||||||
|
Serial.println(MYSERVER->arg("rolloffset"));
|
||||||
|
Serial.println(MYSERVER->arg("pitchoffset"));
|
||||||
|
if (MYSERVER->hasArg("Angle0"))
|
||||||
|
{
|
||||||
|
Serial.println(MYSERVER->arg("Angle0"));
|
||||||
|
/* code */
|
||||||
|
}
|
||||||
|
if (MYSERVER->hasArg("Angle90"))
|
||||||
|
{
|
||||||
|
Serial.println(MYSERVER->arg("Angle90"));
|
||||||
|
/* code */
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(MYSERVER->arg("pitchoffset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
mywebserver::mywebserver()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(SPIFFS.begin()){ // 启动闪存文件系统
|
||||||
|
Serial.println("SPIFFS Started.");
|
||||||
|
} else {
|
||||||
|
Serial.println("SPIFFS Failed to Start.");
|
||||||
|
}
|
||||||
|
server = new WebServer(80);
|
||||||
|
server->enableCORS(true);
|
||||||
|
MYSERVER=server;
|
||||||
|
server->onNotFound(handleUserRequet);
|
||||||
|
server->on("/setting",HTTP_GET,founddate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mywebserver::mywebserver(int port)
|
||||||
|
{
|
||||||
|
Serial.begin(9600);
|
||||||
|
if(SPIFFS.begin()){ // 启动闪存文件系统
|
||||||
|
Serial.println("SPIFFS Started.");
|
||||||
|
} else {
|
||||||
|
Serial.println("SPIFFS Failed to Start.");
|
||||||
|
}
|
||||||
|
server = new WebServer(port);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
server->enableCORS(true);
|
||||||
|
MYSERVER=server;
|
||||||
|
server->sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
server->sendHeader("Access-Control-Allow-Methods","server->sendHeader");
|
||||||
|
|
||||||
|
|
||||||
|
server->onNotFound(handleUserRequet);
|
||||||
|
server->on("/setting",HTTP_GET,founddate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void mywebserver::loop()
|
||||||
|
{
|
||||||
|
server->handleClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mywebserver::begin()
|
||||||
|
{
|
||||||
|
server->begin();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void mywebserver::on(String str,void *funct())
|
||||||
|
{
|
||||||
|
server->on(str,funct);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
25
src/mywebserver.h
Normal file
25
src/mywebserver.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef MYWEBSERVER_H
|
||||||
|
#define MYWEBSERVER_H
|
||||||
|
#include<Arduino.h>
|
||||||
|
#include <WebServer.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static WebServer *MYSERVER;
|
||||||
|
|
||||||
|
class mywebserver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
mywebserver();
|
||||||
|
WebServer *server;
|
||||||
|
mywebserver(int port);
|
||||||
|
void loop();
|
||||||
|
void begin();
|
||||||
|
void on(String str,void *funct());
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
354
src/webpages.h
354
src/webpages.h
@ -1,354 +0,0 @@
|
|||||||
// #ifndef WEBPAGES_H
|
|
||||||
// #define WEBPAGES_H
|
|
||||||
|
|
||||||
// #include <Arduino.h>
|
|
||||||
|
|
||||||
// const char index_html[] PROGMEM = R"rawliteral(
|
|
||||||
// <!DOCTYPE html>
|
|
||||||
// <html>
|
|
||||||
// <head>
|
|
||||||
// <title>ESP32 Data Display</title>
|
|
||||||
// <meta charset="UTF-8">
|
|
||||||
// <script>
|
|
||||||
// async function fetchData() {
|
|
||||||
// const response = await fetch('/data');
|
|
||||||
// if (!response.ok) {
|
|
||||||
// alert('数据获取失败');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const data = await response.json();
|
|
||||||
|
|
||||||
// document.getElementById('activeDuration').innerText = data.duration;
|
|
||||||
// document.getElementById('temperature').innerText = data.temperature;
|
|
||||||
// document.getElementById('humidity').innerText = data.humidity;
|
|
||||||
// document.getElementById('lightA').innerText = data.lightA;
|
|
||||||
// document.getElementById('lightB').innerText = data.lightB;
|
|
||||||
// document.getElementById('wiper').innerText = data.wiper;
|
|
||||||
// document.getElementById('busVoltage').innerText = data.busVoltage;
|
|
||||||
// document.getElementById('shuntVoltage').innerText = data.shuntVoltage;
|
|
||||||
// document.getElementById('current').innerText = data.current;
|
|
||||||
// document.getElementById('power').innerText = data.power;
|
|
||||||
|
|
||||||
// // 获取灯光状态
|
|
||||||
// const statusResponse = await fetch('/lightStatus');
|
|
||||||
// const statusText = await statusResponse.text();
|
|
||||||
// document.getElementById('lightStatus').innerText = statusText === 'on' ? '开启' : '关闭';
|
|
||||||
|
|
||||||
// // 获取自动调节状态
|
|
||||||
// const autoAdjustStatusResponse = await fetch('/autoAdjustStatus');
|
|
||||||
// const autoAdjustStatusText = await autoAdjustStatusResponse.text();
|
|
||||||
// document.getElementById('autoAdjustStatus').innerText = autoAdjustStatusText === 'enabled' ? '开启' : '关闭';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function setWiper() {
|
|
||||||
// const wiperValue = document.getElementById('wiperValue').value;
|
|
||||||
// const response = await fetch('/setWiper', {
|
|
||||||
// method: 'POST',
|
|
||||||
// headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
// body: 'value=' + encodeURIComponent(wiperValue)
|
|
||||||
// });
|
|
||||||
// if (response.ok) {
|
|
||||||
// alert('Wiper value set successfully!');
|
|
||||||
// } else {
|
|
||||||
// alert('Failed to set Wiper value!');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function resetDuration() {
|
|
||||||
// const response = await fetch('/resetDuration', { method: 'POST' });
|
|
||||||
// if (response.ok) {
|
|
||||||
// alert('累计使用时长已清空');
|
|
||||||
// } else {
|
|
||||||
// alert('清空失败');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function turnOnLight() {
|
|
||||||
// const response = await fetch('/LightOpen', { method: 'POST' });
|
|
||||||
// if (response.ok) {
|
|
||||||
// updateLightStatus("开启");
|
|
||||||
// } else {
|
|
||||||
// alert('打开失败');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function turnOffLight() {
|
|
||||||
// const response = await fetch('/LightClose', { method: 'POST' });
|
|
||||||
// if (response.ok) {
|
|
||||||
// updateLightStatus("关闭");
|
|
||||||
// } else {
|
|
||||||
// alert('关闭失败');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function updateLightStatus(status) {
|
|
||||||
// document.getElementById('lightStatus').innerText = status;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function enableAutoAdjust() {
|
|
||||||
// const targetLux = document.getElementById('targetLux').value;
|
|
||||||
// if (!targetLux || isNaN(targetLux) || parseInt(targetLux) <= 0) {
|
|
||||||
// alert('请输入有效的正整数作为目标照度');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 发送请求给 ESP32 开启自动调节并设置目标照度
|
|
||||||
// const response = await fetch('/startAutoAdjust', {
|
|
||||||
// method: 'POST',
|
|
||||||
// headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
// body: 'target=' + encodeURIComponent(targetLux)
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (response.ok) {
|
|
||||||
// alert('已开启自动调节');
|
|
||||||
// } else {
|
|
||||||
// alert('开启失败');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function disableAutoAdjust() {
|
|
||||||
// const response = await fetch('/stopAutoAdjust', { method: 'POST' });
|
|
||||||
// if (response.ok) {
|
|
||||||
// alert('已关闭自动调节');
|
|
||||||
// } else {
|
|
||||||
// alert('关闭失败');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// setInterval(fetchData, 1000); // 每秒刷新一次数据
|
|
||||||
// </script>
|
|
||||||
// </head>
|
|
||||||
// <body onload="fetchData()">
|
|
||||||
// <h1>实时数据显示</h1>
|
|
||||||
|
|
||||||
// <p>累计使用时长: <span id="activeDuration">加载中...</span></p>
|
|
||||||
// <button onclick="resetDuration()">清空累计时长</button>
|
|
||||||
|
|
||||||
// <p>温度: <span id="temperature">加载中...</span> °C</p>
|
|
||||||
// <p>湿度: <span id="humidity">加载中...</span> %RH</p>
|
|
||||||
// <p>光照强度(A): <span id="lightA">加载中...</span> lx</p>
|
|
||||||
// <p>光照强度(B): <span id="lightB">加载中...</span> lx</p>
|
|
||||||
// <p>电位器Wiper值: <span id="wiper">加载中...</span></p>
|
|
||||||
// <p>总线电压: <span id="busVoltage">加载中...</span> V</p>
|
|
||||||
// <p>分流电压: <span id="shuntVoltage">加载中...</span> mV</p>
|
|
||||||
// <p>电流: <span id="current">加载中...</span> A</p>
|
|
||||||
// <p>功率: <span id="power">加载中...</span> W</p>
|
|
||||||
|
|
||||||
// <h2>设置Wiper值</h2>
|
|
||||||
// <input type="range" id="wiperValue" min="0" max="127" step="1" value="2" />
|
|
||||||
// <button onclick="setWiper()">设置</button>
|
|
||||||
|
|
||||||
// <h2>灯光控制</h2>
|
|
||||||
// <p>灯光状态: <span id="lightStatus">加载中...</span></p>
|
|
||||||
// <button onclick="turnOnLight()">开灯</button>
|
|
||||||
// <button onclick="turnOffLight()">关灯</button>
|
|
||||||
|
|
||||||
// <h2>自动调节</h2>
|
|
||||||
// <p>状态: <span id="autoAdjustStatus">加载中...</span></p>
|
|
||||||
// <p>目标照度: <input type="number" id="targetLux" min="0" max="100000" step="1" value="2000" /> lux</p>
|
|
||||||
// <button onclick="enableAutoAdjust()">开启</button>
|
|
||||||
// <button onclick="disableAutoAdjust()">关闭</button>
|
|
||||||
// </body>
|
|
||||||
// </html>
|
|
||||||
// )rawliteral";
|
|
||||||
|
|
||||||
// #endif // WEBPAGES_H
|
|
||||||
|
|
||||||
#ifndef WEBPAGES_H
|
|
||||||
#define WEBPAGES_H
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
const char index_html[] PROGMEM = R"rawliteral(
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>ESP32 Data Display</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<script>
|
|
||||||
async function fetchData() {
|
|
||||||
const response = await fetch('/data');
|
|
||||||
if (!response.ok) {
|
|
||||||
alert('数据获取失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
document.getElementById('activeDuration').innerText = data.duration;
|
|
||||||
document.getElementById('temperature').innerText = data.temperature;
|
|
||||||
document.getElementById('humidity').innerText = data.humidity;
|
|
||||||
document.getElementById('lightA').innerText = data.lightA;
|
|
||||||
document.getElementById('lightB').innerText = data.lightB;
|
|
||||||
document.getElementById('wiper').innerText = data.wiper;
|
|
||||||
document.getElementById('busVoltage').innerText = data.busVoltage;
|
|
||||||
document.getElementById('shuntVoltage').innerText = data.shuntVoltage;
|
|
||||||
document.getElementById('current').innerText = data.current;
|
|
||||||
document.getElementById('power').innerText = data.power;
|
|
||||||
|
|
||||||
// 获取灯光状态
|
|
||||||
const statusResponse = await fetch('/lightStatus');
|
|
||||||
const statusText = await statusResponse.text();
|
|
||||||
document.getElementById('lightStatus').innerText = statusText === 'on' ? '开启' : '关闭';
|
|
||||||
|
|
||||||
// 获取自动调节状态
|
|
||||||
const autoAdjustStatusResponse = await fetch('/autoAdjustStatus');
|
|
||||||
const autoAdjustStatusText = await autoAdjustStatusResponse.text();
|
|
||||||
document.getElementById('autoAdjustStatus').innerText = autoAdjustStatusText === 'enabled' ? '开启' : '关闭';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setWiper() {
|
|
||||||
const wiperValue = document.getElementById('wiperValue').value;
|
|
||||||
const response = await fetch('/setWiper', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
body: 'value=' + encodeURIComponent(wiperValue)
|
|
||||||
});
|
|
||||||
if (response.ok) {
|
|
||||||
alert('Wiper value set successfully!');
|
|
||||||
} else {
|
|
||||||
alert('Failed to set Wiper value!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resetDuration() {
|
|
||||||
const response = await fetch('/resetDuration', { method: 'POST' });
|
|
||||||
if (response.ok) {
|
|
||||||
alert('累计使用时长已清空');
|
|
||||||
} else {
|
|
||||||
alert('清空失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function turnOnLight() {
|
|
||||||
const response = await fetch('/LightOpen', { method: 'POST' });
|
|
||||||
if (response.ok) {
|
|
||||||
updateLightStatus("开启");
|
|
||||||
} else {
|
|
||||||
alert('打开失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function turnOffLight() {
|
|
||||||
const response = await fetch('/LightClose', { method: 'POST' });
|
|
||||||
if (response.ok) {
|
|
||||||
updateLightStatus("关闭");
|
|
||||||
} else {
|
|
||||||
alert('关闭失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLightStatus(status) {
|
|
||||||
document.getElementById('lightStatus').innerText = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function enableAutoAdjust() {
|
|
||||||
const targetLux = document.getElementById('targetLux').value;
|
|
||||||
if (!targetLux || isNaN(targetLux) || parseInt(targetLux) <= 0) {
|
|
||||||
alert('请输入有效的正整数作为目标照度');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送请求给 ESP32 开启自动调节并设置目标照度
|
|
||||||
const response = await fetch('/startAutoAdjust', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
body: 'target=' + encodeURIComponent(targetLux)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
alert('已开启自动调节');
|
|
||||||
} else {
|
|
||||||
alert('开启失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function disableAutoAdjust() {
|
|
||||||
const response = await fetch('/stopAutoAdjust', { method: 'POST' });
|
|
||||||
if (response.ok) {
|
|
||||||
alert('已关闭自动调节');
|
|
||||||
} else {
|
|
||||||
alert('关闭失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInterval(fetchData, 1000); // 每秒刷新一次数据
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body onload="fetchData()">
|
|
||||||
<h1>实时数据显示</h1>
|
|
||||||
|
|
||||||
<p>累计使用时长: <span id="activeDuration">加载中...</span></p>
|
|
||||||
<button onclick="resetDuration()">清空累计时长</button>
|
|
||||||
|
|
||||||
<p>温度: <span id="temperature">加载中...</span> °C</p>
|
|
||||||
<p>湿度: <span id="humidity">加载中...</span> %RH</p>
|
|
||||||
<p>光照强度(A): <span id="lightA">加载中...</span> lx</p>
|
|
||||||
<p>光照强度(B): <span id="lightB">加载中...</span> lx</p>
|
|
||||||
<p>电位器Wiper值: <span id="wiper">加载中...</span></p>
|
|
||||||
<p>总线电压: <span id="busVoltage">加载中...</span> V</p>
|
|
||||||
<p>分流电压: <span id="shuntVoltage">加载中...</span> mV</p>
|
|
||||||
<p>电流: <span id="current">加载中...</span> A</p>
|
|
||||||
<p>功率: <span id="power">加载中...</span> W</p>
|
|
||||||
|
|
||||||
<h2>设置Wiper值</h2>
|
|
||||||
<input type="range" id="wiperValue" min="0" max="127" step="1" value="2" />
|
|
||||||
<button onclick="setWiper()">设置</button>
|
|
||||||
|
|
||||||
<h2>灯光控制</h2>
|
|
||||||
<p>灯光状态: <span id="lightStatus">加载中...</span></p>
|
|
||||||
<button onclick="turnOnLight()">开灯</button>
|
|
||||||
<button onclick="turnOffLight()">关灯</button>
|
|
||||||
|
|
||||||
<h2>自动调节</h2>
|
|
||||||
<p>状态: <span id="autoAdjustStatus">加载中...</span></p>
|
|
||||||
<p>目标照度: <input type="number" id="targetLux" min="0" max="100000" step="1" value="2000" /> lux</p>
|
|
||||||
<button onclick="enableAutoAdjust()">开启</button>
|
|
||||||
<button onclick="disableAutoAdjust()">关闭</button>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)rawliteral";
|
|
||||||
|
|
||||||
// 新增 config_html 页面
|
|
||||||
const char config_html[] PROGMEM = R"rawliteral(
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>ESP32 WiFi Setup</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<script>
|
|
||||||
async function saveWiFiSettings() {
|
|
||||||
const ssid = document.getElementById("ssid").value;
|
|
||||||
const password = document.getElementById("password").value;
|
|
||||||
|
|
||||||
const response = await fetch("/saveWiFi", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
||||||
body: "ssid=" + encodeURIComponent(ssid) + "&password=" + encodeURIComponent(password)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
alert("WiFi 设置保存成功!");
|
|
||||||
} else {
|
|
||||||
alert("保存失败,请重试。");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>WiFi 设置</h1>
|
|
||||||
<form onsubmit="event.preventDefault(); saveWiFiSettings();">
|
|
||||||
<label for="ssid">SSID:</label><br/>
|
|
||||||
<input type="text" id="ssid" name="ssid"><br/><br/>
|
|
||||||
|
|
||||||
<label for="password">密码:</label><br/>
|
|
||||||
<input type="password" id="password" name="password"><br/><br/>
|
|
||||||
|
|
||||||
<input type="submit" value="保存">
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)rawliteral";
|
|
||||||
|
|
||||||
#endif // WEBPAGES_H
|
|
||||||
Reference in New Issue
Block a user