122 Commits

Author SHA1 Message Date
ce8e8bbe7b Merge branch 'dev' of https://github.com/mp-se/gravitymon into dev 2022-10-18 19:30:55 +02:00
0ca60ec71f GitHub Action Build 2022-10-18 17:21:00 +00:00
d7981851bd Update readme 2022-10-18 19:19:25 +02:00
2a419c10d1 Update 2022-10-18 19:04:05 +02:00
b265dba422 Merge 2022-10-18 19:01:41 +02:00
74a0598905 Merge 2022-10-18 19:00:53 +02:00
3b7be30363 Merge branch 'master' into dev 2022-10-18 19:00:28 +02:00
5889ebda1e Bump doc version 2022-10-18 18:57:06 +02:00
ec77b873a8 Update build targets 2022-10-18 18:55:03 +02:00
04120a0490 Removed obsolete files from bin 2022-10-18 18:08:47 +02:00
4f28ea9975 Added release notes 2022-10-18 09:39:04 +02:00
c1eade04af Update build 2022-10-18 09:28:54 +02:00
2fd0c881f3 Bump version 2022-10-18 09:28:03 +02:00
8113275402 Fix bug in templating 2022-10-18 09:27:51 +02:00
b5928cb201 GitHub Action Build 2022-10-17 19:07:44 +00:00
22f9a2d228 Fix precommit 2022-10-17 21:03:12 +02:00
343aea7ebe Fix sluggish webserver 2022-10-17 21:02:19 +02:00
19e67cb678 Refactor html serving 2022-10-17 21:02:08 +02:00
379dff1d22 Fix updated path 2022-10-17 20:34:59 +02:00
e82cd2aeae Fix build errors 2022-10-17 20:27:22 +02:00
6262cec27d Update esp32c3 support 2022-10-17 20:19:20 +02:00
a9347c7e03 Removed warning from wifi lib 2022-10-16 20:40:41 +02:00
60adcabd81 Fixed conflict with logging library 2022-10-16 20:40:08 +02:00
411cec08c7 Added macro for controling serial port 2022-10-16 20:39:27 +02:00
b6fcf94191 Updated install docs 2022-10-16 20:34:57 +02:00
e9ef632cce Added docs on esp32 2022-10-16 10:46:09 +02:00
7d4c42a47c Added new targets to UI 2022-10-16 10:16:16 +02:00
9ce6d54b80 Updated i2c lib for esp32 2022-10-16 09:23:51 +02:00
2e96e4aea8 Updated esp32 debug target 2022-10-15 17:42:50 +02:00
775ba53260 Update release notes 2022-10-15 17:41:41 +02:00
6e0af97574 Disable BLE for ESP32S2 2022-10-15 17:41:17 +02:00
531baa917e Added c3 targets to bin folder 2022-10-14 19:39:38 +02:00
7f73f22759 Docs update 2022-10-14 19:39:01 +02:00
0fad08ccc5 Added log entry when doing factory reset 2022-10-14 19:38:41 +02:00
fcfc8df625 Reading wifi creds from eeprom, fixed ota filenames 2022-10-14 19:38:04 +02:00
e54c1d2518 Fixed bug in template engine, not including the start of tempalte 2022-10-14 19:37:14 +02:00
027e98d2de Update board pins 2022-10-14 19:36:36 +02:00
91227b0728 Added esp32 reset reason 2022-10-14 19:36:01 +02:00
ddeca29f8e Update targets 2022-10-14 19:35:39 +02:00
15d3371437 Updated pins for new boards 2022-10-12 23:26:17 +02:00
ac51c52c74 Moved global classes to main 2022-10-12 19:52:44 +02:00
1148a23bb4 Added c3 target 2022-10-12 19:52:15 +02:00
1ddd8bc669 Removed upload functions (not used) 2022-10-12 19:51:38 +02:00
7664215d23 Limit wifi power on esp32c3 2022-10-12 19:30:49 +02:00
9eb356bd43 Upgrade wifi libs 2022-10-12 19:26:24 +02:00
f4401ea526 Merge pull request #105 from jinjorge/doc_fix_functionality
Typo fixes in functionality doc
2022-09-17 09:39:33 +02:00
535367d943 Merge pull request #107 from jinjorge/doc_fix_index
Typo fixes in index doc
2022-09-17 09:39:05 +02:00
8db58c76dc Renamed Functionality doc 2022-09-15 12:58:21 -07:00
9441e4bc54 Integrate PR feedback 2022-09-15 11:41:42 -07:00
b7d2183564 Merge pull request #99 from jinjorge/doc_fix_api_rst
Typo fixes for api doc
2022-09-15 20:26:15 +02:00
18f7ba8911 Merge pull request #100 from jinjorge/doc_fix_advanced_rst
Typo fixes
2022-09-15 20:25:36 +02:00
af0d6f21ca Merge pull request #101 from jinjorge/doc_fix_configuration
Typo fixes for configuration documentation
2022-09-15 20:25:05 +02:00
e3fcd53a36 Merge pull request #102 from jinjorge/doc_fix_contributing
Fix typos in contributing doc
2022-09-15 20:23:36 +02:00
5149760d22 Merge pull request #103 from jinjorge/doc_fix_data_doc
Typo fixes in data doc
2022-09-15 20:23:09 +02:00
403719073b Merge pull request #104 from jinjorge/doc_fix_formula
Typo fixes in formula doc
2022-09-15 20:22:32 +02:00
dd3a4e5742 Merge pull request #106 from jinjorge/doc_fix_hardware
Typo fix for hardware doc
2022-09-15 20:18:52 +02:00
2e27ec78d6 Merge pull request #108 from jinjorge/doc_fix_installation
Typo fixes in installation doc
2022-09-15 20:15:43 +02:00
d5dae6a40d Merge pull request #109 from jinjorge/doc_fx_intro
Typo fixes in intro doc
2022-09-15 20:15:06 +02:00
3b716e5499 Merge pull request #110 from jinjorge/doc_fix_q_and_a
Typo fixes in question and answer doc
2022-09-15 20:14:32 +02:00
2aebae59b3 Merge pull request #111 from jinjorge/doc_fix_releases
Typo fixes to release notes doc
2022-09-15 20:13:38 +02:00
eb4b975407 Merge pull request #112 from jinjorge/doc_fix_services
Typo fixes in services doc
2022-09-15 20:12:49 +02:00
1f25e3ac50 Merge pull request #113 from jinjorge/doc_fix_troubleshooting
Typo fixes in troubleshooting doc
2022-09-15 20:11:43 +02:00
f1a608d060 Typo fixes in troubleshooting doc 2022-09-15 11:00:27 -07:00
c33326e6a4 Typo fixes in services doc 2022-09-15 10:57:47 -07:00
1afb5ed604 Typo fixes to release notes doc 2022-09-15 10:52:00 -07:00
823d8ca39e Typo fixes in question and answer doc 2022-09-15 10:42:46 -07:00
5a11ab84db Typo fixes in intro doc 2022-09-15 10:39:25 -07:00
5378d4c700 Typo fixes in installation doc 2022-09-15 10:36:51 -07:00
c10abe2087 Typo fixes in index doc 2022-09-15 10:32:39 -07:00
ec3ef06826 Typo fix for hardware doc 2022-09-15 10:26:55 -07:00
b9273b7b79 Typo fixes in functionality doc 2022-09-15 10:22:29 -07:00
6b649070e1 Typo fixes in formula doc 2022-09-15 10:16:11 -07:00
291229255c Typo fixes in data doc 2022-09-15 10:13:40 -07:00
2747484775 Fix typos in contributing doc 2022-09-15 10:11:04 -07:00
ecf0c08f47 Typo fixes for configuration documentation 2022-09-15 10:06:48 -07:00
eb82bf526d Typo fixes 2022-09-14 23:35:48 -07:00
b45ef627a0 Typo fixes for api doc 2022-09-14 23:30:03 -07:00
d1b94ce2b0 GitHub Action Build 2022-08-21 17:59:36 +00:00
d4b78a0e1b Showing wifi ssid in config 2022-08-21 18:48:08 +02:00
646d8f8d12 Added copy button to docs 2022-08-21 18:39:46 +02:00
059865f271 GitHub Action Build 2022-08-14 12:27:26 +00:00
a9deb588aa Fixed error printout for calibration errors 2022-08-14 14:23:23 +02:00
0de8971255 GitHub Action Build 2022-08-14 11:59:10 +00:00
08a102159b Increased file eror log to 4k 2022-08-14 13:54:29 +02:00
8b13b4769c GitHub Action Build 2022-08-14 08:59:57 +00:00
c3044f9878 Updated 1.1 docs 2022-08-14 10:54:43 +02:00
0a4e7f37b2 Gen .map always 2022-08-09 20:28:52 +02:00
69f4b8ec3d Doc updates 2022-08-09 20:25:17 +02:00
d4c88c1200 Updated docs 2022-08-06 09:17:10 +02:00
4bbfb77361 Fix pre-commit 2022-08-06 08:55:52 +02:00
655235fc4e Added log message to webserver 2022-08-06 08:52:54 +02:00
4b0e5b393a Storage mode deepSleep forever 2022-08-05 22:50:03 +02:00
db590f8f5f Updated docs 2022-08-05 22:49:44 +02:00
4c805fe235 Added crash detector 2022-08-05 18:17:10 +02:00
34a1d7d3c3 GitHub Action Build 2022-08-05 09:21:15 +00:00
bcee0e21da Corrected error code from mqtt push 2022-08-05 11:16:58 +02:00
9fc5ab147d GitHub Action Build 2022-08-05 08:17:37 +00:00
b3a89a1fcc Fix javascript error in format 2022-08-05 10:13:20 +02:00
03b58eb112 GitHub Action Build 2022-08-05 08:00:11 +00:00
63ddcfbb57 Fixed compiler error on esp32 + release notes 2022-08-05 09:55:47 +02:00
68d44a5846 Fixes for new tpl engine, optimize memory. 2022-08-05 09:38:10 +02:00
45294f6b07 Using strncat instead 2022-08-04 16:17:24 +02:00
09d8226af1 Bump beta4 2022-08-04 16:12:28 +02:00
6c94c6b204 Precommit fixes 2022-08-04 16:12:14 +02:00
9e437d1e0d Refactored error logger to reduce memory footprint 2022-08-04 08:31:10 +02:00
a486f1be30 Updated code for gyro error to UI 2022-08-03 17:22:26 +02:00
0536b14280 Updated docs for beta3 2022-08-02 13:42:39 +02:00
a6bff7287e Added "not found" messages for gyro/temp sensor. 2022-08-02 13:02:01 +02:00
414d7d51c2 GitHub Action Build 2022-08-02 06:28:23 +00:00
640733f143 Added drop down menu, fixed bus in ha workflow 2022-08-02 08:24:08 +02:00
f6196e6dbf GitHub Action Build 2022-08-01 20:33:24 +00:00
f857dab3c0 Merge branch 'dev' of https://github.com/mp-se/gravitymon into dev 2022-08-01 22:28:48 +02:00
787c5c09bb Updated workflow for HA registration 2022-08-01 22:28:17 +02:00
afe3ec2412 GitHub Action Build 2022-08-01 19:30:38 +00:00
980099a5e5 Updated clang format 2022-08-01 21:26:20 +02:00
99d577d4a0 Updated release notes and error message 2022-08-01 21:25:21 +02:00
6db6e96d90 Fixed crash after firmware update 2022-08-01 16:16:24 +02:00
92df08baa2 Updated format template 2022-08-01 11:26:10 +02:00
5466550f68 Updated format templates 2022-08-01 11:25:55 +02:00
94f703b087 Bump to beta3 2022-08-01 11:06:14 +02:00
57e078986b Upd release notes 2022-08-01 11:05:53 +02:00
e445e7649c Refactor format read to handle large payload 2022-08-01 11:03:51 +02:00
104 changed files with 1692 additions and 2335 deletions

View File

@ -21,6 +21,7 @@ jobs:
pip install docutils==0.16 pip install docutils==0.16
pip install pygments==2.11.1 pip install pygments==2.11.1
pip install furo==2022.1.2 pip install furo==2022.1.2
pip install sphinx-copybutton
pip list pip list
build-command: "sphinx-build -b html ./source ../docs" build-command: "sphinx-build -b html ./source ../docs"

View File

@ -36,9 +36,7 @@ jobs:
git config --global advice.detachedHead false git config --global advice.detachedHead false
- name: Run PlatformIO - name: Run PlatformIO
#run: pio run -e gravity-release -e gravity-perf -e gravity-debug run: pio run -e gravity-release
run: pio run -e gravity-release -e gravity-perf
#run: pio run -e gravity-release
- uses: EndBug/add-and-commit@v7 # You can change this to use a specific version. https://github.com/marketplace/actions/add-commit - uses: EndBug/add-and-commit@v7 # You can change this to use a specific version. https://github.com/marketplace/actions/add-commit
with: with:

View File

@ -36,7 +36,7 @@ jobs:
git config --global advice.detachedHead false git config --global advice.detachedHead false
- name: Run PlatformIO - name: Run PlatformIO
run: pio run -e gravity-release -e gravity-perf -e gravity32-release -e gravity32-perf run: pio run -e gravity-release -e gravity32-release -e gravity32c3-release
- uses: EndBug/add-and-commit@v7 # You can change this to use a specific version. https://github.com/marketplace/actions/add-commit - uses: EndBug/add-and-commit@v7 # You can change this to use a specific version. https://github.com/marketplace/actions/add-commit
with: with:

View File

@ -10,7 +10,7 @@
GravityMon is a replacement firmware for the iSpindle firmware. It's 100% compatible with the iSpindle hardware design so it does not require any hardware changes. GravityMon is a replacement firmware for the iSpindle firmware. It's 100% compatible with the iSpindle hardware design so it does not require any hardware changes.
Now also works with ESP32 (use ESP32 d1 mini which is compatible with ESP8266) Now also works with ESP32, either an ESP32 d1 mini or ESP32 c3 mini which both are compatible with ESP8266.
Installation can be made using https://www.brewflasher.com or https://web.brewflasher.com Installation can be made using https://www.brewflasher.com or https://web.brewflasher.com
@ -21,18 +21,24 @@ Note! If Brewflasher being flagged as malware by your antivirus software, try th
The main differences: The main differences:
--------------------- ---------------------
* Modern web based user interface for configuration when connected to WIFI * Operates in two modes gravity monitoring and configuration mode
* Efficient software, long lifespan (+45 days with 5min update frequencey) * Gravity mode is comparable to how the iSpindle works when collectintg data
* Send data to multiple endpoints (http-post, http-get, influxdb v2, mqtt) * Configuration mode has a modern HTML5 based web UI. No need to start the access point to change settings
* Instructions for service such as; Brewfather, Fermentrack, Ubidots, Home Assistant, Brewers Friend, Brewspy, Thingspeak, Blynk. * Offloading some of the functionallity to run in the web browser, this allows for more advanced features.
* SSL support for all remote endpoints * REST API to enable scripted configuration
* ESP32 support with Bluetooth push * Send data to multiple endpoints and services at once (2xHTTP POST, HTTP GET, MQTT, INFLUXDB2)
* Customize data format to be pushed * Directly test all endpoints from user interface with feedback to simplify troubleshooting
* Automatic temperature adjustment of gravity when enabled * Complete format customization for all endpoints using templates (dont really need to change the software to support new services)
* Use the temperature sensor in gyro instead of DS18B20 * Setup guides for how to send data to many popular services. Currently 10+ are documented
* Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity. * Automatic temperature adjustment of gravity (just tick a checkbox)
* Visual graph showing how gravity formula will be interpreted * OTA support from webserver
* OTA support or firmware upload via web interface * Firmware update via web interface
* REST API for scripting * Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity and let GravityMon creates a formula
* Visual graph showing how formula will be interpreted based on entered values
* Using the temperature sensor in gyro instead of DS18B20 (faster)
* SSL support in all endpoints (no certificate validation due to limitations on esp8266).
* Built in performance measurements (used to optimise code)
* Storage mode when placed on cap (indefinite sleep)
* Customize various hardware parameters to opimize device functionallity.
*
No code has been reused from the iSpindle project. No code has been reused from the iSpindle project.

View File

@ -1 +0,0 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><style>.row-margin-10{margin-top:1em}</style></head><body class="py-4"><!-- START MENU --><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script><nav class="navbar navbar-expand-lg navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="/index.htm">Home</a></li><li class="nav-item"><a class="nav-link" href="/config.htm">Configuration</a></li><li class="nav-item"><a class="nav-link" href="/calibration.htm">Calibration</a></li><li class="nav-item active"><a class="nav-link" href="#"><b>About</b></a></li></ul></div></div></nav><!-- START BODY --><div class="container row-margin-10"><div class="accordion row-margin-10" id="accordion"><div class="accordion-item"><h2 class="accordion-header" id="headingAbout"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAbout" aria-expanded="true" aria-controls="collapseAbout"><b>About</b></button></h2><div id="collapseAbout" class="accordion-collapse collapse show" aria-labelledby="headingAbout" data-bs-parent="#accordion"><div class="accordion-body"><div class="row h3 col-sm-8">Beer Gravity Monitor</div><div class="row col-sm-8 mb-3">This is a piece of software for the iSpindle hardware and will work in a similar way. No part of this software is copied from the iSpindle project.</div><div class="row h3 col-sm-8 mb-3">MIT License</div><div class="row col-sm-8 mb-3">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</div><div class="row h3 col-sm-8 mb-3">Credits to</div><div class="row col-sm-8 mb-3">This software uses the following libraries and without these this software would have been much more difficult to acheive:<br><br><ul><li>https://github.com/jrowberg/i2cdevlib</li><li>https://github.com/codeplea/tinyexpr</li><li>https://github.com/graphitemaster/incbin</li><li>https://github.com/khoih-prog/ESP_DoubleResetDetector</li><li>https://github.com/khoih-prog/ESP_WiFiManager</li><li>https://github.com/thijse/Arduino-Log</li><li>https://github.com/bblanchon/ArduinoJson</li><li>https://github.com/PaulStoffregen/OneWire</li><li>https://github.com/milesburton/Arduino-Temperature-Control-Library</li><li>https://github.com/Rotario</li><li>https://github.com/256dpi/arduino-mqtt</li><li>https://graphjs.com</li><li>https://getbootstrap.com</li><li>https://github.com/lorol/LITTLEFS</li><li>https://github.com/h2zero/NimBLE-Arduino</li><li>https://github.com/spouliot/tilt-sim</li></ul></div></div></div></div></div></div><!-- START FOOTER --><div class="container themed-container bg-primary text-light row-margin-10">(C) Copyright 2021-22 Magnus Persson</div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/firmware32c3.bin Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
bin/partitions32c3.bin Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{ "project":"gravmon", "version":"1.1.0", "html": [ ] } { "project":"gravmon", "version":"1.2.0", "html": [ ] }

35
ex/exception_dump.txt Normal file
View File

@ -0,0 +1,35 @@
User exception (panic/abort/assert)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
Panic core_esp8266_main.cpp:215 loop_task
>>>stack>>>
ctx: sys
sp: 3fffff10 end: 3fffffb0 offset: 0000
3fffff10: 00000000 02ac3bd9 40280793 3ffeaec4
3fffff20: 000000fe 00000000 00000000 00000000
3fffff30: 00000000 00000000 00000000 3fff1edc
3fffff40: 3fff1fa8 3fff1fa8 3fff0280 3fff1e94
3fffff50: 3fffdad0 00000000 3ffe8648 4022d992
3fffff60: 402854b2 3fffdab0 00000000 4022d9ff
3fffff70: 00000000 3fffdad0 3fff1e94 4022d0d8
3fffff80: 40000f49 40000f49 3fffdab0 40000f49
3fffff90: 40000e19 000b5a21 00000000 00000005
3fffffa0: 00000000 aa55aa55 000000d0 401057f9
<<<stack<<<
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
load 0x4010f000, len 3460, room 16
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4
tail 4
chksum 0xc9
csum 0xc9
v000b5a30
~ld

View File

@ -28,20 +28,29 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/index.htm">Home</a> <a class="nav-link" href="/index.htm">Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item dropdown">
<a class="nav-link" href="/config.htm">Configuration</a> <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/config.htm">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/calibration.htm">Calibration</a> <a class="nav-link" href="/calibration.htm">Calibration</a>
</li> </li>
<li class="nav-item active"> <li class="nav-item">
<a class="nav-link" href="#"><b>About</b></a> <a class="nav-link active" href="#">About</a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="spinner-border text-light" id="spinner" role="status"></div>
</div> </div>
</nav> </nav>
<!-- START BODY --> <!-- START BODY -->
<div class="container row-margin-10"> <div class="container row-margin-10">

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><style>.row-margin-10{margin-top:1em}</style></head><body class="py-4"><!-- START MENU --><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script><nav class="navbar navbar-expand-lg navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="/index.htm">Home</a></li><li class="nav-item"><a class="nav-link" href="/config.htm">Configuration</a></li><li class="nav-item"><a class="nav-link" href="/calibration.htm">Calibration</a></li><li class="nav-item active"><a class="nav-link" href="#"><b>About</b></a></li></ul></div></div></nav><!-- START BODY --><div class="container row-margin-10"><div class="accordion row-margin-10" id="accordion"><div class="accordion-item"><h2 class="accordion-header" id="headingAbout"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAbout" aria-expanded="true" aria-controls="collapseAbout"><b>About</b></button></h2><div id="collapseAbout" class="accordion-collapse collapse show" aria-labelledby="headingAbout" data-bs-parent="#accordion"><div class="accordion-body"><div class="row h3 col-sm-8">Beer Gravity Monitor</div><div class="row col-sm-8 mb-3">This is a piece of software for the iSpindle hardware and will work in a similar way. No part of this software is copied from the iSpindle project.</div><div class="row h3 col-sm-8 mb-3">MIT License</div><div class="row col-sm-8 mb-3">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</div><div class="row h3 col-sm-8 mb-3">Credits to</div><div class="row col-sm-8 mb-3">This software uses the following libraries and without these this software would have been much more difficult to acheive:<br><br><ul><li>https://github.com/jrowberg/i2cdevlib</li><li>https://github.com/codeplea/tinyexpr</li><li>https://github.com/graphitemaster/incbin</li><li>https://github.com/khoih-prog/ESP_DoubleResetDetector</li><li>https://github.com/khoih-prog/ESP_WiFiManager</li><li>https://github.com/thijse/Arduino-Log</li><li>https://github.com/bblanchon/ArduinoJson</li><li>https://github.com/PaulStoffregen/OneWire</li><li>https://github.com/milesburton/Arduino-Temperature-Control-Library</li><li>https://github.com/Rotario</li><li>https://github.com/256dpi/arduino-mqtt</li><li>https://graphjs.com</li><li>https://getbootstrap.com</li><li>https://github.com/lorol/LITTLEFS</li><li>https://github.com/h2zero/NimBLE-Arduino</li><li>https://github.com/spouliot/tilt-sim</li></ul></div></div></div></div></div></div><!-- START FOOTER --><div class="container themed-container bg-primary text-light row-margin-10">(C) Copyright 2021-22 Magnus Persson</div></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><style>.row-margin-10{margin-top:1em}</style></head><body class="py-4"><!-- START MENU --><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script><nav class="navbar navbar-expand-lg navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="/index.htm">Home</a></li><li class="nav-item dropdown"><a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">Configuration</a><ul class="dropdown-menu"><li><a class="dropdown-item" href="/config.htm">Configuration</a></li><li><a class="dropdown-item" href="/format.htm">Format editor</a></li><li><a class="dropdown-item" href="/test.htm">Test push</a></li><li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/calibration.htm">Calibration</a></li><li class="nav-item"><a class="nav-link active" href="#">About</a></li></ul></div><div class="spinner-border text-light" id="spinner" role="status"></div></div></nav><!-- START BODY --><div class="container row-margin-10"><div class="accordion row-margin-10" id="accordion"><div class="accordion-item"><h2 class="accordion-header" id="headingAbout"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAbout" aria-expanded="true" aria-controls="collapseAbout"><b>About</b></button></h2><div id="collapseAbout" class="accordion-collapse collapse show" aria-labelledby="headingAbout" data-bs-parent="#accordion"><div class="accordion-body"><div class="row h3 col-sm-8">Beer Gravity Monitor</div><div class="row col-sm-8 mb-3">This is a piece of software for the iSpindle hardware and will work in a similar way. No part of this software is copied from the iSpindle project.</div><div class="row h3 col-sm-8 mb-3">MIT License</div><div class="row col-sm-8 mb-3">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</div><div class="row h3 col-sm-8 mb-3">Credits to</div><div class="row col-sm-8 mb-3">This software uses the following libraries and without these this software would have been much more difficult to acheive:<br><br><ul><li>https://github.com/jrowberg/i2cdevlib</li><li>https://github.com/codeplea/tinyexpr</li><li>https://github.com/graphitemaster/incbin</li><li>https://github.com/khoih-prog/ESP_DoubleResetDetector</li><li>https://github.com/khoih-prog/ESP_WiFiManager</li><li>https://github.com/thijse/Arduino-Log</li><li>https://github.com/bblanchon/ArduinoJson</li><li>https://github.com/PaulStoffregen/OneWire</li><li>https://github.com/milesburton/Arduino-Temperature-Control-Library</li><li>https://github.com/Rotario</li><li>https://github.com/256dpi/arduino-mqtt</li><li>https://graphjs.com</li><li>https://getbootstrap.com</li><li>https://github.com/lorol/LITTLEFS</li><li>https://github.com/h2zero/NimBLE-Arduino</li><li>https://github.com/spouliot/tilt-sim</li></ul></div></div></div></div></div></div><!-- START FOOTER --><div class="container themed-container bg-primary text-light row-margin-10">(C) Copyright 2021-22 Magnus Persson</div></body></html>

View File

@ -16,8 +16,6 @@
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container"> <div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
@ -29,11 +27,19 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/index.htm">Home</a> <a class="nav-link" href="/index.htm">Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item dropdown">
<a class="nav-link" href="/config.htm">Configuration</a> <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/config.htm">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</li> </li>
<li class="nav-item active"> <li class="nav-item">
<a class="nav-link" href="#"><b>Calibration</b></a> <a class="nav-link active" href="#">Calibration</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/about.htm">About</a> <a class="nav-link" href="/about.htm">About</a>

File diff suppressed because one or more lines are too long

View File

@ -28,10 +28,18 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/index.htm">Home</a> <a class="nav-link" href="/index.htm">Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item dropdown">
<a class="nav-link active" href="#"><b>Configuration</b></a> <a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/calibration.htm">Calibration</a> <a class="nav-link" href="/calibration.htm">Calibration</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
@ -144,6 +152,21 @@
<hr class="my-2"> <hr class="my-2">
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Wifi</label>
<div class="col-sm-2">
<label class="col-sm-4 col-form-label" id="wifi-ssid"></label>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Wifi 2</label>
<div class="col-sm-2">
<label class="col-sm-4 col-form-label" id="wifi-ssid2"></label>
</div>
</div>
<hr class="my-2">
<div class="row mb-3"> <div class="row mb-3">
<label for="calibrate-btn" class="col-sm-2 col-form-label">Current calibration</label> <label for="calibrate-btn" class="col-sm-2 col-form-label">Current calibration</label>
<label for="calibrate-btn" class="col-sm-2 col-form-label" id="gyro-calibration-data">Loading...</label> <label for="calibrate-btn" class="col-sm-2 col-form-label" id="gyro-calibration-data">Loading...</label>
@ -846,7 +869,7 @@
$.getJSON(url, function (cfg) { $.getJSON(url, function (cfg) {
console.log( cfg ); console.log( cfg );
if(cfg["platform"]=="esp32") { if(cfg["platform"]=="esp32" || cfg["platform"]=="esp32c3") {
$('#ble').prop('disabled', false); $('#ble').prop('disabled', false);
$("#ble").val(cfg["ble"]); $("#ble").val(cfg["ble"]);
} }
@ -893,6 +916,8 @@
$("#angle").text(cfg["angle"]); $("#angle").text(cfg["angle"]);
$("#runtime-average").val(cfg["runtime-average"]); $("#runtime-average").val(cfg["runtime-average"]);
$("#water-angle").text( "(Water angle: " + cfg["formula-calculation-data"]["a1"] + ") - default off"); $("#water-angle").text( "(Water angle: " + cfg["formula-calculation-data"]["a1"] + ") - default off");
$("#wifi-ssid").text(cfg["wifi-ssid"]);
$("#wifi-ssid2").text(cfg["wifi-ssid2"]);
//$("#gravity").text(cfg["gravity"] + " SG"); //$("#gravity").text(cfg["gravity"] + " SG");
}) })
.fail(function () { .fail(function () {

File diff suppressed because one or more lines are too long

View File

@ -15,8 +15,6 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container"> <div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
@ -24,16 +22,34 @@
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="javascript:history.back()">Back to configuration</a> <a class="nav-link" href="/index.htm">Home</a>
</li> </li>
</ul> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/config.htm">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="#">Upload firmware</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="/calibration.htm">Calibration</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about.htm">About</a>
</li>
</ul>
</div> </div>
<div class="spinner-border text-light" id="spinner" role="status"></div> <div class="spinner-border text-light" id="spinner" role="status"></div>
</div> </div>
</nav> </nav>
<!-- START MAIN INDEX --> <!-- START MAIN INDEX -->
<div class="container row-margin-10"> <div class="container row-margin-10">
@ -135,7 +151,7 @@
showError("Upload failed"); showError("Upload failed");
}, },
success: function(resp) { success: function(resp) {
showSuccess("Upload completed, device is restarting. Waiting 10 seconds to refresh browser."); showSuccess("Upload completed, device is restarting. Waiting 10 seconds to refresh browser. If you don't get any gyro readings after update, please press the reset button!");
setTimeout(() => { setTimeout(() => {
window.location = "/"; window.location = "/";
}, 10000); }, 10000);

View File

@ -1,4 +1,4 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><style>.row-margin-10{margin-top:1em}</style></head><body class="py-4"><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><!-- START MENU --><nav class="navbar navbar-expand-lg navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav mr-auto"><li class="nav-item"><a class="nav-link" href="javascript:history.back()">Back to configuration</a></li></ul></div><div class="spinner-border text-light" id="spinner" role="status"></div></div></nav><!-- START MAIN INDEX --><div class="container row-margin-10"><div class="alert alert-success alert-dismissible hide fade d-none" role="alert"><div id="alert"></div><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div><script type="text/javascript">function showError(s){$(".alert").removeClass("alert-success").addClass("alert-danger").removeClass("hide").addClass("show").removeClass("d-none"),$("#alert").text(s)}function showSuccess(s){$(".alert").addClass("alert-success").removeClass("alert-danger").removeClass("hide").addClass("show").removeClass("d-none"),$("#alert").text(s)}$("#alert-btn").click(function(s){$(".alert").addClass("hide").removeClass("show").addClass("d-none")})</script><div class="accordion" id="accordion"><div class="accordion-item"><h2 class="accordion-header" id="headingFirmware"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFirmware" aria-expanded="true" aria-controls="collapseFirmware"><b>Upload firmware</b></button></h2><div id="collapseFirmware" class="accordion-collapse collapse show" aria-labelledby="headingFirmware" data-bs-parent="#accordion"><div class="accordion-body"><div class="row mb-3"><div class="col-md-12 themed-grid-col bg-light">Here you can upload a new firmware version, it will not check the version number so you can also downgrade the firmware here.</div></div><div class="row mb-3"><div class="col-md-2 themed-grid-col bg-light">Current version:</div><div class="col-md-10 themed-grid-col bg-light" id="app-ver">Loading...</div></div><div class="row mb-3"><div class="col-md-2 themed-grid-col bg-light">Platform:</div><div class="col-md-10 themed-grid-col bg-light" id="platform">Loading...</div></div><form id="uploadForm" enctype="multipart/form-data"><div class="row mb-3"><div class="col-md-8 custom-file"><input type="file" accept=".bin" class="custom-file-input" name="name" id="name" onchange="checkName()" data-bs-toggle="tooltip" title="Select a firmware file to upload"></div></div><div class="row mb-3"><div class="col-md-4"><button type="submit" class="btn btn-primary" id="upload-btn" value="upload" data-bs-toggle="tooltip" title="Update the device with the selected firmware">Flash firmware</button></div></div></form><div class="progress"><div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div></div></div></div></div></div><script type="text/javascript">window.onload = getStatus; <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><style>.row-margin-10{margin-top:1em}</style></head><body class="py-4"><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><nav class="navbar navbar-expand-lg navbar-dark bg-primary"><div class="container"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="/index.htm">Home</a></li><li class="nav-item dropdown"><a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">Configuration</a><ul class="dropdown-menu"><li><a class="dropdown-item" href="/config.htm">Configuration</a></li><li><a class="dropdown-item" href="/format.htm">Format editor</a></li><li><a class="dropdown-item" href="/test.htm">Test push</a></li><li><a class="dropdown-item" href="#">Upload firmware</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/calibration.htm">Calibration</a></li><li class="nav-item"><a class="nav-link" href="/about.htm">About</a></li></ul></div><div class="spinner-border text-light" id="spinner" role="status"></div></div></nav><!-- START MAIN INDEX --><div class="container row-margin-10"><div class="alert alert-success alert-dismissible hide fade d-none" role="alert"><div id="alert"></div><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div><script type="text/javascript">function showError(s){$(".alert").removeClass("alert-success").addClass("alert-danger").removeClass("hide").addClass("show").removeClass("d-none"),$("#alert").text(s)}function showSuccess(s){$(".alert").addClass("alert-success").removeClass("alert-danger").removeClass("hide").addClass("show").removeClass("d-none"),$("#alert").text(s)}$("#alert-btn").click(function(s){$(".alert").addClass("hide").removeClass("show").addClass("d-none")})</script><div class="accordion" id="accordion"><div class="accordion-item"><h2 class="accordion-header" id="headingFirmware"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFirmware" aria-expanded="true" aria-controls="collapseFirmware"><b>Upload firmware</b></button></h2><div id="collapseFirmware" class="accordion-collapse collapse show" aria-labelledby="headingFirmware" data-bs-parent="#accordion"><div class="accordion-body"><div class="row mb-3"><div class="col-md-12 themed-grid-col bg-light">Here you can upload a new firmware version, it will not check the version number so you can also downgrade the firmware here.</div></div><div class="row mb-3"><div class="col-md-2 themed-grid-col bg-light">Current version:</div><div class="col-md-10 themed-grid-col bg-light" id="app-ver">Loading...</div></div><div class="row mb-3"><div class="col-md-2 themed-grid-col bg-light">Platform:</div><div class="col-md-10 themed-grid-col bg-light" id="platform">Loading...</div></div><form id="uploadForm" enctype="multipart/form-data"><div class="row mb-3"><div class="col-md-8 custom-file"><input type="file" accept=".bin" class="custom-file-input" name="name" id="name" onchange="checkName()" data-bs-toggle="tooltip" title="Select a firmware file to upload"></div></div><div class="row mb-3"><div class="col-md-4"><button type="submit" class="btn btn-primary" id="upload-btn" value="upload" data-bs-toggle="tooltip" title="Update the device with the selected firmware">Flash firmware</button></div></div></form><div class="progress"><div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div></div></div></div></div></div><script type="text/javascript">window.onload = getStatus;
$(document).ready(function() { $(document).ready(function() {
$("#uploadForm").on('submit', function(e) { $("#uploadForm").on('submit', function(e) {
@ -26,7 +26,7 @@
showError("Upload failed"); showError("Upload failed");
}, },
success: function(resp) { success: function(resp) {
showSuccess("Upload completed, device is restarting. Waiting 10 seconds to refresh browser."); showSuccess("Upload completed, device is restarting. Waiting 10 seconds to refresh browser. If you don't get any gyro readings after update, please press the reset button!");
setTimeout(() => { setTimeout(() => {
window.location = "/"; window.location = "/";
}, 10000); }, 10000);

View File

@ -15,8 +15,6 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container"> <div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
@ -24,39 +22,81 @@
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="javascript:history.back()">Back to configuration</a> <a class="nav-link" href="/index.htm">Home</a>
</li> </li>
</ul> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/config.htm">Configuration</a></li>
<li><a class="dropdown-item" href="#">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="/calibration.htm">Calibration</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about.htm">About</a>
</li>
</ul>
</div> </div>
<div class="spinner-border text-light" id="spinner" role="status"></div> <div class="spinner-border text-light" id="spinner" role="status"></div>
</div> </div>
</nav> </nav>
<!-- START MAIN INDEX --> <!-- START MAIN INDEX -->
<div class="container row-margin-10"> <div class="container row-margin-10">
<div class="alert alert-success alert-dismissible hide fade d-none" role="alert"> <div class="alert alert-success alert-dismissible hide fade d-none" role="alert" id="alert">
<div id="alert"></div> <div id="alert-msg"></div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<div class="alert alert-warning alert-dismissible hide fade d-none" role="alert" id="warning-ha">
<div>Home Assistant device configuration detected in MQTT format. These messages will be posted when format is saved and not during gravity measurement.</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<div class="alert alert-warning alert-dismissible hide fade d-none" role="alert" id="warning-length">
<div>The format template is quite large, its possible the device will not have enough memory to handle it.</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function showError( msg ) { function showError( msg ) {
$('.alert').removeClass('alert-success').addClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none'); $('#alert').removeClass('alert-success').addClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none');
$('#alert').text( msg ); $('#alert-msg').text( msg );
} }
function showSuccess( msg ) { function showSuccess( msg ) {
$('.alert').addClass('alert-success').removeClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none'); $('#alert').addClass('alert-success').removeClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none');
$('#alert').text( msg ); $('#alert-msg').text( msg );
} }
$("#alert-btn").click(function(e){ $("#alert-btn").click(function(e){
$('.alert').addClass('hide').removeClass('show').addClass('d-none'); $('#alert').addClass('hide').removeClass('show').addClass('d-none');
}); });
function showWarningHomeAssistant() {
$('#warning-ha').removeClass('d-none').addClass('show').removeClass('hide');
}
function hideWarningHomeAssistant() {
$('#warning-ha').addClass('d-none').removeClass('show').addClass('hide');
}
function showWarningLength() {
$('#warning-length').removeClass('d-none').addClass('show').removeClass('hide');
}
function hideWarningLength() {
$('#warning-length').addClass('d-none').removeClass('show').addClass('hide');
}
</script> </script>
<div class="accordion" id="accordion"> <div class="accordion" id="accordion">
@ -89,7 +129,7 @@
<div class="row mb-3"> <div class="row mb-3">
<div class="col-sm-12"> <div class="col-sm-12">
<textarea rows="10" class="form-control" name="format" id="format"> <textarea rows="10" class="form-control" name="format" id="format" onchange="updateStatusField()" onkeydown="updateStatusField()">
</textarea> </textarea>
</div> </div>
</div> </div>
@ -102,7 +142,7 @@
{ "id": "BrewFatherCustom-Post", "format": "%7B%20%20%20%22name%22%3A%20%22%24%7Bmdns%7D%22%2C%20%20%20%22temp%22%3A%20%24%7Btemp%7D%2C%20%20%20%22aux_temp%22%3A%200%2C%20%20%20%22ext_temp%22%3A%200%2C%20%20%20%22temp_unit%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%20%20%22gravity_unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%20%20%20%22pressure%22%3A%200%2C%20%20%20%22pressure_unit%22%3A%20%22PSI%22%2C%20%20%20%22ph%22%3A%200%2C%20%20%20%22bpm%22%3A%200%2C%20%20%20%22comment%22%3A%20%22%22%2C%20%20%20%22beer%22%3A%20%22%22%2C%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%7D" }, { "id": "BrewFatherCustom-Post", "format": "%7B%20%20%20%22name%22%3A%20%22%24%7Bmdns%7D%22%2C%20%20%20%22temp%22%3A%20%24%7Btemp%7D%2C%20%20%20%22aux_temp%22%3A%200%2C%20%20%20%22ext_temp%22%3A%200%2C%20%20%20%22temp_unit%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%20%20%22gravity_unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%20%20%20%22pressure%22%3A%200%2C%20%20%20%22pressure_unit%22%3A%20%22PSI%22%2C%20%20%20%22ph%22%3A%200%2C%20%20%20%22bpm%22%3A%200%2C%20%20%20%22comment%22%3A%20%22%22%2C%20%20%20%22beer%22%3A%20%22%22%2C%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%7D" },
{ "id": "iSpindle-Mqtt", "format": "ispindel%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Bangle%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Ftemp_units%3A%24%7Btemp-unit%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Finterval%3A%24%7Bsleep-interval%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2FRSSI%3A%24%7Brssi%7D%7C" }, { "id": "iSpindle-Mqtt", "format": "ispindel%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Bangle%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Ftemp_units%3A%24%7Btemp-unit%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Finterval%3A%24%7Bsleep-interval%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2FRSSI%3A%24%7Brssi%7D%7C" },
{ "id": "HomeAssistant-Mqtt", "format": "gravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Frssi%3A%24%7Brssi%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Btilt%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0A" }, { "id": "HomeAssistant-Mqtt", "format": "gravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Frssi%3A%24%7Brssi%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Btilt%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0A" },
{ "id": "HomeAssistant-Mqtt2", "format": "gravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Frssi%3A%24%7Brssi%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Btilt%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Ftemperature%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_temp%22%2C%22name%22%3A%22temperature%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22%24%7Btemp-unit%7D%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Ftemperature%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Fgravity%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_grav%22%2C%22name%22%3A%22gravity%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22%20%24%7Bgravity-unit%7D%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Fgravity%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Frssi%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_rssi%22%2C%22name%22%3A%22rssi%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22dBm%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Frssi%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Ftilt%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_tilt%22%2C%22name%22%3A%22tilt%22%2C%22dev_cla%22%3A%22temperature%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Ftilt%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Fbattery%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_batt%22%2C%22name%22%3A%22battery%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22V%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Fbattery%22%7D%7C%0A" }, { "id": "HomeAssistant-Mqtt2", "format": "gravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Frssi%3A%24%7Brssi%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Btilt%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Ftemperature%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_temp%22%2C%22name%22%3A%22temperature%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22%24%7Btemp-unit%7D%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Ftemperature%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Fgravity%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_grav%22%2C%22name%22%3A%22gravity%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22%20%24%7Bgravity-unit%7D%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Fgravity%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Frssi%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_rssi%22%2C%22name%22%3A%22rssi%22%2C%22dev_cla%22%3A%22signal_strength%22%2C%22unit_of_meas%22%3A%22dBm%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Frssi%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Ftilt%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_tilt%22%2C%22name%22%3A%22tilt%22%2C%22dev_cla%22%3A%22temperature%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Ftilt%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Fbattery%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_batt%22%2C%22name%22%3A%22battery%22%2C%22dev_cla%22%3A%22voltage%22%2C%22unit_of_meas%22%3A%22V%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Fbattery%22%7D%7C%0A" },
{ "id": "Brewblox-Mqtt", "format": "brewcast%2Fhistory%3A%7B%22key%22%3A%22%24%7Bmdns%7D%22%2C%22data%22%3A%7B%22Temperature%5BdegC%5D%22%3A%20%24%7Btemp-c%7D%2C%22Temperature%5BdegF%5D%22%3A%20%24%7Btemp-f%7D%2C%22Battery%5BV%5D%22%3A%24%7Bbattery%7D%2C%22Tilt%5Bdeg%5D%22%3A%24%7Bangle%7D%2C%22Rssi%5BdBm%5D%22%3A%24%7Brssi%7D%2C%22SG%22%3A%24%7Bgravity-sg%7D%2C%22Plato%22%3A%24%7Bgravity-plato%7D%7D%7D%7C" }, { "id": "Brewblox-Mqtt", "format": "brewcast%2Fhistory%3A%7B%22key%22%3A%22%24%7Bmdns%7D%22%2C%22data%22%3A%7B%22Temperature%5BdegC%5D%22%3A%20%24%7Btemp-c%7D%2C%22Temperature%5BdegF%5D%22%3A%20%24%7Btemp-f%7D%2C%22Battery%5BV%5D%22%3A%24%7Bbattery%7D%2C%22Tilt%5Bdeg%5D%22%3A%24%7Bangle%7D%2C%22Rssi%5BdBm%5D%22%3A%24%7Brssi%7D%2C%22SG%22%3A%24%7Bgravity-sg%7D%2C%22Plato%22%3A%24%7Bgravity-plato%7D%7D%7D%7C" },
{ "id": "UBIDots-Post", "format": "%7B%0A%20%20%20%22temperature%22%3A%20%24%7Btemp%7D%2C%0A%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%0A%20%20%20%22angle%22%3A%20%24%7Bangle%7D%2C%0A%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%2C%0A%20%20%20%22rssi%22%3A%20%24%7Brssi%7D%0A%7D" } ]; { "id": "UBIDots-Post", "format": "%7B%0A%20%20%20%22temperature%22%3A%20%24%7Btemp%7D%2C%0A%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%0A%20%20%20%22angle%22%3A%20%24%7Bangle%7D%2C%0A%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%2C%0A%20%20%20%22rssi%22%3A%20%24%7Brssi%7D%0A%7D" } ];
</script> </script>
@ -130,6 +170,9 @@
</div> </div>
</div> </div>
<div class="col-sm-8" id="status">
</div>
<hr class="my-2"> <hr class="my-2">
<pre class="card-preview" id="preview" name="preview"></pre> <pre class="card-preview" id="preview" name="preview"></pre>
@ -143,6 +186,8 @@
<script type="text/javascript"> <script type="text/javascript">
window.onload = getConfig; window.onload = getConfig;
var maxCharsInFormatTemplate = 1500;
setButtonDisabled( true ); setButtonDisabled( true );
// Opens the targetet according (if URL has #collapseOne to #collapseFour) // Opens the targetet according (if URL has #collapseOne to #collapseFour)
@ -153,6 +198,17 @@
} }
}); });
function updateStatusField() {
var t = $("#format").val();
$("#status").text( t.length + " characters in template, recommended maximum is " + maxCharsInFormatTemplate );
if (t.length > maxCharsInFormatTemplate) {
showWarningLength();
} else {
hideWarningLength();
}
};
$("#push-target").change(function(e){ $("#push-target").change(function(e){
console.log(e) console.log(e)
selectFormat(); selectFormat();
@ -169,29 +225,88 @@
$("#format").val( decodeURIComponent(item.format) ); $("#format").val( decodeURIComponent(item.format) );
} }
}); });
updateStatusField();
}); });
// Clear the selected template // Clear the selected template
$("#clear-btn").click(function(e) { $("#clear-btn").click(function(e) {
$("#format").val( "" ); $("#format").val( "" );
updateStatusField();
}); });
// Store the format // Store the format
$("#format-btn").click(function(e) { $("#format-btn").click(function(e) {
var s = $("#format").val(); var s = $("#format").val();
s = s.replaceAll("\n", "");
var obj = 'id=' + $("#id").val() + '&' + $("#push-target").val() + '=' + encodeURIComponent(s);
console.log(obj);
/*if (s.length > maxCharsInFormatTemplate) {
showError("Format template is too large for the device to handle, unable to save.")
return;
}*/
$('#spinner').show();
setButtonDisabled( true );
var ha = false;
hideWarningHomeAssistant();
if ($("#push-target").val() == "mqtt") {
if (s.search("homeassistant/sensor/") != -1) {
console.log("Current format is mqtt, it contains topics for Home Assistant device registration.")
showWarningHomeAssistant();
ha = true;
}
}
s = s.replaceAll("\n", "");
var obj = 'id=' + $("#id").val() + "&" + $("#push-target").val() + '=' + encodeURIComponent(s);
console.log(obj);
$.ajax( { $.ajax( {
type: "POST", type: "POST",
url: "/api/config/format", url: "/api/config/format",
data: obj, data: obj,
success: function(result) { showSuccess('Format stored successfully.'); getConfig(); }, success: function(result) { showSuccess('Format stored successfully.'); postHomeAssistant(ha); },
error: function(result) { showError('Unable to store format.'); } error: function(result) { showError('Unable to store format.'); $('#spinner').hide(); },
always: function() { $('#spinner').hide(); setButtonDisabled( false ); }
} ); } );
}); });
function postHomeAssistant(active) {
if (!active) {
getConfig();
return;
}
console.log("Current format is mqtt, running post tests to register device.")
$('#spinner').show();
setButtonDisabled( true );
var url = "/api/test/push";
url += "?id=" + $("#id").val() + "&format=mqtt";
//var url = "/test/push.json";
$.getJSON(url, function (cfg) {
console.log(cfg);
var code = cfg["code"];
var success = cfg["success"];
var enabled = cfg["enabled"];
if(success) {
showSuccess( "Format stored successfully. Home Assistant Device Registration Successful." );
} else {
showError( "Format stored successfully. Home Assistant Device Registration Failed!" );
}
})
.fail(function() {
showError( "Format stored successfully. Home Assistant Device Registration Failed!" );
})
.always(function() {
$('#spinner').hide();
setButtonDisabled( false );
getConfig();
});
}
// Test the calibration // Test the calibration
$("#test-btn").click(function(e) { $("#test-btn").click(function(e) {
var url = "/api/status"; var url = "/api/status";
@ -265,6 +380,9 @@
function setButtonDisabled( b ) { function setButtonDisabled( b ) {
$("#format-btn").prop("disabled", b); $("#format-btn").prop("disabled", b);
$("#test-btn").prop("disabled", b); $("#test-btn").prop("disabled", b);
$("#copy-btn").prop("disabled", b);
$("#clear-btn").prop("disabled", b);
$("#push-target").prop("disabled", b);
} }
function selectFormat() { function selectFormat() {
@ -276,6 +394,7 @@
console.log(s); console.log(s);
$("#format").val(s); $("#format").val(s);
$("#preview").text(""); $("#preview").text("");
updateStatusField();
} }
// Get the configuration values from the API // Get the configuration values from the API
@ -283,7 +402,7 @@
setButtonDisabled( true ); setButtonDisabled( true );
var url = "/api/config/format"; var url = "/api/config/format";
//var url = "/test/format.json"; // var url = "/test/format.json";
$('#spinner').show(); $('#spinner').show();
$.getJSON(url, function (cfg) { $.getJSON(url, function (cfg) {
console.log( cfg ); console.log( cfg );
@ -303,6 +422,8 @@
$('#spinner').hide(); $('#spinner').hide();
setButtonDisabled( false ); setButtonDisabled( false );
}); });
updateStatusField();
} }
</script> </script>

File diff suppressed because one or more lines are too long

View File

@ -16,8 +16,6 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container"> <div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
@ -27,12 +25,20 @@
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link active" href="#"><b>Home</b></a> <a class="nav-link active" href="#">Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item dropdown">
<a class="nav-link" href="/config.htm">Configuration</a> <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/config.htm">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/calibration.htm">Calibration</a> <a class="nav-link" href="/calibration.htm">Calibration</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
@ -44,6 +50,7 @@
</div> </div>
</nav> </nav>
<!-- START MAIN INDEX --> <!-- START MAIN INDEX -->
<div class="container row-margin-10"> <div class="container row-margin-10">
@ -153,11 +160,33 @@
}); });
setInterval(function() { setInterval(function() {
loadLog(); loadLog();
}, 5000); }, 30000);
function loadLog() { function loadLog() {
$("#logContent").load("/log"); var url2 = "/log2";
//$("#logContent").load("/test/log"); var url1 = "/log";
//var url2 = "/test/log2";
//var url1 = "/test/log1";
var log = "";
$.get(url2, function(data) {
console.log(data);
var list = data.split("\n");
list.forEach(function (item, index) {
log = item + "\n" + log;
});
}).always( function() {
$.get(url1, function(data) {
console.log(data);
var list = data.split("\n");
list.forEach(function (item, index) {
log = item + "\n" + log;
});
}).always( function() {
console.log(log);
$("#logContent").text(log);
});
});
}; };
</script> </script>
@ -175,13 +204,13 @@
<div class="collapse row-margin-10" id="collapseLog"> <div class="collapse row-margin-10" id="collapseLog">
<div class="card card-body"> <div class="card card-body">
<pre><code class="card-text" id="logContent"></code></pre> <pre><code class="card-text" id="logContent" data-bs-toggle="tooltip" title="Shows the last errors on the device, newest on top.">Loading log data, please wait...</code></pre>
</div> </div>
</div> </div>
<div class="collapse row-margin-10" id="collapseSupport"> <div class="collapse row-margin-10" id="collapseSupport">
<div class="card card-body"> <div class="card card-body">
<pre><code class="card-text" id="supportContent"></code></pre> <pre><code class="card-text" id="supportContent">Collecting support data, please wait...</code></pre>
</div> </div>
</div> </div>
@ -293,7 +322,11 @@
var angle = cfg["angle"]; var angle = cfg["angle"];
if(angle==0) { if(angle==-1) {
showError("Unable to connect to gyro, try a reset or power off/on")
$("#angle").text("No gyro");
$("#gravity").text("No gyro");
} else if(angle==0) {
$("#angle").text("Gyro moving"); $("#angle").text("Gyro moving");
$("#gravity").text("Gyro moving"); $("#gravity").text("Gyro moving");
} else { } else {
@ -322,10 +355,14 @@
$("#battery").text(batt + " V (" + charge + "%)" ); $("#battery").text(batt + " V (" + charge + "%)" );
if( cfg["temp-format"] == "C") if( cfg["temp-c"] == -273) {
$("#temp").text(cfg["temp-c"] + " C"); $("#temp").text("No temp sensor");
else } else {
$("#temp").text(cfg["temp-f"] + " F"); if( cfg["temp-format"] == "C")
$("#temp").text(cfg["temp-c"] + " C");
else
$("#temp").text(cfg["temp-f"] + " F");
}
if( cfg["sleep-mode"] ) if( cfg["sleep-mode"] )
$("#sleep-mode").attr("checked", true ); $("#sleep-mode").attr("checked", true );
@ -342,7 +379,7 @@
} }
function start() { function start() {
setInterval(getStatus, 3000); setInterval(getStatus, 5000);
} }
</script> </script>

File diff suppressed because one or more lines are too long

View File

@ -15,8 +15,6 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container"> <div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
@ -24,11 +22,28 @@
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="javascript:history.back()">Back to configuration</a> <a class="nav-link" href="/index.htm">Home</a>
</li> </li>
</ul> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/config.htm">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="#">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="/calibration.htm">Calibration</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about.htm">About</a>
</li>
</ul>
</div> </div>
<div class="spinner-border text-light" id="spinner" role="status"></div> <div class="spinner-border text-light" id="spinner" role="status"></div>
</div> </div>

File diff suppressed because one or more lines are too long

View File

@ -1,179 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>Beer Gravity Monitor</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<style>
.row-margin-10 { margin-top: 1.0em; }
</style>
</head>
<body class="py-4">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="spinner-border text-light" id="spinner" role="status"></div>
</div>
</nav>
<!-- START MAIN INDEX -->
<div class="container row-margin-10">
<div class="alert alert-success alert-dismissible hide fade d-none" role="alert">
<div id="alert"></div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<script type="text/javascript">
function showError( msg ) {
$('.alert').removeClass('alert-success').addClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none');
$('#alert').text( msg );
}
function showSuccess( msg ) {
$('.alert').addClass('alert-success').removeClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none');
$('#alert').text( msg );
}
$("#alert-btn").click(function(e){
$('.alert').addClass('hide').removeClass('show').addClass('d-none');
});
</script>
<div class="accordion" id="accordion">
<div class="accordion-item">
<h2 class="accordion-header" id="headingUpload">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseUpload" aria-expanded="true" aria-controls="collapseUpload">
<b>Upload missing html files</b>
</button>
</h2>
<div id="collapseUpload" class="accordion-collapse collapse show" aria-labelledby="headingUpload" data-bs-parent="#accordion">
<div class="accordion-body">
<div class="row mb-3">
<div class="col-md-8 bg-light">The listed files below needs to be uploaded to the FileSystem in order for the GUI to work.
You can also flash the LittleFS filesystem but in that case you will loose your device settings. An OTA upgrade will automatically download
the files if they are found in the same location as the firmware.bin. This page is a fallback option.
</div>
<div class="col-md-8 bg-light"><br><strong>Once all the files are confirmed, please reboot the device for normal operation.</strong></div>
</div>
<div class="row mb-3">
<div class="col-md-2 bg-light">index.min.htm</div>
<div class="col-md-6 bg-light" id="index">Checking...</div>
</div>
<div class="row mb-3">
<div class="col-md-2 bg-light">config.min.htm</div>
<div class="col-md-6 bg-light" id="config">Checking...</div>
</div>
<div class="row mb-3">
<div class="col-md-2 bg-light">calibration.min.htm</div>
<div class="col-md-6 bg-light" id="calibration">Checking...</div>
</div>
<div class="row mb-3">
<div class="col-md-2 bg-light">format.min.htm</div>
<div class="col-md-6 bg-light" id="format">Checking...</div>
</div>
<div class="row mb-3">
<div class="col-md-2 bg-light">test.min.htm</div>
<div class="col-md-6 bg-light" id="test">Checking...</div>
</div>
<div class="row mb-3">
<div class="col-md-2 bg-light">about.min.htm</div>
<div class="col-md-6 bg-light" id="about">Checking...</div>
</div>
<form action="/api/upload" method="post" enctype="multipart/form-data">
<div class="row mb-3">
<div class="col-md-8 custom-file">
<input type="file" accept=".min.htm" class="custom-file-input" name="name" id="name" data-bs-toggle="tooltip" title="Select a file that matches the name in the list above to upload it to the device">
</div>
</div>
<div class="row mb-3">
<div class="col-md-3">
<button type="submit" class="btn btn-primary" id="upload-btn" value="upload" data-bs-toggle="tooltip" title="Upload the selected file to the device">Upload</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
window.onload = getUpload;
// Add the following code if you want the name of the file appear on select
$(".custom-file-input").on("change", function() {
var fileName = $(this).val().split("\\").pop();
$(this).siblings(".custom-file-label").addClass("selected").html(fileName);
});
function getUpload() {
var url = "/api/upload";
//var url = "/test/upload.json";
$('#spinner').show();
$.getJSON(url, function (cfg) {
console.log( cfg );
if( cfg["index"] )
$("#index").text("Completed.");
else
$("#index").text("File is missing.");
if( cfg["config"] )
$("#config").text("Completed.");
else
$("#config").text("File is missing.");
if( cfg["calibration"] )
$("#calibration").text("Completed.");
else
$("#calibration").text("File is missing.");
if( cfg["test"] )
$("#test").text("Completed.");
else
$("#test").text("File is missing.");
if( cfg["format"] )
$("#format").text("Completed.");
else
$("#format").text("File is missing.");
if( cfg["about"] )
$("#about").text("Completed.");
else
$("#about").text("File is missing.");
})
.fail(function () {
showError('Unable to get data from the device.');
})
.always(function() {
$('#spinner').hide();
});
}
</script>
<!-- START FOOTER -->
<div class="container themed-container bg-primary text-light row-margin-10">(C) Copyright 2021-22 Magnus Persson</div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@
Built by Khoi Hoang https://github.com/khoih-prog/ESP_DoubleResetDetector Built by Khoi Hoang https://github.com/khoih-prog/ESP_DoubleResetDetector
Licensed under MIT license Licensed under MIT license
Version: 1.3.1 Version: 1.3.2
Version Modified By Date Comments Version Modified By Date Comments
------- ----------- ---------- ----------- ------- ----------- ---------- -----------
@ -24,6 +24,7 @@
1.2.1 K Hoang 26/11/2021 Fix compile error for ESP32 core v1.0.5- 1.2.1 K Hoang 26/11/2021 Fix compile error for ESP32 core v1.0.5-
1.3.0 K Hoang 10/02/2022 Add support to new ESP32-S3 1.3.0 K Hoang 10/02/2022 Add support to new ESP32-S3
1.3.1 K Hoang 04/03/2022 Add waitingForDRD() function to signal in DRD wating period 1.3.1 K Hoang 04/03/2022 Add waitingForDRD() function to signal in DRD wating period
1.3.2 K Hoang 09/09/2022 Fix ESP32 chipID for example ConfigOnDoubleReset
*****************************************************************************************************************************/ *****************************************************************************************************************************/
#pragma once #pragma once
@ -42,13 +43,13 @@
#endif #endif
#ifndef ESP_DOUBLE_RESET_DETECTOR_VERSION #ifndef ESP_DOUBLE_RESET_DETECTOR_VERSION
#define ESP_DOUBLE_RESET_DETECTOR_VERSION "ESP_DoubleResetDetector v1.3.1" #define ESP_DOUBLE_RESET_DETECTOR_VERSION "ESP_DoubleResetDetector v1.3.2"
#define ESP_DOUBLE_RESET_DETECTOR_VERSION_MAJOR 1 #define ESP_DOUBLE_RESET_DETECTOR_VERSION_MAJOR 1
#define ESP_DOUBLE_RESET_DETECTOR_VERSION_MINOR 3 #define ESP_DOUBLE_RESET_DETECTOR_VERSION_MINOR 3
#define ESP_DOUBLE_RESET_DETECTOR_VERSION_PATCH 1 #define ESP_DOUBLE_RESET_DETECTOR_VERSION_PATCH 2
#define ESP_DOUBLE_RESET_DETECTOR_VERSION_INT 1003001 #define ESP_DOUBLE_RESET_DETECTOR_VERSION_INT 1003002
#endif #endif
#define ESP_DOUBLERESETDETECTOR_VERSION ESP_DOUBLE_RESET_DETECTOR_VERSION #define ESP_DOUBLERESETDETECTOR_VERSION ESP_DOUBLE_RESET_DETECTOR_VERSION

View File

@ -16,47 +16,18 @@
Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager
Licensed under MIT license Licensed under MIT license
Version: 1.8.0 Version: 1.11.0
Version Modified By Date Comments Version Modified By Date Comments
------- ----------- ---------- ----------- ------- ----------- ---------- -----------
1.0.0 K Hoang 07/10/2019 Initial coding 1.0.0 K Hoang 07/10/2019 Initial coding
1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 ...
1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. 1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp
1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples 1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h
1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. 1.10.0 K Hoang 10/02/2022 Add support to new ESP32-S3
1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc 1.10.1 K Hoang 11/02/2022 Add LittleFS support to ESP32-C3. Use core LittleFS instead of Lorol's LITTLEFS for v2.0.0+
1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) 1.10.2 K Hoang 13/03/2022 Send CORS header in handleWifiSave() function
1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md 1.11.0 K Hoang 09/09/2022 Fix ESP32 chipID and add ESP_getChipOUI()
1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+
1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal.
Add, enhance examples (fix MDNS for ESP32)
1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict.
1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings.
1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime
1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement.
1.1.2 K Hoang 17/08/2020 Fix bug. Add example.
1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug.
1.3.0 K Hoang 04/12/2020 Add LittleFS support to ESP32 using LITTLEFS Library
1.4.1 K Hoang 22/12/2020 Fix staticIP not saved. Add functions. Add complex examples. Sync with ESPAsync_WiFiManager
1.4.2 K Hoang 14/01/2021 Fix examples' bug not using saved WiFi Credentials after losing all WiFi connections.
1.4.3 K Hoang 23/01/2021 Fix examples' bug not saving Static IP in certain cases.
1.5.0 K Hoang 12/02/2021 Add support to new ESP32-S2
1.5.1 K Hoang 26/03/2021 Fix compiler error if setting Compiler Warnings to All. Retest with esp32 core v1.0.6
1.5.2 K Hoang 08/04/2021 Fix example misleading messages.
1.5.3 K Hoang 13/04/2021 Add dnsServer error message.
1.6.0 K Hoang 20/04/2021 Add support to new ESP32-C3 using SPIFFS or EEPROM
1.6.1 K Hoang 25/04/2021 Fix MultiWiFi bug. Fix captive-portal bug if CP AP address is not default 192.168.4.1
1.7.0 K Hoang 06/05/2021 Set _timezoneName. Add support to new ESP32-S2 (METRO_ESP32S2, FUNHOUSE_ESP32S2, etc.)
1.7.1 K Hoang 08/05/2021 Fix Json bug. Fix timezoneName not displayed in Info page.
1.7.2 K Hoang 08/05/2021 Fix warnings with ESP8266 core v3.0.0
1.7.3 K Hoang 29/07/2021 Fix MultiWiFi connection issue with ESP32 core v2.0.0-rc1+
1.7.4 K Hoang 13/08/2021 Add WiFi scanning of hidden SSIDs
1.7.5 K Hoang 10/10/2021 Update `platform.ini` and `library.json`
1.7.6 K Hoang 26/11/2021 Auto detect ESP32 core and use either built-in LittleFS or LITTLEFS library
1.7.7 K Hoang 26/11/2021 Fix compile error for ESP32 core v1.0.5-
1.7.8 K Hoang 30/11/2021 Fix bug to permit using HTTP port different from 80. Fix bug
1.8.0 K Hoang 29/12/2021 Enable compatibility with old code to include only ESP_WiFiManager.h
*****************************************************************************************************************************/ *****************************************************************************************************************************/
#pragma once #pragma once
@ -80,7 +51,7 @@ ESP_WMParameter::ESP_WMParameter(const char *custom)
////////////////////////////////////////// //////////////////////////////////////////
ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement) ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, const int& length, const char *custom, const int& labelPlacement)
{ {
init(id, placeholder, defaultValue, length, custom, labelPlacement); init(id, placeholder, defaultValue, length, custom, labelPlacement);
} }
@ -94,7 +65,7 @@ ESP_WMParameter::ESP_WMParameter(const WMParam_Data& WMParam_data)
////// //////
////////////////////////////////////////// //////////////////////////////////////////
void ESP_WMParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement) void ESP_WMParameter::init(const char *id, const char *placeholder, const char *defaultValue, const int& length, const char *custom, const int& labelPlacement)
{ {
_WMParam_data._id = id; _WMParam_data._id = id;
_WMParam_data._placeholder = placeholder; _WMParam_data._placeholder = placeholder;
@ -252,7 +223,8 @@ ESP_WiFiManager::ESP_WiFiManager(const char *iHostname)
#ifdef ESP8266 #ifdef ESP8266
String _hostname = "ESP8266-" + String(ESP.getChipId(), HEX); String _hostname = "ESP8266-" + String(ESP.getChipId(), HEX);
#else //ESP32 #else //ESP32
String _hostname = "ESP32-" + String((uint32_t)ESP.getEfuseMac(), HEX); String _hostname = "ESP32-" + String(ESP_getChipId(), HEX);
#endif #endif
_hostname.toUpperCase(); _hostname.toUpperCase();
@ -461,7 +433,8 @@ bool ESP_WiFiManager::autoConnect()
#ifdef ESP8266 #ifdef ESP8266
String ssid = "ESP_" + String(ESP.getChipId()); String ssid = "ESP_" + String(ESP.getChipId());
#else //ESP32 #else //ESP32
String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac()); String ssid = "ESP_" + String(ESP_getChipId());
#endif #endif
return autoConnect(ssid.c_str(), NULL); return autoConnect(ssid.c_str(), NULL);
@ -522,7 +495,7 @@ bool ESP_WiFiManager::startConfigPortal()
#ifdef ESP8266 #ifdef ESP8266
String ssid = "ESP_" + String(ESP.getChipId()); String ssid = "ESP_" + String(ESP.getChipId());
#else //ESP32 #else //ESP32
String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac()); String ssid = "ESP_" + String(ESP_getChipId());
#endif #endif
ssid.toUpperCase(); ssid.toUpperCase();
@ -864,7 +837,7 @@ void ESP_WiFiManager::startWPS()
//Convenient for debugging but wasteful of program space. //Convenient for debugging but wasteful of program space.
//Remove if short of space //Remove if short of space
const char* ESP_WiFiManager::getStatus(int status) const char* ESP_WiFiManager::getStatus(const int& status)
{ {
switch (status) switch (status)
{ {
@ -920,21 +893,21 @@ void ESP_WiFiManager::resetSettings()
////////////////////////////////////////// //////////////////////////////////////////
void ESP_WiFiManager::setTimeout(unsigned long seconds) void ESP_WiFiManager::setTimeout(const unsigned long& seconds)
{ {
setConfigPortalTimeout(seconds); setConfigPortalTimeout(seconds);
} }
////////////////////////////////////////// //////////////////////////////////////////
void ESP_WiFiManager::setConfigPortalTimeout(unsigned long seconds) void ESP_WiFiManager::setConfigPortalTimeout(const unsigned long& seconds)
{ {
_configPortalTimeout = seconds * 1000; _configPortalTimeout = seconds * 1000;
} }
////////////////////////////////////////// //////////////////////////////////////////
void ESP_WiFiManager::setConnectTimeout(unsigned long seconds) void ESP_WiFiManager::setConnectTimeout(const unsigned long& seconds)
{ {
_connectTimeout = seconds * 1000; _connectTimeout = seconds * 1000;
} }
@ -949,7 +922,7 @@ void ESP_WiFiManager::setDebugOutput(bool debug)
////////////////////////////////////////// //////////////////////////////////////////
// KH, new from v1.0.10 to enable dynamic/random channel // KH, new from v1.0.10 to enable dynamic/random channel
int ESP_WiFiManager::setConfigPortalChannel(int channel) int ESP_WiFiManager::setConfigPortalChannel(const int& channel)
{ {
// If channel < MIN_WIFI_CHANNEL - 1 or channel > MAX_WIFI_CHANNEL => channel = 1 // If channel < MIN_WIFI_CHANNEL - 1 or channel > MAX_WIFI_CHANNEL => channel = 1
// If channel == 0 => will use random channel from MIN_WIFI_CHANNEL to MAX_WIFI_CHANNEL // If channel == 0 => will use random channel from MIN_WIFI_CHANNEL to MAX_WIFI_CHANNEL
@ -1037,7 +1010,7 @@ void ESP_WiFiManager::setSTAStaticIPConfig(const IPAddress& ip, const IPAddress&
////////////////////////////////////////// //////////////////////////////////////////
void ESP_WiFiManager::setMinimumSignalQuality(int quality) void ESP_WiFiManager::setMinimumSignalQuality(const int& quality)
{ {
_minimumQuality = quality; _minimumQuality = quality;
} }
@ -1392,6 +1365,11 @@ void ESP_WiFiManager::handleWifiSave()
_pass1 = server->arg("p1").c_str(); _pass1 = server->arg("p1").c_str();
/////////////////////// ///////////////////////
#if USING_CORS_FEATURE
// New from v1.10.2, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*"
server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header);
#endif
#if USE_ESP_WIFIMANAGER_NTP #if USE_ESP_WIFIMANAGER_NTP
@ -1584,10 +1562,23 @@ void ESP_WiFiManager::handleInfo()
page += F("<table class=\"table\">"); page += F("<table class=\"table\">");
page += F("<thead><tr><th>Name</th><th>Value</th></tr></thead><tbody><tr><td>Chip ID</td><td>"); page += F("<thead><tr><th>Name</th><th>Value</th></tr></thead><tbody><tr><td>Chip ID</td><td>");
page += F("0x");
#ifdef ESP8266 #ifdef ESP8266
page += String(ESP.getChipId(), HEX); //ESP.getChipId(); page += String(ESP.getChipId(), HEX); //ESP.getChipId();
#else //ESP32 #else //ESP32
page += String((uint32_t)ESP.getEfuseMac(), HEX); //ESP.getChipId();
page += String(ESP_getChipId(), HEX); //ESP.getChipId();
page += F("</td></tr>");
page += F("<tr><td>Chip OUI</td><td>");
page += F("0x");
page += String(getChipOUI(), HEX); //ESP.getChipId();
page += F("</td></tr>");
page += F("<tr><td>Chip Model</td><td>");
page += ESP.getChipModel();
page += F(" Rev");
page += ESP.getChipRevision();
#endif #endif
page += F("</td></tr>"); page += F("</td></tr>");
@ -2019,7 +2010,7 @@ int ESP_WiFiManager::scanWifiNetworks(int **indicesptr)
////////////////////////////////////////// //////////////////////////////////////////
int ESP_WiFiManager::getRSSIasQuality(int RSSI) int ESP_WiFiManager::getRSSIasQuality(const int& RSSI)
{ {
int quality = 0; int quality = 0;
@ -2116,6 +2107,31 @@ String ESP_WiFiManager::getStoredWiFiPass()
return String(reinterpret_cast<char*>(conf.sta.password)); return String(reinterpret_cast<char*>(conf.sta.password));
} }
uint32_t getChipID()
{
uint64_t chipId64 = 0;
for (int i = 0; i < 6; i++)
{
chipId64 |= ( ( (uint64_t) ESP.getEfuseMac() >> (40 - (i * 8)) ) & 0xff ) << (i * 8);
}
return (uint32_t) (chipId64 & 0xFFFFFF);
}
uint32_t getChipOUI()
{
uint64_t chipId64 = 0;
for (int i = 0; i < 6; i++)
{
chipId64 |= ( ( (uint64_t) ESP.getEfuseMac() >> (40 - (i * 8)) ) & 0xff ) << (i * 8);
}
return (uint32_t) (chipId64 >> 24);
}
#endif #endif

View File

@ -16,48 +16,18 @@
Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager
Licensed under MIT license Licensed under MIT license
Version: 1.9.0 Version: 1.11.0
Version Modified By Date Comments Version Modified By Date Comments
------- ----------- ---------- ----------- ------- ----------- ---------- -----------
1.0.0 K Hoang 07/10/2019 Initial coding 1.0.0 K Hoang 07/10/2019 Initial coding
1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 ...
1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL.
1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples
1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature.
1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc
1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 )
1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md
1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+
1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal.
Add, enhance examples (fix MDNS for ESP32)
1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict.
1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings.
1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime
1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement.
1.1.2 K Hoang 17/08/2020 Fix bug. Add example.
1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug.
1.3.0 K Hoang 04/12/2020 Add LittleFS support to ESP32 using LITTLEFS Library
1.4.1 K Hoang 22/12/2020 Fix staticIP not saved. Add functions. Add complex examples. Sync with ESPAsync_WiFiManager
1.4.2 K Hoang 14/01/2021 Fix examples' bug not using saved WiFi Credentials after losing all WiFi connections.
1.4.3 K Hoang 23/01/2021 Fix examples' bug not saving Static IP in certain cases.
1.5.0 K Hoang 12/02/2021 Add support to new ESP32-S2
1.5.1 K Hoang 26/03/2021 Fix compiler error if setting Compiler Warnings to All. Retest with esp32 core v1.0.6
1.5.2 K Hoang 08/04/2021 Fix example misleading messages.
1.5.3 K Hoang 13/04/2021 Add dnsServer error message.
1.6.0 K Hoang 20/04/2021 Add support to new ESP32-C3 using SPIFFS or EEPROM
1.6.1 K Hoang 25/04/2021 Fix MultiWiFi bug. Fix captive-portal bug if CP AP address is not default 192.168.4.1
1.7.0 K Hoang 06/05/2021 Set _timezoneName. Add support to new ESP32-S2 (METRO_ESP32S2, FUNHOUSE_ESP32S2, etc.)
1.7.1 K Hoang 08/05/2021 Fix Json bug. Fix timezoneName not displayed in Info page.
1.7.2 K Hoang 08/05/2021 Fix warnings with ESP8266 core v3.0.0
1.7.3 K Hoang 29/07/2021 Fix MultiWiFi connection issue with ESP32 core v2.0.0-rc1+
1.7.4 K Hoang 13/08/2021 Add WiFi scanning of hidden SSIDs
1.7.5 K Hoang 10/10/2021 Update `platform.ini` and `library.json`
1.7.6 K Hoang 26/11/2021 Auto detect ESP32 core and use either built-in LittleFS or LITTLEFS library
1.7.7 K Hoang 26/11/2021 Fix compile error for ESP32 core v1.0.5-
1.7.8 K Hoang 30/11/2021 Fix bug to permit using HTTP port different from 80. Fix bug
1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp 1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp
1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h 1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h
1.10.0 K Hoang 10/02/2022 Add support to new ESP32-S3
1.10.1 K Hoang 11/02/2022 Add LittleFS support to ESP32-C3. Use core LittleFS instead of Lorol's LITTLEFS for v2.0.0+
1.10.2 K Hoang 13/03/2022 Send CORS header in handleWifiSave() function
1.11.0 K Hoang 09/09/2022 Fix ESP32 chipID and add ESP_getChipOUI()
*****************************************************************************************************************************/ *****************************************************************************************************************************/
#pragma once #pragma once

View File

@ -16,48 +16,18 @@
Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager
Licensed under MIT license Licensed under MIT license
Version: 1.9.0 Version: 1.11.0
Version Modified By Date Comments Version Modified By Date Comments
------- ----------- ---------- ----------- ------- ----------- ---------- -----------
1.0.0 K Hoang 07/10/2019 Initial coding 1.0.0 K Hoang 07/10/2019 Initial coding
1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 ...
1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL.
1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples
1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature.
1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc
1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 )
1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md
1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+
1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal.
Add, enhance examples (fix MDNS for ESP32)
1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict.
1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings.
1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime
1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement.
1.1.2 K Hoang 17/08/2020 Fix bug. Add example.
1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug.
1.3.0 K Hoang 04/12/2020 Add LittleFS support to ESP32 using LITTLEFS Library
1.4.1 K Hoang 22/12/2020 Fix staticIP not saved. Add functions. Add complex examples. Sync with ESPAsync_WiFiManager
1.4.2 K Hoang 14/01/2021 Fix examples' bug not using saved WiFi Credentials after losing all WiFi connections.
1.4.3 K Hoang 23/01/2021 Fix examples' bug not saving Static IP in certain cases.
1.5.0 K Hoang 12/02/2021 Add support to new ESP32-S2
1.5.1 K Hoang 26/03/2021 Fix compiler error if setting Compiler Warnings to All. Retest with esp32 core v1.0.6
1.5.2 K Hoang 08/04/2021 Fix example misleading messages.
1.5.3 K Hoang 13/04/2021 Add dnsServer error message.
1.6.0 K Hoang 20/04/2021 Add support to new ESP32-C3 using SPIFFS or EEPROM
1.6.1 K Hoang 25/04/2021 Fix MultiWiFi bug. Fix captive-portal bug if CP AP address is not default 192.168.4.1
1.7.0 K Hoang 06/05/2021 Set _timezoneName. Add support to new ESP32-S2 (METRO_ESP32S2, FUNHOUSE_ESP32S2, etc.)
1.7.1 K Hoang 08/05/2021 Fix Json bug. Fix timezoneName not displayed in Info page.
1.7.2 K Hoang 08/05/2021 Fix warnings with ESP8266 core v3.0.0
1.7.3 K Hoang 29/07/2021 Fix MultiWiFi connection issue with ESP32 core v2.0.0-rc1+
1.7.4 K Hoang 13/08/2021 Add WiFi scanning of hidden SSIDs
1.7.5 K Hoang 10/10/2021 Update `platform.ini` and `library.json`
1.7.6 K Hoang 26/11/2021 Auto detect ESP32 core and use either built-in LittleFS or LITTLEFS library
1.7.7 K Hoang 26/11/2021 Fix compile error for ESP32 core v1.0.5-
1.7.8 K Hoang 30/11/2021 Fix bug to permit using HTTP port different from 80. Fix bug
1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp 1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp
1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h 1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h
1.10.0 K Hoang 10/02/2022 Add support to new ESP32-S3
1.10.1 K Hoang 11/02/2022 Add LittleFS support to ESP32-C3. Use core LittleFS instead of Lorol's LITTLEFS for v2.0.0+
1.10.2 K Hoang 13/03/2022 Send CORS header in handleWifiSave() function
1.11.0 K Hoang 09/09/2022 Fix ESP32 chipID and add ESP_getChipOUI()
*****************************************************************************************************************************/ *****************************************************************************************************************************/
#pragma once #pragma once
@ -70,33 +40,48 @@
#elif ( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \ #elif ( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \
ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \ ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \
ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM ) ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM )
#warning Using ESP32_S2. To follow library instructions to install esp32-s2 core and WebServer Patch #if (_WIFIMGR_LOGLEVEL_ > 3)
#warning You have to select HUGE APP or 1.9-2.0 MB APP to be able to run Config Portal. Must use PSRAM #warning Using ESP32_S2. To follow library instructions to install esp32-s2 core and WebServer Patch
#warning You have to select HUGE APP or 1.9-2.0 MB APP to be able to run Config Portal. Must use PSRAM
#endif
#define USING_ESP32_S2 true #define USING_ESP32_S2 true
#elif ( ARDUINO_ESP32C3_DEV ) #elif ( ARDUINO_ESP32C3_DEV )
#warning Using ESP32_C3. To follow library instructions to install esp32-c3 core. Only SPIFFS and EEPROM OK. #if (_WIFIMGR_LOGLEVEL_ > 3)
#warning You have to select Flash size 2MB and Minimal APP (1.3MB + 700KB) for some boards #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
#warning Using ESP32_C3 using core v2.0.0+. Either LittleFS, SPIFFS or EEPROM OK.
#else
#warning Using ESP32_C3 using core v1.0.6-. To follow library instructions to install esp32-c3 core. Only SPIFFS and EEPROM OK.
#endif
#endif
// #warning You have to select Flash size 2MB and Minimal APP (1.3MB + 700KB) for some boards
#define USING_ESP32_C3 true #define USING_ESP32_C3 true
#elif ( defined(ARDUINO_ESP32S3_DEV) || defined(ARDUINO_ESP32_S3_BOX) || defined(ARDUINO_TINYS3) || \
defined(ARDUINO_PROS3) || defined(ARDUINO_FEATHERS3) )
#if (_WIFIMGR_LOGLEVEL_ > 3)
#warning Using ESP32_S3. To install esp32-s3-support branch if using core v2.0.2-
#endif
#define USING_ESP32_S3 true
#endif #endif
#define ESP_WIFIMANAGER_VERSION "ESP_WiFiManager v1.9.0" #define ESP_WIFIMANAGER_VERSION "ESP_WiFiManager v1.11.0"
#define ESP_WIFIMANAGER_VERSION_MAJOR 1 #define ESP_WIFIMANAGER_VERSION_MAJOR 1
#define ESP_WIFIMANAGER_VERSION_MINOR 9 #define ESP_WIFIMANAGER_VERSION_MINOR 11
#define ESP_WIFIMANAGER_VERSION_PATCH 0 #define ESP_WIFIMANAGER_VERSION_PATCH 0
#define ESP_WIFIMANAGER_VERSION_INT 1009000 #define ESP_WIFIMANAGER_VERSION_INT 1011000
#include "ESP_WiFiManager_Debug.h" #include "ESP_WiFiManager_Debug.h"
#if ( defined(HTTP_PORT) && (HTTP_PORT < 65536) && (HTTP_PORT > 0) ) #if ( defined(HTTP_PORT) && (HTTP_PORT < 65536) && (HTTP_PORT > 0) )
#if (_WIFIMGR_LOGLEVEL_ > 2) #if (_WIFIMGR_LOGLEVEL_ > 3)
#warning Using custom HTTP_PORT #warning Using custom HTTP_PORT
#endif #endif
#define HTTP_PORT_TO_USE HTTP_PORT #define HTTP_PORT_TO_USE HTTP_PORT
#else #else
#if (_WIFIMGR_LOGLEVEL_ > 2) #if (_WIFIMGR_LOGLEVEL_ > 3)
#warning Using default HTTP_PORT = 80 #warning Using default HTTP_PORT = 80
#endif #endif
@ -126,9 +111,20 @@
} }
#define ESP_getChipId() (ESP.getChipId()) #define ESP_getChipId() (ESP.getChipId())
#else //ESP32 #else //ESP32
#include <esp_wifi.h> #include <esp_wifi.h>
#define ESP_getChipId() ((uint32_t)ESP.getEfuseMac())
uint32_t getChipID();
uint32_t getChipOUI();
#if defined(ESP_getChipId)
#undef ESP_getChipId
#endif
#define ESP_getChipId() getChipID() // ((uint32_t)ESP.getEfuseMac())
#define ESP_getChipOUI() getChipOUI() // ((uint32_t)ESP.getEfuseMac())
#endif #endif
// New in v1.4.0 // New in v1.4.0
@ -199,7 +195,10 @@ const char WM_HTTP_SCRIPT_NTP_HIDDEN[] PROGMEM = "<p><input type='hidden' id='ti
#if !(USE_CLOUDFLARE_NTP) #if !(USE_CLOUDFLARE_NTP)
#undef USE_CLOUDFLARE_NTP #undef USE_CLOUDFLARE_NTP
#define USE_CLOUDFLARE_NTP true #define USE_CLOUDFLARE_NTP true
#warning Forcing USE_CLOUDFLARE_NTP for ESP8266 as low memory can cause blank page
#if (_WIFIMGR_LOGLEVEL_ > 3)
#warning Forcing USE_CLOUDFLARE_NTP for ESP8266 as low memory can cause blank page
#endif
#endif #endif
#endif #endif
@ -291,8 +290,8 @@ class ESP_WMParameter
{ {
public: public:
ESP_WMParameter(const char *custom); ESP_WMParameter(const char *custom);
ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, const int& length,
const char *custom = "", int labelPlacement = WFM_LABEL_BEFORE); const char *custom = "", const int& labelPlacement = WFM_LABEL_BEFORE);
// New in v1.4.0 // New in v1.4.0
ESP_WMParameter(const WMParam_Data& WMParam_data); ESP_WMParameter(const WMParam_Data& WMParam_data);
@ -302,7 +301,7 @@ class ESP_WMParameter
// New in v1.4.0 // New in v1.4.0
void setWMParam_Data(const WMParam_Data& WMParam_data); void setWMParam_Data(const WMParam_Data& WMParam_data);
void getWMParam_Data(WMParam_Data &WMParam_data); void getWMParam_Data(WMParam_Data& WMParam_data);
////// //////
const char *getID(); const char *getID();
@ -318,7 +317,8 @@ class ESP_WMParameter
const char *_customHTML; const char *_customHTML;
void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement); void init(const char *id, const char *placeholder, const char *defaultValue, const int& length,
const char *custom, const int& labelPlacement);
friend class ESP_WiFiManager; friend class ESP_WiFiManager;
}; };
@ -359,27 +359,27 @@ class ESP_WiFiManager
//sets timeout before webserver loop ends and exits even if there has been no setup. //sets timeout before webserver loop ends and exits even if there has been no setup.
//usefully for devices that failed to connect at some point and got stuck in a webserver loop //usefully for devices that failed to connect at some point and got stuck in a webserver loop
//in seconds setConfigPortalTimeout is a new name for setTimeout //in seconds setConfigPortalTimeout is a new name for setTimeout
void setConfigPortalTimeout(unsigned long seconds); void setConfigPortalTimeout(const unsigned long& seconds);
void setTimeout(unsigned long seconds); void setTimeout(const unsigned long& seconds);
//sets timeout for which to attempt connecting, usefull if you get a lot of failed connects //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects
void setConnectTimeout(unsigned long seconds); void setConnectTimeout(const unsigned long& seconds);
void setDebugOutput(bool debug); void setDebugOutput(bool debug);
//defaults to not showing anything under 8% signal quality if called //defaults to not showing anything under 8% signal quality if called
void setMinimumSignalQuality(int quality = 8); void setMinimumSignalQuality(const int& quality = 8);
// KH, new from v1.0.10 to enable dynamic/random channel // KH, new from v1.0.10 to enable dynamic/random channel
int setConfigPortalChannel(int channel = 1); int setConfigPortalChannel(const int& channel = 1);
////// //////
//sets a custom ip /gateway /subnet configuration //sets a custom ip /gateway /subnet configuration
void setAPStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn); void setAPStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn);
// New in v1.4.0 // New in v1.4.0
void setAPStaticIPConfig(const WiFi_AP_IPConfig& WM_AP_IPconfig); void setAPStaticIPConfig(const WiFi_AP_IPConfig& WM_AP_IPconfig);
void getAPStaticIPConfig(WiFi_AP_IPConfig &WM_AP_IPconfig); void getAPStaticIPConfig(WiFi_AP_IPConfig& WM_AP_IPconfig);
////// //////
//sets config for a static IP //sets config for a static IP
@ -387,7 +387,7 @@ class ESP_WiFiManager
// New in v1.4.0 // New in v1.4.0
void setSTAStaticIPConfig(const WiFi_STA_IPConfig& WM_STA_IPconfig); void setSTAStaticIPConfig(const WiFi_STA_IPConfig& WM_STA_IPconfig);
void getSTAStaticIPConfig(WiFi_STA_IPConfig &WM_STA_IPconfig); void getSTAStaticIPConfig(WiFi_STA_IPConfig& WM_STA_IPconfig);
////// //////
#if USE_CONFIGURABLE_DNS #if USE_CONFIGURABLE_DNS
@ -447,7 +447,7 @@ class ESP_WiFiManager
#define MAX_WIFI_CREDENTIALS 2 #define MAX_WIFI_CREDENTIALS 2
String getSSID(uint8_t index) String getSSID(const uint8_t& index)
{ {
if (index == 0) if (index == 0)
return _ssid; return _ssid;
@ -457,7 +457,7 @@ class ESP_WiFiManager
return String(""); return String("");
} }
String getPW(uint8_t index) String getPW(const uint8_t& index)
{ {
if (index == 0) if (index == 0)
return _pass; return _pass;
@ -488,7 +488,7 @@ class ESP_WiFiManager
// returns the Parameters Count // returns the Parameters Count
int getParametersCount(); int getParametersCount();
const char* getStatus(int status); const char* getStatus(const int& status);
#ifdef ESP32 #ifdef ESP32
String getStoredWiFiSSID(); String getStoredWiFiSSID();
@ -605,7 +605,7 @@ class ESP_WiFiManager
void setupConfigPortal(); void setupConfigPortal();
void startWPS(); void startWPS();
//const char* getStatus(int status); //const char* getStatus(const int& status);
const char* _apName = "no-net"; const char* _apName = "no-net";
const char* _apPassword = NULL; const char* _apPassword = NULL;
@ -686,13 +686,13 @@ class ESP_WiFiManager
void handleNotFound(); void handleNotFound();
bool captivePortal(); bool captivePortal();
void reportStatus(String &page); void reportStatus(String& page);
// DNS server // DNS server
const byte DNS_PORT = 53; const byte DNS_PORT = 53;
//helpers //helpers
int getRSSIasQuality(int RSSI); int getRSSIasQuality(const int& RSSI);
bool isIp(const String& str); bool isIp(const String& str);
String toStringIp(const IPAddress& ip); String toStringIp(const IPAddress& ip);
@ -715,10 +715,13 @@ class ESP_WiFiManager
void DEBUG_WM(Generic text); void DEBUG_WM(Generic text);
template <class T> template <class T>
auto optionalIPFromString(T *obj, const char *s) -> decltype(obj->fromString(s)) { auto optionalIPFromString(T *obj, const char *s) -> decltype(obj->fromString(s))
{
return obj->fromString(s); return obj->fromString(s);
} }
auto optionalIPFromString(...) -> bool {
auto optionalIPFromString(...) -> bool
{
LOGINFO("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); LOGINFO("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work.");
return false; return false;
} }

View File

@ -16,48 +16,18 @@
Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager
Licensed under MIT license Licensed under MIT license
Version: 1.9.0 Version: 1.11.0
Version Modified By Date Comments Version Modified By Date Comments
------- ----------- ---------- ----------- ------- ----------- ---------- -----------
1.0.0 K Hoang 07/10/2019 Initial coding 1.0.0 K Hoang 07/10/2019 Initial coding
1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 ...
1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL.
1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples
1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature.
1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc
1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 )
1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md
1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+
1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal.
Add, enhance examples (fix MDNS for ESP32)
1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict.
1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings.
1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime
1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement.
1.1.2 K Hoang 17/08/2020 Fix bug. Add example.
1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug.
1.3.0 K Hoang 04/12/2020 Add LittleFS support to ESP32 using LITTLEFS Library
1.4.1 K Hoang 22/12/2020 Fix staticIP not saved. Add functions. Add complex examples. Sync with ESPAsync_WiFiManager
1.4.2 K Hoang 14/01/2021 Fix examples' bug not using saved WiFi Credentials after losing all WiFi connections.
1.4.3 K Hoang 23/01/2021 Fix examples' bug not saving Static IP in certain cases.
1.5.0 K Hoang 12/02/2021 Add support to new ESP32-S2
1.5.1 K Hoang 26/03/2021 Fix compiler error if setting Compiler Warnings to All. Retest with esp32 core v1.0.6
1.5.2 K Hoang 08/04/2021 Fix example misleading messages.
1.5.3 K Hoang 13/04/2021 Add dnsServer error message.
1.6.0 K Hoang 20/04/2021 Add support to new ESP32-C3 using SPIFFS or EEPROM
1.6.1 K Hoang 25/04/2021 Fix MultiWiFi bug. Fix captive-portal bug if CP AP address is not default 192.168.4.1
1.7.0 K Hoang 06/05/2021 Set _timezoneName. Add support to new ESP32-S2 (METRO_ESP32S2, FUNHOUSE_ESP32S2, etc.)
1.7.1 K Hoang 08/05/2021 Fix Json bug. Fix timezoneName not displayed in Info page.
1.7.2 K Hoang 08/05/2021 Fix warnings with ESP8266 core v3.0.0
1.7.3 K Hoang 29/07/2021 Fix MultiWiFi connection issue with ESP32 core v2.0.0-rc1+
1.7.4 K Hoang 13/08/2021 Add WiFi scanning of hidden SSIDs
1.7.5 K Hoang 10/10/2021 Update `platform.ini` and `library.json`
1.7.6 K Hoang 26/11/2021 Auto detect ESP32 core and use either built-in LittleFS or LITTLEFS library
1.7.7 K Hoang 26/11/2021 Fix compile error for ESP32 core v1.0.5-
1.7.8 K Hoang 30/11/2021 Fix bug to permit using HTTP port different from 80. Fix bug
1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp 1.8.0 K Hoang 29/12/2021 Fix `multiple-definitions` linker error and weird bug related to src_cpp
1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h 1.9.0 K Hoang 17/01/2022 Enable compatibility with old code to include only ESP_WiFiManager.h
1.10.0 K Hoang 10/02/2022 Add support to new ESP32-S3
1.10.1 K Hoang 11/02/2022 Add LittleFS support to ESP32-C3. Use core LittleFS instead of Lorol's LITTLEFS for v2.0.0+
1.10.2 K Hoang 13/03/2022 Send CORS header in handleWifiSave() function
1.11.0 K Hoang 09/09/2022 Fix ESP32 chipID and add ESP_getChipOUI()
*****************************************************************************************************************************/ *****************************************************************************************************************************/
#pragma once #pragma once

View File

@ -71,8 +71,6 @@
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
#if 1
#define TZ_Africa_Abidjan ("GMT0") #define TZ_Africa_Abidjan ("GMT0")
#define TZ_Africa_Accra ("GMT0") #define TZ_Africa_Accra ("GMT0")
#define TZ_Africa_Addis_Ababa ("EAT-3") #define TZ_Africa_Addis_Ababa ("EAT-3")
@ -534,479 +532,11 @@
#define TZ_Etc_Universal ("UTC0") #define TZ_Etc_Universal ("UTC0")
#define TZ_Etc_Zulu ("UTC0") #define TZ_Etc_Zulu ("UTC0")
#else
#define TZ_Africa_Abidjan PSTR("GMT0")
#define TZ_Africa_Accra PSTR("GMT0")
#define TZ_Africa_Addis_Ababa PSTR("EAT-3")
#define TZ_Africa_Algiers PSTR("CET-1")
#define TZ_Africa_Asmara PSTR("EAT-3")
#define TZ_Africa_Bamako PSTR("GMT0")
#define TZ_Africa_Bangui PSTR("WAT-1")
#define TZ_Africa_Banjul PSTR("GMT0")
#define TZ_Africa_Bissau PSTR("GMT0")
#define TZ_Africa_Blantyre PSTR("CAT-2")
#define TZ_Africa_Brazzaville PSTR("WAT-1")
#define TZ_Africa_Bujumbura PSTR("CAT-2")
#define TZ_Africa_Cairo PSTR("EET-2")
#define TZ_Africa_Casablanca PSTR("<+01>-1")
#define TZ_Africa_Ceuta PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Africa_Conakry PSTR("GMT0")
#define TZ_Africa_Dakar PSTR("GMT0")
#define TZ_Africa_Dar_es_Salaam PSTR("EAT-3")
#define TZ_Africa_Djibouti PSTR("EAT-3")
#define TZ_Africa_Douala PSTR("WAT-1")
#define TZ_Africa_El_Aaiun PSTR("<+01>-1")
#define TZ_Africa_Freetown PSTR("GMT0")
#define TZ_Africa_Gaborone PSTR("CAT-2")
#define TZ_Africa_Harare PSTR("CAT-2")
#define TZ_Africa_Johannesburg PSTR("SAST-2")
#define TZ_Africa_Juba PSTR("EAT-3")
#define TZ_Africa_Kampala PSTR("EAT-3")
#define TZ_Africa_Khartoum PSTR("CAT-2")
#define TZ_Africa_Kigali PSTR("CAT-2")
#define TZ_Africa_Kinshasa PSTR("WAT-1")
#define TZ_Africa_Lagos PSTR("WAT-1")
#define TZ_Africa_Libreville PSTR("WAT-1")
#define TZ_Africa_Lome PSTR("GMT0")
#define TZ_Africa_Luanda PSTR("WAT-1")
#define TZ_Africa_Lubumbashi PSTR("CAT-2")
#define TZ_Africa_Lusaka PSTR("CAT-2")
#define TZ_Africa_Malabo PSTR("WAT-1")
#define TZ_Africa_Maputo PSTR("CAT-2")
#define TZ_Africa_Maseru PSTR("SAST-2")
#define TZ_Africa_Mbabane PSTR("SAST-2")
#define TZ_Africa_Mogadishu PSTR("EAT-3")
#define TZ_Africa_Monrovia PSTR("GMT0")
#define TZ_Africa_Nairobi PSTR("EAT-3")
#define TZ_Africa_Ndjamena PSTR("WAT-1")
#define TZ_Africa_Niamey PSTR("WAT-1")
#define TZ_Africa_Nouakchott PSTR("GMT0")
#define TZ_Africa_Ouagadougou PSTR("GMT0")
#define TZ_Africa_PortomNovo PSTR("WAT-1")
#define TZ_Africa_Sao_Tome PSTR("GMT0")
#define TZ_Africa_Tripoli PSTR("EET-2")
#define TZ_Africa_Tunis PSTR("CET-1")
#define TZ_Africa_Windhoek PSTR("CAT-2")
#define TZ_America_Adak PSTR("HST10HDT,M3.2.0,M11.1.0")
#define TZ_America_Anchorage PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Anguilla PSTR("AST4")
#define TZ_America_Antigua PSTR("AST4")
#define TZ_America_Araguaina PSTR("<-03>3")
#define TZ_America_Argentina_Buenos_Aires PSTR("<-03>3")
#define TZ_America_Argentina_Catamarca PSTR("<-03>3")
#define TZ_America_Argentina_Cordoba PSTR("<-03>3")
#define TZ_America_Argentina_Jujuy PSTR("<-03>3")
#define TZ_America_Argentina_La_Rioja PSTR("<-03>3")
#define TZ_America_Argentina_Mendoza PSTR("<-03>3")
#define TZ_America_Argentina_Rio_Gallegos PSTR("<-03>3")
#define TZ_America_Argentina_Salta PSTR("<-03>3")
#define TZ_America_Argentina_San_Juan PSTR("<-03>3")
#define TZ_America_Argentina_San_Luis PSTR("<-03>3")
#define TZ_America_Argentina_Tucuman PSTR("<-03>3")
#define TZ_America_Argentina_Ushuaia PSTR("<-03>3")
#define TZ_America_Aruba PSTR("AST4")
#define TZ_America_Asuncion PSTR("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
#define TZ_America_Atikokan PSTR("EST5")
#define TZ_America_Bahia PSTR("<-03>3")
#define TZ_America_Bahia_Banderas PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Barbados PSTR("AST4")
#define TZ_America_Belem PSTR("<-03>3")
#define TZ_America_Belize PSTR("CST6")
#define TZ_America_BlancmSablon PSTR("AST4")
#define TZ_America_Boa_Vista PSTR("<-04>4")
#define TZ_America_Bogota PSTR("<-05>5")
#define TZ_America_Boise PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Cambridge_Bay PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Campo_Grande PSTR("<-04>4")
#define TZ_America_Cancun PSTR("EST5")
#define TZ_America_Caracas PSTR("<-04>4")
#define TZ_America_Cayenne PSTR("<-03>3")
#define TZ_America_Cayman PSTR("EST5")
#define TZ_America_Chicago PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Chihuahua PSTR("MST7MDT,M4.1.0,M10.5.0")
#define TZ_America_Costa_Rica PSTR("CST6")
#define TZ_America_Creston PSTR("MST7")
#define TZ_America_Cuiaba PSTR("<-04>4")
#define TZ_America_Curacao PSTR("AST4")
#define TZ_America_Danmarkshavn PSTR("GMT0")
#define TZ_America_Dawson PSTR("MST7")
#define TZ_America_Dawson_Creek PSTR("MST7")
#define TZ_America_Denver PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Detroit PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Dominica PSTR("AST4")
#define TZ_America_Edmonton PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Eirunepe PSTR("<-05>5")
#define TZ_America_El_Salvador PSTR("CST6")
#define TZ_America_Fortaleza PSTR("<-03>3")
#define TZ_America_Fort_Nelson PSTR("MST7")
#define TZ_America_Glace_Bay PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Godthab PSTR("<-03>3<-02>,M3.5.0/-2,M10.5.0/-1")
#define TZ_America_Goose_Bay PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Grand_Turk PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Grenada PSTR("AST4")
#define TZ_America_Guadeloupe PSTR("AST4")
#define TZ_America_Guatemala PSTR("CST6")
#define TZ_America_Guayaquil PSTR("<-05>5")
#define TZ_America_Guyana PSTR("<-04>4")
#define TZ_America_Halifax PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Havana PSTR("CST5CDT,M3.2.0/0,M11.1.0/1")
#define TZ_America_Hermosillo PSTR("MST7")
#define TZ_America_Indiana_Indianapolis PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Knox PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Marengo PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Petersburg PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Tell_City PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Vevay PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Vincennes PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Indiana_Winamac PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Inuvik PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Iqaluit PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Jamaica PSTR("EST5")
#define TZ_America_Juneau PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Kentucky_Louisville PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Kentucky_Monticello PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Kralendijk PSTR("AST4")
#define TZ_America_La_Paz PSTR("<-04>4")
#define TZ_America_Lima PSTR("<-05>5")
#define TZ_America_Los_Angeles PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Lower_Princes PSTR("AST4")
#define TZ_America_Maceio PSTR("<-03>3")
#define TZ_America_Managua PSTR("CST6")
#define TZ_America_Manaus PSTR("<-04>4")
#define TZ_America_Marigot PSTR("AST4")
#define TZ_America_Martinique PSTR("AST4")
#define TZ_America_Matamoros PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Mazatlan PSTR("MST7MDT,M4.1.0,M10.5.0")
#define TZ_America_Menominee PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Merida PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Metlakatla PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Mexico_City PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Miquelon PSTR("<-03>3<-02>,M3.2.0,M11.1.0")
#define TZ_America_Moncton PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Monterrey PSTR("CST6CDT,M4.1.0,M10.5.0")
#define TZ_America_Montevideo PSTR("<-03>3")
#define TZ_America_Montreal PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Montserrat PSTR("AST4")
#define TZ_America_Nassau PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_New_York PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Nipigon PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Nome PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Noronha PSTR("<-02>2")
#define TZ_America_North_Dakota_Beulah PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_North_Dakota_Center PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_North_Dakota_New_Salem PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Ojinaga PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_America_Panama PSTR("EST5")
#define TZ_America_Pangnirtung PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Paramaribo PSTR("<-03>3")
#define TZ_America_Phoenix PSTR("MST7")
#define TZ_America_PortmaumPrince PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Port_of_Spain PSTR("AST4")
#define TZ_America_Porto_Velho PSTR("<-04>4")
#define TZ_America_Puerto_Rico PSTR("AST4")
#define TZ_America_Punta_Arenas PSTR("<-03>3")
#define TZ_America_Rainy_River PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Rankin_Inlet PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Recife PSTR("<-03>3")
#define TZ_America_Regina PSTR("CST6")
#define TZ_America_Resolute PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Rio_Branco PSTR("<-05>5")
#define TZ_America_Santarem PSTR("<-03>3")
#define TZ_America_Santiago PSTR("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
#define TZ_America_Santo_Domingo PSTR("AST4")
#define TZ_America_Sao_Paulo PSTR("<-03>3")
#define TZ_America_Scoresbysund PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
#define TZ_America_Sitka PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_St_Barthelemy PSTR("AST4")
#define TZ_America_St_Johns PSTR("NST3:30NDT,M3.2.0,M11.1.0")
#define TZ_America_St_Kitts PSTR("AST4")
#define TZ_America_St_Lucia PSTR("AST4")
#define TZ_America_St_Thomas PSTR("AST4")
#define TZ_America_St_Vincent PSTR("AST4")
#define TZ_America_Swift_Current PSTR("CST6")
#define TZ_America_Tegucigalpa PSTR("CST6")
#define TZ_America_Thule PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_America_Thunder_Bay PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Tijuana PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Toronto PSTR("EST5EDT,M3.2.0,M11.1.0")
#define TZ_America_Tortola PSTR("AST4")
#define TZ_America_Vancouver PSTR("PST8PDT,M3.2.0,M11.1.0")
#define TZ_America_Whitehorse PSTR("MST7")
#define TZ_America_Winnipeg PSTR("CST6CDT,M3.2.0,M11.1.0")
#define TZ_America_Yakutat PSTR("AKST9AKDT,M3.2.0,M11.1.0")
#define TZ_America_Yellowknife PSTR("MST7MDT,M3.2.0,M11.1.0")
#define TZ_Antarctica_Casey PSTR("<+11>-11")
#define TZ_Antarctica_Davis PSTR("<+07>-7")
#define TZ_Antarctica_DumontDUrville PSTR("<+10>-10")
#define TZ_Antarctica_Macquarie PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Antarctica_Mawson PSTR("<+05>-5")
#define TZ_Antarctica_McMurdo PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3")
#define TZ_Antarctica_Palmer PSTR("<-03>3")
#define TZ_Antarctica_Rothera PSTR("<-03>3")
#define TZ_Antarctica_Syowa PSTR("<+03>-3")
#define TZ_Antarctica_Troll PSTR("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
#define TZ_Antarctica_Vostok PSTR("<+06>-6")
#define TZ_Arctic_Longyearbyen PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Asia_Aden PSTR("<+03>-3")
#define TZ_Asia_Almaty PSTR("<+06>-6")
#define TZ_Asia_Amman PSTR("EET-2EEST,M3.5.4/24,M10.5.5/1")
#define TZ_Asia_Anadyr PSTR("<+12>-12")
#define TZ_Asia_Aqtau PSTR("<+05>-5")
#define TZ_Asia_Aqtobe PSTR("<+05>-5")
#define TZ_Asia_Ashgabat PSTR("<+05>-5")
#define TZ_Asia_Atyrau PSTR("<+05>-5")
#define TZ_Asia_Baghdad PSTR("<+03>-3")
#define TZ_Asia_Bahrain PSTR("<+03>-3")
#define TZ_Asia_Baku PSTR("<+04>-4")
#define TZ_Asia_Bangkok PSTR("<+07>-7")
#define TZ_Asia_Barnaul PSTR("<+07>-7")
#define TZ_Asia_Beirut PSTR("EET-2EEST,M3.5.0/0,M10.5.0/0")
#define TZ_Asia_Bishkek PSTR("<+06>-6")
#define TZ_Asia_Brunei PSTR("<+08>-8")
#define TZ_Asia_Chita PSTR("<+09>-9")
#define TZ_Asia_Choibalsan PSTR("<+08>-8")
#define TZ_Asia_Colombo PSTR("<+0530>-5:30")
#define TZ_Asia_Damascus PSTR("EET-2EEST,M3.5.5/0,M10.5.5/0")
#define TZ_Asia_Dhaka PSTR("<+06>-6")
#define TZ_Asia_Dili PSTR("<+09>-9")
#define TZ_Asia_Dubai PSTR("<+04>-4")
#define TZ_Asia_Dushanbe PSTR("<+05>-5")
#define TZ_Asia_Famagusta PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Asia_Gaza PSTR("EET-2EEST,M3.4.4/48,M10.4.4/49")
#define TZ_Asia_Hebron PSTR("EET-2EEST,M3.4.4/48,M10.4.4/49")
#define TZ_Asia_Ho_Chi_Minh PSTR("<+07>-7")
#define TZ_Asia_Hong_Kong PSTR("HKT-8")
#define TZ_Asia_Hovd PSTR("<+07>-7")
#define TZ_Asia_Irkutsk PSTR("<+08>-8")
#define TZ_Asia_Jakarta PSTR("WIB-7")
#define TZ_Asia_Jayapura PSTR("WIT-9")
#define TZ_Asia_Jerusalem PSTR("IST-2IDT,M3.4.4/26,M10.5.0")
#define TZ_Asia_Kabul PSTR("<+0430>-4:30")
#define TZ_Asia_Kamchatka PSTR("<+12>-12")
#define TZ_Asia_Karachi PSTR("PKT-5")
#define TZ_Asia_Kathmandu PSTR("<+0545>-5:45")
#define TZ_Asia_Khandyga PSTR("<+09>-9")
#define TZ_Asia_Kolkata PSTR("IST-5:30")
#define TZ_Asia_Krasnoyarsk PSTR("<+07>-7")
#define TZ_Asia_Kuala_Lumpur PSTR("<+08>-8")
#define TZ_Asia_Kuching PSTR("<+08>-8")
#define TZ_Asia_Kuwait PSTR("<+03>-3")
#define TZ_Asia_Macau PSTR("CST-8")
#define TZ_Asia_Magadan PSTR("<+11>-11")
#define TZ_Asia_Makassar PSTR("WITA-8")
#define TZ_Asia_Manila PSTR("PST-8")
#define TZ_Asia_Muscat PSTR("<+04>-4")
#define TZ_Asia_Nicosia PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Asia_Novokuznetsk PSTR("<+07>-7")
#define TZ_Asia_Novosibirsk PSTR("<+07>-7")
#define TZ_Asia_Omsk PSTR("<+06>-6")
#define TZ_Asia_Oral PSTR("<+05>-5")
#define TZ_Asia_Phnom_Penh PSTR("<+07>-7")
#define TZ_Asia_Pontianak PSTR("WIB-7")
#define TZ_Asia_Pyongyang PSTR("KST-9")
#define TZ_Asia_Qatar PSTR("<+03>-3")
#define TZ_Asia_Qyzylorda PSTR("<+05>-5")
#define TZ_Asia_Riyadh PSTR("<+03>-3")
#define TZ_Asia_Sakhalin PSTR("<+11>-11")
#define TZ_Asia_Samarkand PSTR("<+05>-5")
#define TZ_Asia_Seoul PSTR("KST-9")
#define TZ_Asia_Shanghai PSTR("CST-8")
#define TZ_Asia_Singapore PSTR("<+08>-8")
#define TZ_Asia_Srednekolymsk PSTR("<+11>-11")
#define TZ_Asia_Taipei PSTR("CST-8")
#define TZ_Asia_Tashkent PSTR("<+05>-5")
#define TZ_Asia_Tbilisi PSTR("<+04>-4")
#define TZ_Asia_Tehran PSTR("<+0330>-3:30<+0430>,J79/24,J263/24")
#define TZ_Asia_Thimphu PSTR("<+06>-6")
#define TZ_Asia_Tokyo PSTR("JST-9")
#define TZ_Asia_Tomsk PSTR("<+07>-7")
#define TZ_Asia_Ulaanbaatar PSTR("<+08>-8")
#define TZ_Asia_Urumqi PSTR("<+06>-6")
#define TZ_Asia_UstmNera PSTR("<+10>-10")
#define TZ_Asia_Vientiane PSTR("<+07>-7")
#define TZ_Asia_Vladivostok PSTR("<+10>-10")
#define TZ_Asia_Yakutsk PSTR("<+09>-9")
#define TZ_Asia_Yangon PSTR("<+0630>-6:30")
#define TZ_Asia_Yekaterinburg PSTR("<+05>-5")
#define TZ_Asia_Yerevan PSTR("<+04>-4")
#define TZ_Atlantic_Azores PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
#define TZ_Atlantic_Bermuda PSTR("AST4ADT,M3.2.0,M11.1.0")
#define TZ_Atlantic_Canary PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Atlantic_Cape_Verde PSTR("<-01>1")
#define TZ_Atlantic_Faroe PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Atlantic_Madeira PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Atlantic_Reykjavik PSTR("GMT0")
#define TZ_Atlantic_South_Georgia PSTR("<-02>2")
#define TZ_Atlantic_Stanley PSTR("<-03>3")
#define TZ_Atlantic_St_Helena PSTR("GMT0")
#define TZ_Australia_Adelaide PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Brisbane PSTR("AEST-10")
#define TZ_Australia_Broken_Hill PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Currie PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Darwin PSTR("ACST-9:30")
#define TZ_Australia_Eucla PSTR("<+0845>-8:45")
#define TZ_Australia_Hobart PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Lindeman PSTR("AEST-10")
#define TZ_Australia_Lord_Howe PSTR("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
#define TZ_Australia_Melbourne PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Australia_Perth PSTR("AWST-8")
#define TZ_Australia_Sydney PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
#define TZ_Europe_Amsterdam PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Andorra PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Astrakhan PSTR("<+04>-4")
#define TZ_Europe_Athens PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Belgrade PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Berlin PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Bratislava PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Brussels PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Bucharest PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Budapest PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Busingen PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Chisinau PSTR("EET-2EEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Copenhagen PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Dublin PSTR("IST-1GMT0,M10.5.0,M3.5.0/1")
#define TZ_Europe_Gibraltar PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Guernsey PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Helsinki PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Isle_of_Man PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Istanbul PSTR("<+03>-3")
#define TZ_Europe_Jersey PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Kaliningrad PSTR("EET-2")
#define TZ_Europe_Kiev PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Kirov PSTR("<+03>-3")
#define TZ_Europe_Lisbon PSTR("WET0WEST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Ljubljana PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_London PSTR("GMT0BST,M3.5.0/1,M10.5.0")
#define TZ_Europe_Luxembourg PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Madrid PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Malta PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Mariehamn PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Minsk PSTR("<+03>-3")
#define TZ_Europe_Monaco PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Moscow PSTR("MSK-3")
#define TZ_Europe_Oslo PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Paris PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Podgorica PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Prague PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Riga PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Rome PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Samara PSTR("<+04>-4")
#define TZ_Europe_San_Marino PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Sarajevo PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Saratov PSTR("<+04>-4")
#define TZ_Europe_Simferopol PSTR("MSK-3")
#define TZ_Europe_Skopje PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Sofia PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Stockholm PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Tallinn PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Tirane PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Ulyanovsk PSTR("<+04>-4")
#define TZ_Europe_Uzhgorod PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Vaduz PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Vatican PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Vienna PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Vilnius PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Volgograd PSTR("<+04>-4")
#define TZ_Europe_Warsaw PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Zagreb PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Europe_Zaporozhye PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
#define TZ_Europe_Zurich PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
#define TZ_Indian_Antananarivo PSTR("EAT-3")
#define TZ_Indian_Chagos PSTR("<+06>-6")
#define TZ_Indian_Christmas PSTR("<+07>-7")
#define TZ_Indian_Cocos PSTR("<+0630>-6:30")
#define TZ_Indian_Comoro PSTR("EAT-3")
#define TZ_Indian_Kerguelen PSTR("<+05>-5")
#define TZ_Indian_Mahe PSTR("<+04>-4")
#define TZ_Indian_Maldives PSTR("<+05>-5")
#define TZ_Indian_Mauritius PSTR("<+04>-4")
#define TZ_Indian_Mayotte PSTR("EAT-3")
#define TZ_Indian_Reunion PSTR("<+04>-4")
#define TZ_Pacific_Apia PSTR("<+13>-13<+14>,M9.5.0/3,M4.1.0/4")
#define TZ_Pacific_Auckland PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3")
#define TZ_Pacific_Bougainville PSTR("<+11>-11")
#define TZ_Pacific_Chatham PSTR("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
#define TZ_Pacific_Chuuk PSTR("<+10>-10")
#define TZ_Pacific_Easter PSTR("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
#define TZ_Pacific_Efate PSTR("<+11>-11")
#define TZ_Pacific_Enderbury PSTR("<+13>-13")
#define TZ_Pacific_Fakaofo PSTR("<+13>-13")
#define TZ_Pacific_Fiji PSTR("<+12>-12<+13>,M11.2.0,M1.2.3/99")
#define TZ_Pacific_Funafuti PSTR("<+12>-12")
#define TZ_Pacific_Galapagos PSTR("<-06>6")
#define TZ_Pacific_Gambier PSTR("<-09>9")
#define TZ_Pacific_Guadalcanal PSTR("<+11>-11")
#define TZ_Pacific_Guam PSTR("ChST-10")
#define TZ_Pacific_Honolulu PSTR("HST10")
#define TZ_Pacific_Kiritimati PSTR("<+14>-14")
#define TZ_Pacific_Kosrae PSTR("<+11>-11")
#define TZ_Pacific_Kwajalein PSTR("<+12>-12")
#define TZ_Pacific_Majuro PSTR("<+12>-12")
#define TZ_Pacific_Marquesas PSTR("<-0930>9:30")
#define TZ_Pacific_Midway PSTR("SST11")
#define TZ_Pacific_Nauru PSTR("<+12>-12")
#define TZ_Pacific_Niue PSTR("<-11>11")
#define TZ_Pacific_Norfolk PSTR("<+11>-11<+12>,M10.1.0,M4.1.0/3")
#define TZ_Pacific_Noumea PSTR("<+11>-11")
#define TZ_Pacific_Pago_Pago PSTR("SST11")
#define TZ_Pacific_Palau PSTR("<+09>-9")
#define TZ_Pacific_Pitcairn PSTR("<-08>8")
#define TZ_Pacific_Pohnpei PSTR("<+11>-11")
#define TZ_Pacific_Port_Moresby PSTR("<+10>-10")
#define TZ_Pacific_Rarotonga PSTR("<-10>10")
#define TZ_Pacific_Saipan PSTR("ChST-10")
#define TZ_Pacific_Tahiti PSTR("<-10>10")
#define TZ_Pacific_Tarawa PSTR("<+12>-12")
#define TZ_Pacific_Tongatapu PSTR("<+13>-13")
#define TZ_Pacific_Wake PSTR("<+12>-12")
#define TZ_Pacific_Wallis PSTR("<+12>-12")
#define TZ_Etc_GMT PSTR("GMT0")
#define TZ_Etc_GMTm0 PSTR("GMT0")
#define TZ_Etc_GMTm1 PSTR("<+01>-1")
#define TZ_Etc_GMTm2 PSTR("<+02>-2")
#define TZ_Etc_GMTm3 PSTR("<+03>-3")
#define TZ_Etc_GMTm4 PSTR("<+04>-4")
#define TZ_Etc_GMTm5 PSTR("<+05>-5")
#define TZ_Etc_GMTm6 PSTR("<+06>-6")
#define TZ_Etc_GMTm7 PSTR("<+07>-7")
#define TZ_Etc_GMTm8 PSTR("<+08>-8")
#define TZ_Etc_GMTm9 PSTR("<+09>-9")
#define TZ_Etc_GMTm10 PSTR("<+10>-10")
#define TZ_Etc_GMTm11 PSTR("<+11>-11")
#define TZ_Etc_GMTm12 PSTR("<+12>-12")
#define TZ_Etc_GMTm13 PSTR("<+13>-13")
#define TZ_Etc_GMTm14 PSTR("<+14>-14")
#define TZ_Etc_GMT0 PSTR("GMT0")
#define TZ_Etc_GMTp0 PSTR("GMT0")
#define TZ_Etc_GMTp1 PSTR("<-01>1")
#define TZ_Etc_GMTp2 PSTR("<-02>2")
#define TZ_Etc_GMTp3 PSTR("<-03>3")
#define TZ_Etc_GMTp4 PSTR("<-04>4")
#define TZ_Etc_GMTp5 PSTR("<-05>5")
#define TZ_Etc_GMTp6 PSTR("<-06>6")
#define TZ_Etc_GMTp7 PSTR("<-07>7")
#define TZ_Etc_GMTp8 PSTR("<-08>8")
#define TZ_Etc_GMTp9 PSTR("<-09>9")
#define TZ_Etc_GMTp10 PSTR("<-10>10")
#define TZ_Etc_GMTp11 PSTR("<-11>11")
#define TZ_Etc_GMTp12 PSTR("<-12>12")
#define TZ_Etc_UCT PSTR("UTC0")
#define TZ_Etc_UTC PSTR("UTC0")
#define TZ_Etc_Greenwich PSTR("GMT0")
#define TZ_Etc_Universal PSTR("UTC0")
#define TZ_Etc_Zulu PSTR("UTC0")
#endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#define TIMEZONE_MAX_LEN 50 #define TIMEZONE_MAX_LEN 50
#if 1 static const char TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
const char TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
{ {
#if USING_AFRICA #if USING_AFRICA
"Africa/Abidjan", //PSTR("GMT0") "Africa/Abidjan", //PSTR("GMT0")
@ -1503,7 +1033,7 @@ const char TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const char ESP_TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ = static const char ESP_TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
{ {
#if USING_AFRICA #if USING_AFRICA
TZ_Africa_Abidjan, //PSTR("GMT0") TZ_Africa_Abidjan, //PSTR("GMT0")
@ -1999,152 +1529,4 @@ const char ESP_TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
#endif #endif
}; };
#else
const char TZ_NAME[][TIMEZONE_MAX_LEN] =
{
"Pacific/Pago_Pago",
"America/Adak",
"Pacific/Honolulu",
"Pacific/Marquesas",
"Pacific/Gambier",
"America/Anchorage",
"America/Los_Angeles",
"Pacific/Pitcairn",
"America/Phoenix",
"America/Denver",
"America/Guatemala",
"America/Chicago",
"Pacific/Easter",
"America/Bogota",
"America/New_York",
"America/Caracas",
"America/Halifax",
"America/Santo_Domingo",
"America/Santiago",
"America/St_Johns",
"America/Godthab",
"America/Argentina/Buenos_Aires",
"America/Montevideo",
"Etc/GMT+2",
"Atlantic/Azores",
"Atlantic/Cape_Verde",
"Etc/UTC",
"Europe/London",
"Europe/Berlin",
"Africa/Lagos",
"Africa/Windhoek",
"Asia/Beirut",
"Africa/Johannesburg",
"Asia/Baghdad",
"Europe/Moscow",
"Asia/Tehran",
"Asia/Dubai",
"Asia/Baku",
"Asia/Kabul",
"Asia/Yekaterinburg",
"Asia/Karachi",
"Asia/Kolkata",
"Asia/Kathmandu",
"Asia/Dhaka",
"Asia/Omsk",
"Asia/Krasnoyarsk",
"Asia/Jakarta",
"Asia/Shanghai",
"Asia/Irkutsk",
"Australia/Eucla",
"Asia/Yakutsk",
"Asia/Tokyo",
"Australia/Darwin",
"Australia/Adelaide",
"Australia/Brisbane",
"Asia/Vladivostok",
"Australia/Sydney",
"Australia/Lord_Howe",
"Asia/Kamchatka",
"Pacific/Noumea",
"Pacific/Norfolk",
"Pacific/Auckland",
"Pacific/Tarawa",
"Pacific/Chatham",
"Pacific/Tongatapu",
"Pacific/Apia",
"Pacific/Kiritimati",
};
////////////////////////////////////////////////////////////
const char ESP_TZ_NAME[][TIMEZONE_MAX_LEN] =
{
TZ_Pacific_Pago_Pago, //PSTR("SST11")
TZ_America_Adak, //PSTR("HST10HDT,M3.2.0,M11.1.0")
TZ_Pacific_Honolulu, //PSTR("HST10")
TZ_Pacific_Marquesas, //PSTR("<-0930>9:30")
TZ_Pacific_Gambier, //PSTR("<-09>9")
TZ_America_Anchorage, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
TZ_America_Los_Angeles, //"PST8PDT,M3.2.0,M11.1.0", //"America/Los_Angeles",
TZ_Pacific_Pitcairn, //PSTR("<-08>8")
TZ_America_Phoenix, //PSTR("MST7")
TZ_America_Denver, //"MST7MDT,M3.2.0,M11.1.0", //"America/Denver",
TZ_America_Guatemala, //PSTR("CST6")
TZ_America_Chicago, //"CST6CDT,M3.2.0,M11.1.0", //"America/Chicago",
TZ_Pacific_Easter, //PSTR("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
TZ_America_Bogota, //PSTR("<-05>5")
TZ_America_New_York, //"EST5EDT,M3.2.0,M11.1.0", //"America/New_York",
TZ_America_Caracas, //PSTR("<-04>4")
TZ_America_Halifax, //"AST4ADT,M3.2.0,M11.1.0", //"America/Halifax",
TZ_America_Santo_Domingo, //PSTR("AST4")
TZ_America_Santiago, //"<-04>4<-03>,M9.1.6/24,M4.1.6/24", //"America/Santiago",
TZ_America_St_Johns, //PSTR("NST3:30NDT,M3.2.0,M11.1.0")
TZ_America_Godthab, //"<-03>3<-02>,M3.5.0/-2,M10.5.0/-1", //"America/Godthab",
TZ_America_Argentina_Buenos_Aires, //PSTR("<-03>3")
TZ_America_Montevideo, //"<-03>3", //"America/Montevideo",
TZ_Etc_GMTp2, //PSTR("<-02>2")
TZ_Atlantic_Azores, //PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
TZ_Atlantic_Cape_Verde, //PSTR("<-01>1")
TZ_Etc_UTC, //PSTR("UTC0")
TZ_Europe_London, //PSTR("GMT0BST,M3.5.0/1,M10.5.0")
TZ_Europe_Berlin, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
TZ_Africa_Lagos, //PSTR("WAT-1")
TZ_Africa_Windhoek, //PSTR("CAT-2")
TZ_Asia_Beirut, //"EET-2EEST,M3.5.0/0,M10.5.0/0" //"Asia/Beirut",
TZ_Africa_Johannesburg, //"SAST-2", //"Africa/Johannesburg",
TZ_Asia_Baghdad, //"<+03>-3", //"Asia/Baghdad",
TZ_Europe_Moscow, //PSTR("MSK-3")
TZ_Asia_Tehran, //PSTR("<+0330>-3:30<+0430>,J79/24,J263/24")
TZ_Asia_Dubai, //"<+04>-4", //"Asia/Dubai",
TZ_Asia_Baku, //PSTR("<+04>-4")
TZ_Asia_Kabul, //PSTR("<+0430>-4:30")
TZ_Asia_Yekaterinburg, //PSTR("<+05>-5")
TZ_Asia_Karachi, //PSTR("PKT-5")
TZ_Asia_Kolkata, //PSTR("IST-5:30")
TZ_Asia_Kathmandu, //PSTR("<+0545>-5:45")
TZ_Asia_Dhaka, //"<+06>-6", //"Asia/Dhaka",
TZ_Asia_Omsk, //PSTR("<+06>-6")
TZ_Asia_Krasnoyarsk, //PSTR("<+07>-7")
TZ_Asia_Jakarta, //"WIB-7", //"Asia/Jakarta",
TZ_Asia_Shanghai, //"CST-8", //"Asia/Shanghai",
TZ_Asia_Irkutsk, //PSTR("<+08>-8")
TZ_Australia_Eucla, //PSTR("<+0845>-8:45")
TZ_Asia_Yakutsk, //PSTR("<+09>-9")
TZ_Asia_Tokyo, //"JST-9", //"Asia/Tokyo",
TZ_Australia_Darwin, //PSTR("ACST-9:30")
TZ_Australia_Adelaide, //PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
TZ_Australia_Brisbane, //"AEST-10", //"Australia/Brisbane",
TZ_Asia_Vladivostok, //PSTR("<+10>-10")
TZ_Australia_Sydney, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
TZ_Australia_Lord_Howe, //PSTR("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
TZ_Asia_Kamchatka, //PSTR("<+12>-12")
TZ_Pacific_Noumea, //"<+11>-11", //"Pacific/Noumea",
TZ_Pacific_Norfolk, //PSTR("<+11>-11<+12>,M10.1.0,M4.1.0/3")
TZ_Pacific_Auckland, //"NZST-12NZDT,M9.5.0,M4.1.0/3", //"Pacific/Auckland",
TZ_Pacific_Tarawa, //"<+12>-12", //"Pacific/Tarawa",
TZ_Pacific_Chatham, //PSTR("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
TZ_Pacific_Tongatapu, //PSTR("<+13>-13")
TZ_Pacific_Apia, //PSTR("<+13>-13<+14>,M9.5.0/3,M4.1.0/4")
TZ_Pacific_Kiritimati, //PSTR("<+14>-14")
};
#endif
#endif // TZDB_H #endif // TZDB_H

View File

@ -234,9 +234,7 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8
useWire->beginTransmission(devAddr); useWire->beginTransmission(devAddr);
useWire->send(regAddr); useWire->send(regAddr);
useWire->endTransmission(); useWire->endTransmission();
useWire->beginTransmission(devAddr);
useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH));
for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = useWire->receive(); data[count] = useWire->receive();
#ifdef I2CDEV_SERIAL_DEBUG #ifdef I2CDEV_SERIAL_DEBUG
@ -244,8 +242,6 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8
if (count + 1 < length) Serial.print(" "); if (count + 1 < length) Serial.print(" ");
#endif #endif
} }
useWire->endTransmission();
} }
#elif (ARDUINO == 100) #elif (ARDUINO == 100)
// Arduino v1.0.0, Wire library // Arduino v1.0.0, Wire library
@ -258,9 +254,7 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8
useWire->beginTransmission(devAddr); useWire->beginTransmission(devAddr);
useWire->write(regAddr); useWire->write(regAddr);
useWire->endTransmission(); useWire->endTransmission();
useWire->beginTransmission(devAddr);
useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH));
for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = useWire->read(); data[count] = useWire->read();
#ifdef I2CDEV_SERIAL_DEBUG #ifdef I2CDEV_SERIAL_DEBUG
@ -268,8 +262,6 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8
if (count + 1 < length) Serial.print(" "); if (count + 1 < length) Serial.print(" ");
#endif #endif
} }
useWire->endTransmission();
} }
#elif (ARDUINO > 100) #elif (ARDUINO > 100)
// Arduino v1.0.1+, Wire library // Arduino v1.0.1+, Wire library
@ -282,10 +274,7 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8
useWire->beginTransmission(devAddr); useWire->beginTransmission(devAddr);
useWire->write(regAddr); useWire->write(regAddr);
useWire->endTransmission(); useWire->endTransmission();
// See: https://github.com/espressif/arduino-esp32/issues/6674
// useWire->beginTransmission(devAddr);
useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH));
for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = useWire->read(); data[count] = useWire->read();
#ifdef I2CDEV_SERIAL_DEBUG #ifdef I2CDEV_SERIAL_DEBUG
@ -357,7 +346,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1
useWire->beginTransmission(devAddr); useWire->beginTransmission(devAddr);
useWire->send(regAddr); useWire->send(regAddr);
useWire->endTransmission(); useWire->endTransmission();
useWire->beginTransmission(devAddr);
useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
bool msb = true; // starts with MSB, then LSB bool msb = true; // starts with MSB, then LSB
@ -376,8 +364,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1
} }
msb = !msb; msb = !msb;
} }
useWire->endTransmission();
} }
#elif (ARDUINO == 100) #elif (ARDUINO == 100)
// Arduino v1.0.0, Wire library // Arduino v1.0.0, Wire library
@ -390,7 +376,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1
useWire->beginTransmission(devAddr); useWire->beginTransmission(devAddr);
useWire->write(regAddr); useWire->write(regAddr);
useWire->endTransmission(); useWire->endTransmission();
useWire->beginTransmission(devAddr);
useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
bool msb = true; // starts with MSB, then LSB bool msb = true; // starts with MSB, then LSB
@ -409,8 +394,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1
} }
msb = !msb; msb = !msb;
} }
useWire->endTransmission();
} }
#elif (ARDUINO > 100) #elif (ARDUINO > 100)
// Arduino v1.0.1+, Wire library // Arduino v1.0.1+, Wire library
@ -423,7 +406,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1
useWire->beginTransmission(devAddr); useWire->beginTransmission(devAddr);
useWire->write(regAddr); useWire->write(regAddr);
useWire->endTransmission(); useWire->endTransmission();
useWire->beginTransmission(devAddr);
useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
bool msb = true; // starts with MSB, then LSB bool msb = true; // starts with MSB, then LSB
@ -442,8 +424,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1
} }
msb = !msb; msb = !msb;
} }
useWire->endTransmission();
} }
#endif #endif
@ -1486,4 +1466,4 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT;
return rxBufferLength - rxBufferIndex; return rxBufferLength - rxBufferIndex;
} }
#endif #endif

View File

@ -308,4 +308,4 @@ class I2Cdev {
#endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE #endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
#endif /* _I2CDEV_H_ */ #endif /* _I2CDEV_H_ */

View File

@ -16,172 +16,232 @@ include_dir = lib
upload_speed = 921600 upload_speed = 921600
monitor_speed = 115200 monitor_speed = 115200
platform = espressif8266 @ 4.0.1 platform = espressif8266 @ 4.0.1
platform32 = espressif32 @ 5.2.0
framework = arduino framework = arduino
board = d1_mini board = d1_mini
build_unflags = build_unflags =
build_flags = build_flags =
-D BAUD=${common_env_data.monitor_speed} -Wl,-Map,output.map
-D ACTIVATE_OTA -DBAUD=${common_env_data.monitor_speed}
#-D DEBUG_ESP_HTTP_CLIENT
#-D DEBUG_ESP_HTTP_SERVER
#-D DEBUG_ESP_PORT=Serial
#-D DEBUG_ESP_WIFI
#-D DEBUG_ESP_SSL
#-D DEBUG_ESP_CORE
#-D SKIP_SLEEPMODE #-D SKIP_SLEEPMODE
-D USE_LITTLEFS=true #-D FORCE_GRAVITY_MODE
-D EMBED_HTML # If this is not used the html files needs to be on the file system (can be uploaded) #-D DOUBLERESETDETECTOR_DEBUG=true
-D USER_SSID=\""\"" # =\""myssid\"" -DACTIVATE_OTA
-D USER_SSID_PWD=\""\"" # =\""mypwd\"" -DCFG_DISABLE_LOGGING # Turn off verbose/notice logging to reduce size and dont overload uart (applies to LOG_LEVEL6)
-D CFG_APPVER="\"1.1.0\"" -DGYRO_DISABLE_LOGGING
-D CFG_GITREV=\""beta-2\"" -DCALC_DISABLE_LOGGING
-DHELPER_DISABLE_LOGGING
-DPUSH_DISABLE_LOGGING
-DTSEN_DISABLE_LOGGING
-DWIFI_DISABLE_LOGGING
-DWEB_DISABLE_LOGGING
-DMAIN_DISABLE_LOGGING
-DUSE_LITTLEFS=true
-DUSER_SSID=\""\"" # =\""myssid\""
-DUSER_SSID_PWD=\""\"" # =\""mypwd\""
-DCFG_APPVER="\"1.2.0\""
-DCFG_GITREV=\""beta-1\""
#!python script/git_rev.py #!python script/git_rev.py
lib_deps = # Switched to forks for better version control. lib_deps =
# Using local copy of these libraries # Using local copy of these libraries
#https://github.com/mp-se/i2cdevlib.git#<document> # https://github.com/mp-se/i2cdevlib.git#<document>
#https://github.com/mp-se/OneWire # Using this version; https://github.com/arendst/Tasmota/tree/development/lib/lib_basic/OneWire-Stickbreaker # https://github.com/mp-se/OneWire
#https://github.com/mp-se/Arduino-Temperature-Control-Library # https://github.com/mp-se/Arduino-Temperature-Control-Library
#https://github.com/khoih-prog/ESP_WiFiManager # https://github.com/khoih-prog/ESP_WiFiManager
#https://github.com/khoih-prog/ESP_DoubleResetDetector # https://github.com/khoih-prog/ESP_DoubleResetDetector
https://github.com/mp-se/tinyexpr # https://github.com/codeplea/tinyexpr https://github.com/mp-se/tinyexpr # https://github.com/codeplea/tinyexpr
https://github.com/mp-se/incbin # https://github.com/graphitemaster/incbin https://github.com/mp-se/Arduino-Log#1.1.1 # https://github.com/thijse/Arduino-Log
https://github.com/mp-se/Arduino-Log#1.1.1 # https://github.com/thijse/Arduino-Log https://github.com/mp-se/ArduinoJson#v6.18.5 # https://github.com/bblanchon/ArduinoJson
https://github.com/mp-se/ArduinoJson#v6.18.5 # https://github.com/bblanchon/ArduinoJson https://github.com/mp-se/arduinoCurveFitting#v1.0.6 # https://github.com/Rotario/arduinoCurveFitting
https://github.com/mp-se/arduinoCurveFitting#v1.0.6 # https://github.com/Rotario/arduinoCurveFitting https://github.com/mp-se/arduino-mqtt#v2.5.0 # https://github.com/256dpi/arduino-mqtt
https://github.com/mp-se/arduino-mqtt#v2.5.0 # https://github.com/256dpi/arduino-mqtt lib_deps32 =
https://github.com/mp-se/NimBLE-Arduino#1.3.8 # https://github.com/h2zero/NimBLE-Arduino
[env:gravity-debug]
upload_speed = ${common_env_data.upload_speed}
monitor_speed = ${common_env_data.monitor_speed}
framework = ${common_env_data.framework}
platform = ${common_env_data.platform}
extra_scripts = extra_scripts =
script/copy_html.py
script/copy_firmware.py script/copy_firmware.py
script/create_versionjson.py script/create_versionjson.py
build_unflags =
${common_env_data.build_unflags} ; [env:gravity-debug]
build_flags = ; upload_speed = ${common_env_data.upload_speed}
-Wl,-Map,output.map ; monitor_speed = ${common_env_data.monitor_speed}
${common_env_data.build_flags} ; framework = ${common_env_data.framework}
#-D PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS ; platform = ${common_env_data.platform}
#-D SKIP_SLEEPMODE ; extra_scripts = ${common_env_data.extra_scripts}
#-D DOUBLERESETDETECTOR_DEBUG=true ; build_unflags = ${common_env_data.build_unflags}
#-D FORCE_GRAVITY_MODE # used to debug gravity mode ; build_flags =
-D COLLECT_PERFDATA # This option will collect runtime data for a few defined methods to measure time, dumped to serial and/or influxdb ; ${common_env_data.build_flags}
-D LOG_LEVEL=6 # Maximum log level for the debug build. ; #-D DEBUG_ESP_HTTP_CLIENT
-D CFG_DISABLE_LOGGING # Turn off verbose/notice logging to reduce size and dont overload uart. ; #-D DEBUG_ESP_HTTP_SERVER
-D GYRO_DISABLE_LOGGING ; #-D DEBUG_ESP_PORT=Serial
-D CALC_DISABLE_LOGGING ; #-D DEBUG_ESP_WIFI
-D HELPER_DISABLE_LOGGING ; #-D DEBUG_ESP_SSL
-D PUSH_DISABLE_LOGGING ; #-D DEBUG_ESP_CORE
-D TSEN_DISABLE_LOGGING ; -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
-D WIFI_DISABLE_LOGGING ; -DCOLLECT_PERFDATA # Collect runtime data for a few defined methods to measure time, dumped to serial and/or influxdb
-D WEB_DISABLE_LOGGING ; -DLOG_LEVEL=6
-D MAIN_DISABLE_LOGGING ; lib_deps =
lib_deps = ; https://github.com/mp-se/incbin # https://github.com/graphitemaster/incbin
${common_env_data.lib_deps} ; ${common_env_data.lib_deps}
board = ${common_env_data.board} ; board = ${common_env_data.board}
#build_type = debug ; build_type = release
build_type = release ; board_build.filesystem = littlefs
board_build.filesystem = littlefs ; monitor_filters = esp8266_exception_decoder
monitor_filters = esp8266_exception_decoder
[env:gravity-release] [env:gravity-release]
upload_speed = ${common_env_data.upload_speed} upload_speed = ${common_env_data.upload_speed}
monitor_speed = ${common_env_data.monitor_speed} monitor_speed = ${common_env_data.monitor_speed}
framework = ${common_env_data.framework} framework = ${common_env_data.framework}
platform = ${common_env_data.platform} platform = ${common_env_data.platform}
extra_scripts = extra_scripts = ${common_env_data.extra_scripts}
script/copy_html.py
script/copy_firmware.py
script/create_versionjson.py
build_unflags = ${common_env_data.build_unflags} build_unflags = ${common_env_data.build_unflags}
build_flags = build_flags =
${common_env_data.build_flags} ${common_env_data.build_flags}
-D LOG_LEVEL=4 -D LOG_LEVEL=4
lib_deps = lib_deps =
${common_env_data.lib_deps} https://github.com/mp-se/incbin # https://github.com/graphitemaster/incbin
board = ${common_env_data.board}
build_type = release
board_build.filesystem = littlefs
[env:gravity-perf]
upload_speed = ${common_env_data.upload_speed}
monitor_speed = ${common_env_data.monitor_speed}
framework = ${common_env_data.framework}
platform = ${common_env_data.platform}
extra_scripts =
script/copy_html.py
script/copy_firmware.py
script/create_versionjson.py
build_unflags = ${common_env_data.build_unflags}
build_flags =
${common_env_data.build_flags}
-D COLLECT_PERFDATA
-D LOG_LEVEL=5
lib_deps =
${common_env_data.lib_deps} ${common_env_data.lib_deps}
board = ${common_env_data.board} board = ${common_env_data.board}
build_type = release build_type = release
board_build.filesystem = littlefs board_build.filesystem = littlefs
[env:gravity32-release] [env:gravity32-release]
framework = arduino framework = ${common_env_data.framework}
platform = espressif32 @ 5.0.0 platform = ${common_env_data.platform32}
upload_speed = ${common_env_data.upload_speed} upload_speed = ${common_env_data.upload_speed}
monitor_speed = ${common_env_data.monitor_speed} monitor_speed = ${common_env_data.monitor_speed}
extra_scripts = extra_scripts = ${common_env_data.extra_scripts}
script/copy_html.py
script/copy_firmware.py
script/create_versionjson.py
build_unflags = build_unflags =
${common_env_data.build_unflags} ${common_env_data.build_unflags}
build_flags = build_flags =
-Wl,-Map,output.map -Wl,-Map,output.map
#-DCORE_DEBUG_LEVEL=0
${common_env_data.build_flags} ${common_env_data.build_flags}
#-D COLLECT_PERFDATA
-D LOG_LEVEL=5 -D LOG_LEVEL=5
-D CFG_DISABLE_LOGGING # Turn off verbose/notice logging to reduce size and dont overload uart (applies to LOG_LEVEL6)
-D GYRO_DISABLE_LOGGING
-D CALC_DISABLE_LOGGING
-D HELPER_DISABLE_LOGGING
-D PUSH_DISABLE_LOGGING
-D TSEN_DISABLE_LOGGING
-D WIFI_DISABLE_LOGGING
-D WEB_DISABLE_LOGGING
-D MAIN_DISABLE_LOGGING
lib_deps = lib_deps =
${common_env_data.lib_deps} ${common_env_data.lib_deps}
https://github.com/mp-se/NimBLE-Arduino#1.3.8 # https://github.com/h2zero/NimBLE-Arduino ${common_env_data.lib_deps32}
lib_ignore = lib_ignore =
board = featheresp32 board = wemos_d1_mini32
build_type = release build_type = release
board_build.partitions = part32.csv board_build.partitions = part32.csv
board_build.filesystem = littlefs board_build.filesystem = littlefs
monitor_filters = esp32_exception_decoder board_build.embed_txtfiles =
html/calibration.min.htm
html/config.min.htm
html/firmware.min.htm
html/format.min.htm
html/about.min.htm
html/index.min.htm
html/test.min.htm
[env:gravity32-perf] [env:gravity32c3-release]
framework = arduino framework = ${common_env_data.framework}
platform = espressif32 @ 5.0.0 platform = ${common_env_data.platform32}
upload_speed = ${common_env_data.upload_speed} upload_speed = ${common_env_data.upload_speed}
monitor_speed = ${common_env_data.monitor_speed} monitor_speed = ${common_env_data.monitor_speed}
extra_scripts = extra_scripts = ${common_env_data.extra_scripts}
script/copy_html.py
script/copy_firmware.py
script/create_versionjson.py
build_unflags = build_unflags =
${common_env_data.build_unflags} ${common_env_data.build_unflags}
build_flags = build_flags =
-Wl,-Map,output.map -Wl,-Map,output.map
${common_env_data.build_flags} ${common_env_data.build_flags}
-D COLLECT_PERFDATA -DLOG_LEVEL=5
-D LOG_LEVEL=5 -DCORE_DEBUG_LEVEL=0
-DESP32C3
-DARDUINO_ESP32C3_DEV
-DUSE_SERIAL0
lib_deps = lib_deps =
${common_env_data.lib_deps} ${common_env_data.lib_deps}
https://github.com/mp-se/NimBLE-Arduino#1.3.8 # https://github.com/h2zero/NimBLE-Arduino ${common_env_data.lib_deps32}
board = featheresp32 lib_ignore =
board = lolin_c3_mini
build_type = release build_type = release
board_build.partitions = part32.csv board_build.partitions = part32.csv
board_build.filesystem = littlefs board_build.filesystem = littlefs
monitor_filters = esp32_exception_decoder board_build.embed_txtfiles =
html/calibration.min.htm
html/config.min.htm
html/firmware.min.htm
html/format.min.htm
html/about.min.htm
html/index.min.htm
html/test.min.htm
[env:gravity32c3-debug]
framework = ${common_env_data.framework}
platform = ${common_env_data.platform32}
upload_speed = ${common_env_data.upload_speed}
monitor_speed = ${common_env_data.monitor_speed}
monitor_filters = time, colorize, log2file, esp32_exception_decoder
extra_scripts = ${common_env_data.extra_scripts}
upload_port = COM8
debug_tool = esp-prog
debug_init_break = break setup
build_unflags =
-DCFG_DISABLE_LOGGING
-DGYRO_DISABLE_LOGGING
-DCALC_DISABLE_LOGGING
-DHELPER_DISABLE_LOGGING
-DPUSH_DISABLE_LOGGING
-DTSEN_DISABLE_LOGGING
-DWIFI_DISABLE_LOGGING
-DWEB_DISABLE_LOGGING
-DMAIN_DISABLE_LOGGING
${common_env_data.build_unflags}
build_flags =
-Wl,-Map,output.map
${common_env_data.build_flags}
-DLOG_LEVEL=6
-DCORE_DEBUG_LEVEL=5
-DJTAG_DEBUG
-DESP32C3
-DUSE_SERIAL0
-DARDUINO_ESP32C3_DEV
-DCOLLECT_PERFDATA # Collect runtime data for a few defined methods to measure time, dumped to serial and/or influxdb
lib_deps =
${common_env_data.lib_deps}
${common_env_data.lib_deps32}
lib_ignore =
board = esp32-c3-devkitm-1
build_type = debug
board_build.partitions = part32.csv
board_build.filesystem = littlefs
board_build.embed_txtfiles =
html/calibration.min.htm
html/config.min.htm
html/firmware.min.htm
html/format.min.htm
html/about.min.htm
html/index.min.htm
html/test.min.htm
; [env:gravity32s2-release]
; framework = ${common_env_data.framework}
; platform = ${common_env_data.platform32}
; upload_speed = ${common_env_data.upload_speed}
; monitor_speed = ${common_env_data.monitor_speed}
; extra_scripts = ${common_env_data.extra_scripts}
; build_unflags =
; ${common_env_data.build_unflags}
; build_flags =
; -Wl,-Map,output.map
; ${common_env_data.build_flags}
; -DLOG_LEVEL=5
; -DCORE_DEBUG_LEVEL=0
; -DESP32S2
; -DARDUINO_ESP32S2_DEV
; lib_deps =
; ${common_env_data.lib_deps}
; ${common_env_data.lib_deps32}
; lib_ignore =
; board = lolin_s2_mini
; build_type = debug
; board_build.partitions = part32.csv
; board_build.filesystem = littlefs
; board_build.embed_txtfiles =
; html/calibration.min.htm
; html/config.min.htm
; html/firmware.min.htm
; html/format.min.htm
; html/about.min.htm
; html/index.min.htm
; html/test.min.htm

View File

@ -23,12 +23,6 @@ def after_build(source, target, env):
print( "Copy file : " + source + " -> " + target ) print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target ) shutil.copyfile( source, target )
if name == "gravity-perf" :
target = dir + "/bin/firmware-perf.bin"
source = dir + "/.pio/build/" + name + "/firmware.bin"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
if name == "gravity32-release" : if name == "gravity32-release" :
target = dir + "/bin/firmware32.bin" target = dir + "/bin/firmware32.bin"
source = dir + "/.pio/build/" + name + "/firmware.bin" source = dir + "/.pio/build/" + name + "/firmware.bin"
@ -40,18 +34,28 @@ def after_build(source, target, env):
print( "Copy file : " + source + " -> " + target ) print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target ) shutil.copyfile( source, target )
if name == "gravity32-perf" : if name == "gravity32c3-release" :
target = dir + "/bin/firmware32-perf.bin" target = dir + "/bin/firmware32c3.bin"
source = dir + "/.pio/build/" + name + "/firmware.bin" source = dir + "/.pio/build/" + name + "/firmware.bin"
print( "Copy file : " + source + " -> " + target ) print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target ) shutil.copyfile( source, target )
if name == "gravity32-release2" : target = dir + "/bin/partitions32c3.bin"
target = dir + "/bin/firmware32_2.bin" source = dir + "/.pio/build/" + name + "/partitions.bin"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
if name == "gravity32s2-release" :
target = dir + "/bin/firmware32s2.bin"
source = dir + "/.pio/build/" + name + "/firmware.bin" source = dir + "/.pio/build/" + name + "/firmware.bin"
print( "Copy file : " + source + " -> " + target ) print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target ) shutil.copyfile( source, target )
target = dir + "/bin/partitions32s2.bin"
source = dir + "/.pio/build/" + name + "/partitions.bin"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
print( "Adding custom build step (copy firmware): ") print( "Adding custom build step (copy firmware): ")
env.AddPostAction("buildprog", after_build) env.AddPostAction("buildprog", after_build)

View File

@ -1,34 +0,0 @@
Import("env")
import shutil, os
print( "Executing custom step " )
dir = env.GetLaunchDir()
source = dir + "/html/"
target = dir + "/data/"
print( "Copy html-files from " + source + " -> " + target )
os.makedirs(os.path.dirname( target ), exist_ok=True)
file = "about.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "calibration.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "config.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "index.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "upload.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "format.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "test.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )
file = "firmware.min.htm"
#print( "Copy file: " + source + file + "->" + target + file)
shutil.copyfile( source + file, target + file )

View File

@ -12,42 +12,6 @@ def after_build(source, target, env):
dir = env.GetLaunchDir() dir = env.GetLaunchDir()
#name = env.get( "PIOENV" ) #name = env.get( "PIOENV" )
# Copy file 1
source = dir + "/data/index.min.htm"
target = dir + "/bin/index.min.htm"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
# Copy file 2
source = dir + "/data/config.min.htm"
target = dir + "/bin/config.min.htm"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
# Copy file 3
source = dir + "/data/about.min.htm"
target = dir + "/bin/about.min.htm"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
# Copy file 4
source = dir + "/data/calibration.min.htm"
target = dir + "/bin/calibration.min.htm"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
# Copy file 5
source = dir + "/data/format.min.htm"
target = dir + "/bin/format.min.htm"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
# Copy file 6
source = dir + "/data/test.min.htm"
target = dir + "/bin/test.min.htm"
print( "Copy file : " + source + " -> " + target )
shutil.copyfile( source, target )
target = dir + "/bin/version.json" target = dir + "/bin/version.json"
ver = get_build_flag_value("CFG_APPVER") ver = get_build_flag_value("CFG_APPVER")

View File

@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#if defined(ESP32) #if defined(ESP32) && !defined(ESP32S2)
#include <ble.hpp> #include <ble.hpp>
#include <string> #include <string>
@ -99,4 +99,4 @@ void BleSender::sendData(float tempF, float gravSG) {
delay(100); delay(100);
} }
#endif // ESP32 #endif // ESP32 && !ESP32S2

View File

@ -24,14 +24,12 @@ SOFTWARE.
#ifndef SRC_BLE_HPP_ #ifndef SRC_BLE_HPP_
#define SRC_BLE_HPP_ #define SRC_BLE_HPP_
#if defined(ESP32) #if defined(ESP32) && !defined(ESP32S2)
#include <Arduino.h>
#include <NimBLEBeacon.h> #include <NimBLEBeacon.h>
#include <NimBLEDevice.h> #include <NimBLEDevice.h>
#include <config.hpp>
#include <main.hpp>
class BleSender { class BleSender {
private: private:
BLEAdvertising* _advertising; BLEAdvertising* _advertising;
@ -43,5 +41,5 @@ class BleSender {
void sendData(float tempF, float gravSG); void sendData(float tempF, float gravSG);
}; };
#endif // ESP32 #endif // ESP32 && !ESP32S2
#endif // SRC_BLE_HPP_ #endif // SRC_BLE_HPP_

View File

@ -52,8 +52,7 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
#endif #endif
if (noAngles < 3) { if (noAngles < 3) {
ErrorFileLog errLog; writeErrorLog("CALC: Not enough values for deriving formula");
errLog.addEntry(F("CALC: Not enough values for deriving formula"));
return ERR_FORMULA_NOTENOUGHVALUES; return ERR_FORMULA_NOTENOUGHVALUES;
} else { } else {
double coeffs[order + 1]; double coeffs[order + 1];
@ -98,13 +97,10 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
// If the deviation is more than 2 degress we mark it as failed. // If the deviation is more than 2 degress we mark it as failed.
if (dev * 1000 > myAdvancedConfig.getMaxFormulaCreationDeviation()) { if (dev * 1000 > myAdvancedConfig.getMaxFormulaCreationDeviation()) {
char s[120]; writeErrorLog(
snprintf(&s[0], sizeof(s), "CALC: Validation failed on angle %.2f, deviation too large %.4f "
"CALC: Validation failed on angle %f, deviation too large " "SG, formula order %d",
"%.2f SG, formula order %d", fd.a[i], dev * 1000, order);
fd.a[i], dev * 1000, order);
ErrorFileLog errLog;
errLog.addEntry(&s[0]);
valid = false; valid = false;
} }
} }
@ -118,8 +114,7 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
} }
} }
ErrorFileLog errLog; writeErrorLog("CALC: Internal error finding formula.");
errLog.addEntry(F("CALC: Internal error finding formula."));
return ERR_FORMULA_INTERNAL; return ERR_FORMULA_INTERNAL;
} }
@ -164,8 +159,7 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
return g; return g;
} }
ErrorFileLog errLog; writeErrorLog("CALC: Failed to parse gravity expression %d", err);
errLog.addEntry("CALC: Failed to parse gravity expression " + String(err));
return 0; return 0;
} }
@ -211,10 +205,9 @@ double gravityTemperatureCorrectionC(double gravitySG, double tempC,
return g; return g;
} }
ErrorFileLog errLog; writeErrorLog(
errLog.addEntry( "CALC: Failed to parse expression for gravity temperature correction %d",
"CALC: Failed to parse expression for gravity temperature correction " + err);
String(err));
return gravitySG; return gravitySG;
} }

View File

@ -145,8 +145,7 @@ bool Config::saveFile() {
File configFile = LittleFS.open(CFG_FILENAME, "w"); File configFile = LittleFS.open(CFG_FILENAME, "w");
if (!configFile) { if (!configFile) {
ErrorFileLog errLog; writeErrorLog("CFG : Failed to save configuration.");
errLog.addEntry(F("CFG : Failed to save configuration."));
return false; return false;
} }
@ -154,8 +153,8 @@ bool Config::saveFile() {
createJson(doc); createJson(doc);
#if LOG_LEVEL == 6 && !defined(DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
serializeJson(doc, configFile); serializeJson(doc, configFile);
@ -176,16 +175,14 @@ bool Config::loadFile() {
#endif #endif
if (!LittleFS.exists(CFG_FILENAME)) { if (!LittleFS.exists(CFG_FILENAME)) {
ErrorFileLog errLog; writeErrorLog("CFG : Configuration file does not exist.");
errLog.addEntry(F("CFG : Configuration file does not exist."));
return false; return false;
} }
File configFile = LittleFS.open(CFG_FILENAME, "r"); File configFile = LittleFS.open(CFG_FILENAME, "r");
if (!configFile) { if (!configFile) {
ErrorFileLog errLog; writeErrorLog("CFG : Failed to load configuration.");
errLog.addEntry(F("CFG : Failed to load configuration."));
return false; return false;
} }
@ -195,14 +192,13 @@ bool Config::loadFile() {
DynamicJsonDocument doc(3000); DynamicJsonDocument doc(3000);
DeserializationError err = deserializeJson(doc, configFile); DeserializationError err = deserializeJson(doc, configFile);
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
configFile.close(); configFile.close();
if (err) { if (err) {
ErrorFileLog errLog; writeErrorLog("CFG : Failed to parse configuration (json)");
errLog.addEntry(F("CFG : Failed to parse configuration (json)"));
return false; return false;
} }
@ -377,8 +373,7 @@ bool AdvancedConfig::saveFile() {
File configFile = LittleFS.open(CFG_HW_FILENAME, "w"); File configFile = LittleFS.open(CFG_HW_FILENAME, "w");
if (!configFile) { if (!configFile) {
ErrorFileLog errLog; writeErrorLog("CFG : Failed to write hardware configuration ");
errLog.addEntry(F("CFG : Failed to write hardware configuration "));
return false; return false;
} }
@ -400,8 +395,8 @@ bool AdvancedConfig::saveFile() {
doc[PARAM_HW_IGNORE_LOW_ANGLES] = this->isIgnoreLowAnges(); doc[PARAM_HW_IGNORE_LOW_ANGLES] = this->isIgnoreLowAnges();
#if LOG_LEVEL == 6 && !defined(DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
serializeJson(doc, configFile); serializeJson(doc, configFile);
@ -429,8 +424,7 @@ bool AdvancedConfig::loadFile() {
File configFile = LittleFS.open(CFG_HW_FILENAME, "r"); File configFile = LittleFS.open(CFG_HW_FILENAME, "r");
if (!configFile) { if (!configFile) {
ErrorFileLog errLog; writeErrorLog("CFG : Failed to read hardware configuration");
errLog.addEntry(F("CFG : Failed to read hardware configuration "));
return false; return false;
} }
@ -440,14 +434,13 @@ bool AdvancedConfig::loadFile() {
DynamicJsonDocument doc(512); DynamicJsonDocument doc(512);
DeserializationError err = deserializeJson(doc, configFile); DeserializationError err = deserializeJson(doc, configFile);
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
configFile.close(); configFile.close();
if (err) { if (err) {
ErrorFileLog errLog; writeErrorLog("CFG : Failed to parse hardware configuration (json)");
errLog.addEntry(F("CFG : Failed to parse hardware configuration (json)"));
return false; return false;
} }

View File

@ -143,7 +143,15 @@ class Config {
String _mDNS = ""; String _mDNS = "";
String _otaURL = ""; String _otaURL = "";
char _tempFormat = 'C'; char _tempFormat = 'C';
#if defined(ESP8266)
float _voltageFactor = 1.59; float _voltageFactor = 1.59;
#elif defined(ESP32C3)
float _voltageFactor = 1.3;
#elif defined(ESP32S2)
float _voltageFactor = 1.3;
#else // ESP32
float _voltageFactor = 1.3;
#endif
float _voltageConfig = 4.15; float _voltageConfig = 4.15;
float _tempSensorAdjC = 0; float _tempSensorAdjC = 0;
int _sleepInterval = 900; int _sleepInterval = 900;

View File

@ -46,8 +46,7 @@ bool GyroSensor::setup() {
uint8_t id = accelgyro.getDeviceID(); uint8_t id = accelgyro.getDeviceID();
if (id != 0x34 && id != 0x38) { // Allow both MPU6050 and MPU6000 if (id != 0x34 && id != 0x38) { // Allow both MPU6050 and MPU6000
ErrorFileLog errLog; writeErrorLog("GYRO: Failed to connect to gyro, is it connected?");
errLog.addEntry(F("GYRO: Failed to connect to gyro, is it connected?"));
_sensorConnected = false; _sensorConnected = false;
} else { } else {
#if !defined(GYRO_DISABLE_LOGGING) #if !defined(GYRO_DISABLE_LOGGING)
@ -294,9 +293,8 @@ void GyroSensor::applyCalibration() {
if ((_calibrationOffset.ax + _calibrationOffset.ay + _calibrationOffset.az + if ((_calibrationOffset.ax + _calibrationOffset.ay + _calibrationOffset.az +
_calibrationOffset.gx + _calibrationOffset.gy + _calibrationOffset.gz) == _calibrationOffset.gx + _calibrationOffset.gy + _calibrationOffset.gz) ==
0) { 0) {
ErrorFileLog errLog; writeErrorLog(
errLog.addEntry( "GYRO: No valid calibration values, please calibrate the device.");
F("GYRO: No valid calibration values, please calibrate the device."));
return; return;
} }
@ -316,14 +314,14 @@ void GyroSensor::calibrateSensor() {
Log.verbose(F("GYRO: Calibrating sensor" CR)); Log.verbose(F("GYRO: Calibrating sensor" CR));
#endif #endif
// accelgyro.PrintActiveOffsets(); // accelgyro.PrintActiveOffsets();
// Serial.print( CR ); // EspSerial.print( CR );
accelgyro.setDLPFMode(MPU6050_DLPF_BW_5); accelgyro.setDLPFMode(MPU6050_DLPF_BW_5);
accelgyro.CalibrateAccel(6); // 6 = 600 readings accelgyro.CalibrateAccel(6); // 6 = 600 readings
accelgyro.CalibrateGyro(6); accelgyro.CalibrateGyro(6);
accelgyro.PrintActiveOffsets(); accelgyro.PrintActiveOffsets();
Serial.print(CR); EspSerial.print(CR);
_calibrationOffset.ax = accelgyro.getXAccelOffset(); _calibrationOffset.ax = accelgyro.getXAccelOffset();
_calibrationOffset.ay = accelgyro.getYAccelOffset(); _calibrationOffset.ay = accelgyro.getYAccelOffset();

View File

@ -36,9 +36,6 @@ SOFTWARE.
#include <tempsensor.hpp> #include <tempsensor.hpp>
#include <wifi.hpp> #include <wifi.hpp>
SerialDebug mySerial;
BatteryVoltage myBatteryVoltage;
// tcp cleanup, to avoid memory crash. // tcp cleanup, to avoid memory crash.
struct tcp_pcb; struct tcp_pcb;
extern struct tcp_pcb* tcp_tw_pcbs; extern struct tcp_pcb* tcp_tw_pcbs;
@ -47,75 +44,128 @@ void tcp_cleanup() {
while (tcp_tw_pcbs) tcp_abort(tcp_tw_pcbs); while (tcp_tw_pcbs) tcp_abort(tcp_tw_pcbs);
} }
// void checkResetReason() {
// Convert sg to plato #if defined(ESP8266)
// rst_info* _rinfo;
_rinfo = ESP.getResetInfoPtr();
Log.notice(F("HELP: Last reset cause %d" CR), _rinfo->exccause);
if (_rinfo->exccause > 0) {
char s[120];
snprintf(&s[0], sizeof(s),
"HELP: Exception (%d) reason=%d epc1=0x%08x epc2=0x%08x "
"epc3=0x%08x execvaddr=0x%08x depc=0x%08x",
_rinfo->exccause, _rinfo->reason, _rinfo->epc1, _rinfo->epc2,
_rinfo->epc3, _rinfo->excvaddr, _rinfo->depc);
writeErrorLog(&s[0]);
}
#else // defined (ESP32)
RESET_REASON r = rtc_get_reset_reason(
0); // We only check cpu0 since we dont use cpu1 on the esp32
String rStr;
switch (r) {
case 0:
rStr = F("None");
break;
case 1:
rStr = F("vbat power on reset");
break;
case 3:
rStr = F("software reset digital core");
break;
case 4:
rStr = F("legacy watch dog reset digital core");
break;
case 5:
rStr = F("deep Sleep reset digital core");
break;
case 6:
rStr = F("reset by SLC module, reset digital core");
break;
case 7:
rStr = F("timer Group0 Watch dog reset digital core");
break;
case 8:
rStr = F("timer Group1 Watch dog reset digital core");
break;
case 9:
rStr = F("RTC Watch dog Reset digital core");
break;
case 10:
rStr = F("instrusion tested to reset CPU");
break;
case 11:
rStr = F("time Group reset CPU");
break;
case 12:
rStr = F("software reset CPU");
break;
case 13:
rStr = F("RTC Watch dog Reset CPU");
break;
case 14:
rStr = F("for APP CPU, reseted by PRO CPU");
break;
case 15:
rStr = F("reset when the vdd voltage is not stable");
break;
case 16:
rStr = F("RTC Watch dog reset digital core and rtc module");
break;
default:
rStr = F("unknown reset reason");
break;
}
Log.notice(F("HELP: Last reset cause '%s' (%d)" CR), rStr.c_str(), r);
#warning "TODO: Implement logging of crashes for esp32"
#endif
}
void writeErrorLog(const char* format, ...) {
File f = LittleFS.open(ERR_FILENAME, "a");
if (f && f.size() > ERR_FILEMAXSIZE) {
f.close();
LittleFS.remove(ERR_FILENAME2);
LittleFS.rename(ERR_FILENAME, ERR_FILENAME2);
f = LittleFS.open(ERR_FILENAME, "a");
}
va_list arg;
va_start(arg, format);
char buf[120];
vsnprintf(&buf[0], sizeof(buf), format, arg);
va_end(arg);
Log.errorln(&buf[0]);
if (f) {
#if defined(ESP8266)
f.write(&buf[0], strlen(&buf[0]));
#else // ESP32
f.write((unsigned char*)&buf[0], strlen(&buf[0]));
#endif
f.println();
f.close();
} else {
Log.warning(F("HELP: Failed to open error log." CR));
}
}
double convertToPlato(double sg) { double convertToPlato(double sg) {
if (sg) return 259 - (259 / sg); if (sg) return 259 - (259 / sg);
return 0; return 0;
} }
//
// Convert plato to sg
//
double convertToSG(double plato) { return 259 / (259 - plato); } double convertToSG(double plato) { return 259 / (259 - plato); }
//
// Conversion to F
//
float convertCtoF(float c) { return (c * 1.8) + 32.0; } float convertCtoF(float c) { return (c * 1.8) + 32.0; }
//
// Conversion to C
//
float convertFtoC(float f) { return (f - 32.0) / 1.8; } float convertFtoC(float f) { return (f - 32.0) / 1.8; }
//
// Load error log from disk
//
ErrorFileLog::ErrorFileLog() {
File errFile = LittleFS.open(ERR_FILENAME, "r");
int i = 0;
if (errFile) {
do {
_errors[i] = errFile.readStringUntil('\n');
_errors[i].replace("\r", "");
_errors[i].replace("\n", "");
} while (_errors[i++].length());
errFile.close();
}
}
//
// Add new entry to top of error log
//
void ErrorFileLog::addEntry(String err) {
for (int i = (ERR_COUNT - 1); i > 0; i--) {
_errors[i] = _errors[i - 1];
}
_errors[0] = err;
err += String(CR);
Log.error(err.c_str());
save();
}
//
// Save error log
//
void ErrorFileLog::save() {
File errFile = LittleFS.open(ERR_FILENAME, "w");
if (errFile) {
for (int i = 0; i < ERR_COUNT; i++) {
errFile.println(_errors[i]);
}
errFile.close();
}
}
//
// Load history log of floats
//
FloatHistoryLog::FloatHistoryLog(String fName) { FloatHistoryLog::FloatHistoryLog(String fName) {
_fName = fName; _fName = fName;
@ -133,9 +183,6 @@ FloatHistoryLog::FloatHistoryLog(String fName) {
} }
} }
//
// Add entry to top of log
//
void FloatHistoryLog::addEntry(float time) { void FloatHistoryLog::addEntry(float time) {
for (int i = (10 - 1); i > 0; i--) { for (int i = (10 - 1); i > 0; i--) {
_runTime[i] = _runTime[i - 1]; _runTime[i] = _runTime[i - 1];
@ -144,9 +191,6 @@ void FloatHistoryLog::addEntry(float time) {
save(); save();
} }
//
// Save log
//
void FloatHistoryLog::save() { void FloatHistoryLog::save() {
File runFile = LittleFS.open(_fName, "w"); File runFile = LittleFS.open(_fName, "w");
if (runFile) { if (runFile) {
@ -157,9 +201,6 @@ void FloatHistoryLog::save() {
} }
} }
//
// Print the heap information.
//
void printHeap(String prefix) { void printHeap(String prefix) {
#if defined(ESP8266) #if defined(ESP8266)
Log.notice( Log.notice(
@ -175,9 +216,6 @@ void printHeap(String prefix) {
#endif #endif
} }
//
// Enter deep sleep for the defined duration (Argument is seconds)
//
void deepSleep(int t) { void deepSleep(int t) {
#if LOG_LEVEL == 6 && !defined(HELPER_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(HELPER_DISABLE_LOGGING)
Log.verbose(F("HELP: Entering sleep mode for %ds." CR), t); Log.verbose(F("HELP: Entering sleep mode for %ds." CR), t);
@ -186,9 +224,6 @@ void deepSleep(int t) {
ESP.deepSleep(wake); ESP.deepSleep(wake);
} }
//
// Print the build options used
//
void printBuildOptions() { void printBuildOptions() {
Log.notice(F("Build options: %s (%s) LOGLEVEL %d " Log.notice(F("Build options: %s (%s) LOGLEVEL %d "
#ifdef SKIP_SLEEPMODE #ifdef SKIP_SLEEPMODE
@ -201,31 +236,29 @@ void printBuildOptions() {
CFG_APPVER, CFG_GITREV, LOG_LEVEL); CFG_APPVER, CFG_GITREV, LOG_LEVEL);
} }
//
// Configure serial debug output
//
SerialDebug::SerialDebug(const uint32_t serialSpeed) { SerialDebug::SerialDebug(const uint32_t serialSpeed) {
// Start serial with auto-detected rate (default to defined BAUD) // Start serial with auto-detected rate (default to defined BAUD)
Serial.flush(); EspSerial.begin(serialSpeed);
Serial.begin(serialSpeed); EspSerial.println("Serial connection established");
getLog()->begin(LOG_LEVEL, &EspSerial, true);
getLog()->begin(LOG_LEVEL, &Serial, true);
getLog()->setPrefix(printTimestamp); getLog()->setPrefix(printTimestamp);
getLog()->notice(F("SDBG: Serial logging started at %u." CR), serialSpeed); getLog()->notice(F("SDBG: Serial logging started at %u." CR), serialSpeed);
} }
//
// Print the timestamp (ms since start of device)
//
void printTimestamp(Print* _logOutput, int _logLevel) { void printTimestamp(Print* _logOutput, int _logLevel) {
char c[12]; char c[12];
snprintf(c, sizeof(c), "%10lu ", millis()); snprintf(c, sizeof(c), "%10lu ", millis());
_logOutput->print(c); _logOutput->print(c);
} }
// BatteryVoltage::BatteryVoltage() {
// Read and calculate the battery voltage #if defined(ESP8266)
// pinMode(PIN_A0, INPUT);
#else
pinMode(PIN_A0, INPUT_PULLDOWN);
#endif
}
void BatteryVoltage::read() { void BatteryVoltage::read() {
// The analog pin can only handle 3.3V maximum voltage so we need to reduce // The analog pin can only handle 3.3V maximum voltage so we need to reduce
// the voltage (from max 5V) // the voltage (from max 5V)
@ -251,9 +284,6 @@ void BatteryVoltage::read() {
PerfLogging myPerfLogging; PerfLogging myPerfLogging;
//
// Clear the current cache
//
void PerfLogging::clear() { void PerfLogging::clear() {
// Clear the measurements // Clear the measurements
if (first == 0) return; if (first == 0) return;
@ -270,17 +300,11 @@ void PerfLogging::clear() {
} while (pe != 0); } while (pe != 0);
} }
//
// Start measuring this performance point
//
void PerfLogging::start(const char* key) { void PerfLogging::start(const char* key) {
PerfEntry* pe = add(key); PerfEntry* pe = add(key);
pe->start = millis(); pe->start = millis();
} }
//
// Finalize measuring of this performance point
//
void PerfLogging::stop(const char* key) { void PerfLogging::stop(const char* key) {
PerfEntry* pe = find(key); PerfEntry* pe = find(key);
@ -293,9 +317,6 @@ void PerfLogging::stop(const char* key) {
} }
} }
//
// Print the collected performance data
//
void PerfLogging::print() { void PerfLogging::print() {
PerfEntry* pe = first; PerfEntry* pe = first;
@ -305,9 +326,6 @@ void PerfLogging::print() {
} }
} }
//
// Push collected performance data to influx (use influx configuration)
//
void PerfLogging::pushInflux() { void PerfLogging::pushInflux() {
if (!myConfig.isInfluxDb2Active()) return; if (!myConfig.isInfluxDb2Active()) return;
@ -388,7 +406,7 @@ void PerfLogging::pushInflux() {
// Send HTTP POST request // Send HTTP POST request
String auth = "Token " + String(myConfig.getInfluxDb2PushToken()); String auth = "Token " + String(myConfig.getInfluxDb2PushToken());
http.addHeader(F("Authorization"), auth.c_str()); http.addHeader(F("Authorization"), auth.c_str());
http.setTimeout(myAdvancedConfig.getPushTimeout()); http.setTimeout(myAdvancedConfig.getPushTimeout() * 1000);
int httpResponseCode = http.POST(body); int httpResponseCode = http.POST(body);
if (httpResponseCode == 204) { if (httpResponseCode == 204) {
@ -409,29 +427,19 @@ void PerfLogging::pushInflux() {
#endif // COLLECT_PERFDATA #endif // COLLECT_PERFDATA
//
// Convert float to formatted string with n decimals. Buffer should be at least
// 10 chars.
//
char* convertFloatToString(float f, char* buffer, int dec) { char* convertFloatToString(float f, char* buffer, int dec) {
dtostrf(f, 6, dec, buffer); dtostrf(f, 6, dec, buffer);
return buffer; return buffer;
} }
//
// Reduce precision to n decimals
//
float reduceFloatPrecision(float f, int dec) { float reduceFloatPrecision(float f, int dec) {
char buffer[5]; char buffer[5];
dtostrf(f, 6, dec, &buffer[0]); dtostrf(f, 6, dec, &buffer[0]);
return atof(&buffer[0]); return atof(&buffer[0]);
} }
//
// urlencode // urlencode
//
// https://circuits4you.com/2019/03/21/esp8266-url-encode-decode-example/ // https://circuits4you.com/2019/03/21/esp8266-url-encode-decode-example/
//
String urlencode(String str) { String urlencode(String str) {
String encodedString; String encodedString;
encodedString.reserve(str.length() * 2); encodedString.reserve(str.length() * 2);
@ -475,9 +483,6 @@ unsigned char h2int(char c) {
return (0); return (0);
} }
//
// urlencode string
//
String urldecode(String str) { String urldecode(String str) {
String encodedString; String encodedString;
encodedString.reserve(str.length()); encodedString.reserve(str.length());

View File

@ -28,13 +28,18 @@ SOFTWARE.
#include <main.hpp> #include <main.hpp>
#define ERR_FILENAME "/error.log" #define ERR_FILENAME "/error.log"
#define ERR_COUNT 15 #define ERR_FILENAME2 "/error2.log"
#define ERR_FILEMAXSIZE 4000
#define RUNTIME_FILENAME "/runtime.log" #define RUNTIME_FILENAME "/runtime.log"
// tcp cleanup // tcp cleanup
void tcp_cleanup(); void tcp_cleanup();
// Error logging
void writeErrorLog(const char* format, ...);
void checkResetReason();
// Sleep mode // Sleep mode
void deepSleep(int t); void deepSleep(int t);
@ -67,16 +72,6 @@ class SerialDebug {
static Logging* getLog() { return &Log; } static Logging* getLog() { return &Log; }
}; };
class ErrorFileLog {
private:
String _errors[ERR_COUNT];
public:
ErrorFileLog();
void addEntry(String error);
void save();
};
class FloatHistoryLog { class FloatHistoryLog {
private: private:
String _fName; String _fName;
@ -93,9 +88,10 @@ class FloatHistoryLog {
class BatteryVoltage { class BatteryVoltage {
private: private:
float _batteryLevel; float _batteryLevel = 0;
public: public:
BatteryVoltage();
void read(); void read();
float getVoltage() { return _batteryLevel; } float getVoltage() { return _batteryLevel; }
}; };

View File

@ -22,6 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include <ble.hpp> #include <ble.hpp>
#undef LOG_LEVEL_ERROR
#undef LOG_LEVEL_INFO
#include <calc.hpp> #include <calc.hpp>
#include <config.hpp> #include <config.hpp>
#include <gyro.hpp> #include <gyro.hpp>
@ -33,12 +35,14 @@ SOFTWARE.
#include <wifi.hpp> #include <wifi.hpp>
// #define FORCE_GRAVITY_MODE // #define FORCE_GRAVITY_MODE
SerialDebug mySerial;
BatteryVoltage myBatteryVoltage;
// Define constats for this program // Define constats for this program
#ifdef DEACTIVATE_SLEEPMODE #ifdef DEACTIVATE_SLEEPMODE
const int interval = 1000; // ms, time to wait between changes to output const int interval = 1000; // ms, time to wait between changes to output
#else #else
int interval = 200; // ms, time to wait between changes to output int interval = 200; // ms, time to wait between changes to output
#endif #endif
bool sleepModeAlwaysSkip = bool sleepModeAlwaysSkip =
false; // Flag set in web interface to override normal behaviour false; // Flag set in web interface to override normal behaviour
@ -117,10 +121,9 @@ void checkSleepMode(float angle, float volt) {
Log.notice( Log.notice(
F("Main: Storage mode entered, going to sleep for maximum time." CR)); F("Main: Storage mode entered, going to sleep for maximum time." CR));
#if defined(ESP8266) #if defined(ESP8266)
ESP.deepSleep(ESP.deepSleepMax()); ESP.deepSleep(0); // indefinite sleep
#else #else
#warning "Check and test the max deep sleep for esp32" ESP.deepSleep(0); // indefinite sleep
deepSleep(70 * 60); // quick search on internet suggest max time is 70 min
#endif #endif
} }
} }
@ -133,11 +136,8 @@ void setup() {
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
// Add a delay so that serial is started. // Add a delay so that serial is started.
// delay(3000); // delay(3000);
#if defined(ESP8266)
Log.verbose(F("Main: Reset reason %s." CR), ESP.getResetInfo().c_str());
#else // defined (ESP32)
#endif
#endif #endif
// Main startup // Main startup
#if defined(ESP8266) #if defined(ESP8266)
Log.notice(F("Main: Started setup for %s." CR), Log.notice(F("Main: Started setup for %s." CR),
@ -157,6 +157,7 @@ void setup() {
LOG_PERF_START("main-config-load"); LOG_PERF_START("main-config-load");
myConfig.checkFileSystem(); myConfig.checkFileSystem();
checkResetReason();
myConfig.loadFile(); myConfig.loadFile();
myWifi.init(); myWifi.init();
myAdvancedConfig.loadFile(); myAdvancedConfig.loadFile();
@ -192,18 +193,20 @@ void setup() {
break; break;
default: default:
if (!myGyro.setup()) { if (myGyro.setup()) {
ErrorFileLog errLog;
errLog.addEntry(
F("MAIN: Failed to initialize the gyro, is it connected?"));
} else {
LOG_PERF_START("main-gyro-read"); LOG_PERF_START("main-gyro-read");
myGyro.read(); myGyro.read();
LOG_PERF_STOP("main-gyro-read"); LOG_PERF_STOP("main-gyro-read");
} else {
Log.notice(
F("Main: Failed to connect to the gyro, software will not be able "
"to detect angles." CR));
} }
myBatteryVoltage.read(); myBatteryVoltage.read();
checkSleepMode(myGyro.getAngle(), myBatteryVoltage.getVoltage()); checkSleepMode(myGyro.getAngle(), myBatteryVoltage.getVoltage());
Log.notice(F("Main: Battery %F V, Gyro=%F, Run-mode=%d." CR),
myBatteryVoltage.getVoltage(), myGyro.getAngle(), runMode);
#if defined(ESP32) #if defined(ESP32)
if (!myConfig.isWifiPushActive() && runMode == RunMode::gravityMode) { if (!myConfig.isWifiPushActive() && runMode == RunMode::gravityMode) {
@ -307,13 +310,13 @@ bool loopReadGravity() {
pushMillis = millis(); pushMillis = millis();
LOG_PERF_START("loop-push"); LOG_PERF_START("loop-push");
#if defined(ESP32) #if defined(ESP32) && !defined(ESP32S2)
if (myConfig.isBLEActive()) { if (myConfig.isBLEActive()) {
BleSender ble(myConfig.getColorBLE()); BleSender ble(myConfig.getColorBLE());
ble.sendData(convertCtoF(tempC), gravitySG); ble.sendData(convertCtoF(tempC), gravitySG);
Log.notice(F("MAIN: Broadcast data over bluetooth." CR)); Log.notice(F("MAIN: Broadcast data over bluetooth." CR));
} }
#endif #endif // ESP32 && !ESP32S2
if (myWifi.isConnected()) { // no need to try if there is no wifi if (myWifi.isConnected()) { // no need to try if there is no wifi
// connection. // connection.
@ -385,10 +388,10 @@ void loop() {
break; break;
case RunMode::configurationMode: case RunMode::configurationMode:
if (myWifi.isConnected()) myWebServerHandler.loop(); myWebServerHandler.loop();
myWifi.loop(); myWifi.loop();
loopGravityOnInterval(); loopGravityOnInterval();
delay(1);
// If we switched mode, dont include this in the log. // If we switched mode, dont include this in the log.
if (runMode != RunMode::configurationMode) skipRunTimeLog = true; if (runMode != RunMode::configurationMode) skipRunTimeLog = true;

View File

@ -45,19 +45,62 @@ extern RunMode runMode;
#define PIN_DS D6 #define PIN_DS D6
#define PIN_LED 2 #define PIN_LED 2
// #define PIN_A0 A0 // #define PIN_A0 A0
#else // defined (ESP32) #elif defined(ESP32C3)
#include <FS.h> #include <FS.h>
#include <LittleFS.h> #include <LittleFS.h>
#include "esp32c3/rom/rtc.h"
#define ESPhttpUpdate httpUpdate #define ESPhttpUpdate httpUpdate
#define ESP_RESET ESP.restart #define ESP_RESET ESP.restart
#define ESP8266WebServer WebServer #define ESP8266WebServer WebServer
#define PIN_SDA 17 #if defined(JTAG_DEBUG)
#define PIN_SCL 16 #define PIN_SDA 8
#define PIN_DS 19 #define PIN_SCL 9
#define PIN_A0 36 #warning "ESP32C3 JTAG debugging enabled, using GYRO on GPIO 8/9"
#define PIN_LED 2 #else
#define PIN_SDA 7
#define PIN_SCL 6
#endif
#define PIN_DS A3
#define PIN_A0 A0
// This should be the LED_BUILTIN, but that is also connected SDA (Gyro) so we
// cannot use both. So we point LED to pin 8 which is not used.
#define PIN_LED 8
/*
#elif defined(ESP32S2)
#include <FS.h>
#include <LittleFS.h>
#include "esp32s2/rom/rtc.h"
#define ESPhttpUpdate httpUpdate
#define ESP_RESET ESP.restart
#define ESP8266WebServer WebServer
#define PIN_SDA SDA
#define PIN_SCL SCL
#define PIN_DS A8
#define PIN_A0 A2
#define PIN_LED LED_BUILTIN
*/
#else // defined (ESP32)
#include <FS.h>
#include <LittleFS.h>
#include "esp32/rom/rtc.h"
#define ESPhttpUpdate httpUpdate
#define ESP_RESET ESP.restart
#define ESP8266WebServer WebServer
#define PIN_SDA D3
#define PIN_SCL D4
#define PIN_DS D6
#define PIN_LED LED_BUILTIN
// #define PIN_A0 A4
#endif #endif
#define PIN_LED 2 #if defined(ESP32C3) && defined(USE_SERIAL0)
#define EspSerial Serial0
// #warning "Using Serial0 for output RX/TX pins on ESP32C3"
#else
#define EspSerial Serial
#endif
#endif // SRC_MAIN_HPP_ #endif // SRC_MAIN_HPP_

View File

@ -34,9 +34,6 @@ SOFTWARE.
#define PUSHINT_FILENAME "/push.dat" #define PUSHINT_FILENAME "/push.dat"
//
// Decrease counters
//
void PushIntervalTracker::update(const int index, const int defaultValue) { void PushIntervalTracker::update(const int index, const int defaultValue) {
if (_counters[index] <= 0) if (_counters[index] <= 0)
_counters[index] = defaultValue; _counters[index] = defaultValue;
@ -44,9 +41,6 @@ void PushIntervalTracker::update(const int index, const int defaultValue) {
_counters[index]--; _counters[index]--;
} }
//
// Load data from file
//
void PushIntervalTracker::load() { void PushIntervalTracker::load() {
File intFile = LittleFS.open(PUSHINT_FILENAME, "r"); File intFile = LittleFS.open(PUSHINT_FILENAME, "r");
@ -143,10 +137,11 @@ void PushTarget::sendAll(float angle, float gravitySG, float corrGravitySG,
if (myConfig.isMqttActive() && intDelay.useMqtt()) { if (myConfig.isMqttActive() && intDelay.useMqtt()) {
LOG_PERF_START("push-mqtt"); LOG_PERF_START("push-mqtt");
sendMqtt(engine, myConfig.isMqttSSL()); sendMqtt(engine, myConfig.isMqttSSL(), true);
LOG_PERF_STOP("push-mqtt"); LOG_PERF_STOP("push-mqtt");
} }
engine.freeMemory();
intDelay.save(); intDelay.save();
} }
@ -232,8 +227,7 @@ void PushTarget::sendInfluxDb2(TemplatingEngine& engine, bool isSecure) {
_lastSuccess = true; _lastSuccess = true;
Log.notice(F("PUSH: InfluxDB2 push successful, response=%d" CR), _lastCode); Log.notice(F("PUSH: InfluxDB2 push successful, response=%d" CR), _lastCode);
} else { } else {
ErrorFileLog errLog; writeErrorLog("PUSH: Influxdb push failed response=%d", _lastCode);
errLog.addEntry("PUSH: Influxdb push failed response=" + String(_lastCode));
} }
if (isSecure) { if (isSecure) {
@ -261,8 +255,8 @@ void PushTarget::addHttpHeader(HTTPClient& http, String header) {
value.c_str()); value.c_str());
http.addHeader(name, value); http.addHeader(name, value);
} else { } else {
ErrorFileLog errLog; writeErrorLog("PUSH: Unable to set header, invalid value %s",
errLog.addEntry("PUSH: Unable to set header, invalid value " + header); header.c_str());
} }
} }
@ -338,9 +332,8 @@ void PushTarget::sendHttpPost(TemplatingEngine& engine, bool isSecure,
_lastSuccess = true; _lastSuccess = true;
Log.notice(F("PUSH: HTTP post successful, response=%d" CR), _lastCode); Log.notice(F("PUSH: HTTP post successful, response=%d" CR), _lastCode);
} else { } else {
ErrorFileLog errLog; writeErrorLog("PUSH: HTTP post failed response=%d http%d", _lastCode,
errLog.addEntry("PUSH: HTTP post failed response=" + String(_lastCode) + index + 1);
String(index == 0 ? " (http)" : " (http2)"));
} }
if (isSecure) { if (isSecure) {
@ -399,8 +392,7 @@ void PushTarget::sendHttpGet(TemplatingEngine& engine, bool isSecure) {
_lastSuccess = true; _lastSuccess = true;
Log.notice(F("PUSH: HTTP get successful, response=%d" CR), _lastCode); Log.notice(F("PUSH: HTTP get successful, response=%d" CR), _lastCode);
} else { } else {
ErrorFileLog errLog; writeErrorLog("PUSH: HTTP get failed response=%d", _lastCode);
errLog.addEntry("PUSH: HTTP get failed response=" + String(_lastCode));
} }
if (isSecure) { if (isSecure) {
@ -416,9 +408,11 @@ void PushTarget::sendHttpGet(TemplatingEngine& engine, bool isSecure) {
// //
// Send data to mqtt target // Send data to mqtt target
// //
void PushTarget::sendMqtt(TemplatingEngine& engine, bool isSecure) { void PushTarget::sendMqtt(TemplatingEngine& engine, bool isSecure,
bool skipHomeAssistantRegistration) {
#if !defined(PUSH_DISABLE_LOGGING) #if !defined(PUSH_DISABLE_LOGGING)
Log.notice(F("PUSH: Sending values to mqtt." CR)); Log.notice(F("PUSH: Sending values to mqtt. Skip HA registration=%s" CR),
skipHomeAssistantRegistration ? "yes" : "no");
#endif #endif
_lastCode = 0; _lastCode = 0;
_lastSuccess = false; _lastSuccess = false;
@ -483,15 +477,22 @@ void PushTarget::sendMqtt(TemplatingEngine& engine, bool isSecure) {
Log.verbose(F("PUSH: topic '%s', value '%s'." CR), topic.c_str(), Log.verbose(F("PUSH: topic '%s', value '%s'." CR), topic.c_str(),
value.c_str()); value.c_str());
#endif #endif
if (mqtt.publish(topic, value)) {
_lastSuccess = true; if (skipHomeAssistantRegistration &&
Log.notice(F("PUSH: MQTT publish successful on %s" CR), topic.c_str()); topic.startsWith("homeassistant/sensor/")) {
_lastCode = 0; Log.notice(F("PUSH: Ignoring Home Assistant registration topic %s" CR),
topic.c_str());
} else { } else {
_lastCode = mqtt.lastError(); if (mqtt.publish(topic, value)) {
ErrorFileLog errLog; _lastSuccess = true;
errLog.addEntry("PUSH: MQTT push on " + topic + Log.notice(F("PUSH: MQTT publish successful on %s" CR), topic.c_str());
" failed error=" + String(mqtt.lastError())); _lastCode = 0;
} else {
_lastSuccess = false;
_lastCode = mqtt.lastError();
writeErrorLog("PUSH: MQTT push on %s failed error=%d", topic.c_str(),
_lastCode);
}
} }
index = next + 1; index = next + 1;

View File

@ -61,7 +61,8 @@ class PushTarget {
sendHttpGet(engine, isSecure); sendHttpGet(engine, isSecure);
} }
void sendInfluxDb2(TemplatingEngine& engine, bool isSecure); void sendInfluxDb2(TemplatingEngine& engine, bool isSecure);
void sendMqtt(TemplatingEngine& engine, bool isSecure); void sendMqtt(TemplatingEngine& engine, bool isSecure,
bool skipHomeAssistantRegistration = true);
int getLastCode() { return _lastCode; } int getLastCode() { return _lastCode; }
bool getLastSuccess() { return _lastSuccess; } bool getLastSuccess() { return _lastSuccess; }
}; };

View File

@ -23,23 +23,16 @@ SOFTWARE.
*/ */
#if defined(ESP8266) #if defined(ESP8266)
#define INCBIN_OUTPUT_SECTION ".irom.text" #define INCBIN_OUTPUT_SECTION ".irom.text"
#endif
#include <incbin.h> #include <incbin.h>
#include <resources.hpp> #include <resources.hpp>
INCBIN(IndexHtm, "html/index.min.htm");
#if defined(EMBED_HTML) INCBIN(ConfigHtm, "html/config.min.htm");
// Using minify to reduce memory usage. Reducing RAM memory usage with about 7% INCBIN(CalibrationHtm, "html/calibration.min.htm");
INCBIN(IndexHtm, "data/index.min.htm"); INCBIN(FormatHtm, "html/format.min.htm");
INCBIN(ConfigHtm, "data/config.min.htm"); INCBIN(TestHtm, "html/test.min.htm");
INCBIN(CalibrationHtm, "data/calibration.min.htm"); INCBIN(AboutHtm, "html/about.min.htm");
INCBIN(FormatHtm, "data/format.min.htm"); INCBIN(FirmwareHtm, "html/firmware.min.htm");
INCBIN(TestHtm, "data/test.min.htm");
INCBIN(AboutHtm, "data/about.min.htm");
#else
// Minium web interface for uploading htm files
INCBIN(UploadHtm, "data/upload.min.htm");
#endif #endif
INCBIN(FirmwareHtm, "data/firmware.min.htm");
// EOF // EOF

View File

@ -141,30 +141,30 @@ void TemplatingEngine::initialize(float angle, float gravitySG,
// //
// Create the data using defined template. // Create the data using defined template.
// //
const String& TemplatingEngine::create(TemplatingEngine::Templates idx) { const char* TemplatingEngine::create(TemplatingEngine::Templates idx) {
String fname; String fname;
baseTemplate.reserve(600); _baseTemplate.reserve(600);
// Load templates from memory // Load templates from memory
switch (idx) { switch (idx) {
case TEMPLATE_HTTP1: case TEMPLATE_HTTP1:
baseTemplate = String(iSpindleFormat); _baseTemplate = String(iSpindleFormat);
fname = TPL_FNAME_HTTP1; fname = TPL_FNAME_HTTP1;
break; break;
case TEMPLATE_HTTP2: case TEMPLATE_HTTP2:
baseTemplate = String(iSpindleFormat); _baseTemplate = String(iSpindleFormat);
fname = TPL_FNAME_HTTP2; fname = TPL_FNAME_HTTP2;
break; break;
case TEMPLATE_HTTP3: case TEMPLATE_HTTP3:
baseTemplate = String(iHttpGetFormat); _baseTemplate = String(iHttpGetFormat);
fname = TPL_FNAME_HTTP3; fname = TPL_FNAME_HTTP3;
break; break;
case TEMPLATE_INFLUX: case TEMPLATE_INFLUX:
baseTemplate = String(influxDbFormat); _baseTemplate = String(influxDbFormat);
fname = TPL_FNAME_INFLUXDB; fname = TPL_FNAME_INFLUXDB;
break; break;
case TEMPLATE_MQTT: case TEMPLATE_MQTT:
baseTemplate = String(mqttFormat); _baseTemplate = String(mqttFormat);
fname = TPL_FNAME_MQTT; fname = TPL_FNAME_MQTT;
break; break;
} }
@ -175,7 +175,7 @@ const String& TemplatingEngine::create(TemplatingEngine::Templates idx) {
char buf[file.size() + 1]; char buf[file.size() + 1];
memset(&buf[0], 0, file.size() + 1); memset(&buf[0], 0, file.size() + 1);
file.readBytes(&buf[0], file.size()); file.readBytes(&buf[0], file.size());
baseTemplate = String(&buf[0]); _baseTemplate = String(&buf[0]);
file.close(); file.close();
Log.notice(F("TPL : Template loaded from disk %s." CR), fname.c_str()); Log.notice(F("TPL : Template loaded from disk %s." CR), fname.c_str());
} }
@ -185,13 +185,16 @@ const String& TemplatingEngine::create(TemplatingEngine::Templates idx) {
#endif #endif
// Insert data into template. // Insert data into template.
transform(baseTemplate); transform();
_baseTemplate.clear();
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6
// Log.verbose(F("TPL : Transformed '%s'." CR), baseTemplate.c_str()); // Log.verbose(F("TPL : Transformed '%s'." CR), baseTemplate.c_str());
#endif #endif
return baseTemplate; if (_output) return _output;
return "";
} }
// EOF // EOF

View File

@ -75,34 +75,35 @@ class TemplatingEngine {
String val; String val;
}; };
KeyVal items[23] = {{TPL_MDNS, ""}, {TPL_ID, ""}, KeyVal _items[23] = {{TPL_MDNS, ""}, {TPL_ID, ""},
{TPL_SLEEP_INTERVAL, ""}, {TPL_TEMP, ""}, {TPL_SLEEP_INTERVAL, ""}, {TPL_TEMP, ""},
{TPL_TEMP_C, ""}, {TPL_TEMP_F, ""}, {TPL_TEMP_C, ""}, {TPL_TEMP_F, ""},
{TPL_TEMP_UNITS, ""}, {TPL_BATTERY, ""}, {TPL_TEMP_UNITS, ""}, {TPL_BATTERY, ""},
{TPL_RSSI, ""}, {TPL_RUN_TIME, ""}, {TPL_RSSI, ""}, {TPL_RUN_TIME, ""},
{TPL_ANGLE, ""}, {TPL_TILT, ""}, {TPL_ANGLE, ""}, {TPL_TILT, ""},
{TPL_GRAVITY, ""}, {TPL_GRAVITY_G, ""}, {TPL_GRAVITY, ""}, {TPL_GRAVITY_G, ""},
{TPL_GRAVITY_P, ""}, {TPL_GRAVITY_CORR, ""}, {TPL_GRAVITY_P, ""}, {TPL_GRAVITY_CORR, ""},
{TPL_GRAVITY_CORR_G, ""}, {TPL_GRAVITY_CORR_P, ""}, {TPL_GRAVITY_CORR_G, ""}, {TPL_GRAVITY_CORR_P, ""},
{TPL_GRAVITY_UNIT, ""}, {TPL_TOKEN, ""}, {TPL_GRAVITY_UNIT, ""}, {TPL_TOKEN, ""},
{TPL_TOKEN2, ""}, {TPL_APP_VER, ""}, {TPL_TOKEN2, ""}, {TPL_APP_VER, ""},
{TPL_APP_BUILD, ""}}; {TPL_APP_BUILD, ""}};
char buffer[20]; char _buffer[20] = "";
String baseTemplate; String _baseTemplate;
char *_output = 0;
void setVal(String key, float val, int dec = 2) { void setVal(String key, float val, int dec = 2) {
String s = convertFloatToString(val, &buffer[0], dec); String s = convertFloatToString(val, &_buffer[0], dec);
s.trim(); s.trim();
setVal(key, s); setVal(key, s);
} }
void setVal(String key, int val) { setVal(key, String(val)); } void setVal(String key, int val) { setVal(key, String(val)); }
void setVal(String key, char val) { setVal(key, String(val)); } void setVal(String key, char val) { setVal(key, String(val)); }
void setVal(String key, String val) { void setVal(String key, String val) {
int max = sizeof(items) / sizeof(KeyVal); int max = sizeof(_items) / sizeof(KeyVal);
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
if (items[i].key.equals(key)) { if (_items[i].key.equals(key)) {
items[i].val = val; _items[i].val = val;
return; return;
} }
} }
@ -110,22 +111,74 @@ class TemplatingEngine {
Log.warning(F("TPL : Key not found %s." CR), key.c_str()); Log.warning(F("TPL : Key not found %s." CR), key.c_str());
} }
void transform(String& s) { void transform() {
int max = sizeof(items) / sizeof(KeyVal); const char *format = _baseTemplate.c_str();
for (int i = 0; i < max; i++) { int len = _baseTemplate.length();
while (s.indexOf(items[i].key) != -1) int size = len;
s.replace(items[i].key, items[i].val);
// Lets check how much memory will be needed to transform the template
for (int j = 0; j < len - 2; j++) {
if (*(format + j) == '$' && *(format + j + 1) == '{') {
// Start of format tag found
int max = sizeof(_items) / sizeof(KeyVal);
for (int i = 0; i < max; i++) {
if (strncmp(format + j, _items[i].key.c_str(),
_items[i].key.length()) == 0) {
// Found key
size = size - _items[i].key.length() + _items[i].val.length();
}
}
}
} }
freeMemory(); // In case this is reused
_output = static_cast<char *>(malloc(size + 20));
if (!_output) {
Log.error(F("TPL : Unable to allocate memory for transforming template, "
"needed %d." CR),
size);
return;
}
memset(_output, 0, size + 20);
// Lets do the transformation
int k = 0;
for (int j = 0; j < len - 2; j++) {
if (*(format + j) == '$' && *(format + j + 1) == '{') {
// Start of format tag found
int max = sizeof(_items) / sizeof(KeyVal);
for (int i = 0; i < max; i++) {
if (strncmp(format + j, _items[i].key.c_str(),
_items[i].key.length()) == 0) {
// Found key
strncat(_output, format + k, j - k);
strncat(_output, _items[i].val.c_str(), _items[i].val.length());
k = j + _items[i].key.length();
}
}
}
}
strncat(_output, format + k, size - k);
Log.notice(F("TPL : Transformed template %d chars to %d chars" CR),
strlen(format), strlen(_output));
#if LOG_LEVEL == 6
printHeap("TPL ");
Log.verboseln(format);
Log.verboseln(_output);
#endif
} }
void dumpAll() { void dumpAll() {
int max = sizeof(items) / sizeof(KeyVal); int max = sizeof(_items) / sizeof(KeyVal);
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
Serial.print("Key=\'"); EspSerial.print("Key=\'");
Serial.print(items[i].key.c_str()); EspSerial.print(_items[i].key.c_str());
Serial.print("\', Val=\'"); EspSerial.print("\', Val=\'");
Serial.print(items[i].val.c_str()); EspSerial.print(_items[i].val.c_str());
Serial.println("\'"); EspSerial.println("\'");
} }
} }
@ -138,9 +191,16 @@ class TemplatingEngine {
TEMPLATE_MQTT = 4 TEMPLATE_MQTT = 4
}; };
TemplatingEngine() {}
~TemplatingEngine() { freeMemory(); }
void freeMemory() {
if (_output) free(_output);
_output = 0;
}
void initialize(float angle, float gravitySG, float corrGravitySG, void initialize(float angle, float gravitySG, float corrGravitySG,
float tempC, float runTime); float tempC, float runTime);
const String& create(TemplatingEngine::Templates idx); const char *create(TemplatingEngine::Templates idx);
}; };
#endif // SRC_TEMPLATING_HPP_ #endif // SRC_TEMPLATING_HPP_

View File

@ -37,9 +37,6 @@ WebServerHandler myWebServerHandler; // My wrapper class fr webserver functions
extern bool sleepModeActive; extern bool sleepModeActive;
extern bool sleepModeAlwaysSkip; extern bool sleepModeAlwaysSkip;
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleConfig() { void WebServerHandler::webHandleConfig() {
LOG_PERF_START("webserver-api-config"); LOG_PERF_START("webserver-api-config");
Log.notice(F("WEB : webServer callback for /api/config(get)." CR)); Log.notice(F("WEB : webServer callback for /api/config(get)." CR));
@ -90,13 +87,17 @@ void WebServerHandler::webHandleConfig() {
#if defined(ESP8266) #if defined(ESP8266)
doc[PARAM_PLATFORM] = "esp8266"; doc[PARAM_PLATFORM] = "esp8266";
#else #elif defined(ESP32C3)
doc[PARAM_PLATFORM] = "esp32c3";
#elif defined(ESP32S2)
doc[PARAM_PLATFORM] = "esp32s3";
#else // esp32 mini
doc[PARAM_PLATFORM] = "esp32"; doc[PARAM_PLATFORM] = "esp32";
#endif #endif
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
String out; String out;
@ -107,179 +108,64 @@ void WebServerHandler::webHandleConfig() {
LOG_PERF_STOP("webserver-api-config"); LOG_PERF_STOP("webserver-api-config");
} }
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleUpload() {
LOG_PERF_START("webserver-api-upload");
Log.notice(F("WEB : webServer callback for /api/upload(get)." CR));
DynamicJsonDocument doc(300);
doc["index"] = checkHtmlFile(WebServerHandler::HTML_INDEX);
doc["config"] = checkHtmlFile(WebServerHandler::HTML_CONFIG);
doc["calibration"] = checkHtmlFile(WebServerHandler::HTML_CALIBRATION);
doc["format"] = checkHtmlFile(WebServerHandler::HTML_FORMAT);
doc["about"] = checkHtmlFile(WebServerHandler::HTML_ABOUT);
doc["test"] = checkHtmlFile(WebServerHandler::HTML_TEST);
#if defined(ESP8266)
JsonArray files = doc.createNestedArray(PARAM_FILES);
// Show files in the filessytem at startup
FSInfo fs;
LittleFS.info(fs);
Dir dir = LittleFS.openDir("/");
while (dir.next()) {
JsonObject obj = files.createNestedObject();
obj[PARAM_FILE_NAME] = dir.fileName();
obj[PARAM_FILE_SIZE] = dir.fileSize();
}
#else // defined(ESP32)
JsonArray files = doc.createNestedArray(PARAM_FILES);
File dir = LittleFS.open("/");
while (true) {
File entry = dir.openNextFile();
if (!entry) {
// no more files
break;
}
if (!entry.isDirectory()) {
JsonObject obj = files.createNestedObject();
obj[PARAM_FILE_NAME] = entry.name();
obj[PARAM_FILE_SIZE] = entry.size();
}
entry.close();
}
dir.close();
#endif
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial);
Serial.print(CR);
#endif
String out;
out.reserve(300);
serializeJson(doc, out);
doc.clear();
_server->send(200, "application/json", out.c_str());
LOG_PERF_STOP("webserver-api-upload");
}
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleUploadFile() { void WebServerHandler::webHandleUploadFile() {
LOG_PERF_START("webserver-api-upload-file"); LOG_PERF_START("webserver-api-upload-file");
Log.verbose(F("WEB : webServer callback for /api/upload(post)." CR)); Log.verbose(F("WEB : webServer callback for /api/upload(post)." CR));
HTTPUpload& upload = _server->upload(); HTTPUpload& upload = _server->upload();
String f = upload.filename; String f = upload.filename;
bool validFilename = false;
bool firmware = false;
if (f.equalsIgnoreCase("index.min.htm") ||
f.equalsIgnoreCase("calibration.min.htm") ||
f.equalsIgnoreCase("config.min.htm") ||
f.equalsIgnoreCase("format.min.htm") ||
f.equalsIgnoreCase("test.min.htm") ||
f.equalsIgnoreCase("about.min.htm")) {
validFilename = true;
}
if (f.endsWith(".bin")) {
validFilename = true;
firmware = true;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose( Log.verbose(F("WEB : webServer callback for /api/upload, receiving file %s, "
F("WEB : webServer callback for /api/upload, receiving file %s, %d(%d) " "%d(%d)." CR),
"valid=%s, firmware=%s." CR), f.c_str(), upload.currentSize, upload.totalSize);
f.c_str(), upload.currentSize, upload.totalSize,
validFilename ? "yes" : "no", firmware ? "yes" : "no");
#endif #endif
if (firmware) { // Handle firmware update, hardcode since function return wrong value.
// Handle firmware update, hardcode since function return wrong value. // (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
// (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; uint32_t maxSketchSpace = MAX_SKETCH_SPACE;
uint32_t maxSketchSpace = MAX_SKETCH_SPACE;
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
_uploadReturn = 200; _uploadReturn = 200;
Log.notice(F("WEB : Start firmware upload, max sketch size %d kb." CR), Log.notice(F("WEB : Start firmware upload, max sketch size %d kb." CR),
maxSketchSpace / 1024); maxSketchSpace / 1024);
if (!Update.begin(maxSketchSpace, U_FLASH, PIN_LED)) { if (!Update.begin(maxSketchSpace, U_FLASH, PIN_LED)) {
ErrorFileLog errLog; writeErrorLog("WEB : Not enough space to store for this firmware.");
errLog.addEntry(
F("WEB : Not enough space to store for this firmware."));
_uploadReturn = 500;
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
Log.notice(F("WEB : Writing firmware upload %d (%d)." CR),
upload.totalSize, maxSketchSpace);
if (upload.totalSize > maxSketchSpace) {
Log.error(F("WEB : Firmware file is to large." CR));
_uploadReturn = 500;
} else if (Update.write(upload.buf, upload.currentSize) !=
upload.currentSize) {
Log.warning(F("WEB : Firmware write was unsuccessful." CR));
_uploadReturn = 500;
}
} else if (upload.status == UPLOAD_FILE_END) {
Log.notice(F("WEB : Finish firmware upload." CR));
if (Update.end(true)) {
_server->send(200);
delay(500);
ESP_RESET();
} else {
ErrorFileLog errLog;
errLog.addEntry("WEB : Failed to finish firmware flashing error=" +
String(Update.getError()));
_uploadReturn = 500;
}
} else {
Update.end();
Log.notice(F("WEB : Firmware flashing aborted." CR));
_uploadReturn = 500; _uploadReturn = 500;
} }
} else if (upload.status == UPLOAD_FILE_WRITE) {
Log.notice(F("WEB : Writing firmware upload %d (%d)." CR), upload.totalSize,
maxSketchSpace);
delay(0); if (upload.totalSize > maxSketchSpace) {
Log.error(F("WEB : Firmware file is to large." CR));
} else { _uploadReturn = 500;
// Handle HTML file upload } else if (Update.write(upload.buf, upload.currentSize) !=
if (upload.status == UPLOAD_FILE_START) { upload.currentSize) {
_uploadReturn = 200; Log.warning(F("WEB : Firmware write was unsuccessful." CR));
Log.notice(F("WEB : Start html upload." CR)); _uploadReturn = 500;
if (validFilename) _uploadFile = LittleFS.open(f, "w");
} else if (upload.status == UPLOAD_FILE_WRITE) {
Log.notice(F("WEB : Writing html upload." CR));
if (_uploadFile) _uploadFile.write(upload.buf, upload.currentSize);
} else if (upload.status == UPLOAD_FILE_END) {
Log.notice(F("WEB : Finish html upload." CR));
if (_uploadFile) {
_uploadFile.close();
Log.notice(F("WEB : Html file uploaded %d bytes." CR),
upload.totalSize);
}
_server->sendHeader("Location", "/");
_server->send(303);
} else {
_server->send(500, "text/plain", "Couldn't upload html file.");
} }
} else if (upload.status == UPLOAD_FILE_END) {
Log.notice(F("WEB : Finish firmware upload." CR));
if (Update.end(true)) {
_server->send(200);
delay(500);
ESP_RESET();
} else {
writeErrorLog("WEB : Failed to finish firmware flashing error=%d",
Update.getError());
_uploadReturn = 500;
}
} else {
Update.end();
Log.notice(F("WEB : Firmware flashing aborted." CR));
_uploadReturn = 500;
} }
delay(0);
LOG_PERF_STOP("webserver-api-upload-file"); LOG_PERF_STOP("webserver-api-upload-file");
} }
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleCalibrate() { void WebServerHandler::webHandleCalibrate() {
LOG_PERF_START("webserver-api-calibrate"); LOG_PERF_START("webserver-api-calibrate");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -297,9 +183,6 @@ void WebServerHandler::webHandleCalibrate() {
LOG_PERF_STOP("webserver-api-calibrate"); LOG_PERF_STOP("webserver-api-calibrate");
} }
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleFactoryDefaults() { void WebServerHandler::webHandleFactoryDefaults() {
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
Log.notice(F("WEB : webServer callback for /api/factory." CR)); Log.notice(F("WEB : webServer callback for /api/factory." CR));
@ -316,6 +199,7 @@ void WebServerHandler::webHandleFactoryDefaults() {
LittleFS.remove(TPL_FNAME_INFLUXDB); LittleFS.remove(TPL_FNAME_INFLUXDB);
LittleFS.remove(TPL_FNAME_MQTT); LittleFS.remove(TPL_FNAME_MQTT);
LittleFS.end(); LittleFS.end();
Log.notice(F("WEB : Deleted files in filesystem, rebooting." CR));
delay(500); delay(500);
ESP_RESET(); ESP_RESET();
} else { } else {
@ -323,16 +207,27 @@ void WebServerHandler::webHandleFactoryDefaults() {
} }
} }
// void WebServerHandler::webHandleLogClear() {
// Callback from webServer when / has been accessed. String id = _server->arg(PARAM_ID);
// Log.notice(F("WEB : webServer callback for /api/clearlog." CR));
if (!id.compareTo(myConfig.getID())) {
_server->send(200, "text/plain", "Removing logfiles...");
LittleFS.remove(ERR_FILENAME);
LittleFS.remove(ERR_FILENAME2);
_server->send(200, "text/plain", "Logfiles cleared.");
} else {
_server->send(400, "text/plain", "Unknown ID.");
}
}
void WebServerHandler::webHandleStatus() { void WebServerHandler::webHandleStatus() {
LOG_PERF_START("webserver-api-status"); LOG_PERF_START("webserver-api-status");
Log.notice(F("WEB : webServer callback for /api/status(get)." CR)); Log.notice(F("WEB : webServer callback for /api/status(get)." CR));
DynamicJsonDocument doc(500); DynamicJsonDocument doc(500);
double angle = 0; double angle = 0; // Indicate we have no valid gyro value
if (myGyro.hasValue()) angle = myGyro.getAngle(); if (myGyro.hasValue()) angle = myGyro.getAngle();
@ -340,7 +235,10 @@ void WebServerHandler::webHandleStatus() {
double gravity = calculateGravity(angle, tempC); double gravity = calculateGravity(angle, tempC);
doc[PARAM_ID] = myConfig.getID(); doc[PARAM_ID] = myConfig.getID();
doc[PARAM_ANGLE] = reduceFloatPrecision(angle); doc[PARAM_ANGLE] = myGyro.isConnected()
? reduceFloatPrecision(angle)
: -1; // Indicate that we have no connection to gyro
if (myConfig.isGravityTempAdj()) { if (myConfig.isGravityTempAdj()) {
gravity = gravityTemperatureCorrectionC( gravity = gravityTemperatureCorrectionC(
gravity, tempC, myAdvancedConfig.getDefaultCalibrationTemp()); gravity, tempC, myAdvancedConfig.getDefaultCalibrationTemp());
@ -372,13 +270,17 @@ void WebServerHandler::webHandleStatus() {
#if defined(ESP8266) #if defined(ESP8266)
doc[PARAM_PLATFORM] = "esp8266"; doc[PARAM_PLATFORM] = "esp8266";
#else #elif defined(ESP32C3)
doc[PARAM_PLATFORM] = "esp32c3";
#elif defined(ESP32S2)
doc[PARAM_PLATFORM] = "esp32s3";
#else // esp32 mini
doc[PARAM_PLATFORM] = "esp32"; doc[PARAM_PLATFORM] = "esp32";
#endif #endif
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
String out; String out;
@ -389,9 +291,6 @@ void WebServerHandler::webHandleStatus() {
LOG_PERF_STOP("webserver-api-status"); LOG_PERF_STOP("webserver-api-status");
} }
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleClearWIFI() { void WebServerHandler::webHandleClearWIFI() {
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
Log.notice(F("WEB : webServer callback for /api/clearwifi." CR)); Log.notice(F("WEB : webServer callback for /api/clearwifi." CR));
@ -412,9 +311,6 @@ void WebServerHandler::webHandleClearWIFI() {
} }
} }
//
// Used to force the device to never sleep.
//
void WebServerHandler::webHandleStatusSleepmode() { void WebServerHandler::webHandleStatusSleepmode() {
LOG_PERF_START("webserver-api-sleepmode"); LOG_PERF_START("webserver-api-sleepmode");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -440,9 +336,6 @@ void WebServerHandler::webHandleStatusSleepmode() {
LOG_PERF_STOP("webserver-api-sleepmode"); LOG_PERF_STOP("webserver-api-sleepmode");
} }
//
// Update device settings.
//
void WebServerHandler::webHandleConfigDevice() { void WebServerHandler::webHandleConfigDevice() {
LOG_PERF_START("webserver-api-config-device"); LOG_PERF_START("webserver-api-config-device");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -472,9 +365,6 @@ void WebServerHandler::webHandleConfigDevice() {
LOG_PERF_STOP("webserver-api-config-device"); LOG_PERF_STOP("webserver-api-config-device");
} }
//
// Update push settings.
//
void WebServerHandler::webHandleConfigPush() { void WebServerHandler::webHandleConfigPush() {
LOG_PERF_START("webserver-api-config-push"); LOG_PERF_START("webserver-api-config-push");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -536,9 +426,6 @@ void WebServerHandler::webHandleConfigPush() {
LOG_PERF_STOP("webserver-api-config-push"); LOG_PERF_STOP("webserver-api-config-push");
} }
//
// Get string with all received arguments. Used for debugging only.
//
String WebServerHandler::getRequestArguments() { String WebServerHandler::getRequestArguments() {
String debug; String debug;
@ -555,9 +442,6 @@ String WebServerHandler::getRequestArguments() {
return debug; return debug;
} }
//
// Update gravity settings.
//
void WebServerHandler::webHandleConfigGravity() { void WebServerHandler::webHandleConfigGravity() {
LOG_PERF_START("webserver-api-config-gravity"); LOG_PERF_START("webserver-api-config-gravity");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -592,9 +476,6 @@ void WebServerHandler::webHandleConfigGravity() {
LOG_PERF_STOP("webserver-api-config-gravity"); LOG_PERF_STOP("webserver-api-config-gravity");
} }
//
// Update hardware settings.
//
void WebServerHandler::webHandleConfigHardware() { void WebServerHandler::webHandleConfigHardware() {
LOG_PERF_START("webserver-api-config-hardware"); LOG_PERF_START("webserver-api-config-hardware");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -646,9 +527,6 @@ void WebServerHandler::webHandleConfigHardware() {
LOG_PERF_STOP("webserver-api-config-hardware"); LOG_PERF_STOP("webserver-api-config-hardware");
} }
//
// Update advanced settings.
//
void WebServerHandler::webHandleConfigAdvancedWrite() { void WebServerHandler::webHandleConfigAdvancedWrite() {
LOG_PERF_START("webserver-api-config-advanced"); LOG_PERF_START("webserver-api-config-advanced");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -724,9 +602,6 @@ void WebServerHandler::webHandleConfigAdvancedWrite() {
LOG_PERF_STOP("webserver-api-config-advanced"); LOG_PERF_STOP("webserver-api-config-advanced");
} }
//
// Read advanced settings
//
void WebServerHandler::webHandleConfigAdvancedRead() { void WebServerHandler::webHandleConfigAdvancedRead() {
LOG_PERF_START("webserver-api-config-advanced"); LOG_PERF_START("webserver-api-config-advanced");
Log.notice(F("WEB : webServer callback for /api/config/advanced(get)." CR)); Log.notice(F("WEB : webServer callback for /api/config/advanced(get)." CR));
@ -755,8 +630,8 @@ void WebServerHandler::webHandleConfigAdvancedRead() {
doc[PARAM_HW_IGNORE_LOW_ANGLES] = myAdvancedConfig.isIgnoreLowAnges(); doc[PARAM_HW_IGNORE_LOW_ANGLES] = myAdvancedConfig.isIgnoreLowAnges();
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
String out; String out;
@ -767,9 +642,6 @@ void WebServerHandler::webHandleConfigAdvancedRead() {
LOG_PERF_STOP("webserver-api-config-advanced"); LOG_PERF_STOP("webserver-api-config-advanced");
} }
//
// Callback from webServer when / has been accessed.
//
void WebServerHandler::webHandleFormulaRead() { void WebServerHandler::webHandleFormulaRead() {
LOG_PERF_START("webserver-api-formula-read"); LOG_PERF_START("webserver-api-formula-read");
Log.notice(F("WEB : webServer callback for /api/formula(get)." CR)); Log.notice(F("WEB : webServer callback for /api/formula(get)." CR));
@ -841,8 +713,8 @@ void WebServerHandler::webHandleFormulaRead() {
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
String out; String out;
@ -853,9 +725,6 @@ void WebServerHandler::webHandleFormulaRead() {
LOG_PERF_STOP("webserver-api-formula-read"); LOG_PERF_STOP("webserver-api-formula-read");
} }
//
// Update format template
//
void WebServerHandler::webHandleConfigFormatWrite() { void WebServerHandler::webHandleConfigFormatWrite() {
LOG_PERF_START("webserver-api-config-format-write"); LOG_PERF_START("webserver-api-config-format-write");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -892,17 +761,13 @@ void WebServerHandler::webHandleConfigFormatWrite() {
_server->sendHeader("Location", "/format.htm", true); _server->sendHeader("Location", "/format.htm", true);
_server->send(302, "text/plain", "Format updated"); _server->send(302, "text/plain", "Format updated");
} else { } else {
ErrorFileLog errLog; writeErrorLog("WEB : Unable to store format file");
errLog.addEntry(F("WEB : Unable to store format file"));
_server->send(400, "text/plain", "Unable to store format in file."); _server->send(400, "text/plain", "Unable to store format in file.");
} }
LOG_PERF_STOP("webserver-api-config-format-write"); LOG_PERF_STOP("webserver-api-config-format-write");
} }
//
// Get format with real data
//
void WebServerHandler::webHandleTestPush() { void WebServerHandler::webHandleTestPush() {
LOG_PERF_START("webserver-api-test-push"); LOG_PERF_START("webserver-api-test-push");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -947,10 +812,11 @@ void WebServerHandler::webHandleTestPush() {
push.sendInfluxDb2(engine, myConfig.isInfluxSSL()); push.sendInfluxDb2(engine, myConfig.isInfluxSSL());
enabled = true; enabled = true;
} else if (!type.compareTo(PARAM_FORMAT_MQTT) && myConfig.isMqttActive()) { } else if (!type.compareTo(PARAM_FORMAT_MQTT) && myConfig.isMqttActive()) {
push.sendMqtt(engine, myConfig.isMqttSSL()); push.sendMqtt(engine, myConfig.isMqttSSL(), false);
enabled = true; enabled = true;
} }
engine.freeMemory();
DynamicJsonDocument doc(100); DynamicJsonDocument doc(100);
doc[PARAM_PUSH_ENABLED] = enabled; doc[PARAM_PUSH_ENABLED] = enabled;
doc[PARAM_PUSH_SUCCESS] = push.getLastSuccess(); doc[PARAM_PUSH_SUCCESS] = push.getLastSuccess();
@ -962,18 +828,14 @@ void WebServerHandler::webHandleTestPush() {
doc.clear(); doc.clear();
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, EspSerial);
Serial.print(CR); EspSerial.print(CR);
#endif #endif
_server->send(200, "application/json", out.c_str()); _server->send(200, "application/json", out.c_str());
LOG_PERF_STOP("webserver-api-test-push"); LOG_PERF_STOP("webserver-api-test-push");
} }
//
// Write file to disk, if there is no data then delete the current file (if it
// exists) = reset to default.
//
bool WebServerHandler::writeFile(String fname, String data) { bool WebServerHandler::writeFile(String fname, String data) {
if (data.length()) { if (data.length()) {
data = urldecode(data); data = urldecode(data);
@ -999,9 +861,6 @@ bool WebServerHandler::writeFile(String fname, String data) {
return false; return false;
} }
//
// Read file from disk
//
String WebServerHandler::readFile(String fname) { String WebServerHandler::readFile(String fname) {
File file = LittleFS.open(fname, "r"); File file = LittleFS.open(fname, "r");
if (file) { if (file) {
@ -1015,63 +874,60 @@ String WebServerHandler::readFile(String fname) {
return ""; return "";
} }
//
// Get format templates
//
void WebServerHandler::webHandleConfigFormatRead() { void WebServerHandler::webHandleConfigFormatRead() {
LOG_PERF_START("webserver-api-config-format-read"); LOG_PERF_START("webserver-api-config-format-read");
Log.notice(F("WEB : webServer callback for /api/config/formula(get)." CR)); Log.notice(F("WEB : webServer callback for /api/config/formula(get)." CR));
DynamicJsonDocument doc(5000); String out;
out.reserve(7000);
doc[PARAM_ID] = myConfig.getID(); out += "{\"id\":\"" + String(myConfig.getID()) + "\",";
String s = readFile(TPL_FNAME_HTTP1); String s = readFile(TPL_FNAME_HTTP1);
out += "\"" + String(PARAM_FORMAT_HTTP1) + "\":\"";
if (s.length()) if (s.length())
doc[PARAM_FORMAT_HTTP1] = urlencode(s); out += urlencode(s);
else else
doc[PARAM_FORMAT_HTTP1] = urlencode(String(&iSpindleFormat[0])); out += urlencode(String(&iSpindleFormat[0]));
s = readFile(TPL_FNAME_HTTP2); s = readFile(TPL_FNAME_HTTP2);
out += "\",\"" + String(PARAM_FORMAT_HTTP2) + "\":\"";
if (s.length()) if (s.length())
doc[PARAM_FORMAT_HTTP2] = urlencode(s); out += urlencode(s);
else else
doc[PARAM_FORMAT_HTTP2] = urlencode(String(&iSpindleFormat[0])); out += urlencode(String(&iSpindleFormat[0]));
s = readFile(TPL_FNAME_HTTP3); s = readFile(TPL_FNAME_HTTP3);
out += "\",\"" + String(PARAM_FORMAT_HTTP3) + "\":\"";
if (s.length()) if (s.length())
doc[PARAM_FORMAT_HTTP3] = urlencode(s); out += urlencode(s);
else else
doc[PARAM_FORMAT_HTTP3] = urlencode(String(&iHttpGetFormat[0])); out += urlencode(String(&iHttpGetFormat[0]));
s = readFile(TPL_FNAME_INFLUXDB); s = readFile(TPL_FNAME_INFLUXDB);
out += "\",\"" + String(PARAM_FORMAT_INFLUXDB) + "\":\"";
if (s.length()) if (s.length())
doc[PARAM_FORMAT_INFLUXDB] = urlencode(s); out += urlencode(s);
else else
doc[PARAM_FORMAT_INFLUXDB] = urlencode(String(&influxDbFormat[0])); out += urlencode(String(&influxDbFormat[0]));
s = readFile(TPL_FNAME_MQTT); s = readFile(TPL_FNAME_MQTT);
out += "\",\"" + String(PARAM_FORMAT_MQTT) + "\":\"";
if (s.length()) if (s.length())
doc[PARAM_FORMAT_MQTT] = urlencode(s); out += urlencode(s);
else else
doc[PARAM_FORMAT_MQTT] = urlencode(String(&mqttFormat[0])); out += urlencode(String(&mqttFormat[0]));
out += "\"}";
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); EspSerial.print(out.c_str());
Serial.print(CR); EspSerial.print(CR);
#endif #endif
String out;
out.reserve(3000);
serializeJson(doc, out);
doc.clear();
_server->send(200, "application/json", out.c_str()); _server->send(200, "application/json", out.c_str());
LOG_PERF_STOP("webserver-api-config-format-read"); LOG_PERF_STOP("webserver-api-config-format-read");
} }
//
// Update hardware settings.
//
void WebServerHandler::webHandleFormulaWrite() { void WebServerHandler::webHandleFormulaWrite() {
LOG_PERF_START("webserver-api-formula-write"); LOG_PERF_START("webserver-api-formula-write");
String id = _server->arg(PARAM_ID); String id = _server->arg(PARAM_ID);
@ -1164,62 +1020,14 @@ void WebServerHandler::webHandleFormulaWrite() {
LOG_PERF_STOP("webserver-api-formula-write"); LOG_PERF_STOP("webserver-api-formula-write");
} }
//
// Helper function to check if files exist on file system.
//
const char* WebServerHandler::getHtmlFileName(HtmlFile item) {
Log.notice(F("WEB : Looking up filename for %d." CR), item);
switch (item) {
case HtmlFile::HTML_INDEX:
return "index.min.htm";
case HtmlFile::HTML_CONFIG:
return "config.min.htm";
case HtmlFile::HTML_CALIBRATION:
return "calibration.min.htm";
case HtmlFile::HTML_FORMAT:
return "format.min.htm";
case HtmlFile::HTML_ABOUT:
return "about.min.htm";
case HtmlFile::HTML_TEST:
return "test.min.htm";
}
return "";
}
//
// Helper function to check if files exist on file system.
//
bool WebServerHandler::checkHtmlFile(HtmlFile item) {
const char* fn = getHtmlFileName(item);
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : Checking for file %s." CR), fn);
#endif
// TODO: We might need to add more checks here like zero file size etc. But
// for now we only check if the file exist.
return LittleFS.exists(fn);
}
//
// Handler for page not found
//
void WebServerHandler::webHandlePageNotFound() { void WebServerHandler::webHandlePageNotFound() {
Log.error(F("WEB : URL not found %s received." CR), _server->uri().c_str()); Log.error(F("WEB : URL not found %s received." CR), _server->uri().c_str());
_server->send(404, "text/plain", F("URL not found")); _server->send(404, "text/plain", F("URL not found"));
} }
//
// Setup the Web Server callbacks and start it
//
bool WebServerHandler::setupWebServer() { bool WebServerHandler::setupWebServer() {
Log.notice(F("WEB : Configuring web server." CR)); Log.notice(F("WEB : Configuring web server." CR));
_server = new ESP8266WebServer(); _server = new ESP8266WebServer();
MDNS.begin(myConfig.getMDNS()); MDNS.begin(myConfig.getMDNS());
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
@ -1238,7 +1046,7 @@ bool WebServerHandler::setupWebServer() {
LittleFS.remove(dir.fileName().c_str()); LittleFS.remove(dir.fileName().c_str());
} }
} }
#else // defined( ESP32 ) #else // ESP32
File root = LittleFS.open("/"); File root = LittleFS.open("/");
File f = root.openNextFile(); File f = root.openNextFile();
while (f) { while (f) {
@ -1255,7 +1063,7 @@ bool WebServerHandler::setupWebServer() {
#endif #endif
// Static content // Static content
#if defined(EMBED_HTML) Log.notice(F("WEB : Setting up handlers for web server." CR));
_server->on("/", std::bind(&WebServerHandler::webReturnIndexHtm, this)); _server->on("/", std::bind(&WebServerHandler::webReturnIndexHtm, this));
_server->on("/index.htm", _server->on("/index.htm",
std::bind(&WebServerHandler::webReturnIndexHtm, this)); std::bind(&WebServerHandler::webReturnIndexHtm, this));
@ -1269,61 +1077,29 @@ bool WebServerHandler::setupWebServer() {
std::bind(&WebServerHandler::webReturnAboutHtm, this)); std::bind(&WebServerHandler::webReturnAboutHtm, this));
_server->on("/test.htm", _server->on("/test.htm",
std::bind(&WebServerHandler::webReturnTestHtm, this)); std::bind(&WebServerHandler::webReturnTestHtm, this));
#else
// Check if the html files exist, if so serve them, else show the static
// upload page.
if (checkHtmlFile(HTML_INDEX) && checkHtmlFile(HTML_CONFIG) &&
checkHtmlFile(HTML_CALIBRATION) && checkHtmlFile(HTML_FORMAT) &&
checkHtmlFile(HTML_ABOUT) && checkHtmlFile(HTML_TEST)) {
Log.notice(F("WEB : All html files exist, starting in normal mode." CR));
_server->serveStatic("/", LittleFS, "/index.min.htm");
_server->serveStatic("/index.htm", LittleFS, "/index.min.htm");
_server->serveStatic("/config.htm", LittleFS, "/config.min.htm");
_server->serveStatic("/about.htm", LittleFS, "/about.min.htm");
_server->serveStatic("/test.htm", LittleFS, "/test.min.htm");
_server->serveStatic("/calibration.htm", LittleFS, "/calibration.min.htm");
_server->serveStatic("/format.htm", LittleFS, "/format.min.htm");
// Also add the static upload view in case we we have issues that needs to
// be fixed.
_server->on("/upload.htm",
std::bind(&WebServerHandler::webReturnUploadHtm, this));
} else {
Log.error(F("WEB : Missing html files, starting with upload UI." CR));
_server->on("/", std::bind(&WebServerHandler::webReturnUploadHtm, this));
}
#endif
_server->on("/firmware.htm", _server->on("/firmware.htm",
std::bind(&WebServerHandler::webReturnFirmwareHtm, this)); std::bind(&WebServerHandler::webReturnFirmwareHtm, this));
_server->serveStatic("/log", LittleFS, ERR_FILENAME); _server->serveStatic("/log", LittleFS, ERR_FILENAME);
_server->serveStatic("/log2", LittleFS, ERR_FILENAME2);
_server->serveStatic("/runtime", LittleFS, RUNTIME_FILENAME); _server->serveStatic("/runtime", LittleFS, RUNTIME_FILENAME);
// Dynamic content // Dynamic content
_server->on( _server->on("/api/clearlog", HTTP_GET,
"/api/config", HTTP_GET, std::bind(&WebServerHandler::webHandleLogClear, this));
std::bind(&WebServerHandler::webHandleConfig, this)); // Get config.json _server->on("/api/config", HTTP_GET,
std::bind(&WebServerHandler::webHandleConfig, this));
_server->on("/api/formula", HTTP_GET, _server->on("/api/formula", HTTP_GET,
std::bind(&WebServerHandler::webHandleFormulaRead, std::bind(&WebServerHandler::webHandleFormulaRead, this));
this)); // Get formula.json (calibration page)
_server->on("/api/formula", HTTP_POST, _server->on("/api/formula", HTTP_POST,
std::bind(&WebServerHandler::webHandleFormulaWrite, std::bind(&WebServerHandler::webHandleFormulaWrite, this));
this)); // Get formula.json (calibration page)
_server->on("/api/calibrate", HTTP_POST, _server->on("/api/calibrate", HTTP_POST,
std::bind(&WebServerHandler::webHandleCalibrate, std::bind(&WebServerHandler::webHandleCalibrate, this));
this)); // Run calibration routine (param id)
_server->on("/api/factory", HTTP_GET, _server->on("/api/factory", HTTP_GET,
std::bind(&WebServerHandler::webHandleFactoryDefaults, std::bind(&WebServerHandler::webHandleFactoryDefaults, this));
this)); // Reset the device
_server->on("/api/status", HTTP_GET, _server->on("/api/status", HTTP_GET,
std::bind(&WebServerHandler::webHandleStatus, std::bind(&WebServerHandler::webHandleStatus, this));
this)); // Get the status.json
_server->on("/api/clearwifi", HTTP_GET, _server->on("/api/clearwifi", HTTP_GET,
std::bind(&WebServerHandler::webHandleClearWIFI, std::bind(&WebServerHandler::webHandleClearWIFI, this));
this)); // Clear wifi settings
_server->on(
"/api/upload", HTTP_GET,
std::bind(&WebServerHandler::webHandleUpload, this)); // Get upload.json
_server->on("/api/upload", HTTP_POST, _server->on("/api/upload", HTTP_POST,
std::bind(&WebServerHandler::webReturnOK, this), std::bind(&WebServerHandler::webReturnOK, this),
@ -1367,9 +1143,6 @@ bool WebServerHandler::setupWebServer() {
return true; return true;
} }
//
// called from main loop
//
void WebServerHandler::loop() { void WebServerHandler::loop() {
#if defined(ESP8266) #if defined(ESP8266)
MDNS.update(); MDNS.update();

View File

@ -29,26 +29,42 @@ SOFTWARE.
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#define MAX_SKETCH_SPACE 1044464 #define MAX_SKETCH_SPACE 1044464
#else // defined (ESP32) #else
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <Update.h> #include <Update.h>
#include <WebServer.h> #include <WebServer.h>
#include <WiFi.h> #include <WiFi.h>
#define MAX_SKETCH_SPACE 1835008 #define MAX_SKETCH_SPACE 1835008
#endif #endif
#include <incbin.h>
#if defined(EMBED_HTML) #if defined(ESP8266)
#include <incbin.h>
INCBIN_EXTERN(IndexHtm); INCBIN_EXTERN(IndexHtm);
INCBIN_EXTERN(ConfigHtm); INCBIN_EXTERN(ConfigHtm);
INCBIN_EXTERN(CalibrationHtm); INCBIN_EXTERN(CalibrationHtm);
INCBIN_EXTERN(FormatHtm); INCBIN_EXTERN(FormatHtm);
INCBIN_EXTERN(TestHtm); INCBIN_EXTERN(TestHtm);
INCBIN_EXTERN(AboutHtm); INCBIN_EXTERN(AboutHtm);
#else
INCBIN_EXTERN(UploadHtm);
#endif
INCBIN_EXTERN(FirmwareHtm); INCBIN_EXTERN(FirmwareHtm);
#else // ESP32
extern const uint8_t indexHtmStart[] asm("_binary_html_index_min_htm_start");
extern const uint8_t indexHtmEnd[] asm("_binary_html_index_min_htm_end");
extern const uint8_t configHtmStart[] asm("_binary_html_config_min_htm_start");
extern const uint8_t configHtmEnd[] asm("_binary_html_config_min_htm_end");
extern const uint8_t calibrationHtmStart[] asm(
"_binary_html_calibration_min_htm_start");
extern const uint8_t calibrationHtmEnd[] asm(
"_binary_html_calibration_min_htm_end");
extern const uint8_t formatHtmStart[] asm("_binary_html_format_min_htm_start");
extern const uint8_t formatHtmEnd[] asm("_binary_html_format_min_htm_end");
extern const uint8_t testHtmStart[] asm("_binary_html_test_min_htm_start");
extern const uint8_t testHtmEnd[] asm("_binary_html_test_min_htm_end");
extern const uint8_t aboutHtmStart[] asm("_binary_html_about_min_htm_start");
extern const uint8_t aboutHtmEnd[] asm("_binary_html_about_min_htm_end");
extern const uint8_t firmwareHtmStart[] asm(
"_binary_html_firmware_min_htm_start");
extern const uint8_t firmwareHtmEnd[] asm("_binary_html_firmware_min_htm_end");
#endif
class WebServerHandler { class WebServerHandler {
private: private:
@ -75,7 +91,7 @@ class WebServerHandler {
void webHandleFactoryDefaults(); void webHandleFactoryDefaults();
void webHandleCalibrate(); void webHandleCalibrate();
void webHandleUploadFile(); void webHandleUploadFile();
void webHandleUpload(); void webHandleLogClear();
void webHandlePageNotFound(); void webHandlePageNotFound();
String readFile(String fname); String readFile(String fname);
@ -85,7 +101,7 @@ class WebServerHandler {
// Inline functions. // Inline functions.
void webReturnOK() { _server->send(_uploadReturn); } void webReturnOK() { _server->send(_uploadReturn); }
#if defined(EMBED_HTML) #if defined(ESP8266)
void webReturnIndexHtm() { void webReturnIndexHtm() {
_server->send_P(200, "text/html", (const char*)gIndexHtmData, _server->send_P(200, "text/html", (const char*)gIndexHtmData,
gIndexHtmSize); gIndexHtmSize);
@ -109,31 +125,46 @@ class WebServerHandler {
void webReturnTestHtm() { void webReturnTestHtm() {
_server->send_P(200, "text/html", (const char*)gTestHtmData, gTestHtmSize); _server->send_P(200, "text/html", (const char*)gTestHtmData, gTestHtmSize);
} }
#else
void webReturnUploadHtm() {
_server->send_P(200, "text/html", (const char*)gUploadHtmData,
gUploadHtmSize);
}
#endif
void webReturnFirmwareHtm() { void webReturnFirmwareHtm() {
_server->send_P(200, "text/html", (const char*)gFirmwareHtmData, _server->send_P(200, "text/html", (const char*)gFirmwareHtmData,
gFirmwareHtmSize); gFirmwareHtmSize);
} }
#else // ESP32
void webReturnIndexHtm() {
_server->send_P(200, "text/html", (const char*)indexHtmStart,
strlen(reinterpret_cast<const char*>(&indexHtmStart[0])));
}
void webReturnConfigHtm() {
_server->send_P(200, "text/html", (const char*)configHtmStart,
strlen(reinterpret_cast<const char*>(&configHtmStart[0])));
}
void webReturnCalibrationHtm() {
_server->send_P(
200, "text/html", (const char*)calibrationHtmStart,
strlen(reinterpret_cast<const char*>(&calibrationHtmStart[0])));
}
void webReturnFormatHtm() {
_server->send_P(200, "text/html", (const char*)formatHtmStart,
strlen(reinterpret_cast<const char*>(&formatHtmStart[0])));
}
void webReturnAboutHtm() {
_server->send_P(200, "text/html", (const char*)aboutHtmStart,
strlen(reinterpret_cast<const char*>(&aboutHtmStart[0])));
}
void webReturnTestHtm() {
_server->send_P(200, "text/html", (const char*)testHtmStart,
strlen(reinterpret_cast<const char*>(&testHtmStart[0])));
}
void webReturnFirmwareHtm() {
_server->send_P(
200, "text/html", (const char*)firmwareHtmStart,
strlen(reinterpret_cast<const char*>(&firmwareHtmStart[0])));
}
#endif
public: public:
enum HtmlFile {
HTML_INDEX = 0,
HTML_CONFIG = 1,
HTML_ABOUT = 2,
HTML_CALIBRATION = 3,
HTML_FORMAT = 4,
HTML_TEST = 5
};
bool setupWebServer(); bool setupWebServer();
void loop(); void loop();
bool checkHtmlFile(HtmlFile item);
const char* getHtmlFileName(HtmlFile item);
}; };
// Global instance created // Global instance created

View File

@ -30,7 +30,6 @@ SOFTWARE.
#include <WiFiClient.h> #include <WiFiClient.h>
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
#endif #endif
#include <incbin.h>
#include <config.hpp> #include <config.hpp>
#include <main.hpp> #include <main.hpp>
@ -59,16 +58,10 @@ WifiConnection myWifi;
const char *userSSID = USER_SSID; const char *userSSID = USER_SSID;
const char *userPWD = USER_SSID_PWD; const char *userPWD = USER_SSID_PWD;
//
// Initialize
//
void WifiConnection::init() { void WifiConnection::init() {
myDRD = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS); myDRD = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS);
} }
//
// Check if we have a valid wifi configuration
//
bool WifiConnection::hasConfig() { bool WifiConnection::hasConfig() {
if (strlen(myConfig.getWifiSSID(0))) return true; if (strlen(myConfig.getWifiSSID(0))) return true;
if (strlen(userSSID)) return true; if (strlen(userSSID)) return true;
@ -76,49 +69,37 @@ bool WifiConnection::hasConfig() {
// Check if there are stored WIFI Settings we can use. // Check if there are stored WIFI Settings we can use.
#if defined(ESP8266) #if defined(ESP8266)
String ssid = WiFi.SSID(); String ssid = WiFi.SSID();
String pwd = WiFi.psk();
#else
ESP_WiFiManager wifiMgr;
String ssid = wifiMgr.WiFi_SSID();
String pwd = wifiMgr.WiFi_Pass();
#endif
if (ssid.length()) { if (ssid.length()) {
Log.notice(F("WIFI: Found credentials in EEPORM." CR)); Log.notice(F("WIFI: Found stored credentials." CR));
myConfig.setWifiSSID(ssid, 0); myConfig.setWifiSSID(ssid, 0);
if (WiFi.psk().length()) myConfig.setWifiPass(WiFi.psk(), 0); if (pwd.length()) myConfig.setWifiPass(pwd, 0);
myConfig.saveFile(); myConfig.saveFile();
return true; return true;
} }
#else // defined( ESP32 )
#warning "Cant read SSID property on ESP32 until a connection has been made!"
#endif
return false; return false;
} }
//
// Check if the wifi is connected
//
bool WifiConnection::isConnected() { return WiFi.status() == WL_CONNECTED; } bool WifiConnection::isConnected() { return WiFi.status() == WL_CONNECTED; }
//
// Get the IP adress
//
String WifiConnection::getIPAddress() { return WiFi.localIP().toString(); } String WifiConnection::getIPAddress() { return WiFi.localIP().toString(); }
//
// Additional method to detect double reset.
//
bool WifiConnection::isDoubleResetDetected() { bool WifiConnection::isDoubleResetDetected() {
if (strlen(userSSID)) if (strlen(userSSID))
return false; // Ignore this if we have hardcoded settings. return false; // Ignore this if we have hardcoded settings.
return myDRD->detectDoubleReset(); return myDRD->detectDoubleReset();
} }
//
// Stop double reset detection
//
void WifiConnection::stopDoubleReset() { myDRD->stop(); } void WifiConnection::stopDoubleReset() { myDRD->stop(); }
//
// Start the wifi manager
//
void WifiConnection::startPortal() { void WifiConnection::startPortal() {
Log.notice(F("WIFI: Starting Wifi config portal." CR)); Log.notice(F("WIFI: Starting Wifi config portal." CR));
@ -137,6 +118,11 @@ void WifiConnection::startPortal() {
ESP_WMParameter deviceName(mdns.c_str()); ESP_WMParameter deviceName(mdns.c_str());
myWifiManager->addParameter(&deviceName); myWifiManager->addParameter(&deviceName);
#if defined(ESP32C3)
Log.notice(F("WIFI: Reducing wifi power for c3 chip." CR));
WiFi.setTxPower(WIFI_POWER_8_5dBm); // Required for ESP32C3 Mini
#endif
myWifiManager->startConfigPortal(WIFI_DEFAULT_SSID, WIFI_DEFAULT_PWD); myWifiManager->startConfigPortal(WIFI_DEFAULT_SSID, WIFI_DEFAULT_PWD);
if (myWifiManager->getSSID(0).length()) { if (myWifiManager->getSSID(0).length()) {
@ -165,17 +151,17 @@ void WifiConnection::startPortal() {
ESP_RESET(); ESP_RESET();
} }
//
// Call the wifi manager in loop
//
void WifiConnection::loop() { myDRD->loop(); } void WifiConnection::loop() { myDRD->loop(); }
//
// Connect to last known access point, non blocking mode.
//
void WifiConnection::connectAsync(int wifiIndex) { void WifiConnection::connectAsync(int wifiIndex) {
WiFi.persistent(true); WiFi.persistent(true);
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
#if defined(ESP32C3)
Log.notice(F("WIFI: Reducing wifi power for c3 chip." CR));
WiFi.setTxPower(WIFI_POWER_8_5dBm); // Required for ESP32C3 Mini
#endif
if (strlen(userSSID)) { if (strlen(userSSID)) {
Log.notice(F("WIFI: Connecting to wifi using hardcoded settings %s." CR), Log.notice(F("WIFI: Connecting to wifi using hardcoded settings %s." CR),
userSSID); userSSID);
@ -188,39 +174,31 @@ void WifiConnection::connectAsync(int wifiIndex) {
} }
} }
//
// Blocks until wifi connection has been found
//
bool WifiConnection::waitForConnection(int maxTime) { bool WifiConnection::waitForConnection(int maxTime) {
#if DEBUG_LEVEL == 6 #if DEBUG_LEVEL == 6
WiFi.printDiag(Serial); WiFi.printDiag(EspSerial);
#endif #endif
int i = 0; int i = 0;
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED) {
delay(100); delay(100);
if (i % 10) Serial.print("."); if (i % 10) EspSerial.print(".");
if (i++ > if (i++ >
(maxTime * 10)) { // Try for maxTime seconds. Since delay is 100ms. (maxTime * 10)) { // Try for maxTime seconds. Since delay is 100ms.
ErrorFileLog errLog; writeErrorLog("WIFI: Failed to connect to wifi %d", WiFi.status());
errLog.addEntry("WIFI: Failed to connect to wifi " +
String(WiFi.status()));
WiFi.disconnect(); WiFi.disconnect();
Serial.print(CR); EspSerial.print(CR);
return false; // Return to main that we have failed to connect. return false; // Return to main that we have failed to connect.
} }
} }
Serial.print(CR); EspSerial.print(CR);
Log.notice(F("WIFI: Connected to wifi %s ip=%s." CR), WiFi.SSID().c_str(), Log.notice(F("WIFI: Connected to wifi %s ip=%s." CR), WiFi.SSID().c_str(),
getIPAddress().c_str()); getIPAddress().c_str());
Log.notice(F("WIFI: Using mDNS name %s." CR), myConfig.getMDNS()); Log.notice(F("WIFI: Using mDNS name %s." CR), myConfig.getMDNS());
return true; return true;
} }
//
// Check what network is the strongest.
//
int WifiConnection::findStrongestNetwork() { int WifiConnection::findStrongestNetwork() {
if (!myConfig.dualWifiConfigured()) { if (!myConfig.dualWifiConfigured()) {
Log.notice(F("WIFI: Only one wifi SSID is configured, skipping scan." CR)); Log.notice(F("WIFI: Only one wifi SSID is configured, skipping scan." CR));
@ -254,9 +232,6 @@ int WifiConnection::findStrongestNetwork() {
return 1; // Second network is the strongest return 1; // Second network is the strongest
} }
//
// Connect to last known access point, blocking mode.
//
bool WifiConnection::connect() { bool WifiConnection::connect() {
/* /*
// Alternative code for connecting to strongest wifi. // Alternative code for connecting to strongest wifi.
@ -302,10 +277,6 @@ bool WifiConnection::connect() {
return true; return true;
} }
//
// This will erase the stored credentials and forcing the WIFI manager to AP
// mode.
//
bool WifiConnection::disconnect() { bool WifiConnection::disconnect() {
Log.notice(F("WIFI: Erasing stored WIFI credentials." CR)); Log.notice(F("WIFI: Erasing stored WIFI credentials." CR));
// Erase WIFI credentials // Erase WIFI credentials
@ -313,10 +284,6 @@ bool WifiConnection::disconnect() {
} }
#if defined(ACTIVATE_OTA) #if defined(ACTIVATE_OTA)
//
//
//
bool WifiConnection::updateFirmware() { bool WifiConnection::updateFirmware() {
if (!_newFirmware) { if (!_newFirmware) {
Log.notice(F("WIFI: No newer version exist, skipping update." CR)); Log.notice(F("WIFI: No newer version exist, skipping update." CR));
@ -332,6 +299,10 @@ bool WifiConnection::updateFirmware() {
String serverPath = myConfig.getOtaURL(); String serverPath = myConfig.getOtaURL();
#if defined(ESP8266) #if defined(ESP8266)
serverPath += "firmware.bin"; serverPath += "firmware.bin";
#elif defined(ESP32C3)
serverPath += "firmware32c3.bin";
#elif defined(ESP32S2)
serverPath += "firmware32s2.bin";
#else // defined (ESP32) #else // defined (ESP32)
serverPath += "firmware32.bin"; serverPath += "firmware32.bin";
#endif #endif
@ -346,9 +317,7 @@ bool WifiConnection::updateFirmware() {
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: { case HTTP_UPDATE_FAILED: {
ErrorFileLog errLog; writeErrorLog("WIFI: OTA update failed %d", ESPhttpUpdate.getLastError());
errLog.addEntry("WIFI: OTA update failed " +
String(ESPhttpUpdate.getLastError()));
} break; } break;
case HTTP_UPDATE_NO_UPDATES: case HTTP_UPDATE_NO_UPDATES:
break; break;
@ -363,9 +332,6 @@ bool WifiConnection::updateFirmware() {
return false; return false;
} }
//
// Download and save file
//
void WifiConnection::downloadFile(HTTPClient &http, String &fname) { void WifiConnection::downloadFile(HTTPClient &http, String &fname) {
#if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Download file %s." CR), fname); Log.verbose(F("WIFI: Download file %s." CR), fname);
@ -378,15 +344,10 @@ void WifiConnection::downloadFile(HTTPClient &http, String &fname) {
f.close(); f.close();
Log.notice(F("WIFI: Downloaded file %s." CR), fname.c_str()); Log.notice(F("WIFI: Downloaded file %s." CR), fname.c_str());
} else { } else {
ErrorFileLog errLog; writeErrorLog("WIFI: Failed to download html-file %d", httpResponseCode);
errLog.addEntry("WIFI: Failed to download html-file " +
String(httpResponseCode));
} }
} }
//
// Check what firmware version is available over OTA
//
bool WifiConnection::checkFirmwareVersion() { bool WifiConnection::checkFirmwareVersion() {
#if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Checking if new version exist." CR)); Log.verbose(F("WIFI: Checking if new version exist." CR));
@ -419,8 +380,7 @@ bool WifiConnection::checkFirmwareVersion() {
#endif #endif
DeserializationError err = deserializeJson(ver, payload); DeserializationError err = deserializeJson(ver, payload);
if (err) { if (err) {
ErrorFileLog errLog; writeErrorLog("WIFI: Failed to parse version.json");
errLog.addEntry(F("WIFI: Failed to parse version.json"));
} else { } else {
#if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Project %s version %s." CR), Log.verbose(F("WIFI: Project %s version %s." CR),
@ -476,9 +436,6 @@ bool WifiConnection::checkFirmwareVersion() {
return _newFirmware; return _newFirmware;
} }
//
// Parse a version string in the format M.m.p (eg. 1.2.10)
//
bool WifiConnection::parseFirmwareVersionString(int (&num)[3], bool WifiConnection::parseFirmwareVersionString(int (&num)[3],
const char *version) { const char *version) {
#if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)

View File

@ -17,7 +17,7 @@ To reduce the need for adding custom endpoints for various services there is an
:alt: Format editor :alt: Format editor
You enter the format data in the text field and the test button will show an example on what the output would look like. If the data cannot be formatted in json it will just be displayed as a long string. You enter the format data in the text field and the test button will show an example on what the output would look like. If the data cannot be formatted in json it will just be displayed as a long string.
The save button will save the current formla and reload the data from the device. The save button will save the current formula and reload the data from the device.
You can also select a template from the list and copy that to the current endpoint. You can also select a template from the list and copy that to the current endpoint.

View File

@ -8,7 +8,7 @@ All the API's use a key called ``ID`` which is the unique device id (chip id). T
GET: /api/config GET: /api/config
================ ================
Retrive the current configuation of the device via an HTTP GET command. Payload is in JSON format. Retrieve the current configuration of the device via an HTTP GET command. Payload is in JSON format.
* ``temp-format`` can be either ``C`` or ``F`` * ``temp-format`` can be either ``C`` or ``F``
* ``gravity-format`` is always ``G`` (plato is not yet supported) * ``gravity-format`` is always ``G`` (plato is not yet supported)
@ -65,6 +65,8 @@ Other parameters are the same as in the configuration guide.
"angle": 90.93, "angle": 90.93,
"gravity": 1.105, "gravity": 1.105,
"battery": 0.04, "battery": 0.04,
"app-ver": "0.1.0",
"app-build": "build",
"platform": "esp8266", "platform": "esp8266",
"runtime-average": 3.12 "runtime-average": 3.12
} }
@ -79,10 +81,12 @@ This API has been removed from 0.9 and merged with /api/status
GET: /api/status GET: /api/status
================ ================
Retrive the current device status via an HTTP GET command. Payload is in JSON format. Retrieve the current device status via an HTTP GET command. Payload is in JSON format.
* ``temp-format`` can be either ``C`` or ``F`` * ``temp-format`` can be either ``C`` or ``F``
* ``platform`` can be either ``esp8266`` or ``esp32`` * ``platform`` can be either ``esp8266``, ``esp32c3``, ``esp32s2`` or ``esp32``
* ``temp-c`` will be set to -273 C if there is no temp sensor
* ``angle`` will be set to 0 if no valid angle is found and -1 if there is no gyro
Other parameters are the same as in the configuration guide. Other parameters are the same as in the configuration guide.
@ -102,6 +106,7 @@ Other parameters are the same as in the configuration guide.
"token2": "token2", "token2": "token2",
"rssi": -56, "rssi": -56,
"app-ver": "0.0.0", "app-ver": "0.0.0",
"app-build": "gitrev",
"mdns": "gravmon", "mdns": "gravmon",
"sleep-interval": 30, "sleep-interval": 30,
"platform": "esp8266", "platform": "esp8266",
@ -112,10 +117,10 @@ Other parameters are the same as in the configuration guide.
GET: /api/config/formula GET: /api/config/formula
======================== ========================
Retrive the data used for formula calculation data via an HTTP GET command. Payload is in JSON format. Retrieve the data used for formula calculation data via an HTTP GET command. Payload is in JSON format.
* ``a1``-``a10`` are the angles/tilt readings (up to 10 are currently supported) * ``a1``-``a10`` are the angles/tilt readings (up to 10 are currently supported)
* ``g1``-``g10`` are the corresponding gravity reaadings in SG or Plato depending on the device-format. * ``g1``-``g10`` are the corresponding gravity readings in SG or Plato depending on the device-format.
.. code-block:: json .. code-block:: json
@ -156,18 +161,19 @@ Used for adjusting some internal constants and other advanced settings. Should b
{ {
"gyro-read-count": 50, "gyro-read-count": 50,
"tempsensor-resolution": 9,
"gyro-moving-threashold": 500, "gyro-moving-threashold": 500,
"formula-max-deviation": 1.6, "formula-max-deviation": 3.0,
"wifi-portal-timeout": 120, "wifi-portal-timeout": 120,
"wifi-connect-timeout": 20, "wifi-connect-timeout": 20,
"push-timeout": 10,
"formula-calibration-temp": 20, "formula-calibration-temp": 20,
"ignore-low-angles": false,
"int-http1": 0, "int-http1": 0,
"int-http2": 0, "int-http2": 0,
"int-http3": 0, "int-http3": 0,
"int-influx": 0, "int-influx": 0,
"int-mqtt": 0 "int-mqtt": 0,
"tempsensor-resolution": 9,
"ignore-low-angles": false
} }
POST: /api/config/advanced POST: /api/config/advanced
@ -233,7 +239,7 @@ Used to update device settings via an HTTP POST command.
Payload should be in standard format used for posting a form. Such as as: `id=value&mdns=value` etc. Key value pairs are shown below. Payload should be in standard format used for posting a form. Such as as: `id=value&mdns=value` etc. Key value pairs are shown below.
* ``temp-format`` can be either ``C`` (Celcius) or ``F`` (Farenheight) * ``temp-format`` can be either ``C`` (Celsius) or ``F`` (Fahrenheit)
.. code-block:: .. code-block::
@ -321,7 +327,7 @@ POST: /api/config/formula
Used to update formula calculation data via an HTTP POST command. Payload is in JSON format. Used to update formula calculation data via an HTTP POST command. Payload is in JSON format.
* ``a1``-``a10`` are the angles/tilt readings (up to 10 are currently supported) * ``a1``-``a10`` are the angles/tilt readings (up to 10 are currently supported)
* ``g1``-``g10`` are the corresponding gravity reaadings (in SG) * ``g1``-``g10`` are the corresponding gravity readings (in SG)
Payload should be in standard format used for posting a form. Such as as: `id=value&mdns=value` etc. Key value pairs are shown below. Payload should be in standard format used for posting a form. Such as as: `id=value&mdns=value` etc. Key value pairs are shown below.
@ -354,7 +360,7 @@ Calling the API's from Python
============================= =============================
Here is some example code for how to access the API's from a python script. Keys should always be Here is some example code for how to access the API's from a python script. Keys should always be
present or the API call will fail. present or the API call will fail. You only need to include the parameters you want to change.
The requests package converts the json to standard form post format. The requests package converts the json to standard form post format.
@ -363,7 +369,7 @@ The requests package converts the json to standard form post format.
import requests import requests
import json import json
host = "192.168.1.1" # IP adress (or name) of the device to send these settings to host = "192.168.1.1" # IP address (or name) of the device to send these settings to
id = "ee1bfc" # Device ID (shown in serial console during startup or in UI) id = "ee1bfc" # Device ID (shown in serial console during startup or in UI)
def set_config( url, json ): def set_config( url, json ):
@ -419,7 +425,7 @@ The requests package converts the json to standard form post format.
"temp-adjustment": 0, # If temp sensor needs to be corrected "temp-adjustment": 0, # If temp sensor needs to be corrected
"gyro-temp": "on", # Use the temp sensor in the gyro instead (on/off) "gyro-temp": "on", # Use the temp sensor in the gyro instead (on/off)
"ble": "red", # Enable ble on esp32 "ble": "red", # Enable ble on esp32
"ota-url": "" # if the device should seach for a new update when active "ota-url": "" # if the device should search for a new update when active
} }
set_config( url, json ) set_config( url, json )

View File

@ -29,14 +29,9 @@ In the platformio config there are 3 targets defined
* gravity-debug; Maximum logging for trouble shooting, deep sleep is disabled. * gravity-debug; Maximum logging for trouble shooting, deep sleep is disabled.
* gravity-release; Standard release * gravity-release; Standard release
* gravity-perf; Standard release but contains code for measuring performance. * gravity32-release: Version for ESP32 mini.
* gravity32-release: Version for ESP32. * gravity32-c3-release: Version for ESP32 C3 mini.
* gravity32-perf: Version for ESP32 but contains code for measuring performance. * gravity32-s2-release: Version for ESP32 S2 mini.
.. note::
There is an experimental ESP32 target but since platformio only supports SDK 1.0.6 and the WIFI connection is really slow compared to ESP8266,
so the recommendation is to wait for support on 2.0.x branch. With the tested version an wifi connection takes 3-8s on a ESP32 compared
to 0.5s on an ESP8266. There is also a bug in OneWire connected to ESP32 that has not been fixed in the main repository yet.
.. warning:: .. warning::
The debug target can be unstable and crash the device under certain circumstanses. Excessive logging to the serial port can cause corruption and crashes. The debug target can be unstable and crash the device under certain circumstanses. Excessive logging to the serial port can cause corruption and crashes.
@ -91,8 +86,6 @@ This is a list of C++ defines that is used to enable/disable functions in the co
- Done include verbose logging in the corresponding class. Excessive logging may crash device. - Done include verbose logging in the corresponding class. Excessive logging may crash device.
* - USE_LITTLEFS * - USE_LITTLEFS
- Use the new filesystem in Ardurino - Use the new filesystem in Ardurino
* - EMBED_HTML
- Html files are included in code, if not defined they are served from the file system.
* - USER_SSID * - USER_SSID
- If defined the device will always use this SSID - If defined the device will always use this SSID
* - USER_SSID_PWD * - USER_SSID_PWD

View File

@ -22,7 +22,7 @@ copyright = '2021-2022, Magnus Persson'
author = 'Magnus Persson' author = 'Magnus Persson'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = '1.1.0' release = '1.2.0'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
@ -31,6 +31,7 @@ release = '1.1.0'
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ extensions = [
'sphinx_copybutton'
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.

View File

@ -23,22 +23,23 @@ URL: (http://gravmon.local)
:alt: Index page :alt: Index page
Configuration is accessed by entering the URL for the device, this will be the mDNS name *device.local* or the IP adress. The following chapter assumes the device name is *gravmon*. Configuration is accessed by entering the URL for the device, this will be the mDNS name *device.local* or the IP address. The following chapter assumes the device name is *gravmon*.
The main page shows the device readings; gravity, angle, temperature and battery charge. If the checkbox is active then the device will never go into sleep mode. This is useful if The main page shows the device readings; gravity, angle, temperature and battery charge. If the checkbox is active then the device will never go into sleep mode. This is useful if
you are collecting angle/tilt for calibration. If this is unchecked the device will change mode as explained before. you are collecting angle/tilt for calibration. If this is unchecked the device will change mode as explained before.
You can also view the average time a gravity measurement takes. Under optimal setting this should be around 1.5 - 2.0 seconds. If this is higher than 2 seconds this is most likley connected to slow wifi You can also view the average time a gravity measurement takes. Under optimal setting this should be around 1.5 - 2.0 seconds. If this is higher than 2 seconds this is most likely connected to slow wifi
connection. It will show 0 if data has not been collected yet. connection. It will show 0 if data has not been collected yet.
.. tip:: .. tip::
If you are connected to the device via a serial console (speed: 115200) you can see the connection sequence and get the Unique ID and IP adress from there. If you are connected to the device via a serial console (speed: 115200) you can see the connection sequence and get the Unique ID and IP address from there.
.. tip:: .. tip::
The button `view error log` will show the last 15 errors on the device. This can be useful for checking errors without The button `view error log` will show the last error messages on the device. This can be useful for checking errors without
the need to connect to the serial port or to check what errors has occured while in `gravity mode`. the need to connect to the serial port or to check what errors has occurred while in `gravity mode`. From v1.1 it will also detect
any abnormal restarts or crashes and record these in the logfile.
Configuration Configuration
@ -60,7 +61,7 @@ The limitation is 63 chars but using long names might break endpoints that data
* **Temperature format:** * **Temperature format:**
Choose between Celsius and Farenheight when displaying temperature. Choose between Celsius and Fahrenheit when displaying temperature.
* **Interval:** * **Interval:**
@ -93,7 +94,7 @@ Push Settings
.. note:: .. note::
When enabling SSL this will not validate the root CA of the remote service, this is a design decision based on two aspects. Enabling CA validation will take 3-4s extra on each connection which means way less When enabling SSL this will not validate the root CA of the remote service, this is a design decision based on two aspects. Enabling CA validation will take 3-4s extra on each connection which means way less
battery life, so the decision is to prioritize battery life over security. The data transmitted is not really that sensitive anyway so I belive this is a good balance. battery life, so the decision is to prioritize battery life over security. The data transmitted is not really that sensitive anyway so I believe this is a good balance.
* **HTTP 1 (POST):** * **HTTP 1 (POST):**
@ -128,7 +129,7 @@ The token is included in the default format for the HTTP GET url but can be used
:width: 300 :width: 300
:alt: HTTP Headers :alt: HTTP Headers
You can define 2 http headers per push target. This is available via a pop-up window but dont forget You can define 2 http headers per push target. This is available via a pop-up window but don't forget
to press the save buttons on the post section to save the values. One common header is content type which is the to press the save buttons on the post section to save the values. One common header is content type which is the
default setting for http targets. default setting for http targets.
@ -196,14 +197,14 @@ Gravity Settings
* **Gravity format:** * **Gravity format:**
Gravity format can be eihter `SG` or `Plato`. The device will use SG Internally and convert to Plato when displaying or sending data. Gravity format can be either `SG` or `Plato`. The device will use SG Internally and convert to Plato when displaying or sending data.
* **Gravity formula:** * **Gravity formula:**
Gravity formula is compatible with standard iSpindle formulas so any existing calculation option can be used. You can also use Gravity formula is compatible with standard iSpindle formulas so any existing calculation option can be used. You can also use
the feature to create the formula by supplying the raw data. See :ref:`create-formula` the feature to create the formula by supplying the raw data. See :ref:`create-formula`
The gravity formula accepts to paramaters, **tilt** for the angle or **temp** for temperature (temperature inserted into the formula The gravity formula accepts to parameters, **tilt** for the angle or **temp** for temperature (temperature inserted into the formula
will be in celsius). I would recommend to use the formula calculation feature instead since this is much easier. will be in celsius). I would recommend to use the formula calculation feature instead since this is much easier.
* **Temperature correct gravity:** * **Temperature correct gravity:**
@ -215,7 +216,7 @@ build this into the gravity formula.
This formula assumes that the calibration has been done at 20°C / 68°F. This formula assumes that the calibration has been done at 20°C / 68°F.
Formula used in temperature correction. Formula used in temperature correction. The calibration temperature can be changed under advanced settings.
:: ::
@ -232,12 +233,13 @@ Hardware Settings
* **Voltage factor:** * **Voltage factor:**
Factor used to calcualate the battery voltage. If you get a too low/high voltage you can adjust this value. Factor used to calculate the battery voltage. If you get a too low/high voltage you can adjust this value.
* **Config voltage:** * **Config voltage:**
Defines the level of voltage when the device should enter config mode due to charging. This might vary between different battery manufacturers. Defines the level of voltage when the device should enter config mode due to charging. This might vary between different battery manufacturers.
If you dont what the device to go into configuration mode when charging, set this to 6V. If you don't what the device to go into configuration mode when charging, set this to 6V. This was added since different batteries have different
voltages when fully charged.
* **Temperature correction:** * **Temperature correction:**
@ -248,14 +250,15 @@ when the device starts. So changing this will not take affect until the device i
Enable this feature will use the temp sensor i the gyro instead of the DS18B20, the benefit is shorter run time and Enable this feature will use the temp sensor i the gyro instead of the DS18B20, the benefit is shorter run time and
longer battery life (this is an experimental feature). The value used is the first temperature reading from when the longer battery life (this is an experimental feature). The value used is the first temperature reading from when the
device is activated, since the gyro should be cool this is reflecting the surronding temperature. After it has device is activated, since the gyro should be cool this is reflecting the surrounding temperature. After it has
been running the value would be totally off. been running the value would be totally off.
* **Enable storage mode when placed on cap** * **Enable storage mode when placed on cap**
When place on the cap (<5 degres tilt) the device will go into max sleep. In order to wake it up you need to do a reset (or wait for the device When place on the cap (<5 degree tilt) the device will go into deep sleep forever (until reset). In order to wake it
to wake up). One option is to attach a magnetic reed switch (default open) to the reset pin and use a magnet to force a reset without opening up you need to do a reset. One option is to attach a magnetic reed switch (default open) to the reset pin and use a
the tube. The reed switch is typically an electronic component of 14 mm long incapsulated in a small glass tube. magnet to force a reset without opening the tube. The reed switch is typically an electronic component of 14 mm
long encapsulated in a small glass tube. See hardware section for more information, :ref:`hardware`.
* **Bluetooth: (Only ESP32)** * **Bluetooth: (Only ESP32)**
@ -287,7 +290,7 @@ This option gives you the possibility to install an new version of the firmware
:alt: Update firmware :alt: Update firmware
Advanded Settings Advanced Settings
+++++++++++++++++ +++++++++++++++++
.. image:: images/config5.png .. image:: images/config5.png
@ -296,27 +299,31 @@ Advanded Settings
.. warning:: .. warning::
Changeing these parameters with caution. The wrong values might cause the device to become unresponsive. Change these parameters with caution. The wrong values might cause the device to become unresponsive.
* **Gyro reads:** * **Gyro reads:**
This defines how many gyro reads will be done before an angle is calculated. More reads will give better accuracy and also allow detection of This defines how many gyro reads will be done before an angle is calculated. More reads will give better accuracy and also allow detection of
movement. Too many reads will take time and affecte batterylife. 50 takes about 800 ms to execute. movement. Too many reads will take time and affect battery life. 50 takes about 800 ms to execute.
* **Gyro moving threashold:** * **Gyro moving threshold:**
This is the max amount of deviation allowed for a stable reading. This is the max amount of deviation allowed for a stable reading.
* **Formula deviation:** * **Formula deviation:**
This is the maximum devation on the formlula allowed for it to be accepted. Once the formula has been derived it will be validated against the supplied This is the maximum deviation on the formula allowed for it to be accepted. Once the formula has been derived it will be validated against the supplied
data and of the deviation on any point is bigger the formula will be rejected. data and of the deviation on any point is bigger the formula will be rejected.
* **Ignore angles below water:** * **Ignore angles below water:**
If this option is checked any angles below that of SG 1 will be discarded as invalid and never sent to any server. Default = off. If this option is checked any angles below that of SG 1 will be discarded as invalid and never sent to any server. Default = off.
* **Gravity calibration temp**
This option allows you to set the correction temperature used in the automatic temperature gravity adjustment formula. Standard is 20C.
* **DS18B20 Resolution:** * **DS18B20 Resolution:**
Define the resolution used on the temp sensor. 9 bits is default and will give an accuracy of 0.5C, 12 bits will give an accuracy of 0.0625C but will also Define the resolution used on the temp sensor. 9 bits is default and will give an accuracy of 0.5C, 12 bits will give an accuracy of 0.0625C but will also
@ -328,11 +335,11 @@ This is the amount of time allowed for a wifi connect.
* **Wifi portal timeout:** * **Wifi portal timeout:**
If the wifi portal is triggered (can be triggerd by reset) then this is the amount of time allowed before it exists again. If the wifi portal is triggered (can be triggered by reset) then this is the amount of time allowed before it exists again.
* **Skip Interval (...):** * **Skip Interval (...):**
These options allow the user to have variable push intervals for the diffrent endpoints. 0 means that every wakeup will send data to that endpoint. If you enter another number then that defines how many sleep cycles will be skipped. These options allow the user to have variable push intervals for the different endpoints. 0 means that every wakeup will send data to that endpoint. If you enter another number then that defines how many sleep cycles will be skipped.
If the sleep interval is 300s and MQTT is set to 0 and HTTP1 is set to 2 then MQTT will be sent every 300s while HTTP1 would be sent 900s. This is great if you want to send data to a local mqtt server often but brewfather will only If the sleep interval is 300s and MQTT is set to 0 and HTTP1 is set to 2 then MQTT will be sent every 300s while HTTP1 would be sent 900s. This is great if you want to send data to a local mqtt server often but brewfather will only
accept data every 15 min. accept data every 15 min.

View File

@ -7,11 +7,11 @@ In order to keep the source code in good condition I use `pre-commit <https://pr
.. note:: .. note::
If you are using Windows as a base platform I would suggest that you install pre-commit under wsl (Windows Subssytem for Windows) and run it from there, I have found If you are using Windows as a base platform I would suggest that you install pre-commit under wsl (Windows Subsystem for Windows) and run it from there, I have found
that this approach works fine. that this approach works fine.
The following command will run pre-commit on all the source files. Assuming you are inte project directory. The following command will run pre-commit on all the source files. Assuming you are in the project directory.
.. code-block:: .. code-block::

View File

@ -134,7 +134,7 @@ version.json
============ ============
Contents version.json. The version is used by the device to check if the this version is newer. The html files will also be downloaded if the are present on the server. This way it's easy to Contents version.json. The version is used by the device to check if the this version is newer. The html files will also be downloaded if the are present on the server. This way it's easy to
upgrade to a version that serve the html files from the file system. If they dont exist nothing will happen, the OTA flashing will still work. If the html files are missing from the file system upgrade to a version that serve the html files from the file system. If they don't exist nothing will happen, the OTA flashing will still work. If the html files are missing from the file system
they can be uploaded manually afterwards. they can be uploaded manually afterwards.
.. code-block:: json .. code-block:: json

View File

@ -9,7 +9,7 @@ Create formula
Here you can enter up to 10 values (angles + gravity) that is then used to create the formula. Angles equal to zero will be regarded as empty even if there is a gravity reading. Here you can enter up to 10 values (angles + gravity) that is then used to create the formula. Angles equal to zero will be regarded as empty even if there is a gravity reading.
When you submit the values the device will try create a forumla with increasing level of complexity. It will start When you submit the values the device will try create a formula with increasing level of complexity. It will start
with a order 2 formula and then try 3 and 4. with a order 2 formula and then try 3 and 4.
Once the formula has been created it will validate the formula against the supplied angles/gravity and if there is a too Once the formula has been created it will validate the formula against the supplied angles/gravity and if there is a too
@ -21,14 +21,14 @@ Under the Error Log you will also find hints to what problem the formula creator
`CALC: Validation failed on angle 33.430000, deviation too large 3.14, formula order 2` `CALC: Validation failed on angle 33.430000, deviation too large 3.14, formula order 2`
This means that the angle 33.43 had a deviation of 5.8 SG and since the default threashold is 3, it will fail. You This means that the angle 33.43 had a deviation of 5.8 SG and since the default threshold is 3, it will fail. You
can also see that it has failed on that point in both a order 2 and 4 formula. can also see that it has failed on that point in both a order 2 and 4 formula.
.. image:: images/qa_1.png .. image:: images/qa_1.png
:width: 400 :width: 400
:alt: Example of deviating value :alt: Example of deviating value
So in this case you can either increase the threashold or remove the angle that has an issue. You can also So in this case you can either increase the threshold or remove the angle that has an issue. You can also
use the graph on the calibration page to identify angles that is probably not correct. use the graph on the calibration page to identify angles that is probably not correct.
.. image:: images/formula2.png .. image:: images/formula2.png

View File

@ -1,6 +1,6 @@
.. _functionallity: .. _functionality:
Functionallity Functionality
============== ==============
The main features The main features
@ -68,7 +68,7 @@ The main features
Currently the device can handle 10 data points which should be enough to get a accurate formula. At least 3 data points Currently the device can handle 10 data points which should be enough to get a accurate formula. At least 3 data points
is needed to get an accurate formula. is needed to get an accurate formula.
* **Customize the data format beeing sent to push targets** * **Customize the data format being sent to push targets**
In order to make it easier to support more targets there is a built in format editor that can be used to In order to make it easier to support more targets there is a built in format editor that can be used to
customize the data that is to be sent. This way you can easily adapt the software to new targets without coding. customize the data that is to be sent. This way you can easily adapt the software to new targets without coding.
@ -79,7 +79,7 @@ The main features
* **Automatic temperature adjustment of gravity reading** * **Automatic temperature adjustment of gravity reading**
If you want to correct gravity based on beer temperature you can do this in the formula but here is a nice If you want to correct gravity based on beer temperature you can do this in the formula but here is a nice
feature that can correct the gravity as a second step making this independant of the formula. feature that can correct the gravity as a second step making this independent of the formula.
* **OTA support from webserver** * **OTA support from webserver**
@ -99,8 +99,8 @@ The main features
* **WIFI connection issues** * **WIFI connection issues**
The software will not wait indefiently for a wifi connection. If it takes longer than 20 seconds to connect then The software will not wait indefinitely for a wifi connection. If it takes longer than 20 seconds to connect then
the device will try the seconday wifi configuration, and that also failes it will go into deep sleep for 60 seconds and then the device will try the secondary wifi configuration, and that also fails it will go into deep sleep for 60 seconds and then
retry later. This to conserve batter as much as possible. retry later. This to conserve batter as much as possible.
* **Use gyro temperature sensor** * **Use gyro temperature sensor**
@ -119,7 +119,7 @@ The main features
:width: 800 :width: 800
:alt: Gyro temp vs DS18B20 :alt: Gyro temp vs DS18B20
* **Celsius or Farenheigt** * **Celsius or Fahrenheit**
You can switch between different temperature formats. GravityMon will always use C for it's internal calculations and You can switch between different temperature formats. GravityMon will always use C for it's internal calculations and
convert to F when displayed. convert to F when displayed.
@ -131,15 +131,15 @@ The main features
* **Stable gyro data** * **Stable gyro data**
The device will read the gyro 50 times to get an accurate reading. If the standad deviation is to high it will not The device will read the gyro 50 times to get an accurate reading. If the standard deviation is to high it will not
use the data since this is inacurate and the device is probably moving, probably do to active fermentation or movement of use the data since this is inaccurate and the device is probably moving, probably do to active fermentation or movement of
fermentation vessel. This sequence takes 900 ms seconds to execute and besides wifi connection this is what consumes the most fermentation vessel. This sequence takes 900 ms seconds to execute and besides wifi connection this is what consumes the most
battery. With more testing this might be changes to either speed up or provide more stable readings. battery. With more testing this might be changes to either speed up or provide more stable readings.
* **Performance measurements** * **Performance measurements**
I've also create a small library to measure execution code in some areas of the code that i know is time consuming. This I've also create a small library to measure execution code in some areas of the code that i know is time consuming. This
way I can find a good balance between performace and quality. This is a lot of help trying to figure out where bottlenecks way I can find a good balance between performance and quality. This is a lot of help trying to figure out where bottlenecks
are in the code and where to put optimization efforts. Examples of real measurements: are in the code and where to put optimization efforts. Examples of real measurements:
* Reading the gyro: 885 ms * Reading the gyro: 885 ms
@ -160,7 +160,7 @@ The main features
Battery life Battery life
------------ ------------
The long term battery test has now been completed. Using a 2200 mA battery and sending data every 5 minutes to a local server on my network. The battery lasted 47 days which is excellet battery life. The long term battery test has now been completed. Using a 2200 mA battery and sending data every 5 minutes to a local server on my network. The battery lasted 47 days which is excellent battery life.
In another test I had a device running with an sleep interval of only 30s with ok wifi connection. The device lasted 12 days which i think is excellent considering the short sleep interval. In another test I had a device running with an sleep interval of only 30s with ok wifi connection. The device lasted 12 days which i think is excellent considering the short sleep interval.
@ -173,7 +173,7 @@ Performance
Since I have the possibility to measure the performance of different function in the code this is what I have been able to gather. Since I have the possibility to measure the performance of different function in the code this is what I have been able to gather.
The typical runtime in a measurement cycle is approx 2 seconds and in some cases it can take up to 6-8 seconds but this is mainly related to establishing the WIFI connection. So stable wifi is The typical runtime in a measurement cycle is approx 2 seconds and in some cases it can take up to 6-8 seconds but this is mainly related to establishing the WIFI connection. So stable wifi is
essential for long batterylife. Out of the 2 seconds of run-time the major time is spent on gyro readings (1.3s) and temperature measurements of (0.6s) so using the gyro sensor for measureing essential for long battery life. Out of the 2 seconds of run-time the major time is spent on gyro readings (1.3s) and temperature measurements of (0.6s) so using the gyro sensor for measuring
temperature would reduce the total runtime with 25%. Sending data over http takes less than 100ms (on my local network) so this is not drawing much power. temperature would reduce the total runtime with 25%. Sending data over http takes less than 100ms (on my local network) so this is not drawing much power.
The image below shows how the run-time varies over time. The pink line is the wifi connection time and this is why the time varies. The orange is the total runtime for the awake period. The image below shows how the run-time varies over time. The pink line is the wifi connection time and this is why the time varies. The orange is the total runtime for the awake period.

View File

@ -3,43 +3,104 @@
Hardware Hardware
######## ########
There are lots of resouces out there on how to build the hardware for an iSpindle so I will not go into details on that part. Here are two of my builds using the iSpindle PCB v4. iSpindle based on esp8266
=========================
.. image:: images/ispindel.jpg There are lots of resouces out there on how to build the hardware for an iSpindle so I will not go into details on that part. I typically use one of the
excellent pcb boards that, for example the iSpindel PCB v4.0 from Cherry Philip. Here is one of my standard builds using an esp8266.
.. image:: images/ispindel_esp8266.jpg
:width: 500 :width: 500
:alt: Builds of iSpindel :alt: iSpindle esp8266
It's possible to use this PCB and mount an ESP32 on top of that. It must be an pin compatible ESP32 and the one I used was called *ESP32 d1 mini*. Since this is the same width as the PCB you need to
mount it really close to the PCB in order for it to fit in the PET tube/container. I also had to smooth the edge of the ESP32 in order for it to fit.
I would suggest that you try how it fits into the PET tube before soldering it to the PCB. Make sure that the battery is attached since this will be a really tight fit.
You also need to desolder (remove) the RED ON LED from the ESP32 or the battery power will be reduced a lot.
Final thing is to add a resistor between A0 (Analog PIN) and ground of 470k. The reason is that the esp8266 has a build in resistor which
the esp32 does not have. So in order to get a valid voltage (less than 3.2V) on the A0 pin this is needed. Once the modification is done you might
need to adjust the voltage factor so the battery reading is correct.
.. image:: images/esp32.jpg
:width: 500
:alt: Mounting esp32
Schema for esp8266 build Schema for esp8266 build
------------------------ ++++++++++++++++++++++++
.. image:: images/schema_esp8266.png .. image:: images/schema_esp8266.png
:width: 700 :width: 700
:alt: Schema esp8266 :alt: Schema esp8266
iSpindle based on esp32
=======================
I've experimented with porting my software version to esp32 and this is a selection of options i have been testing.
.. warning::
Work to support esp32s2 is still ongoing, ESP32-mini and ESP32c3-mini is confirmed to be working. However I would recommend the C3 variant.
.. image:: images/esp32_hardware.jpg
:width: 500
:alt: iSpindle esp32 hardware options
* esp32 mini, this was the first board i tried which is a smaller form factor of the first generetion esp32 with 2 cores. Slow on connecting to wifi is the main downside.
* esp32c3 mini, a newer version based on the latest risc v7 architecture, is seen as the replacement for the esp8266 with bluetooth support.
* esp32s2 mini, similar to the c3 board but without bluetooth support.
It's possible to use this PCB and mount an ESP32 mini on top of that (c3 and s2 are prefered). The esp32 mini is a larger formfactor and can be hard to fit into the tube.
.. note::
You need to add a resistor between A0 (Analog PIN) and ground of 470k. The reason is that the esp8266 has a build in resistor for a voltage divider
which the esp32 does not have. So in order to get a valid voltage (less than 3.2V) on the A0 pin this is needed. Once the modification is done you might
need to adjust the voltage factor so the battery reading is correct.
ESP32c3 mini
++++++++++++
This is model is now fully supported by gravitymon.
.. image:: images/ispindel_esp32c3.jpg
:width: 500
:alt: Esp32c3 mini build
Here is an image of where I added the resistor for the voltage divider.
.. image:: images/esp32_res.jpg
:width: 500
:alt: Esp32c3 adding resistor as voltage dividier.
ESP32s2 mini
++++++++++++
Work in progress...
ESP32 d1 mini
+++++++++++++
I would suggest that you try how it fits into the PET tube before soldering it to the PCB. Make sure that the battery is attached since this will be a really tight fit.
.. image:: images/ispindel_esp32.jpg
:width: 500
:alt: Esp32 mini build
Schema for esp32 build Schema for esp32 build
---------------------- ++++++++++++++++++++++
.. note:: .. note::
This schema assumes that an ESP32 D1 Mini (pin compatible with ESP8266 D1 Mini is used) This schema assumes that an ESP32 D1 Mini (pin compatible with ESP8266 D1 Mini is used). The ESP32 has two rows of pins but
The ESP32 has two rows of pins but only the inner row is used. The main difference is the added resistor R3 so we only the inner row is used. The main difference is the added resistor R3 so we get a voltage divider for measuring battery.
get a voltage divider for measuring battery. The ESP8266 has a built in resistor thats not visible on the schema. The ESP8266 has a built in resistor thats not visible on the schema and this acts as a voltage divider.
.. image:: images/schema_esp32.png .. image:: images/schema_esp32.png
:width: 700 :width: 700
:alt: Schema esp32 :alt: Schema esp32
Adding a reed (magnetic) reset switch
=====================================
A reed switch is a switch that reacts to magnetic fields. The ones I have tested are normally open and close in proximity to
a magnet.
.. image:: images/reed.jpg
:width: 400
:alt: Reed switch
If this is connected to the reset button a magnet can be used to trigger a reset of the device. The image below shows how
I mounted the iSPINDLE PCB v4.0 just under the cap. The lower red circle shows the reset connection point for the reed switch.
The reed switch is the glass tube visible under the esp8266.
.. image:: images/reed_build.jpg
:width: 400
:alt: Reed build

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 931 KiB

After

Width:  |  Height:  |  Size: 888 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -7,66 +7,91 @@ Welcome to GravityMon's documentation!
###################################### ######################################
.. note:: .. note::
This documentation reflects **v1.1 BETA 2**. Last updated 2022-07-23 This documentation reflects **v1.2 - beta 1**. Last updated 2022-10-15
* Docs for: `v1.0 <https://mp-se.github.io/gravitymon/v1.0/index.html>`_ User interface overview
* Docs for: `v0.9 <https://mp-se.github.io/gravitymon/v0.9/index.html>`_ -----------------------
This animation shows how the user interface is structured, it reflects an older version but the structure is the same.
.. image:: images/gravitymon.gif .. image:: images/gravitymon.gif
:width: 800 :width: 800
:alt: User Inteface Walkthrough :alt: User Inteface Walkthrough
.. _main_features:
Main features
-------------
* Support either an ESP8266-d1-mini, ESP32-mini or ESP32C3-mini board (see :ref:`hardware`)
* Operates in two modes gravity monitoring and configuration mode
* Gravity mode is comparable to how the iSpindle works when collecting data
* Configuration mode has a modern HTML5 based web UI. No need to start the access point to change settings
* Offloading some of the functionality to run in the web browser, this allows for more advanced features.
* REST API to enable scripted configuration
* Send data to multiple endpoints and services at once (2xHTTP POST, HTTP GET, MQTT, INFLUXDB2)
* Directly test all endpoints from user interface with feedback to simplify troubleshooting
* Complete format customization for all endpoints using templates (don't really need to change the software to support new services)
* Setup guides for how to send data to many popular services. Currently 10+ are documented
* Automatic temperature adjustment of gravity (just tick a checkbox)
* OTA support from webserver
* Firmware update via web interface
* Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity and let GravityMon creates a formula
* Visual graph showing how formula will be interpreted based on entered values
* Using the temperature sensor in gyro instead of DS18B20 (faster)
* SSL support in all endpoints (no certificate validation due to limitations on esp8266).
* Built in performance measurements (used to optimize code)
* Storage mode when placed on cap (indefinite sleep)
* Customize various hardware parameters to optimize device functionality.
For a complete breakdown see the :ref:`functionality`
.. note::
If you are missing some feature, please reach out on `Github <https://github.com/mp-se/gravitymon/discussions>`_ or `homebrewtalk.com <https://www.homebrewtalk.com/threads/replacement-firmware-for-ispindel-gravitymon.698058/>`_
What is GravityMon?
--------------------
GravityMon is used to measure gravity and temperature during fermentation of beer and report the progress. The graph below is GravityMon is used to measure gravity and temperature during fermentation of beer and report the progress. The graph below is
an example on how the fermentation process can be tracked. This is from my last brew that was over on a few days. The graph is rendered using an example on how the fermentation process can be tracked. The graph has been rendered using Fermentrack.
Fermentrack.
.. image:: images/fermentation.png .. image:: images/fermentation.png
:width: 500 :width: 500
:alt: Example fermentation :alt: Example fermentation
GravityMon is a replacement firmware for the iSpindle and uses the same hardware configuration and is 100% compatible. It GravityMon is a replacement firmware for the iSpindle and uses the same hardware configuration and is 100% compatible. It
implements a lot of the features that has been requested in the orginal iSpindle project but has been rejected for implements a lot of the features that has been requested in the original iSpindle project but never implemented for
various reasons. Here is a list of :ref:`main_features`. various reasons. Here is a list of :ref:`main_features`.
From v0.9 the firmware now supports a iSpindle build based on an ESP32 d1 mini (pin compatible with esp8266). See :ref:`hardware`. From v0.9 the firmware also supports a iSpindle built using an ESP32 d1 mini (pin compatible with esp8266). Currently this is an experimental
version but since it has more memory and processing capacity it could support more functions. See :ref:`hardware`.
I started GravityMon because I like to create software and wanted to do some low level programming. I had done a few I started GravityMon because I like to create software and wanted to do some microcontroller programming. I had done a few
projects based on esp8266 and also started to brew beer so this combination was quite natural. projects based on esp8266 and also started to brew beer so this combination was quite natural.
The hardware design comes from the fantastic iSpindle project so that is not covered in this documentation. For more The hardware design comes from the fantastic iSpindle project so that is not covered in this documentation. For more
information on this topic and function please visit `iSpindel Homepage <https://www.ispindel.de>`_ . information on this topic and function please visit `iSpindel Homepage <https://www.ispindel.de>`_ .
My approach to this software is a little different from that the original iSpindle firmware. The github repository My approach to this software is a little different from that the original iSpindle firmware as can be seen in the list of features.
can be found here; `GravityMon on Github <https://github.com/mp-se/gravitymon>`_
The github repository can be found here; `GravityMon on Github <https://github.com/mp-se/gravitymon>`_
.. note:: .. note::
I dont take responsibility for any errors or issues caused by the software. The software is provided as-is. I will however I don't take responsibility for any errors or issues caused by the software. The software is provided as-is. I will however
try my best to fix issues that might occur. try my best to fix issues that might occur.
I have tested this software over the last year on 20+ brews with good results. I have tested this software on 40+ brews with good results.
.. _main_features:
Main features: Documentation for older versions
-------------- --------------------------------
* Operates in two modes gravity monitoring and configuration mode (simplify calibration). Gravity mode * Docs for: `v1.0 <https://mp-se.github.io/gravitymon/v1.0/index.html>`_
is comparable to how the iSpindle works. * Docs for: `v0.9 <https://mp-se.github.io/gravitymon/v0.9/index.html>`_
* Modern web based UI when in configuration mode. No need to start the access point changing settings.
* REST API to enable scripted configuration
* Send data to multiple endpoints and services at once
* Setup guides for how to send data to many popular services. Currently 8+ are documented.
* Automatic temperature adjustment of gravity reading
* OTA support from webserver
* Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity and
let GravityMon create the formula.
* Visual graph showing how formula will be interpreted based on entered values
* Using the temperature sensor in gyro instead of DS18B20 (faster)
* SSL support in standard HTTP and MQTT connections.
* Option to customize data posted to endpoints using template from the UI.
* Built in performance measurements (used to optimise code)
For a complete breakdown see the :ref:`functionallity`
Software architecture
---------------------
This is a simple overview of the different components that the software contains. The green ones are only active during `configuration mode` in This is a simple overview of the different components that the software contains. The green ones are only active during `configuration mode` in
order to save battery. order to save battery.
@ -78,8 +103,8 @@ order to save battery.
Credits to Credits to
---------- ----------
Ideas to some of these functions have been picked up from disucssions in the iSpindle forums. This software uses Ideas to some of these functions have been picked up from discussions in the iSpindle forums. This software uses
the following libraries and without these this would have been much more difficult to acheive: the following libraries and without these this would have been much more difficult to achieve:
* https://github.com/jrowberg/i2cdevlib * https://github.com/jrowberg/i2cdevlib
@ -87,7 +112,7 @@ the following libraries and without these this would have been much more difficu
* https://github.com/codeplea/tinyexpr * https://github.com/codeplea/tinyexpr
Proccess the gravity formula and calculate the gravity and various corrections. Process the gravity formula and calculate the gravity and various corrections.
* https://github.com/graphitemaster/incbin * https://github.com/graphitemaster/incbin
@ -123,7 +148,7 @@ the following libraries and without these this would have been much more difficu
* https://github.com/256dpi/arduino-mqtt * https://github.com/256dpi/arduino-mqtt
Library for sending data to mqtt based on lightweight mqtt implemenentation. Library for sending data to mqtt based on lightweight mqtt implementation.
* https://graphjs.com/ * https://graphjs.com/
@ -151,7 +176,7 @@ the following libraries and without these this would have been much more difficu
intro intro
releases releases
functionallity functionality
installation installation
configuration configuration
troubleshooting troubleshooting

View File

@ -12,7 +12,7 @@ You have these 3 options for flashing this firmware.
Brewflasher Brewflasher
=========== ===========
The prefered option for flashing GravityMon is using BrewFlasher, its a tools that support many brewing related firmwares for ESP8266 and ESP32. This works The preferred option for flashing GravityMon is using BrewFlasher, its a tools that support many brewing related firmwares for ESP8266 and ESP32. This works
on both Windows and Mac. You can download the latest version from here: `Brewflasher <https://www.brewflasher.com/>`_ there is also a web based version on both Windows and Mac. You can download the latest version from here: `Brewflasher <https://www.brewflasher.com/>`_ there is also a web based version
available here `Brewflasher WEB <https://web.brewflasher.com/>`_. available here `Brewflasher WEB <https://web.brewflasher.com/>`_.
@ -23,30 +23,30 @@ available here `Brewflasher WEB <https://web.brewflasher.com/>`_.
Binaries Binaries
******** ********
In the /bin directory you will find 3 different firmware builds; In the /bin directory you will find 4 different firmware builds;
* **firmware.bin** * **firmware.bin**
This is the standard release build (prefered version) This is the standard release build (preferred version)
* **firmware-perf.bin**
This version also submits performance data to an influx database with detailed execution times.
* **firmware32.bin** * **firmware32.bin**
This is the standard release build for an ESP32 variant. When flashing an ESP32 you also need the **partition32.bin** file that outlines the flash memory structure. Due to This is the release build for an ESP32-d1-mini variant. When flashing an ESP32 you also need the *partition32.bin* file that outlines the flash memory structure. Due to
the size of the firmware we are using a custom partition setup. the size of the firmware we are using a custom partition setup.
In these versions all the html files are embedded in the binaries. The file system is currently only used for storing * **firmware32c3.bin**
the configuration file.
If the software becomes so large the html files can be moved to the file system, but this is not enabled by This is the release build for an ESP32c3-mini variant. When flashing an ESP32 you also need the *partition32c3.bin* file that outlines the flash memory structure. Due to
default (see compiling for details). This approach makes installation much easier and ensure that html files the size of the firmware we are using a custom partition setup.
and code is in sync.
Esptool * **firmware32s2.bin**
=======
This is the release build for an ESP32s2-mini variant. When flashing an ESP32 you also need the *partition32s2.bin* file that outlines the flash memory structure. Due to
the size of the firmware we are using a custom partition setup.
Esptool (esp8266)
=================
The other option for flashing esp8266 device is via the official esptool. Documentation can be found The other option for flashing esp8266 device is via the official esptool. Documentation can be found
here; `esptool home page <https://docs.espressif.com/projects/esptool/en/latest/esp32/>`_ here; `esptool home page <https://docs.espressif.com/projects/esptool/en/latest/esp32/>`_
@ -61,11 +61,11 @@ If there are issues you can try do erase the flash first using this command;
``esptool.py --port COM4 erase_flash`` ``esptool.py --port COM4 erase_flash``
iSpindel iSpindel (esp8266)
======== ==================
If you already have the device flashed with iSpindel firmware you can go into the configuration mode where you will find If you already have the device flashed with iSpindel firmware you can go into the configuration mode where you will find
an option for updating firmware. The option is under the maintence meny. an option for updating firmware. The option is under the maintenance menu.
Select the esp8266 version of the firmware called firmware.bin and press upload. Select the esp8266 version of the firmware called firmware.bin and press upload.
@ -101,9 +101,21 @@ To check output from the device (logs) there are several tools out there. I foun
Just select a baud rate of 115200, 8N1. Just select a baud rate of 115200, 8N1.
.. image:: images/serial.png .. image:: images/serial.png
:width: 800 :width: 600
:alt: Serial output :alt: Serial output
On the build for esp32c3 the serial output is written to UART0 which is connected to the RX/TX pins on the chip. This way the serial output can be viewed
without a connection to the USB port, convinient when running the device on battery power.
You need a USB to TTL cable that you connect the TX, RX and GND pins. **Dont connect the power pin** if you are powering the device from USB or Battery.
.. image:: images/usb-ttl.jpg
:width: 300
:alt: USB to TTL cable
.. image:: images/serial_esp32c3.jpg
:width: 300
:alt: Serial output ESP32c3
.. _setup_wifi: .. _setup_wifi:
@ -113,24 +125,24 @@ Configuring WIFI
When the device is flashed it will need to have WIFI configuration in order to work. If you have used other software on When the device is flashed it will need to have WIFI configuration in order to work. If you have used other software on
the device its possible that wifi settings already exist. the device its possible that wifi settings already exist.
If this is not configured in the device it will create an wirless access point called `GravMon`. The default password is `password`. If this is not configured in the device it will create an wireless access point called `GravMon`. The default password is `password`.
Connect to this AP and enter the SSID and password you want to use. If the web page dont open automatically you can enter the following adress Connect to this AP and enter the SSID and password you want to use. If the web page don't open automatically you can enter the following address
in the browser: **http://192.168.4.1** in the browser: **http://192.168.4.1**
Before pressing save on the network infomration, make a note of the devicename that is shown on the screen, this will be the name that is used Before pressing save on the network information, make a note of the devicename that is shown on the screen, this will be the name that is used
in the next step to access the configuration pages. The link would look like this: **http://gravitymon56EA34.local** in the next step to access the configuration pages. The link would look like this: **http://gravitymon56EA34.local**
.. note:: .. note::
When selecting a SSID in the list this will be populated in both wifi fields. This is the behaviour of the wifi manager library that I'm using, When selecting a SSID in the list this will be populated in both wifi fields. This is the behaviour of the wifi manager library that I'm using,
in the future this is planned to be moved to the normal UI. in the future this is planned to be moved to the normal UI.
Under wifi settings you can define a primary and seconday wifi SSID. The seconday will be used in case the primary fails. If the seconday is Under wifi settings you can define a primary and secondary wifi SSID. The secondary will be used in case the primary fails. If the secondary is
successful then it will be used as primary. *The second wifi setting is optional and not needed.* successful then it will be used as primary. *The second wifi setting is optional and not needed.*
.. image:: images/wifi.png .. image:: images/wifi.png
:width: 200 :width: 300
:alt: Wifi page :alt: Wifi page
@ -141,10 +153,10 @@ Finding the device adress
Once the wifi network settings have been added then the device will reboot and connect to your network. If the blue led is flashing then it's up and running and is ready to be configured. Once the wifi network settings have been added then the device will reboot and connect to your network. If the blue led is flashing then it's up and running and is ready to be configured.
If your computer supports mDNS the adress you saw before can be used in your web browser to connect to the device. Windows does not have the best support for mDNS so if you are having issues If your computer supports mDNS the address you saw before can be used in your web browser to connect to the device. Windows does not have the best support for mDNS so if you are having issues
with finding the network name you can try the following: with finding the network name you can try the following:
* Check your wireless router for the IP adress and use that to connect instead, for example; http://192.168.1.56 * Check your wireless router for the IP address and use that to connect instead, for example; http://192.168.1.56
* Download an IP scanner / Port Scanner on your Windows computer or mobile device and use that to find what devices are listening on port 80. * Download an IP scanner / Port Scanner on your Windows computer or mobile device and use that to find what devices are listening on port 80.
Once you can access the user interface then proceed to the next step. Once you can access the user interface then proceed to the next step.

View File

@ -3,7 +3,7 @@
Getting started Getting started
=============== ===============
First you need a completed iSpindle hardware, there are several resouces around that topic so it First you need a completed iSpindle hardware, there are several resources around that topic so it
will not be covered in this documentation. Please visit `iSpindel Homepage <https://www.ispindel.de>`_ for will not be covered in this documentation. Please visit `iSpindel Homepage <https://www.ispindel.de>`_ for
more information. more information.
@ -29,7 +29,7 @@ Step 3 - Configuration
---------------------- ----------------------
Once the device can connect to WIFI it will go into `configuration mode` and start a web server for Once the device can connect to WIFI it will go into `configuration mode` and start a web server for
doing the initial configuration. In order to access the device you will need to find its name or ip adress. doing the initial configuration. In order to access the device you will need to find its name or ip address.
It will broadcast a name like gravitymonXXXXXX.local over mDNS. Where the XXXXXX is the unique device id. You can It will broadcast a name like gravitymonXXXXXX.local over mDNS. Where the XXXXXX is the unique device id. You can
find the name via an mDNS browser, check your router or connect the device to a serial monitor. On windows mDNS find the name via an mDNS browser, check your router or connect the device to a serial monitor. On windows mDNS
@ -50,7 +50,7 @@ Configuration - Device Settings - Gyro Calibration
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++
You need to place the device on a flat surface and then press the You need to place the device on a flat surface and then press the
calibrate button. It will take a few seconds for this to complete and the angle should be close to 90 degress. Without calibrate button. It will take a few seconds for this to complete and the angle should be close to 90 degrees. Without
calibration the device will not go into gravity mode. calibration the device will not go into gravity mode.
Configuration - Push Settings Configuration - Push Settings
@ -65,7 +65,7 @@ previous calibration then you can add them here, if not follow the calibration g
There are several guides for how to calibrate the device (`iSpindle Calibration <https://www.ispindel.de/docs/Calibration_en.html>`_) There are several guides for how to calibrate the device (`iSpindle Calibration <https://www.ispindel.de/docs/Calibration_en.html>`_)
This will get the data points needed to create the formula, and the datapoints will be stored on the device so you can This will get the data points needed to create the formula, and the data points will be stored on the device so you can
adjust them when needed. adjust them when needed.
Step 4 - Completed Step 4 - Completed

View File

@ -4,14 +4,14 @@ Q & A
My device is no going in to sleep after fully charged My device is no going in to sleep after fully charged
----------------------------------------------------- -----------------------------------------------------
- Calibrate the device in the web interface - Calibrate the device in the web interface
- Check the angle/tilt. If the device is reporting 90 degress then its not going into sleep. Tilt the device and check if sleep works. - Check the angle/tilt. If the device is reporting 90 degrees then its not going into sleep. Tilt the device and check if sleep works.
- Check in reported voltage of the battery in the web interface. If this is higher than 4.15V the device belives its beeing charged. In that case adjust the voltage factor under hardware so the voltage drops below 4.15V. - Check in reported voltage of the battery in the web interface. If this is higher than 4.15V the device believes its being charged. In that case adjust the voltage factor under hardware so the voltage drops below 4.15V.
- Check if the `always on` option is activated in the web interface. - Check if the `always on` option is activated in the web interface.
My device reports a temperature of -273C or -491F My device reports a temperature of -273C or -491F
------------------------------------------------- -------------------------------------------------
- The DS18B20 temperature sensor cannot be found and this is the default value reported in this case. - The DS18B20 temperature sensor cannot be found and this is the default value reported in this case.
- Check the orienation of the sensor and soldering. - Check the orientation of the sensor and soldering.
Calibration error (unable to find a valid formula) Calibration error (unable to find a valid formula)
-------------------------------------------------- --------------------------------------------------
@ -28,16 +28,16 @@ To fix these this you can;
- remove the value from the list (setting the angle to zero will do that) - remove the value from the list (setting the angle to zero will do that)
- change the advanced setting (Formula max deviation) to a higher value and save the values again. - change the advanced setting (Formula max deviation) to a higher value and save the values again.
In the case above this paramater was changed from 1.6 SG to 4 SG and the formula was accepted. The deviation on this point was just above 3 SG. In the case above this parameter was changed from 1.6 SG to 4 SG and the formula was accepted. The deviation on this point was just above 3 SG.
User interface does not render correctly User interface does not render correctly
---------------------------------------- ----------------------------------------
Since the user interface is built using bootstrap v5 the device requires access to the internet Since the user interface is built using bootstrap v5 the device requires access to the internet
to download required javascripts and css files. Due to size it would not be possible to store these to download required javascript and css files. Due to size it would not be possible to store these
on the device. Make sure the device can access: https://cdn.jsdelivr.net/npm/bootstrap on the device. Make sure the device can access: https://cdn.jsdelivr.net/npm/bootstrap
Data is not popoulated in the fields Data is not populated in the fields
------------------------------------ ------------------------------------
The user interface uses JQuery to fetch data from the device. This javascript library needs to be downloaded The user interface uses JQuery to fetch data from the device. This javascript library needs to be downloaded

View File

@ -3,35 +3,83 @@
Releases Releases
######## ########
v1.1.0 - beta 2 v1.2.0 - beta1
=============== ==============
Documentation
+++++++++++++
* Fixed errors in data format section
* Added q&a on formula creation and value deviation
* Added documentation for Brewpiless as target
* Updated docs for ubidots service integration.
* Added brewblox as new service
* (beta2) Updated docs for HA integration since method was depricated
User interface
++++++++++++++
* Under format options its now possible to select brewfather ispindle format to avoid mixing endpoints.
* Added brewblox as format under format options.
* User can now edit the voltage level that forces the device into config mode (charging)
* (beta2) Calibration temperature (for temp adjustment) can now be set under advanced settings.
* (beta2) Changes length of device name from 12 to 63 chars. 63 is the max limit according to mdns.
Features Features
++++++++ ++++++++
* Added storage mode which is activated under hardware setting. When place on the cap (<5 degres tilt) the device will go into storage mode and sleep for the max allowed time. * Added support for the ESP32 C3 mini board
* Added ${app-ver} and ${app-build} to format template as new variables. * Serial output is written to TX/RX pins instead of the USB connection for the ESP32c3. This way the serial console can be viewed when running on battery power.
* Added format templates for HA auto registration
* (beta2) Improved error messages when creating formula so the meaasurement points can be identified. Issues adressed
* (beta2) Changed defaule validation threashold from 1.6 SG to 3.0 SG, this should allow for some more variance when creating formula. ++++++++++++++++
* (beta2) Updated format template for Home Assistant for using manual configuration (Aligned with new mqtt configuration format) * BUG: The first portion of a format template was lost when doing conversion.
* (beta2) Added format template for Home Assistant with automatic device registration
Documentation
+++++++++++++
* Updated hardware section with options for ESP32 boards
* Updated installation instructions.
v1.1.1
======
* BUG: The text before the first variable was missed in the conversion of a format template.
v1.1.0
======
Features
++++++++
* Added information to error log about abnormal resets (for instance crashes) to detect and fix those
* Changed storage mode so that the device will go into deep sleep until reset (sleep forever)
* Updated sensor types in home assistant for auto registration of device
* Added ${app-ver} and ${app-build} to format template as new variables
* Improved error messages when creating formula so the troublesome measurement points can be identified
* Changed default validation threshold from 1.6 SG to 3.0 SG, this should allow for some more variance when creating formula
* Updated format template for Home Assistant, aligned with new mqtt configuration format
* Added format template for Home Assistant with automatic device registration
* Added storage mode which is activated under hardware setting. When place on the cap (<5 degree tilt) the device will go into storage mode and deep sleep.
Known issues, not yet fixed
+++++++++++++++++++++++++++
* When updating firmware and the feature `deep sleep` is active the device will activate deep sleep if the gyro is not responding. FIX: Reboot device
Issues addressed
++++++++++++++++
* Refactored error logging function to reduce memory usage and crashes. Max size of error log is 2 x 4 kb
* Refactored format template engine to reduce memory usage and crashes, can how handle slightly larger payloads than before. Increase from around 1100 chars to 1600 chars
* BUG: Refactored format api to handle larger payloads
* BUG: After manual firmware upload the device would crash and go into wifi setup mode.
* BUG: After manual firmware upload the device will in some cases not be able to connect with the gyro, the symptom is that it will say, "Gyro moving" in the web UI. In this case the device needs to be reset (or powered on/off). I havent found a way to fix this from the code. The message after firmware update has been updated with this information
* BUG: Temp corrected gravity was not used when pushing data to removed
* BUG: Low memory in format api which resulted in mqtt template to be set to null
* BUG: Large format templates could be saved but when loading it's only blank
* BUG: Copy format templates used an old format for iSpindle and Gravmon where the token was not used
* BUG: Gravity correction formula not calculating correctly
User interface
++++++++++++++
* Updated format template with information on size and warning message if the template is too large
* Added error message if gyro connection/initialization fails (before the message was Gyro Moving only)
* Added error message if no temp sensor can be found
* Added drop down menus in user interface to simplify navigation to sub pages (format, test and upload)
* Added Assistant Device registration, this is only done when format template is saved, during normal operation only data values are posted on MQTT. If HA is restarted then the device will disappear
* Calibration temperature (for temp adjustment) can now be set under advanced settings, default is 20C
* Changed length of device name from 12 to 63 chars. 63 is the max limit according to mdns.
* Under format options its now possible to select brewfather iSpindle format to avoid errors connected to using the wrong format template with the various brewfather endpoints
* Added brewblox as format under format options
* Added home assistant (with device registration) as format under format options
* User can now edit the voltage level that forces the device into config mode (device detects charging)
Documentation
+++++++++++++
* Added documentation for Brewpiless as target
* Added documentation for BVrewblox as target
* Updated documentation for HA integration since described method was deprecated
* Updated documentation for ubidots service integration
* Updated documentation in data format section
* Updated hardware section with documentation on installing reed switch
* Updated configuration section with documentation on new settings
* Added q&a on formula creation and value deviation
Other Other
+++++ +++++
@ -40,13 +88,6 @@ Other
* Updated OneWire library to be complaint with new ESP32 SDK * Updated OneWire library to be complaint with new ESP32 SDK
* Fixed issue in i2cdev connected to wrong usage of TwoWire on ESP32 (Gyro initialization hang). * Fixed issue in i2cdev connected to wrong usage of TwoWire on ESP32 (Gyro initialization hang).
Issues adressed
++++++++++++++++
* BUG: Copy format templates used an old format for iSpindle and Gravmon where the token was not used.
* BUG: Gravity correction formula not calculating correctly.
* (beta2) BUG: Temp corrected gravity was not used when pushing data to removed
* (beta2) BUG: Low memory in format api which resulted in mqtt template to be set to null
* (beta2) BUG: Large format templates could be saved but when loading it's only blank. Increased total memory from 3kb to 5kb
v1.0.0 v1.0.0
====== ======
@ -55,14 +96,14 @@ Documentation
+++++++++++++ +++++++++++++
* Update documentation to match v1.0 * Update documentation to match v1.0
* Installation instructions updated on how to find the device after wifi has been configured. * Installation instructions updated on how to find the device after wifi has been configured.
* Documentation on brewfather has been updated to adress SG/Plato conversion * Documentation on brewfather has been updated to address SG/Plato conversion
* Added circuit diagram for esp8266 and esp32 * Added circuit diagram for esp8266 and esp32
* Added additional http error codes to troubleshooting documentation * Added additional http error codes to troubleshooting documentation
User interface User interface
++++++++++++++ ++++++++++++++
* Upgraded to bootstrap v5.1 for web pages. * Upgraded to bootstrap v5.1 for web pages.
* Added button on indexpage to direct to github issues. * Added button on index page to direct to github issues.
* Added button to extract important information for support requests. * Added button to extract important information for support requests.
* First point in gravity formula is now reserved for water gravity, this to allow detection of angles below water that can be filtered out. * First point in gravity formula is now reserved for water gravity, this to allow detection of angles below water that can be filtered out.
* Changed layout on index page with measured data on top. * Changed layout on index page with measured data on top.
@ -73,19 +114,19 @@ Features
++++++++ ++++++++
* Added advanced setting to ignore angles that are lower than water. This is disabled by default. * Added advanced setting to ignore angles that are lower than water. This is disabled by default.
* Added support for MPU6500 (standard is MPU6050). * Added support for MPU6500 (standard is MPU6050).
* Removed brewfather option (can use standard HTTP options), the old apporach can still be used via changing format template. * Removed brewfather option (can use standard HTTP options), the old approach can still be used via changing format template.
* Added 5 more points for formula creation, so a total of 10 angles/gravity values can be stored. * Added 5 more points for formula creation, so a total of 10 angles/gravity values can be stored.
* Added https support for Influxdb v2 * Added https support for Influxdb v2
* Added possibility to set 2 wifi ssid where the second acts as a fallback in case it fails to connect. If succesful the seconday becomes the new primary. * Added possibility to set 2 wifi ssid where the second acts as a fallback in case it fails to connect. If successful the secondary becomes the new primary.
* SSL connections are skipped on ESP8266 when in config mode since there is a high probability it will crash due to low memory. * SSL connections are skipped on ESP8266 when in config mode since there is a high probability it will crash due to low memory.
* Advanced settings: Added possibility to have variable push intervals for different endpoints so that different frequency can be used, for example; 5min mqtt, 15min brewfather. * Advanced settings: Added possibility to have variable push intervals for different endpoints so that different frequency can be used, for example; 5min mqtt, 15min brewfather.
* Advanced settings: Changes how many times the gyro is read (less reads, quicker but less accurate) * Advanced settings: Changes how many times the gyro is read (less reads, quicker but less accurate)
* Advanced settings: Set amount of gyro movement is allowed for a accurate read. * Advanced settings: Set amount of gyro movement is allowed for a accurate read.
* Advanced settings: What deviation is acceptable for creating formula deviation * Advanced settings: What deviation is acceptable for creating formula deviation
* Advanced settings: Various timeouts, wifi connect, wifi portal, http connects. * Advanced settings: Various timeouts, wifi connect, wifi portal, http connects.
* Advanced settings: Adjust resolution of temp sensor (9 bits to 12 bits), higher resolution takes longer thus reducing batterylife * Advanced settings: Adjust resolution of temp sensor (9 bits to 12 bits), higher resolution takes longer thus reducing battery life
Issues adressed Issues addressed
++++++++++++++++ ++++++++++++++++
* BUG: Fixed issue in formula calculation in case there were a gap in the data series * BUG: Fixed issue in formula calculation in case there were a gap in the data series
* BUG: Field name for wifi strength changed from "rssi" to "RSSI" * BUG: Field name for wifi strength changed from "rssi" to "RSSI"
@ -96,7 +137,7 @@ v0.9.0
====== ======
* Added one http push target that uses HTTP GET. This can be used with ubidots or blynk api's. * Added one http push target that uses HTTP GET. This can be used with ubidots or blynk api's.
* Added function to test push targets from configuration page. It will send data and show the return code as a first step. * Added function to test push targets from configuration page. It will send data and show the return code as a first step.
* Added documetation on how to integrate with Blynk.io using http get. * Added documentation on how to integrate with Blynk.io using http get.
* Config page now shows the estimated runtime for the device (based on a full battery and previous average runtime) * Config page now shows the estimated runtime for the device (based on a full battery and previous average runtime)
* Experimental release of firmware using an esp32 instead of esp8266 * Experimental release of firmware using an esp32 instead of esp8266
* Merged index and device pages into one so that all the needed information is available on the index page. * Merged index and device pages into one so that all the needed information is available on the index page.
@ -113,9 +154,9 @@ v0.9.0
* BUG: Corrected PIN for voltage read on ESP32 * BUG: Corrected PIN for voltage read on ESP32
* BUG: If using plato and not gravity formula was defined the value was set to null. * BUG: If using plato and not gravity formula was defined the value was set to null.
* BUG: Temp format name was incorrect in iSpindle format causing receiver to incorrectly read temperature. * BUG: Temp format name was incorrect in iSpindle format causing receiver to incorrectly read temperature.
* BUG: Temperature sensor adjusmemnt value was not handled properly when using Farenheight. * BUG: Temperature sensor adjustment value was not handled properly when using Fahrenheit.
* BUG: If the ID was to low the device id could end up with a leading space causing errors in data post. Added leading zero to ID. * BUG: If the ID was to low the device id could end up with a leading space causing errors in data post. Added leading zero to ID.
* BUG: Entering wifi setup and a timeout occured the wifi settings could be deleted. * BUG: Entering wifi setup and a timeout occurred the wifi settings could be deleted.
v0.8.0 v0.8.0
====== ======
@ -135,7 +176,7 @@ v0.8.0
from 16k to 2k. This can make a huge difference on a device with only 40k RAM. Not all from 16k to 2k. This can make a huge difference on a device with only 40k RAM. Not all
servers might support this feature. servers might support this feature.
* Updated documentation pages. * Updated documentation pages.
* Tested batterylife, 47 days using an update frequency of 5 min * Tested battery life, 47 days using an update frequency of 5 min
v0.7.1 v0.7.1
====== ======
@ -157,7 +198,7 @@ Latest stable version. `Release v0.7 on Github <https://github.com/mp-se/gravity
* Added support for Plato * Added support for Plato
* Added error handling for calibration page. * Added error handling for calibration page.
* Added experimental target ESP32 (using an ESP32 D1 Mini which is pin compatible with ESP8266). Not * Added experimental target ESP32 (using an ESP32 D1 Mini which is pin compatible with ESP8266). Not
really usable since wifi connection is extreamly slow with current Arduino releases (3-8 seconds). really usable since wifi connection is extremely slow with current Arduino releases (3-8 seconds).
* Added experimental format editor so users can customize their data format used for pushing data. * Added experimental format editor so users can customize their data format used for pushing data.
This will reduce the need for custom push targets. As long as the service is supporting http This will reduce the need for custom push targets. As long as the service is supporting http
or https then the data format can be customized. or https then the data format can be customized.
@ -188,7 +229,7 @@ v0.6.0
v0.5.0 v0.5.0
====== ======
* Added feature to calcuate formula on device * Added feature to calculate formula on device
* Total rewrite of documentation * Total rewrite of documentation
* WIFI settings are now stored in config file * WIFI settings are now stored in config file
* Defined version numbers for all dependant libraries to avoid updates breaking build. * Defined version numbers for all dependant libraries to avoid updates breaking build.

View File

@ -8,11 +8,11 @@ This chapter contains a list of targets and what configuration is needed to inte
Brewfather Brewfather
++++++++++ ++++++++++
Brewfather is an all in one service that allows you to manage you recepies and brews. Brewfather is an all in one service that allows you to manage you recipes and brews.
**Option 1** - iSpindle Endpoint **Option 1** - iSpindle Endpoint
This opion makes use of the standard http (1 or 2) endpoints in the push section. If you are using SG then the device name needs to end with [SG] or brewfather will assume This option makes use of the standard http (1 or 2) endpoints in the push section. If you are using SG then the device name needs to end with [SG] or brewfather will assume
that the data is in plato. You can also modify the format template using the following options: that the data is in plato. You can also modify the format template using the following options:
Update the following part `"gravity": ${gravity-plato},` or `"name" : "${mdns}[SG]",`` Update the following part `"gravity": ${gravity-plato},` or `"name" : "${mdns}[SG]",``
@ -29,7 +29,7 @@ Documentation on this can be found under `Brewfather iSpindle Endpoint <https://
**Option 2** - Custom Stream **Option 2** - Custom Stream
This option makes use of the http push endpoint with a custom format template. Just enter the http stream adress found This option makes use of the http push endpoint with a custom format template. Just enter the http stream address found
on brewfather, not other settings are needed. The stream endpoint URL has the following format: on brewfather, not other settings are needed. The stream endpoint URL has the following format:
.. code-block:: .. code-block::
@ -79,7 +79,7 @@ UBIdots
you might need to reduce the number of values sent to the service. It will also treat every parameter as a number unless you create a custom device type and explicit define the string values you might need to reduce the number of values sent to the service. It will also treat every parameter as a number unless you create a custom device type and explicit define the string values
as text. This will require a paid subscription (as I interpret the documentation). The example format below will only send numbers so that should work fine with the paid subscription. as text. This will require a paid subscription (as I interpret the documentation). The example format below will only send numbers so that should work fine with the paid subscription.
For this service there are two options to configure the integration. First you will need your default token which is found under `API Credentials` (<api-tokem> in the example below). For this service there are two options to configure the integration. First you will need your default token which is found under `API Credentials` (<api-token> in the example below).
Swap the text <devicename> with the name you want to show in ubidots. Swap the text <devicename> with the name you want to show in ubidots.
**Option 1** - token as an URL parameter **Option 1** - token as an URL parameter
@ -112,7 +112,7 @@ Under `Headers` (button after the http url in the UI) enter the following string
This is the more secure option. This is the more secure option.
Even though ubidots can handle the default ispindle format it probably better to just post the data you want. This is an example of a Even though ubidots can handle the default iSpindle format it probably better to just post the data you want. This is an example of a
format template that can be used. For information on customizing the format see :ref:`format-editor`. format template that can be used. For information on customizing the format see :ref:`format-editor`.
.. code-block:: .. code-block::
@ -163,8 +163,9 @@ username / password to be able to publish messages on a topic.
gravmon/${mdns}/battery:${battery}| gravmon/${mdns}/battery:${battery}|
It's also possible to allow home assistant to do autodisovery and automatically create the sensor. This format It's also possible to allow home assistant to do auto discovery and automatically create the sensor. This format
template will create two sensors and update the values for them. template will create two sensors and update the values for them. The registration will occur when you save the format template. If Home Assistant
is restarted then the device will disappear. The first method is the most persistent one.
.. warning:: .. warning::
This will only work on 1.1+ since the the memory allocation on previous versions are not enough to handle this large payload. This will only work on 1.1+ since the the memory allocation on previous versions are not enough to handle this large payload.
@ -182,16 +183,16 @@ template will create two sensors and update the values for them.
homeassistant/sensor/gravmon_${id}/gravity/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_grav","name":"gravity","dev_cla":"temperature","unit_of_meas":" ${gravity-unit}","stat_t":"gravmon/${mdns}/gravity"}| homeassistant/sensor/gravmon_${id}/gravity/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_grav","name":"gravity","dev_cla":"temperature","unit_of_meas":" ${gravity-unit}","stat_t":"gravmon/${mdns}/gravity"}|
homeassistant/sensor/gravmon_${id}/rssi/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_rssi","name":"rssi","dev_cla":"temperature","unit_of_meas":"dBm","stat_t":"gravmon/${mdns}/rssi"}| homeassistant/sensor/gravmon_${id}/rssi/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_rssi","name":"rssi","dev_cla":"temperature","unit_of_meas":"dBm","stat_t":"gravmon/${mdns}/rssi"}|
homeassistant/sensor/gravmon_${id}/tilt/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_tilt","name":"tilt","dev_cla":"temperature","stat_t":"gravmon/${mdns}/tilt"}| homeassistant/sensor/gravmon_${id}/tilt/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_tilt","name":"tilt","dev_cla":"temperature","stat_t":"gravmon/${mdns}/tilt"}|
homeassistant/sensor/gravmon_${id}/battery/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_batt","name":"battery","dev_cla":"temperature","unit_of_meas":"V","stat_t":"gravmon/${mdns}/battery"}| homeassistant/sensor/gravmon_${id}/battery/config:{"dev":{"name":"${mdns}","mdl":"gravmon","sw":"${app-ver}","ids":"${id}"},"uniq_id":"${id}_batt","name":"battery","dev_cla":"voltage","unit_of_meas":"V","stat_t":"gravmon/${mdns}/battery"}|
Brewer's Friend Brewer's Friend
+++++++++++++++ +++++++++++++++
Brewer's friend is an all in one service that allows you to manage you recepies and brews. Brewer's friend is an all in one service that allows you to manage you recipes and brews.
.. warning:: .. warning::
I dont have an account for brewers friend so I have not been able to verfy this completely. Its based on I don't have an account for brewers friend so I have not been able to verify this completely. Its based on
the available documentation. If this works please let the available documentation. If this works please let
You can find you API key when logged in to the service. Follow these `instructions <https://docs.brewersfriend.com/devices/ispindel>`_ You can find you API key when logged in to the service. Follow these `instructions <https://docs.brewersfriend.com/devices/ispindel>`_
@ -292,7 +293,7 @@ Brewpiless
If you connect the device to the brewpiless access point there is not way to access the user interface for configuration so it's recommended to connect the device to your normal network. If you connect the device to the brewpiless access point there is not way to access the user interface for configuration so it's recommended to connect the device to your normal network.
The device need to have a name starting with iSpindle, for example `iSpindel000`. Set the URL for one of the http POST targets to `http://ip/gravity` where ip is the ip adress of Brewpiless. The device need to have a name starting with iSpindle, for example `iSpindel000`. Set the URL for one of the http POST targets to `http://ip/gravity` where ip is the ip address of Brewpiless.
BrewBlox BrewBlox
@ -301,8 +302,8 @@ BrewBlox
To send iSpindel data to brewblox over mqtt you need to modify the format template to match the expected format. Once you have configured the mqtt information you also need to update the format template To send iSpindel data to brewblox over mqtt you need to modify the format template to match the expected format. Once you have configured the mqtt information you also need to update the format template
for this target. for this target.
This format template will post the expected json document on the topic, dont forget the `|` character at the end of the line which is needed to parse the payload. The first to words are the topic This format template will post the expected json document on the topic, don't forget the `|` character at the end of the line which is needed to parse the payload. The first to words are the topic
name and after the first `:` this is the json playload. Text within the brackets will be used as the unit for the value and degC is displayed as °C. You can add other parameters under the data section name and after the first `:` this is the json payload. Text within the brackets will be used as the unit for the value and degC is displayed as °C. You can add other parameters under the data section
in the json document if you need other values as well. in the json document if you need other values as well.
.. code-block:: .. code-block::

View File

@ -13,12 +13,12 @@ Log errors
* Error validating created formula. Deviation to large, formula rejected * Error validating created formula. Deviation to large, formula rejected
The device will try to create formulas with different complexities. It will try to The device will try to create formulas with different complexities. It will try to
validate the formula using the supplied values. If the differnce is more than 1.6 SG on any point validate the formula using the supplied values. If the difference is more than 1.6 SG on any point
the formula will be rejected. Check the entered values if they seams to be resonable. the formula will be rejected. Check the entered values if they seams to be reasonable.
* No valid calibration values, please calibrate the device. * No valid calibration values, please calibrate the device.
The gyro needs to be calibrated at 90 degress (flat). This is done on the configration page. The gyro needs to be calibrated at 90 degrees (flat). This is done on the configuration page.
* Low on memory, skipping push * Low on memory, skipping push
@ -33,10 +33,10 @@ Log errors
* Influxdb push failed response * Influxdb push failed response
* HTTP push failed response * HTTP push failed response
All these errors are standard http error codes. This are the commone ones; All these errors are standard http error codes. This are the common ones;
* 400 - Bad request. Probably an issue with the post format. Check format in the format editor. * 400 - Bad request. Probably an issue with the post format. Check format in the format editor.
* 401 - Unathorized. The service needs an token or other means to authenticate the device. * 401 - Unauthorized. The service needs an token or other means to authenticate the device.
* 403 - Forbidden. Could be an issue with token or URL. * 403 - Forbidden. Could be an issue with token or URL.
* 404 - Not found. Probably a wrong URL. * 404 - Not found. Probably a wrong URL.

View File

@ -1,7 +1,7 @@
{ {
"gyro-read-count": 50, "gyro-read-count": 50,
"gyro-moving-threashold": 500, "gyro-moving-threashold": 500,
"formula-max-deviation": 1.6, "formula-max-deviation": 3,
"wifi-portal-timeout": 120, "wifi-portal-timeout": 120,
"wifi-connect-timeout": 20, "wifi-connect-timeout": 20,
"push-timeout": 10, "push-timeout": 10,

Some files were not shown because too many files have changed in this diff Show More