- EspOS blogja
- A hozzászóláshoz be kell jelentkezni
- 628 megtekintés
Hozzászólások
Frissítve, v502
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
Frissítve, v503
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
Update v508
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
Update v518
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
Update v520
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
Update v522
Már nincs kedvem hozzá, de megcsináltam.
Microsoft Windows [Version 10.0.22631.5335]
(c) Microsoft Corporation. Minden jog fenntartva.
f:\EspOS>cloc ./
525 text files.
486 unique files.
311 files ignored.
github.com/AlDanial/cloc v 2.04 T=17.98 s (27.0 files/s, 6255.5 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C/C++ Header 285 2314 529 56598
HTML 125 2687 41 29517
Arduino Sketch 32 1100 198 9880
JavaScript 13 988 323 7006
DOS Batch 5 161 10 481
Text 16 37 0 320
Markdown 1 39 0 110
JSON 3 0 0 49
PHP 3 2 0 39
Clojure 3 2 0 25
-------------------------------------------------------------------------------
SUM: 486 7330 1101 104025
-------------------------------------------------------------------------------
f:\EspOS>
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
ESP8266 lezárva.
Kezembe került egy ESP32C3 devboard.
Ezt is mint a WinFos telepítés után egy fájlkezelővel kezdem. Total Commander logikát követtem, még a duplaklikk is működik.
Két nap alatt idáig jutottam:
FileManager.ino
#include <Arduino.h>#include <WiFi.h>#include <AsyncTCP.h>#include <ESPAsyncWebServer.h>#include <LittleFS.h>#include <vector>#include <algorithm>
const char* ssid="asajah";const char* pass="xxxxxxxx";
bool systemFolder = true;bool coreFolder = true;
AsyncWebServer server(80);
/* ================= REKURZÍV TÖRLÉS ================= */bool rm_rf(const String &path){File f=LittleFS.open(path);if(!f) return false;
if(!f.isDirectory()){ f.close(); return LittleFS.remove(path);}
File c=f.openNextFile();while(c){ String p=String(c.name()); if(c.isDirectory()) rm_rf(p); else LittleFS.remove(p); c=f.openNextFile();}f.close();return LittleFS.rmdir(path);}
/* ================= HTML ================= */const char INDEX_HTML[] PROGMEM = R"rawliteral(<!DOCTYPE html><html><head><meta charset="utf-8"><title>ESP32 File Manager</title><style>body{font-family:sans-serif}.box{border:1px solid #aaa;padding:10px;margin:10px;width:520px}li{cursor:pointer;padding:2px;white-space:nowrap;}li.sel{background:#def}li.up{font-weight:bold}.name{display:inline-block;min-width:18em}.size-num{display:inline-block;width:8ch;text-align:right;font-family:monospace;}.size-unit{display:inline-block;margin-left:0.5ch;font-family:monospace;color:#555;}#drop{border:2px dashed #888;padding:20px;text-align:center}#flash-status{height:20px;width:100%;border:1px solid #888;position:relative;background:#ccc;margin-bottom:5px}#flash-bar{height:100%;width:0%;color:white;padding-right:4px;box-sizing:border-box;text-align:right}button{margin:2px}</style></head><body>
<div class="box"><h3>Flash files</h3><div>Path: <span id="path">/</span></div><button onclick="mkdir()">➕ Create DIR</button><ul id="files"></ul><button id="open" disabled onclick="openFile()">Open</button><button id="dl" disabled onclick="download()">Download</button><button id="rm" disabled onclick="del()">Delete</button><button id="rn" disabled onclick="ren()">Rename</button><button id="edit" disabled onclick="editFile()">Edit</button></div>
<div class="box"><h3>Upload</h3><div id="flash-status"><div id="flash-bar">0 kB / 0 kB</div></div><div id="drop">Drag & Drop files here</div><br><input type="file" id="f" multiple><button onclick="uploadBtn()">Upload</button></div>
<script>let cwd="/", sel=null, selIsDir=false, selIsSystem=false;let flashTimer=null;
function loadFlashStatus(){fetch('/flashfree').then(r=>r.json()).then(j=>{ let bar=document.getElementById('flash-bar'); let percent=(j.used/j.total)*100; bar.style.background=percent<70?'green':percent<90?'orange':'red'; bar.style.width=percent+'%'; bar.textContent=j.used+' kB / '+j.total+' kB';});}
function btn(e,dir){document.getElementById('dl').disabled = !e || dir;document.getElementById('rm').disabled = !e || selIsSystem;document.getElementById('rn').disabled = !e || selIsSystem;document.getElementById('open').disabled = !e;document.getElementById('edit').disabled = !e || dir;}
function renderEntry(f,type){let ul=document.getElementById('files');let li=document.createElement('li');
let icon = f.dir ? '📁 ' : '📄 ';if(type==="system") icon='⚙️ ';if(type==="core") icon='🔺 ';
let name=document.createElement('span');name.className='name';name.textContent=icon+f.name;li.appendChild(name);
if(!f.dir){ li.innerHTML+= '<span class="size-num">'+f.size+'</span>'+ '<span class="size-unit">B</span>';}
li.onclick=()=>{ [...ul.children].forEach(x=>x.classList.remove('sel')); li.classList.add('sel'); sel=cwd+(cwd.endsWith('/')?'':'/')+f.name; selIsDir=f.dir; selIsSystem=(cwd==="/" && f.dir && (f.name==="system"||f.name==="core")); btn(true,f.dir);};
li.ondblclick=e=>{ e.preventDefault(); if(f.dir){ cwd=sel; load(); } else window.open(sel,'_blank');};
ul.appendChild(li);}
function load(){document.getElementById('path').textContent=cwd;loadFlashStatus();
fetch('/list',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'path='+encodeURIComponent(cwd)}).then(r=>r.json()).then(j=>{ let ul=document.getElementById('files'); ul.innerHTML=''; sel=null; selIsSystem=false; btn(false,false);
if(cwd!="/"){ let li=document.createElement('li'); li.textContent='📁 ..'; li.className='up'; li.onclick=()=>{ cwd=cwd.substring(0,cwd.lastIndexOf('/'))||"/"; load(); }; ul.appendChild(li); }
let core=null, system=null, others=[]; j.forEach(f=>{ if(cwd==="/" && f.dir && f.name==="core") core=f; else if(cwd==="/" && f.dir && f.name==="system") system=f; else others.push(f); });
if(core) renderEntry(core,"core"); if(system) renderEntry(system,"system"); others.forEach(f=>renderEntry(f,"normal"));});}
function uploadFiles(files){let i=0;flashTimer=setInterval(loadFlashStatus,300);(function next(){ if(i>=files.length){ clearInterval(flashTimer); loadFlashStatus(); load(); return; } upload(files[i++],next);})();}
function upload(file,done){let x=new XMLHttpRequest();x.onload=()=>{ if(done)done(); };x.open('POST','/upload?path='+encodeURIComponent(cwd)+'&name='+encodeURIComponent(file.name));x.send(file);}
function uploadBtn(){ uploadFiles(document.getElementById('f').files); }
drop.ondragover=e=>e.preventDefault();drop.ondrop=e=>{ e.preventDefault(); uploadFiles(e.dataTransfer.files); };
function mkdir(){let n=prompt("Dir name:"); if(!n)return;fetch('/mkdir',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'path='+encodeURIComponent(cwd+"/"+n)}).then(load);}function del(){if(selIsSystem){ alert("protected"); return; }if(!sel||!confirm("Delete?")) return;fetch('/delete',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'path='+encodeURIComponent(sel)}).then(load);}function ren(){if(!sel) return;let base=sel.substring(0,sel.lastIndexOf('/'));let n=prompt("New name:",sel.split('/').pop());if(!n) return;fetch('/rename',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'old='+encodeURIComponent(sel)+'&new='+encodeURIComponent(base+'/'+n)}).then(load);}function download(){ if(!sel||selIsDir) return; let a=document.createElement('a'); a.href=sel; a.download=''; a.click(); }function openFile(){ if(!sel) return; if(selIsDir){ cwd=sel; load(); } else window.open(sel); }
function editFile(){if(!sel||selIsDir) return;let f=document.createElement('form');f.method='POST'; f.action='/system/editor.html';let i=document.createElement('input');i.name='path'; i.value=sel;f.appendChild(i); document.body.appendChild(f);f.submit(); document.body.removeChild(f);}
load();</script></body></html>)rawliteral";
/* ================= SETUP ================= */void setup(){Serial.begin(115200);LittleFS.begin(true);
WiFi.mode(WIFI_STA);WiFi.config(IPAddress(192,168,0,88),IPAddress(192,168,0,1),IPAddress(255,255,255,0));WiFi.begin(ssid,pass);while(WiFi.status()!=WL_CONNECTED){ delay(200); yield(); }
server.on("/",HTTP_GET,[](AsyncWebServerRequest*r){ r->send(200,"text/html",INDEX_HTML); });server.serveStatic("/",LittleFS,"/");
struct Entry{String name;bool dir;size_t size;};
server.on("/list",HTTP_POST,[](AsyncWebServerRequest*r){ String path="/"; if(r->hasParam("path",true)) path=r->getParam("path",true)->value(); File dir=LittleFS.open(path); if(!dir||!dir.isDirectory()){ r->send(200,"application/json","[]"); return; }
std::vector<Entry> v; File x=dir.openNextFile(); while(x){ String n=String(x.name()).substring(String(x.name()).lastIndexOf('/')+1); v.push_back({n,x.isDirectory(),x.isDirectory()?0:x.size()}); x=dir.openNextFile(); }
auto cmp=[](const Entry&a,const Entry&b){ String A=a.name,B=b.name; A.toLowerCase();B.toLowerCase(); return A<B; }; std::sort(v.begin(),v.end(),cmp);
String j="["; for(size_t i=0;i<v.size();i++){ if(i)j+=","; j+="{\"name\":\""+v[i].name+"\",\"dir\":"+(v[i].dir?"true":"false")+",\"size\":"+String(v[i].size)+"}"; } j+="]"; r->send(200,"application/json",j);});
server.on("/flashfree",HTTP_GET,[](AsyncWebServerRequest*r){ r->send(200,"application/json", "{\"total\":"+String(LittleFS.totalBytes()/1024)+",\"used\":"+String(LittleFS.usedBytes()/1024)+"}");});
server.on("/upload",HTTP_POST,[](AsyncWebServerRequest*r){ r->send(200); },NULL,[](AsyncWebServerRequest*r,uint8_t*d,size_t l,size_t i,size_t t){ static File file; if(i==0){ if(file)file.close(); if(!r->hasParam("path")||!r->hasParam("name")) return; String p=r->getParam("path")->value(); if(!p.endsWith("/"))p+="/"; file=LittleFS.open(p+r->getParam("name")->value(),"w"); } if(file) file.write(d,l); if(i+l==t && file) file.close();});
server.on("/mkdir",HTTP_POST,[](AsyncWebServerRequest*r){ r->send(LittleFS.mkdir(r->getParam("path",true)->value())?200:500); });server.on("/delete",HTTP_POST,[](AsyncWebServerRequest*r){ r->send(rm_rf(r->getParam("path",true)->value())?200:500); });server.on("/rename",HTTP_POST,[](AsyncWebServerRequest*r){ r->send(LittleFS.rename(r->getParam("old",true)->value(),r->getParam("new",true)->value())?200:500); });
server.on("/system/editor.html",HTTP_POST,[](AsyncWebServerRequest*r){ String path=""; if(r->hasParam("path",true)) path=r->getParam("path",true)->value(); File f=LittleFS.open("/system/editor.html","r"); if(!f){ r->send(404); return; } String h=f.readString(); f.close(); h.replace("<!--INSERT_PATH_HERE-->",path); r->send(200,"text/html",h);});
server.begin();}
void loop(){}
/system/editor.html
<!DOCTYPE html><html><head><meta charset="utf-8"><title>File Editor</title><style>body{font-family:sans-serif;margin:10px}textarea{width:100%;height:70vh;font-family:monospace;font-size:14px;box-sizing:border-box;}button{margin-top:5px;padding:5px 10px;font-size:14px;}#status{margin-top:5px;color:green;}</style></head><body>
<h3>File Editor</h3><div>Path: <span id="filepath"></span></div><textarea id="editor"></textarea><br><button id="saveBtn" disabled>Save</button><div id="status"></div>
<script>// POST esetén a szerver ideágyazza a path-otlet path = "<!--INSERT_PATH_HERE-->";
// Ha GET, akkor query stringből vesszükif(!path){ const params = new URLSearchParams(window.location.search); path = params.get('path') || '';}
const editor = document.getElementById('editor');const saveBtn = document.getElementById('saveBtn');const status = document.getElementById('status');let original = '';
if(!path){ editor.value = 'No file specified'; saveBtn.disabled = true;}else{ document.getElementById('filepath').textContent = path; fetch(path).then(r=>r.text()).then(t=>{ editor.value = t; original = t; saveBtn.disabled = false; }).catch(e=>{ editor.value='Failed to load file'; saveBtn.disabled = true; });}
saveBtn.onclick = ()=>{ if(editor.value === original){ status.textContent = 'No changes to save.'; return; }
fetch('/upload?path=' + encodeURIComponent(path.substring(0,path.lastIndexOf('/')+1)) + '&name=' + encodeURIComponent(path.split('/').pop()), { method:'POST', body: new Blob([editor.value]) }).then(r=>{ if(r.ok){ status.textContent = 'File saved successfully.'; original = editor.value; }else{ status.textContent = 'Failed to save file.'; status.style.color='red'; } }).catch(e=>{ status.textContent='Error saving file'; status.style.color='red'; });};</script>
</body></html>
EspOS hibáiból tanulva innen folyt köv. Először egy HTTP/HTTPS webszerver lesz, aztán meg majd valami.
Akinek van kedve meg valami ESP32 kütyüje próbálja ki, várom a visszajelzéseket.
AsyncWebServer új verzió kell hozzá,
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni
Szerintem kiindulásnak jó. Ha megtanulom a githubot fel lesz basszva oda.
Egy TC stílusú fájkezelő egy használható text editorral.
σ→0, SNR<1 (A semleges részecskékkel nincs mérhető kölcsönhatás)
- A hozzászóláshoz be kell jelentkezni