mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-11 18:54:28 +05:00
Compare commits
76 Commits
1.4.0-rc.1
...
1.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b631b496cb | ||
|
|
36328a1db5 | ||
|
|
a28c7f67b5 | ||
|
|
bb9b6a5f4c | ||
|
|
ce7bd7e23b | ||
|
|
249d32ce35 | ||
|
|
baf8adfb02 | ||
|
|
018a1c5188 | ||
|
|
b600c130f0 | ||
|
|
59eb05726a | ||
|
|
f245f37dfd | ||
|
|
a825412f37 | ||
|
|
935f8bd0a8 | ||
|
|
f78d2f38b8 | ||
|
|
ef083991e3 | ||
|
|
3c0f846335 | ||
|
|
85011ce4ea | ||
|
|
8687e122ca | ||
|
|
d35ea81080 | ||
|
|
cca8ec58b4 | ||
|
|
301b14bbd4 | ||
|
|
41ce9b268e | ||
|
|
646939179e | ||
|
|
73dddd18f0 | ||
|
|
f069de0415 | ||
|
|
f4a4afeb29 | ||
|
|
f9824337dc | ||
|
|
1cd8c6a336 | ||
|
|
63228baebd | ||
|
|
6bb261dfd7 | ||
|
|
a026a962f0 | ||
|
|
db2faad741 | ||
|
|
fbc43dc535 | ||
|
|
31dfc21d69 | ||
|
|
96289cb0f7 | ||
|
|
73da3ee07a | ||
|
|
a14281924f | ||
|
|
3dec390cce | ||
|
|
9a29819d4f | ||
|
|
2af159d566 | ||
|
|
92ca257d32 | ||
|
|
44b6620431 | ||
|
|
b89f61ed58 | ||
|
|
ab1566bd45 | ||
|
|
86734ab622 | ||
|
|
0a8dd2a076 | ||
|
|
a7a561622e | ||
|
|
b0e0f6fd7d | ||
|
|
53eaa1d7f1 | ||
|
|
a7d796e0cc | ||
|
|
4490b38130 | ||
|
|
0ede2240a2 | ||
|
|
0cff35ee12 | ||
|
|
14aef20234 | ||
|
|
560f8fbd51 | ||
|
|
946414ad31 | ||
|
|
39a29042e1 | ||
|
|
f544f01caa | ||
|
|
41cca76bfa | ||
|
|
942bc53043 | ||
|
|
1bad689b6b | ||
|
|
2f4dbcc205 | ||
|
|
9e3ef7a465 | ||
|
|
a5f6749101 | ||
|
|
b07dd46f55 | ||
|
|
07ab121788 | ||
|
|
7cbc52a8b0 | ||
|
|
e090be380c | ||
|
|
0bf49d2249 | ||
|
|
a83d94d361 | ||
|
|
358980da4c | ||
|
|
f91e39d067 | ||
|
|
1d53f21d46 | ||
|
|
c225e7c2a8 | ||
|
|
6831c4331f | ||
|
|
8fb62ce8ae |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.pio
|
.pio
|
||||||
.vscode
|
.vscode
|
||||||
build/*.bin
|
build/*.bin
|
||||||
|
data/**/*.gz
|
||||||
secrets.ini
|
secrets.ini
|
||||||
!.gitkeep
|
!.gitkeep
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||

|

|
||||||
<br>
|
<br>
|
||||||
[](https://github.com/Laxilef/OTGateway/releases)
|
[](https://github.com/Laxilef/OTGateway/releases)
|
||||||
[](https://github.com/Laxilef/OTGateway/releases/latest)
|
[](https://github.com/Laxilef/OTGateway/releases/latest)
|
||||||
[](LICENSE.txt)
|
[](LICENSE.txt)
|
||||||
[](https://t.me/otgateway)
|
[](https://t.me/otgateway)
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
- PID
|
- PID
|
||||||
- Equithermic curves - adjusts the temperature based on indoor and outdoor temperatures
|
- Equithermic curves - adjusts the temperature based on indoor and outdoor temperatures
|
||||||
- Hysteresis setting (for accurate maintenance of room temperature)
|
- Hysteresis setting (for accurate maintenance of room temperature)
|
||||||
- Ability to connect an external sensors to monitor outdoor and indoor temperature ([compatible sensors](#compatible-temperature-sensors))
|
- Ability to connect an external sensors to monitor outdoor and indoor temperature ([compatible sensors](https://github.com/Laxilef/OTGateway/wiki/Compatibility#temperature-sensors))
|
||||||
- Emergency mode. If the Wi-Fi connection is lost or the gateway cannot connect to the MQTT server, the mode will turn on. This mode will automatically maintain the set temperature and prevent your home from freezing. In this mode it is also possible to use equithermal curves (weather-compensated control).
|
- Emergency mode. If the Wi-Fi connection is lost or the gateway cannot connect to the MQTT server, the mode will turn on. This mode will automatically maintain the set temperature and prevent your home from freezing. In this mode it is also possible to use equithermal curves (weather-compensated control).
|
||||||
- Automatic error reset (not with all boilers)
|
- Automatic error reset (not with all boilers)
|
||||||
- Diagnostics:
|
- Diagnostics:
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
- The current temperature of the heat carrier (usually the return heat carrier)
|
- The current temperature of the heat carrier (usually the return heat carrier)
|
||||||
- Set heat carrier temperature (depending on the selected mode)
|
- Set heat carrier temperature (depending on the selected mode)
|
||||||
- Current hot water temperature
|
- Current hot water temperature
|
||||||
- Auto tuning of PID and Equitherm parameters *(in development)*
|
|
||||||
- [Home Assistant](https://www.home-assistant.io/) integration via MQTT. The ability to create any automation for the boiler!
|
- [Home Assistant](https://www.home-assistant.io/) integration via MQTT. The ability to create any automation for the boiler!
|
||||||
|
|
||||||

|

|
||||||
@@ -72,7 +71,7 @@ All available information and instructions can be found in the wiki:
|
|||||||
- [ESP32Scheduler](https://github.com/laxilef/ESP32Scheduler) (for ESP32)
|
- [ESP32Scheduler](https://github.com/laxilef/ESP32Scheduler) (for ESP32)
|
||||||
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
|
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
|
||||||
- [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library)
|
- [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library)
|
||||||
- [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient) /
|
- [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient)
|
||||||
- [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet)
|
- [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet)
|
||||||
- [FileData](https://github.com/GyverLibs/FileData)
|
- [FileData](https://github.com/GyverLibs/FileData)
|
||||||
- [GyverPID](https://github.com/GyverLibs/GyverPID)
|
- [GyverPID](https://github.com/GyverLibs/GyverPID)
|
||||||
|
|||||||
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
230
data/index.html
230
data/index.html
@@ -1,230 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>OpenTherm Gateway</title>
|
|
||||||
<link rel="stylesheet" href="/static/pico.min.css">
|
|
||||||
<link rel="stylesheet" href="/static/app.css"/>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header class="container">
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<li><a href="/"><div class="logo">OpenTherm Gateway</div></a></li>
|
|
||||||
</ul>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/Laxilef/OTGateway/wiki" role="button" class="secondary" target="_blank">Help</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main class="container">
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>Network</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div class="main-busy" aria-busy="true"></div>
|
|
||||||
<table class="main-table hidden">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Hostname:</th>
|
|
||||||
<td><b class="network-hostname"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">MAC:</th>
|
|
||||||
<td><b class="network-mac"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Connected:</th>
|
|
||||||
<td><input type="radio" class="network-connected" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">SSID:</th>
|
|
||||||
<td><b class="network-ssid"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Signal:</th>
|
|
||||||
<td><b class="network-signal"></b> %</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">IP:</th>
|
|
||||||
<td><b class="network-ip"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Subnet:</th>
|
|
||||||
<td><b class="network-subnet"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Gateway:</th>
|
|
||||||
<td><b class="network-gateway"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">DNS:</th>
|
|
||||||
<td><b class="network-dns"></b></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="grid">
|
|
||||||
<a href="/network.html" role="button">Network settings</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>System</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div class="system-busy" aria-busy="true"></div>
|
|
||||||
<table class="system-table hidden">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Version:</th>
|
|
||||||
<td><b class="version"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Build date:</th>
|
|
||||||
<td><b class="build-date"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Uptime:</th>
|
|
||||||
<td><b class="uptime-days"></b> days, <b class="uptime-hours"></b> hours, <b class="uptime-min"></b> min., <b class="uptime-sec"></b> sec.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Free memory:</th>
|
|
||||||
<td><b class="free-heap"></b> of <b class="total-heap"></b> bytes (min: <b class="min-free-heap"></b> bytes)<br>max free block: <b class="max-free-block-heap"></b> bytes (min: <b class="min-max-free-block-heap"></b> bytes)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Last reset reason:</th>
|
|
||||||
<td><b class="reset-reason"></b></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<a href="/settings.html" role="button">Settings</a>
|
|
||||||
<a href="/upgrade.html" role="button">Upgrade</a>
|
|
||||||
<a href="/restart.html" role="button" class="secondary restart">Restart</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>States and sensors</h2>
|
|
||||||
<p>More information and settings can be found in your home assistant after setting up network and MQTT</p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div class="ot-busy" aria-busy="true"></div>
|
|
||||||
<table class="ot-table hidden">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">OpenTherm connected:</th>
|
|
||||||
<td><input type="radio" class="ot-connected" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">MQTT connected:</th>
|
|
||||||
<td><input type="radio" class="mqtt-connected" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Emergency:</th>
|
|
||||||
<td><input type="radio" class="ot-emergency" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Heating:</th>
|
|
||||||
<td><input type="radio" class="ot-heating" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">DHW:</th>
|
|
||||||
<td><input type="radio" class="ot-dhw" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Flame:</th>
|
|
||||||
<td><input type="radio" class="ot-flame" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Fault:</th>
|
|
||||||
<td><input type="radio" class="ot-fault" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Diagnostic:</th>
|
|
||||||
<td><input type="radio" class="ot-diagnostic" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">External pump:</th>
|
|
||||||
<td><input type="radio" class="ot-external-pump" aria-invalid="false" checked disabled /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Modulation:</th>
|
|
||||||
<td><b class="ot-modulation"></b> %</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Pressure:</th>
|
|
||||||
<td><b class="ot-pressure"></b> bar</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">DHW flow rate:</th>
|
|
||||||
<td><b class="ot-dhw-flow-rate"></b> l/min</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Fault code:</th>
|
|
||||||
<td><b class="ot-fault-code"></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Indoor temp:</th>
|
|
||||||
<td><b class="indoor-temp"></b> C</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Outdoor temp:</th>
|
|
||||||
<td><b class="outdoor-temp"></b> C</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Heating temp:</th>
|
|
||||||
<td><b class="heating-temp"></b> C</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Heating setpoint temp:</th>
|
|
||||||
<td><b class="heating-setpoint-temp"></b> C</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">DHW temp:</th>
|
|
||||||
<td><b class="dhw-temp"></b> C</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="container">
|
|
||||||
<small>
|
|
||||||
<b>Made by Laxilef</b>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
|
||||||
</small>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="/static/app.js"></script>
|
|
||||||
<script>
|
|
||||||
window.onload = async function () {
|
|
||||||
setTimeout(async function onLoadPage() {
|
|
||||||
await loadNetworkStatus();
|
|
||||||
await loadVars();
|
|
||||||
|
|
||||||
setTimeout(onLoadPage, 10000);
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,357 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Settings - OpenTherm Gateway</title>
|
|
||||||
<link rel="stylesheet" href="/static/pico.min.css">
|
|
||||||
<link rel="stylesheet" href="/static/app.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header class="container">
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<li><a href="/"><div class="logo">OpenTherm Gateway</div></a></li>
|
|
||||||
</ul>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/Laxilef/OTGateway/wiki" role="button" class="secondary" target="_blank">Help</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main class="container">
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>Portal settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="portal-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="portal-settings" class="hidden">
|
|
||||||
<div class="grid">
|
|
||||||
<label for="portal-login">
|
|
||||||
Login
|
|
||||||
<input type="text" class="portal-login" name="portal[login]" maxlength="12" required>
|
|
||||||
</label>
|
|
||||||
<label for="portal-password">
|
|
||||||
Password
|
|
||||||
<input type="password" class="portal-password" name="portal[password]" maxlength="32" required>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="portal-use-auth">
|
|
||||||
<input type="checkbox" class="portal-use-auth" name="portal[useAuth]" value="true">
|
|
||||||
Use auth
|
|
||||||
</label>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>OpenTherm settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="opentherm-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="opentherm-settings" class="hidden">
|
|
||||||
<div class="grid">
|
|
||||||
<label for="opentherm-in-pin">
|
|
||||||
In GPIO
|
|
||||||
<input type="number" inputmode="numeric" class="opentherm-in-pin" name="opentherm[inPin]" min="0" max="99" step="1" required>
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-in-pin">
|
|
||||||
Out GPIO
|
|
||||||
<input type="number" inputmode="numeric" class="opentherm-out-pin" name="opentherm[outPin]" min="0" max="99" step="1" required>
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-member-id-code">
|
|
||||||
Master MemberID code
|
|
||||||
<input type="number" inputmode="numeric" class="opentherm-member-id-code" name="opentherm[memberIdCode]" min="0" max="65535" step="1" required>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<mark>After changing GPIO, the ESP must be restarted for the changes to take effect.</mark>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Options</legend>
|
|
||||||
<label for="opentherm-dhw-present">
|
|
||||||
<input type="checkbox" class="opentherm-dhw-present" name="opentherm[dhwPresent]" value="true">
|
|
||||||
DHW present
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-sw-mode">
|
|
||||||
<input type="checkbox" class="opentherm-sw-mode" name="opentherm[summerWinterMode]" value="true">
|
|
||||||
Summer/winter mode
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-heating-ch2-enabled">
|
|
||||||
<input type="checkbox" class="opentherm-heating-ch2-enabled" name="opentherm[heatingCh2Enabled]" value="true">
|
|
||||||
Heating CH2 always enabled
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-heating-ch1-to-ch2">
|
|
||||||
<input type="checkbox" class="opentherm-heating-ch1-to-ch2" name="opentherm[heatingCh1ToCh2]" value="true">
|
|
||||||
Duplicate heating CH1 to CH2
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-dhw-to-ch2">
|
|
||||||
<input type="checkbox" class="opentherm-dhw-to-ch2" name="opentherm[dhwToCh2]" value="true">
|
|
||||||
Duplicate DHW to CH2
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-dhw-blocking">
|
|
||||||
<input type="checkbox" class="opentherm-dhw-blocking" name="opentherm[dhwBlocking]" value="true">
|
|
||||||
DHW blocking
|
|
||||||
</label>
|
|
||||||
<label for="opentherm-sync-modulation-with-heating">
|
|
||||||
<input type="checkbox" class="opentherm-sync-modulation-with-heating" name="opentherm[modulationSyncWithHeating]" value="true">
|
|
||||||
Sync modulation with heating
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>MQTT settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="mqtt-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="mqtt-settings" class="hidden">
|
|
||||||
<div class="grid">
|
|
||||||
<label for="mqtt-server">
|
|
||||||
Server
|
|
||||||
<input type="text" class="mqtt-server" name="mqtt[server]" maxlength="80" required>
|
|
||||||
</label>
|
|
||||||
<label for="mqtt-port">
|
|
||||||
Port
|
|
||||||
<input type="number" inputmode="numeric" class="mqtt-port" name="mqtt[port]" min="1" max="65535" step="1" required>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<label for="mqtt-user">
|
|
||||||
User
|
|
||||||
<input type="text" class="mqtt-user" name="mqtt[user]" maxlength="32" required>
|
|
||||||
</label>
|
|
||||||
<label for="mqtt-password">
|
|
||||||
Password
|
|
||||||
<input type="password" class="mqtt-password" name="mqtt[password]" maxlength="32">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<label for="mqtt-prefix">
|
|
||||||
Prefix
|
|
||||||
<input type="text" class="mqtt-prefix" name="mqtt[prefix]" maxlength="32" required>
|
|
||||||
</label>
|
|
||||||
<label for="mqtt-interval">
|
|
||||||
Publish interval <small>(sec)</small>
|
|
||||||
<input type="number" inputmode="numeric" class="mqtt-interval" name="mqtt[interval]" min="3" max="60" step="1" required>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>Outdoor sensor settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="outdoor-sensor-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="outdoor-sensor-settings" class="hidden">
|
|
||||||
<fieldset>
|
|
||||||
<legend>Source type</legend>
|
|
||||||
<label>
|
|
||||||
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="0" />
|
|
||||||
From boiler via OpenTherm
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="1" />
|
|
||||||
Manual via MQTT/API
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="2" />
|
|
||||||
External (DS18B20)
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<label for="outdoor-sensor-pin">
|
|
||||||
GPIO
|
|
||||||
<input type="number" inputmode="numeric" class="outdoor-sensor-pin" name="sensors[outdoor][pin]" min="0" max="99" step="1" required>
|
|
||||||
</label>
|
|
||||||
<label for="outdoor-sensor-offset">
|
|
||||||
Temp offset (calibration)
|
|
||||||
<input type="number" inputmode="numeric" class="outdoor-sensor-offset" name="sensors[outdoor][offset]" min="-20" max="20" step="0.01" required>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>Indoor sensor settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="indoor-sensor-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="indoor-sensor-settings" class="hidden">
|
|
||||||
<fieldset>
|
|
||||||
<legend>Source type</legend>
|
|
||||||
<label>
|
|
||||||
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="1" />
|
|
||||||
Manual via MQTT/API
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="2" />
|
|
||||||
External (DS18B20)
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="3" />
|
|
||||||
BLE device <i>(ONLY for some ESP32 which support BLE)</i>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<label for="indoor-sensor-pin">
|
|
||||||
GPIO
|
|
||||||
<input type="number" inputmode="numeric" class="indoor-sensor-pin" name="sensors[indoor][pin]" min="0" max="99" step="1" required>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<label for="indoor-sensor-offset">
|
|
||||||
Temp offset (calibration)
|
|
||||||
<input type="number" inputmode="numeric" class="indoor-sensor-offset" name="sensors[indoor][offset]" min="-20" max="20" step="0.01" required>
|
|
||||||
</label>
|
|
||||||
<label for="indoor-sensor-ble-addresss">
|
|
||||||
BLE addresss
|
|
||||||
<input type="text" class="indoor-sensor-ble-addresss" name="sensors[indoor][bleAddresss]" pattern="([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}">
|
|
||||||
<small>ONLY for some ESP32 which support BLE</small>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>External pump settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="extpump-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="extpump-settings" class="hidden">
|
|
||||||
<label for="extpump-use">
|
|
||||||
<input type="checkbox" class="extpump-use" name="externalPump[use]" value="true">
|
|
||||||
Use external pump
|
|
||||||
</label>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<label for="extpump-pin">
|
|
||||||
Relay GPIO
|
|
||||||
<input type="number" inputmode="numeric" class="extpump-pin" name="externalPump[pin]" min="0" max="99" step="1" required>
|
|
||||||
</label>
|
|
||||||
<label for="extpump-pc-time">
|
|
||||||
Post circulation time <small>(min)</small>
|
|
||||||
<input type="number" inputmode="numeric" class="extpump-pc-time" name="externalPump[postCirculationTime]" min="1" max="120" step="1" required>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<label for="extpump-as-interval">
|
|
||||||
Anti stuck interval <small>(days)</small>
|
|
||||||
<input type="number" inputmode="numeric" class="extpump-as-interval" name="externalPump[antiStuckInterval]" min="1" max="366" step="1" required>
|
|
||||||
</label>
|
|
||||||
<label for="extpump-as-time">
|
|
||||||
Anti stuck time <small>(min)</small>
|
|
||||||
<input type="number" inputmode="numeric" class="extpump-as-time" name="externalPump[antiStuckTime]" min="1" max="20" step="1" required>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div>
|
|
||||||
<hgroup>
|
|
||||||
<h2>System settings</h2>
|
|
||||||
<p></p>
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
<div id="system-settings-busy" aria-busy="true"></div>
|
|
||||||
<form action="/api/settings" id="system-settings" class="hidden">
|
|
||||||
<fieldset>
|
|
||||||
<label for="system-debug">
|
|
||||||
<input type="checkbox" class="system-debug" name="system[debug]" value="true">
|
|
||||||
Debug mode
|
|
||||||
</label>
|
|
||||||
<label for="system-use-serial">
|
|
||||||
<input type="checkbox" class="system-use-serial" name="system[useSerial]" value="true">
|
|
||||||
Enable serial port
|
|
||||||
</label>
|
|
||||||
<label for="system-use-telnet">
|
|
||||||
<input type="checkbox" class="system-use-telnet" name="system[useTelnet]" value="true">
|
|
||||||
Enable telnet
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<mark>After changing this settings, the ESP must be restarted for the changes to take effect.</mark>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="container">
|
|
||||||
<small>
|
|
||||||
<b>Made by Laxilef</b>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
|
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
|
||||||
</small>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="/static/app.js"></script>
|
|
||||||
<script>
|
|
||||||
window.onload = async function () {
|
|
||||||
await loadSettings();
|
|
||||||
|
|
||||||
setupForm('#portal-settings');
|
|
||||||
setupForm('#opentherm-settings');
|
|
||||||
setupForm('#mqtt-settings');
|
|
||||||
setupForm('#outdoor-sensor-settings');
|
|
||||||
setupForm('#indoor-sensor-settings');
|
|
||||||
setupForm('#extpump-settings');
|
|
||||||
setupForm('#system-settings');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
0
data/static/.gitkeep
Normal file
0
data/static/.gitkeep
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -8,6 +8,7 @@ public:
|
|||||||
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
|
typedef std::function<void(unsigned long, unsigned long, OpenThermResponseStatus, byte)> AfterSendRequestCallback;
|
||||||
|
|
||||||
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
|
CustomOpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false) : OpenTherm(inPin, outPin, isSlave) {}
|
||||||
|
~CustomOpenTherm() {}
|
||||||
|
|
||||||
CustomOpenTherm* setYieldCallback(YieldCallback callback = nullptr) {
|
CustomOpenTherm* setYieldCallback(YieldCallback callback = nullptr) {
|
||||||
this->yieldCallback = callback;
|
this->yieldCallback = callback;
|
||||||
@@ -46,7 +47,7 @@ public:
|
|||||||
|
|
||||||
unsigned long _response;
|
unsigned long _response;
|
||||||
OpenThermResponseStatus _responseStatus = OpenThermResponseStatus::NONE;
|
OpenThermResponseStatus _responseStatus = OpenThermResponseStatus::NONE;
|
||||||
if (!this->sendRequestAync(request)) {
|
if (!this->sendRequestAsync(request)) {
|
||||||
_response = 0;
|
_response = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -88,7 +89,7 @@ public:
|
|||||||
| (dhwBlocking << 6);
|
| (dhwBlocking << 6);
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
|
|
||||||
return this->sendRequest(this->buildRequest(
|
return this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::READ_DATA,
|
OpenThermMessageType::READ_DATA,
|
||||||
OpenThermMessageID::Status,
|
OpenThermMessageID::Status,
|
||||||
data
|
data
|
||||||
@@ -96,30 +97,60 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool setHeatingCh1Temp(float temperature) {
|
bool setHeatingCh1Temp(float temperature) {
|
||||||
unsigned long response = this->sendRequest(this->buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::TSet,
|
OpenThermMessageID::TSet,
|
||||||
this->temperatureToData(temperature)
|
temperatureToData(temperature)
|
||||||
));
|
));
|
||||||
|
|
||||||
return isValidResponse(response);
|
return isValidResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setHeatingCh2Temp(float temperature) {
|
bool setHeatingCh2Temp(float temperature) {
|
||||||
unsigned long response = this->sendRequest(this->buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::TsetCH2,
|
OpenThermMessageID::TsetCH2,
|
||||||
this->temperatureToData(temperature)
|
temperatureToData(temperature)
|
||||||
));
|
));
|
||||||
|
|
||||||
return isValidResponse(response);
|
return isValidResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setDhwTemp(float temperature) {
|
bool setDhwTemp(float temperature) {
|
||||||
unsigned long response = this->sendRequest(this->buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::TdhwSet,
|
OpenThermMessageID::TdhwSet,
|
||||||
this->temperatureToData(temperature)
|
temperatureToData(temperature)
|
||||||
|
));
|
||||||
|
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setRoomSetpoint(float temperature) {
|
||||||
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::TrSet,
|
||||||
|
temperatureToData(temperature)
|
||||||
|
));
|
||||||
|
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setRoomSetpointCh2(float temperature) {
|
||||||
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::TrSetCH2,
|
||||||
|
temperatureToData(temperature)
|
||||||
|
));
|
||||||
|
|
||||||
|
return isValidResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setRoomTemp(float temperature) {
|
||||||
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
|
OpenThermMessageType::WRITE_DATA,
|
||||||
|
OpenThermMessageID::Tr,
|
||||||
|
temperatureToData(temperature)
|
||||||
));
|
));
|
||||||
|
|
||||||
return isValidResponse(response);
|
return isValidResponse(response);
|
||||||
@@ -128,9 +159,9 @@ public:
|
|||||||
bool sendBoilerReset() {
|
bool sendBoilerReset() {
|
||||||
unsigned int data = 1;
|
unsigned int data = 1;
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
unsigned long response = this->sendRequest(this->buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::Command,
|
OpenThermMessageID::RemoteRequest,
|
||||||
data
|
data
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -140,9 +171,9 @@ public:
|
|||||||
bool sendServiceReset() {
|
bool sendServiceReset() {
|
||||||
unsigned int data = 10;
|
unsigned int data = 10;
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
unsigned long response = this->sendRequest(this->buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::Command,
|
OpenThermMessageID::RemoteRequest,
|
||||||
data
|
data
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -152,9 +183,9 @@ public:
|
|||||||
bool sendWaterFilling() {
|
bool sendWaterFilling() {
|
||||||
unsigned int data = 2;
|
unsigned int data = 2;
|
||||||
data <<= 8;
|
data <<= 8;
|
||||||
unsigned long response = this->sendRequest(this->buildRequest(
|
unsigned long response = this->sendRequest(buildRequest(
|
||||||
OpenThermMessageType::WRITE_DATA,
|
OpenThermMessageType::WRITE_DATA,
|
||||||
OpenThermMessageID::Command,
|
OpenThermMessageID::RemoteRequest,
|
||||||
data
|
data
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -162,24 +193,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// converters
|
// converters
|
||||||
float fromF88(unsigned long response) {
|
template <class T>
|
||||||
const byte valueLB = response & 0xFF;
|
static unsigned int toFloat(const T val) {
|
||||||
const byte valueHB = (response >> 8) & 0xFF;
|
|
||||||
|
|
||||||
float value = (int8_t)valueHB;
|
|
||||||
return value + (float)valueLB / 256.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> unsigned int toF88(T val) {
|
|
||||||
return (unsigned int)(val * 256);
|
return (unsigned int)(val * 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t fromS16(unsigned long response) {
|
static short getInt(const unsigned long response) {
|
||||||
const byte valueLB = response & 0xFF;
|
return response & 0xffff;
|
||||||
const byte valueHB = (response >> 8) & 0xFF;
|
|
||||||
|
|
||||||
int16_t value = valueHB;
|
|
||||||
return ((value << 8) + valueLB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ const char HA_AVAILABILITY_MODE[] PROGMEM = "availability_mode";
|
|||||||
const char HA_TOPIC[] PROGMEM = "topic";
|
const char HA_TOPIC[] PROGMEM = "topic";
|
||||||
const char HA_DEVICE_CLASS[] PROGMEM = "device_class";
|
const char HA_DEVICE_CLASS[] PROGMEM = "device_class";
|
||||||
const char HA_UNIT_OF_MEASUREMENT[] PROGMEM = "unit_of_measurement";
|
const char HA_UNIT_OF_MEASUREMENT[] PROGMEM = "unit_of_measurement";
|
||||||
|
const char HA_UNIT_OF_MEASUREMENT_C[] PROGMEM = "°C";
|
||||||
|
const char HA_UNIT_OF_MEASUREMENT_F[] PROGMEM = "°F";
|
||||||
const char HA_ICON[] PROGMEM = "icon";
|
const char HA_ICON[] PROGMEM = "icon";
|
||||||
const char HA_MIN[] PROGMEM = "min";
|
const char HA_MIN[] PROGMEM = "min";
|
||||||
const char HA_MAX[] PROGMEM = "max";
|
const char HA_MAX[] PROGMEM = "max";
|
||||||
@@ -50,6 +52,7 @@ const char HA_TEMPERATURE_COMMAND_TOPIC[] PROGMEM = "temperature_command_t
|
|||||||
const char HA_TEMPERATURE_COMMAND_TEMPLATE[] PROGMEM = "temperature_command_template";
|
const char HA_TEMPERATURE_COMMAND_TEMPLATE[] PROGMEM = "temperature_command_template";
|
||||||
const char HA_TEMPERATURE_STATE_TOPIC[] PROGMEM = "temperature_state_topic";
|
const char HA_TEMPERATURE_STATE_TOPIC[] PROGMEM = "temperature_state_topic";
|
||||||
const char HA_TEMPERATURE_STATE_TEMPLATE[] PROGMEM = "temperature_state_template";
|
const char HA_TEMPERATURE_STATE_TEMPLATE[] PROGMEM = "temperature_state_template";
|
||||||
|
const char HA_TEMPERATURE_UNIT[] PROGMEM = "temperature_unit";
|
||||||
const char HA_MODE_COMMAND_TOPIC[] PROGMEM = "mode_command_topic";
|
const char HA_MODE_COMMAND_TOPIC[] PROGMEM = "mode_command_topic";
|
||||||
const char HA_MODE_COMMAND_TEMPLATE[] PROGMEM = "mode_command_template";
|
const char HA_MODE_COMMAND_TEMPLATE[] PROGMEM = "mode_command_template";
|
||||||
const char HA_MODE_STATE_TOPIC[] PROGMEM = "mode_state_topic";
|
const char HA_MODE_STATE_TOPIC[] PROGMEM = "mode_state_topic";
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
#include "NetworkConnection.h"
|
#include "NetworkConnection.h"
|
||||||
using namespace Network;
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
void Connection::setup(bool useDhcp) {
|
void NetworkConnection::setup(bool useDhcp) {
|
||||||
setUseDhcp(useDhcp);
|
setUseDhcp(useDhcp);
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
wifi_set_event_handler_cb(Connection::onEvent);
|
wifi_set_event_handler_cb(NetworkConnection::onEvent);
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
WiFi.onEvent(Connection::onEvent);
|
WiFi.onEvent(NetworkConnection::onEvent);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::reset() {
|
void NetworkConnection::reset() {
|
||||||
status = Status::NONE;
|
status = Status::NONE;
|
||||||
disconnectReason = DisconnectReason::NONE;
|
disconnectReason = DisconnectReason::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::setUseDhcp(bool value) {
|
void NetworkConnection::setUseDhcp(bool value) {
|
||||||
useDhcp = value;
|
useDhcp = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::Status Connection::getStatus() {
|
NetworkConnection::Status NetworkConnection::getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::DisconnectReason Connection::getDisconnectReason() {
|
NetworkConnection::DisconnectReason NetworkConnection::getDisconnectReason() {
|
||||||
return disconnectReason;
|
return disconnectReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
void Connection::onEvent(System_Event_t *event) {
|
void NetworkConnection::onEvent(System_Event_t *event) {
|
||||||
switch (event->event) {
|
switch (event->event) {
|
||||||
case EVENT_STAMODE_CONNECTED:
|
case EVENT_STAMODE_CONNECTED:
|
||||||
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
||||||
@@ -75,7 +75,7 @@ void Connection::onEvent(System_Event_t *event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
void Connection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
void NetworkConnection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||||
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
status = useDhcp ? Status::CONNECTING : Status::CONNECTED;
|
||||||
@@ -106,7 +106,7 @@ void Connection::onEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Connection::DisconnectReason Connection::convertDisconnectReason(uint8_t reason) {
|
NetworkConnection::DisconnectReason NetworkConnection::convertDisconnectReason(uint8_t reason) {
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
#if defined(ARDUINO_ARCH_ESP8266)
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
case REASON_BEACON_TIMEOUT:
|
case REASON_BEACON_TIMEOUT:
|
||||||
@@ -145,6 +145,6 @@ Connection::DisconnectReason Connection::convertDisconnectReason(uint8_t reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::useDhcp = false;
|
bool NetworkConnection::useDhcp = false;
|
||||||
Connection::Status Connection::status = Status::NONE;
|
NetworkConnection::Status NetworkConnection::status = Status::NONE;
|
||||||
Connection::DisconnectReason Connection::disconnectReason = DisconnectReason::NONE;
|
NetworkConnection::DisconnectReason NetworkConnection::disconnectReason = DisconnectReason::NONE;
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Network {
|
namespace NetworkUtils {
|
||||||
struct Connection {
|
struct NetworkConnection {
|
||||||
enum class Status {
|
enum class Status {
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
@@ -7,35 +7,35 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <NetworkConnection.h>
|
#include <NetworkConnection.h>
|
||||||
|
|
||||||
namespace Network {
|
namespace NetworkUtils {
|
||||||
class Manager {
|
class NetworkMgr {
|
||||||
public:
|
public:
|
||||||
typedef std::function<void()> YieldCallback;
|
typedef std::function<void()> YieldCallback;
|
||||||
typedef std::function<void(unsigned int)> DelayCallback;
|
typedef std::function<void(unsigned int)> DelayCallback;
|
||||||
|
|
||||||
Manager() {
|
NetworkMgr() {
|
||||||
Connection::setup(this->useDhcp);
|
NetworkConnection::setup(this->useDhcp);
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setYieldCallback(YieldCallback callback = nullptr) {
|
NetworkMgr* setYieldCallback(YieldCallback callback = nullptr) {
|
||||||
this->yieldCallback = callback;
|
this->yieldCallback = callback;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setDelayCallback(DelayCallback callback = nullptr) {
|
NetworkMgr* setDelayCallback(DelayCallback callback = nullptr) {
|
||||||
this->delayCallback = callback;
|
this->delayCallback = callback;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setHostname(const char* value) {
|
NetworkMgr* setHostname(const char* value) {
|
||||||
this->hostname = value;
|
this->hostname = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setApCredentials(const char* ssid, const char* password = nullptr, byte channel = 0) {
|
NetworkMgr* setApCredentials(const char* ssid, const char* password = nullptr, byte channel = 0) {
|
||||||
this->apName = ssid;
|
this->apName = ssid;
|
||||||
this->apPassword = password;
|
this->apPassword = password;
|
||||||
this->apChannel = channel;
|
this->apChannel = channel;
|
||||||
@@ -43,7 +43,7 @@ namespace Network {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setStaCredentials(const char* ssid = nullptr, const char* password = nullptr, byte channel = 0) {
|
NetworkMgr* setStaCredentials(const char* ssid = nullptr, const char* password = nullptr, byte channel = 0) {
|
||||||
this->staSsid = ssid;
|
this->staSsid = ssid;
|
||||||
this->staPassword = password;
|
this->staPassword = password;
|
||||||
this->staChannel = channel;
|
this->staChannel = channel;
|
||||||
@@ -51,14 +51,14 @@ namespace Network {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setUseDhcp(bool value) {
|
NetworkMgr* setUseDhcp(bool value) {
|
||||||
this->useDhcp = value;
|
this->useDhcp = value;
|
||||||
Connection::setup(this->useDhcp);
|
NetworkConnection::setup(this->useDhcp);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setStaticConfig(const char* ip, const char* gateway, const char* subnet, const char* dns) {
|
NetworkMgr* setStaticConfig(const char* ip, const char* gateway, const char* subnet, const char* dns) {
|
||||||
this->staticIp.fromString(ip);
|
this->staticIp.fromString(ip);
|
||||||
this->staticGateway.fromString(gateway);
|
this->staticGateway.fromString(gateway);
|
||||||
this->staticSubnet.fromString(subnet);
|
this->staticSubnet.fromString(subnet);
|
||||||
@@ -67,7 +67,7 @@ namespace Network {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager* setStaticConfig(IPAddress &ip, IPAddress &gateway, IPAddress &subnet, IPAddress &dns) {
|
NetworkMgr* setStaticConfig(IPAddress& ip, IPAddress& gateway, IPAddress& subnet, IPAddress& dns) {
|
||||||
this->staticIp = ip;
|
this->staticIp = ip;
|
||||||
this->staticGateway = gateway;
|
this->staticGateway = gateway;
|
||||||
this->staticSubnet = subnet;
|
this->staticSubnet = subnet;
|
||||||
@@ -81,11 +81,11 @@ namespace Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isConnected() {
|
bool isConnected() {
|
||||||
return this->isStaEnabled() && Connection::getStatus() == Connection::Status::CONNECTED;
|
return this->isStaEnabled() && NetworkConnection::getStatus() == NetworkConnection::Status::CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConnecting() {
|
bool isConnecting() {
|
||||||
return this->isStaEnabled() && Connection::getStatus() == Connection::Status::CONNECTING;
|
return this->isStaEnabled() && NetworkConnection::getStatus() == NetworkConnection::Status::CONNECTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStaEnabled() {
|
bool isStaEnabled() {
|
||||||
@@ -147,16 +147,19 @@ namespace Network {
|
|||||||
bool resetWifi() {
|
bool resetWifi() {
|
||||||
// set policy manual for work 13 ch
|
// set policy manual for work 13 ch
|
||||||
{
|
{
|
||||||
wifi_country_t country = {"CN", 1, 13, WIFI_COUNTRY_POLICY_MANUAL};
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
wifi_country_t country = {"CN", 1, 13, WIFI_COUNTRY_POLICY_AUTO};
|
||||||
wifi_set_country(&country);
|
wifi_set_country(&country);
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const wifi_country_t country = {"CN", 1, 13, CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER, WIFI_COUNTRY_POLICY_AUTO};
|
||||||
esp_wifi_set_country(&country);
|
esp_wifi_set_country(&country);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFi.persistent(false);
|
WiFi.persistent(false);
|
||||||
|
#if !defined(ESP_ARDUINO_VERSION_MAJOR) || ESP_ARDUINO_VERSION_MAJOR < 3
|
||||||
WiFi.setAutoConnect(false);
|
WiFi.setAutoConnect(false);
|
||||||
|
#endif
|
||||||
WiFi.setAutoReconnect(false);
|
WiFi.setAutoReconnect(false);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
@@ -180,8 +183,13 @@ namespace Network {
|
|||||||
|
|
||||||
wifi_station_dhcpc_set_maxtry(5);
|
wifi_station_dhcpc_set_maxtry(5);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && ESP_ARDUINO_VERSION_MAJOR < 3
|
||||||
|
// Nothing. Because memory leaks when turn off WiFi on ESP32 SDK < 3.0.0
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
return WiFi.mode(WIFI_OFF);
|
return WiFi.mode(WIFI_OFF);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconnect() {
|
void reconnect() {
|
||||||
@@ -195,6 +203,7 @@ namespace Network {
|
|||||||
|
|
||||||
if (force && !this->isApEnabled()) {
|
if (force && !this->isApEnabled()) {
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
|
NetworkConnection::reset();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*#ifdef ARDUINO_ARCH_ESP8266
|
/*#ifdef ARDUINO_ARCH_ESP8266
|
||||||
@@ -210,7 +219,7 @@ namespace Network {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
if (this->setWifiHostname(this->hostname)) {
|
if (this->setWifiHostname(this->hostname)) {
|
||||||
@@ -225,7 +234,7 @@ namespace Network {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
if (this->setWifiHostname(this->hostname)) {
|
if (this->setWifiHostname(this->hostname)) {
|
||||||
@@ -235,7 +244,7 @@ namespace Network {
|
|||||||
Log.serrorln(FPSTR(L_NETWORK), F("Set hostname '%s': fail"), this->hostname);
|
Log.serrorln(FPSTR(L_NETWORK), F("Set hostname '%s': fail"), this->hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!this->useDhcp) {
|
if (!this->useDhcp) {
|
||||||
@@ -248,9 +257,9 @@ namespace Network {
|
|||||||
while (millis() - beginConnectionTime < timeout) {
|
while (millis() - beginConnectionTime < timeout) {
|
||||||
this->delayCallback(100);
|
this->delayCallback(100);
|
||||||
|
|
||||||
Connection::Status status = Connection::getStatus();
|
NetworkConnection::Status status = NetworkConnection::getStatus();
|
||||||
if (status != Connection::Status::CONNECTING && status != Connection::Status::NONE) {
|
if (status != NetworkConnection::Status::CONNECTING && status != NetworkConnection::Status::NONE) {
|
||||||
return status == Connection::Status::CONNECTED;
|
return status == NetworkConnection::Status::CONNECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,13 +267,22 @@ namespace Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (this->isConnected() && !this->hasStaCredentials()) {
|
if (this->reconnectFlag) {
|
||||||
|
this->delayCallback(5000);
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_NETWORK), F("Reconnecting..."));
|
||||||
|
this->reconnectFlag = false;
|
||||||
|
this->resetWifi();
|
||||||
|
NetworkConnection::reset();
|
||||||
|
this->delayCallback(1000);
|
||||||
|
|
||||||
|
} else if (this->isConnected() && !this->hasStaCredentials()) {
|
||||||
Log.sinfoln(FPSTR(L_NETWORK), F("Reset"));
|
Log.sinfoln(FPSTR(L_NETWORK), F("Reset"));
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
Connection::reset();
|
NetworkConnection::reset();
|
||||||
this->delayCallback(200);
|
this->delayCallback(1000);
|
||||||
|
|
||||||
} else if (this->isConnected() && !this->reconnectFlag) {
|
} else if (this->isConnected()) {
|
||||||
if (!this->connected) {
|
if (!this->connected) {
|
||||||
this->connectedTime = millis();
|
this->connectedTime = millis();
|
||||||
this->connected = true;
|
this->connected = true;
|
||||||
@@ -300,7 +318,7 @@ namespace Network {
|
|||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_NETWORK),
|
FPSTR(L_NETWORK),
|
||||||
F("Disconnected, reason: %d, uptime: %lu s."),
|
F("Disconnected, reason: %d, uptime: %lu s."),
|
||||||
Connection::getDisconnectReason(),
|
NetworkConnection::getDisconnectReason(),
|
||||||
(millis() - this->connectedTime) / 1000
|
(millis() - this->connectedTime) / 1000
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -322,18 +340,17 @@ namespace Network {
|
|||||||
} else if (this->isConnecting() && millis() - this->prevReconnectingTime > this->resetConnectionTimeout) {
|
} else if (this->isConnecting() && millis() - this->prevReconnectingTime > this->resetConnectionTimeout) {
|
||||||
Log.swarningln(FPSTR(L_NETWORK), F("Connection timeout, reset wifi..."));
|
Log.swarningln(FPSTR(L_NETWORK), F("Connection timeout, reset wifi..."));
|
||||||
this->resetWifi();
|
this->resetWifi();
|
||||||
Connection::reset();
|
NetworkConnection::reset();
|
||||||
this->delayCallback(200);
|
this->delayCallback(250);
|
||||||
|
|
||||||
} else if (!this->isConnecting() && this->hasStaCredentials() && (!this->prevReconnectingTime || millis() - this->prevReconnectingTime > this->reconnectInterval)) {
|
} else if (!this->isConnecting() && this->hasStaCredentials() && (!this->prevReconnectingTime || millis() - this->prevReconnectingTime > this->reconnectInterval)) {
|
||||||
Log.sinfoln(FPSTR(L_NETWORK), F("Try connect..."));
|
Log.sinfoln(FPSTR(L_NETWORK), F("Try connect..."));
|
||||||
|
|
||||||
this->reconnectFlag = false;
|
NetworkConnection::reset();
|
||||||
Connection::reset();
|
|
||||||
if (!this->connect(true, this->connectionTimeout)) {
|
if (!this->connect(true, this->connectionTimeout)) {
|
||||||
Log.straceln(FPSTR(L_NETWORK), F("Connection failed. Status: %d, reason: %d"), Connection::getStatus(), Connection::getDisconnectReason());
|
Log.straceln(FPSTR(L_NETWORK), F("Connection failed. Status: %d, reason: %d"), NetworkConnection::getStatus(), NetworkConnection::getDisconnectReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
this->prevReconnectingTime = millis();
|
this->prevReconnectingTime = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
|
#include <detail/mimetable.h>
|
||||||
|
|
||||||
|
using namespace mime;
|
||||||
|
|
||||||
class StaticPage : public RequestHandler {
|
class StaticPage : public RequestHandler {
|
||||||
public:
|
public:
|
||||||
@@ -61,6 +64,14 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!this->path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !this->fs->exists(path)) {
|
||||||
|
String pathWithGz = this->path + FPSTR(mimeTable[gz].endsWith);
|
||||||
|
|
||||||
|
if (this->fs->exists(pathWithGz)) {
|
||||||
|
this->path += FPSTR(mimeTable[gz].endsWith);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
File file = this->fs->open(this->path, "r");
|
File file = this->fs->open(this->path, "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return false;
|
return false;
|
||||||
@@ -93,6 +104,6 @@ protected:
|
|||||||
BeforeSendCallback beforeSendCallback;
|
BeforeSendCallback beforeSendCallback;
|
||||||
String eTag;
|
String eTag;
|
||||||
const char* uri = nullptr;
|
const char* uri = nullptr;
|
||||||
const char* path = nullptr;
|
String path;
|
||||||
const char* cacheHeader = nullptr;
|
const char* cacheHeader = nullptr;
|
||||||
};
|
};
|
||||||
@@ -174,7 +174,7 @@ public:
|
|||||||
Log.serrorln(
|
Log.serrorln(
|
||||||
FPSTR(L_PORTAL_OTA),
|
FPSTR(L_PORTAL_OTA),
|
||||||
F("File '%s', on writing %d bytes: %s"),
|
F("File '%s', on writing %d bytes: %s"),
|
||||||
upload.filename.c_str(), upload.totalSize, result->error
|
upload.filename.c_str(), upload.totalSize, result->error.c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
159
platformio.ini
159
platformio.ini
@@ -15,59 +15,65 @@ extra_configs = secrets.default.ini
|
|||||||
[env]
|
[env]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.0.3
|
bblanchon/ArduinoJson@^7.0.4
|
||||||
;ihormelnyk/OpenTherm Library@^1.1.4
|
;ihormelnyk/OpenTherm Library@^1.1.5
|
||||||
https://github.com/Laxilef/opentherm_library/archive/refs/heads/fix_start_bit.zip
|
https://github.com/ihormelnyk/opentherm_library#master
|
||||||
arduino-libraries/ArduinoMqttClient@^0.1.8
|
arduino-libraries/ArduinoMqttClient@^0.1.8
|
||||||
lennarthennigs/ESP Telnet@^2.2
|
lennarthennigs/ESP Telnet@^2.2
|
||||||
gyverlibs/FileData@^1.0.2
|
gyverlibs/FileData@^1.0.2
|
||||||
gyverlibs/GyverPID@^3.3.2
|
gyverlibs/GyverPID@^3.3.2
|
||||||
gyverlibs/GyverBlinker@^1.0
|
gyverlibs/GyverBlinker@^1.0
|
||||||
|
https://github.com/PaulStoffregen/OneWire#master
|
||||||
milesburton/DallasTemperature@^3.11.0
|
milesburton/DallasTemperature@^3.11.0
|
||||||
laxilef/TinyLogger@^1.1.0
|
laxilef/TinyLogger@^1.1.0
|
||||||
build_flags =
|
build_flags =
|
||||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||||
|
;-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||||
-D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
|
-D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
|
||||||
-mtext-section-literals
|
-mtext-section-literals
|
||||||
-D MQTT_CLIENT_STD_FUNCTION_CALLBACK=1
|
-D MQTT_CLIENT_STD_FUNCTION_CALLBACK=1
|
||||||
;-D DEBUG_ESP_CORE -D DEBUG_ESP_WIFI -D DEBUG_ESP_PORT=Serial
|
;-D DEBUG_ESP_CORE -D DEBUG_ESP_WIFI -D DEBUG_ESP_HTTP_SERVER -D DEBUG_ESP_PORT=Serial
|
||||||
-D USE_SERIAL=${secrets.use_serial}
|
-D USE_SERIAL=${secrets.use_serial}
|
||||||
-D USE_TELNET=${secrets.use_telnet}
|
-D USE_TELNET=${secrets.use_telnet}
|
||||||
-D DEBUG_BY_DEFAULT=${secrets.debug}
|
-D DEBUG_BY_DEFAULT=${secrets.debug}
|
||||||
-D HOSTNAME_DEFAULT='"${secrets.hostname}"'
|
-D DEFAULT_HOSTNAME='"${secrets.hostname}"'
|
||||||
-D AP_SSID_DEFAULT='"${secrets.ap_ssid}"'
|
-D DEFAULT_AP_SSID='"${secrets.ap_ssid}"'
|
||||||
-D AP_PASSWORD_DEFAULT='"${secrets.ap_password}"'
|
-D DEFAULT_AP_PASSWORD='"${secrets.ap_password}"'
|
||||||
-D STA_SSID_DEFAULT='"${secrets.sta_ssid}"'
|
-D DEFAULT_STA_SSID='"${secrets.sta_ssid}"'
|
||||||
-D STA_PASSWORD_DEFAULT='"${secrets.sta_password}"'
|
-D DEFAULT_STA_PASSWORD='"${secrets.sta_password}"'
|
||||||
-D PORTAL_LOGIN_DEFAULT='"${secrets.portal_login}"'
|
-D DEFAULT_PORTAL_LOGIN='"${secrets.portal_login}"'
|
||||||
-D PORTAL_PASSWORD_DEFAULT='"${secrets.portal_password}"'
|
-D DEFAULT_PORTAL_PASSWORD='"${secrets.portal_password}"'
|
||||||
-D MQTT_SERVER_DEFAULT='"${secrets.mqtt_server}"'
|
-D DEFAULT_MQTT_SERVER='"${secrets.mqtt_server}"'
|
||||||
-D MQTT_PORT_DEFAULT=${secrets.mqtt_port}
|
-D DEFAULT_MQTT_PORT=${secrets.mqtt_port}
|
||||||
-D MQTT_USER_DEFAULT='"${secrets.mqtt_user}"'
|
-D DEFAULT_MQTT_USER='"${secrets.mqtt_user}"'
|
||||||
-D MQTT_PASSWORD_DEFAULT='"${secrets.mqtt_password}"'
|
-D DEFAULT_MQTT_PASSWORD='"${secrets.mqtt_password}"'
|
||||||
-D MQTT_PREFIX_DEFAULT='"${secrets.mqtt_prefix}"'
|
-D DEFAULT_MQTT_PREFIX='"${secrets.mqtt_prefix}"'
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_filters = direct
|
monitor_filters = direct
|
||||||
board_build.flash_mode = dio
|
board_build.flash_mode = dio
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
version = 1.4.0-rc.15
|
version = 1.4.1
|
||||||
|
|
||||||
; Defaults
|
; Defaults
|
||||||
[esp8266_defaults]
|
[esp8266_defaults]
|
||||||
platform = espressif8266
|
platform = espressif8266@^4.2.1
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
nrwiersma/ESP8266Scheduler@^1.1
|
nrwiersma/ESP8266Scheduler@^1.2
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
post:tools/build.py
|
post:tools/build.py
|
||||||
build_flags = ${env.build_flags}
|
build_flags = ${env.build_flags}
|
||||||
board_build.ldscript = eagle.flash.1m256.ld
|
board_build.ldscript = eagle.flash.4m1m.ld
|
||||||
;board_build.ldscript = eagle.flash.4m1m.ld
|
|
||||||
|
|
||||||
[esp32_defaults]
|
[esp32_defaults]
|
||||||
platform = espressif32
|
;platform = espressif32@^6.7
|
||||||
|
platform = https://github.com/platformio/platform-espressif32.git
|
||||||
|
platform_packages =
|
||||||
|
;platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.17.zip
|
||||||
|
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||||
|
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||||
board_build.partitions = esp32_partitions.csv
|
board_build.partitions = esp32_partitions.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
@@ -91,12 +97,12 @@ extra_scripts = ${esp8266_defaults.extra_scripts}
|
|||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D OT_IN_PIN_DEFAULT=4
|
-D DEFAULT_OT_IN_GPIO=4
|
||||||
-D OT_OUT_PIN_DEFAULT=5
|
-D DEFAULT_OT_OUT_GPIO=5
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=14
|
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
||||||
-D LED_STATUS_PIN=13
|
-D DEFAULT_STATUS_LED_GPIO=13
|
||||||
-D LED_OT_RX_PIN=15
|
-D DEFAULT_OT_RX_LED_GPIO=15
|
||||||
|
|
||||||
[env:d1_mini_lite]
|
[env:d1_mini_lite]
|
||||||
platform = ${esp8266_defaults.platform}
|
platform = ${esp8266_defaults.platform}
|
||||||
@@ -107,12 +113,12 @@ extra_scripts = ${esp8266_defaults.extra_scripts}
|
|||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D OT_IN_PIN_DEFAULT=4
|
-D DEFAULT_OT_IN_GPIO=4
|
||||||
-D OT_OUT_PIN_DEFAULT=5
|
-D DEFAULT_OT_OUT_GPIO=5
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=14
|
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
||||||
-D LED_STATUS_PIN=13
|
-D DEFAULT_STATUS_LED_GPIO=13
|
||||||
-D LED_OT_RX_PIN=15
|
-D DEFAULT_OT_RX_LED_GPIO=15
|
||||||
|
|
||||||
[env:d1_mini_pro]
|
[env:d1_mini_pro]
|
||||||
platform = ${esp8266_defaults.platform}
|
platform = ${esp8266_defaults.platform}
|
||||||
@@ -123,31 +129,37 @@ extra_scripts = ${esp8266_defaults.extra_scripts}
|
|||||||
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
board_build.ldscript = ${esp8266_defaults.board_build.ldscript}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp8266_defaults.build_flags}
|
${esp8266_defaults.build_flags}
|
||||||
-D OT_IN_PIN_DEFAULT=4
|
-D DEFAULT_OT_IN_GPIO=4
|
||||||
-D OT_OUT_PIN_DEFAULT=5
|
-D DEFAULT_OT_OUT_GPIO=5
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=14
|
-D DEFAULT_SENSOR_INDOOR_GPIO=14
|
||||||
-D LED_STATUS_PIN=13
|
-D DEFAULT_STATUS_LED_GPIO=13
|
||||||
-D LED_OT_RX_PIN=15
|
-D DEFAULT_OT_RX_LED_GPIO=15
|
||||||
|
|
||||||
[env:s2_mini]
|
[env:s2_mini]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = lolin_s2_mini
|
board = lolin_s2_mini
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps = ${esp32_defaults.lib_deps}
|
lib_deps = ${esp32_defaults.lib_deps}
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
lib_ignore = ${esp32_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
|
build_unflags =
|
||||||
|
-DARDUINO_USB_MODE=1
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D OT_IN_PIN_DEFAULT=33
|
-D ARDUINO_USB_MODE=0
|
||||||
-D OT_OUT_PIN_DEFAULT=35
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=9
|
-D DEFAULT_OT_IN_GPIO=33
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=7
|
-D DEFAULT_OT_OUT_GPIO=35
|
||||||
-D LED_STATUS_PIN=11
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=9
|
||||||
-D LED_OT_RX_PIN=12
|
-D DEFAULT_SENSOR_INDOOR_GPIO=7
|
||||||
|
-D DEFAULT_STATUS_LED_GPIO=11
|
||||||
|
-D DEFAULT_OT_RX_LED_GPIO=12
|
||||||
|
|
||||||
[env:s3_mini]
|
[env:s3_mini]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = lolin_s3_mini
|
board = lolin_s3_mini
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -155,18 +167,23 @@ lib_deps =
|
|||||||
h2zero/NimBLE-Arduino@^1.4.1
|
h2zero/NimBLE-Arduino@^1.4.1
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
lib_ignore = ${esp32_defaults.lib_ignore}
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
|
build_unflags =
|
||||||
|
-DARDUINO_USB_MODE=1
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
|
-D ARDUINO_USB_MODE=0
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
-D OT_IN_PIN_DEFAULT=35
|
-D DEFAULT_OT_IN_GPIO=35
|
||||||
-D OT_OUT_PIN_DEFAULT=36
|
-D DEFAULT_OT_OUT_GPIO=36
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=13
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=13
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=12
|
-D DEFAULT_SENSOR_INDOOR_GPIO=12
|
||||||
-D LED_STATUS_PIN=11
|
-D DEFAULT_STATUS_LED_GPIO=11
|
||||||
-D LED_OT_RX_PIN=10
|
-D DEFAULT_OT_RX_LED_GPIO=10
|
||||||
|
|
||||||
[env:c3_mini]
|
[env:c3_mini]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = lolin_c3_mini
|
board = lolin_c3_mini
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -179,15 +196,16 @@ build_unflags =
|
|||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
-D OT_IN_PIN_DEFAULT=8
|
-D DEFAULT_OT_IN_GPIO=8
|
||||||
-D OT_OUT_PIN_DEFAULT=10
|
-D DEFAULT_OT_OUT_GPIO=10
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=0
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=0
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=1
|
-D DEFAULT_SENSOR_INDOOR_GPIO=1
|
||||||
-D LED_STATUS_PIN=4
|
-D DEFAULT_STATUS_LED_GPIO=4
|
||||||
-D LED_OT_RX_PIN=5
|
-D DEFAULT_OT_RX_LED_GPIO=5
|
||||||
|
|
||||||
[env:nodemcu_32s]
|
[env:nodemcu_32s]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = nodemcu-32s
|
board = nodemcu-32s
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -198,16 +216,17 @@ extra_scripts = ${esp32_defaults.extra_scripts}
|
|||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
-D OT_IN_PIN_DEFAULT=21
|
-D DEFAULT_OT_IN_GPIO=21
|
||||||
-D OT_OUT_PIN_DEFAULT=22
|
-D DEFAULT_OT_OUT_GPIO=22
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=13
|
-D DEFAULT_SENSOR_INDOOR_GPIO=13
|
||||||
-D LED_STATUS_PIN=2 ; 18
|
-D DEFAULT_STATUS_LED_GPIO=2 ; 18
|
||||||
-D LED_OT_RX_PIN=19
|
-D DEFAULT_OT_RX_LED_GPIO=19
|
||||||
;-D WOKWI=1
|
;-D WOKWI=1
|
||||||
|
|
||||||
[env:d1_mini32]
|
[env:d1_mini32]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = wemos_d1_mini32
|
board = wemos_d1_mini32
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -218,9 +237,9 @@ extra_scripts = ${esp32_defaults.extra_scripts}
|
|||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
-D USE_BLE=1
|
-D USE_BLE=1
|
||||||
-D OT_IN_PIN_DEFAULT=21
|
-D DEFAULT_OT_IN_GPIO=21
|
||||||
-D OT_OUT_PIN_DEFAULT=22
|
-D DEFAULT_OT_OUT_GPIO=22
|
||||||
-D SENSOR_OUTDOOR_PIN_DEFAULT=12
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=12
|
||||||
-D SENSOR_INDOOR_PIN_DEFAULT=18
|
-D DEFAULT_SENSOR_INDOOR_GPIO=18
|
||||||
-D LED_STATUS_PIN=2
|
-D DEFAULT_STATUS_LED_GPIO=2
|
||||||
-D LED_OT_RX_PIN=19
|
-D DEFAULT_OT_RX_LED_GPIO=19
|
||||||
|
|||||||
534
src/HaHelper.h
534
src/HaHelper.h
@@ -6,98 +6,6 @@ public:
|
|||||||
static const byte TEMP_SOURCE_HEATING = 0;
|
static const byte TEMP_SOURCE_HEATING = 0;
|
||||||
static const byte TEMP_SOURCE_INDOOR = 1;
|
static const byte TEMP_SOURCE_INDOOR = 1;
|
||||||
|
|
||||||
bool publishSwitchEmergency(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Use emergency");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:sun-snowflake-variant");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.enable }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"enable\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"enable\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishNumberEmergencyTarget(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_target"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_target"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Emergency target temp");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-alert");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.target|float(0)|round(1) }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"emergency\": {\"target\" : {{ value }}}}");
|
|
||||||
doc[FPSTR(HA_MIN)] = 5;
|
|
||||||
doc[FPSTR(HA_MAX)] = 50;
|
|
||||||
doc[FPSTR(HA_STEP)] = 0.5;
|
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("emergency_target")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishSwitchEmergencyUseEquitherm(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.outdoor.type != 1, 'online', 'offline') }}");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_use_equitherm"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_use_equitherm"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Use equitherm in emergency");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:snowflake-alert");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.useEquitherm }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"useEquitherm\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"useEquitherm\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency_use_equitherm")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishSwitchEmergencyUsePid(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.indoor.type != 1, 'online', 'offline') }}");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_use_pid"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_use_pid"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Use PID in emergency");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:snowflake-alert");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.emergency.usePid }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"emergency\": {\"usePid\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"emergency\": {\"usePid\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency_use_pid")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool publishSwitchHeating(bool enabledByDefault = true) {
|
bool publishSwitchHeating(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
@@ -142,7 +50,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("heating_turbo")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("heating_turbo")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberHeatingTarget(byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) {
|
bool publishNumberHeatingTarget(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -150,7 +58,14 @@ public:
|
|||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_target"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_target"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating target");
|
doc[FPSTR(HA_NAME)] = F("Heating target");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
@@ -159,7 +74,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"target\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = minTemp;
|
doc[FPSTR(HA_MIN)] = minTemp;
|
||||||
doc[FPSTR(HA_MAX)] = maxTemp;
|
doc[FPSTR(HA_MAX)] = maxTemp;
|
||||||
doc[FPSTR(HA_STEP)] = 0.5;
|
doc[FPSTR(HA_STEP)] = 0.5f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -167,14 +82,21 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_target")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_target")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberHeatingHysteresis(bool enabledByDefault = true) {
|
bool publishNumberHeatingHysteresis(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_hysteresis"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_hysteresis"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_hysteresis"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_hysteresis"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating hysteresis");
|
doc[FPSTR(HA_NAME)] = F("Heating hysteresis");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:altimeter");
|
doc[FPSTR(HA_ICON)] = F("mdi:altimeter");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
@@ -183,7 +105,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"hysteresis\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"hysteresis\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 5;
|
doc[FPSTR(HA_MAX)] = 5;
|
||||||
doc[FPSTR(HA_STEP)] = 0.1;
|
doc[FPSTR(HA_STEP)] = 0.1f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -191,7 +113,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_hysteresis")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_hysteresis")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorHeatingSetpoint(bool enabledByDefault = true) {
|
bool publishSensorHeatingSetpoint(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -200,18 +122,25 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating setpoint");
|
doc[FPSTR(HA_NAME)] = F("Heating setpoint");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:coolant-temperature");
|
doc[FPSTR(HA_ICON)] = F("mdi:coolant-temperature");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingSetpoint|int(0) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.parameters.heatingSetpoint|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_setpoint")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_setpoint")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorBoilerHeatingMinTemp(bool enabledByDefault = true) {
|
bool publishSensorBoilerHeatingMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -223,7 +152,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Boiler heating min temp");
|
doc[FPSTR(HA_NAME)] = F("Boiler heating min temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -234,7 +170,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_heating_min_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_heating_min_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorBoilerHeatingMaxTemp(bool enabledByDefault = true) {
|
bool publishSensorBoilerHeatingMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -246,7 +182,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Boiler heating max temp");
|
doc[FPSTR(HA_NAME)] = F("Boiler heating max temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -257,22 +200,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_heating_max_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_heating_max_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberHeatingMinTemp(bool enabledByDefault = true) {
|
bool publishNumberHeatingMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_min_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_min_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_min_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_min_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
|
doc[FPSTR(HA_MAX)] = 99;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = 32;
|
||||||
|
doc[FPSTR(HA_MAX)] = 211;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating min temp");
|
doc[FPSTR(HA_NAME)] = F("Heating min temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.minTemp|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.minTemp|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"minTemp\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"minTemp\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
|
||||||
doc[FPSTR(HA_MAX)] = 99;
|
|
||||||
doc[FPSTR(HA_STEP)] = 1;
|
doc[FPSTR(HA_STEP)] = 1;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
@@ -281,22 +233,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_min_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_min_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberHeatingMaxTemp(bool enabledByDefault = true) {
|
bool publishNumberHeatingMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_max_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_max_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_max_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_max_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = 1;
|
||||||
|
doc[FPSTR(HA_MAX)] = 100;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = 33;
|
||||||
|
doc[FPSTR(HA_MAX)] = 212;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating max temp");
|
doc[FPSTR(HA_NAME)] = F("Heating max temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.maxTemp|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.heating.maxTemp|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"maxTemp\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"heating\": {\"maxTemp\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 1;
|
|
||||||
doc[FPSTR(HA_MAX)] = 100;
|
|
||||||
doc[FPSTR(HA_STEP)] = 1;
|
doc[FPSTR(HA_STEP)] = 1;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
@@ -352,7 +313,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("dhw")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("dhw")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberDhwTarget(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
|
bool publishNumberDhwTarget(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -360,11 +321,18 @@ public:
|
|||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_target"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_target"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("DHW target");
|
doc[FPSTR(HA_NAME)] = F("DHW target");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.target|int(0) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.target|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = minTemp;
|
doc[FPSTR(HA_MIN)] = minTemp;
|
||||||
@@ -377,7 +345,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_target")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_target")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorBoilerDhwMinTemp(bool enabledByDefault = true) {
|
bool publishSensorBoilerDhwMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -389,7 +357,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Boiler DHW min temp");
|
doc[FPSTR(HA_NAME)] = F("Boiler DHW min temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -400,7 +375,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_dhw_min_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_dhw_min_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorBoilerDhwMaxTemp(bool enabledByDefault = true) {
|
bool publishSensorBoilerDhwMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -412,7 +387,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Boiler DHW max temp");
|
doc[FPSTR(HA_NAME)] = F("Boiler DHW max temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -423,22 +405,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_dhw_max_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_dhw_max_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberDhwMinTemp(bool enabledByDefault = true) {
|
bool publishNumberDhwMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_min_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_min_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_min_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_min_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
|
doc[FPSTR(HA_MAX)] = 99;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = 32;
|
||||||
|
doc[FPSTR(HA_MAX)] = 211;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("DHW min temp");
|
doc[FPSTR(HA_NAME)] = F("DHW min temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.minTemp|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.minTemp|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"minTemp\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"minTemp\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
|
||||||
doc[FPSTR(HA_MAX)] = 99;
|
|
||||||
doc[FPSTR(HA_STEP)] = 1;
|
doc[FPSTR(HA_STEP)] = 1;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
@@ -447,22 +438,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_min_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_min_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberDhwMaxTemp(bool enabledByDefault = true) {
|
bool publishNumberDhwMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_max_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_max_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_max_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_max_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = 1;
|
||||||
|
doc[FPSTR(HA_MAX)] = 100;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = 33;
|
||||||
|
doc[FPSTR(HA_MAX)] = 212;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("DHW max temp");
|
doc[FPSTR(HA_NAME)] = F("DHW max temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.maxTemp|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.dhw.maxTemp|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"maxTemp\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"maxTemp\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 1;
|
|
||||||
doc[FPSTR(HA_MAX)] = 100;
|
|
||||||
doc[FPSTR(HA_STEP)] = 1;
|
doc[FPSTR(HA_STEP)] = 1;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
@@ -504,9 +504,9 @@ public:
|
|||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.p_factor|float(0)|round(3) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.p_factor|float(0)|round(3) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"p_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"p_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0.1;
|
doc[FPSTR(HA_MIN)] = 0.1f;
|
||||||
doc[FPSTR(HA_MAX)] = 1000;
|
doc[FPSTR(HA_MAX)] = 1000;
|
||||||
doc[FPSTR(HA_STEP)] = 0.1;
|
doc[FPSTR(HA_STEP)] = 0.1f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -522,12 +522,12 @@ public:
|
|||||||
doc[FPSTR(HA_NAME)] = F("PID factor I");
|
doc[FPSTR(HA_NAME)] = F("PID factor I");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:alpha-i-circle-outline");
|
doc[FPSTR(HA_ICON)] = F("mdi:alpha-i-circle-outline");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.i_factor|float(0)|round(3) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.i_factor|float(0)|round(4) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"i_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"i_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 100;
|
doc[FPSTR(HA_MAX)] = 100;
|
||||||
doc[FPSTR(HA_STEP)] = 0.001;
|
doc[FPSTR(HA_STEP)] = 0.001f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -579,22 +579,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("pid_dt")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("pid_dt")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberPidMinTemp(bool enabledByDefault = true) {
|
bool publishNumberPidMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pid_min_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pid_min_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pid_min_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pid_min_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
|
doc[FPSTR(HA_MAX)] = 99;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
|
doc[FPSTR(HA_MAX)] = 211;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("PID min temp");
|
doc[FPSTR(HA_NAME)] = F("PID min temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.minTemp|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.minTemp|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"minTemp\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"minTemp\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
|
||||||
doc[FPSTR(HA_MAX)] = 99;
|
|
||||||
doc[FPSTR(HA_STEP)] = 1;
|
doc[FPSTR(HA_STEP)] = 1;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
@@ -603,22 +612,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("pid_min_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("pid_min_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberPidMaxTemp(bool enabledByDefault = true) {
|
bool publishNumberPidMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pid_max_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pid_max_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pid_max_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pid_max_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = 1;
|
||||||
|
doc[FPSTR(HA_MAX)] = 100;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = 1;
|
||||||
|
doc[FPSTR(HA_MAX)] = 212;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("PID max temp");
|
doc[FPSTR(HA_NAME)] = F("PID max temp");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.maxTemp|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.pid.maxTemp|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"maxTemp\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"pid\": {\"maxTemp\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 1;
|
|
||||||
doc[FPSTR(HA_MAX)] = 100;
|
|
||||||
doc[FPSTR(HA_STEP)] = 1;
|
doc[FPSTR(HA_STEP)] = 1;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
@@ -660,9 +678,9 @@ public:
|
|||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.n_factor|float(0)|round(3) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.equitherm.n_factor|float(0)|round(3) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"n_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"n_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0.001;
|
doc[FPSTR(HA_MIN)] = 0.001f;
|
||||||
doc[FPSTR(HA_MAX)] = 10;
|
doc[FPSTR(HA_MAX)] = 10;
|
||||||
doc[FPSTR(HA_STEP)] = 0.001;
|
doc[FPSTR(HA_STEP)] = 0.001f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -683,7 +701,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"k_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"k_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 10;
|
doc[FPSTR(HA_MAX)] = 10;
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -706,7 +724,7 @@ public:
|
|||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"t_factor\" : {{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"equitherm\": {\"t_factor\" : {{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = 0;
|
doc[FPSTR(HA_MIN)] = 0;
|
||||||
doc[FPSTR(HA_MAX)] = 10;
|
doc[FPSTR(HA_MAX)] = 10;
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -715,48 +733,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool publishSwitchTuning(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("tuning"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("tuning"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Tuning");
|
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:tune-vertical");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
|
||||||
doc[FPSTR(HA_STATE_ON)] = true;
|
|
||||||
doc[FPSTR(HA_STATE_OFF)] = false;
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.tuning.enable }}");
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
|
||||||
doc[FPSTR(HA_PAYLOAD_ON)] = F("{\"tuning\": {\"enable\" : true}}");
|
|
||||||
doc[FPSTR(HA_PAYLOAD_OFF)] = F("{\"tuning\": {\"enable\" : false}}");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("tuning")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool publishSelectTuningRegulator(bool enabledByDefault = true) {
|
|
||||||
JsonDocument doc;
|
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"tuning\": {\"regulator\": {% if value == 'Equitherm' %}0{% elif value == 'PID' %}1{% endif %}}}");
|
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("tuning_regulator"));
|
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("tuning_regulator"));
|
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Tuning regulator");
|
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{% if value_json.tuning.regulator == 0 %}Equitherm{% elif value_json.tuning.regulator == 1 %}PID{% endif %}");
|
|
||||||
doc[FPSTR(HA_OPTIONS)][0] = F("Equitherm");
|
|
||||||
doc[FPSTR(HA_OPTIONS)][1] = F("PID");
|
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SELECT), F("tuning_regulator")).c_str(), doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool publishBinSensorStatus(bool enabledByDefault = true) {
|
bool publishBinSensorStatus(bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -980,7 +956,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("modulation")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("modulation")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorPressure(bool enabledByDefault = true) {
|
bool publishSensorPressure(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -992,7 +968,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("pressure");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("pressure");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("bar");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("bar");
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("psi");
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Pressure");
|
doc[FPSTR(HA_NAME)] = F("Pressure");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:gauge");
|
doc[FPSTR(HA_ICON)] = F("mdi:gauge");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1003,7 +986,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("pressure")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("pressure")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorDhwFlowRate(bool enabledByDefault = true) {
|
bool publishSensorDhwFlowRate(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1015,7 +998,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("volume_flow_rate");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("volume_flow_rate");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("L/min");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("L/min");
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("gal/min");
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("DHW flow rate");
|
doc[FPSTR(HA_NAME)] = F("DHW flow rate");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1027,22 +1017,31 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool publishNumberIndoorTemp(bool enabledByDefault = true) {
|
bool publishNumberIndoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("indoor_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("indoor_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("indoor_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("indoor_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = -99;
|
||||||
|
doc[FPSTR(HA_MAX)] = 99;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = -147;
|
||||||
|
doc[FPSTR(HA_MAX)] = 211;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Indoor temperature");
|
doc[FPSTR(HA_NAME)] = F("Indoor temperature");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
|
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.indoor|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"indoor\":{{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"indoor\":{{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = -99;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MAX)] = 99;
|
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -1050,7 +1049,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("indoor_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("indoor_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorIndoorTemp(bool enabledByDefault = true) {
|
bool publishSensorIndoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1059,7 +1058,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Indoor temperature");
|
doc[FPSTR(HA_NAME)] = F("Indoor temperature");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
|
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1070,22 +1076,31 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("indoor_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("indoor_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishNumberOutdoorTemp(bool enabledByDefault = true) {
|
bool publishNumberOutdoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("outdoor_temp"));
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("outdoor_temp"));
|
||||||
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("outdoor_temp"));
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("outdoor_temp"));
|
||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
doc[FPSTR(HA_MIN)] = -99;
|
||||||
|
doc[FPSTR(HA_MAX)] = 99;
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
doc[FPSTR(HA_MIN)] = -147;
|
||||||
|
doc[FPSTR(HA_MAX)] = 211;
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Outdoor temperature");
|
doc[FPSTR(HA_NAME)] = F("Outdoor temperature");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
|
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}");
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.outdoor|float(0)|round(1) }}");
|
||||||
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
|
||||||
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"outdoor\":{{ value }}}}");
|
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"temperatures\": {\"outdoor\":{{ value }}}}");
|
||||||
doc[FPSTR(HA_MIN)] = -99;
|
doc[FPSTR(HA_STEP)] = 0.01f;
|
||||||
doc[FPSTR(HA_MAX)] = 99;
|
|
||||||
doc[FPSTR(HA_STEP)] = 0.01;
|
|
||||||
doc[FPSTR(HA_MODE)] = "box";
|
doc[FPSTR(HA_MODE)] = "box";
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
@@ -1093,7 +1108,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("outdoor_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("outdoor_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorOutdoorTemp(bool enabledByDefault = true) {
|
bool publishSensorOutdoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1102,7 +1117,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Outdoor temperature");
|
doc[FPSTR(HA_NAME)] = F("Outdoor temperature");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
|
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1113,7 +1135,7 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("outdoor_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("outdoor_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorHeatingTemp(bool enabledByDefault = true) {
|
bool publishSensorHeatingTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1125,7 +1147,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("Heating temperature");
|
doc[FPSTR(HA_NAME)] = F("Heating temperature");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1136,7 +1165,37 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishSensorDhwTemp(bool enabledByDefault = true) {
|
bool publishSensorHeatingReturnTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
|
JsonDocument doc;
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
|
||||||
|
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
||||||
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_return_temp"));
|
||||||
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_return_temp"));
|
||||||
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
doc[FPSTR(HA_NAME)] = F("Heating return temperature");
|
||||||
|
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
|
||||||
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.heatingReturn|float(0)|round(2) }}");
|
||||||
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_return_temp")).c_str(), doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool publishSensorDhwTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1148,7 +1207,14 @@ public:
|
|||||||
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_NAME)] = F("DHW temperature");
|
doc[FPSTR(HA_NAME)] = F("DHW temperature");
|
||||||
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
|
||||||
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
@@ -1159,8 +1225,38 @@ public:
|
|||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("dhw_temp")).c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("dhw_temp")).c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool publishSensorExhaustTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
|
||||||
|
JsonDocument doc;
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
|
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
|
||||||
|
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
|
||||||
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
|
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("exhaust_temp"));
|
||||||
|
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("exhaust_temp"));
|
||||||
|
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
|
||||||
|
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
|
||||||
|
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
|
||||||
|
|
||||||
bool publishClimateHeating(byte minTemp = 20, byte maxTemp = 90, byte currentTempSource = HaHelper::TEMP_SOURCE_HEATING, bool enabledByDefault = true) {
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
doc[FPSTR(HA_NAME)] = F("Exhaust temperature");
|
||||||
|
doc[FPSTR(HA_ICON)] = F("mdi:smoke");
|
||||||
|
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
|
||||||
|
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.temperatures.exhaust|float(0)|round(2) }}");
|
||||||
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("exhaust_temp")).c_str(), doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool publishClimateHeating(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 20, byte maxTemp = 90, byte currentTempSource = HaHelper::TEMP_SOURCE_HEATING, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1186,6 +1282,13 @@ public:
|
|||||||
doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.heating.target|float(0)|round(1) }}");
|
doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.heating.target|float(0)|round(1) }}");
|
||||||
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "C";
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "F";
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"heating\": {\"enable\" : true}}"
|
doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"heating\": {\"enable\" : true}}"
|
||||||
"{% elif value == 'off' %}{\"heating\": {\"enable\" : false}}{% endif %}");
|
"{% elif value == 'off' %}{\"heating\": {\"enable\" : false}}{% endif %}");
|
||||||
@@ -1206,14 +1309,14 @@ public:
|
|||||||
|
|
||||||
doc[FPSTR(HA_MIN_TEMP)] = minTemp;
|
doc[FPSTR(HA_MIN_TEMP)] = minTemp;
|
||||||
doc[FPSTR(HA_MAX_TEMP)] = maxTemp;
|
doc[FPSTR(HA_MAX_TEMP)] = maxTemp;
|
||||||
doc[FPSTR(HA_TEMP_STEP)] = 0.5;
|
doc[FPSTR(HA_TEMP_STEP)] = 0.5f;
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
return this->publish(this->getTopic(FPSTR(HA_ENTITY_CLIMATE), F("heating"), '_').c_str(), doc);
|
return this->publish(this->getTopic(FPSTR(HA_ENTITY_CLIMATE), F("heating"), '_').c_str(), doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool publishClimateDhw(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
|
bool publishClimateDhw(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
|
||||||
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
|
||||||
@@ -1229,7 +1332,14 @@ public:
|
|||||||
doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
doc[FPSTR(HA_TEMPERATURE_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
|
||||||
|
|
||||||
doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
doc[FPSTR(HA_TEMPERATURE_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
|
||||||
doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.dhw.target|int(0) }}");
|
doc[FPSTR(HA_TEMPERATURE_STATE_TEMPLATE)] = F("{{ value_json.dhw.target|float(0)|round(1) }}");
|
||||||
|
|
||||||
|
if (unit == UnitSystem::METRIC) {
|
||||||
|
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "C";
|
||||||
|
|
||||||
|
} else if (unit == UnitSystem::IMPERIAL) {
|
||||||
|
doc[FPSTR(HA_TEMPERATURE_UNIT)] = "F";
|
||||||
|
}
|
||||||
|
|
||||||
doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
doc[FPSTR(HA_MODE_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
|
||||||
doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"dhw\": {\"enable\" : true}}"
|
doc[FPSTR(HA_MODE_COMMAND_TEMPLATE)] = F("{% if value == 'heat' %}{\"dhw\": {\"enable\" : true}}"
|
||||||
|
|||||||
124
src/MainTask.h
124
src/MainTask.h
@@ -1,6 +1,8 @@
|
|||||||
#include <Blinker.h>
|
#include <Blinker.h>
|
||||||
|
|
||||||
extern Network::Manager* network;
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
|
extern NetworkMgr* network;
|
||||||
extern MqttTask* tMqtt;
|
extern MqttTask* tMqtt;
|
||||||
extern OpenThermTask* tOt;
|
extern OpenThermTask* tOt;
|
||||||
extern FileData fsSettings, fsNetworkSettings;
|
extern FileData fsSettings, fsNetworkSettings;
|
||||||
@@ -27,7 +29,6 @@ protected:
|
|||||||
enum class PumpStartReason {NONE, HEATING, ANTISTUCK};
|
enum class PumpStartReason {NONE, HEATING, ANTISTUCK};
|
||||||
|
|
||||||
Blinker* blinker = nullptr;
|
Blinker* blinker = nullptr;
|
||||||
bool blinkerInitialized = false;
|
|
||||||
unsigned long firstFailConnect = 0;
|
unsigned long firstFailConnect = 0;
|
||||||
unsigned long lastHeapInfo = 0;
|
unsigned long lastHeapInfo = 0;
|
||||||
unsigned int minFreeHeap = 0;
|
unsigned int minFreeHeap = 0;
|
||||||
@@ -39,29 +40,21 @@ protected:
|
|||||||
unsigned long externalPumpStartTime = 0;
|
unsigned long externalPumpStartTime = 0;
|
||||||
bool telnetStarted = false;
|
bool telnetStarted = false;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Main";
|
return "Main";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {}
|
||||||
#ifdef LED_STATUS_PIN
|
|
||||||
pinMode(LED_STATUS_PIN, OUTPUT);
|
|
||||||
digitalWrite(LED_STATUS_PIN, LOW);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (settings.externalPump.pin != 0) {
|
|
||||||
pinMode(settings.externalPump.pin, OUTPUT);
|
|
||||||
digitalWrite(settings.externalPump.pin, LOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
network->loop();
|
network->loop();
|
||||||
@@ -89,20 +82,31 @@ protected:
|
|||||||
Log.sinfoln(FPSTR(L_MAIN), F("Restart signal received. Restart after 10 sec."));
|
Log.sinfoln(FPSTR(L_MAIN), F("Restart signal received. Restart after 10 sec."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tOt->isEnabled() && settings.opentherm.inPin > 0 && settings.opentherm.outPin > 0 && settings.opentherm.inPin != settings.opentherm.outPin) {
|
vars.states.mqtt = tMqtt->isConnected();
|
||||||
tOt->enable();
|
vars.sensors.rssi = network->isConnected() ? WiFi.RSSI() : 0;
|
||||||
|
|
||||||
|
if (vars.states.emergency && !settings.emergency.enable) {
|
||||||
|
vars.states.emergency = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (network->isConnected()) {
|
if (network->isConnected()) {
|
||||||
vars.sensors.rssi = WiFi.RSSI();
|
|
||||||
|
|
||||||
if (!this->telnetStarted && telnetStream != nullptr) {
|
if (!this->telnetStarted && telnetStream != nullptr) {
|
||||||
telnetStream->begin(23, false);
|
telnetStream->begin(23, false);
|
||||||
this->telnetStarted = true;
|
this->telnetStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tMqtt->isEnabled() && strlen(settings.mqtt.server) > 0) {
|
if (settings.mqtt.enable && !tMqtt->isEnabled()) {
|
||||||
tMqtt->enable();
|
tMqtt->enable();
|
||||||
|
|
||||||
|
} else if (!settings.mqtt.enable && tMqtt->isEnabled()) {
|
||||||
|
tMqtt->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vars.states.emergency && settings.emergency.enable && settings.emergency.onMqttFault && !tMqtt->isEnabled()) {
|
||||||
|
vars.states.emergency = true;
|
||||||
|
|
||||||
|
} else if (vars.states.emergency && !settings.emergency.onMqttFault) {
|
||||||
|
vars.states.emergency = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->firstFailConnect != 0) {
|
if (this->firstFailConnect != 0) {
|
||||||
@@ -126,12 +130,12 @@ protected:
|
|||||||
tMqtt->disable();
|
tMqtt->disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.emergency.enable && !vars.states.emergency) {
|
if (!vars.states.emergency && settings.emergency.enable && settings.emergency.onNetworkFault) {
|
||||||
if (this->firstFailConnect == 0) {
|
if (this->firstFailConnect == 0) {
|
||||||
this->firstFailConnect = millis();
|
this->firstFailConnect = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (millis() - this->firstFailConnect > EMERGENCY_TIME_TRESHOLD) {
|
if (millis() - this->firstFailConnect > (settings.emergency.tresholdTime * 1000)) {
|
||||||
vars.states.emergency = true;
|
vars.states.emergency = true;
|
||||||
Log.sinfoln(FPSTR(L_MAIN), F("Emergency mode enabled"));
|
Log.sinfoln(FPSTR(L_MAIN), F("Emergency mode enabled"));
|
||||||
}
|
}
|
||||||
@@ -140,9 +144,7 @@ protected:
|
|||||||
this->yield();
|
this->yield();
|
||||||
|
|
||||||
|
|
||||||
#ifdef LED_STATUS_PIN
|
this->ledStatus();
|
||||||
this->ledStatus(LED_STATUS_PIN);
|
|
||||||
#endif
|
|
||||||
this->externalPump();
|
this->externalPump();
|
||||||
this->yield();
|
this->yield();
|
||||||
|
|
||||||
@@ -211,16 +213,32 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ledStatus(uint8_t ledPin) {
|
void ledStatus() {
|
||||||
uint8_t errors[4];
|
uint8_t errors[4];
|
||||||
uint8_t errCount = 0;
|
uint8_t errCount = 0;
|
||||||
static uint8_t errPos = 0;
|
static uint8_t errPos = 0;
|
||||||
static unsigned long endBlinkTime = 0;
|
static unsigned long endBlinkTime = 0;
|
||||||
static bool ledOn = false;
|
static bool ledOn = false;
|
||||||
|
static uint8_t configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
|
||||||
if (!this->blinkerInitialized) {
|
if (settings.system.statusLedGpio != configuredGpio) {
|
||||||
this->blinker->init(ledPin);
|
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
this->blinkerInitialized = true;
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.system.statusLedGpio)) {
|
||||||
|
configuredGpio = settings.system.statusLedGpio;
|
||||||
|
pinMode(configuredGpio, OUTPUT);
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
this->blinker->init(configuredGpio);
|
||||||
|
|
||||||
|
} else if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuredGpio == GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!network->isConnected()) {
|
if (!network->isConnected()) {
|
||||||
@@ -247,14 +265,14 @@ protected:
|
|||||||
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
|
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
|
||||||
if (errCount == 0) {
|
if (errCount == 0) {
|
||||||
if (!ledOn) {
|
if (!ledOn) {
|
||||||
digitalWrite(ledPin, HIGH);
|
digitalWrite(configuredGpio, HIGH);
|
||||||
ledOn = true;
|
ledOn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (ledOn) {
|
} else if (ledOn) {
|
||||||
digitalWrite(ledPin, LOW);
|
digitalWrite(configuredGpio, LOW);
|
||||||
ledOn = false;
|
ledOn = false;
|
||||||
endBlinkTime = millis();
|
endBlinkTime = millis();
|
||||||
return;
|
return;
|
||||||
@@ -275,6 +293,34 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void externalPump() {
|
void externalPump() {
|
||||||
|
static uint8_t configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
|
||||||
|
if (settings.externalPump.gpio != configuredGpio) {
|
||||||
|
if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPIO_IS_VALID(settings.externalPump.gpio)) {
|
||||||
|
configuredGpio = settings.externalPump.gpio;
|
||||||
|
pinMode(configuredGpio, OUTPUT);
|
||||||
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
|
||||||
|
} else if (configuredGpio != GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
configuredGpio = GPIO_IS_NOT_CONFIGURED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuredGpio == GPIO_IS_NOT_CONFIGURED) {
|
||||||
|
if (vars.states.externalPump) {
|
||||||
|
vars.states.externalPump = false;
|
||||||
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
|
|
||||||
|
Log.sinfoln("EXTPUMP", F("Disabled: use = off"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vars.states.heating && this->heatingEnabled) {
|
if (!vars.states.heating && this->heatingEnabled) {
|
||||||
this->heatingEnabled = false;
|
this->heatingEnabled = false;
|
||||||
this->heatingDisabledTime = millis();
|
this->heatingDisabledTime = millis();
|
||||||
@@ -283,11 +329,9 @@ protected:
|
|||||||
this->heatingEnabled = true;
|
this->heatingEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.externalPump.use || settings.externalPump.pin == 0) {
|
if (!settings.externalPump.use) {
|
||||||
if (vars.states.externalPump) {
|
if (vars.states.externalPump) {
|
||||||
if (settings.externalPump.pin != 0) {
|
digitalWrite(configuredGpio, LOW);
|
||||||
digitalWrite(settings.externalPump.pin, LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
vars.states.externalPump = false;
|
vars.states.externalPump = false;
|
||||||
vars.parameters.extPumpLastEnableTime = millis();
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
@@ -300,7 +344,7 @@ protected:
|
|||||||
|
|
||||||
if (vars.states.externalPump && !this->heatingEnabled) {
|
if (vars.states.externalPump && !this->heatingEnabled) {
|
||||||
if (this->extPumpStartReason == MainTask::PumpStartReason::HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
|
if (this->extPumpStartReason == MainTask::PumpStartReason::HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
|
||||||
digitalWrite(settings.externalPump.pin, LOW);
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
|
||||||
vars.states.externalPump = false;
|
vars.states.externalPump = false;
|
||||||
vars.parameters.extPumpLastEnableTime = millis();
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
@@ -308,7 +352,7 @@ protected:
|
|||||||
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
|
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
|
||||||
|
|
||||||
} else if (this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
|
} else if (this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
|
||||||
digitalWrite(settings.externalPump.pin, LOW);
|
digitalWrite(configuredGpio, LOW);
|
||||||
|
|
||||||
vars.states.externalPump = false;
|
vars.states.externalPump = false;
|
||||||
vars.parameters.extPumpLastEnableTime = millis();
|
vars.parameters.extPumpLastEnableTime = millis();
|
||||||
@@ -324,7 +368,7 @@ protected:
|
|||||||
this->externalPumpStartTime = millis();
|
this->externalPumpStartTime = millis();
|
||||||
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
|
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
|
||||||
|
|
||||||
digitalWrite(settings.externalPump.pin, HIGH);
|
digitalWrite(configuredGpio, HIGH);
|
||||||
|
|
||||||
Log.sinfoln("EXTPUMP", F("Enabled: heating on"));
|
Log.sinfoln("EXTPUMP", F("Enabled: heating on"));
|
||||||
|
|
||||||
@@ -333,7 +377,7 @@ protected:
|
|||||||
this->externalPumpStartTime = millis();
|
this->externalPumpStartTime = millis();
|
||||||
this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK;
|
this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK;
|
||||||
|
|
||||||
digitalWrite(settings.externalPump.pin, HIGH);
|
digitalWrite(configuredGpio, HIGH);
|
||||||
|
|
||||||
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
|
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
|
||||||
}
|
}
|
||||||
|
|||||||
215
src/MqttTask.h
215
src/MqttTask.h
@@ -20,6 +20,11 @@ public:
|
|||||||
if (this->client != nullptr) {
|
if (this->client != nullptr) {
|
||||||
if (this->client->connected()) {
|
if (this->client->connected()) {
|
||||||
this->client->stop();
|
this->client->stop();
|
||||||
|
|
||||||
|
if (this->connected) {
|
||||||
|
this->onDisconnect();
|
||||||
|
this->connected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this->client;
|
delete this->client;
|
||||||
@@ -31,6 +36,12 @@ public:
|
|||||||
|
|
||||||
void disable() {
|
void disable() {
|
||||||
this->client->stop();
|
this->client->stop();
|
||||||
|
|
||||||
|
if (this->connected) {
|
||||||
|
this->onDisconnect();
|
||||||
|
this->connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
Task::disable();
|
Task::disable();
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_MQTT), F("Disabled"));
|
Log.sinfoln(FPSTR(L_MQTT), F("Disabled"));
|
||||||
@@ -42,15 +53,25 @@ public:
|
|||||||
Log.sinfoln(FPSTR(L_MQTT), F("Enabled"));
|
Log.sinfoln(FPSTR(L_MQTT), F("Enabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConnected() {
|
inline bool isConnected() {
|
||||||
return this->connected;
|
return this->connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void resetPublishedSettingsTime() {
|
||||||
|
this->prevPubSettingsTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void resetPublishedVarsTime() {
|
||||||
|
this->prevPubVarsTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MqttWiFiClient* wifiClient = nullptr;
|
MqttWiFiClient* wifiClient = nullptr;
|
||||||
MqttClient* client = nullptr;
|
MqttClient* client = nullptr;
|
||||||
HaHelper* haHelper = nullptr;
|
HaHelper* haHelper = nullptr;
|
||||||
MqttWriter* writer = nullptr;
|
MqttWriter* writer = nullptr;
|
||||||
|
UnitSystem currentUnitSystem = UnitSystem::METRIC;
|
||||||
|
bool currentHomeAssistantDiscovery = false;
|
||||||
unsigned short readyForSendTime = 15000;
|
unsigned short readyForSendTime = 15000;
|
||||||
unsigned long lastReconnectTime = 0;
|
unsigned long lastReconnectTime = 0;
|
||||||
unsigned long connectedTime = 0;
|
unsigned long connectedTime = 0;
|
||||||
@@ -60,19 +81,21 @@ protected:
|
|||||||
bool connected = false;
|
bool connected = false;
|
||||||
bool newConnection = false;
|
bool newConnection = false;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Mqtt";
|
return "Mqtt";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool isReadyForSend() {
|
inline bool isReadyForSend() {
|
||||||
return millis() - this->connectedTime > this->readyForSendTime;
|
return millis() - this->connectedTime > this->readyForSendTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,13 +198,15 @@ protected:
|
|||||||
this->onConnect();
|
this->onConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->connected && settings.emergency.enable && !vars.states.emergency && millis() - this->disconnectedTime > EMERGENCY_TIME_TRESHOLD) {
|
if (settings.emergency.enable && settings.emergency.onMqttFault) {
|
||||||
vars.states.emergency = true;
|
if (!this->connected && !vars.states.emergency && millis() - this->disconnectedTime > (settings.emergency.tresholdTime * 1000)) {
|
||||||
Log.sinfoln(FPSTR(L_MQTT), F("Emergency mode enabled"));
|
vars.states.emergency = true;
|
||||||
|
Log.sinfoln(FPSTR(L_MQTT), F("Emergency mode enabled"));
|
||||||
|
|
||||||
} else if (this->connected && vars.states.emergency && millis() - this->connectedTime > 10000) {
|
} else if (this->connected && vars.states.emergency && millis() - this->connectedTime > 10000) {
|
||||||
vars.states.emergency = false;
|
vars.states.emergency = false;
|
||||||
Log.sinfoln(FPSTR(L_MQTT), F("Emergency mode disabled"));
|
Log.sinfoln(FPSTR(L_MQTT), F("Emergency mode disabled"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->connected) {
|
if (!this->connected) {
|
||||||
@@ -213,14 +238,24 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// publish ha entities if not published
|
// publish ha entities if not published
|
||||||
if (this->newConnection) {
|
if (settings.mqtt.homeAssistantDiscovery) {
|
||||||
this->publishHaEntities();
|
if (this->newConnection || !this->currentHomeAssistantDiscovery || this->currentUnitSystem != settings.system.unitSystem) {
|
||||||
this->publishNonStaticHaEntities(true);
|
this->publishHaEntities();
|
||||||
this->newConnection = false;
|
this->publishNonStaticHaEntities(true);
|
||||||
|
this->currentHomeAssistantDiscovery = true;
|
||||||
|
this->currentUnitSystem = settings.system.unitSystem;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// publish non static ha entities
|
// publish non static ha entities
|
||||||
this->publishNonStaticHaEntities();
|
this->publishNonStaticHaEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (this->currentHomeAssistantDiscovery) {
|
||||||
|
this->currentHomeAssistantDiscovery = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->newConnection) {
|
||||||
|
this->newConnection = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,61 +311,35 @@ protected:
|
|||||||
Log.swarningln(FPSTR(L_MQTT_MSG), F("Not valid json"));
|
Log.swarningln(FPSTR(L_MQTT_MSG), F("Not valid json"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
if (this->haHelper->getDeviceTopic("state/set").equals(topic)) {
|
if (this->haHelper->getDeviceTopic("state/set").equals(topic)) {
|
||||||
this->writer->publish(this->haHelper->getDeviceTopic("state/set").c_str(), nullptr, 0, true);
|
this->writer->publish(this->haHelper->getDeviceTopic("state/set").c_str(), nullptr, 0, true);
|
||||||
this->updateVariables(doc);
|
|
||||||
|
if (jsonToVars(doc, vars)) {
|
||||||
|
this->resetPublishedVarsTime();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (this->haHelper->getDeviceTopic("settings/set").equals(topic)) {
|
} else if (this->haHelper->getDeviceTopic("settings/set").equals(topic)) {
|
||||||
this->writer->publish(this->haHelper->getDeviceTopic("settings/set").c_str(), nullptr, 0, true);
|
this->writer->publish(this->haHelper->getDeviceTopic("settings/set").c_str(), nullptr, 0, true);
|
||||||
this->updateSettings(doc);
|
|
||||||
|
if (safeJsonToSettings(doc, settings)) {
|
||||||
|
this->resetPublishedSettingsTime();
|
||||||
|
fsSettings.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool updateSettings(JsonDocument& doc) {
|
|
||||||
bool changed = safeJsonToSettings(doc, settings);
|
|
||||||
doc.clear();
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
this->prevPubSettingsTime = 0;
|
|
||||||
fsSettings.update();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool updateVariables(JsonDocument& doc) {
|
|
||||||
bool changed = jsonToVars(doc, vars);
|
|
||||||
doc.clear();
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
this->prevPubVarsTime = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void publishHaEntities() {
|
void publishHaEntities() {
|
||||||
// emergency
|
|
||||||
this->haHelper->publishSwitchEmergency();
|
|
||||||
this->haHelper->publishNumberEmergencyTarget();
|
|
||||||
this->haHelper->publishSwitchEmergencyUseEquitherm();
|
|
||||||
this->haHelper->publishSwitchEmergencyUsePid();
|
|
||||||
|
|
||||||
// heating
|
// heating
|
||||||
this->haHelper->publishSwitchHeating(false);
|
this->haHelper->publishSwitchHeating(false);
|
||||||
this->haHelper->publishSwitchHeatingTurbo();
|
this->haHelper->publishSwitchHeatingTurbo();
|
||||||
this->haHelper->publishNumberHeatingHysteresis();
|
this->haHelper->publishNumberHeatingHysteresis(settings.system.unitSystem);
|
||||||
this->haHelper->publishSensorHeatingSetpoint(false);
|
this->haHelper->publishSensorHeatingSetpoint(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishSensorBoilerHeatingMinTemp(false);
|
this->haHelper->publishSensorBoilerHeatingMinTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishSensorBoilerHeatingMaxTemp(false);
|
this->haHelper->publishSensorBoilerHeatingMaxTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishNumberHeatingMinTemp(false);
|
this->haHelper->publishNumberHeatingMinTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishNumberHeatingMaxTemp(false);
|
this->haHelper->publishNumberHeatingMaxTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishNumberHeatingMaxModulation(false);
|
this->haHelper->publishNumberHeatingMaxModulation(false);
|
||||||
|
|
||||||
// pid
|
// pid
|
||||||
@@ -339,8 +348,8 @@ protected:
|
|||||||
this->haHelper->publishNumberPidFactorI();
|
this->haHelper->publishNumberPidFactorI();
|
||||||
this->haHelper->publishNumberPidFactorD();
|
this->haHelper->publishNumberPidFactorD();
|
||||||
this->haHelper->publishNumberPidDt(false);
|
this->haHelper->publishNumberPidDt(false);
|
||||||
this->haHelper->publishNumberPidMinTemp(false);
|
this->haHelper->publishNumberPidMinTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishNumberPidMaxTemp(false);
|
this->haHelper->publishNumberPidMaxTemp(settings.system.unitSystem, false);
|
||||||
|
|
||||||
// equitherm
|
// equitherm
|
||||||
this->haHelper->publishSwitchEquitherm();
|
this->haHelper->publishSwitchEquitherm();
|
||||||
@@ -348,10 +357,6 @@ protected:
|
|||||||
this->haHelper->publishNumberEquithermFactorK();
|
this->haHelper->publishNumberEquithermFactorK();
|
||||||
this->haHelper->publishNumberEquithermFactorT();
|
this->haHelper->publishNumberEquithermFactorT();
|
||||||
|
|
||||||
// tuning
|
|
||||||
this->haHelper->publishSwitchTuning();
|
|
||||||
this->haHelper->publishSelectTuningRegulator();
|
|
||||||
|
|
||||||
// states
|
// states
|
||||||
this->haHelper->publishBinSensorStatus();
|
this->haHelper->publishBinSensorStatus();
|
||||||
this->haHelper->publishBinSensorOtStatus();
|
this->haHelper->publishBinSensorOtStatus();
|
||||||
@@ -362,14 +367,16 @@ protected:
|
|||||||
|
|
||||||
// sensors
|
// sensors
|
||||||
this->haHelper->publishSensorModulation(false);
|
this->haHelper->publishSensorModulation(false);
|
||||||
this->haHelper->publishSensorPressure(false);
|
this->haHelper->publishSensorPressure(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishSensorFaultCode();
|
this->haHelper->publishSensorFaultCode();
|
||||||
this->haHelper->publishSensorRssi(false);
|
this->haHelper->publishSensorRssi(false);
|
||||||
this->haHelper->publishSensorUptime(false);
|
this->haHelper->publishSensorUptime(false);
|
||||||
|
|
||||||
// temperatures
|
// temperatures
|
||||||
this->haHelper->publishNumberIndoorTemp();
|
this->haHelper->publishNumberIndoorTemp(settings.system.unitSystem);
|
||||||
this->haHelper->publishSensorHeatingTemp();
|
this->haHelper->publishSensorHeatingTemp(settings.system.unitSystem);
|
||||||
|
this->haHelper->publishSensorHeatingReturnTemp(settings.system.unitSystem, false);
|
||||||
|
this->haHelper->publishSensorExhaustTemp(settings.system.unitSystem, false);
|
||||||
|
|
||||||
// buttons
|
// buttons
|
||||||
this->haHelper->publishButtonRestart(false);
|
this->haHelper->publishButtonRestart(false);
|
||||||
@@ -379,27 +386,36 @@ protected:
|
|||||||
|
|
||||||
bool publishNonStaticHaEntities(bool force = false) {
|
bool publishNonStaticHaEntities(bool force = false) {
|
||||||
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
|
static byte _heatingMinTemp, _heatingMaxTemp, _dhwMinTemp, _dhwMaxTemp = 0;
|
||||||
static bool _isStupidMode, _editableOutdoorTemp, _editableIndoorTemp, _dhwPresent = false;
|
static bool _noRegulators, _editableOutdoorTemp, _editableIndoorTemp, _dhwPresent = false;
|
||||||
|
|
||||||
bool published = false;
|
bool published = false;
|
||||||
bool isStupidMode = !settings.pid.enable && !settings.equitherm.enable;
|
bool noRegulators = !settings.opentherm.nativeHeatingControl && !settings.pid.enable && !settings.equitherm.enable;
|
||||||
byte heatingMinTemp = isStupidMode ? settings.heating.minTemp : 10;
|
byte heatingMinTemp = 0;
|
||||||
byte heatingMaxTemp = isStupidMode ? settings.heating.maxTemp : 30;
|
byte heatingMaxTemp = 0;
|
||||||
bool editableOutdoorTemp = settings.sensors.outdoor.type == 1;
|
bool editableOutdoorTemp = settings.sensors.outdoor.type == SensorType::MANUAL;
|
||||||
bool editableIndoorTemp = settings.sensors.indoor.type == 1;
|
bool editableIndoorTemp = settings.sensors.indoor.type == SensorType::MANUAL;
|
||||||
|
|
||||||
|
if (noRegulators) {
|
||||||
|
heatingMinTemp = settings.heating.minTemp;
|
||||||
|
heatingMaxTemp = settings.heating.maxTemp;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
heatingMinTemp = convertTemp(THERMOSTAT_INDOOR_MIN_TEMP, UnitSystem::METRIC, settings.system.unitSystem);
|
||||||
|
heatingMaxTemp = convertTemp(THERMOSTAT_INDOOR_MAX_TEMP, UnitSystem::METRIC, settings.system.unitSystem);
|
||||||
|
}
|
||||||
|
|
||||||
if (force || _dhwPresent != settings.opentherm.dhwPresent) {
|
if (force || _dhwPresent != settings.opentherm.dhwPresent) {
|
||||||
_dhwPresent = settings.opentherm.dhwPresent;
|
_dhwPresent = settings.opentherm.dhwPresent;
|
||||||
|
|
||||||
if (_dhwPresent) {
|
if (_dhwPresent) {
|
||||||
this->haHelper->publishSwitchDhw(false);
|
this->haHelper->publishSwitchDhw(false);
|
||||||
this->haHelper->publishSensorBoilerDhwMinTemp(false);
|
this->haHelper->publishSensorBoilerDhwMinTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishSensorBoilerDhwMaxTemp(false);
|
this->haHelper->publishSensorBoilerDhwMaxTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishNumberDhwMinTemp(false);
|
this->haHelper->publishNumberDhwMinTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishNumberDhwMaxTemp(false);
|
this->haHelper->publishNumberDhwMaxTemp(settings.system.unitSystem, false);
|
||||||
this->haHelper->publishBinSensorDhw();
|
this->haHelper->publishBinSensorDhw();
|
||||||
this->haHelper->publishSensorDhwTemp();
|
this->haHelper->publishSensorDhwTemp(settings.system.unitSystem);
|
||||||
this->haHelper->publishSensorDhwFlowRate(false);
|
this->haHelper->publishSensorDhwFlowRate(settings.system.unitSystem, false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this->haHelper->deleteSwitchDhw();
|
this->haHelper->deleteSwitchDhw();
|
||||||
@@ -417,30 +433,17 @@ protected:
|
|||||||
published = true;
|
published = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force || _heatingMinTemp != heatingMinTemp || _heatingMaxTemp != heatingMaxTemp) {
|
if (force || _noRegulators != noRegulators || _heatingMinTemp != heatingMinTemp || _heatingMaxTemp != heatingMaxTemp) {
|
||||||
if (settings.heating.target < heatingMinTemp || settings.heating.target > heatingMaxTemp) {
|
|
||||||
settings.heating.target = constrain(settings.heating.target, heatingMinTemp, heatingMaxTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
_heatingMinTemp = heatingMinTemp;
|
_heatingMinTemp = heatingMinTemp;
|
||||||
_heatingMaxTemp = heatingMaxTemp;
|
_heatingMaxTemp = heatingMaxTemp;
|
||||||
_isStupidMode = isStupidMode;
|
_noRegulators = noRegulators;
|
||||||
|
|
||||||
this->haHelper->publishNumberHeatingTarget(heatingMinTemp, heatingMaxTemp, false);
|
this->haHelper->publishNumberHeatingTarget(settings.system.unitSystem, heatingMinTemp, heatingMaxTemp, false);
|
||||||
this->haHelper->publishClimateHeating(
|
this->haHelper->publishClimateHeating(
|
||||||
|
settings.system.unitSystem,
|
||||||
heatingMinTemp,
|
heatingMinTemp,
|
||||||
heatingMaxTemp,
|
heatingMaxTemp,
|
||||||
isStupidMode ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
|
noRegulators ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
|
||||||
);
|
|
||||||
|
|
||||||
published = true;
|
|
||||||
|
|
||||||
} else if (_isStupidMode != isStupidMode) {
|
|
||||||
_isStupidMode = isStupidMode;
|
|
||||||
this->haHelper->publishClimateHeating(
|
|
||||||
heatingMinTemp,
|
|
||||||
heatingMaxTemp,
|
|
||||||
isStupidMode ? HaHelper::TEMP_SOURCE_HEATING : HaHelper::TEMP_SOURCE_INDOOR
|
|
||||||
);
|
);
|
||||||
|
|
||||||
published = true;
|
published = true;
|
||||||
@@ -450,8 +453,8 @@ protected:
|
|||||||
_dhwMinTemp = settings.dhw.minTemp;
|
_dhwMinTemp = settings.dhw.minTemp;
|
||||||
_dhwMaxTemp = settings.dhw.maxTemp;
|
_dhwMaxTemp = settings.dhw.maxTemp;
|
||||||
|
|
||||||
this->haHelper->publishNumberDhwTarget(settings.dhw.minTemp, settings.dhw.maxTemp, false);
|
this->haHelper->publishNumberDhwTarget(settings.system.unitSystem, settings.dhw.minTemp, settings.dhw.maxTemp, false);
|
||||||
this->haHelper->publishClimateDhw(settings.dhw.minTemp, settings.dhw.maxTemp);
|
this->haHelper->publishClimateDhw(settings.system.unitSystem, settings.dhw.minTemp, settings.dhw.maxTemp);
|
||||||
|
|
||||||
published = true;
|
published = true;
|
||||||
}
|
}
|
||||||
@@ -461,10 +464,10 @@ protected:
|
|||||||
|
|
||||||
if (editableOutdoorTemp) {
|
if (editableOutdoorTemp) {
|
||||||
this->haHelper->deleteSensorOutdoorTemp();
|
this->haHelper->deleteSensorOutdoorTemp();
|
||||||
this->haHelper->publishNumberOutdoorTemp();
|
this->haHelper->publishNumberOutdoorTemp(settings.system.unitSystem);
|
||||||
} else {
|
} else {
|
||||||
this->haHelper->deleteNumberOutdoorTemp();
|
this->haHelper->deleteNumberOutdoorTemp();
|
||||||
this->haHelper->publishSensorOutdoorTemp();
|
this->haHelper->publishSensorOutdoorTemp(settings.system.unitSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
published = true;
|
published = true;
|
||||||
@@ -475,10 +478,10 @@ protected:
|
|||||||
|
|
||||||
if (editableIndoorTemp) {
|
if (editableIndoorTemp) {
|
||||||
this->haHelper->deleteSensorIndoorTemp();
|
this->haHelper->deleteSensorIndoorTemp();
|
||||||
this->haHelper->publishNumberIndoorTemp();
|
this->haHelper->publishNumberIndoorTemp(settings.system.unitSystem);
|
||||||
} else {
|
} else {
|
||||||
this->haHelper->deleteNumberIndoorTemp();
|
this->haHelper->deleteNumberIndoorTemp();
|
||||||
this->haHelper->publishSensorIndoorTemp();
|
this->haHelper->publishSensorIndoorTemp(settings.system.unitSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
published = true;
|
published = true;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
196
src/PortalTask.h
196
src/PortalTask.h
@@ -14,7 +14,9 @@ using WebServer = ESP8266WebServer;
|
|||||||
#include <UpgradeHandler.h>
|
#include <UpgradeHandler.h>
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
|
|
||||||
extern Network::Manager* network;
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
|
extern NetworkMgr* network;
|
||||||
extern FileData fsSettings, fsNetworkSettings;
|
extern FileData fsSettings, fsNetworkSettings;
|
||||||
extern MqttTask* tMqtt;
|
extern MqttTask* tMqtt;
|
||||||
|
|
||||||
@@ -53,17 +55,19 @@ protected:
|
|||||||
unsigned long webServerChangeState = 0;
|
unsigned long webServerChangeState = 0;
|
||||||
unsigned long dnsServerChangeState = 0;
|
unsigned long dnsServerChangeState = 0;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Portal";
|
return "Portal";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
this->dnsServer->setTTL(0);
|
this->dnsServer->setTTL(0);
|
||||||
@@ -86,9 +90,21 @@ protected:
|
|||||||
this->webServer->addHandler(indexPage);*/
|
this->webServer->addHandler(indexPage);*/
|
||||||
this->webServer->addHandler(new StaticPage("/", &LittleFS, "/index.html", PORTAL_CACHE));
|
this->webServer->addHandler(new StaticPage("/", &LittleFS, "/index.html", PORTAL_CACHE));
|
||||||
|
|
||||||
|
// dashboard page
|
||||||
|
auto dashboardPage = (new StaticPage("/dashboard.html", &LittleFS, "/dashboard.html", PORTAL_CACHE))
|
||||||
|
->setBeforeSendCallback([this]() {
|
||||||
|
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
|
this->webServer->requestAuthentication(DIGEST_AUTH);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
this->webServer->addHandler(dashboardPage);
|
||||||
|
|
||||||
// restart
|
// restart
|
||||||
this->webServer->on("/restart.html", HTTP_GET, [this]() {
|
this->webServer->on("/restart.html", HTTP_GET, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
this->webServer->send(401);
|
this->webServer->send(401);
|
||||||
return;
|
return;
|
||||||
@@ -103,7 +119,7 @@ protected:
|
|||||||
// network settings page
|
// network settings page
|
||||||
auto networkPage = (new StaticPage("/network.html", &LittleFS, "/network.html", PORTAL_CACHE))
|
auto networkPage = (new StaticPage("/network.html", &LittleFS, "/network.html", PORTAL_CACHE))
|
||||||
->setBeforeSendCallback([this]() {
|
->setBeforeSendCallback([this]() {
|
||||||
if (this->isNeedAuth() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
this->webServer->requestAuthentication(DIGEST_AUTH);
|
this->webServer->requestAuthentication(DIGEST_AUTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -115,7 +131,7 @@ protected:
|
|||||||
// settings page
|
// settings page
|
||||||
auto settingsPage = (new StaticPage("/settings.html", &LittleFS, "/settings.html", PORTAL_CACHE))
|
auto settingsPage = (new StaticPage("/settings.html", &LittleFS, "/settings.html", PORTAL_CACHE))
|
||||||
->setBeforeSendCallback([this]() {
|
->setBeforeSendCallback([this]() {
|
||||||
if (this->isNeedAuth() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
this->webServer->requestAuthentication(DIGEST_AUTH);
|
this->webServer->requestAuthentication(DIGEST_AUTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -127,7 +143,7 @@ protected:
|
|||||||
// upgrade page
|
// upgrade page
|
||||||
auto upgradePage = (new StaticPage("/upgrade.html", &LittleFS, "/upgrade.html", PORTAL_CACHE))
|
auto upgradePage = (new StaticPage("/upgrade.html", &LittleFS, "/upgrade.html", PORTAL_CACHE))
|
||||||
->setBeforeSendCallback([this]() {
|
->setBeforeSendCallback([this]() {
|
||||||
if (this->isNeedAuth() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
this->webServer->requestAuthentication(DIGEST_AUTH);
|
this->webServer->requestAuthentication(DIGEST_AUTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -138,7 +154,7 @@ protected:
|
|||||||
|
|
||||||
// OTA
|
// OTA
|
||||||
auto upgradeHandler = (new UpgradeHandler("/api/upgrade"))->setCanUploadCallback([this](const String& uri) {
|
auto upgradeHandler = (new UpgradeHandler("/api/upgrade"))->setCanUploadCallback([this](const String& uri) {
|
||||||
if (this->isNeedAuth() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
this->webServer->sendHeader("Connection", "close");
|
this->webServer->sendHeader("Connection", "close");
|
||||||
this->webServer->send(401);
|
this->webServer->send(401);
|
||||||
return false;
|
return false;
|
||||||
@@ -172,7 +188,7 @@ protected:
|
|||||||
|
|
||||||
// backup
|
// backup
|
||||||
this->webServer->on("/api/backup/save", HTTP_GET, [this]() {
|
this->webServer->on("/api/backup/save", HTTP_GET, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -196,7 +212,7 @@ protected:
|
|||||||
});
|
});
|
||||||
|
|
||||||
this->webServer->on("/api/backup/restore", HTTP_POST, [this]() {
|
this->webServer->on("/api/backup/restore", HTTP_POST, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -253,7 +269,7 @@ protected:
|
|||||||
|
|
||||||
// network
|
// network
|
||||||
this->webServer->on("/api/network/settings", HTTP_GET, [this]() {
|
this->webServer->on("/api/network/settings", HTTP_GET, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -267,7 +283,7 @@ protected:
|
|||||||
});
|
});
|
||||||
|
|
||||||
this->webServer->on("/api/network/settings", HTTP_POST, [this]() {
|
this->webServer->on("/api/network/settings", HTTP_POST, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -298,8 +314,14 @@ protected:
|
|||||||
doc.clear();
|
doc.clear();
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
networkSettingsToJson(networkSettings, doc);
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc);
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this->webServer->send(201);
|
doc.clear();
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
fsNetworkSettings.update();
|
fsNetworkSettings.update();
|
||||||
network->setHostname(networkSettings.hostname)
|
network->setHostname(networkSettings.hostname)
|
||||||
@@ -312,33 +334,11 @@ protected:
|
|||||||
networkSettings.staticConfig.dns
|
networkSettings.staticConfig.dns
|
||||||
)
|
)
|
||||||
->reconnect();
|
->reconnect();
|
||||||
|
|
||||||
} else {
|
|
||||||
this->webServer->send(200);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->webServer->on("/api/network/status", HTTP_GET, [this]() {
|
|
||||||
bool isConnected = network->isConnected();
|
|
||||||
|
|
||||||
JsonDocument doc;
|
|
||||||
doc["hostname"] = networkSettings.hostname;
|
|
||||||
doc["mac"] = network->getStaMac();
|
|
||||||
doc["isConnected"] = isConnected;
|
|
||||||
doc["ssid"] = network->getStaSsid();
|
|
||||||
doc["signalQuality"] = isConnected ? Network::Manager::rssiToSignalQuality(network->getRssi()) : 0;
|
|
||||||
doc["channel"] = isConnected ? network->getStaChannel() : 0;
|
|
||||||
doc["ip"] = isConnected ? network->getStaIp().toString() : "";
|
|
||||||
doc["subnet"] = isConnected ? network->getStaSubnet().toString() : "";
|
|
||||||
doc["gateway"] = isConnected ? network->getStaGateway().toString() : "";
|
|
||||||
doc["dns"] = isConnected ? network->getStaDns().toString() : "";
|
|
||||||
doc.shrinkToFit();
|
|
||||||
|
|
||||||
this->bufferedWebServer->send(200, "application/json", doc);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->webServer->on("/api/network/scan", HTTP_GET, [this]() {
|
this->webServer->on("/api/network/scan", HTTP_GET, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
this->webServer->send(401);
|
this->webServer->send(401);
|
||||||
return;
|
return;
|
||||||
@@ -348,7 +348,11 @@ protected:
|
|||||||
auto apCount = WiFi.scanComplete();
|
auto apCount = WiFi.scanComplete();
|
||||||
if (apCount <= 0) {
|
if (apCount <= 0) {
|
||||||
if (apCount != WIFI_SCAN_RUNNING) {
|
if (apCount != WIFI_SCAN_RUNNING) {
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
WiFi.scanNetworks(true, true);
|
WiFi.scanNetworks(true, true);
|
||||||
|
#else
|
||||||
|
WiFi.scanNetworks(true, true, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
this->webServer->send(404);
|
this->webServer->send(404);
|
||||||
@@ -359,10 +363,16 @@ protected:
|
|||||||
for (short int i = 0; i < apCount; i++) {
|
for (short int i = 0; i < apCount; i++) {
|
||||||
String ssid = WiFi.SSID(i);
|
String ssid = WiFi.SSID(i);
|
||||||
doc[i]["ssid"] = ssid;
|
doc[i]["ssid"] = ssid;
|
||||||
doc[i]["signalQuality"] = Network::Manager::rssiToSignalQuality(WiFi.RSSI(i));
|
doc[i]["bssid"] = WiFi.BSSIDstr(i);
|
||||||
|
doc[i]["signalQuality"] = NetworkMgr::rssiToSignalQuality(WiFi.RSSI(i));
|
||||||
doc[i]["channel"] = WiFi.channel(i);
|
doc[i]["channel"] = WiFi.channel(i);
|
||||||
doc[i]["hidden"] = !ssid.length();
|
doc[i]["hidden"] = !ssid.length();
|
||||||
doc[i]["encryptionType"] = WiFi.encryptionType(i);
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
const bss_info* info = WiFi.getScanInfoByIndex(i);
|
||||||
|
doc[i]["auth"] = info->authmode;
|
||||||
|
#else
|
||||||
|
doc[i]["auth"] = WiFi.encryptionType(i);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
@@ -374,7 +384,7 @@ protected:
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
this->webServer->on("/api/settings", HTTP_GET, [this]() {
|
this->webServer->on("/api/settings", HTTP_GET, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -388,7 +398,7 @@ protected:
|
|||||||
});
|
});
|
||||||
|
|
||||||
this->webServer->on("/api/settings", HTTP_POST, [this]() {
|
this->webServer->on("/api/settings", HTTP_POST, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -419,12 +429,17 @@ protected:
|
|||||||
doc.clear();
|
doc.clear();
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
if (changed) {
|
settingsToJson(settings, doc);
|
||||||
fsSettings.update();
|
doc.shrinkToFit();
|
||||||
this->webServer->send(201);
|
|
||||||
|
|
||||||
} else {
|
this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc);
|
||||||
this->webServer->send(200);
|
|
||||||
|
if (changed) {
|
||||||
|
doc.clear();
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
fsSettings.update();
|
||||||
|
tMqtt->resetPublishedSettingsTime();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -433,24 +448,13 @@ protected:
|
|||||||
this->webServer->on("/api/vars", HTTP_GET, [this]() {
|
this->webServer->on("/api/vars", HTTP_GET, [this]() {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
varsToJson(vars, doc);
|
varsToJson(vars, doc);
|
||||||
|
|
||||||
doc["system"]["version"] = PROJECT_VERSION;
|
|
||||||
doc["system"]["buildDate"] = __DATE__ " " __TIME__;
|
|
||||||
doc["system"]["uptime"] = millis() / 1000ul;
|
|
||||||
doc["system"]["totalHeap"] = getTotalHeap();
|
|
||||||
doc["system"]["freeHeap"] = getFreeHeap();
|
|
||||||
doc["system"]["minFreeHeap"] = getFreeHeap(true);
|
|
||||||
doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap();
|
|
||||||
doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true);
|
|
||||||
doc["system"]["resetReason"] = getResetReason();
|
|
||||||
doc["system"]["mqttConnected"] = tMqtt->isConnected();
|
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
this->bufferedWebServer->send(200, "application/json", doc);
|
this->bufferedWebServer->send(200, "application/json", doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
this->webServer->on("/api/vars", HTTP_POST, [this]() {
|
this->webServer->on("/api/vars", HTTP_POST, [this]() {
|
||||||
if (this->isNeedAuth()) {
|
if (this->isAuthRequired()) {
|
||||||
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
|
||||||
return this->webServer->send(401);
|
return this->webServer->send(401);
|
||||||
}
|
}
|
||||||
@@ -481,14 +485,76 @@ protected:
|
|||||||
doc.clear();
|
doc.clear();
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
if (changed) {
|
varsToJson(vars, doc);
|
||||||
this->webServer->send(201);
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
this->bufferedWebServer->send(changed ? 201 : 200, "application/json", doc);
|
||||||
|
|
||||||
} else {
|
if (changed) {
|
||||||
this->webServer->send(200);
|
doc.clear();
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
tMqtt->resetPublishedVarsTime();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this->webServer->on("/api/info", HTTP_GET, [this]() {
|
||||||
|
bool isConnected = network->isConnected();
|
||||||
|
|
||||||
|
JsonDocument doc;
|
||||||
|
doc["network"]["hostname"] = networkSettings.hostname;
|
||||||
|
doc["network"]["mac"] = network->getStaMac();
|
||||||
|
doc["network"]["connected"] = isConnected;
|
||||||
|
doc["network"]["ssid"] = network->getStaSsid();
|
||||||
|
doc["network"]["signalQuality"] = isConnected ? NetworkMgr::rssiToSignalQuality(network->getRssi()) : 0;
|
||||||
|
doc["network"]["channel"] = isConnected ? network->getStaChannel() : 0;
|
||||||
|
doc["network"]["ip"] = isConnected ? network->getStaIp().toString() : "";
|
||||||
|
doc["network"]["subnet"] = isConnected ? network->getStaSubnet().toString() : "";
|
||||||
|
doc["network"]["gateway"] = isConnected ? network->getStaGateway().toString() : "";
|
||||||
|
doc["network"]["dns"] = isConnected ? network->getStaDns().toString() : "";
|
||||||
|
|
||||||
|
doc["system"]["version"] = PROJECT_VERSION;
|
||||||
|
doc["system"]["buildDate"] = __DATE__ " " __TIME__;
|
||||||
|
doc["system"]["uptime"] = millis() / 1000ul;
|
||||||
|
doc["system"]["totalHeap"] = getTotalHeap();
|
||||||
|
doc["system"]["freeHeap"] = getFreeHeap();
|
||||||
|
doc["system"]["minFreeHeap"] = getFreeHeap(true);
|
||||||
|
doc["system"]["maxFreeBlockHeap"] = getMaxFreeBlockHeap();
|
||||||
|
doc["system"]["minMaxFreeBlockHeap"] = getMaxFreeBlockHeap(true);
|
||||||
|
doc["system"]["resetReason"] = getResetReason();
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
doc["system"]["chipModel"] = esp_is_8285() ? "ESP8285" : "ESP8266";
|
||||||
|
doc["system"]["chipRevision"] = 0;
|
||||||
|
doc["system"]["chipCores"] = 1;
|
||||||
|
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
||||||
|
doc["system"]["coreVersion"] = ESP.getCoreVersion();
|
||||||
|
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
||||||
|
doc["system"]["flashRealSize"] = ESP.getFlashChipRealSize();
|
||||||
|
#elif ARDUINO_ARCH_ESP32
|
||||||
|
doc["system"]["chipModel"] = ESP.getChipModel();
|
||||||
|
doc["system"]["chipRevision"] = ESP.getChipRevision();
|
||||||
|
doc["system"]["chipCores"] = ESP.getChipCores();
|
||||||
|
doc["system"]["cpuFreq"] = ESP.getCpuFreqMHz();
|
||||||
|
doc["system"]["coreVersion"] = ESP.getSdkVersion();
|
||||||
|
doc["system"]["flashSize"] = ESP.getFlashChipSize();
|
||||||
|
doc["system"]["flashRealSize"] = doc["system"]["flashSize"];
|
||||||
|
#else
|
||||||
|
doc["system"]["chipModel"] = 0;
|
||||||
|
doc["system"]["chipRevision"] = 0;
|
||||||
|
doc["system"]["chipCores"] = 0;
|
||||||
|
doc["system"]["cpuFreq"] = 0;
|
||||||
|
doc["system"]["coreVersion"] = 0;
|
||||||
|
doc["system"]["flashSize"] = 0;
|
||||||
|
doc["system"]["flashRealSize"] = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
this->bufferedWebServer->send(200, "application/json", doc);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// not found
|
// not found
|
||||||
this->webServer->onNotFound([this]() {
|
this->webServer->onNotFound([this]() {
|
||||||
@@ -559,8 +625,8 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNeedAuth() {
|
bool isAuthRequired() {
|
||||||
return !network->isApEnabled() && settings.portal.useAuth && strlen(settings.portal.password);
|
return !network->isApEnabled() && settings.portal.auth && strlen(settings.portal.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onCaptivePortal() {
|
void onCaptivePortal() {
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
#include <Equitherm.h>
|
#include <Equitherm.h>
|
||||||
#include <GyverPID.h>
|
#include <GyverPID.h>
|
||||||
#include <PIDtuner.h>
|
|
||||||
|
|
||||||
Equitherm etRegulator;
|
Equitherm etRegulator;
|
||||||
GyverPID pidRegulator(0, 0, 0);
|
GyverPID pidRegulator(0, 0, 0);
|
||||||
PIDtuner pidTuner;
|
|
||||||
|
|
||||||
|
|
||||||
class RegulatorTask : public LeanTask {
|
class RegulatorTask : public LeanTask {
|
||||||
@@ -12,27 +10,26 @@ public:
|
|||||||
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
RegulatorTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool tunerInit = false;
|
|
||||||
byte tunerState = 0;
|
|
||||||
byte tunerRegulator = 0;
|
|
||||||
float prevHeatingTarget = 0;
|
float prevHeatingTarget = 0;
|
||||||
float prevEtResult = 0;
|
float prevEtResult = 0;
|
||||||
float prevPidResult = 0;
|
float prevPidResult = 0;
|
||||||
|
|
||||||
const char* getTaskName() {
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const char* getTaskName() override {
|
||||||
return "Regulator";
|
return "Regulator";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
/*BaseType_t getTaskCore() override {
|
||||||
return 1;
|
return 1;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
byte newTemp = vars.parameters.heatingSetpoint;
|
float newTemp = vars.parameters.heatingSetpoint;
|
||||||
|
|
||||||
if (vars.states.emergency) {
|
if (vars.states.emergency) {
|
||||||
if (settings.heating.turbo) {
|
if (settings.heating.turbo) {
|
||||||
@@ -41,74 +38,60 @@ protected:
|
|||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
newTemp = getEmergencyModeTemp();
|
newTemp = this->getEmergencyModeTemp();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (vars.tuning.enable || tunerInit) {
|
if (settings.heating.turbo && (fabs(settings.heating.target - vars.temperatures.indoor) < 1 || !settings.heating.enable || (settings.equitherm.enable && settings.pid.enable))) {
|
||||||
if (settings.heating.turbo) {
|
settings.heating.turbo = false;
|
||||||
settings.heating.turbo = false;
|
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
||||||
}
|
|
||||||
|
|
||||||
newTemp = getTuningModeTemp();
|
|
||||||
|
|
||||||
if (newTemp == 0) {
|
|
||||||
vars.tuning.enable = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vars.tuning.enable) {
|
newTemp = this->getNormalModeTemp();
|
||||||
if (settings.heating.turbo && (fabs(settings.heating.target - vars.temperatures.indoor) < 1 || !settings.heating.enable || (settings.equitherm.enable && settings.pid.enable))) {
|
|
||||||
settings.heating.turbo = false;
|
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("Turbo mode auto disabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
newTemp = getNormalModeTemp();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ограничиваем, если до этого не ограничило
|
// Limits
|
||||||
if (newTemp < settings.heating.minTemp || newTemp > settings.heating.maxTemp) {
|
newTemp = constrain(
|
||||||
newTemp = constrain(newTemp, settings.heating.minTemp, settings.heating.maxTemp);
|
newTemp,
|
||||||
}
|
!settings.opentherm.nativeHeatingControl ? settings.heating.minTemp : THERMOSTAT_INDOOR_MIN_TEMP,
|
||||||
|
!settings.opentherm.nativeHeatingControl ? settings.heating.maxTemp : THERMOSTAT_INDOOR_MAX_TEMP
|
||||||
|
);
|
||||||
|
|
||||||
if (abs(vars.parameters.heatingSetpoint - newTemp) + 0.0001 >= 1) {
|
if (fabs(vars.parameters.heatingSetpoint - newTemp) > 0.4999f) {
|
||||||
vars.parameters.heatingSetpoint = newTemp;
|
vars.parameters.heatingSetpoint = newTemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte getEmergencyModeTemp() {
|
float getEmergencyModeTemp() {
|
||||||
float newTemp = 0;
|
float newTemp = 0;
|
||||||
|
|
||||||
// if use equitherm
|
// if use equitherm
|
||||||
if (settings.emergency.useEquitherm && settings.sensors.outdoor.type != 1) {
|
if (settings.emergency.useEquitherm) {
|
||||||
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
||||||
|
|
||||||
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
|
if (fabs(prevEtResult - etResult) > 0.4999f) {
|
||||||
prevEtResult = etResult;
|
prevEtResult = etResult;
|
||||||
newTemp += etResult;
|
newTemp += etResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New emergency result: %hhu (%.2f)"), (uint8_t) round(etResult), etResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New emergency result: %.2f"), etResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevEtResult;
|
newTemp += prevEtResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(settings.emergency.usePid && settings.sensors.indoor.type != 1) {
|
} else if(settings.emergency.usePid) {
|
||||||
if (vars.parameters.heatingEnabled) {
|
if (vars.parameters.heatingEnabled) {
|
||||||
float pidResult = getPidTemp(
|
float pidResult = getPidTemp(
|
||||||
settings.heating.minTemp,
|
settings.heating.minTemp,
|
||||||
settings.heating.maxTemp
|
settings.heating.maxTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fabs(prevPidResult - pidResult) + 0.0001 >= 0.5) {
|
if (fabs(prevPidResult - pidResult) > 0.4999f) {
|
||||||
prevPidResult = pidResult;
|
prevPidResult = pidResult;
|
||||||
newTemp += pidResult;
|
newTemp += pidResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New emergency result: %hhu (%.2f)"), (uint8_t) round(pidResult), pidResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New emergency result: %.2f"), pidResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevPidResult;
|
newTemp += prevPidResult;
|
||||||
@@ -123,17 +106,17 @@ protected:
|
|||||||
newTemp = settings.emergency.target;
|
newTemp = settings.emergency.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
return round(newTemp);
|
return newTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte getNormalModeTemp() {
|
float getNormalModeTemp() {
|
||||||
float newTemp = 0;
|
float newTemp = 0;
|
||||||
|
|
||||||
if (fabs(prevHeatingTarget - settings.heating.target) > 0.0001) {
|
if (fabs(prevHeatingTarget - settings.heating.target) > 0.0001f) {
|
||||||
prevHeatingTarget = settings.heating.target;
|
prevHeatingTarget = settings.heating.target;
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR), F("New target: %.2f"), settings.heating.target);
|
Log.sinfoln(FPSTR(L_REGULATOR), F("New target: %.2f"), settings.heating.target);
|
||||||
|
|
||||||
if (settings.equitherm.enable && settings.pid.enable) {
|
if (/*settings.equitherm.enable && */settings.pid.enable) {
|
||||||
pidRegulator.integral = 0;
|
pidRegulator.integral = 0;
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
}
|
}
|
||||||
@@ -143,11 +126,11 @@ protected:
|
|||||||
if (settings.equitherm.enable) {
|
if (settings.equitherm.enable) {
|
||||||
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
float etResult = getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp);
|
||||||
|
|
||||||
if (fabs(prevEtResult - etResult) + 0.0001 >= 0.5) {
|
if (fabs(prevEtResult - etResult) > 0.4999f) {
|
||||||
prevEtResult = etResult;
|
prevEtResult = etResult;
|
||||||
newTemp += etResult;
|
newTemp += etResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New result: %hhu (%.2f)"), (uint8_t) round(etResult), etResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_EQUITHERM), F("New result: %.2f"), etResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevEtResult;
|
newTemp += prevEtResult;
|
||||||
@@ -162,11 +145,12 @@ protected:
|
|||||||
settings.pid.maxTemp
|
settings.pid.maxTemp
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fabs(prevPidResult - pidResult) + 0.0001 >= 0.5) {
|
if (fabs(prevPidResult - pidResult) > 0.4999f) {
|
||||||
prevPidResult = pidResult;
|
prevPidResult = pidResult;
|
||||||
newTemp += pidResult;
|
newTemp += pidResult;
|
||||||
|
|
||||||
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New result: %hhd (%.2f)"), (int8_t) round(pidResult), pidResult);
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("New result: %.2f"), pidResult);
|
||||||
|
Log.straceln(FPSTR(L_REGULATOR_PID), F("Integral: %.2f"), pidRegulator.integral);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newTemp += prevPidResult;
|
newTemp += prevPidResult;
|
||||||
@@ -174,6 +158,10 @@ protected:
|
|||||||
} else {
|
} else {
|
||||||
newTemp += prevPidResult;
|
newTemp += prevPidResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (fabs(pidRegulator.integral) > 0.0001f) {
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// default temp, manual mode
|
// default temp, manual mode
|
||||||
@@ -181,108 +169,46 @@ protected:
|
|||||||
newTemp = settings.heating.target;
|
newTemp = settings.heating.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
newTemp = round(newTemp);
|
|
||||||
newTemp = constrain(newTemp, 0, 100);
|
|
||||||
return newTemp;
|
return newTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte getTuningModeTemp() {
|
/**
|
||||||
if (tunerInit && (!vars.tuning.enable || vars.tuning.regulator != tunerRegulator)) {
|
* @brief Get the Equitherm Temp
|
||||||
if (tunerRegulator == 0) {
|
* Calculations in degrees C, conversion occurs when using F
|
||||||
pidTuner.reset();
|
*
|
||||||
}
|
* @param minTemp
|
||||||
|
* @param maxTemp
|
||||||
tunerInit = false;
|
* @return float
|
||||||
tunerRegulator = 0;
|
*/
|
||||||
tunerState = 0;
|
|
||||||
Log.sinfoln("REGULATOR.TUNING", F("Stopped"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vars.tuning.enable) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (vars.tuning.regulator == 0) {
|
|
||||||
// @TODO дописать
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.EQUITHERM", F("Not implemented"));
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} else if (vars.tuning.regulator == 1) {
|
|
||||||
// PID tuner
|
|
||||||
float defaultTemp = settings.equitherm.enable
|
|
||||||
? getEquithermTemp(settings.heating.minTemp, settings.heating.maxTemp)
|
|
||||||
: settings.heating.target;
|
|
||||||
|
|
||||||
if (tunerInit && pidTuner.getState() == 3) {
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Finished"));
|
|
||||||
for (Stream* stream : Log.getStreams()) {
|
|
||||||
pidTuner.debugText(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
pidTuner.reset();
|
|
||||||
tunerInit = false;
|
|
||||||
tunerRegulator = 0;
|
|
||||||
tunerState = 0;
|
|
||||||
|
|
||||||
if (pidTuner.getAccuracy() < 90) {
|
|
||||||
Log.swarningln("REGULATOR.TUNING.PID", F("Bad result, try again..."));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
settings.pid.p_factor = pidTuner.getPID_p();
|
|
||||||
settings.pid.i_factor = pidTuner.getPID_i();
|
|
||||||
settings.pid.d_factor = pidTuner.getPID_d();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tunerInit) {
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Start..."));
|
|
||||||
|
|
||||||
float step;
|
|
||||||
if (vars.temperatures.indoor - vars.temperatures.outdoor > 10) {
|
|
||||||
step = ceil(vars.parameters.heatingSetpoint / vars.temperatures.indoor * 2);
|
|
||||||
} else {
|
|
||||||
step = 5.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float startTemp = step;
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Started. Start value: %f, step: %f"), startTemp, step);
|
|
||||||
pidTuner.setParameters(NORMAL, startTemp, step, 20 * 60 * 1000, 0.15, 60 * 1000, 10000);
|
|
||||||
tunerInit = true;
|
|
||||||
tunerRegulator = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pidTuner.setInput(vars.temperatures.indoor);
|
|
||||||
pidTuner.compute();
|
|
||||||
|
|
||||||
if (tunerState > 0 && pidTuner.getState() != tunerState) {
|
|
||||||
Log.sinfoln("REGULATOR.TUNING.PID", F("Log:"));
|
|
||||||
for (Stream* stream : Log.getStreams()) {
|
|
||||||
pidTuner.debugText(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
tunerState = pidTuner.getState();
|
|
||||||
}
|
|
||||||
|
|
||||||
return round(defaultTemp + pidTuner.getOutput());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float getEquithermTemp(int minTemp, int maxTemp) {
|
float getEquithermTemp(int minTemp, int maxTemp) {
|
||||||
|
float targetTemp = vars.states.emergency ? settings.emergency.target : settings.heating.target;
|
||||||
|
float indoorTemp = vars.temperatures.indoor;
|
||||||
|
float outdoorTemp = vars.temperatures.outdoor;
|
||||||
|
|
||||||
|
if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
|
||||||
|
minTemp = f2c(minTemp);
|
||||||
|
maxTemp = f2c(maxTemp);
|
||||||
|
targetTemp = f2c(targetTemp);
|
||||||
|
indoorTemp = f2c(indoorTemp);
|
||||||
|
outdoorTemp = f2c(outdoorTemp);
|
||||||
|
}
|
||||||
|
|
||||||
if (vars.states.emergency) {
|
if (vars.states.emergency) {
|
||||||
etRegulator.Kt = 0;
|
if (settings.sensors.indoor.type == SensorType::MANUAL) {
|
||||||
etRegulator.indoorTemp = 0;
|
etRegulator.Kt = 0;
|
||||||
etRegulator.outdoorTemp = vars.temperatures.outdoor;
|
etRegulator.indoorTemp = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
etRegulator.Kt = settings.equitherm.t_factor;
|
||||||
|
etRegulator.indoorTemp = indoorTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
etRegulator.outdoorTemp = outdoorTemp;
|
||||||
|
|
||||||
} else if (settings.pid.enable) {
|
} else if (settings.pid.enable) {
|
||||||
etRegulator.Kt = 0;
|
etRegulator.Kt = 0;
|
||||||
etRegulator.indoorTemp = round(vars.temperatures.indoor);
|
etRegulator.indoorTemp = round(indoorTemp);
|
||||||
etRegulator.outdoorTemp = round(vars.temperatures.outdoor);
|
etRegulator.outdoorTemp = round(outdoorTemp);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (settings.heating.turbo) {
|
if (settings.heating.turbo) {
|
||||||
@@ -290,23 +216,41 @@ protected:
|
|||||||
} else {
|
} else {
|
||||||
etRegulator.Kt = settings.equitherm.t_factor;
|
etRegulator.Kt = settings.equitherm.t_factor;
|
||||||
}
|
}
|
||||||
etRegulator.indoorTemp = vars.temperatures.indoor;
|
etRegulator.indoorTemp = indoorTemp;
|
||||||
etRegulator.outdoorTemp = vars.temperatures.outdoor;
|
etRegulator.outdoorTemp = outdoorTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
etRegulator.setLimits(minTemp, maxTemp);
|
etRegulator.setLimits(minTemp, maxTemp);
|
||||||
etRegulator.Kn = settings.equitherm.n_factor;
|
etRegulator.Kn = settings.equitherm.n_factor;
|
||||||
// etRegulator.Kn = tuneEquithermN(etRegulator.Kn, vars.temperatures.indoor, settings.heating.target, 300, 1800, 0.01, 1);
|
|
||||||
etRegulator.Kk = settings.equitherm.k_factor;
|
etRegulator.Kk = settings.equitherm.k_factor;
|
||||||
etRegulator.targetTemp = vars.states.emergency ? settings.emergency.target : settings.heating.target;
|
etRegulator.targetTemp = targetTemp;
|
||||||
|
float result = etRegulator.getResult();
|
||||||
|
|
||||||
return etRegulator.getResult();
|
if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
|
||||||
|
result = c2f(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getPidTemp(int minTemp, int maxTemp) {
|
float getPidTemp(int minTemp, int maxTemp) {
|
||||||
pidRegulator.Kp = settings.pid.p_factor;
|
if (fabs(pidRegulator.Kp - settings.pid.p_factor) >= 0.0001f) {
|
||||||
pidRegulator.Ki = settings.pid.i_factor;
|
pidRegulator.Kp = settings.pid.p_factor;
|
||||||
pidRegulator.Kd = settings.pid.d_factor;
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(pidRegulator.Ki - settings.pid.i_factor) >= 0.0001f) {
|
||||||
|
pidRegulator.Ki = settings.pid.i_factor;
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(pidRegulator.Kd - settings.pid.d_factor) >= 0.0001f) {
|
||||||
|
pidRegulator.Kd = settings.pid.d_factor;
|
||||||
|
pidRegulator.integral = 0;
|
||||||
|
Log.sinfoln(FPSTR(L_REGULATOR_PID), F("Integral sum has been reset"));
|
||||||
|
}
|
||||||
|
|
||||||
pidRegulator.setLimits(minTemp, maxTemp);
|
pidRegulator.setLimits(minTemp, maxTemp);
|
||||||
pidRegulator.setDt(settings.pid.dt * 1000u);
|
pidRegulator.setDt(settings.pid.dt * 1000u);
|
||||||
@@ -315,32 +259,4 @@ protected:
|
|||||||
|
|
||||||
return pidRegulator.getResultTimer();
|
return pidRegulator.getResultTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
float tuneEquithermN(float ratio, float currentTemp, float setTemp, unsigned int dirtyInterval = 60, unsigned int accurateInterval = 1800, float accurateStep = 0.01, float accurateStepAfter = 1) {
|
|
||||||
static uint32_t _prevIteration = millis();
|
|
||||||
|
|
||||||
if (abs(currentTemp - setTemp) < accurateStepAfter) {
|
|
||||||
if (millis() - _prevIteration < (accurateInterval * 1000)) {
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentTemp - setTemp > 0.1f) {
|
|
||||||
ratio -= accurateStep;
|
|
||||||
|
|
||||||
} else if (currentTemp - setTemp < -0.1f) {
|
|
||||||
ratio += accurateStep;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (millis() - _prevIteration < (dirtyInterval * 1000)) {
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
ratio = ratio * (setTemp / currentTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
_prevIteration = millis();
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,61 +32,95 @@ protected:
|
|||||||
DallasTemperature* indoorSensor = nullptr;
|
DallasTemperature* indoorSensor = nullptr;
|
||||||
|
|
||||||
bool initOutdoorSensor = false;
|
bool initOutdoorSensor = false;
|
||||||
|
unsigned long initOutdoorSensorTime = 0;
|
||||||
unsigned long startOutdoorConversionTime = 0;
|
unsigned long startOutdoorConversionTime = 0;
|
||||||
float filteredOutdoorTemp = 0;
|
float filteredOutdoorTemp = 0;
|
||||||
bool emptyOutdoorTemp = true;
|
bool emptyOutdoorTemp = true;
|
||||||
|
|
||||||
bool initIndoorSensor = false;
|
bool initIndoorSensor = false;
|
||||||
|
unsigned long initIndoorSensorTime = 0;
|
||||||
unsigned long startIndoorConversionTime = 0;
|
unsigned long startIndoorConversionTime = 0;
|
||||||
float filteredIndoorTemp = 0;
|
float filteredIndoorTemp = 0;
|
||||||
bool emptyIndoorTemp = true;
|
bool emptyIndoorTemp = true;
|
||||||
|
|
||||||
#if USE_BLE
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
#if USE_BLE
|
||||||
BLEClient* pBleClient = nullptr;
|
BLEClient* pBleClient = nullptr;
|
||||||
bool initBleSensor = false;
|
bool initBleSensor = false;
|
||||||
bool initBleNotify = false;
|
bool initBleNotify = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* getTaskName() {
|
const char* getTaskName() override {
|
||||||
return "Sensors";
|
return "Sensors";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int getTaskCore() {
|
BaseType_t getTaskCore() override {
|
||||||
return 1;
|
// https://github.com/h2zero/NimBLE-Arduino/issues/676
|
||||||
}*/
|
#if USE_BLE && defined(CONFIG_BT_NIMBLE_PINNED_TO_CORE)
|
||||||
|
return CONFIG_BT_NIMBLE_PINNED_TO_CORE;
|
||||||
|
#else
|
||||||
|
return tskNO_AFFINITY;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int getTaskPriority() {
|
int getTaskPriority() override {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (settings.sensors.outdoor.type == 2 && settings.sensors.outdoor.pin) {
|
bool indoorTempUpdated = false;
|
||||||
|
bool outdoorTempUpdated = false;
|
||||||
|
|
||||||
|
if (settings.sensors.outdoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.outdoor.gpio)) {
|
||||||
outdoorTemperatureSensor();
|
outdoorTemperatureSensor();
|
||||||
|
outdoorTempUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.sensors.indoor.type == 2 && settings.sensors.indoor.pin) {
|
if (settings.sensors.indoor.type == SensorType::DS18B20 && GPIO_IS_VALID(settings.sensors.indoor.gpio)) {
|
||||||
indoorTemperatureSensor();
|
indoorTemperatureSensor();
|
||||||
|
indoorTempUpdated = true;
|
||||||
|
}
|
||||||
|
#if USE_BLE
|
||||||
|
else if (settings.sensors.indoor.type == SensorType::BLUETOOTH) {
|
||||||
|
indoorTemperatureBluetoothSensor();
|
||||||
|
indoorTempUpdated = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (outdoorTempUpdated) {
|
||||||
|
float newTemp = settings.sensors.outdoor.offset;
|
||||||
|
if (settings.system.unitSystem == UnitSystem::METRIC) {
|
||||||
|
newTemp += this->filteredOutdoorTemp;
|
||||||
|
|
||||||
|
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
|
||||||
|
newTemp += c2f(this->filteredOutdoorTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(vars.temperatures.outdoor - newTemp) > 0.099f) {
|
||||||
|
vars.temperatures.outdoor = newTemp;
|
||||||
|
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_BLE
|
if (indoorTempUpdated) {
|
||||||
if (settings.sensors.indoor.type == 3) {
|
float newTemp = settings.sensors.indoor.offset;
|
||||||
bluetoothSensor();
|
if (settings.system.unitSystem == UnitSystem::METRIC) {
|
||||||
}
|
newTemp += this->filteredIndoorTemp;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fabs(vars.temperatures.outdoor - this->filteredOutdoorTemp) > 0.099) {
|
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
|
||||||
vars.temperatures.outdoor = this->filteredOutdoorTemp + settings.sensors.outdoor.offset;
|
newTemp += c2f(this->filteredIndoorTemp);
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (fabs(vars.temperatures.indoor - this->filteredIndoorTemp) > 0.099) {
|
if (fabs(vars.temperatures.indoor - newTemp) > 0.099f) {
|
||||||
vars.temperatures.indoor = this->filteredIndoorTemp + settings.sensors.indoor.offset;
|
vars.temperatures.indoor = newTemp;
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
|
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_BLE
|
#if USE_BLE
|
||||||
void bluetoothSensor() {
|
void indoorTemperatureBluetoothSensor() {
|
||||||
static bool initBleNotify = false;
|
static bool initBleNotify = false;
|
||||||
if (!initBleSensor && millis() > 5000) {
|
if (!initBleSensor && millis() > 5000) {
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_BLE), F("Init BLE"));
|
Log.sinfoln(FPSTR(L_SENSORS_BLE), F("Init BLE"));
|
||||||
@@ -136,7 +170,7 @@ protected:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.01);
|
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.01f);
|
||||||
Log.straceln(FPSTR(L_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp);
|
Log.straceln(FPSTR(L_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp);
|
||||||
|
|
||||||
if (this->emptyIndoorTemp) {
|
if (this->emptyIndoorTemp) {
|
||||||
@@ -204,10 +238,16 @@ protected:
|
|||||||
|
|
||||||
void outdoorTemperatureSensor() {
|
void outdoorTemperatureSensor() {
|
||||||
if (!this->initOutdoorSensor) {
|
if (!this->initOutdoorSensor) {
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("Starting on gpio %hhu..."), settings.sensors.outdoor.pin);
|
if (this->initOutdoorSensorTime && millis() - this->initOutdoorSensorTime < EXT_SENSORS_INTERVAL * 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.pin);
|
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("Starting on GPIO %hhu..."), settings.sensors.outdoor.gpio);
|
||||||
|
|
||||||
|
this->oneWireOutdoorSensor->begin(settings.sensors.outdoor.gpio);
|
||||||
|
this->oneWireOutdoorSensor->reset();
|
||||||
this->outdoorSensor->begin();
|
this->outdoorSensor->begin();
|
||||||
|
this->initOutdoorSensorTime = millis();
|
||||||
|
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_OUTDOOR),
|
FPSTR(L_SENSORS_OUTDOOR),
|
||||||
@@ -270,10 +310,16 @@ protected:
|
|||||||
|
|
||||||
void indoorTemperatureSensor() {
|
void indoorTemperatureSensor() {
|
||||||
if (!this->initIndoorSensor) {
|
if (!this->initIndoorSensor) {
|
||||||
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("Starting on gpio %hhu..."), settings.sensors.indoor.pin);
|
if (this->initIndoorSensorTime && millis() - this->initIndoorSensorTime < EXT_SENSORS_INTERVAL * 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("Starting on GPIO %hhu..."), settings.sensors.indoor.gpio);
|
||||||
|
|
||||||
this->oneWireIndoorSensor->begin(settings.sensors.indoor.pin);
|
this->oneWireIndoorSensor->begin(settings.sensors.indoor.gpio);
|
||||||
|
this->oneWireIndoorSensor->reset();
|
||||||
this->indoorSensor->begin();
|
this->indoorSensor->begin();
|
||||||
|
this->initIndoorSensorTime = millis();
|
||||||
|
|
||||||
Log.straceln(
|
Log.straceln(
|
||||||
FPSTR(L_SENSORS_INDOOR),
|
FPSTR(L_SENSORS_INDOOR),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
struct NetworkSettings {
|
struct NetworkSettings {
|
||||||
char hostname[25] = HOSTNAME_DEFAULT;
|
char hostname[25] = DEFAULT_HOSTNAME;
|
||||||
bool useDhcp = true;
|
bool useDhcp = true;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -10,14 +10,14 @@ struct NetworkSettings {
|
|||||||
} staticConfig;
|
} staticConfig;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
char ssid[33] = AP_SSID_DEFAULT;
|
char ssid[33] = DEFAULT_AP_SSID;
|
||||||
char password[65] = AP_PASSWORD_DEFAULT;
|
char password[65] = DEFAULT_AP_PASSWORD;
|
||||||
byte channel = 6;
|
byte channel = 6;
|
||||||
} ap;
|
} ap;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
char ssid[33] = STA_SSID_DEFAULT;
|
char ssid[33] = DEFAULT_STA_SSID;
|
||||||
char password[65] = STA_PASSWORD_DEFAULT;
|
char password[65] = DEFAULT_STA_PASSWORD;
|
||||||
byte channel = 0;
|
byte channel = 0;
|
||||||
} sta;
|
} sta;
|
||||||
} networkSettings;
|
} networkSettings;
|
||||||
@@ -25,19 +25,34 @@ struct NetworkSettings {
|
|||||||
struct Settings {
|
struct Settings {
|
||||||
struct {
|
struct {
|
||||||
bool debug = DEBUG_BY_DEFAULT;
|
bool debug = DEBUG_BY_DEFAULT;
|
||||||
bool useSerial = USE_SERIAL;
|
|
||||||
bool useTelnet = USE_TELNET;
|
struct {
|
||||||
|
bool enable = USE_SERIAL;
|
||||||
|
unsigned int baudrate = 115200;
|
||||||
|
} serial;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool enable = USE_TELNET;
|
||||||
|
unsigned short port = 23;
|
||||||
|
} telnet;
|
||||||
|
|
||||||
|
UnitSystem unitSystem = UnitSystem::METRIC;
|
||||||
|
byte statusLedGpio = DEFAULT_STATUS_LED_GPIO;
|
||||||
} system;
|
} system;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool useAuth = false;
|
bool auth = false;
|
||||||
char login[13] = PORTAL_LOGIN_DEFAULT;
|
char login[13] = DEFAULT_PORTAL_LOGIN;
|
||||||
char password[33] = PORTAL_PASSWORD_DEFAULT;
|
char password[33] = DEFAULT_PORTAL_PASSWORD;
|
||||||
} portal;
|
} portal;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
byte inPin = OT_IN_PIN_DEFAULT;
|
UnitSystem unitSystem = UnitSystem::METRIC;
|
||||||
byte outPin = OT_OUT_PIN_DEFAULT;
|
byte inGpio = DEFAULT_OT_IN_GPIO;
|
||||||
|
byte outGpio = DEFAULT_OT_OUT_GPIO;
|
||||||
|
byte rxLedGpio = DEFAULT_OT_RX_LED_GPIO;
|
||||||
|
byte faultStateGpio = DEFAULT_OT_FAULT_STATE_GPIO;
|
||||||
|
byte invertFaultState = false;
|
||||||
unsigned int memberIdCode = 0;
|
unsigned int memberIdCode = 0;
|
||||||
bool dhwPresent = true;
|
bool dhwPresent = true;
|
||||||
bool summerWinterMode = false;
|
bool summerWinterMode = false;
|
||||||
@@ -46,28 +61,35 @@ struct Settings {
|
|||||||
bool dhwToCh2 = false;
|
bool dhwToCh2 = false;
|
||||||
bool dhwBlocking = false;
|
bool dhwBlocking = false;
|
||||||
bool modulationSyncWithHeating = false;
|
bool modulationSyncWithHeating = false;
|
||||||
|
bool getMinMaxTemp = true;
|
||||||
|
bool nativeHeatingControl = false;
|
||||||
} opentherm;
|
} opentherm;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
char server[81] = MQTT_SERVER_DEFAULT;
|
bool enable = false;
|
||||||
unsigned short port = MQTT_PORT_DEFAULT;
|
char server[81] = DEFAULT_MQTT_SERVER;
|
||||||
char user[33] = MQTT_USER_DEFAULT;
|
unsigned short port = DEFAULT_MQTT_PORT;
|
||||||
char password[33] = MQTT_PASSWORD_DEFAULT;
|
char user[33] = DEFAULT_MQTT_USER;
|
||||||
char prefix[33] = MQTT_PREFIX_DEFAULT;
|
char password[33] = DEFAULT_MQTT_PASSWORD;
|
||||||
|
char prefix[33] = DEFAULT_MQTT_PREFIX;
|
||||||
unsigned short interval = 5;
|
unsigned short interval = 5;
|
||||||
|
bool homeAssistantDiscovery = true;
|
||||||
} mqtt;
|
} mqtt;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
float target = 40.0f;
|
float target = DEFAULT_HEATING_TARGET_TEMP;
|
||||||
|
unsigned short tresholdTime = 120;
|
||||||
bool useEquitherm = false;
|
bool useEquitherm = false;
|
||||||
bool usePid = false;
|
bool usePid = false;
|
||||||
|
bool onNetworkFault = true;
|
||||||
|
bool onMqttFault = true;
|
||||||
} emergency;
|
} emergency;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
bool turbo = false;
|
bool turbo = false;
|
||||||
float target = 40.0f;
|
float target = DEFAULT_HEATING_TARGET_TEMP;
|
||||||
float hysteresis = 0.5f;
|
float hysteresis = 0.5f;
|
||||||
byte minTemp = DEFAULT_HEATING_MIN_TEMP;
|
byte minTemp = DEFAULT_HEATING_MIN_TEMP;
|
||||||
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
@@ -76,16 +98,16 @@ struct Settings {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
byte target = 40;
|
float target = DEFAULT_DHW_TARGET_TEMP;
|
||||||
byte minTemp = DEFAULT_DHW_MIN_TEMP;
|
byte minTemp = DEFAULT_DHW_MIN_TEMP;
|
||||||
byte maxTemp = DEFAULT_DHW_MAX_TEMP;
|
byte maxTemp = DEFAULT_DHW_MAX_TEMP;
|
||||||
} dhw;
|
} dhw;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable = false;
|
bool enable = false;
|
||||||
float p_factor = 50;
|
float p_factor = 2;
|
||||||
float i_factor = 0.006f;
|
float i_factor = 0.0055f;
|
||||||
float d_factor = 10000;
|
float d_factor = 0;
|
||||||
unsigned short dt = 180;
|
unsigned short dt = 180;
|
||||||
byte minTemp = 0;
|
byte minTemp = 0;
|
||||||
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
@@ -100,16 +122,14 @@ struct Settings {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
// 0 - boiler, 1 - manual, 2 - ds18b20
|
SensorType type = SensorType::BOILER;
|
||||||
byte type = 0;
|
byte gpio = DEFAULT_SENSOR_OUTDOOR_GPIO;
|
||||||
byte pin = SENSOR_OUTDOOR_PIN_DEFAULT;
|
|
||||||
float offset = 0.0f;
|
float offset = 0.0f;
|
||||||
} outdoor;
|
} outdoor;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
// 1 - manual, 2 - ds18b20, 3 - ble
|
SensorType type = SensorType::MANUAL;
|
||||||
byte type = 1;
|
byte gpio = DEFAULT_SENSOR_INDOOR_GPIO;
|
||||||
byte pin = SENSOR_INDOOR_PIN_DEFAULT;
|
|
||||||
uint8_t bleAddresss[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t bleAddresss[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
float offset = 0.0f;
|
float offset = 0.0f;
|
||||||
} indoor;
|
} indoor;
|
||||||
@@ -117,7 +137,7 @@ struct Settings {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool use = false;
|
bool use = false;
|
||||||
byte pin = EXT_PUMP_PIN_DEFAULT;
|
byte gpio = DEFAULT_EXT_PUMP_GPIO;
|
||||||
unsigned short postCirculationTime = 600;
|
unsigned short postCirculationTime = 600;
|
||||||
unsigned int antiStuckInterval = 2592000;
|
unsigned int antiStuckInterval = 2592000;
|
||||||
unsigned short antiStuckTime = 300;
|
unsigned short antiStuckTime = 300;
|
||||||
@@ -127,11 +147,6 @@ struct Settings {
|
|||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
struct Variables {
|
struct Variables {
|
||||||
struct {
|
|
||||||
bool enable = false;
|
|
||||||
byte regulator = 0;
|
|
||||||
} tuning;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool otStatus = false;
|
bool otStatus = false;
|
||||||
bool emergency = false;
|
bool emergency = false;
|
||||||
@@ -141,6 +156,7 @@ struct Variables {
|
|||||||
bool fault = false;
|
bool fault = false;
|
||||||
bool diagnostic = false;
|
bool diagnostic = false;
|
||||||
bool externalPump = false;
|
bool externalPump = false;
|
||||||
|
bool mqtt = false;
|
||||||
} states;
|
} states;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -155,14 +171,16 @@ struct Variables {
|
|||||||
float indoor = 0.0f;
|
float indoor = 0.0f;
|
||||||
float outdoor = 0.0f;
|
float outdoor = 0.0f;
|
||||||
float heating = 0.0f;
|
float heating = 0.0f;
|
||||||
|
float heatingReturn = 0.0f;
|
||||||
float dhw = 0.0f;
|
float dhw = 0.0f;
|
||||||
|
float exhaust = 0.0f;
|
||||||
} temperatures;
|
} temperatures;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool heatingEnabled = false;
|
bool heatingEnabled = false;
|
||||||
byte heatingMinTemp = DEFAULT_HEATING_MIN_TEMP;
|
byte heatingMinTemp = DEFAULT_HEATING_MIN_TEMP;
|
||||||
byte heatingMaxTemp = DEFAULT_HEATING_MAX_TEMP;
|
byte heatingMaxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
byte heatingSetpoint = 0;
|
float heatingSetpoint = 0;
|
||||||
unsigned long extPumpLastEnableTime = 0;
|
unsigned long extPumpLastEnableTime = 0;
|
||||||
byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP;
|
byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP;
|
||||||
byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP;
|
byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP;
|
||||||
|
|||||||
137
src/defines.h
137
src/defines.h
@@ -1,28 +1,27 @@
|
|||||||
#define PROJECT_NAME "OpenTherm Gateway"
|
#define PROJECT_NAME "OpenTherm Gateway"
|
||||||
#define PROJECT_VERSION "1.4.0-rc.15"
|
#define PROJECT_VERSION "1.4.1"
|
||||||
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
|
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
|
||||||
|
|
||||||
#define EMERGENCY_TIME_TRESHOLD 120000
|
#define MQTT_RECONNECT_INTERVAL 15000
|
||||||
#define MQTT_RECONNECT_INTERVAL 15000
|
|
||||||
#define MQTT_KEEPALIVE 30
|
|
||||||
|
|
||||||
#define OPENTHERM_OFFLINE_TRESHOLD 10
|
#define EXT_SENSORS_INTERVAL 5000
|
||||||
|
#define EXT_SENSORS_FILTER_K 0.15
|
||||||
|
|
||||||
#define EXT_SENSORS_INTERVAL 5000
|
#define CONFIG_URL "http://%s/"
|
||||||
#define EXT_SENSORS_FILTER_K 0.15
|
#define SETTINGS_VALID_VALUE "stvalid" // only 8 chars!
|
||||||
|
#define GPIO_IS_NOT_CONFIGURED 0xff
|
||||||
|
|
||||||
#define CONFIG_URL "http://%s/"
|
#define DEFAULT_HEATING_TARGET_TEMP 40
|
||||||
#define SETTINGS_VALID_VALUE "stvalid" // only 8 chars!
|
#define DEFAULT_HEATING_MIN_TEMP 20
|
||||||
|
#define DEFAULT_HEATING_MAX_TEMP 90
|
||||||
|
|
||||||
#define DEFAULT_HEATING_MIN_TEMP 20
|
#define DEFAULT_DHW_TARGET_TEMP 40
|
||||||
#define DEFAULT_HEATING_MAX_TEMP 90
|
#define DEFAULT_DHW_MIN_TEMP 30
|
||||||
#define DEFAULT_DHW_MIN_TEMP 30
|
#define DEFAULT_DHW_MAX_TEMP 60
|
||||||
#define DEFAULT_DHW_MAX_TEMP 60
|
|
||||||
|
|
||||||
|
#define THERMOSTAT_INDOOR_DEFAULT_TEMP 20
|
||||||
#ifndef WM_DEBUG_MODE
|
#define THERMOSTAT_INDOOR_MIN_TEMP 5
|
||||||
#define WM_DEBUG_MODE WM_DEBUG_NOTIFY
|
#define THERMOSTAT_INDOOR_MAX_TEMP 30
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USE_SERIAL
|
#ifndef USE_SERIAL
|
||||||
#define USE_SERIAL true
|
#define USE_SERIAL true
|
||||||
@@ -36,80 +35,112 @@
|
|||||||
#define USE_BLE false
|
#define USE_BLE false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HOSTNAME_DEFAULT
|
#ifndef DEFAULT_HOSTNAME
|
||||||
#define HOSTNAME_DEFAULT "opentherm"
|
#define DEFAULT_HOSTNAME "opentherm"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef AP_SSID_DEFAULT
|
#ifndef DEFAULT_AP_SSID
|
||||||
#define AP_SSID_DEFAULT "OpenTherm Gateway"
|
#define DEFAULT_AP_SSID "OpenTherm Gateway"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef AP_PASSWORD_DEFAULT
|
#ifndef DEFAULT_AP_PASSWORD
|
||||||
#define AP_PASSWORD_DEFAULT "otgateway123456"
|
#define DEFAULT_AP_PASSWORD "otgateway123456"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STA_SSID_DEFAULT
|
#ifndef DEFAULT_STA_SSID
|
||||||
#define STA_SSID_DEFAULT ""
|
#define DEFAULT_STA_SSID ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STA_PASSWORD_DEFAULT
|
#ifndef DEFAULT_STA_PASSWORD
|
||||||
#define STA_PASSWORD_DEFAULT ""
|
#define DEFAULT_STA_PASSWORD ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DEBUG_BY_DEFAULT
|
#ifndef DEBUG_BY_DEFAULT
|
||||||
#define DEBUG_BY_DEFAULT false
|
#define DEBUG_BY_DEFAULT false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PORTAL_LOGIN_DEFAULT
|
#ifndef DEFAULT_STATUS_LED_GPIO
|
||||||
#define PORTAL_LOGIN_DEFAULT ""
|
#define DEFAULT_STATUS_LED_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PORTAL_PASSWORD_DEFAULT
|
#ifndef DEFAULT_PORTAL_LOGIN
|
||||||
#define PORTAL_PASSWORD_DEFAULT ""
|
#define DEFAULT_PORTAL_LOGIN ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MQTT_SERVER_DEFAULT
|
#ifndef DEFAULT_PORTAL_PASSWORD
|
||||||
#define MQTT_SERVER_DEFAULT ""
|
#define DEFAULT_PORTAL_PASSWORD ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MQTT_PORT_DEFAULT
|
#ifndef DEFAULT_MQTT_SERVER
|
||||||
#define MQTT_PORT_DEFAULT 1883
|
#define DEFAULT_MQTT_SERVER ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MQTT_USER_DEFAULT
|
#ifndef DEFAULT_MQTT_PORT
|
||||||
#define MQTT_USER_DEFAULT ""
|
#define DEFAULT_MQTT_PORT 1883
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MQTT_PASSWORD_DEFAULT
|
#ifndef DEFAULT_MQTT_USER
|
||||||
#define MQTT_PASSWORD_DEFAULT ""
|
#define DEFAULT_MQTT_USER ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MQTT_PREFIX_DEFAULT
|
#ifndef DEFAULT_MQTT_PASSWORD
|
||||||
#define MQTT_PREFIX_DEFAULT "opentherm"
|
#define DEFAULT_MQTT_PASSWORD ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OT_IN_PIN_DEFAULT
|
#ifndef DEFAULT_MQTT_PREFIX
|
||||||
#define OT_IN_PIN_DEFAULT 0
|
#define DEFAULT_MQTT_PREFIX "opentherm"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OT_OUT_PIN_DEFAULT
|
#ifndef DEFAULT_OT_IN_GPIO
|
||||||
#define OT_OUT_PIN_DEFAULT 0
|
#define DEFAULT_OT_IN_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SENSOR_OUTDOOR_PIN_DEFAULT
|
#ifndef DEFAULT_OT_OUT_GPIO
|
||||||
#define SENSOR_OUTDOOR_PIN_DEFAULT 0
|
#define DEFAULT_OT_OUT_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SENSOR_INDOOR_PIN_DEFAULT
|
#ifndef DEFAULT_OT_RX_LED_GPIO
|
||||||
#define SENSOR_INDOOR_PIN_DEFAULT 0
|
#define DEFAULT_OT_RX_LED_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef EXT_PUMP_PIN_DEFAULT
|
#ifndef DEFAULT_OT_FAULT_STATE_GPIO
|
||||||
#define EXT_PUMP_PIN_DEFAULT 0
|
#define DEFAULT_OT_FAULT_STATE_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_SENSOR_OUTDOOR_GPIO
|
||||||
|
#define DEFAULT_SENSOR_OUTDOOR_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_SENSOR_INDOOR_GPIO
|
||||||
|
#define DEFAULT_SENSOR_INDOOR_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFAULT_EXT_PUMP_GPIO
|
||||||
|
#define DEFAULT_EXT_PUMP_GPIO GPIO_IS_NOT_CONFIGURED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PROGMEM
|
#ifndef PROGMEM
|
||||||
#define PROGMEM
|
#define PROGMEM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#elif !defined(GPIO_IS_VALID_GPIO)
|
||||||
|
#define GPIO_IS_VALID_GPIO(gpioNum) (gpioNum >= 0 && gpioNum <= 16)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GPIO_IS_VALID(gpioNum) (gpioNum != GPIO_IS_NOT_CONFIGURED && GPIO_IS_VALID_GPIO(gpioNum))
|
||||||
|
|
||||||
|
enum class SensorType : byte {
|
||||||
|
BOILER,
|
||||||
|
MANUAL,
|
||||||
|
DS18B20,
|
||||||
|
BLUETOOTH
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class UnitSystem : byte {
|
||||||
|
METRIC,
|
||||||
|
IMPERIAL
|
||||||
|
};
|
||||||
|
|
||||||
char buffer[255];
|
char buffer[255];
|
||||||
27
src/main.cpp
27
src/main.cpp
@@ -4,11 +4,11 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <FileData.h>
|
#include <FileData.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#include "ESPTelnetStream.h"
|
#include <ESPTelnetStream.h>
|
||||||
#include <TinyLogger.h>
|
#include <TinyLogger.h>
|
||||||
#include <NetworkManager.h>
|
#include <NetworkMgr.h>
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include <utils.h>
|
#include "utils.h"
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
#include <ESP32Scheduler.h>
|
#include <ESP32Scheduler.h>
|
||||||
@@ -27,11 +27,13 @@
|
|||||||
#include "PortalTask.h"
|
#include "PortalTask.h"
|
||||||
#include "MainTask.h"
|
#include "MainTask.h"
|
||||||
|
|
||||||
|
using namespace NetworkUtils;
|
||||||
|
|
||||||
// Vars
|
// Vars
|
||||||
FileData fsNetworkSettings(&LittleFS, "/network.conf", 'n', &networkSettings, sizeof(networkSettings), 1000);
|
FileData fsNetworkSettings(&LittleFS, "/network.conf", 'n', &networkSettings, sizeof(networkSettings), 1000);
|
||||||
FileData fsSettings(&LittleFS, "/settings.conf", 's', &settings, sizeof(settings), 60000);
|
FileData fsSettings(&LittleFS, "/settings.conf", 's', &settings, sizeof(settings), 60000);
|
||||||
ESPTelnetStream* telnetStream = nullptr;
|
ESPTelnetStream* telnetStream = nullptr;
|
||||||
Network::Manager* network = nullptr;
|
NetworkMgr* network = nullptr;
|
||||||
|
|
||||||
// Tasks
|
// Tasks
|
||||||
MqttTask* tMqtt;
|
MqttTask* tMqtt;
|
||||||
@@ -109,12 +111,19 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// logs
|
// logs
|
||||||
if (!settings.system.useSerial) {
|
if (!settings.system.serial.enable) {
|
||||||
Log.clearStreams();
|
|
||||||
Serial.end();
|
Serial.end();
|
||||||
|
Log.clearStreams();
|
||||||
|
|
||||||
|
} else if (settings.system.serial.baudrate != 115200) {
|
||||||
|
Serial.end();
|
||||||
|
Log.clearStreams();
|
||||||
|
|
||||||
|
Serial.begin(settings.system.serial.baudrate);
|
||||||
|
Log.addStream(&Serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.system.useTelnet) {
|
if (settings.system.telnet.enable) {
|
||||||
telnetStream = new ESPTelnetStream;
|
telnetStream = new ESPTelnetStream;
|
||||||
telnetStream->setKeepAliveInterval(500);
|
telnetStream->setKeepAliveInterval(500);
|
||||||
Log.addStream(telnetStream);
|
Log.addStream(telnetStream);
|
||||||
@@ -123,7 +132,7 @@ void setup() {
|
|||||||
Log.setLevel(settings.system.debug ? TinyLogger::Level::VERBOSE : TinyLogger::Level::INFO);
|
Log.setLevel(settings.system.debug ? TinyLogger::Level::VERBOSE : TinyLogger::Level::INFO);
|
||||||
|
|
||||||
// network
|
// network
|
||||||
network = (new Network::Manager)
|
network = (new NetworkMgr)
|
||||||
->setHostname(networkSettings.hostname)
|
->setHostname(networkSettings.hostname)
|
||||||
->setStaCredentials(
|
->setStaCredentials(
|
||||||
#ifdef WOKWI
|
#ifdef WOKWI
|
||||||
@@ -143,7 +152,7 @@ void setup() {
|
|||||||
tMqtt = new MqttTask(false, 500);
|
tMqtt = new MqttTask(false, 500);
|
||||||
Scheduler.start(tMqtt);
|
Scheduler.start(tMqtt);
|
||||||
|
|
||||||
tOt = new OpenThermTask(false, 750);
|
tOt = new OpenThermTask(true, 750);
|
||||||
Scheduler.start(tOt);
|
Scheduler.start(tOt);
|
||||||
|
|
||||||
tSensors = new SensorsTask(true, EXT_SENSORS_INTERVAL);
|
tSensors = new SensorsTask(true, EXT_SENSORS_INTERVAL);
|
||||||
|
|||||||
1125
src/utils.h
1125
src/utils.h
File diff suppressed because it is too large
Load Diff
415
src_data/dashboard.html
Normal file
415
src_data/dashboard.html
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Dashboard - OpenTherm Gateway</title>
|
||||||
|
<link rel="stylesheet" href="/static/pico.min.css">
|
||||||
|
<link rel="stylesheet" href="/static/app.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header class="container">
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/"><div class="logo">OpenTherm Gateway</div></a></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/Laxilef/OTGateway/wiki" role="button" class="secondary" target="_blank">Help</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<article>
|
||||||
|
<hgroup>
|
||||||
|
<h2>Dashboard</h2>
|
||||||
|
<p></p>
|
||||||
|
</hgroup>
|
||||||
|
|
||||||
|
<div id="dashboard-busy" aria-busy="true"></div>
|
||||||
|
<div id="dashboard-container" class="hidden">
|
||||||
|
<details open>
|
||||||
|
<summary><b>Control</b></summary>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="thermostat" id="thermostat-heating">
|
||||||
|
<div class="thermostat-header">Heating</div>
|
||||||
|
<div class="thermostat-temp">
|
||||||
|
<div class="thermostat-temp-target"><span id="thermostat-heating-target"></span> <span class="temp-unit"></span></div>
|
||||||
|
<div class="thermostat-temp-current">Current: <span id="thermostat-heating-current"></span> <span class="temp-unit"></span></div>
|
||||||
|
</div>
|
||||||
|
<div class="thermostat-minus"><button id="thermostat-heating-minus" class="outline"><i class="icons-down"></i></button></div>
|
||||||
|
<div class="thermostat-plus"><button id="thermostat-heating-plus" class="outline"><i class="icons-up"></i></button></div>
|
||||||
|
<div class="thermostat-control">
|
||||||
|
<input type="checkbox" role="switch" id="thermostat-heating-enabled" value="true">
|
||||||
|
<label htmlFor="thermostat-heating-enabled">Enable</label>
|
||||||
|
|
||||||
|
<input type="checkbox" role="switch" id="thermostat-heating-turbo" value="true">
|
||||||
|
<label htmlFor="thermostat-heating-turbo">Turbo mode</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="thermostat" id="thermostat-dhw">
|
||||||
|
<div class="thermostat-header">DHW</div>
|
||||||
|
<div class="thermostat-temp">
|
||||||
|
<div class="thermostat-temp-target"><span id="thermostat-dhw-target"></span> <span class="temp-unit"></span></div>
|
||||||
|
<div class="thermostat-temp-current">Current: <span id="thermostat-dhw-current"></span> <span class="temp-unit"></span></div>
|
||||||
|
</div>
|
||||||
|
<div class="thermostat-minus"><button class="outline" id="thermostat-dhw-minus"><i class="icons-down"></i></button></div>
|
||||||
|
<div class="thermostat-plus"><button class="outline" id="thermostat-dhw-plus"><i class="icons-up"></i></button></div>
|
||||||
|
<div class="thermostat-control">
|
||||||
|
<input type="checkbox" role="switch" id="thermostat-dhw-enabled" value="true">
|
||||||
|
<label htmlFor="thermostat-dhw-enabled">Enable</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>States and sensors</b></summary>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">OpenTherm connected:</th>
|
||||||
|
<td><input type="radio" id="ot-connected" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">MQTT connected:</th>
|
||||||
|
<td><input type="radio" id="mqtt-connected" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Emergency:</th>
|
||||||
|
<td><input type="radio" id="ot-emergency" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Heating:</th>
|
||||||
|
<td><input type="radio" id="ot-heating" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">DHW:</th>
|
||||||
|
<td><input type="radio" id="ot-dhw" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Flame:</th>
|
||||||
|
<td><input type="radio" id="ot-flame" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Fault:</th>
|
||||||
|
<td><input type="radio" id="ot-fault" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Diagnostic:</th>
|
||||||
|
<td><input type="radio" id="ot-diagnostic" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">External pump:</th>
|
||||||
|
<td><input type="radio" id="ot-external-pump" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Modulation:</th>
|
||||||
|
<td><b id="ot-modulation"></b> %</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Pressure:</th>
|
||||||
|
<td><b id="ot-pressure"></b> <span class="pressure-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">DHW flow rate:</th>
|
||||||
|
<td><b id="ot-dhw-flow-rate"></b> <span class="volume-unit"></span>/min</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Fault code:</th>
|
||||||
|
<td><b id="ot-fault-code"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Indoor temp:</th>
|
||||||
|
<td><b id="indoor-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Outdoor temp:</th>
|
||||||
|
<td><b id="outdoor-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Heating temp:</th>
|
||||||
|
<td><b id="heating-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Heating setpoint temp:</th>
|
||||||
|
<td><b id="heating-setpoint-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Heating return temp:</th>
|
||||||
|
<td><b id="heating-return-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">DHW temp:</th>
|
||||||
|
<td><b id="dhw-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Exhaust temp:</th>
|
||||||
|
<td><b id="exhaust-temp"></b> <span class="temp-unit"></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>OpenTherm diagnostic</b></summary>
|
||||||
|
<pre><b>Vendor:</b> <span id="slave-vendor"></span>
|
||||||
|
<b>Member ID:</b> <span id="slave-member-id"></span>
|
||||||
|
<b>Flags:</b> <span id="slave-flags"></span>
|
||||||
|
<b>Type:</b> <span id="slave-type"></span>
|
||||||
|
<b>Version:</b> <span id="slave-version"></span>
|
||||||
|
<b>OT version:</b> <span id="slave-ot-version"></span>
|
||||||
|
<b>Heating limits:</b> <span id="heating-min-temp"></span>...<span id="heating-max-temp"></span> <span class="temp-unit"></span>
|
||||||
|
<b>DHW limits:</b> <span id="dhw-min-temp"></span>...<span id="dhw-max-temp"></span> <span class="temp-unit"></span></pre>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="container">
|
||||||
|
<small>
|
||||||
|
<b>Made by Laxilef</b>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
||||||
|
</small>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="/static/app.js"></script>
|
||||||
|
<script>
|
||||||
|
let modifiedTime = null;
|
||||||
|
let noRegulators;
|
||||||
|
let prevSettings;
|
||||||
|
let newSettings = {
|
||||||
|
heating: {
|
||||||
|
enable: false,
|
||||||
|
turbo: false,
|
||||||
|
target: 0
|
||||||
|
},
|
||||||
|
dhw: {
|
||||||
|
enable: false,
|
||||||
|
target: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = async function () {
|
||||||
|
document.querySelector('#thermostat-heating-minus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.heating.target -= 0.5;
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
|
let minTemp;
|
||||||
|
if (noRegulators) {
|
||||||
|
minTemp = prevSettings.heating.minTemp;
|
||||||
|
} else {
|
||||||
|
minTemp = prevSettings.system.unitSystem == 0 ? 5 : 41;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevSettings && newSettings.heating.target < minTemp) {
|
||||||
|
newSettings.heating.target = minTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#thermostat-heating-target', newSettings.heating.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#thermostat-heating-plus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.heating.target += 0.5;
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
|
let maxTemp;
|
||||||
|
if (noRegulators) {
|
||||||
|
maxTemp = prevSettings.heating.maxTemp;
|
||||||
|
} else {
|
||||||
|
maxTemp = prevSettings.system.unitSystem == 0 ? 30 : 86;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevSettings && newSettings.heating.target > maxTemp) {
|
||||||
|
newSettings.heating.target = maxTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#thermostat-heating-target', newSettings.heating.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#thermostat-dhw-minus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.dhw.target -= 1.0;
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
|
if (newSettings.dhw.target < prevSettings.dhw.minTemp) {
|
||||||
|
newSettings.dhw.target = prevSettings.dhw.minTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#thermostat-dhw-target', newSettings.dhw.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#thermostat-dhw-plus').addEventListener('click', (event) => {
|
||||||
|
if (!prevSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings.dhw.target += 1.0;
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
|
if (newSettings.dhw.target > prevSettings.dhw.maxTemp) {
|
||||||
|
newSettings.dhw.target = prevSettings.dhw.maxTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue('#thermostat-dhw-target', newSettings.dhw.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#thermostat-heating-enabled').addEventListener('change', (event) => {
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
newSettings.heating.enable = event.currentTarget.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#thermostat-heating-turbo').addEventListener('change', (event) => {
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
newSettings.heating.turbo = event.currentTarget.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('#thermostat-dhw-enabled').addEventListener('change', (event) => {
|
||||||
|
modifiedTime = Date.now();
|
||||||
|
newSettings.dhw.enable = event.currentTarget.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(async function onLoadPage() {
|
||||||
|
if (modifiedTime) {
|
||||||
|
if ((Date.now() - modifiedTime) < 5000) {
|
||||||
|
setTimeout(onLoadPage, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiedTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// settings
|
||||||
|
try {
|
||||||
|
let modified = prevSettings && (
|
||||||
|
(prevSettings.heating.enable != newSettings.heating.enable)
|
||||||
|
|| (prevSettings.heating.turbo != newSettings.heating.turbo)
|
||||||
|
|| (prevSettings.heating.target != newSettings.heating.target)
|
||||||
|
|| (prevSettings.opentherm.dhwPresent && prevSettings.dhw.enable != newSettings.dhw.enable)
|
||||||
|
|| (prevSettings.opentherm.dhwPresent && prevSettings.dhw.target != newSettings.dhw.target)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
console.log(newSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parameters = {cache: 'no-cache'};
|
||||||
|
if (modified) {
|
||||||
|
parameters.method = "POST";
|
||||||
|
parameters.body = JSON.stringify(newSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch('/api/settings', parameters);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Response not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
noRegulators = !result.opentherm.nativeHeatingControl && !result.equitherm.enable && !result.pid.enable;
|
||||||
|
prevSettings = result;
|
||||||
|
newSettings.heating.enable = result.heating.enable;
|
||||||
|
newSettings.heating.turbo = result.heating.turbo;
|
||||||
|
newSettings.heating.target = result.heating.target;
|
||||||
|
newSettings.dhw.enable = result.dhw.enable;
|
||||||
|
newSettings.dhw.target = result.dhw.target;
|
||||||
|
|
||||||
|
if (result.opentherm.dhwPresent) {
|
||||||
|
show('#thermostat-dhw');
|
||||||
|
} else {
|
||||||
|
hide('#thermostat-dhw');
|
||||||
|
}
|
||||||
|
|
||||||
|
setCheckboxValue('#thermostat-heating-enabled', result.heating.enable);
|
||||||
|
setCheckboxValue('#thermostat-heating-turbo', result.heating.turbo);
|
||||||
|
setValue('#thermostat-heating-target', result.heating.target);
|
||||||
|
|
||||||
|
setCheckboxValue('#thermostat-dhw-enabled', result.dhw.enable);
|
||||||
|
setValue('#thermostat-dhw-target', result.dhw.target);
|
||||||
|
|
||||||
|
setValue('.temp-unit', temperatureUnit(result.system.unitSystem));
|
||||||
|
setValue('.pressure-unit', pressureUnit(result.system.unitSystem));
|
||||||
|
setValue('.volume-unit', volumeUnit(result.system.unitSystem));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vars
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/vars', { cache: 'no-cache' });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Response not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
setValue('#thermostat-heating-current', noRegulators ? result.temperatures.heating : result.temperatures.indoor);
|
||||||
|
setValue('#thermostat-dhw-current', result.temperatures.dhw);
|
||||||
|
|
||||||
|
setState('#ot-connected', result.states.otStatus);
|
||||||
|
setState('#ot-emergency', result.states.emergency);
|
||||||
|
setState('#ot-heating', result.states.heating);
|
||||||
|
setState('#ot-dhw', result.states.dhw);
|
||||||
|
setState('#ot-flame', result.states.flame);
|
||||||
|
setState('#ot-fault', result.states.fault);
|
||||||
|
setState('#ot-diagnostic', result.states.diagnostic);
|
||||||
|
setState('#ot-external-pump', result.states.externalPump);
|
||||||
|
setState('#mqtt-connected', result.states.mqtt);
|
||||||
|
|
||||||
|
setValue('#ot-modulation', result.sensors.modulation);
|
||||||
|
setValue('#ot-pressure', result.sensors.pressure);
|
||||||
|
setValue('#ot-dhw-flow-rate', result.sensors.dhwFlowRate);
|
||||||
|
setValue('#ot-fault-code', result.sensors.faultCode ? ("E" + result.sensors.faultCode) : "-");
|
||||||
|
|
||||||
|
setValue('#indoor-temp', result.temperatures.indoor);
|
||||||
|
setValue('#outdoor-temp', result.temperatures.outdoor);
|
||||||
|
setValue('#heating-temp', result.temperatures.heating);
|
||||||
|
setValue('#heating-return-temp', result.temperatures.heatingReturn);
|
||||||
|
setValue('#dhw-temp', result.temperatures.dhw);
|
||||||
|
setValue('#exhaust-temp', result.temperatures.exhaust);
|
||||||
|
|
||||||
|
setValue('#heating-min-temp', result.parameters.heatingMinTemp);
|
||||||
|
setValue('#heating-max-temp', result.parameters.heatingMaxTemp);
|
||||||
|
setValue('#heating-setpoint-temp', result.parameters.heatingSetpoint);
|
||||||
|
setValue('#dhw-min-temp', result.parameters.dhwMinTemp);
|
||||||
|
setValue('#dhw-max-temp', result.parameters.dhwMaxTemp);
|
||||||
|
|
||||||
|
setValue('#slave-member-id', result.parameters.slaveMemberId);
|
||||||
|
setValue('#slave-vendor', memberIdToVendor(result.parameters.slaveMemberId));
|
||||||
|
|
||||||
|
setValue('#slave-flags', result.parameters.slaveFlags);
|
||||||
|
setValue('#slave-type', result.parameters.slaveType);
|
||||||
|
setValue('#slave-version', result.parameters.slaveVersion);
|
||||||
|
setValue('#slave-ot-version', result.parameters.slaveOtVersion);
|
||||||
|
setBusy('#dashboard-busy', '#dashboard-container', false);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(onLoadPage, 10000);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
191
src_data/index.html
Normal file
191
src_data/index.html
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>OpenTherm Gateway</title>
|
||||||
|
<link rel="stylesheet" href="/static/pico.min.css">
|
||||||
|
<link rel="stylesheet" href="/static/app.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header class="container">
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/"><div class="logo">OpenTherm Gateway</div></a></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/Laxilef/OTGateway/wiki" role="button" class="secondary" target="_blank">Help</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<article>
|
||||||
|
<div>
|
||||||
|
<hgroup>
|
||||||
|
<h2>Network</h2>
|
||||||
|
<p></p>
|
||||||
|
</hgroup>
|
||||||
|
|
||||||
|
<div id="main-busy" aria-busy="true"></div>
|
||||||
|
<table id="main-table" class="hidden">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Hostname:</th>
|
||||||
|
<td><b id="network-hostname"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">MAC:</th>
|
||||||
|
<td><b id="network-mac"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Connected:</th>
|
||||||
|
<td><input type="radio" id="network-connected" aria-invalid="false" checked disabled /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">SSID:</th>
|
||||||
|
<td><b id="network-ssid"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Signal:</th>
|
||||||
|
<td><b id="network-signal"></b> %</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">IP:</th>
|
||||||
|
<td><b id="network-ip"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Subnet:</th>
|
||||||
|
<td><b id="network-subnet"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Gateway:</th>
|
||||||
|
<td><b id="network-gateway"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">DNS:</th>
|
||||||
|
<td><b id="network-dns"></b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="grid">
|
||||||
|
<a href="/network.html" role="button">Network settings</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<div>
|
||||||
|
<hgroup>
|
||||||
|
<h2>System</h2>
|
||||||
|
<p></p>
|
||||||
|
</hgroup>
|
||||||
|
|
||||||
|
<div id="system-busy" aria-busy="true"></div>
|
||||||
|
<table id="system-table" class="hidden">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Version:</th>
|
||||||
|
<td><b id="version"></b>, core/sdk: <b id="core-version"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Build date:</th>
|
||||||
|
<td><b id="build-date"></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Uptime:</th>
|
||||||
|
<td><b id="uptime-days"></b> days, <b id="uptime-hours"></b> hours, <b id="uptime-min"></b> min., <b id="uptime-sec"></b> sec.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Free memory:</th>
|
||||||
|
<td><b id="free-heap"></b> of <b id="total-heap"></b> bytes (min: <b id="min-free-heap"></b> bytes)<br />max free block: <b id="max-free-block-heap"></b> bytes (min: <b id="min-max-free-block-heap"></b> bytes)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Board:</th>
|
||||||
|
<td>Chip <b id="chip-model"></b> (rev. <span id="chip-revision"></span>)<br />Cores: <b id="chip-cores"></b>, frequency: <b id="cpu-freq"></b> mHz<br />Flash size: <b id="flash-size"></b> MB (real: <b id="flash-real-size"></b> MB)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Last reset reason:</th>
|
||||||
|
<td><b id="reset-reason"></b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<a href="/dashboard.html" role="button">Dashboard</a>
|
||||||
|
<a href="/settings.html" role="button">Settings</a>
|
||||||
|
<a href="/upgrade.html" role="button">Upgrade</a>
|
||||||
|
<a href="/restart.html" role="button" class="secondary restart">Restart</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="container">
|
||||||
|
<small>
|
||||||
|
<b>Made by Laxilef</b>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
||||||
|
</small>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="/static/app.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = async function () {
|
||||||
|
setTimeout(async function onLoadPage() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/info', { cache: 'no-cache' });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Response not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
setValue('#network-hostname', result.network.hostname);
|
||||||
|
setValue('#network-mac', result.network.mac);
|
||||||
|
setState('#network-connected', result.network.connected);
|
||||||
|
setValue('#network-ssid', result.network.ssid);
|
||||||
|
setValue('#network-signal', result.network.signalQuality);
|
||||||
|
setValue('#network-ip', result.network.ip);
|
||||||
|
setValue('#network-subnet', result.network.subnet);
|
||||||
|
setValue('#network-gateway', result.network.gateway);
|
||||||
|
setValue('#network-dns', result.network.dns);
|
||||||
|
setBusy('#main-busy', '#main-table', false);
|
||||||
|
|
||||||
|
setValue('#version', result.system.version);
|
||||||
|
setValue('#build-date', result.system.buildDate);
|
||||||
|
setValue('#uptime', result.system.uptime);
|
||||||
|
setValue('#uptime-days', Math.floor(result.system.uptime / 86400));
|
||||||
|
setValue('#uptime-hours', Math.floor(result.system.uptime % 86400 / 3600));
|
||||||
|
setValue('#uptime-min', Math.floor(result.system.uptime % 3600 / 60));
|
||||||
|
setValue('#uptime-sec', Math.floor(result.system.uptime % 60));
|
||||||
|
setValue('#total-heap', result.system.totalHeap);
|
||||||
|
setValue('#free-heap', result.system.freeHeap);
|
||||||
|
setValue('#min-free-heap', result.system.minFreeHeap);
|
||||||
|
setValue('#max-free-block-heap', result.system.maxFreeBlockHeap);
|
||||||
|
setValue('#min-max-free-block-heap', result.system.minMaxFreeBlockHeap);
|
||||||
|
setValue('#reset-reason', result.system.resetReason);
|
||||||
|
|
||||||
|
setValue('#chip-model', result.system.chipModel);
|
||||||
|
setValue('#chip-revision', result.system.chipRevision);
|
||||||
|
setValue('#chip-cores', result.system.chipCores);
|
||||||
|
setValue('#cpu-freq', result.system.cpuFreq);
|
||||||
|
setValue('#core-version', result.system.coreVersion);
|
||||||
|
setValue('#flash-size', result.system.flashSize / 1024 / 1024);
|
||||||
|
setValue('#flash-real-size', result.system.flashRealSize / 1024 / 1024);
|
||||||
|
|
||||||
|
setBusy('#system-busy', '#system-table', false);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(onLoadPage, 10000);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -31,32 +31,38 @@
|
|||||||
|
|
||||||
<div id="network-settings-busy" aria-busy="true"></div>
|
<div id="network-settings-busy" aria-busy="true"></div>
|
||||||
<form action="/api/network/settings" id="network-settings" class="hidden">
|
<form action="/api/network/settings" id="network-settings" class="hidden">
|
||||||
<label for="hostname">
|
<label for="network-hostname">
|
||||||
Hostname
|
Hostname
|
||||||
<input type="text" class="network-hostname" name="hostname" maxlength="24" pattern="[A-Za-z0-9]+[A-Za-z0-9\-]+[A-Za-z0-9]+" required>
|
<input type="text" id="network-hostname" name="hostname" maxlength="24" pattern="[A-Za-z0-9]+[A-Za-z0-9\-]+[A-Za-z0-9]+" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="network-use-dhcp">
|
<label for="network-use-dhcp">
|
||||||
<input type="checkbox" class="network-use-dhcp" name="useDhcp" value="true">
|
<input type="checkbox" id="network-use-dhcp" name="useDhcp" value="true">
|
||||||
Use DHCP
|
Use DHCP
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br />
|
||||||
<hr>
|
<hr />
|
||||||
|
|
||||||
<label for="network-static-ip">
|
<label for="network-static-ip">
|
||||||
Static IP:
|
Static IP:
|
||||||
<input type="text" class="network-static-ip" name="staticConfig[ip]" value="true" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
<input type="text" id="network-static-ip" name="staticConfig[ip]" value="true" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="network-static-gateway">
|
<label for="network-static-gateway">
|
||||||
Static gateway:
|
Static gateway:
|
||||||
<input type="text" class="network-static-gateway" name="staticConfig[gateway]" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
<input type="text" id="network-static-gateway" name="staticConfig[gateway]" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="network-static-subnet">
|
<label for="network-static-subnet">
|
||||||
Static subnet:
|
Static subnet:
|
||||||
<input type="text" class="network-static-subnet" name="staticConfig[subnet]" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
<input type="text" id="network-static-subnet" name="staticConfig[subnet]" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="network-static-dns">
|
<label for="network-static-dns">
|
||||||
Static DNS:
|
Static DNS:
|
||||||
<input type="text" class="network-static-dns" name="staticConfig[dns]" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
<input type="text" id="network-static-dns" name="staticConfig[dns]" maxlength="16" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,40 +76,44 @@
|
|||||||
</hgroup>
|
</hgroup>
|
||||||
|
|
||||||
<form action="/api/network/scan" id="network-scan">
|
<form action="/api/network/scan" id="network-scan">
|
||||||
<figure style="max-height: 25em;">
|
<div style="max-height: 25rem;" class="overflow-auto">
|
||||||
<table id="networks" role="grid">
|
<table id="networks" role="grid">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<th scope="col">#</th>
|
||||||
<th scope="col">SSID</th>
|
<th scope="col">SSID</th>
|
||||||
<th scope="col">Signal</th>
|
<th scope="col">Info</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</table>
|
||||||
</figure>
|
</div>
|
||||||
|
|
||||||
<button type="submit">Refresh</button>
|
<button type="submit">Refresh</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<hr>
|
<hr />
|
||||||
<div>
|
<div>
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h2>WiFi settings</h2>
|
<h2>WiFi settings</h2>
|
||||||
<p></p>
|
<p></p>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
|
|
||||||
<div id="sta-settings-busy" aria-busy="true"></div>
|
<div id="sta-settings-busy" aria-busy="true"></div>
|
||||||
<form action="/api/network/settings" id="sta-settings" class="hidden">
|
<form action="/api/network/settings" id="sta-settings" class="hidden">
|
||||||
<label for="sta-ssid">
|
<label for="sta-ssid">
|
||||||
SSID:
|
SSID:
|
||||||
<input type="text" class="sta-ssid" name="sta[ssid]" maxlength="32" required>
|
<input type="text" id="sta-ssid" name="sta[ssid]" maxlength="32" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="sta-password">
|
<label for="sta-password">
|
||||||
Password:
|
Password:
|
||||||
<input type="password" class="sta-password" name="sta[password]" maxlength="64" required>
|
<input type="password" id="sta-password" name="sta[password]" maxlength="64" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="sta-channel">
|
<label for="sta-channel">
|
||||||
Channel:
|
Channel:
|
||||||
<input type="number" inputmode="numeric" class="sta-channel" name="sta[channel]" min="0" max="12" step="1" required>
|
<input type="number" inputmode="numeric" id="sta-channel" name="sta[channel]" min="0" max="12" step="1" required>
|
||||||
<small>set 0 for auto select</small>
|
<small>set 0 for auto select</small>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -119,20 +129,24 @@
|
|||||||
<h2>AP settings</h2>
|
<h2>AP settings</h2>
|
||||||
<p></p>
|
<p></p>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
|
|
||||||
<div id="ap-settings-busy" aria-busy="true"></div>
|
<div id="ap-settings-busy" aria-busy="true"></div>
|
||||||
<form action="/api/network/settings" id="ap-settings" class="hidden">
|
<form action="/api/network/settings" id="ap-settings" class="hidden">
|
||||||
<label for="ap-ssid">
|
<label for="ap-ssid">
|
||||||
SSID:
|
SSID:
|
||||||
<input type="text" class="ap-ssid" name="ap[ssid]" maxlength="32" required>
|
<input type="text" id="ap-ssid" name="ap[ssid]" maxlength="32" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="ap-password">
|
<label for="ap-password">
|
||||||
Password:
|
Password:
|
||||||
<input type="text" class="ap-password" name="ap[password]" maxlength="64" required>
|
<input type="text" id="ap-password" name="ap[password]" maxlength="64" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="ap-channel">
|
<label for="ap-channel">
|
||||||
Channel:
|
Channel:
|
||||||
<input type="number" inputmode="numeric" class="ap-channel" name="ap[channel]" min="1" max="12" step="1" required>
|
<input type="number" inputmode="numeric" id="ap-channel" name="ap[channel]" min="1" max="12" step="1" required>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,7 +159,7 @@
|
|||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
|
• <a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
||||||
</small>
|
</small>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -153,14 +167,45 @@
|
|||||||
<script src="/static/app.js"></script>
|
<script src="/static/app.js"></script>
|
||||||
<script>
|
<script>
|
||||||
window.onload = async function () {
|
window.onload = async function () {
|
||||||
await loadNetworkSettings();
|
const fillData = (data) => {
|
||||||
|
setInputValue('#network-hostname', data.hostname);
|
||||||
|
setCheckboxValue('#network-use-dhcp', data.useDhcp);
|
||||||
|
setInputValue('#network-static-ip', data.staticConfig.ip);
|
||||||
|
setInputValue('#network-static-gateway', data.staticConfig.gateway);
|
||||||
|
setInputValue('#network-static-subnet', data.staticConfig.subnet);
|
||||||
|
setInputValue('#network-static-dns', data.staticConfig.dns);
|
||||||
|
setBusy('#network-settings-busy', '#network-settings', false);
|
||||||
|
|
||||||
setupForm('#network-settings');
|
setInputValue('#sta-ssid', data.sta.ssid);
|
||||||
setupNetworkScanForm('#network-scan', '#networks');
|
setInputValue('#sta-password', data.sta.password);
|
||||||
setupForm('#sta-settings');
|
setInputValue('#sta-channel', data.sta.channel);
|
||||||
setupForm('#ap-settings');
|
setBusy('#sta-settings-busy', '#sta-settings', false);
|
||||||
|
|
||||||
|
setInputValue('#ap-ssid', data.ap.ssid);
|
||||||
|
setInputValue('#ap-password', data.ap.password);
|
||||||
|
setInputValue('#ap-channel', data.ap.channel);
|
||||||
|
setBusy('#ap-settings-busy', '#ap-settings', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/network/settings', { cache: 'no-cache' });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Response not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
fillData(result);
|
||||||
|
|
||||||
|
setupForm('#network-settings', fillData, ['hostname']);
|
||||||
|
setupNetworkScanForm('#network-scan', '#networks');
|
||||||
|
setupForm('#sta-settings', fillData, ['sta.ssid', 'sta.password']);
|
||||||
|
setupForm('#ap-settings', fillData, ['ap.ssid', 'ap.password']);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
833
src_data/settings.html
Normal file
833
src_data/settings.html
Normal file
@@ -0,0 +1,833 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Settings - OpenTherm Gateway</title>
|
||||||
|
<link rel="stylesheet" href="/static/pico.min.css">
|
||||||
|
<link rel="stylesheet" href="/static/app.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header class="container">
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/"><div class="logo">OpenTherm Gateway</div></a></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/Laxilef/OTGateway/wiki" role="button" class="secondary" target="_blank">Help</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<article>
|
||||||
|
<hgroup>
|
||||||
|
<h2>Settings</h2>
|
||||||
|
<p></p>
|
||||||
|
</hgroup>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Portal settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="portal-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="portal-settings" class="hidden">
|
||||||
|
<div class="grid">
|
||||||
|
<label for="portal-login">
|
||||||
|
Login
|
||||||
|
<input type="text" id="portal-login" name="portal[login]" maxlength="12" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="portal-password">
|
||||||
|
Password
|
||||||
|
<input type="password" id="portal-password" name="portal[password]" maxlength="32" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="portal-auth">
|
||||||
|
<input type="checkbox" id="portal-auth" name="portal[auth]" value="true">
|
||||||
|
Require authentication
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>System settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="system-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="system-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Unit system</legend>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="system-unit-system" name="system[unitSystem]" value="0" />
|
||||||
|
Metric (celsius, liters, bar)
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="system-unit-system" name="system[unitSystem]" value="1" />
|
||||||
|
Imperial (fahrenheit, gallons, psi)
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<label for="system-status-led-gpio">
|
||||||
|
Status LED GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="system-status-led-gpio" name="system[statusLedGpio]" min="0" max="254" step="1">
|
||||||
|
<small>blank - not use</small>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Diagnostic</legend>
|
||||||
|
|
||||||
|
<label for="system-debug">
|
||||||
|
<input type="checkbox" id="system-debug" name="system[debug]" value="true">
|
||||||
|
Debug mode
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="system-serial-enable">
|
||||||
|
<input type="checkbox" id="system-serial-enable" name="system[serial][enable]" value="true">
|
||||||
|
Enable Serial port
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="system-telnet-enable">
|
||||||
|
<input type="checkbox" id="system-telnet-enable" name="system[telnet][enable]" value="true">
|
||||||
|
Enable Telnet
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="system-serial-baudrate">
|
||||||
|
Serial port baud rate
|
||||||
|
<input type="number" inputmode="numeric" id="system-serial-baudrate" name="system[serial][baudrate]" min="9600" max="115200" step="1" required>
|
||||||
|
<small>Available: 9600, 19200, 38400, 57600, 74880, 115200</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="system-telnet-port">
|
||||||
|
Telnet port
|
||||||
|
<input type="number" inputmode="numeric" id="system-telnet-port" name="system[telnet][port]" min="1" max="65535" step="1" required>
|
||||||
|
<small>Default: 23</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mark>After changing this settings, the ESP must be restarted for the changes to take effect.</mark>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Heating settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="heating-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="heating-settings" class="hidden">
|
||||||
|
<div class="grid">
|
||||||
|
<label for="heating-min-temp">
|
||||||
|
Minimum temperature
|
||||||
|
<input type="number" inputmode="numeric" id="heating-min-temp" name="heating[minTemp]" min="0" max="0" step="1" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="heating-max-temp">
|
||||||
|
Maximum temperature
|
||||||
|
<input type="number" inputmode="numeric" id="heating-max-temp" name="heating[maxTemp]" min="0" max="0" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="heating-hysteresis">
|
||||||
|
Hysteresis
|
||||||
|
<input type="number" inputmode="numeric" id="heating-hysteresis" name="heating[hysteresis]" min="0" max="5" step="0.05" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="heating-max-modulation">
|
||||||
|
Max modulation level
|
||||||
|
<input type="number" inputmode="numeric" id="heating-max-modulation" name="heating[maxModulation]" min="1" max="100" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>DHW settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="dhw-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="dhw-settings" class="hidden">
|
||||||
|
<div class="grid">
|
||||||
|
<label for="dhw-min-temp">
|
||||||
|
Minimum temperature
|
||||||
|
<input type="number" inputmode="numeric" id="dhw-min-temp" name="dhw[minTemp]" min="0" max="0" step="1" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="dhw-max-temp">
|
||||||
|
Maximum temperature
|
||||||
|
<input type="number" inputmode="numeric" id="dhw-max-temp" name="dhw[maxTemp]" min="0" max="0" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Emergency mode settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="emergency-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="emergency-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<label for="emergency-enable">
|
||||||
|
<input type="checkbox" id="emergency-enable" name="emergency[enable]" value="true">
|
||||||
|
Enable
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<small>
|
||||||
|
<b>!</b> Emergency mode can be useful <u>only</u> when using Equitherm and/or PID (when normal work) and when reporting indoor/outdoor temperature via MQTT or API. In this mode, sensor values that are reported via MQTT/API are not used.
|
||||||
|
</small>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="emergency-target">
|
||||||
|
Target temperature
|
||||||
|
<input type="number" inputmode="numeric" id="emergency-target" name="emergency[target]" min="0" max="0" step="1" required>
|
||||||
|
<small>
|
||||||
|
<u>Indoor temperature</u> if Equitherm or PID is <b>enabled</b><br />
|
||||||
|
<u>Heat carrier temperature</u> if Equitherm and PID <b>is disabled</b>
|
||||||
|
</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="emergency-treshold-time">
|
||||||
|
Treshold time <small>(sec)</small>
|
||||||
|
<input type="number" inputmode="numeric" id="emergency-treshold-time" name="emergency[tresholdTime]" min="60" max="1800" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Events</legend>
|
||||||
|
|
||||||
|
<label for="emergency-on-network-fault">
|
||||||
|
<input type="checkbox" id="emergency-on-network-fault" name="emergency[onNetworkFault]" value="true">
|
||||||
|
On network fault
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="emergency-on-mqtt-fault">
|
||||||
|
<input type="checkbox" id="emergency-on-mqtt-fault" name="emergency[onMqttFault]" value="true">
|
||||||
|
On MQTT fault
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Using regulators</legend>
|
||||||
|
|
||||||
|
<label for="emergency-use-equitherm">
|
||||||
|
<input type="checkbox" id="emergency-use-equitherm" name="emergency[useEquitherm]" value="true">
|
||||||
|
<span>
|
||||||
|
Equitherm <small>(requires at least an external/boiler <u>outdoor</u> sensor)</small>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label for="emergency-use-pid">
|
||||||
|
<input type="checkbox" id="emergency-use-pid" name="emergency[usePid]" value="true">
|
||||||
|
<span>
|
||||||
|
PID <small>(requires at least an external/BLE <u>indoor</u> sensor)</small>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Equitherm settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="equitherm-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="equitherm-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<label for="equitherm-enable">
|
||||||
|
<input type="checkbox" id="equitherm-enable" name="equitherm[enable]" value="true">
|
||||||
|
Enable
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="equitherm-n-factor">
|
||||||
|
N factor
|
||||||
|
<input type="number" inputmode="numeric" id="equitherm-n-factor" name="equitherm[n_factor]" min="0.001" max="10" step="0.001" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="equitherm-k-factor">
|
||||||
|
K factor
|
||||||
|
<input type="number" inputmode="numeric" id="equitherm-k-factor" name="equitherm[k_factor]" min="0" max="10" step="0.01" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="equitherm-t-factor">
|
||||||
|
T factor
|
||||||
|
<input type="number" inputmode="numeric" id="equitherm-t-factor" name="equitherm[t_factor]" min="0" max="10" step="0.01" required>
|
||||||
|
<small>Not used if PID is enabled</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>PID settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="pid-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="pid-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<label for="pid-enable">
|
||||||
|
<input type="checkbox" id="pid-enable" name="pid[enable]" value="true">
|
||||||
|
Enable
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="pid-p-factor">
|
||||||
|
P factor
|
||||||
|
<input type="number" inputmode="numeric" id="pid-p-factor" name="pid[p_factor]" min="0.1" max="1000" step="0.1" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="pid-i-factor">
|
||||||
|
I factor
|
||||||
|
<input type="number" inputmode="numeric" id="pid-i-factor" name="pid[i_factor]" min="0" max="100" step="0.0001" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="pid-d-factor">
|
||||||
|
D factor
|
||||||
|
<input type="number" inputmode="numeric" id="pid-d-factor" name="pid[d_factor]" min="0" max="100000" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="pid-dt">
|
||||||
|
DT <small>in seconds</small>
|
||||||
|
<input type="number" inputmode="numeric" id="pid-dt" name="pid[dt]" min="30" max="600" step="1" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="pid-min-temp">
|
||||||
|
Minimum temperature
|
||||||
|
<input type="number" inputmode="numeric" id="pid-min-temp" name="pid[minTemp]" min="0" max="0" step="1" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="pid-max-temp">
|
||||||
|
Maximum temperature
|
||||||
|
<input type="number" inputmode="numeric" id="pid-max-temp" name="pid[maxTemp]" min="0" max="0" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>OpenTherm settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="opentherm-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="opentherm-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Unit system</legend>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="opentherm-unit-system" name="opentherm[unitSystem]" value="0" />
|
||||||
|
Metric (celsius)
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="opentherm-unit-system" name="opentherm[unitSystem]" value="1" />
|
||||||
|
Imperial (fahrenheit)
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="opentherm-in-gpio">
|
||||||
|
In GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-in-gpio" name="opentherm[inGpio]" min="0" max="254" step="1">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-in-gpio">
|
||||||
|
Out GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-out-gpio" name="opentherm[outGpio]" min="0" max="254" step="1">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="opentherm-rx-led-gpio">
|
||||||
|
RX LED GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-rx-led-gpio" name="opentherm[rxLedGpio]" min="0" max="254" step="1">
|
||||||
|
<small>blank - not use</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-member-id-code">
|
||||||
|
Master MemberID code
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-member-id-code" name="opentherm[memberIdCode]" min="0" max="65535" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Options</legend>
|
||||||
|
<label for="opentherm-dhw-present">
|
||||||
|
<input type="checkbox" id="opentherm-dhw-present" name="opentherm[dhwPresent]" value="true">
|
||||||
|
DHW present
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-sw-mode">
|
||||||
|
<input type="checkbox" id="opentherm-sw-mode" name="opentherm[summerWinterMode]" value="true">
|
||||||
|
Summer/winter mode
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-heating-ch2-enabled">
|
||||||
|
<input type="checkbox" id="opentherm-heating-ch2-enabled" name="opentherm[heatingCh2Enabled]" value="true">
|
||||||
|
Heating CH2 always enabled
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-heating-ch1-to-ch2">
|
||||||
|
<input type="checkbox" id="opentherm-heating-ch1-to-ch2" name="opentherm[heatingCh1ToCh2]" value="true">
|
||||||
|
Duplicate heating CH1 to CH2
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-dhw-to-ch2">
|
||||||
|
<input type="checkbox" id="opentherm-dhw-to-ch2" name="opentherm[dhwToCh2]" value="true">
|
||||||
|
Duplicate DHW to CH2
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-dhw-blocking">
|
||||||
|
<input type="checkbox" id="opentherm-dhw-blocking" name="opentherm[dhwBlocking]" value="true">
|
||||||
|
DHW blocking
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-sync-modulation-with-heating">
|
||||||
|
<input type="checkbox" id="opentherm-sync-modulation-with-heating" name="opentherm[modulationSyncWithHeating]" value="true">
|
||||||
|
Sync modulation with heating
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-get-min-max-temp">
|
||||||
|
<input type="checkbox" id="opentherm-get-min-max-temp" name="opentherm[getMinMaxTemp]" value="true">
|
||||||
|
Get min/max temp from boiler
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<fieldset>
|
||||||
|
<label for="opentherm-fault-state-gpio">
|
||||||
|
Fault state GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="opentherm-fault-state-gpio" name="opentherm[faultStateGpio]" min="0" max="254" step="1">
|
||||||
|
<small>Can be useful to switch on another boiler <u>via relay</u>. Blank - not use.</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="opentherm-invert-fault-state">
|
||||||
|
<input type="checkbox" id="opentherm-invert-fault-state" name="opentherm[invertFaultState]" value="true">
|
||||||
|
Invert fault state
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<label for="opentherm-native-heating-control">
|
||||||
|
<input type="checkbox" id="opentherm-native-heating-control" name="opentherm[nativeHeatingControl]" value="true">
|
||||||
|
Native heating control (boiler)<br />
|
||||||
|
<small>Works <u>ONLY</u> if the boiler requires the desired room temperature and regulates the temperature of the coolant itself. Not compatible with PID and Equitherm regulators and hysteresis in firmware.</small>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>MQTT settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="mqtt-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="mqtt-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<label for="mqtt-enable">
|
||||||
|
<input type="checkbox" id="mqtt-enable" name="mqtt[enable]" value="true">
|
||||||
|
Enable
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="mqtt-ha-discovery">
|
||||||
|
<input type="checkbox" id="mqtt-ha-discovery" name="mqtt[homeAssistantDiscovery]" value="true">
|
||||||
|
Home Assistant Discovery
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="mqtt-server">
|
||||||
|
Server
|
||||||
|
<input type="text" id="mqtt-server" name="mqtt[server]" maxlength="80" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="mqtt-port">
|
||||||
|
Port
|
||||||
|
<input type="number" inputmode="numeric" id="mqtt-port" name="mqtt[port]" min="1" max="65535" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="mqtt-user">
|
||||||
|
User
|
||||||
|
<input type="text" id="mqtt-user" name="mqtt[user]" maxlength="32" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="mqtt-password">
|
||||||
|
Password
|
||||||
|
<input type="password" id="mqtt-password" name="mqtt[password]" maxlength="32">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="mqtt-prefix">
|
||||||
|
Prefix
|
||||||
|
<input type="text" id="mqtt-prefix" name="mqtt[prefix]" maxlength="32" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="mqtt-interval">
|
||||||
|
Publish interval <small>(sec)</small>
|
||||||
|
<input type="number" inputmode="numeric" id="mqtt-interval" name="mqtt[interval]" min="3" max="60" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Outdoor sensor settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="outdoor-sensor-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="outdoor-sensor-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Source type</legend>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="0" />
|
||||||
|
From boiler via OpenTherm
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="1" />
|
||||||
|
Manual via MQTT/API
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="outdoor-sensor-type" name="sensors[outdoor][type]" value="2" />
|
||||||
|
External (DS18B20)
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<label for="outdoor-sensor-gpio">
|
||||||
|
GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="outdoor-sensor-gpio" name="sensors[outdoor][gpio]" min="0" max="254" step="1">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="outdoor-sensor-offset">
|
||||||
|
Temp offset (calibration)
|
||||||
|
<input type="number" inputmode="numeric" id="outdoor-sensor-offset" name="sensors[outdoor][offset]" min="-10" max="10" step="0.01" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Indoor sensor settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="indoor-sensor-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="indoor-sensor-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Source type</legend>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="1" />
|
||||||
|
Manual via MQTT/API
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="2" />
|
||||||
|
External (DS18B20)
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" class="indoor-sensor-type" name="sensors[indoor][type]" value="3" />
|
||||||
|
BLE device <i>(ONLY for some ESP32 which support BLE)</i>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<label for="indoor-sensor-gpio">
|
||||||
|
GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="indoor-sensor-gpio" name="sensors[indoor][gpio]" min="0" max="254" step="1">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="indoor-sensor-offset">
|
||||||
|
Temp offset (calibration)
|
||||||
|
<input type="number" inputmode="numeric" id="indoor-sensor-offset" name="sensors[indoor][offset]" min="-10" max="10" step="0.01" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="indoor-sensor-ble-addresss">
|
||||||
|
BLE addresss
|
||||||
|
<input type="text" id="indoor-sensor-ble-addresss" name="sensors[indoor][bleAddresss]" pattern="([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}">
|
||||||
|
<small>ONLY for some ESP32 which support BLE</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>External pump settings</b></summary>
|
||||||
|
<div>
|
||||||
|
<div id="extpump-settings-busy" aria-busy="true"></div>
|
||||||
|
<form action="/api/settings" id="extpump-settings" class="hidden">
|
||||||
|
<fieldset>
|
||||||
|
<label for="extpump-use">
|
||||||
|
<input type="checkbox" id="extpump-use" name="externalPump[use]" value="true">
|
||||||
|
Use external pump
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="extpump-gpio">
|
||||||
|
Relay GPIO
|
||||||
|
<input type="number" inputmode="numeric" id="extpump-gpio" name="externalPump[gpio]" min="0" max="254" step="1">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="extpump-pc-time">
|
||||||
|
Post circulation time <small>(min)</small>
|
||||||
|
<input type="number" inputmode="numeric" id="extpump-pc-time" name="externalPump[postCirculationTime]" min="1" max="120" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label for="extpump-as-interval">
|
||||||
|
Anti stuck interval <small>(days)</small>
|
||||||
|
<input type="number" inputmode="numeric" id="extpump-as-interval" name="externalPump[antiStuckInterval]" min="1" max="366" step="1" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="extpump-as-time">
|
||||||
|
Anti stuck time <small>(min)</small>
|
||||||
|
<input type="number" inputmode="numeric" id="extpump-as-time" name="externalPump[antiStuckTime]" min="1" max="20" step="1" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="container">
|
||||||
|
<small>
|
||||||
|
<b>Made by Laxilef</b>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
|
||||||
|
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
||||||
|
</small>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="/static/app.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = async function () {
|
||||||
|
const fillData = (data) => {
|
||||||
|
// System
|
||||||
|
setCheckboxValue('#system-debug', data.system.debug);
|
||||||
|
setCheckboxValue('#system-serial-enable', data.system.serial.enable);
|
||||||
|
setInputValue('#system-serial-baudrate', data.system.serial.baudrate);
|
||||||
|
setCheckboxValue('#system-telnet-enable', data.system.telnet.enable);
|
||||||
|
setInputValue('#system-telnet-port', data.system.telnet.port);
|
||||||
|
setRadioValue('.system-unit-system', data.system.unitSystem);
|
||||||
|
setInputValue('#system-status-led-gpio', data.system.statusLedGpio < 255 ? data.system.statusLedGpio : '');
|
||||||
|
setBusy('#system-settings-busy', '#system-settings', false);
|
||||||
|
|
||||||
|
// Portal
|
||||||
|
setCheckboxValue('#portal-auth', data.portal.auth);
|
||||||
|
setInputValue('#portal-login', data.portal.login);
|
||||||
|
setInputValue('#portal-password', data.portal.password);
|
||||||
|
setBusy('#portal-settings-busy', '#portal-settings', false);
|
||||||
|
|
||||||
|
// Opentherm
|
||||||
|
setRadioValue('.opentherm-unit-system', data.opentherm.unitSystem);
|
||||||
|
setInputValue('#opentherm-in-gpio', data.opentherm.inGpio < 255 ? data.opentherm.inGpio : '');
|
||||||
|
setInputValue('#opentherm-out-gpio', data.opentherm.outGpio < 255 ? data.opentherm.outGpio : '');
|
||||||
|
setInputValue('#opentherm-rx-led-gpio', data.opentherm.rxLedGpio < 255 ? data.opentherm.rxLedGpio : '');
|
||||||
|
setInputValue('#opentherm-fault-state-gpio', data.opentherm.faultStateGpio < 255 ? data.opentherm.faultStateGpio : '');
|
||||||
|
setCheckboxValue('#opentherm-invert-fault-state', data.opentherm.invertFaultState);
|
||||||
|
setInputValue('#opentherm-member-id-code', data.opentherm.memberIdCode);
|
||||||
|
setCheckboxValue('#opentherm-dhw-present', data.opentherm.dhwPresent);
|
||||||
|
setCheckboxValue('#opentherm-sw-mode', data.opentherm.summerWinterMode);
|
||||||
|
setCheckboxValue('#opentherm-heating-ch2-enabled', data.opentherm.heatingCh2Enabled);
|
||||||
|
setCheckboxValue('#opentherm-heating-ch1-to-ch2', data.opentherm.heatingCh1ToCh2);
|
||||||
|
setCheckboxValue('#opentherm-dhw-to-ch2', data.opentherm.dhwToCh2);
|
||||||
|
setCheckboxValue('#opentherm-dhw-blocking', data.opentherm.dhwBlocking);
|
||||||
|
setCheckboxValue('#opentherm-sync-modulation-with-heating', data.opentherm.modulationSyncWithHeating);
|
||||||
|
setCheckboxValue('#opentherm-get-min-max-temp', data.opentherm.getMinMaxTemp);
|
||||||
|
setCheckboxValue('#opentherm-native-heating-control', data.opentherm.nativeHeatingControl);
|
||||||
|
setBusy('#opentherm-settings-busy', '#opentherm-settings', false);
|
||||||
|
|
||||||
|
// MQTT
|
||||||
|
setCheckboxValue('#mqtt-enable', data.mqtt.enable);
|
||||||
|
setCheckboxValue('#mqtt-ha-discovery', data.mqtt.homeAssistantDiscovery);
|
||||||
|
setInputValue('#mqtt-server', data.mqtt.server);
|
||||||
|
setInputValue('#mqtt-port', data.mqtt.port);
|
||||||
|
setInputValue('#mqtt-user', data.mqtt.user);
|
||||||
|
setInputValue('#mqtt-password', data.mqtt.password);
|
||||||
|
setInputValue('#mqtt-prefix', data.mqtt.prefix);
|
||||||
|
setInputValue('#mqtt-interval', data.mqtt.interval);
|
||||||
|
setBusy('#mqtt-settings-busy', '#mqtt-settings', false);
|
||||||
|
|
||||||
|
// Outdoor sensor
|
||||||
|
setRadioValue('.outdoor-sensor-type', data.sensors.outdoor.type);
|
||||||
|
setInputValue('#outdoor-sensor-gpio', data.sensors.outdoor.gpio < 255 ? data.sensors.outdoor.gpio : '');
|
||||||
|
setInputValue('#outdoor-sensor-offset', data.sensors.outdoor.offset);
|
||||||
|
setBusy('#outdoor-sensor-settings-busy', '#outdoor-sensor-settings', false);
|
||||||
|
|
||||||
|
// Indoor sensor
|
||||||
|
setRadioValue('.indoor-sensor-type', data.sensors.indoor.type);
|
||||||
|
setInputValue('#indoor-sensor-gpio', data.sensors.indoor.gpio < 255 ? data.sensors.indoor.gpio : '');
|
||||||
|
setInputValue('#indoor-sensor-offset', data.sensors.indoor.offset);
|
||||||
|
setInputValue('#indoor-sensor-ble-addresss', data.sensors.indoor.bleAddresss);
|
||||||
|
setBusy('#indoor-sensor-settings-busy', '#indoor-sensor-settings', false);
|
||||||
|
|
||||||
|
// Extpump
|
||||||
|
setCheckboxValue('#extpump-use', data.externalPump.use);
|
||||||
|
setInputValue('#extpump-gpio', data.externalPump.gpio < 255 ? data.externalPump.gpio : '');
|
||||||
|
setInputValue('#extpump-pc-time', data.externalPump.postCirculationTime);
|
||||||
|
setInputValue('#extpump-as-interval', data.externalPump.antiStuckInterval);
|
||||||
|
setInputValue('#extpump-as-time', data.externalPump.antiStuckTime);
|
||||||
|
setBusy('#extpump-settings-busy', '#extpump-settings', false);
|
||||||
|
|
||||||
|
// Heating
|
||||||
|
setInputValue('#heating-min-temp', data.heating.minTemp, {
|
||||||
|
"min": data.system.unitSystem == 0 ? 0 : 32,
|
||||||
|
"max": data.system.unitSystem == 0 ? 99 : 211
|
||||||
|
});
|
||||||
|
setInputValue('#heating-max-temp', data.heating.maxTemp, {
|
||||||
|
"min": data.system.unitSystem == 0 ? 1 : 33,
|
||||||
|
"max": data.system.unitSystem == 0 ? 100 : 212
|
||||||
|
});
|
||||||
|
setInputValue('#heating-hysteresis', data.heating.hysteresis);
|
||||||
|
setInputValue('#heating-max-modulation', data.heating.maxModulation);
|
||||||
|
setBusy('#heating-settings-busy', '#heating-settings', false);
|
||||||
|
|
||||||
|
// DHW
|
||||||
|
setInputValue('#dhw-min-temp', data.dhw.minTemp, {
|
||||||
|
"min": data.system.unitSystem == 0 ? 0 : 32,
|
||||||
|
"max": data.system.unitSystem == 0 ? 99 : 211
|
||||||
|
});
|
||||||
|
setInputValue('#dhw-max-temp', data.dhw.maxTemp, {
|
||||||
|
"min": data.system.unitSystem == 0 ? 1 : 33,
|
||||||
|
"max": data.system.unitSystem == 0 ? 100 : 212
|
||||||
|
});
|
||||||
|
setBusy('#dhw-settings-busy', '#dhw-settings', false);
|
||||||
|
|
||||||
|
// Emergency mode
|
||||||
|
setCheckboxValue('#emergency-enable', data.emergency.enable);
|
||||||
|
setInputValue('#emergency-treshold-time', data.emergency.tresholdTime);
|
||||||
|
setCheckboxValue('#emergency-use-equitherm', data.emergency.useEquitherm);
|
||||||
|
setCheckboxValue('#emergency-use-pid', data.emergency.usePid);
|
||||||
|
setCheckboxValue('#emergency-on-network-fault', data.emergency.onNetworkFault);
|
||||||
|
setCheckboxValue('#emergency-on-mqtt-fault', data.emergency.onMqttFault);
|
||||||
|
setInputValue('#emergency-target', data.emergency.target, {
|
||||||
|
"min": (!data.emergency.useEquitherm && !data.emergency.usePid) ? data.heating.minTemp : 10,
|
||||||
|
"max": (!data.emergency.useEquitherm && !data.emergency.usePid) ? data.heating.maxTemp : 30,
|
||||||
|
});
|
||||||
|
setBusy('#emergency-settings-busy', '#emergency-settings', false);
|
||||||
|
|
||||||
|
// Equitherm
|
||||||
|
setCheckboxValue('#equitherm-enable', data.equitherm.enable);
|
||||||
|
setInputValue('#equitherm-n-factor', data.equitherm.n_factor);
|
||||||
|
setInputValue('#equitherm-k-factor', data.equitherm.k_factor);
|
||||||
|
setInputValue('#equitherm-t-factor', data.equitherm.t_factor);
|
||||||
|
setBusy('#equitherm-settings-busy', '#equitherm-settings', false);
|
||||||
|
|
||||||
|
// PID
|
||||||
|
setCheckboxValue('#pid-enable', data.pid.enable);
|
||||||
|
setInputValue('#pid-p-factor', data.pid.p_factor);
|
||||||
|
setInputValue('#pid-i-factor', data.pid.i_factor);
|
||||||
|
setInputValue('#pid-d-factor', data.pid.d_factor);
|
||||||
|
setInputValue('#pid-dt', data.pid.dt);
|
||||||
|
setInputValue('#pid-min-temp', data.pid.minTemp, {
|
||||||
|
"min": 0,
|
||||||
|
"max": data.system.unitSystem == 0 ? 99 : 211
|
||||||
|
});
|
||||||
|
setInputValue('#pid-max-temp', data.pid.maxTemp, {
|
||||||
|
"min": 1,
|
||||||
|
"max": data.system.unitSystem == 0 ? 100 : 212
|
||||||
|
});
|
||||||
|
setBusy('#pid-settings-busy', '#pid-settings', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/settings', { cache: 'no-cache' });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Response not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
fillData(result);
|
||||||
|
|
||||||
|
setupForm('#portal-settings', fillData, ['portal.login', 'portal.password']);
|
||||||
|
setupForm('#system-settings', fillData);
|
||||||
|
setupForm('#heating-settings', fillData);
|
||||||
|
setupForm('#dhw-settings', fillData);
|
||||||
|
setupForm('#emergency-settings', fillData);
|
||||||
|
setupForm('#equitherm-settings', fillData);
|
||||||
|
setupForm('#pid-settings', fillData);
|
||||||
|
setupForm('#opentherm-settings', fillData);
|
||||||
|
setupForm('#mqtt-settings', fillData, ['mqtt.user', 'mqtt.password', 'mqtt.prefix']);
|
||||||
|
setupForm('#outdoor-sensor-settings', fillData);
|
||||||
|
setupForm('#indoor-sensor-settings', fillData, ['sensors.indoor.bleAddresss']);
|
||||||
|
setupForm('#extpump-settings', fillData);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,22 +1,47 @@
|
|||||||
|
@media (min-width: 576px) {
|
||||||
|
article {
|
||||||
|
--pico-block-spacing-vertical: calc(var(--pico-spacing) * 0.75);
|
||||||
|
--pico-block-spacing-horizontal: calc(var(--pico-spacing) * 0.75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
article {
|
||||||
|
--pico-block-spacing-vertical: var(--pico-spacing);
|
||||||
|
--pico-block-spacing-horizontal: var(--pico-spacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
article {
|
||||||
|
--pico-block-spacing-vertical: calc(var(--pico-spacing) * 1.25);
|
||||||
|
--pico-block-spacing-horizontal: calc(var(--pico-spacing) * 1.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 1280px) {
|
@media (min-width: 1280px) {
|
||||||
|
article {
|
||||||
|
--pico-block-spacing-vertical: calc(var(--pico-spacing) * 1.5);
|
||||||
|
--pico-block-spacing-horizontal: calc(var(--pico-spacing) * 1.5);
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1536px) {
|
@media (min-width: 1536px) {
|
||||||
|
article {
|
||||||
|
--pico-block-spacing-vertical: calc(var(--pico-spacing) * 1.75);
|
||||||
|
--pico-block-spacing-horizontal: calc(var(--pico-spacing) * 1.75);
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
header, main, footer {
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
header,
|
|
||||||
main,
|
|
||||||
footer {
|
|
||||||
padding-top: 1rem !important;
|
padding-top: 1rem !important;
|
||||||
padding-bottom: 1rem !important;
|
padding-bottom: 1rem !important;
|
||||||
}
|
}
|
||||||
@@ -29,6 +54,23 @@ footer {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav li a:has(> div.logo) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
details > div {
|
||||||
|
padding: 0 var(--pico-form-element-spacing-horizontal);
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
button.success {
|
button.success {
|
||||||
background-color: var(--pico-form-element-valid-border-color);
|
background-color: var(--pico-form-element-valid-border-color);
|
||||||
border-color: var(--pico-form-element-valid-border-color);
|
border-color: var(--pico-form-element-valid-border-color);
|
||||||
@@ -44,18 +86,6 @@ tr.network:hover {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.greatSignal {
|
|
||||||
background-color: var(--pico-form-element-valid-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.normalSignal {
|
|
||||||
background-color: #e48500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.badSignal {
|
|
||||||
background-color: var(--pico-form-element-invalid-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary {
|
.primary {
|
||||||
border: 0.25rem solid var(--pico-form-element-invalid-border-color);
|
border: 0.25rem solid var(--pico-form-element-invalid-border-color);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@@ -75,6 +105,90 @@ tr.network:hover {
|
|||||||
font-family: var(--pico-font-family-monospace);
|
font-family: var(--pico-font-family-monospace);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav li a:has(> div.logo) {
|
.thermostat {
|
||||||
margin-bottom: 0;
|
display: grid;
|
||||||
}
|
grid-template-columns: 0.5fr 2fr 0.5fr;
|
||||||
|
grid-template-rows: 0.25fr 1fr 0.25fr;
|
||||||
|
gap: 0px 0px;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
justify-content: center;
|
||||||
|
justify-items: center;
|
||||||
|
grid-template-areas:
|
||||||
|
". thermostat-header ."
|
||||||
|
"thermostat-minus thermostat-temp thermostat-plus"
|
||||||
|
"thermostat-control thermostat-control thermostat-control";
|
||||||
|
|
||||||
|
border: .25rem solid var(--pico-blockquote-border-color);
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-header {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: end;
|
||||||
|
grid-area: thermostat-header;
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: .25rem solid var(--pico-primary-hover-border);
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-temp {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 0.5fr;
|
||||||
|
gap: 0px 0px;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
grid-template-areas:
|
||||||
|
"thermostat-temp-target"
|
||||||
|
"thermostat-temp-current";
|
||||||
|
grid-area: thermostat-temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-temp-target {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: center;
|
||||||
|
grid-area: thermostat-temp-target;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-temp-current {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: start;
|
||||||
|
grid-area: thermostat-temp-current;
|
||||||
|
|
||||||
|
color: var(--pico-secondary);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-minus {
|
||||||
|
justify-self: end;
|
||||||
|
align-self: center;
|
||||||
|
grid-area: thermostat-minus;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-plus {
|
||||||
|
justify-self: start;
|
||||||
|
align-self: center;
|
||||||
|
grid-area: thermostat-plus;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thermostat-control {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: start;
|
||||||
|
grid-area: thermostat-control;
|
||||||
|
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*=" icons-"],[class=icons],[class^=icons-] {font-size: 1.35rem; }
|
||||||
|
*:has(> [class*=" icons-"], > [class=icons], > [class^=icons-]):has(+ * > [class*=" icons-"], + * > [class=icons], + * > [class^=icons-]) { margin: 0 0.5rem 0 0; }
|
||||||
|
[data-tooltip]:has(> [class*=" icons-"], > [class=icons], > [class^=icons-]) { border: 0!important; }
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Icons icon font. Generated by Iconly: https://iconly.io/
|
||||||
|
*/
|
||||||
|
@font-face{font-display:auto;font-family:"Icons";font-style:normal;font-weight:400;src:url(./fonts/iconly.eot?1717885802370);src:url(./fonts/iconly.eot?#iefix) format("embedded-opentype"),url(./fonts/iconly.woff2?1717885802370) format("woff2"),url(./fonts/iconly.woff?1717885802370) format("woff"),url(./fonts/iconly.ttf?1717885802370) format("truetype")}[class*=" icons-"],[class=icons],[class^=icons-]{display:inline-block;font-family:"Icons"!important;font-weight:400;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.icons-plus:before{content:"\e000"}.icons-minus:before{content:"\e001"}.icons-unlocked:before{content:"\e002"}.icons-locked:before{content:"\e003"}.icons-wifi-strength-1:before{content:"\e004"}.icons-wifi-strength-0:before{content:"\e005"}.icons-wifi-strength-2:before{content:"\e006"}.icons-wifi-strength-3:before{content:"\e008"}.icons-down:before{content:"\e009"}.icons-wifi-strength-4:before{content:"\e00a"}.icons-up:before{content:"\e00c"}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
function setupForm(formSelector) {
|
function setupForm(formSelector, onResultCallback = null, noCastItems = []) {
|
||||||
const form = document.querySelector(formSelector);
|
const form = document.querySelector(formSelector);
|
||||||
if (!form) {
|
if (!form) {
|
||||||
return;
|
return;
|
||||||
@@ -27,7 +27,7 @@ function setupForm(formSelector) {
|
|||||||
button.setAttribute('aria-busy', true);
|
button.setAttribute('aria-busy', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSuccess = (response) => {
|
const onSuccess = (result) => {
|
||||||
if (button) {
|
if (button) {
|
||||||
button.textContent = 'Saved';
|
button.textContent = 'Saved';
|
||||||
button.classList.add('success');
|
button.classList.add('success');
|
||||||
@@ -41,7 +41,7 @@ function setupForm(formSelector) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFailed = (response) => {
|
const onFailed = () => {
|
||||||
if (button) {
|
if (button) {
|
||||||
button.textContent = 'Error';
|
button.textContent = 'Error';
|
||||||
button.classList.add('failed');
|
button.classList.add('failed');
|
||||||
@@ -68,18 +68,23 @@ function setupForm(formSelector) {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: form2json(fd)
|
body: form2json(fd, noCastItems)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (!response.ok) {
|
||||||
onSuccess(response);
|
throw new Error('Response not valid');
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
const result = response.status != 204 ? (await response.json()) : null;
|
||||||
onFailed(response);
|
onSuccess(result);
|
||||||
|
|
||||||
|
if (onResultCallback instanceof Function) {
|
||||||
|
onResultCallback(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
onFailed(false);
|
console.log(err);
|
||||||
|
onFailed();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -134,7 +139,7 @@ function setupNetworkScanForm(formSelector, tableSelector) {
|
|||||||
row.classList.add("network");
|
row.classList.add("network");
|
||||||
row.setAttribute('data-ssid', result[i].hidden ? '' : result[i].ssid);
|
row.setAttribute('data-ssid', result[i].hidden ? '' : result[i].ssid);
|
||||||
row.onclick = function () {
|
row.onclick = function () {
|
||||||
const input = document.querySelector('input.sta-ssid');
|
const input = document.querySelector('input#sta-ssid');
|
||||||
const ssid = this.getAttribute('data-ssid');
|
const ssid = this.getAttribute('data-ssid');
|
||||||
if (!input || !ssid) {
|
if (!input || !ssid) {
|
||||||
return;
|
return;
|
||||||
@@ -145,19 +150,56 @@ function setupNetworkScanForm(formSelector, tableSelector) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
row.insertCell().textContent = "#" + (i + 1);
|
row.insertCell().textContent = "#" + (i + 1);
|
||||||
row.insertCell().innerHTML = result[i].hidden ? '<i>Hidden</i>' : result[i].ssid;
|
row.insertCell().innerHTML = result[i].hidden ? ("<i>" + result[i].bssid + "</i>") : result[i].ssid;
|
||||||
|
|
||||||
const signalCell = row.insertCell();
|
// info cell
|
||||||
const signalElement = document.createElement("kbd");
|
let infoCell = row.insertCell();
|
||||||
signalElement.textContent = result[i].signalQuality + "%";
|
|
||||||
if (result[i].signalQuality > 60) {
|
// signal quality
|
||||||
signalElement.classList.add('greatSignal');
|
let signalQualityIcon = document.createElement("i");
|
||||||
|
if (result[i].signalQuality > 80) {
|
||||||
|
signalQualityIcon.classList.add('icons-wifi-strength-4');
|
||||||
|
} else if (result[i].signalQuality > 60) {
|
||||||
|
signalQualityIcon.classList.add('icons-wifi-strength-3');
|
||||||
} else if (result[i].signalQuality > 40) {
|
} else if (result[i].signalQuality > 40) {
|
||||||
signalElement.classList.add('normalSignal');
|
signalQualityIcon.classList.add('icons-wifi-strength-2');
|
||||||
|
} else if (result[i].signalQuality > 20) {
|
||||||
|
signalQualityIcon.classList.add('icons-wifi-strength-1');
|
||||||
} else {
|
} else {
|
||||||
signalElement.classList.add('badSignal');
|
signalQualityIcon.classList.add('icons-wifi-strength-0');
|
||||||
}
|
}
|
||||||
signalCell.appendChild(signalElement);
|
|
||||||
|
let signalQualityContainer = document.createElement("span");
|
||||||
|
signalQualityContainer.setAttribute('data-tooltip', result[i].signalQuality + "%");
|
||||||
|
signalQualityContainer.appendChild(signalQualityIcon);
|
||||||
|
infoCell.appendChild(signalQualityContainer);
|
||||||
|
|
||||||
|
// auth
|
||||||
|
const authList = {
|
||||||
|
0: "Open",
|
||||||
|
1: "WEP",
|
||||||
|
2: "WPA",
|
||||||
|
3: "WPA2",
|
||||||
|
4: "WPA/WPA2",
|
||||||
|
5: "WPA/WPA2 Enterprise",
|
||||||
|
6: "WPA3",
|
||||||
|
7: "WPA2/WPA3",
|
||||||
|
8: "WAPI",
|
||||||
|
9: "OWE",
|
||||||
|
10: "WPA3 Enterprise"
|
||||||
|
};
|
||||||
|
let authIcon = document.createElement("i");
|
||||||
|
|
||||||
|
if (result[i].auth == 0) {
|
||||||
|
authIcon.classList.add('icons-unlocked');
|
||||||
|
} else {
|
||||||
|
authIcon.classList.add('icons-locked');
|
||||||
|
}
|
||||||
|
|
||||||
|
let authContainer = document.createElement("span");
|
||||||
|
authContainer.setAttribute('data-tooltip', (result[i].auth in authList) ? authList[result[i].auth] : "unknown");
|
||||||
|
authContainer.appendChild(authIcon);
|
||||||
|
infoCell.appendChild(authContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (button) {
|
if (button) {
|
||||||
@@ -410,6 +452,9 @@ function setupUpgradeForm(formSelector) {
|
|||||||
form.addEventListener('submit', async (event) => {
|
form.addEventListener('submit', async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
hide('.upgrade-firmware-result');
|
||||||
|
hide('.upgrade-filesystem-result');
|
||||||
|
|
||||||
if (button) {
|
if (button) {
|
||||||
button.textContent = 'Uploading...';
|
button.textContent = 'Uploading...';
|
||||||
button.setAttribute('disabled', true);
|
button.setAttribute('disabled', true);
|
||||||
@@ -437,157 +482,15 @@ function setupUpgradeForm(formSelector) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadNetworkStatus() {
|
|
||||||
let response = await fetch('/api/network/status', { cache: 'no-cache' });
|
|
||||||
let result = await response.json();
|
|
||||||
|
|
||||||
setValue('.network-hostname', result.hostname);
|
|
||||||
setValue('.network-mac', result.mac);
|
|
||||||
setState('.network-connected', result.isConnected);
|
|
||||||
setValue('.network-ssid', result.ssid);
|
|
||||||
setValue('.network-signal', result.signalQuality);
|
|
||||||
setValue('.network-ip', result.ip);
|
|
||||||
setValue('.network-subnet', result.subnet);
|
|
||||||
setValue('.network-gateway', result.gateway);
|
|
||||||
setValue('.network-dns', result.dns);
|
|
||||||
|
|
||||||
setBusy('.main-busy', '.main-table', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadNetworkSettings() {
|
|
||||||
let response = await fetch('/api/network/settings', { cache: 'no-cache' });
|
|
||||||
let result = await response.json();
|
|
||||||
|
|
||||||
setInputValue('.network-hostname', result.hostname);
|
|
||||||
setCheckboxValue('.network-use-dhcp', result.useDhcp);
|
|
||||||
setInputValue('.network-static-ip', result.staticConfig.ip);
|
|
||||||
setInputValue('.network-static-gateway', result.staticConfig.gateway);
|
|
||||||
setInputValue('.network-static-subnet', result.staticConfig.subnet);
|
|
||||||
setInputValue('.network-static-dns', result.staticConfig.dns);
|
|
||||||
setBusy('#network-settings-busy', '#network-settings', false);
|
|
||||||
|
|
||||||
setInputValue('.sta-ssid', result.sta.ssid);
|
|
||||||
setInputValue('.sta-password', result.sta.password);
|
|
||||||
setInputValue('.sta-channel', result.sta.channel);
|
|
||||||
setBusy('#sta-settings-busy', '#sta-settings', false);
|
|
||||||
|
|
||||||
setInputValue('.ap-ssid', result.ap.ssid);
|
|
||||||
setInputValue('.ap-password', result.ap.password);
|
|
||||||
setInputValue('.ap-channel', result.ap.channel);
|
|
||||||
setBusy('#ap-settings-busy', '#ap-settings', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadSettings() {
|
|
||||||
let response = await fetch('/api/settings', { cache: 'no-cache' });
|
|
||||||
let result = await response.json();
|
|
||||||
|
|
||||||
setCheckboxValue('.system-debug', result.system.debug);
|
|
||||||
setCheckboxValue('.system-use-serial', result.system.useSerial);
|
|
||||||
setCheckboxValue('.system-use-telnet', result.system.useTelnet);
|
|
||||||
setBusy('#system-settings-busy', '#system-settings', false);
|
|
||||||
|
|
||||||
setCheckboxValue('.portal-use-auth', result.portal.useAuth);
|
|
||||||
setInputValue('.portal-login', result.portal.login);
|
|
||||||
setInputValue('.portal-password', result.portal.password);
|
|
||||||
setBusy('#portal-settings-busy', '#portal-settings', false);
|
|
||||||
|
|
||||||
setInputValue('.opentherm-in-pin', result.opentherm.inPin);
|
|
||||||
setInputValue('.opentherm-out-pin', result.opentherm.outPin);
|
|
||||||
setInputValue('.opentherm-member-id-code', result.opentherm.memberIdCode);
|
|
||||||
setCheckboxValue('.opentherm-dhw-present', result.opentherm.dhwPresent);
|
|
||||||
setCheckboxValue('.opentherm-sw-mode', result.opentherm.summerWinterMode);
|
|
||||||
setCheckboxValue('.opentherm-heating-ch2-enabled', result.opentherm.heatingCh2Enabled);
|
|
||||||
setCheckboxValue('.opentherm-heating-ch1-to-ch2', result.opentherm.heatingCh1ToCh2);
|
|
||||||
setCheckboxValue('.opentherm-dhw-to-ch2', result.opentherm.dhwToCh2);
|
|
||||||
setCheckboxValue('.opentherm-dhw-blocking', result.opentherm.dhwBlocking);
|
|
||||||
setCheckboxValue('.opentherm-sync-modulation-with-heating', result.opentherm.modulationSyncWithHeating);
|
|
||||||
setBusy('#opentherm-settings-busy', '#opentherm-settings', false);
|
|
||||||
|
|
||||||
setInputValue('.mqtt-server', result.mqtt.server);
|
|
||||||
setInputValue('.mqtt-port', result.mqtt.port);
|
|
||||||
setInputValue('.mqtt-user', result.mqtt.user);
|
|
||||||
setInputValue('.mqtt-password', result.mqtt.password);
|
|
||||||
setInputValue('.mqtt-prefix', result.mqtt.prefix);
|
|
||||||
setInputValue('.mqtt-interval', result.mqtt.interval);
|
|
||||||
setBusy('#mqtt-settings-busy', '#mqtt-settings', false);
|
|
||||||
|
|
||||||
setRadioValue('.outdoor-sensor-type', result.sensors.outdoor.type);
|
|
||||||
setInputValue('.outdoor-sensor-pin', result.sensors.outdoor.pin);
|
|
||||||
setInputValue('.outdoor-sensor-offset', result.sensors.outdoor.offset);
|
|
||||||
setBusy('#outdoor-sensor-settings-busy', '#outdoor-sensor-settings', false);
|
|
||||||
|
|
||||||
setRadioValue('.indoor-sensor-type', result.sensors.indoor.type);
|
|
||||||
setInputValue('.indoor-sensor-pin', result.sensors.indoor.pin);
|
|
||||||
setInputValue('.indoor-sensor-offset', result.sensors.indoor.offset);
|
|
||||||
setInputValue('.indoor-sensor-ble-addresss', result.sensors.indoor.bleAddresss);
|
|
||||||
setBusy('#indoor-sensor-settings-busy', '#indoor-sensor-settings', false);
|
|
||||||
|
|
||||||
setCheckboxValue('.extpump-use', result.externalPump.use);
|
|
||||||
setInputValue('.extpump-pin', result.externalPump.pin);
|
|
||||||
setInputValue('.extpump-pc-time', result.externalPump.postCirculationTime);
|
|
||||||
setInputValue('.extpump-as-interval', result.externalPump.antiStuckInterval);
|
|
||||||
setInputValue('.extpump-as-time', result.externalPump.antiStuckTime);
|
|
||||||
setBusy('#extpump-settings-busy', '#extpump-settings', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadVars() {
|
|
||||||
let response = await fetch('/api/vars');
|
|
||||||
let result = await response.json();
|
|
||||||
|
|
||||||
setState('.ot-connected', result.states.otStatus);
|
|
||||||
setState('.ot-emergency', result.states.emergency);
|
|
||||||
setState('.ot-heating', result.states.heating);
|
|
||||||
setState('.ot-dhw', result.states.dhw);
|
|
||||||
setState('.ot-flame', result.states.flame);
|
|
||||||
setState('.ot-fault', result.states.fault);
|
|
||||||
setState('.ot-diagnostic', result.states.diagnostic);
|
|
||||||
setState('.ot-external-pump', result.states.externalPump);
|
|
||||||
|
|
||||||
setValue('.ot-modulation', result.sensors.modulation);
|
|
||||||
setValue('.ot-pressure', result.sensors.pressure);
|
|
||||||
setValue('.ot-dhw-flow-rate', result.sensors.dhwFlowRate);
|
|
||||||
setValue('.ot-fault-code', result.sensors.faultCode ? ("E" + result.sensors.faultCode) : "-");
|
|
||||||
|
|
||||||
setValue('.indoor-temp', result.temperatures.indoor);
|
|
||||||
setValue('.outdoor-temp', result.temperatures.outdoor);
|
|
||||||
setValue('.heating-temp', result.temperatures.heating);
|
|
||||||
setValue('.heating-setpoint-temp', result.parameters.heatingSetpoint);
|
|
||||||
setValue('.dhw-temp', result.temperatures.dhw);
|
|
||||||
|
|
||||||
setBusy('.ot-busy', '.ot-table', false);
|
|
||||||
|
|
||||||
setValue('.version', result.system.version);
|
|
||||||
setValue('.build-date', result.system.buildDate);
|
|
||||||
setValue('.uptime', result.system.uptime);
|
|
||||||
setValue('.uptime-days', Math.floor(result.system.uptime / 86400));
|
|
||||||
setValue('.uptime-hours', Math.floor(result.system.uptime % 86400 / 3600));
|
|
||||||
setValue('.uptime-min', Math.floor(result.system.uptime % 3600 / 60));
|
|
||||||
setValue('.uptime-sec', Math.floor(result.system.uptime % 60));
|
|
||||||
setValue('.total-heap', result.system.totalHeap);
|
|
||||||
setValue('.free-heap', result.system.freeHeap);
|
|
||||||
setValue('.min-free-heap', result.system.minFreeHeap);
|
|
||||||
setValue('.max-free-block-heap', result.system.maxFreeBlockHeap);
|
|
||||||
setValue('.min-max-free-block-heap', result.system.minMaxFreeBlockHeap);
|
|
||||||
setValue('.reset-reason', result.system.resetReason);
|
|
||||||
setState('.mqtt-connected', result.system.mqttConnected);
|
|
||||||
|
|
||||||
setBusy('.system-busy', '.system-table', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setBusy(busySelector, contentSelector, value) {
|
function setBusy(busySelector, contentSelector, value) {
|
||||||
let busy = document.querySelector(busySelector);
|
|
||||||
let content = document.querySelector(contentSelector);
|
|
||||||
if (!busy || !content) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
busy.classList.add('hidden');
|
hide(busySelector);
|
||||||
content.classList.remove('hidden');
|
show(contentSelector);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
busy.classList.remove('hidden');
|
show(busySelector);
|
||||||
content.classList.add('hidden');
|
hide(contentSelector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,12 +504,14 @@ function setState(selector, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setValue(selector, value) {
|
function setValue(selector, value) {
|
||||||
let item = document.querySelector(selector);
|
let items = document.querySelectorAll(selector);
|
||||||
if (!item) {
|
if (!items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.innerHTML = value;
|
for (let item of items) {
|
||||||
|
item.innerHTML = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCheckboxValue(selector, value) {
|
function setCheckboxValue(selector, value) {
|
||||||
@@ -629,25 +534,120 @@ function setRadioValue(selector, value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setInputValue(selector, value) {
|
function setInputValue(selector, value, attrs = {}) {
|
||||||
let item = document.querySelector(selector);
|
let items = document.querySelectorAll(selector);
|
||||||
if (!item) {
|
if (!items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.value = value;
|
for (let item of items) {
|
||||||
|
item.value = value;
|
||||||
|
|
||||||
|
if (attrs instanceof Object) {
|
||||||
|
for (let attrKey of Object.keys(attrs)) {
|
||||||
|
item.setAttribute(attrKey, attrs[attrKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function show(selector) {
|
||||||
|
let items = document.querySelectorAll(selector);
|
||||||
|
if (!items.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function form2json(data) {
|
for (let item of items) {
|
||||||
|
if (item.classList.contains('hidden')) {
|
||||||
|
item.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide(selector) {
|
||||||
|
let items = document.querySelectorAll(selector);
|
||||||
|
if (!items.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let item of items) {
|
||||||
|
if (!item.classList.contains('hidden')) {
|
||||||
|
item.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unit2str(unitSystem, units = {}, defaultValue = '?') {
|
||||||
|
return (unitSystem in units)
|
||||||
|
? units[unitSystem]
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function temperatureUnit(unitSystem) {
|
||||||
|
return unit2str(unitSystem, {
|
||||||
|
0: "°C",
|
||||||
|
1: "°F"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function pressureUnit(unitSystem) {
|
||||||
|
return unit2str(unitSystem, {
|
||||||
|
0: "bar",
|
||||||
|
1: "psi"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function volumeUnit(unitSystem) {
|
||||||
|
return unit2str(unitSystem, {
|
||||||
|
0: "L",
|
||||||
|
1: "gal"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function memberIdToVendor(memberId) {
|
||||||
|
// https://github.com/Jeroen88/EasyOpenTherm/blob/main/src/EasyOpenTherm.h
|
||||||
|
// https://github.com/Evgen2/SmartTherm/blob/v0.7/src/Web.cpp
|
||||||
|
const vendorList = {
|
||||||
|
1: "Baxi Fourtech/Luna 3",
|
||||||
|
2: "AWB/Brink",
|
||||||
|
4: "ATAG/Brötje/ELCO/GEMINOX",
|
||||||
|
5: "Itho Daalderop",
|
||||||
|
6: "IDEAL",
|
||||||
|
8: "Buderus/Bosch/Hoval",
|
||||||
|
9: "Ferroli",
|
||||||
|
11: "Remeha/De Dietrich",
|
||||||
|
16: "Unical",
|
||||||
|
24: "Vaillant/Bulex",
|
||||||
|
27: "Baxi",
|
||||||
|
29: "Itho Daalderop",
|
||||||
|
33: "Viessmann",
|
||||||
|
41: "Italtherm",
|
||||||
|
56: "Baxi Luna Duo-Tec",
|
||||||
|
131: "Nefit",
|
||||||
|
148: "Navien",
|
||||||
|
173: "Intergas",
|
||||||
|
247: "Baxi Ampera",
|
||||||
|
248: "Zota Lux-X"
|
||||||
|
};
|
||||||
|
|
||||||
|
return (memberId in vendorList)
|
||||||
|
? vendorList[memberId]
|
||||||
|
: "unknown vendor";
|
||||||
|
}
|
||||||
|
|
||||||
|
function form2json(data, noCastItems = []) {
|
||||||
let method = function (object, pair) {
|
let method = function (object, pair) {
|
||||||
let keys = pair[0].replace(/\]/g, '').split('[');
|
let keys = pair[0].replace(/\]/g, '').split('[');
|
||||||
let key = keys[0];
|
let key = keys[0];
|
||||||
let value = pair[1];
|
let value = pair[1];
|
||||||
if (value === 'true' || value === 'false') {
|
|
||||||
value = value === 'true';
|
if (!noCastItems.includes(keys.join('.'))) {
|
||||||
} else if (typeof (value) === 'string' && value.trim() !== '' && !isNaN(value)) {
|
if (value === 'true' || value === 'false') {
|
||||||
value = parseFloat(value);
|
value = value === 'true';
|
||||||
|
|
||||||
|
} else if (typeof (value) === 'string' && value.trim() !== '' && !isNaN(value)) {
|
||||||
|
value = parseFloat(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.length > 1) {
|
if (keys.length > 1) {
|
||||||
|
|||||||
BIN
src_data/static/fonts/iconly.eot
Normal file
BIN
src_data/static/fonts/iconly.eot
Normal file
Binary file not shown.
BIN
src_data/static/fonts/iconly.ttf
Normal file
BIN
src_data/static/fonts/iconly.ttf
Normal file
Binary file not shown.
BIN
src_data/static/fonts/iconly.woff
Normal file
BIN
src_data/static/fonts/iconly.woff
Normal file
Binary file not shown.
BIN
src_data/static/fonts/iconly.woff2
Normal file
BIN
src_data/static/fonts/iconly.woff2
Normal file
Binary file not shown.
4
src_data/static/pico.min.css
vendored
4
src_data/static/pico.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -36,7 +36,7 @@
|
|||||||
Settings file:
|
Settings file:
|
||||||
<input type="file" name="settings" id="restore-file" accept=".json">
|
<input type="file" name="settings" id="restore-file" accept=".json">
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<button type="submit">Restore</button>
|
<button type="submit">Restore</button>
|
||||||
<button type="button" class="secondary" onclick="window.location='/api/backup/save';">Backup</button>
|
<button type="button" class="secondary" onclick="window.location='/api/backup/save';">Backup</button>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
<hgroup>
|
<hgroup>
|
||||||
<h2>Upgrade</h2>
|
<h2>Upgrade</h2>
|
||||||
<p>
|
<p>
|
||||||
In this section you can upgrade the firmware and filesystem of your device.<br>
|
In this section you can upgrade the firmware and filesystem of your device.<br />
|
||||||
Latest releases can be downloaded from the <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank">Releases page</a> of the project repository.
|
Latest releases can be downloaded from the <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank">Releases page</a> of the project repository.
|
||||||
</p>
|
</p>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<button type="button" class="upgrade-firmware-result hidden" disabled></button>
|
<button type="button" class="upgrade-firmware-result hidden" disabled></button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="filesystem-file">
|
<label for="filesystem-file">
|
||||||
Filesystem:
|
Filesystem:
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><mark>After a successful upgrade the filesystem, ALL settings will be reset to default values! Save backup before upgrading.</mark></li>
|
<li><mark>After a successful upgrade the filesystem, ALL settings will be reset to default values! Save backup before upgrading.</mark></li>
|
||||||
<li><mark>After a successful upgrade, the device will automatically reboot after 10 seconds.</mark></li>
|
<li><mark>After a successful upgrade, the device will automatically reboot after 10 seconds.</mark></li>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
• <a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
• <a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
|
• <a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
|
||||||
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
• <a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
|
||||||
</small>
|
</small>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -105,4 +105,4 @@
|
|||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
import gzip
|
||||||
import os
|
import os
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
@@ -12,6 +13,26 @@ def post_build(source, target, env):
|
|||||||
env.Execute("pio run --target buildfs --environment %s" % env["PIOENV"]);
|
env.Execute("pio run --target buildfs --environment %s" % env["PIOENV"]);
|
||||||
|
|
||||||
|
|
||||||
|
def before_buildfs(source, target, env):
|
||||||
|
src = os.path.join(env["PROJECT_DIR"], "src_data")
|
||||||
|
dst = os.path.join(env["PROJECT_DIR"], "data")
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(src, topdown=False):
|
||||||
|
for name in files:
|
||||||
|
src_path = os.path.join(root, name)
|
||||||
|
|
||||||
|
with open(src_path, 'rb') as f_in:
|
||||||
|
dst_name = name + ".gz"
|
||||||
|
dst_path = os.path.join(dst, os.path.relpath(root, src), dst_name)
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(dst, os.path.relpath(root, src))) == False:
|
||||||
|
os.mkdir(os.path.join(dst, os.path.relpath(root, src)))
|
||||||
|
|
||||||
|
with gzip.open(dst_path, 'wb', 9) as f_out:
|
||||||
|
shutil.copyfileobj(f_in, f_out)
|
||||||
|
|
||||||
|
print("Compressed '%s' to '%s'" % (src_path, dst_path))
|
||||||
|
|
||||||
def after_buildfs(source, target, env):
|
def after_buildfs(source, target, env):
|
||||||
copy_to_build_dir({
|
copy_to_build_dir({
|
||||||
source[0].get_abspath(): "filesystem_%s_%s.bin" % (env["PIOENV"], env.GetProjectOption("version")),
|
source[0].get_abspath(): "filesystem_%s_%s.bin" % (env["PIOENV"], env.GetProjectOption("version")),
|
||||||
@@ -31,4 +52,6 @@ def copy_to_build_dir(files, build_dir):
|
|||||||
|
|
||||||
|
|
||||||
env.AddPostAction("buildprog", post_build)
|
env.AddPostAction("buildprog", post_build)
|
||||||
|
env.AddPreAction("$BUILD_DIR/spiffs.bin", before_buildfs)
|
||||||
|
env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs)
|
||||||
env.AddPostAction("buildfs", after_buildfs)
|
env.AddPostAction("buildfs", after_buildfs)
|
||||||
Reference in New Issue
Block a user