文件
phonerail/firmware/main/prov.html
T
zhou yang和Claude Opus 5.5 ece65f7c19 固件 0.1.19~0.1.21-c5:配网热点(SoftAP + 网页)、风扇 40 ℃ 以下断电
- 0.1.19 配网热点:没配 WiFi / 连续 60 s 连不上时自己开 SoftAP,192.168.4.1 网页里加删 WiFi、改 MQTT;
  配置拼成 wifi / mqtt 命令走唯一的命令处理器(新链路号 3 CMD_LINK_AP),MQTT 仍不收配置命令
- 0.1.20 热点口令固定 88888888
- 0.1.21 风扇:板温 >=40 ℃ 上电、<38 ℃ 断电,40~65 ℃ 线性调速;fan 命令加可选 sec(下限到点自动交回)
- mqtt 命令加 keep_pass;net 回应加 ap;status 的 fan 加 left
- 新增 test_prov(13 例),test_t_thermal +3;29 ctest 全绿

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 14:35:44 +08:00

93 行
6.1 KiB
HTML
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
<!doctype html>
<html lang="zh">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>PhoneRail 配网</title>
<style>
body{font:16px/1.5 system-ui,sans-serif;margin:0;padding:16px;max-width:520px;background:#f4f5f7;color:#1c1e21}
h1{font-size:20px;margin:0 0 4px}h2{font-size:16px;margin:0 0 8px}
section{background:#fff;border-radius:8px;padding:12px 14px;margin:12px 0}
input[type=text],input[type=password]{width:100%;box-sizing:border-box;font-size:16px;padding:9px;margin:4px 0;border:1px solid #c5c8ce;border-radius:6px}
button{font-size:16px;padding:9px 14px;margin:6px 6px 0 0;border:0;border-radius:6px;background:#1668dc;color:#fff}
button.s{background:#e6e8eb;color:#1c1e21;padding:4px 10px;font-size:14px;margin:0}
.row{display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid #eceef0}
.row:last-child{border:0}.dim{color:#6b7078;font-size:14px}.ok{color:#18794e}.bad{color:#c0362c}
.msg{min-height:1.5em;margin-top:6px}
</style>
<h1>PhoneRail 配网</h1>
<div class="dim" id="hd">读取中…</div>
<section><h2>状态</h2><div id="st">读取中…</div></section>
<section><h2>WiFi</h2>
<div id="saved"></div>
<button class="s" id="scan" type="button" style="margin-top:8px">扫描附近的 WiFi</button>
<div id="aps"></div>
<form id="fw">
<input type="text" id="ssid" placeholder="WiFi 名称" autocapitalize="off" autocomplete="off" required>
<input type="password" id="pass" placeholder="口令(开放网络留空)" autocomplete="off">
<label class="dim"><input type="checkbox" id="show"> 显示口令</label><br>
<button>保存并连接</button>
</form>
<div class="msg" id="mw"></div>
</section>
<section><h2>服务器(MQTT)</h2>
<form id="fm">
<input type="text" id="uri" placeholder="mqtts://主机:8883" autocapitalize="off" autocomplete="off" required>
<input type="text" id="user" placeholder="账号" autocapitalize="off" autocomplete="off">
<input type="password" id="mp" placeholder="口令(留空 = 不改)" autocomplete="off">
<button>保存</button>
</form>
<div class="msg" id="mm"></div>
</section>
<p class="dim">底板连上 WiFi 后约 1 分钟会自动关掉这个热点。口令只能写入,页面上不会显示已存的口令。</p>
<script>
var $=function(i){return document.getElementById(i)},tele='',filled=false;
var ERR={range:'长度不对:WiFi 口令要 8~63 位(开放网络留空),服务器地址以 mqtt:// 或 mqtts:// 开头',
state:'已经存满 4 组,先删掉一组',bad_char:'不支持引号、反斜杠和换行',too_long:'太长了',
bad_form:'没填完整',io:'写入闪存失败',arg:'参数不对',busy:'底板正忙,过几秒再试',timeout:'底板没有回应,再试一次'};
var WHY={201:'找不到这个 WiFi(名字不对 / 太远 / 只有 5G)',202:'口令不对',15:'口令不对(握手超时)',204:'口令不对(握手失败)',2:'认证过期',200:'信号太弱,掉线'};
var ST={off:'未配置',connecting:'连接中',up:'已连上'};
function el(t,c,x){var e=document.createElement(t);if(c)e.className=c;if(x!=null)e.textContent=x;return e}
function row(k,v,c){var r=el('div','row');r.appendChild(el('span','dim',k));r.appendChild(el('span',c||'',v));return r}
function post(body){return fetch('/c',{method:'POST',body:body}).then(function(r){return r.json()})}
function say(id,j,okText){var m=$(id);m.className='msg '+(j.ok?'ok':'bad');m.textContent=j.ok?okText:('没保存:'+(ERR[j.err]||j.err))}
function fail(id){return function(){var m=$(id);m.className='msg bad';m.textContent='没连上底板,确认手机还连着 PhoneRail 热点'}}
function draw(d){
var n=d.net;$('hd').textContent='板子 '+n.id+' · 固件 '+d.fw;
var s=$('st');s.textContent='';
var w=ST[n.wifi]||n.wifi;
if(n.wifi=='up')w+='「'+n.ssid+'」 '+n.ip+'('+n.rssi+' dBm)';
else if(n.wifi=='connecting')w+='「'+n.ssid+'」';
s.appendChild(row('WiFi',w,n.wifi=='up'?'ok':''));
if(n.wifi!='up'&&n.wifi_reason)s.appendChild(row('上次失败',WHY[n.wifi_reason]||('原因码 '+n.wifi_reason),'bad'));
s.appendChild(row('服务器',n.uri?(ST[n.mqtt]||n.mqtt):'未配置',n.mqtt=='up'?'ok':''));
var v=$('saved');v.textContent='';
if(!n.ssids.length)v.appendChild(el('div','dim','还没有保存任何 WiFi'));
n.ssids.forEach(function(x){var r=el('div','row');r.appendChild(el('span','',x));
var b=el('button','s','删除');b.type='button';
b.onclick=function(){if(confirm('删除「'+x+'」?'))post('del\n'+x).then(function(j){say('mw',j,'已删除');poll()}).catch(fail('mw'))};
r.appendChild(b);v.appendChild(r)});
tele=n.tele_ms||'';
if(!filled){filled=true;$('uri').value=n.uri||'';$('user').value=n.user||'';
if(n.mpass_set)$('mp').placeholder='口令(已设置,留空 = 不改)'}
}
function poll(){fetch('/s').then(function(r){return r.json()}).then(draw).catch(function(){
$('st').textContent='读不到状态:热点可能已经关了(底板连上 WiFi 后会关)'})}
$('show').onchange=function(){$('pass').type=this.checked?'text':'password'};
$('scan').onclick=function(){var a=$('aps');a.textContent='扫描中,约 3 秒…';
fetch('/scan').then(function(r){return r.json()}).then(function(j){a.textContent='';
if(j.err){a.textContent='底板正在尝试连接,过几秒再点一次';return}
if(!j.aps.length)a.textContent='没扫到(底板只支持 2.4G)';
j.aps.forEach(function(p){var r=el('div','row');r.appendChild(el('span','',p.ssid));
r.appendChild(el('span','dim',p.rssi+' dBm'+(p.open?' · 开放':'')));
r.onclick=function(){$('ssid').value=p.ssid;$('pass').focus()};a.appendChild(r)})
}).catch(function(){a.textContent='扫描失败,再点一次'})};
$('fw').onsubmit=function(e){e.preventDefault();
post('wifi\n'+$('ssid').value+'\n'+$('pass').value).then(function(j){
say('mw',j,'已保存,正在连接 —— 看上面的状态');if(j.ok)$('pass').value='';poll()}).catch(fail('mw'))};
$('fm').onsubmit=function(e){e.preventDefault();
post('mqtt\n'+$('uri').value.trim()+'\n'+$('user').value.trim()+'\n'+$('mp').value+'\n'+tele).then(function(j){
say('mm',j,'已保存');if(j.ok)$('mp').value='';poll()}).catch(fail('mm'))};
poll();setInterval(poll,3000);
</script>
</html>