mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-19 11:56:11 +02:00
Merge branch 'development03' into dev03
This commit is contained in:
commit
637459ab9e
19 changed files with 665 additions and 247 deletions
|
@ -209,24 +209,32 @@ time_t ahoywifi::getNtpTime(void) {
|
|||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ahoywifi::scanAvailNetworks(void) {
|
||||
int n = WiFi.scanComplete();
|
||||
if(n == -2)
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ahoywifi::getAvailNetworks(JsonObject obj) {
|
||||
JsonArray nets = obj.createNestedArray("networks");
|
||||
|
||||
int n = WiFi.scanComplete();
|
||||
if(n == -2) {
|
||||
WiFi.scanNetworks(true);
|
||||
} else if(n) {
|
||||
if(n > 0) {
|
||||
int sort[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
sort[i] = i;
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = i + 1; j < n; j++)
|
||||
if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i]))
|
||||
std::swap(sort[i], sort[j]);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
nets[i]["ssid"] = WiFi.SSID(i);
|
||||
nets[i]["rssi"] = WiFi.RSSI(i);
|
||||
// TODO: does github workflow use another version of this library?
|
||||
// ahoywifi.cpp:223:38: error: 'class WiFiClass' has no member named 'isHidden'
|
||||
//nets[i]["hidden"] = WiFi.isHidden(i) ? true : false;
|
||||
nets[i]["ssid"] = WiFi.SSID(sort[i]);
|
||||
nets[i]["rssi"] = WiFi.RSSI(sort[i]);
|
||||
}
|
||||
WiFi.scanDelete();
|
||||
if(WiFi.scanComplete() == -2)
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ class ahoywifi {
|
|||
bool setupStation(uint32_t timeout);
|
||||
bool getApActive(void);
|
||||
time_t getNtpTime(void);
|
||||
void scanAvailNetworks(void);
|
||||
void getAvailNetworks(JsonObject obj);
|
||||
|
||||
private:
|
||||
|
|
|
@ -23,6 +23,7 @@ app::app() {
|
|||
loadDefaultConfig();
|
||||
|
||||
mSys = new HmSystemType();
|
||||
mSys->enableDebug();
|
||||
mShouldReboot = false;
|
||||
}
|
||||
|
||||
|
@ -170,6 +171,23 @@ void app::loop(void) {
|
|||
|
||||
mMqtt.sendMsg("uptime", val);
|
||||
|
||||
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
if(NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
char topic[32 + MAX_NAME_LENGTH], val[32];
|
||||
if (!iv->isAvailable(mUtcTimestamp, rec) && !iv->isProducing(mUtcTimestamp, rec)){
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->name);
|
||||
snprintf(val, 32, DEF_MQTT_IV_MESSAGE_NOT_AVAIL_AND_NOT_PRODUCED);
|
||||
mMqtt.sendMsg(topic, val);
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name);
|
||||
snprintf(val, 32, "0");
|
||||
mMqtt.sendMsg(topic, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef __MQTT_TEST__
|
||||
// für einfacheren Test mit MQTT, den MQTT abschnitt in 10 Sekunden wieder ausführen
|
||||
mMqttTicker = mMqttInterval - 10;
|
||||
|
@ -487,19 +505,6 @@ void app::processPayload(bool retransmit) {
|
|||
}
|
||||
}
|
||||
|
||||
if (mMqttActive) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
char topic[32 + MAX_NAME_LENGTH], val[32];
|
||||
if (!iv->isAvailable(mUtcTimestamp, rec) && !iv->isProducing(mUtcTimestamp, rec)) {
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->name);
|
||||
snprintf(val, 32, DEF_MQTT_IV_MESSAGE_NOT_AVAIL_AND_NOT_PRODUCED);
|
||||
mMqtt.sendMsg(topic, val);
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name);
|
||||
snprintf(val, 32, "0");
|
||||
mMqtt.sendMsg(topic, val);
|
||||
}
|
||||
}
|
||||
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
@ -626,6 +631,12 @@ bool app::getWifiApActive(void) {
|
|||
return mWifi->getApActive();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::scanAvailNetworks(void) {
|
||||
mWifi->scanAvailNetworks();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::getAvailNetworks(JsonObject obj) {
|
||||
mWifi->getAvailNetworks(obj);
|
||||
|
@ -880,6 +891,7 @@ void app::setupMqtt(void) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::resetPayload(Inverter<> *iv) {
|
||||
DPRINTLN(DBG_INFO, "resetPayload: id: " + String(iv->id));
|
||||
|
@ -892,6 +904,8 @@ void app::resetPayload(Inverter<> *iv) {
|
|||
mPayload[iv->id].ts = mUtcTimestamp;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::calculateSunriseSunset() {
|
||||
// Source: https://en.wikipedia.org/wiki/Sunrise_equation#Complete_calculation_on_Earth
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ class app {
|
|||
void saveValues(void);
|
||||
void resetPayload(Inverter<>* iv);
|
||||
bool getWifiApActive(void);
|
||||
void scanAvailNetworks(void);
|
||||
void getAvailNetworks(JsonObject obj);
|
||||
|
||||
uint8_t getIrqPin(void) {
|
||||
|
@ -171,6 +172,7 @@ class app {
|
|||
inline bool mqttIsConnected(void) { return mMqtt.isConnected(); }
|
||||
inline bool getSettingsValid(void) { return mSettingsValid; }
|
||||
inline bool getRebootRequestState(void) { return mShowRebootRequest; }
|
||||
inline uint32_t getMqttTxCnt(void) { return mMqtt.getTxCnt(); }
|
||||
|
||||
HmSystemType *mSys;
|
||||
bool mShouldReboot;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 22
|
||||
#define VERSION_PATCH 25
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
|
|
@ -1,4 +1,33 @@
|
|||
function toggle(id, hide) {
|
||||
/**
|
||||
* GENERIC FUNCTIONS
|
||||
*/
|
||||
|
||||
function topnav() {
|
||||
toggle("topnav");
|
||||
}
|
||||
|
||||
function parseMenu(obj) {
|
||||
var e = document.getElementById("topnav");
|
||||
e.innerHTML = "";
|
||||
for(var i = 0; i < obj["name"].length; i ++) {
|
||||
if(obj["name"][i] == "-")
|
||||
e.appendChild(span("", ["seperator"]));
|
||||
else {
|
||||
var l = link(obj["link"][i], obj["name"][i], obj["trgt"][i]);
|
||||
if(obj["link"][i] == window.location.pathname)
|
||||
l.classList.add("active");
|
||||
e.appendChild(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseVersion(obj) {
|
||||
document.getElementById("version").appendChild(
|
||||
link("https://github.com/lumapu/ahoy/commits/" + obj["build"], "Git SHA: " + obj["build"] + " :: " + obj["version"], "_blank")
|
||||
);
|
||||
}
|
||||
|
||||
function setHide(id, hide) {
|
||||
var elm = document.getElementById(id);
|
||||
if(hide) {
|
||||
if(!elm.classList.contains("hide"))
|
||||
|
@ -8,6 +37,15 @@ function toggle(id, hide) {
|
|||
elm.classList.remove('hide');
|
||||
}
|
||||
|
||||
|
||||
function toggle(id) {
|
||||
var e = document.getElementById(id);
|
||||
if(!e.classList.contains("hide"))
|
||||
e.classList.add("hide");
|
||||
else
|
||||
e.classList.remove('hide');
|
||||
}
|
||||
|
||||
function getAjax(url, ptr, method="GET", json=null) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
if(xhr != null) {
|
||||
|
@ -27,6 +65,10 @@ function getAjax(url, ptr, method="GET", json=null) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CREATE DOM FUNCTIONS
|
||||
*/
|
||||
|
||||
function des(val) {
|
||||
e = document.createElement('p');
|
||||
e.classList.add("subdes");
|
||||
|
@ -68,6 +110,13 @@ function sel(name, opt, selId) {
|
|||
return e;
|
||||
}
|
||||
|
||||
function selDelAllOpt(sel) {
|
||||
var i, l = sel.options.length - 1;
|
||||
for(i = l; i >= 0; i--) {
|
||||
sel.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
function opt(val, html) {
|
||||
o = document.createElement('option');
|
||||
o.value = val;
|
||||
|
@ -93,3 +142,13 @@ function span(val, cl=null, id=null) {
|
|||
function br() {
|
||||
return document.createElement('br');
|
||||
}
|
||||
|
||||
function link(dst, text, target=null) {
|
||||
var a = document.createElement('a');
|
||||
var t = document.createTextNode(text);
|
||||
a.href = dst;
|
||||
if(null != target)
|
||||
a.target = target;
|
||||
a.appendChild(t);
|
||||
return a;
|
||||
}
|
||||
|
|
|
@ -7,65 +7,75 @@
|
|||
<script type="text/javascript" src="api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AHOY</h1>
|
||||
<div id="content" class="content">
|
||||
<SCRIPT>
|
||||
function promptFunction() {
|
||||
var Text = prompt("This project was started from https://www.mikrocontroller.net/topic/525778 this discussion.\n\n" +
|
||||
"The Hoymiles protocol was decrypted through the voluntary efforts of many participants. ahoy, among others, was developed based on this work.\n" +
|
||||
"The software was developed to the best of our knowledge and belief. Nevertheless, no liability can be accepted for a malfunction or guarantee loss of the inverter.\n\n" +
|
||||
"Ahoy is freely available. If you paid money for the software, you probably got ripped off.\n\nPlease type in 'YeS', you are accept our Disclaim. You should then save your config.", "");
|
||||
if (Text != "YeS")
|
||||
promptFunction();
|
||||
else
|
||||
return true;
|
||||
|
||||
}
|
||||
</SCRIPT>
|
||||
<div class="topnav">
|
||||
<a href="/" class="title">AhoyDTU</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="topnav()">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</a>
|
||||
<div id="topnav" class="hide"></div>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<div id="content">
|
||||
<script>
|
||||
function promptFunction() {
|
||||
var Text = prompt("This project was started from https://www.mikrocontroller.net/topic/525778 this discussion.\n\n" +
|
||||
"The Hoymiles protocol was decrypted through the voluntary efforts of many participants. ahoy, among others, was developed based on this work.\n" +
|
||||
"The software was developed to the best of our knowledge and belief. Nevertheless, no liability can be accepted for a malfunction or guarantee loss of the inverter.\n\n" +
|
||||
"Ahoy is freely available. If you paid money for the software, you probably got ripped off.\n\nPlease type in 'YeS', you are accept our Disclaim. You should then save your config.", "");
|
||||
if (Text != "YeS")
|
||||
promptFunction();
|
||||
else
|
||||
return true;
|
||||
|
||||
<p>
|
||||
<a href="/live">Visualization</a><br/>
|
||||
<br/>
|
||||
<a href="/setup">Setup</a><br/>
|
||||
<br/>
|
||||
<a href="/serial">Webserial & Commands</a><br/>
|
||||
</p>
|
||||
<p><span class="des">Uptime: </span><span id="uptime"></span></p>
|
||||
<p><span class="des">ESP-Time: </span><span id="date"></span></p>
|
||||
<div id="sun">
|
||||
<span class="des">Sunrise: </span><span id="sunrise"></span><br>
|
||||
<span class="des">Sunset: </span><span id="sunset"></span>
|
||||
</div>
|
||||
<p><span class="des">WiFi RSSI: </span><span id="wifi_rssi"></span> dBm</p>
|
||||
<p>
|
||||
<span class="des">Statistics: </span>
|
||||
<pre id="stat"></pre>
|
||||
<pre id="iv"></pre>
|
||||
<pre id="warn_info"></pre>
|
||||
</p>
|
||||
<p>Every <span id="refresh"></span> seconds the values are updated</p>
|
||||
}
|
||||
</script>
|
||||
<p><span class="des">Uptime: </span><span id="uptime"></span></p>
|
||||
<p><span class="des">ESP-Time: </span><span id="date"></span></p>
|
||||
<div id="sun">
|
||||
<span class="des">Sunrise: </span><span id="sunrise"></span><br>
|
||||
<span class="des">Sunset: </span><span id="sunset"></span>
|
||||
</div>
|
||||
<p><span class="des">WiFi RSSI: </span><span id="wifi_rssi"></span> dBm</p>
|
||||
<p>
|
||||
<span class="des">Statistics: </span>
|
||||
<pre id="stat"></pre>
|
||||
<pre id="iv"></pre>
|
||||
<pre id="warn_info"></pre>
|
||||
</p>
|
||||
<p>Every <span id="refresh"></span> seconds the values are updated</p>
|
||||
|
||||
<div id="note">
|
||||
New updates can be found on Github: <a href="https://github.com/lumapu/ahoy" target="_blank">https://github.com/lumapu/ahoy</a><br/>
|
||||
<br/>
|
||||
Please report issues in <a href="https://github.com/lumapu/ahoy/issues">Github</a><br/>
|
||||
Discuss with us on <a href="https://discord.gg/WzhxEY62mB">Discord</a><br/>
|
||||
Support this project: <a href="https://paypal.me/lupusch">Donate</a><br/>
|
||||
<p class="lic"><a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de">Creative Commons - https://creativecommons.org/licenses/by-nc-sa/3.0/de/</a><br/>
|
||||
Check the licenses which are published on <a href="https://github.com/lumapu/ahoy">https://github.com/lumapu/ahoy</a> as well</p><br/>
|
||||
|
||||
This project was started from <a href="https://www.mikrocontroller.net/topic/525778" target="_blank">this discussion. (Mikrocontroller.net)</a>
|
||||
<div id="note">
|
||||
Discuss with us on <a href="https://discord.gg/WzhxEY62mB">Discord</a><br/>
|
||||
<h2>Support this project:</h2>
|
||||
<ul>
|
||||
<li>Report <a href="https://github.com/lumapu/ahoy/issues" target="_blank">issues</a></li>
|
||||
<li>Contribute to <a href="https://github.com/lumapu/ahoy/blob/main/tools/esp8266/User_Manual.md" target="_blank">documentation</a></li>
|
||||
<li>Test <a href="https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml" target="_blank">development firmware</a></li>
|
||||
<li>make a <a href="https://paypal.me/lupusch" target="_blank">donation</a></li>
|
||||
</ul>
|
||||
<p class="lic">
|
||||
This project was started from <a href="https://www.mikrocontroller.net/topic/525778" target="_blank">this discussion. (Mikrocontroller.net)</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="left">© 2022</p>
|
||||
<p class="left"><a href="/update">Update Firmware</a></p>
|
||||
<p class="right" id="version"></p>
|
||||
<p class="right"><a href="/reboot">Reboot</a></p>
|
||||
<p class="right"><a href="/api">REST API</a></p>
|
||||
<div class="left">
|
||||
AhoyDTU © 2022
|
||||
<ul>
|
||||
<li><a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||
<li><a href="https://github.com/lumapu/ahoy" target="_blank">Github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="version"></span><br/><br/>
|
||||
<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de" target="_blank" >CC BY-NC-SA 3.0</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var mIntervalSet = false;
|
||||
var exeOnce = true;
|
||||
|
||||
function apiCb(obj) {
|
||||
var e = document.getElementById("apiResult");
|
||||
|
@ -88,8 +98,8 @@
|
|||
function parseSys(obj) {
|
||||
// Disclaimer
|
||||
//if(obj["disclaimer"] == false) sessionStorage.setItem("gDisclaimer", promptFunction());
|
||||
|
||||
document.getElementById("version").innerHTML = "Git SHA: " + obj["build"] + " :: " + obj["version"];
|
||||
if(true == exeOnce)
|
||||
parseVersion(obj);
|
||||
document.getElementById("wifi_rssi").innerHTML = obj["wifi_rssi"];
|
||||
|
||||
var date = new Date(obj["ts_now"] * 1000);
|
||||
|
@ -170,14 +180,16 @@
|
|||
|
||||
function parse(obj) {
|
||||
if(null != obj) {
|
||||
if(true == exeOnce)
|
||||
parseMenu(obj["menu"]);
|
||||
parseSys(obj["system"]);
|
||||
parseStat(obj["statistics"]);
|
||||
parseIv(obj["inverter"]);
|
||||
parseWarnInfo(obj["warnings"], obj["infos"]);
|
||||
document.getElementById("refresh").innerHTML = obj["refresh_interval"];
|
||||
if(false == mIntervalSet) {
|
||||
if(true == exeOnce) {
|
||||
window.setInterval("getAjax('/api/index', parse)", obj["refresh_interval"] * 1000);
|
||||
mIntervalSet = true;
|
||||
exeOnce = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -7,60 +7,78 @@
|
|||
<script type="text/javascript" src="api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Serial Console</h1>
|
||||
<div id="content" class="content">
|
||||
<div class="serial">
|
||||
<textarea id="serial" cols="80" rows="20" readonly></textarea><br/>
|
||||
connected: <span class="dot" id="connected"></span>
|
||||
Uptime: <span id="uptime"></span>
|
||||
<input type="button" value="clear" class="btn" id="clear"/>
|
||||
<input type="button" value="autoscroll" class="btn" id="scroll"/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<hr>
|
||||
<h3>Commands</h3>
|
||||
<br/>
|
||||
<label for="iv">Select Inverter:</label>
|
||||
<select name="iv" id="InvID">
|
||||
</select>
|
||||
<br/>
|
||||
<div id="power">
|
||||
<input type="button" value="Restart" class="btn" id="restart"/>
|
||||
<input type="button" value="Turn Off" class="btn" id="power_off"/>
|
||||
<input type="button" value="Turn On" class="btn" id="power_on"/>
|
||||
<div class="topnav">
|
||||
<a href="/" class="title">AhoyDTU</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="topnav()">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</a>
|
||||
<div id="topnav" class="hide"></div>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<div id="content">
|
||||
<div class="serial">
|
||||
<textarea id="serial" cols="80" rows="20" readonly></textarea><br/>
|
||||
connected: <span class="dot" id="connected"></span>
|
||||
Uptime: <span id="uptime"></span>
|
||||
<input type="button" value="clear" class="btn" id="clear"/>
|
||||
<input type="button" value="autoscroll" class="btn" id="scroll"/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<hr>
|
||||
<h3>Commands</h3>
|
||||
<br/>
|
||||
<label for="iv">Select Inverter:</label>
|
||||
<select name="iv" id="InvID">
|
||||
</select>
|
||||
<br/>
|
||||
<div id="power">
|
||||
<input type="button" value="Restart" class="btn" id="restart"/>
|
||||
<input type="button" value="Turn Off" class="btn" id="power_off"/>
|
||||
<input type="button" value="Turn On" class="btn" id="power_on"/>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<label>Send Power Limit: </label>
|
||||
<input type="number" class="text" name="pwrlimval" maxlength="4"/>
|
||||
<label> </label>
|
||||
<select name="pwrlimcntrl" id="pwrlimcntrl">
|
||||
<option value="" selected disabled hidden>select the unit and persistence</option>
|
||||
<option value="0">absolute in Watt non persistent</option>
|
||||
<option value="1">relative in percent non persistent</option>
|
||||
<option value="256">absolute in Watt persistent</option>
|
||||
<option value="257">relative in percent persistent</option>
|
||||
</select>
|
||||
<br/>
|
||||
<input type="button" value="Send Power Limit" class="btn" id="sendpwrlim"/>
|
||||
<br/>
|
||||
<p>Ctrl result: <span id="result">n/a</span></p>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<label>Send Power Limit: </label>
|
||||
<input type="number" class="text" name="pwrlimval" maxlength="4"/>
|
||||
<label> </label>
|
||||
<select name="pwrlimcntrl" id="pwrlimcntrl">
|
||||
<option value="" selected disabled hidden>select the unit and persistence</option>
|
||||
<option value="0">absolute in Watt non persistent</option>
|
||||
<option value="1">relative in percent non persistent</option>
|
||||
<option value="256">absolute in Watt persistent</option>
|
||||
<option value="257">relative in percent persistent</option>
|
||||
</select>
|
||||
<br/>
|
||||
<input type="button" value="Send Power Limit" class="btn" id="sendpwrlim"/>
|
||||
<br/>
|
||||
<p>Ctrl result: <span id="result">n/a</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="left">© 2022</p>
|
||||
<p class="left"><a href="/">Home</a></p>
|
||||
<p class="right" id="version"></p>
|
||||
<div class="left">
|
||||
AhoyDTU © 2022
|
||||
<ul>
|
||||
<li><a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||
<li><a href="https://github.com/lumapu/ahoy" target="_blank">Github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="version"></span><br/><br/>
|
||||
<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de" target="_blank" >CC BY-NC-SA 3.0</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var mAutoScroll = true;
|
||||
var con = document.getElementById("serial");
|
||||
var mIntervalSet = false;
|
||||
var exeOnce = true;
|
||||
|
||||
function parseSys(obj) {
|
||||
var up = obj["ts_uptime"];
|
||||
|
@ -73,14 +91,15 @@
|
|||
+ ("0"+min).substr(-2) + ":"
|
||||
+ ("0"+sec).substr(-2);
|
||||
|
||||
if(false == mIntervalSet) {
|
||||
document.getElementById("version").innerHTML = "Git SHA: " + obj["build"] + " :: " + obj["version"];
|
||||
if(true == exeOnce) {
|
||||
parseVersion(obj);
|
||||
window.setInterval("getAjax('/api/system', parseSys)", 10000);
|
||||
mIntervalSet = true;
|
||||
exeOnce = false;
|
||||
}
|
||||
}
|
||||
|
||||
function parse(root) {
|
||||
parseMenu(root["menu"]);
|
||||
select = document.getElementById('InvID');
|
||||
|
||||
if(null == root) return;
|
||||
|
|
|
@ -18,10 +18,18 @@
|
|||
</script>
|
||||
</head>
|
||||
<body onload="load()">
|
||||
<h1>Setup</h1>
|
||||
<div id="setup" class="content">
|
||||
<div class="topnav">
|
||||
<a href="/" class="title">AhoyDTU</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="topnav()">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</a>
|
||||
<div id="topnav" class="hide"></div>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<div id="content">
|
||||
<a class="erase" href="/erase">ERASE SETTINGS (not WiFi)</a>
|
||||
<a class="btn" href="/erase">ERASE SETTINGS (not WiFi)</a>
|
||||
|
||||
<form method="post" action="/save">
|
||||
<fieldset>
|
||||
|
@ -36,9 +44,11 @@
|
|||
<fieldset>
|
||||
<legend class="des">WiFi</legend>
|
||||
<p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.</p>
|
||||
<label for="scanbtn">Search Networks</label>
|
||||
<input type="button" name="scanbtn" id="scanbtn" class="btn" value="scan" onclick="scan()"/><br/>
|
||||
<label for="networks">Avail Networks</label>
|
||||
<select name="networks" id="networks" onChange="selNet()">
|
||||
<option value="-1">scanning ...</option>
|
||||
<option value="-1">not scanned</option>
|
||||
</select>
|
||||
<label for="ssid">SSID</label>
|
||||
<input type="text" name="ssid" class="text"/>
|
||||
|
@ -52,7 +62,7 @@
|
|||
<fieldset>
|
||||
<legend class="des">Inverter</legend>
|
||||
<div id="inverter"></div><br/>
|
||||
<input type="button" id="btnAdd" value="Add Inverter"/>
|
||||
<input type="button" id="btnAdd" class="btn" value="Add Inverter"/>
|
||||
<p class="subdes">General</p>
|
||||
<label for="invInterval">Interval [s]</label>
|
||||
<input type="text" class="text" name="invInterval"/>
|
||||
|
@ -139,11 +149,17 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="left"><a href="/">Home</a></p>
|
||||
<p class="left"><a href="/update">Update Firmware</a></p>
|
||||
<p class="right" id="version"></p>
|
||||
<p class="right"><a href="/factory">Factory Reset</a></p>
|
||||
<p class="right"><a href="/reboot">Reboot</a></p>
|
||||
<div class="left">
|
||||
AhoyDTU © 2022
|
||||
<ul>
|
||||
<li><a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||
<li><a href="https://github.com/lumapu/ahoy" target="_blank">Github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="version"></span><br/><br/>
|
||||
<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de" target="_blank" >CC BY-NC-SA 3.0</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var highestId = 0;
|
||||
|
@ -156,6 +172,15 @@
|
|||
ivHtml(JSON.parse('{"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""]}'), highestId + 1);
|
||||
});
|
||||
|
||||
function apiCbWifi(obj) {
|
||||
var e = document.getElementById("networks");
|
||||
selDelAllOpt(e);
|
||||
if(obj["success"])
|
||||
e.appendChild(opt("-1", "scanning ..."))
|
||||
else
|
||||
e.appendChild(opt("-1", "Error: " + obj["error"]));
|
||||
}
|
||||
|
||||
function apiCbNtp(obj) {
|
||||
var e = document.getElementById("apiResultNtp");
|
||||
if(obj["success"])
|
||||
|
@ -180,6 +205,13 @@
|
|||
getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj));
|
||||
}
|
||||
|
||||
function scan() {
|
||||
var obj = new Object();
|
||||
obj.cmd = "scan_wifi";
|
||||
getAjax("/api/setup", apiCbWifi, "POST", JSON.stringify(obj));
|
||||
setTimeout(function() {getAjax('/api/setup/networks', listNetworks)}, 7000);
|
||||
}
|
||||
|
||||
function syncTime() {
|
||||
var obj = new Object();
|
||||
obj.cmd = "sync_ntp";
|
||||
|
@ -197,13 +229,14 @@
|
|||
var e = document.getElementsByName(id + "Addr")[0];
|
||||
e.value = "";
|
||||
e.dispatchEvent(new Event("keyup"));
|
||||
e.dispatchEvent(new Event("change"));
|
||||
document.getElementsByName(id + "Name")[0].value = "";
|
||||
}
|
||||
|
||||
function ivHtml(obj, id) {
|
||||
highestId = id;
|
||||
if(highestId == (maxInv - 1))
|
||||
toggle("btnAdd", true);
|
||||
setHide("btnAdd", true);
|
||||
iv = document.getElementById("inverter");
|
||||
iv.appendChild(des("Inverter " + id));
|
||||
id = "inv" + id;
|
||||
|
@ -212,28 +245,32 @@
|
|||
iv.appendChild(lbl(id + "Addr", "Address*"));
|
||||
var addr = inp(id + "Addr", obj["serial"], 12)
|
||||
iv.appendChild(addr);
|
||||
addr.addEventListener("keyup", (e) => {
|
||||
var serial = addr.value.substring(0,4);
|
||||
var max = 0;
|
||||
for(var i=0;i<4;i++) {
|
||||
toggle(id+"ModPwr"+i, true);
|
||||
toggle(id+"ModName"+i, true);
|
||||
}
|
||||
toggle("lbl"+id+"ModPwr", true);
|
||||
toggle("lbl"+id+"ModName", true);
|
||||
['keyup', 'change'].forEach(function(evt) {
|
||||
|
||||
if(serial == "1161") max = 4;
|
||||
else if(serial == "1141") max = 2;
|
||||
else if(serial == "1121") max = 1;
|
||||
addr.addEventListener(evt, (e) => {
|
||||
var serial = addr.value.substring(0,4);
|
||||
var max = 0;
|
||||
for(var i=0;i<4;i++) {
|
||||
setHide(id+"ModPwr"+i, true);
|
||||
setHide(id+"ModName"+i, true);
|
||||
}
|
||||
setHide("lbl"+id+"ModPwr", true);
|
||||
setHide("lbl"+id+"ModName", true);
|
||||
|
||||
for(var i=0;i<max;i++) {
|
||||
toggle(id+"ModPwr"+i, false);
|
||||
toggle(id+"ModName"+i, false);
|
||||
}
|
||||
if(max != 0) {
|
||||
toggle("lbl"+id+"ModPwr", false);
|
||||
toggle("lbl"+id+"ModName", false);
|
||||
}
|
||||
if(serial === "1161") max = 4;
|
||||
else if(serial === "1141") max = 2;
|
||||
else if(serial === "1121") max = 1;
|
||||
else max = 0;
|
||||
|
||||
if(max != 0) {
|
||||
for(var i=0;i<max;i++) {
|
||||
setHide(id+"ModPwr"+i, false);
|
||||
setHide(id+"ModName"+i, false);
|
||||
}
|
||||
setHide("lbl"+id+"ModPwr", false);
|
||||
setHide("lbl"+id+"ModName", false);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
for(var i of [["Name", "name", "Name*", 32]]) {
|
||||
|
@ -268,7 +305,7 @@
|
|||
function parseSys(obj) {
|
||||
for(var i of [["device", "device_name"], ["ssid", "ssid"]])
|
||||
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
||||
document.getElementById("version").innerHTML = "Git SHA: " + obj["build"] + " :: " + obj["version"];
|
||||
parseVersion(obj);
|
||||
}
|
||||
|
||||
function parseIv(obj) {
|
||||
|
@ -372,6 +409,7 @@
|
|||
|
||||
function parse(root) {
|
||||
if(null != root) {
|
||||
parseMenu(root["menu"]);
|
||||
parseSys(root["system"]);
|
||||
parseIv(root["inverter"]);
|
||||
parseMqtt(root["mqtt"]);
|
||||
|
@ -381,28 +419,26 @@
|
|||
parseRadio(root["radio"]);
|
||||
parseSerial(root["serial"]);
|
||||
}
|
||||
getAjax('/api/setup/networks', listNetworks);
|
||||
window.setInterval("getAjax('/api/setup/networks', listNetworks)", 7000);
|
||||
}
|
||||
|
||||
function listNetworks(root) {
|
||||
var s = document.getElementById("networks");
|
||||
selDelAllOpt(s);
|
||||
if(root["networks"].length > 0) {
|
||||
var s = document.getElementById("networks");
|
||||
var i, l = s.options.length - 1;
|
||||
for(i = l; i >= 0; i--) {
|
||||
s.remove(i);
|
||||
}
|
||||
|
||||
s.appendChild(opt("-1", "please select network"));
|
||||
for(i = 0; i < root["networks"].length; i++) {
|
||||
s.appendChild(opt(root["networks"][i]["ssid"], root["networks"][i]["ssid"] + " (" + root["networks"][i]["rssi"] + " dBm)"));
|
||||
}
|
||||
}
|
||||
else
|
||||
s.appendChild(opt("-1", "no network found"));
|
||||
}
|
||||
|
||||
function selNet() {
|
||||
var s = document.getElementById("networks");
|
||||
var e = document.getElementsByName("ssid")[0];
|
||||
e.value = s.value;
|
||||
if(-1 != s.value)
|
||||
e.value = s.value;
|
||||
}
|
||||
|
||||
hiddenInput = document.getElementById("disclaimer")
|
||||
|
|
|
@ -1,19 +1,158 @@
|
|||
h1 {
|
||||
margin: 0;
|
||||
padding: 20pt;
|
||||
font-size: 22pt;
|
||||
color: #fff;
|
||||
background-color: #006ec0;
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
html, body {
|
||||
font-family: Arial;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.topnav {
|
||||
background-color: #333;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.topnav a {
|
||||
color: #fff;
|
||||
padding: 14px 14px;
|
||||
text-decoration: none;
|
||||
font-size: 17px;
|
||||
display: block;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#topnav a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.topnav a.icon {
|
||||
background: #333;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.topnav a:hover {
|
||||
background-color: #044e86 !important;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.title {
|
||||
background-color: #006ec0;
|
||||
color: #fff !important;
|
||||
padding-left: 80px !important
|
||||
}
|
||||
|
||||
.topnav .icon span {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 3px;
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.topnav .active {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
span.seperator {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin: 5px 0px 5px;
|
||||
background-color: #494949;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 50px 20px 120px 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#footer {
|
||||
height: 120px;
|
||||
margin-top: -120px;
|
||||
background-color: #555;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#footer .right {
|
||||
color: #bbb;
|
||||
margin: 23px 25px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#footer .left {
|
||||
color: #bbb;
|
||||
margin: 23px 0px 0px 25px;
|
||||
}
|
||||
|
||||
#footer ul {
|
||||
list-style-type: none;
|
||||
margin: 20px auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#footer ul li, #footer a {
|
||||
color: #bbb;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#footer a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 992px) {
|
||||
.topnav {
|
||||
width: 230px !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.topnav a.icon {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.topnav a {
|
||||
padding: 14px 24px;
|
||||
}
|
||||
|
||||
.topnav .title {
|
||||
padding-left: 24px !important;
|
||||
}
|
||||
|
||||
.topnav .hide {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 15px 15px 120px 250px;
|
||||
}
|
||||
|
||||
#footer .left {
|
||||
margin-left: 250px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/** old CSS below **/
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
font-size: 13pt;
|
||||
|
@ -31,17 +170,17 @@ p.lic, p.lic a {
|
|||
}
|
||||
|
||||
.s_active, .s_collapsible:hover {
|
||||
background-color: #006ec0;
|
||||
background-color: #044e86;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.s_content {
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
.s_collapsible {
|
||||
background-color: #044e86;
|
||||
background-color: #006ec0;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 18px;
|
||||
|
@ -65,10 +204,6 @@ p.lic, p.lic a {
|
|||
margin: 0 0 7px 12px;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
text-decoration: none;
|
||||
font-size: 13pt;
|
||||
|
@ -79,37 +214,15 @@ a:hover, a:focus {
|
|||
color: #f00;
|
||||
}
|
||||
|
||||
a.erase {
|
||||
a.btn {
|
||||
background-color: #006ec0;
|
||||
color: #fff;
|
||||
padding: 7px;
|
||||
padding: 7px 15px 7px 15px;
|
||||
display: inline-block;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 15px 15px 60px 15px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
height: 45px;
|
||||
background-color: #006ec0;
|
||||
width: 100%;
|
||||
border-top: 5px solid #fff;
|
||||
}
|
||||
|
||||
#footer p, #footer a {
|
||||
color: #fff;
|
||||
padding: 0 7px 0 7px;
|
||||
font-size: 10pt !important;
|
||||
}
|
||||
|
||||
div.content {
|
||||
background-color: #fff;
|
||||
padding-bottom: 65px;
|
||||
overflow: auto;
|
||||
a.btn:hover {
|
||||
background-color: #044e86 !important;
|
||||
}
|
||||
|
||||
input, select {
|
||||
|
@ -160,6 +273,10 @@ label {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
|
54
tools/esp8266/html/system.html
Normal file
54
tools/esp8266/html/system.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>System</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript" src="api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="topnav">
|
||||
<a href="/" class="title">AhoyDTU</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="topnav()">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</a>
|
||||
<div id="topnav" class="hide"></div>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<div id="content">
|
||||
<a href="/factory" class="btn">Factory Reset</a><br/>
|
||||
<br/>
|
||||
<a href="/reboot" class="btn">Reboot</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div class="left">
|
||||
AhoyDTU © 2022
|
||||
<ul>
|
||||
<li><a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||
<li><a href="https://github.com/lumapu/ahoy" target="_blank">Github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="version"></span><br/><br/>
|
||||
<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de" target="_blank" >CC BY-NC-SA 3.0</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
function parseSys(obj) {
|
||||
parseVersion(obj);
|
||||
}
|
||||
|
||||
function parse(obj) {
|
||||
if(null != obj) {
|
||||
parseMenu(obj["menu"]);
|
||||
parseSys(obj["system"]);
|
||||
}
|
||||
}
|
||||
|
||||
getAjax("/api/index", parse);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -7,29 +7,54 @@
|
|||
<script type="text/javascript" src="api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Update</h1>
|
||||
<div id="content" class="content">
|
||||
<div>
|
||||
Make sure that you have noted all your settings before starting an update. New versions may have changed their memory layout which can break your existing settings.<br/>
|
||||
<br/>
|
||||
<a href="/get_setup" target="_blank">Download your settings (JSON file)</a>
|
||||
<div class="topnav">
|
||||
<a href="/" class="title">AhoyDTU</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="topnav()">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</a>
|
||||
<div id="topnav" class="hide"></div>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<div id="content">
|
||||
<div>
|
||||
Make sure that you have noted all your settings before starting an update. New versions may have changed their memory layout which can break your existing settings.<br/>
|
||||
<br/>
|
||||
<a href="/get_setup" target="_blank">Download your settings (JSON file)</a>
|
||||
</div>
|
||||
<br/><br/>
|
||||
<form method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
|
||||
<input type="file" name="update"><input type="submit" value="Update">
|
||||
</form>
|
||||
</div>
|
||||
<br/><br/>
|
||||
<form method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
|
||||
<input type="file" name="update"><input type="submit" value="Update">
|
||||
</form>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="left">© 2022</p>
|
||||
<p class="left"><a href="/">Home</a></p>
|
||||
<p class="right" id="version"></p>
|
||||
<div class="left">
|
||||
AhoyDTU © 2022
|
||||
<ul>
|
||||
<li><a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||
<li><a href="https://github.com/lumapu/ahoy" target="_blank">Github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="version"></span><br/><br/>
|
||||
<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de" target="_blank" >CC BY-NC-SA 3.0</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
function parseSys(obj) {
|
||||
document.getElementById("version").innerHTML = "Git SHA: " + obj["build"] + " :: " + obj["version"];
|
||||
parseVersion(obj);
|
||||
}
|
||||
|
||||
getAjax("/api/system", parseSys);
|
||||
function parse(obj) {
|
||||
if(null != obj) {
|
||||
parseMenu(obj["menu"]);
|
||||
parseSys(obj["system"]);
|
||||
}
|
||||
}
|
||||
|
||||
getAjax("/api/index", parse);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -8,20 +8,40 @@
|
|||
<script type="text/javascript" src="api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AHOY</h1>
|
||||
<div id="content" class="content">
|
||||
<div id="live"></div>
|
||||
<p>Every <span id="refresh"></span> seconds the values are updated</p>
|
||||
<div class="topnav">
|
||||
<a href="/" class="title">AhoyDTU</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="topnav()">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</a>
|
||||
<div id="topnav" class="hide"></div>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<div id="content">
|
||||
<div id="live"></div>
|
||||
<p>Every <span id="refresh"></span> seconds the values are updated</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="left">© 2022</p>
|
||||
<p class="left"><a href="/">Home</a></p>
|
||||
<p class="right" id="version"></p>
|
||||
<div class="left">
|
||||
AhoyDTU © 2022
|
||||
<ul>
|
||||
<li><a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||
<li><a href="https://github.com/lumapu/ahoy" target="_blank">Github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span id="version"></span><br/><br/>
|
||||
<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/de" target="_blank" >CC BY-NC-SA 3.0</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var intervalSet = false;
|
||||
var exeOnce = true;
|
||||
|
||||
function parseSys(obj) {
|
||||
document.getElementById("version").innerHTML = "Git SHA: " + obj["build"] + " :: " + obj["version"];
|
||||
if(true == exeOnce)
|
||||
parseVersion(obj);
|
||||
}
|
||||
|
||||
function parseIv(obj, root) {
|
||||
|
@ -108,12 +128,14 @@
|
|||
|
||||
function parse(obj) {
|
||||
if(null != obj) {
|
||||
if(true == exeOnce)
|
||||
parseMenu(obj["menu"]);
|
||||
parseSys(obj["system"]);
|
||||
parseIv(obj["inverter"], obj);
|
||||
document.getElementById("refresh").innerHTML = obj["refresh_interval"];
|
||||
if(false == intervalSet) {
|
||||
if(true == exeOnce) {
|
||||
window.setInterval("getAjax('/api/live', parse)", obj["refresh_interval"] * 1000);
|
||||
intervalSet = true;
|
||||
exeOnce = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -25,6 +25,9 @@ class mqtt {
|
|||
mClient = new PubSubClient(mEspClient);
|
||||
mAddressSet = false;
|
||||
|
||||
mLastReconnect = 0;
|
||||
mTxCnt = 0;
|
||||
|
||||
memset(mDevName, 0, DEVNAME_LEN);
|
||||
}
|
||||
|
||||
|
@ -50,6 +53,7 @@ class mqtt {
|
|||
char top[64];
|
||||
snprintf(top, 64, "%s/%s", mCfg->topic, topic);
|
||||
sendMsg2(top, msg, false);
|
||||
mTxCnt++;
|
||||
}
|
||||
|
||||
void sendMsg2(const char *topic, const char *msg, boolean retained) {
|
||||
|
@ -75,6 +79,10 @@ class mqtt {
|
|||
mClient->loop();
|
||||
}
|
||||
|
||||
uint32_t getTxCnt(void) {
|
||||
return mTxCnt;
|
||||
}
|
||||
|
||||
private:
|
||||
void reconnect(void) {
|
||||
DPRINTLN(DBG_DEBUG, F("mqtt.h:reconnect"));
|
||||
|
@ -85,8 +93,8 @@ class mqtt {
|
|||
#endif
|
||||
|
||||
boolean resub = false;
|
||||
if(!mClient->connected() && (millis() - lastReconnect) > MQTT_RECONNECT_DELAY ) {
|
||||
lastReconnect = millis();
|
||||
if(!mClient->connected() && (millis() - mLastReconnect) > MQTT_RECONNECT_DELAY ) {
|
||||
mLastReconnect = millis();
|
||||
if(strlen(mDevName) > 0) {
|
||||
// der Server und der Port müssen neu gesetzt werden,
|
||||
// da ein MQTT_CONNECTION_LOST -3 die Werte zerstört hat.
|
||||
|
@ -118,7 +126,8 @@ class mqtt {
|
|||
bool mAddressSet;
|
||||
mqttConfig_t *mCfg;
|
||||
char mDevName[DEVNAME_LEN];
|
||||
unsigned long lastReconnect = 0;
|
||||
uint32_t mLastReconnect;
|
||||
uint32_t mTxCnt;
|
||||
};
|
||||
|
||||
#endif /*__MQTT_H_*/
|
||||
|
|
|
@ -21,7 +21,7 @@ def get_firmware_specifier_build_flag():
|
|||
except:
|
||||
build_version = "g0000000"
|
||||
|
||||
build_flag = "-D AUTO_GIT_HASH=\\\"" + build_version + "\\\""
|
||||
build_flag = "-D AUTO_GIT_HASH=\\\"" + build_version[1:] + "\\\""
|
||||
print ("Firmware Revision: " + build_version)
|
||||
return (build_flag)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "html/h/visualization_html.h"
|
||||
#include "html/h/update_html.h"
|
||||
#include "html/h/serial_html.h"
|
||||
#include "html/h/system_html.h"
|
||||
|
||||
const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq"};
|
||||
|
||||
|
@ -51,6 +52,7 @@ void web::setup(void) {
|
|||
mWeb->on("/favicon.ico", HTTP_GET, std::bind(&web::onFavicon, this, std::placeholders::_1));
|
||||
mWeb->onNotFound ( std::bind(&web::showNotFound, this, std::placeholders::_1));
|
||||
mWeb->on("/reboot", HTTP_ANY, std::bind(&web::onReboot, this, std::placeholders::_1));
|
||||
mWeb->on("/system", HTTP_ANY, std::bind(&web::onSystem, this, std::placeholders::_1));
|
||||
mWeb->on("/erase", HTTP_ANY, std::bind(&web::showErase, this, std::placeholders::_1));
|
||||
mWeb->on("/factory", HTTP_ANY, std::bind(&web::showFactoryRst, this, std::placeholders::_1));
|
||||
|
||||
|
@ -160,8 +162,18 @@ void web::showNotFound(AsyncWebServerRequest *request) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void web::onReboot(AsyncWebServerRequest *request) {
|
||||
request->send(200, F("text/html"), F("<!doctype html><html><head><title>Rebooting ...</title><meta http-equiv=\"refresh\" content=\"10; URL=/\"></head><body>rebooting ... auto reload after 10s</body></html>"));
|
||||
mMain->mShouldReboot = true;
|
||||
request->send(200, F("text/html"), F("<!doctype html><html><head><title>Reboot</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta http-equiv=\"refresh\" content=\"10; URL=/\"></head><body>reboot. Autoreload after 10 seconds</body></html>"));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void web::onSystem(AsyncWebServerRequest *request) {
|
||||
DPRINTLN(DBG_VERBOSE, F("onSystem"));
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html"), system_html, system_html_len);
|
||||
response->addHeader(F("Content-Encoding"), "gzip");
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ class web {
|
|||
|
||||
private:
|
||||
void onSerial(AsyncWebServerRequest *request);
|
||||
void onSystem(AsyncWebServerRequest *request);
|
||||
|
||||
AsyncWebServer *mWeb;
|
||||
AsyncEventSource *mEvts;
|
||||
|
|
|
@ -48,6 +48,7 @@ void webApi::onApi(AsyncWebServerRequest *request) {
|
|||
if(path == "system") getSystem(root);
|
||||
else if(path == "statistics") getStatistics(root);
|
||||
else if(path == "inverter/list") getInverterList(root);
|
||||
else if(path == "menu") getMenu(root);
|
||||
else if(path == "index") getIndex(root);
|
||||
else if(path == "setup") getSetup(root);
|
||||
else if(path == "setup/networks") getNetworks(root);
|
||||
|
@ -241,8 +242,29 @@ void webApi::getSerial(JsonObject obj) {
|
|||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getMenu(JsonObject obj) {
|
||||
obj["name"][0] = "Live";
|
||||
obj["link"][0] = "/live";
|
||||
obj["name"][1] = "Serial Console";
|
||||
obj["link"][1] = "/serial";
|
||||
obj["name"][2] = "Settings";
|
||||
obj["link"][2] = "/setup";
|
||||
obj["name"][3] = "-";
|
||||
obj["name"][4] = "REST API";
|
||||
obj["link"][4] = "/api";
|
||||
obj["trgt"][4] = "_blank";
|
||||
obj["name"][5] = "-";
|
||||
obj["name"][6] = "Update";
|
||||
obj["link"][6] = "/update";
|
||||
obj["name"][7] = "System";
|
||||
obj["link"][7] = "/system";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getIndex(JsonObject obj) {
|
||||
getMenu(obj.createNestedObject(F("menu")));
|
||||
getSystem(obj.createNestedObject(F("system")));
|
||||
getStatistics(obj.createNestedObject(F("statistics")));
|
||||
obj["refresh_interval"] = SEND_INTERVAL;
|
||||
|
@ -275,12 +297,13 @@ void webApi::getIndex(JsonObject obj) {
|
|||
if(!mApp->getSettingsValid())
|
||||
info.add(F("your settings are invalid"));
|
||||
if(mApp->mqttIsConnected())
|
||||
info.add(F("MQTT is connected"));
|
||||
info.add(F("MQTT is connected, ") + String(mApp->getMqttTxCnt()) + F(" packets sent"));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getSetup(JsonObject obj) {
|
||||
getMenu(obj.createNestedObject(F("menu")));
|
||||
getSystem(obj.createNestedObject(F("system")));
|
||||
getInverterList(obj.createNestedObject(F("inverter")));
|
||||
getMqtt(obj.createNestedObject(F("mqtt")));
|
||||
|
@ -300,6 +323,7 @@ void webApi::getNetworks(JsonObject obj) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getLive(JsonObject obj) {
|
||||
getMenu(obj.createNestedObject(F("menu")));
|
||||
getSystem(obj.createNestedObject(F("system")));
|
||||
JsonArray invArr = obj.createNestedArray(F("inverter"));
|
||||
obj["refresh_interval"] = SEND_INTERVAL;
|
||||
|
@ -435,7 +459,9 @@ bool webApi::setCtrl(DynamicJsonDocument jsonIn, JsonObject jsonOut) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool webApi::setSetup(DynamicJsonDocument jsonIn, JsonObject jsonOut) {
|
||||
if(F("set_time") == jsonIn[F("cmd")])
|
||||
if(F("scan_wifi"))
|
||||
mApp->scanAvailNetworks();
|
||||
else if(F("set_time") == jsonIn[F("cmd")])
|
||||
mApp->setTimestamp(jsonIn[F("ts")]);
|
||||
else if(F("sync_ntp") == jsonIn[F("cmd")])
|
||||
mApp->setTimestamp(0); // 0: update ntp flag
|
||||
|
|
|
@ -42,6 +42,7 @@ class webApi {
|
|||
void getRadio(JsonObject obj);
|
||||
void getSerial(JsonObject obj);
|
||||
|
||||
void getMenu(JsonObject obj);
|
||||
void getIndex(JsonObject obj);
|
||||
void getSetup(JsonObject obj);
|
||||
void getNetworks(JsonObject obj);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue