Compare commits
359 Commits
v1.0.0-bet
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
433502e7a0 | ||
|
cd1ada6744 | ||
|
22a4f40f41 | ||
|
59b95cd68b | ||
|
88c396398d | ||
|
5477ab4683 | ||
|
a8773a7ba1 | ||
|
71e67ca3f1 | ||
|
b76c7a55b4 | ||
|
4f806f4b02 | ||
|
a515a164fc | ||
|
b9e645b20d | ||
|
87caf6225b | ||
|
474bcdc5e9 | ||
|
19ab8f5271 | ||
|
6706a7f9d6 | ||
|
7c35bb59d0 | ||
|
47527b8a73 | ||
|
49921bf8dc | ||
|
35540243c6 | ||
|
963966d201 | ||
|
6d5d859283 | ||
|
fe7be5d8d6 | ||
|
71f87ff143 | ||
|
e29090a2a2 | ||
|
924b0356f5 | ||
|
41cb3113b9 | ||
|
dcebbf2e83 | ||
|
66d2e69927 | ||
|
89aa631b75 | ||
|
e75a31ebb7 | ||
|
e622580493 | ||
|
b3a4266da1 | ||
|
fe67ff63f1 | ||
|
ce1061dfb3 | ||
|
c4d070ee89 | ||
|
032f656d51 | ||
|
65e243e391 | ||
|
8a4d0ac035 | ||
|
3be6847238 | ||
|
683ff4e6d5 | ||
|
8e12eac627 | ||
|
83c0bb5283 | ||
|
8257e9ab51 | ||
|
67ebd559d7 | ||
|
6f09afcf96 | ||
|
a7362a42fa | ||
|
a191f6bb35 | ||
|
88cdd986e6 | ||
|
1607503103 | ||
|
31c06bcce4 | ||
|
b2449db6f9 | ||
|
b79e5b5d73 | ||
|
d28d545109 | ||
|
577d7382f4 | ||
|
d4dfccdddd | ||
|
88fc94ed8c | ||
|
0be50389cc | ||
|
9351696732 | ||
|
bc21127479 | ||
|
1dbd03a0f0 | ||
|
61e78beb4a | ||
|
d905aeafe9 | ||
|
60675ecf0f | ||
|
61715cda08 | ||
|
3d26564b8f | ||
|
74b1c40ffd | ||
|
186ae4e4ee | ||
|
f2afd653ae | ||
|
c5e5c7727b | ||
|
8bb720becd | ||
|
756a49af50 | ||
|
e2f972bbc0 | ||
|
9009b41f57 | ||
|
1c3784a223 | ||
|
489b268f73 | ||
|
01c709f9b7 | ||
|
ef3dd420f6 | ||
|
3505673652 | ||
|
8ca51a2888 | ||
|
d4ea1c9f98 | ||
|
6af0af57b8 | ||
|
8ce8deb400 | ||
|
5e24726e7b | ||
|
0b1c87323a | ||
|
787e39eff1 | ||
|
683df36164 | ||
|
9e1701c2da | ||
|
f220df08ac | ||
|
29d6486743 | ||
|
09ffcba84e | ||
|
87eab2a550 | ||
|
5bc3fdb153 | ||
|
de421b5000 | ||
|
7941b04ce8 | ||
|
022e4b804b | ||
|
4c7182a6d6 | ||
|
5ac1ead5b9 | ||
|
4e25eb4b81 | ||
|
6440ba50e2 | ||
|
ea83632285 | ||
|
f319ec4569 | ||
|
21298b09f4 | ||
|
bf17b9b864 | ||
|
acaa5d9f1d | ||
|
5dd4fb3f1e | ||
|
4aae1b912c | ||
|
50c534cbe5 | ||
|
635be88c11 | ||
|
53c953de01 | ||
|
d967d8efd9 | ||
|
bbdbf88a76 | ||
|
47bae4d28e | ||
|
ce8e8bbe7b | ||
|
0ca60ec71f | ||
|
d7981851bd | ||
|
2a419c10d1 | ||
|
b265dba422 | ||
|
74a0598905 | ||
|
3b7be30363 | ||
|
5889ebda1e | ||
|
ec77b873a8 | ||
|
04120a0490 | ||
|
4f28ea9975 | ||
|
c1eade04af | ||
|
2fd0c881f3 | ||
|
8113275402 | ||
|
b5928cb201 | ||
|
22f9a2d228 | ||
|
343aea7ebe | ||
|
19e67cb678 | ||
|
379dff1d22 | ||
|
e82cd2aeae | ||
|
6262cec27d | ||
|
a9347c7e03 | ||
|
60adcabd81 | ||
|
411cec08c7 | ||
|
b6fcf94191 | ||
|
e9ef632cce | ||
|
7d4c42a47c | ||
|
9ce6d54b80 | ||
|
2e96e4aea8 | ||
|
775ba53260 | ||
|
6e0af97574 | ||
|
531baa917e | ||
|
7f73f22759 | ||
|
0fad08ccc5 | ||
|
fcfc8df625 | ||
|
e54c1d2518 | ||
|
027e98d2de | ||
|
91227b0728 | ||
|
ddeca29f8e | ||
|
15d3371437 | ||
|
ac51c52c74 | ||
|
1148a23bb4 | ||
|
1ddd8bc669 | ||
|
7664215d23 | ||
|
9eb356bd43 | ||
|
f4401ea526 | ||
|
535367d943 | ||
|
8db58c76dc | ||
|
9441e4bc54 | ||
|
b7d2183564 | ||
|
18f7ba8911 | ||
|
af0d6f21ca | ||
|
e3fcd53a36 | ||
|
5149760d22 | ||
|
403719073b | ||
|
dd3a4e5742 | ||
|
2e27ec78d6 | ||
|
d5dae6a40d | ||
|
3b716e5499 | ||
|
2aebae59b3 | ||
|
eb4b975407 | ||
|
1f25e3ac50 | ||
|
f1a608d060 | ||
|
c33326e6a4 | ||
|
1afb5ed604 | ||
|
823d8ca39e | ||
|
5a11ab84db | ||
|
5378d4c700 | ||
|
c10abe2087 | ||
|
ec3ef06826 | ||
|
b9273b7b79 | ||
|
6b649070e1 | ||
|
291229255c | ||
|
2747484775 | ||
|
ecf0c08f47 | ||
|
eb82bf526d | ||
|
b45ef627a0 | ||
|
d1b94ce2b0 | ||
|
d4b78a0e1b | ||
|
646d8f8d12 | ||
|
059865f271 | ||
|
a9deb588aa | ||
|
0de8971255 | ||
|
08a102159b | ||
|
8b13b4769c | ||
|
c3044f9878 | ||
|
0a4e7f37b2 | ||
|
69f4b8ec3d | ||
|
d4c88c1200 | ||
|
4bbfb77361 | ||
|
655235fc4e | ||
|
4b0e5b393a | ||
|
db590f8f5f | ||
|
4c805fe235 | ||
|
34a1d7d3c3 | ||
|
bcee0e21da | ||
|
9fc5ab147d | ||
|
b3a89a1fcc | ||
|
03b58eb112 | ||
|
63ddcfbb57 | ||
|
68d44a5846 | ||
|
45294f6b07 | ||
|
09d8226af1 | ||
|
6c94c6b204 | ||
|
9e437d1e0d | ||
|
a486f1be30 | ||
|
0536b14280 | ||
|
a6bff7287e | ||
|
414d7d51c2 | ||
|
640733f143 | ||
|
f6196e6dbf | ||
|
f857dab3c0 | ||
|
787c5c09bb | ||
|
afe3ec2412 | ||
|
980099a5e5 | ||
|
99d577d4a0 | ||
|
6db6e96d90 | ||
|
92df08baa2 | ||
|
5466550f68 | ||
|
94f703b087 | ||
|
57e078986b | ||
|
e445e7649c | ||
|
a5f7f0f8a4 | ||
|
7826e56d8a | ||
|
353d6d77e1 | ||
|
437873489e | ||
|
e34e73fae2 | ||
|
69a4c5607c | ||
|
d980fdae1a | ||
|
272e349375 | ||
|
34d46ef768 | ||
|
588ff2d1e0 | ||
|
5d1811d240 | ||
|
85e602d29b | ||
|
8ee882c522 | ||
|
51e7ee6867 | ||
|
70858ef841 | ||
|
83bd80ba28 | ||
|
d33576b2df | ||
|
5c9525c0c5 | ||
|
ad8704fc20 | ||
|
f1c1958f88 | ||
|
e5394113e4 | ||
|
6d4e713da8 | ||
|
36a858af2d | ||
|
77d2c15e39 | ||
|
9df072cc78 | ||
|
bedbda4662 | ||
|
76702dfc95 | ||
|
789eb32aa8 | ||
|
c0db4dd8da | ||
|
cb677e10ae | ||
|
b4c7566a08 | ||
|
70f391fa1a | ||
|
542beffe4c | ||
|
1a42bd332f | ||
|
c16108352c | ||
|
4b5df951de | ||
|
6bbb904427 | ||
|
66c6c44a38 | ||
|
e2fee1fb35 | ||
|
ae595ff50c | ||
|
50257e2805 | ||
|
c503ad88a9 | ||
|
5b7290c991 | ||
|
f7c43dad55 | ||
|
95654bac66 | ||
|
ffa7ac294d | ||
|
79a3274286 | ||
|
0c936cfb88 | ||
|
f366b78cb3 | ||
|
702eba515d | ||
|
a992e90bc3 | ||
|
8b4b89ba20 | ||
|
361d287a22 | ||
|
8e36453b13 | ||
|
ded06d15a1 | ||
|
67f60b817e | ||
|
6373923506 | ||
|
bf3a3de207 | ||
|
e6fd027d51 | ||
|
0cba58a0dd | ||
|
fd71a2d428 | ||
|
907e33ce2d | ||
|
18ba0b225f | ||
|
2a9472b453 | ||
|
0b23a0f69e | ||
|
9cba1db4e5 | ||
|
9d5d6a5a58 | ||
|
58fe408803 | ||
|
c2ae70bb1a | ||
|
7a3b048d80 | ||
|
ad3fbb7270 | ||
|
02df656343 | ||
|
f73f63fec3 | ||
|
bb09072520 | ||
|
5875ee83d8 | ||
|
6185d67d12 | ||
|
00f82f5c37 | ||
|
59ad285bb8 | ||
|
bc09d617fc | ||
|
a71f54b99f | ||
|
152ff89bf6 | ||
|
d9fb8291f4 | ||
|
030746e982 | ||
|
d4260c6380 | ||
|
50725407ea | ||
|
b4bac17114 | ||
|
cb433a4a91 | ||
|
095c1dc6a7 | ||
|
43e2d165f5 | ||
|
fca7294b61 | ||
|
390c0882d1 | ||
|
5e9e705b96 | ||
|
d67f72f123 | ||
|
f09aadaf66 | ||
|
c68f67a558 | ||
|
299e915bd2 | ||
|
06a1541090 | ||
|
a8b87140b2 | ||
|
1d738a14dd | ||
|
4e37b9329c | ||
|
9712e13c78 | ||
|
1b11e49883 | ||
|
cc6fecbdf8 | ||
|
971b210438 | ||
|
7b2a99c8a3 | ||
|
d6f8ff67a3 | ||
|
f173b205ae | ||
|
e0312ab3c5 | ||
|
7678bb1f43 | ||
|
403ed1d350 | ||
|
ced4c9f8fc | ||
|
7e1862390e | ||
|
a3cd3217ab | ||
|
7ede9a6d19 | ||
|
f27e8ac79f | ||
|
7874f1bcf2 | ||
|
9f87bf5432 | ||
|
5bbb7ebfaa | ||
|
328e7e71ae | ||
|
2912749f19 | ||
|
43b6881477 | ||
|
3a4cfb1ca5 | ||
|
a40c3528d4 | ||
|
87036d56e5 |
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. ...
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Software:**
|
||||||
|
- Platform (esp8266, esp32)
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
17
.github/stale.yaml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 60
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 14
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- on-hold
|
||||||
|
- security
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: wontfix
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
28
.github/workflows/doc-build.yaml
vendored
@ -4,20 +4,26 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
#- dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ammaraskar/sphinx-action@master
|
- uses: ammaraskar/sphinx-action@master
|
||||||
with:
|
with:
|
||||||
docs-folder: "src_docs/"
|
docs-folder: "src_docs/"
|
||||||
pre-build-command: |
|
pre-build-command: |
|
||||||
pip install sphinx_rtd_theme
|
pip install --upgrade pip
|
||||||
pip install furo
|
pip install sphinx==4.3.2
|
||||||
|
pip install docutils==0.16
|
||||||
|
pip install pygments==2.11.1
|
||||||
|
pip install furo==2022.1.2
|
||||||
|
pip install sphinx-copybutton
|
||||||
|
pip list
|
||||||
build-command: "sphinx-build -b html ./source ../docs"
|
build-command: "sphinx-build -b html ./source ../docs"
|
||||||
|
|
||||||
- name: Commit documentation changes
|
- name: Commit documentation changes
|
||||||
@ -34,9 +40,19 @@ jobs:
|
|||||||
git config --local user.name "GitHub Action"
|
git config --local user.name "GitHub Action"
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Update documentation" -a || true
|
git commit -m "Update documentation" -a || true
|
||||||
# git push https://${{secrets.token}}@github.com/mp-se/gravitymon.git
|
|
||||||
# The above command will fail if no changes were present, so we ignore
|
- uses: wangyucode/sftp-upload-action@v1.4.8
|
||||||
# the return code.
|
with:
|
||||||
|
host: ${{ secrets.SFTP_HOST }}
|
||||||
|
port: 22
|
||||||
|
username: ${{ secrets.SFTP_USER }}
|
||||||
|
password: ${{ secrets.SFTP_PASSWD }}
|
||||||
|
forceUpload: false
|
||||||
|
localDir: 'docs/'
|
||||||
|
remoteDir: '/run/www/docs/'
|
||||||
|
exclude: ''
|
||||||
|
dryRun: false
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
uses: ad-m/github-push-action@master
|
uses: ad-m/github-push-action@master
|
||||||
with:
|
with:
|
||||||
|
14
.github/workflows/pio-build-patch.yaml
vendored
@ -10,10 +10,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Cache pip
|
- name: Cache pip
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/pip
|
path: ~/.cache/pip
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
@ -21,13 +21,13 @@ jobs:
|
|||||||
${{ runner.os }}-pip-
|
${{ runner.os }}-pip-
|
||||||
|
|
||||||
- name: Cache PlatformIO
|
- name: Cache PlatformIO
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio
|
path: ~/.platformio
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
|
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: |
|
run: |
|
||||||
@ -36,11 +36,9 @@ 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@v9 # You can change this to use a specific version. https://github.com/marketplace/actions/add-commit
|
||||||
with:
|
with:
|
||||||
add: 'bin'
|
add: 'bin'
|
||||||
author_name: GitHub Action
|
author_name: GitHub Action
|
||||||
|
10
.github/workflows/pio-build.yaml
vendored
@ -10,10 +10,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Cache pip
|
- name: Cache pip
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/pip
|
path: ~/.cache/pip
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
@ -21,7 +21,7 @@ jobs:
|
|||||||
${{ runner.os }}-pip-
|
${{ runner.os }}-pip-
|
||||||
|
|
||||||
- name: Cache PlatformIO
|
- name: Cache PlatformIO
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio
|
path: ~/.platformio
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||||
@ -36,9 +36,9 @@ 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 -e gravity32s2-release -e gravity32c3v1-release -e gravity32lite-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@v9 # You can change this to use a specific version. https://github.com/marketplace/actions/add-commit
|
||||||
with:
|
with:
|
||||||
add: 'bin'
|
add: 'bin'
|
||||||
author_name: GitHub Action
|
author_name: GitHub Action
|
||||||
|
19
.github/workflows/pre-commit.yaml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: pre-commit
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- dev
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pre-commit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
- name: clang format support
|
||||||
|
run: |
|
||||||
|
sudo apt install clang-format cppcheck
|
||||||
|
- uses: pre-commit/action@v3.0.0
|
7
.gitignore
vendored
@ -1,9 +1,6 @@
|
|||||||
.pio/*
|
.pio/*
|
||||||
.vscode/*
|
.vscode/*
|
||||||
*.map
|
*.map
|
||||||
test/*.md
|
|
||||||
test/env/*
|
|
||||||
test/configure_*.py
|
|
||||||
TODO.md
|
|
||||||
src_docs/_build/*
|
src_docs/_build/*
|
||||||
data/*.min.htm
|
.env/*
|
||||||
|
*.pyc
|
@ -4,7 +4,10 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
files: ^src/
|
files: ^src/
|
||||||
|
exclude: 'lib/'
|
||||||
- id: cpplint
|
- id: cpplint
|
||||||
files: ^src/
|
files: ^src/
|
||||||
|
exclude: 'lib/'
|
||||||
- id: cppcheck
|
- id: cppcheck
|
||||||
files: ^src/
|
files: ^src/
|
||||||
|
exclude: 'lib/'
|
||||||
|
35
CONTRIBUTING.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
## How to contribute to GravityMon
|
||||||
|
|
||||||
|
#### **Did you find a bug?**
|
||||||
|
|
||||||
|
* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/mp-se/gravitymon/issues). Dont forget to look under closed issues. There might be a fix but not yet included in the released version.
|
||||||
|
|
||||||
|
* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/mp-se/gravitymon/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, Use the function on the device to extract configuration and device information (does not contain any sensitive data). This can help to pinpoint the issue.
|
||||||
|
|
||||||
|
#### **Did you write a patch that fixes a bug?**
|
||||||
|
|
||||||
|
* Open a new GitHub pull request with the patch.
|
||||||
|
|
||||||
|
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
|
||||||
|
|
||||||
|
* Before submitting, please use `pre-commit` to validate that your code contribution complies with the formatting standards for C++ and C.
|
||||||
|
|
||||||
|
* Check the contribution section under the documentation for additional information.
|
||||||
|
|
||||||
|
#### **Do you intend to add a new feature or change an existing one?**
|
||||||
|
|
||||||
|
* Suggest your change in the [Discussion forums](https://github.com/mp-se/gravitymon/discussions) and start writing code.
|
||||||
|
|
||||||
|
* Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
|
||||||
|
|
||||||
|
#### **Do you have questions about the source software?**
|
||||||
|
|
||||||
|
* Start a discussion in the [Discussion forums](https://github.com/mp-se/gravitymon/discussions) and start writing code.
|
||||||
|
|
||||||
|
#### **Do you want to contribute to the documentation?**
|
||||||
|
|
||||||
|
* Open a new GitHub pull request with the updated documentation changes.
|
||||||
|
|
||||||
|
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
|
||||||
|
|
||||||
|
Thanks!
|
41
README.md
@ -3,37 +3,30 @@
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
# Gravity Monitor for Beer Brewing
|
# Gravity Monitor for Beer Brewing
|
||||||
|
|
||||||
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)
|
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. From v1.2 you can also use GravityMon for the DIY Floaty Hardware with ESP32 Lite.
|
||||||
|
|
||||||
Installation can be made using https://www.brewflasher.com
|
Now also works with ESP32 d1 mini, ESP32 c3 mini, ESP32 S2 mini which both are pin compatible with ESP8266.
|
||||||
|
|
||||||
Note! If its being flagged as malware, try the older version.
|
Installation can be made using https://www.brewflasher.com or the web version at https://web.brewflasher.com
|
||||||
|
|
||||||
The main differences:
|
The documentation can be found here: https://www.gravitymon.com/docs.html
|
||||||
---------------------
|
|
||||||
|
|
||||||
* Modern web based user interface for configuration when connected to WIFI
|
Visit the gravitymon homepage here for more information about the project: https://www.gravitymon.com
|
||||||
* Efficient software, long lifespan (+45 days with 5min update frequencey)
|
|
||||||
* Send data to multiple endpoints (http-post, http-get, influxdb v2, mqtt)
|
|
||||||
* Instructions for service such as; Brewfather, Fermentrack, Ubidots, Home Assistant, Brewers Friend, Brewspy, Thingspeak, Blynk.
|
|
||||||
* SSL support in standard HTTP and MQTT connections.
|
|
||||||
* ESP32 support with Bluetooth push
|
|
||||||
* Customize data format to be pushed
|
|
||||||
* Automatic temperature adjustment of gravity when enabled
|
|
||||||
* Use the temperature sensor in gyro instead of DS18B20
|
|
||||||
* Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity.
|
|
||||||
* Visual graph showing how gravity formula will be interpreted
|
|
||||||
* OTA support
|
|
||||||
* Built in performance measurements (used to optimise code)
|
|
||||||
* REST API for scripting
|
|
||||||
|
|
||||||
No code has been reused from the iSpindle project.
|
If you want to support my work you can do that through these options
|
||||||
|
|
||||||
The documenation can be found here: https://mp-se.github.io/gravitymon/index.html
|
[<img src="https://gravitymon.com/images/buymecoffee.png" height=40>](https://www.buymeacoffee.com/mpse/) [<img src="https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86" height=40>](https://github.com/sponsors/mp-se)
|
||||||
|
|
||||||
|
# Supporters
|
||||||
|
|
||||||
|
Thanks to the following persons for supporting me and this project:
|
||||||
|
|
||||||
|
* David Conde, @davidconde
|
||||||
|
* Lars H.
|
||||||
|
31
TEST.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Unit testing - Python Script
|
||||||
|
|
||||||
|
I have moved my test scripts into this project now. They are mainly based on python scrips and validate the features from the API's.
|
||||||
|
|
||||||
|
Create a virtual environment and install the needed dependecies
|
||||||
|
```
|
||||||
|
python -m venv .env
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Before you runt the script you need to update the IP adress to match the device that you have on your network.
|
||||||
|
|
||||||
|
Running the ALL tests
|
||||||
|
```
|
||||||
|
cd src/test
|
||||||
|
python3 -m unittest -v apitests.py -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Running the ONE test
|
||||||
|
```
|
||||||
|
cd src/test
|
||||||
|
python3 -m unittest -v apitests.API.test_status -v
|
||||||
|
```
|
||||||
|
|
||||||
|
# Unit testing - Specific build
|
||||||
|
|
||||||
|
I've added a specific build that uses the AUnit (https://github.com/bxparks/AUnit) testing framework so that we can test functions or classes on the device itself. I hope this will simplify the release and testing cycle.
|
||||||
|
|
||||||
|
1. Select the build target (gravity-unit)
|
||||||
|
2. Build/upload the code to an iSpindle device.
|
||||||
|
3. Check the output from the serial console.
|
BIN
battery-test-1.2.xlsx
Normal 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>
|
|
BIN
bin/firmware.bin
BIN
bin/firmware32c3.bin
Normal file
BIN
bin/firmware32c3v1.bin
Normal file
BIN
bin/firmware32lite.bin
Normal file
BIN
bin/firmware32s2.bin
Normal file
BIN
bin/partitions32c3.bin
Normal file
BIN
bin/partitions32lite.bin
Normal file
BIN
bin/partitions32s2.bin
Normal file
@ -1 +1 @@
|
|||||||
{ "project":"gravmon", "version":"1.0.0", "html": [ ] }
|
{ "project":"gravmon", "version":"1.2.1", "html": [ ] }
|
@ -28,17 +28,26 @@
|
|||||||
<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>
|
||||||
|
|
||||||
|
@ -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>
|
@ -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>
|
||||||
@ -97,7 +103,8 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="angle1" class="col-sm-1 col-form-label">1.</label>
|
<label for="angle1" class="col-sm-1 col-form-label">1.</label>
|
||||||
<div class="col-sm-4"><input type="number" min="0" max="90" step="0.001" class="form-control" name="a1" id="a1" data-bs-toggle="tooltip" title="Enter the angle for the gravity. Zero value will be ignored"></div>
|
<div class="col-sm-4"><input type="number" min="0" max="90" step="0.001" class="form-control" name="a1" id="a1" data-bs-toggle="tooltip" title="Enter the angle for the gravity. Zero value will be ignored"></div>
|
||||||
<div class="col-sm-4"><input type="number" min="0" max="26" step="0.0001" class="form-control" name="g1" id="g1" data-bs-toggle="tooltip" title="Enter the gravity for the angle."></div>
|
<input hidden type="number" name="g1" id="g1">
|
||||||
|
<div class="col-sm-4"><input disabled type="number" class="form-control" name="g1a" id="g1a" data-bs-toggle="tooltip" title="The first value is reserved for water gravity."></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
@ -369,6 +376,7 @@
|
|||||||
if(isPlato()) {
|
if(isPlato()) {
|
||||||
$("#gravity-header").text("Gravity (Plato):");
|
$("#gravity-header").text("Gravity (Plato):");
|
||||||
$("#g1").val( parseFloat(cfg["g1"]).toFixed(1) );
|
$("#g1").val( parseFloat(cfg["g1"]).toFixed(1) );
|
||||||
|
$("#g1a").val( "0.0" );
|
||||||
$("#g2").val( parseFloat(cfg["g2"]).toFixed(1) );
|
$("#g2").val( parseFloat(cfg["g2"]).toFixed(1) );
|
||||||
$("#g3").val( parseFloat(cfg["g3"]).toFixed(1) );
|
$("#g3").val( parseFloat(cfg["g3"]).toFixed(1) );
|
||||||
$("#g4").val( parseFloat(cfg["g4"]).toFixed(1) );
|
$("#g4").val( parseFloat(cfg["g4"]).toFixed(1) );
|
||||||
@ -381,6 +389,7 @@
|
|||||||
} else {
|
} else {
|
||||||
$("#gravity-header").text("Gravity (SG):");
|
$("#gravity-header").text("Gravity (SG):");
|
||||||
$("#g1").val( parseFloat(cfg["g1"]).toFixed(4) );
|
$("#g1").val( parseFloat(cfg["g1"]).toFixed(4) );
|
||||||
|
$("#g1a").val( "1.0000" );
|
||||||
$("#g2").val( parseFloat(cfg["g2"]).toFixed(4) );
|
$("#g2").val( parseFloat(cfg["g2"]).toFixed(4) );
|
||||||
$("#g3").val( parseFloat(cfg["g3"]).toFixed(4) );
|
$("#g3").val( parseFloat(cfg["g3"]).toFixed(4) );
|
||||||
$("#g4").val( parseFloat(cfg["g4"]).toFixed(4) );
|
$("#g4").val( parseFloat(cfg["g4"]).toFixed(4) );
|
||||||
|
366
html/config.htm
@ -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">
|
||||||
@ -101,19 +109,23 @@
|
|||||||
<div id="collapseDevice" class="accordion-collapse collapse show" aria-labelledby="headingDevice" data-bs-parent="#accordion">
|
<div id="collapseDevice" class="accordion-collapse collapse show" aria-labelledby="headingDevice" data-bs-parent="#accordion">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
|
|
||||||
|
<input type="text" name="runtime-average" id="runtime-average" hidden>
|
||||||
|
<input type="text" name="platform" id="platform" hidden>
|
||||||
|
<input type="text" name="voltage-factor-calc" id="voltage-factor-calc" hidden>
|
||||||
|
|
||||||
<form action="/api/config/device" method="post">
|
<form action="/api/config/device" method="post">
|
||||||
<input type="text" name="id" id="id1" hidden>
|
<input type="text" name="id" id="id1" hidden>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="mdns" class="col-sm-2 col-form-label">Device name:</label>
|
<label for="mdns" class="col-sm-2 col-form-label">Device name</label>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<input type="text" maxlength="12" class="form-control" name="mdns" id="mdns" data-bs-toggle="tooltip" title="Name of the device. Will be used for identifying the device when pushing data and on the local network.">
|
<input type="text" maxlength="63" class="form-control" name="mdns" id="mdns" placeholder="gravmon" data-bs-toggle="tooltip" title="Name of the device. Will be used for identifying the device when pushing data and on the local network.">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<fieldset class="form-group row">
|
<fieldset class="form-group row">
|
||||||
<legend class="col-form-label col-sm-2 float-sm-left pt-0">Temperature Format:</legend>
|
<legend class="col-form-label col-sm-2 float-sm-left pt-0">Temperature Format</legend>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="temp-format" id="temp-format-c" value="C" checked data-bs-toggle="tooltip" title="Temperature format used with displaying data">
|
<input class="form-check-input" type="radio" name="temp-format" id="temp-format-c" value="C" checked data-bs-toggle="tooltip" title="Temperature format used with displaying data">
|
||||||
@ -121,16 +133,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="temp-format" id="temp-format-f" value="F" data-bs-toggle="tooltip" title="Temperature format used with displaying data">
|
<input class="form-check-input" type="radio" name="temp-format" id="temp-format-f" value="F" data-bs-toggle="tooltip" title="Temperature format used with displaying data">
|
||||||
<label class="form-check-label" for="temp-format-f">Farenheight</label>
|
<label class="form-check-label" for="temp-format-f">Fahrenheit</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="sleep-interval" class="col-sm-2 col-form-label">Interval (seconds):</label>
|
<label for="sleep-interval" class="col-sm-2 col-form-label">Interval (seconds)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<input type="number" min="10" max="3600" class="form-control" name="sleep-interval" id="sleep-interval" data-bs-toggle="tooltip" title="The number of seconds that the device will sleep between gravity readings. Recommended value is 300s">
|
<input type="number" min="10" max="3600" class="form-control" name="sleep-interval" id="sleep-interval" placeholder="300" data-bs-toggle="tooltip" title="The number of seconds that the device will sleep between gravity readings. Recommended value is 300s">
|
||||||
</div>
|
</div>
|
||||||
<label for="sleep-interval" class="col-sm-4 col-form-label" id="sleep-interval-info"></label>
|
<label for="sleep-interval" class="col-sm-4 col-form-label" id="sleep-interval-info"></label>
|
||||||
</div>
|
</div>
|
||||||
@ -145,7 +157,22 @@
|
|||||||
<hr class="my-2">
|
<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 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">
|
||||||
|
<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>
|
||||||
<label for="gyro-calibration-data" class="col-sm-2 col-form-label" id="angle">Loading...</label>
|
<label for="gyro-calibration-data" class="col-sm-2 col-form-label" id="angle">Loading...</label>
|
||||||
<div class="col-sm-8 offset-sm-2">
|
<div class="col-sm-8 offset-sm-2">
|
||||||
@ -174,7 +201,7 @@
|
|||||||
<input type="text" name="http-push2-h2" id="http-push2-h2" hidden>
|
<input type="text" name="http-push2-h2" id="http-push2-h2" hidden>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="http-push" class="col-sm-2 col-form-label">HTTP 1 (POST):</label>
|
<label for="http-push" class="col-sm-2 col-form-label">HTTP 1 (POST)</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="url" maxlength="120" class="form-control" name="http-push" id="http-push" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https)">
|
<input type="url" maxlength="120" class="form-control" name="http-push" id="http-push" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https)">
|
||||||
</div>
|
</div>
|
||||||
@ -184,7 +211,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="http-push2" class="col-sm-2 col-form-label">HTTP 2 (POST):</label>
|
<label for="http-push2" class="col-sm-2 col-form-label">HTTP 2 (POST)</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="url" maxlength="120" class="form-control" name="http-push2" id="http-push2" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https)">
|
<input type="url" maxlength="120" class="form-control" name="http-push2" id="http-push2" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https)">
|
||||||
</div>
|
</div>
|
||||||
@ -194,21 +221,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="token" class="col-sm-2 col-form-label">Token:</label>
|
<label for="token" class="col-sm-2 col-form-label">Token</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="50" class="form-control" name="token" id="token" data-bs-toggle="tooltip" title="Token can be used in the format template as a variable, some services use this for authentication">
|
<input type="text" maxlength="50" class="form-control" name="token" id="token" data-bs-toggle="tooltip" title="Token can be used in the format template as a variable, some services use this for authentication">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="http-push3" class="col-sm-2 col-form-label">HTTP 3 (GET):</label>
|
<label for="http-push3" class="col-sm-2 col-form-label">HTTP 3 (GET)</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="url" maxlength="120" class="form-control" name="http-push3" id="http-push3" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https). Do not add the query string, that will be added via the format template">
|
<input type="url" maxlength="120" class="form-control" name="http-push3" id="http-push3" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https). Do not add the query string, that will be added via the format template">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="token2" class="col-sm-2 col-form-label">Token 2:</label>
|
<label for="token2" class="col-sm-2 col-form-label">Token 2</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="50" class="form-control" name="token2" id="token2" data-bs-toggle="tooltip" title="Token can be used in the format template as a variable, some services use this for authentication">
|
<input type="text" maxlength="50" class="form-control" name="token2" id="token2" data-bs-toggle="tooltip" title="Token can be used in the format template as a variable, some services use this for authentication">
|
||||||
</div>
|
</div>
|
||||||
@ -217,17 +244,11 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-8 offset-sm-2">
|
<div class="col-sm-8 offset-sm-2">
|
||||||
<button type="submit" class="btn btn-primary" id="push-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
|
<button type="submit" class="btn btn-primary" id="push-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" id="format-btn" data-bs-toggle="tooltip" title="Open up the format editor to change data format posted">Format editor</button>
|
||||||
|
<button type="button" class="btn btn-secondary" id="test-btn" data-bs-toggle="tooltip" title="Test posting data to defined push targets">Test Push</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-sm-8 offset-sm-2">
|
|
||||||
<button class="btn btn-secondary" id="format-btn" data-bs-toggle="tooltip" title="Open up the format editor to change data format posted">Format editor</button>
|
|
||||||
<button class="btn btn-secondary" id="test-btn" data-bs-toggle="tooltip" title="Test posting data to defined push targets">Test Push</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -246,28 +267,28 @@
|
|||||||
<input type="text" name="section" value="collapsePush2" hidden>
|
<input type="text" name="section" value="collapsePush2" hidden>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="influxdb2-push" class="col-sm-2 col-form-label">InfluxDB v2 URL:</label>
|
<label for="influxdb2-push" class="col-sm-2 col-form-label">InfluxDB v2 URL</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="url" maxlength="40" class="form-control" name="influxdb2-push" placeholder="http://www.internet.com" id="influxdb2-push" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com (Supports http and https)">
|
<input type="url" maxlength="40" class="form-control" name="influxdb2-push" placeholder="http://www.internet.com" id="influxdb2-push" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com (Supports http and https)">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="influxdb2-org" class="col-sm-2 col-form-label">InfluxDB v2 Org:</label>
|
<label for="influxdb2-org" class="col-sm-2 col-form-label">InfluxDB v2 Org</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="50" class="form-control" name="influxdb2-org" id="influxdb2-org" data-bs-toggle="tooltip" title="Identifier to what organisation to use">
|
<input type="text" maxlength="50" class="form-control" name="influxdb2-org" id="influxdb2-org" data-bs-toggle="tooltip" title="Identifier to what organisation to use">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="influxdb2-bucket" class="col-sm-2 col-form-label">InfluxDB v2 Bucket:</label>
|
<label for="influxdb2-bucket" class="col-sm-2 col-form-label">InfluxDB v2 Bucket</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="50" class="form-control" name="influxdb2-bucket" id="influxdb2-bucket" data-bs-toggle="tooltip" title="Identifier for the data bucket to use">
|
<input type="text" maxlength="50" class="form-control" name="influxdb2-bucket" id="influxdb2-bucket" data-bs-toggle="tooltip" title="Identifier for the data bucket to use">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="influxdb2-auth" class="col-sm-2 col-form-label">InfluxDB v2 Auth:</label>
|
<label for="influxdb2-auth" class="col-sm-2 col-form-label">InfluxDB v2 Auth</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="100" class="form-control" name="influxdb2-auth" id="influxdb2-auth" data-bs-toggle="tooltip" title="Authentication token for accessing data bucket">
|
<input type="text" maxlength="100" class="form-control" name="influxdb2-auth" id="influxdb2-auth" data-bs-toggle="tooltip" title="Authentication token for accessing data bucket">
|
||||||
</div>
|
</div>
|
||||||
@ -276,28 +297,28 @@
|
|||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="mqtt-push" class="col-sm-2 col-form-label">MQTT Server:</label>
|
<label for="mqtt-push" class="col-sm-2 col-form-label">MQTT Server</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="40" class="form-control" name="mqtt-push" id="mqtt-push" placeholder="www.internet.com" data-bs-toggle="tooltip" title="Name of server to connect to, use format servername.com">
|
<input type="text" maxlength="40" class="form-control" name="mqtt-push" id="mqtt-push" placeholder="www.internet.com" data-bs-toggle="tooltip" title="Name of server to connect to, use format servername.com">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="mqtt-topic" class="col-sm-2 col-form-label">MQTT Port:</label>
|
<label for="mqtt-topic" class="col-sm-2 col-form-label">MQTT Port</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="number" min="1" max="65535" class="form-control" name="mqtt-port" id="mqtt-port" placeholder="1138" data-bs-toggle="tooltip" title="Port number to use, 1138 is standard. Ports higher than 8000 will assume to use SSL">
|
<input type="number" min="1" max="65535" class="form-control" name="mqtt-port" id="mqtt-port" placeholder="1883" data-bs-toggle="tooltip" title="Port number to use, 1883 is standard. Ports higher than 8000 will assume to use SSL">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="mqtt-user" class="col-sm-2 col-form-label">MQTT User:</label>
|
<label for="mqtt-user" class="col-sm-2 col-form-label">MQTT User</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="20" class="form-control" name="mqtt-user" id="mqtt-user" data-bs-toggle="tooltip" title="Username to use. Leave blank if authentication is disabled">
|
<input type="text" maxlength="20" class="form-control" name="mqtt-user" id="mqtt-user" data-bs-toggle="tooltip" title="Username to use. Leave blank if authentication is disabled">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="mqtt-pass" class="col-sm-2 col-form-label">MQTT Password:</label>
|
<label for="mqtt-pass" class="col-sm-2 col-form-label">MQTT Password</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" maxlength="20" class="form-control" name="mqtt-pass" id="mqtt-pass" data-bs-toggle="tooltip" title="Password to use. Leave blank if authentication is disabled">
|
<input type="text" maxlength="20" class="form-control" name="mqtt-pass" id="mqtt-pass" data-bs-toggle="tooltip" title="Password to use. Leave blank if authentication is disabled">
|
||||||
</div>
|
</div>
|
||||||
@ -306,17 +327,12 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-8 offset-sm-2">
|
<div class="col-sm-8 offset-sm-2">
|
||||||
<button type="submit" class="btn btn-primary" id="push-btn2" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
|
<button type="submit" class="btn btn-primary" id="push-btn2" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" id="format-btn2" data-bs-toggle="tooltip" title="Open up the format editor to change data format posted">Format editor</button>
|
||||||
|
<button type="button" class="btn btn-secondary" id="test-btn2" data-bs-toggle="tooltip" title="Test posting data to defined push targets">Test Push</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-sm-8 offset-sm-2">
|
|
||||||
<button class="btn btn-secondary" id="format-btn2" data-bs-toggle="tooltip" title="Open up the format editor to change data format posted">Format editor</button>
|
|
||||||
<button class="btn btn-secondary" id="test-btn2" data-bs-toggle="tooltip" title="Test posting data to defined push targets">Test Push</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -335,7 +351,7 @@
|
|||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<fieldset class="form-group row">
|
<fieldset class="form-group row">
|
||||||
<legend class="col-form-label col-sm-2 float-sm-left pt-0">Gravity Format:</legend>
|
<label for="gravity-format" class="col-sm-2 col-form-label">Gravity Format</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="gravity-format" id="gravity-format-g" value="G" checked data-bs-toggle="tooltip" title="Present gravity in SG format">
|
<input class="form-check-input" type="radio" name="gravity-format" id="gravity-format-g" value="G" checked data-bs-toggle="tooltip" title="Present gravity in SG format">
|
||||||
@ -352,12 +368,12 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="gravity-formula" class="col-sm-2 col-form-label">Formula</label>
|
<label for="gravity-formula" class="col-sm-2 col-form-label">Formula</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="text" maxlength="200" class="form-control" name="gravity-formula" id="gravity-formula" checked data-bs-toggle="tooltip" title="Formula used to convert angle to gravity">
|
<input type="text" maxlength="200" class="form-control" name="gravity-formula" id="gravity-formula" placeholder="0.0*tilt^2+0.01*tilt+0.2" checked data-bs-toggle="tooltip" title="Formula used to convert angle to gravity">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-4 offset-sm-2">
|
<div class="col-sm-3 offset-sm-2">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" name="gravity-temp-adjustment" id="gravity-temp-adjustment" checked data-bs-toggle="tooltip" title="Adjust the calculated gravity based on the current temperature. Assumes that calibration is done using 20C / 68F">
|
<input class="form-check-input" type="checkbox" name="gravity-temp-adjustment" id="gravity-temp-adjustment" checked data-bs-toggle="tooltip" title="Adjust the calculated gravity based on the current temperature. Assumes that calibration is done using 20C / 68F">
|
||||||
<label class="form-check-label" for="gravity-temp-adjustment">Temperature adjust gravity</label>
|
<label class="form-check-label" for="gravity-temp-adjustment">Temperature adjust gravity</label>
|
||||||
@ -388,22 +404,37 @@
|
|||||||
<input type="text" name="id" id="id4" hidden>
|
<input type="text" name="id" id="id4" hidden>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="voltage-factor" class="col-sm-2 col-form-label">Voltage factor:</label>
|
<label for="voltage-factor" class="col-sm-2 col-form-label">Voltage factor</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<input type="number" step=".01" class="form-control" name="voltage-factor" id="voltage-factor" data-bs-toggle="tooltip" title="Factor used to calculate the battery voltage. When running on battery, the voltage should be less than 4.15V">
|
<input type="number" step=".01" class="form-control" name="voltage-factor" id="voltage-factor" placeholder="1.59" data-bs-toggle="tooltip" title="Factor used to calculate the battery voltage. Can vary depending on the R2 value">
|
||||||
</div>
|
</div>
|
||||||
<label for="voltage-factor" class="col-sm-3 col-form-label" id="battery">Loading...</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<label for="temp-adjustment-value" class="col-sm-2 col-form-label">Temp Sensor Adj:</label>
|
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<input type="number" step=".1" class="form-control" name="temp-adjustment-value" id="temp-adjustment-value" data-bs-toggle="tooltip" title="This value will be added to the sensor value in case the sensor dont show the correct temperature">
|
<label for="voltage-factor" class="col-sm-3 col-form-label" id="battery">Loading...</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<button type="button" class="btn btn-secondary" id="volt-factor-btn" data-bs-toggle="tooltip" title="Calcualte the voltage factor based on measured battery voltage">Calculate</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="number" step=".01" class="form-control" name="measured-voltage" id="measured-voltage" placeholder="" data-bs-toggle="tooltip" title="Enter the measured battery voltage to calcualte the factor">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-3 offset-sm-2">
|
<label for="voltage-config" class="col-sm-2 col-form-label">Config voltage</label>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="number" step=".01" min="3.00" max="6.00" class="form-control" name="voltage-config" id="voltage-config" placeholder="4.16" data-bs-toggle="tooltip" title="Over this level the device will always go into configuration mode, some batteries might have a higher voltage when fully charged">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="temp-adjustment-value" class="col-sm-2 col-form-label">Temp Sensor Adj</label>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="number" step=".1" class="form-control" name="temp-adjustment-value" id="temp-adjustment-value" placeholder="0" data-bs-toggle="tooltip" title="This value will be added to the sensor value in case the sensor dont show the correct temperature">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-4 offset-sm-2">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" name="gyro-temp" id="gyro-temp" data-bs-toggle="tooltip" title="Use the temperature sensor in the gyro instead of DS18B20, require 300s update interval to be accurate">
|
<input class="form-check-input" type="checkbox" name="gyro-temp" id="gyro-temp" data-bs-toggle="tooltip" title="Use the temperature sensor in the gyro instead of DS18B20, require 300s update interval to be accurate">
|
||||||
<label class="form-check-label" for="gyro-temp">Use gyro temperature</label>
|
<label class="form-check-label" for="gyro-temp">Use gyro temperature</label>
|
||||||
@ -411,6 +442,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-4 offset-sm-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="storage-sleep" id="storage-sleep" data-bs-toggle="tooltip" title="If enabled and the device is placed on its cap (less than 5 degress) it will go into sleep for 2000 minutes">
|
||||||
|
<label class="form-check-label" for="storage-sleep">Enable storage mode when placed on cap</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label class="col-sm-2 col-form-label" for="ble">Bluetooth tilt color:</label>
|
<label class="col-sm-2 col-form-label" for="ble">Bluetooth tilt color:</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
@ -428,23 +468,62 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3" id="ota-hide">
|
||||||
<label for="ota-url" class="col-sm-2 col-form-label">OTA base URL:</label>
|
<label for="ota-url" class="col-sm-2 col-form-label">OTA base URL</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="url" maxlength="90" class="form-control" name="ota-url" id="ota-url" placeholder="http://www.local.com/path/" data-bs-toggle="tooltip" title="Base URL to where firmware and version.json file can be found. Needs to end with '/', example: http://www.mysite.com/firmware/">
|
<input type="url" maxlength="90" class="form-control" name="ota-url" id="ota-url" placeholder="http://www.local.com/path/" data-bs-toggle="tooltip" title="Base URL to where firmware and version.json file can be found. Needs to end with '/', example: http://www.mysite.com/firmware/">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-4 offset-sm-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="gravitymon-com" id="gravitymon-com" data-bs-toggle="tooltip" title="If enabled gravitymon.com will be checked for new versions.">
|
||||||
|
<label class="form-check-label" for="gravitymon-com">OTA from gravitymon.com</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$("#volt-factor-btn").click(function(e) {
|
||||||
|
var f = $("#voltage-factor-calc").val();
|
||||||
|
var mv = parseFloat( $("#measured-voltage").val() );
|
||||||
|
|
||||||
|
if( isNaN(mv) ) {
|
||||||
|
showError("You need to enter a measured voltage in order to calculate the factor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vf = mv / f;
|
||||||
|
$("#voltage-factor").val( parseFloat(vf).toFixed(2) );
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var gravitymonUrl = "https://www.gravitymon.com/firmware/";
|
||||||
|
|
||||||
|
$("#gravitymon-com").click(function(e){
|
||||||
|
var b = $("#gravitymon-com").is(":checked");
|
||||||
|
|
||||||
|
if ( b ) {
|
||||||
|
$("#ota-url").val(gravitymonUrl);
|
||||||
|
$('#ota-hide').hide();
|
||||||
|
} else {
|
||||||
|
$('#ota-hide').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-8 offset-sm-2">
|
<div class="col-sm-8 offset-sm-2">
|
||||||
<button type="submit" class="btn btn-primary" id="hardware-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
|
<button type="submit" class="btn btn-primary" id="hardware-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
|
||||||
|
<button type="button" class="btn btn-secondary" id="firmware-btn" checked data-bs-toggle="tooltip" title="Manually upload a new firmware version to the device">Upload firmware</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-8 offset-sm-2">
|
<div class="col-sm-8 offset-sm-2">
|
||||||
<button class="btn btn-secondary" id="firmware-btn" checked data-bs-toggle="tooltip" title="Manually upload a new firmware version to the device">Upload firmware</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -453,45 +532,72 @@
|
|||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<h2 class="accordion-header" id="headingAdvanced">
|
<h2 class="accordion-header" id="headingAdvanced">
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvanced" aria-expanded="false" aria-controls="collapseAdvanced">
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvanced" aria-expanded="false" aria-controls="collapseAdvanced">
|
||||||
<b>Advanced Settings (use with caution)</b>
|
<b>Advanced Software Settings (use with caution)</b>
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
<div id="collapseAdvanced" class="accordion-collapse collapse" aria-labelledby="headingAdvanced" data-bs-parent="#accordion">
|
<div id="collapseAdvanced" class="accordion-collapse collapse" aria-labelledby="headingAdvanced" data-bs-parent="#accordion">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="form-check">
|
||||||
|
<input checked class="form-check-input" type="checkbox" name="adv-config" id="adv-config" data-bs-toggle="tooltip" title="Enable the advanced software settings.">
|
||||||
|
<label class="form-check-label" for="adv-config">Disable advanced software settings</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form action="/api/config/advanced" method="post">
|
<form action="/api/config/advanced" method="post">
|
||||||
<input type="text" name="id" id="id6" hidden>
|
<input type="text" name="id" id="id6" hidden>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="gyro-read-count" class="col-sm-3 col-form-label">Gyro reads:</label>
|
<label for="gyro-read-count" class="col-sm-3 col-form-label">Gyro reads:</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="10" max="100" class="form-control" name="gyro-read-count" id="gyro-read-count" checked data-bs-toggle="tooltip" title="How many times should we read the gyro to get an accurate angle. More reads = better accuracy but higher battery drain">
|
<input disabled type="number" min="10" max="100" class="form-control" name="gyro-read-count" id="gyro-read-count" placeholder="50" checked data-bs-toggle="tooltip" title="How many times should we read the gyro to get an accurate angle. More reads = better accuracy but higher battery drain">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(10-100) - default 50</div>
|
<div class="col-sm-5">(10-100) - default 50</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="gyro-moving-threashold" class="col-sm-3 col-form-label">Gyro moving theashold:</label>
|
<label for="gyro-moving-threashold" class="col-sm-3 col-form-label">Gyro moving theashold</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="50" max="1000" class="form-control" name="gyro-moving-threashold" id="gyro-moving-threashold" checked data-bs-toggle="tooltip" title="How much deviation between gyro reads are acceptable in order to regard this as a valid angle">
|
<input disabled type="number" min="50" max="1000" class="form-control" name="gyro-moving-threashold" id="gyro-moving-threashold" placeholder="500" checked data-bs-toggle="tooltip" title="How much deviation between gyro reads are acceptable in order to regard this as a valid angle">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(50-1000) - default 500</div>
|
<div class="col-sm-5">(50-1000) - default 500</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="formula-max-deviation" class="col-sm-3 col-form-label">Formula max deviation (SG):</label>
|
<label for="formula-max-deviation" class="col-sm-3 col-form-label">Formula max deviation (SG)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" step=".1" min="1" max="10" class="form-control" name="formula-max-deviation" id="formula-max-deviation" checked data-bs-toggle="tooltip" title="When validating the derived formula this is the maximum accepted deviation for the supplied values">
|
<input disabled type="number" step=".1" min="1" max="10" class="form-control" name="formula-max-deviation" id="formula-max-deviation" placeholder="3" checked data-bs-toggle="tooltip" title="When validating the derived formula this is the maximum accepted deviation for the supplied values">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(1 - 10) - default 1.6 SG</div>
|
<div class="col-sm-5">(1 - 10) - default 3 SG</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-3 offset-sm-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<input disabled class="form-check-input" type="checkbox" class="form-control" name="ignore-low-angles" id="ignore-low-angles" data-bs-toggle="tooltip" title="When active, angles below water will be ignored. Note! Angle must be defined under calibration, first field.">
|
||||||
|
<label class="form-check-label" for="ignore-low-angles">Ignore angles below water</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-5" name="water-angle" id="water-angle"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="formula-calibration-temp" class="col-sm-3 col-form-label">Gravity calibration temp</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<input disabled type="number" step=".01" min="0" max="100" class="form-control" name="formula-calibration-temp" id="formula-calibration-temp" placeholder="20" checked data-bs-toggle="tooltip" title="Calibration temperature, used in temperatur correction formula, default 20C/68F">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-5">(0 - 100) - default 20C/68F</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="tempsensor-resolution" class="col-sm-3 col-form-label">DS18B20 resolution (bits):</label>
|
<label for="tempsensor-resolution" class="col-sm-3 col-form-label">DS18B20 resolution (bits)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="9" max="12" class="form-control" name="tempsensor-resolution" id="tempsensor-resolution" checked data-bs-toggle="tooltip" title="Resolution when reading the DS18B20 temperature sensor, higher resolution give better accuracy but takes longer">
|
<input disabled type="number" min="9" max="12" class="form-control" name="tempsensor-resolution" id="tempsensor-resolution" placeholder="9" checked data-bs-toggle="tooltip" title="Resolution when reading the DS18B20 temperature sensor, higher resolution give better accuracy but takes longer">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(9 - 12) - default 9 bits</div>
|
<div class="col-sm-5">(9 - 12) - default 9 bits</div>
|
||||||
</div>
|
</div>
|
||||||
@ -499,17 +605,17 @@
|
|||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="wifi-connect-timeout" class="col-sm-3 col-form-label">Wifi connect timeout (s):</label>
|
<label for="wifi-connect-timeout" class="col-sm-3 col-form-label">Wifi connect timeout (s)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="1" max="60" class="form-control" name="wifi-connect-timeout" id="wifi-connect-timeout" checked data-bs-toggle="tooltip" title="Max time waiting for a wifi connection before going back to sleep">
|
<input disabled type="number" min="1" max="60" class="form-control" name="wifi-connect-timeout" id="wifi-connect-timeout" placeholder="20" checked data-bs-toggle="tooltip" title="Max time waiting for a wifi connection before going back to sleep">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(1 - 60) - default 20 s</div>
|
<div class="col-sm-5">(1 - 60) - default 20 s</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="wifi-portal-timeout" class="col-sm-3 col-form-label">Wifi portal timeout (s):</label>
|
<label for="wifi-portal-timeout" class="col-sm-3 col-form-label">Wifi portal timeout (s)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="10" max="240" class="form-control" name="wifi-portal-timeout" id="wifi-portal-timeout" checked data-bs-toggle="tooltip" title="Max time the wifi portal is active before existing">
|
<input disabled type="number" min="10" max="240" class="form-control" name="wifi-portal-timeout" id="wifi-portal-timeout" placeholder="120" checked data-bs-toggle="tooltip" title="Max time the wifi portal is active before existing">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(10 - 240) - default 120 s</div>
|
<div class="col-sm-5">(10 - 240) - default 120 s</div>
|
||||||
</div>
|
</div>
|
||||||
@ -518,40 +624,40 @@
|
|||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="int-http1" class="col-sm-3 col-form-label">Skip interval - HTTP 1 (POST):</label>
|
<label for="int-http1" class="col-sm-3 col-form-label">Skip interval - HTTP 1 (POST):</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="0" max="5" class="form-control" name="int-http1" id="int-http1" checked data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
<input disabled type="number" min="0" max="5" class="form-control" name="int-http1" id="int-http1" placeholder="0" checked data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(0 - 5) - default 0</div>
|
<div class="col-sm-5">(0 - 5) - default 0</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="int-http2" class="col-sm-3 col-form-label">Skip interval - HTTP 2 (POST):</label>
|
<label for="int-http2" class="col-sm-3 col-form-label">Skip interval - HTTP 2 (POST)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="0" max="5" class="form-control" name="int-http2" id="int-http2" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
<input disabled type="number" min="0" max="5" class="form-control" name="int-http2" id="int-http2" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(0 - 5) - default 0</div>
|
<div class="col-sm-5">(0 - 5) - default 0</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="int-http3" class="col-sm-3 col-form-label">Skip interval - HTTP 3 (GET):</label>
|
<label for="int-http3" class="col-sm-3 col-form-label">Skip interval - HTTP 3 (GET)</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="0" max="5" class="form-control" name="int-http3" id="int-http3" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
<input disabled type="number" min="0" max="5" class="form-control" name="int-http3" id="int-http3" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(0 - 5) - default 0</div>
|
<div class="col-sm-5">(0 - 5) - default 0</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="int-influx" class="col-sm-3 col-form-label">Skip interval - InfluxDB v2:</label>
|
<label for="int-influx" class="col-sm-3 col-form-label">Skip interval - InfluxDB v2</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="0" max="5" class="form-control" name="int-influx" id="int-influx" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
<input disabled type="number" min="0" max="5" class="form-control" name="int-influx" id="int-influx" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(0 - 5) - default 0</div>
|
<div class="col-sm-5">(0 - 5) - default 0</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="int-mqtt" class="col-sm-3 col-form-label">Skip interval - MQTT:</label>
|
<label for="int-mqtt" class="col-sm-3 col-form-label">Skip interval - MQTT</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-3">
|
||||||
<input disabled type="number" min="0" max="5" class="form-control" name="int-mqtt" id="int-mqtt" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
<input disabled type="number" min="0" max="5" class="form-control" name="int-mqtt" id="int-mqtt" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-5">(0 - 5) - default 0</div>
|
<div class="col-sm-5">(0 - 5) - default 0</div>
|
||||||
</div>
|
</div>
|
||||||
@ -563,15 +669,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-sm-4 offset-sm-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" name="adv-config" id="adv-config" checked data-bs-toggle="tooltip" title="Enabled the advanced configuration settings.">
|
|
||||||
<label class="form-check-label" for="adv-config">Enable advanced configuration</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -683,10 +780,40 @@
|
|||||||
// MPU-6050 consumes 4mA
|
// MPU-6050 consumes 4mA
|
||||||
// DS18B20 consumes 1mA
|
// DS18B20 consumes 1mA
|
||||||
// For this estimation we use an average of 160mA
|
// For this estimation we use an average of 160mA
|
||||||
|
var pwrActive = 160; // mA per hour (120-170 mA)
|
||||||
|
var pwrSleep = 15; // mA per day (include all pheripials as well)
|
||||||
|
var batt = 2200; // mA
|
||||||
|
var ble = false;
|
||||||
|
var wifi = true;
|
||||||
|
var platform = $("#platform").val();
|
||||||
|
|
||||||
var pwrActive = 170; // mA per hour
|
if($("#ble").val() != "")
|
||||||
var pwrSleep = 15; // mA per day
|
ble = true;
|
||||||
var batt = 2000; // mA
|
|
||||||
|
if($("#http-push").val() == "" && $("#http-push2").val() == "" && $("#http-push3").val() == "" && $("#influxdb2-push").val() == "" && $("#mqtt-push").val() == "")
|
||||||
|
wifi = false;
|
||||||
|
|
||||||
|
console.log( "Connection options: BLE=" + (ble?"on":"off") + " WIFI=" + (wifi?"on":"off") );
|
||||||
|
|
||||||
|
if(platform == "esp32" && wifi) {
|
||||||
|
var pwrActive = 320; // mA per hour (260-379 mA)
|
||||||
|
} else if(platform == "esp32" && !wifi) {
|
||||||
|
var pwrActive = 160;
|
||||||
|
} else if(platform == "esp32c3" && wifi) {
|
||||||
|
var pwrActive = 320; // mA per hour (290-350 mA)
|
||||||
|
} else if(platform == "esp32c3" && !wifi) {
|
||||||
|
var pwrActive = 160;
|
||||||
|
} else if(platform == "esp32s2" && wifi) {
|
||||||
|
var pwrActive = 280; // mA per hour (260-300 mA)
|
||||||
|
} else if(platform == "esp32s2" && !wifi) {
|
||||||
|
var pwrActive = 160;
|
||||||
|
} else if(platform == "esp32lite" && wifi) {
|
||||||
|
var pwrActive = 330; // mA per hour (260-379 mA)
|
||||||
|
} else if(platform == "esp32lite" && !wifi) {
|
||||||
|
var pwrActive = 160;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log( "Estimated power per hour = " + pwrActive.toString() + "mA on platform = " + platform);
|
||||||
|
|
||||||
if(rt<1) rt = 2;
|
if(rt<1) rt = 2;
|
||||||
|
|
||||||
@ -700,8 +827,11 @@
|
|||||||
var rt = parseInt($("#runtime-average").val());
|
var rt = parseInt($("#runtime-average").val());
|
||||||
var j = 0;
|
var j = 0;
|
||||||
|
|
||||||
if( rt>0 )
|
console.log("Average runtime " + $("#runtime-average").val() )
|
||||||
|
|
||||||
|
if( rt>0 ) {
|
||||||
j = estimateBatteryLife(i, rt);
|
j = estimateBatteryLife(i, rt);
|
||||||
|
}
|
||||||
|
|
||||||
var t1 = Math.floor(i/60) + " m " + (i%60) + " s";
|
var t1 = Math.floor(i/60) + " m " + (i%60) + " s";
|
||||||
var t2 = Math.floor(j/7) + " weeks " + Math.floor(j%7) + " days";
|
var t2 = Math.floor(j/7) + " weeks " + Math.floor(j%7) + " days";
|
||||||
@ -738,14 +868,14 @@
|
|||||||
$("#test-btn2").prop("disabled", b);
|
$("#test-btn2").prop("disabled", b);
|
||||||
$("#advanced-btn").prop("disabled", b);
|
$("#advanced-btn").prop("disabled", b);
|
||||||
|
|
||||||
checkAdvancedSection( b );
|
checkAdvancedSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#adv-config").click(function(e){
|
$("#adv-config").click(function(e){
|
||||||
checkAdvancedSection();
|
checkAdvancedSection();
|
||||||
});
|
});
|
||||||
|
|
||||||
function checkAdvancedSection( b ) {
|
function checkAdvancedSection() {
|
||||||
var b = $("#adv-config").is(":checked");
|
var b = $("#adv-config").is(":checked");
|
||||||
|
|
||||||
$("#advanced-btn").prop("disabled", b);
|
$("#advanced-btn").prop("disabled", b);
|
||||||
@ -754,12 +884,14 @@
|
|||||||
$("#formula-max-deviation").prop("disabled", b);
|
$("#formula-max-deviation").prop("disabled", b);
|
||||||
$("#wifi-portal-timeout").prop("disabled", b);
|
$("#wifi-portal-timeout").prop("disabled", b);
|
||||||
$("#wifi-connect-timeout").prop("disabled", b);
|
$("#wifi-connect-timeout").prop("disabled", b);
|
||||||
|
$("#formula-calibration-temp").prop("disabled", b);
|
||||||
$("#int-http1").prop("disabled", b);
|
$("#int-http1").prop("disabled", b);
|
||||||
$("#int-http2").prop("disabled", b);
|
$("#int-http2").prop("disabled", b);
|
||||||
$("#int-http3").prop("disabled", b);
|
$("#int-http3").prop("disabled", b);
|
||||||
$("#int-influx").prop("disabled", b);
|
$("#int-influx").prop("disabled", b);
|
||||||
$("#int-mqtt").prop("disabled", b);
|
$("#int-mqtt").prop("disabled", b);
|
||||||
$("#tempsensor-resolution").prop("disabled", b);
|
$("#tempsensor-resolution").prop("disabled", b);
|
||||||
|
$("#ignore-low-angles").prop("disabled", b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the advanced values from the API
|
// Get the advanced values from the API
|
||||||
@ -778,11 +910,18 @@
|
|||||||
$("#wifi-portal-timeout").val(cfg["wifi-portal-timeout"]);
|
$("#wifi-portal-timeout").val(cfg["wifi-portal-timeout"]);
|
||||||
$("#wifi-connect-timeout").val(cfg["wifi-connect-timeout"]);
|
$("#wifi-connect-timeout").val(cfg["wifi-connect-timeout"]);
|
||||||
$("#tempsensor-resolution").val(cfg["tempsensor-resolution"]);
|
$("#tempsensor-resolution").val(cfg["tempsensor-resolution"]);
|
||||||
|
$("#ignore-low-angles").prop( "checked", cfg["ignore-low-angles"] );
|
||||||
|
$("#formula-calibration-temp").val(cfg["formula-calibration-temp"]);
|
||||||
$("#int-http1").val(cfg["int-http1"]);
|
$("#int-http1").val(cfg["int-http1"]);
|
||||||
$("#int-http2").val(cfg["int-http2"]);
|
$("#int-http2").val(cfg["int-http2"]);
|
||||||
$("#int-http3").val(cfg["int-http3"]);
|
$("#int-http3").val(cfg["int-http3"]);
|
||||||
$("#int-influx").val(cfg["int-influx"]);
|
$("#int-influx").val(cfg["int-influx"]);
|
||||||
$("#int-mqtt").val(cfg["int-mqtt"]);
|
$("#int-mqtt").val(cfg["int-mqtt"]);
|
||||||
|
|
||||||
|
if ( cfg["gyro-read-count"] != 50 || cfg["gyro-moving-threashold"] != 500 || cfg["formula-max-deviation"] != 3 || cfg["wifi-portal-timeout"] != 120 || cfg["wifi-connect-timeout"] != 20 || cfg["tempsensor-resolution"] != 9 ||
|
||||||
|
cfg["int-http1"] != 0 || cfg["int-http2"] != 0 || cfg["int-http3"] != 0 || cfg["int-influx"] != 0 || cfg["int-mqtt"] != 0 || cfg["ignore-low-angles"] != false || (cfg["formula-calibration-temp"] != 20 && cfg["formula-calibration-temp"] != 68)) {
|
||||||
|
$("#adv-config").attr("checked", false );
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.fail(function () {
|
.fail(function () {
|
||||||
showError('Unable to get data from the device.');
|
showError('Unable to get data from the device.');
|
||||||
@ -803,11 +942,15 @@
|
|||||||
$.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" || cfg["platform"]=="esp32lite") {
|
||||||
$('#ble').prop('disabled', false);
|
$('#ble').prop('disabled', false);
|
||||||
$("#ble").val(cfg["ble"]);
|
$("#ble").val(cfg["ble"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cfg["platform"]=="esp32lite") {
|
||||||
|
$('#gyro-temp').prop('disabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
$("#id1").val(cfg["id"]);
|
$("#id1").val(cfg["id"]);
|
||||||
$("#id2").val(cfg["id"]);
|
$("#id2").val(cfg["id"]);
|
||||||
$("#id3").val(cfg["id"]);
|
$("#id3").val(cfg["id"]);
|
||||||
@ -820,6 +963,12 @@
|
|||||||
if( cfg["gravity-format"] == "G" ) $("#gravity-format-g").click();
|
if( cfg["gravity-format"] == "G" ) $("#gravity-format-g").click();
|
||||||
else $("#gravity-format-p").click();
|
else $("#gravity-format-p").click();
|
||||||
$("#ota-url").val(cfg["ota-url"]);
|
$("#ota-url").val(cfg["ota-url"]);
|
||||||
|
|
||||||
|
if( cfg["ota-url"] == gravitymonUrl) {
|
||||||
|
$("#gravitymon-com").prop( "checked", true );
|
||||||
|
$("#ota-hide").hide();
|
||||||
|
}
|
||||||
|
|
||||||
$("#token").val(cfg["token"]);
|
$("#token").val(cfg["token"]);
|
||||||
$("#token2").val(cfg["token2"]);
|
$("#token2").val(cfg["token2"]);
|
||||||
$("#http-push").val(cfg["http-push"]);
|
$("#http-push").val(cfg["http-push"]);
|
||||||
@ -839,14 +988,21 @@
|
|||||||
$("#mqtt-pass").val(cfg["mqtt-pass"]);
|
$("#mqtt-pass").val(cfg["mqtt-pass"]);
|
||||||
$("#sleep-interval").val(cfg["sleep-interval"]);
|
$("#sleep-interval").val(cfg["sleep-interval"]);
|
||||||
$("#voltage-factor").val(cfg["voltage-factor"]);
|
$("#voltage-factor").val(cfg["voltage-factor"]);
|
||||||
|
$("#voltage-config").val(cfg["voltage-config"]);
|
||||||
$("#gravity-formula").val(cfg["gravity-formula"]);
|
$("#gravity-formula").val(cfg["gravity-formula"]);
|
||||||
$("#temp-adjustment-value").val(cfg["temp-adjustment-value"]);
|
$("#temp-adjustment-value").val(cfg["temp-adjustment-value"]);
|
||||||
$("#gravity-temp-adjustment").prop( "checked", cfg["gravity-temp-adjustment"] );
|
$("#gravity-temp-adjustment").prop( "checked", cfg["gravity-temp-adjustment"] );
|
||||||
$("#gyro-temp").prop( "checked", cfg["gyro-temp"] );
|
$("#gyro-temp").prop( "checked", cfg["gyro-temp"] );
|
||||||
|
$("#storage-sleep").prop( "checked", cfg["storage-sleep"] );
|
||||||
$("#gyro-calibration-data").text( cfg["gyro-calibration-data"]["ax"] + "," + cfg["gyro-calibration-data"]["ay"] + "," + cfg["gyro-calibration-data"]["az"] + "," + cfg["gyro-calibration-data"]["gx"] + "," + cfg["gyro-calibration-data"]["gy"] + "," + cfg["gyro-calibration-data"]["gz"] );
|
$("#gyro-calibration-data").text( cfg["gyro-calibration-data"]["ax"] + "," + cfg["gyro-calibration-data"]["ay"] + "," + cfg["gyro-calibration-data"]["az"] + "," + cfg["gyro-calibration-data"]["gx"] + "," + cfg["gyro-calibration-data"]["gy"] + "," + cfg["gyro-calibration-data"]["gz"] );
|
||||||
$("#battery").text(cfg["battery"] + " V");
|
$("#battery").text(cfg["battery"] + " V");
|
||||||
$("#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");
|
||||||
|
$("#wifi-ssid").text(cfg["wifi-ssid"]);
|
||||||
|
$("#wifi-ssid2").text(cfg["wifi-ssid2"]);
|
||||||
|
$("#platform").val(cfg["platform"]);
|
||||||
|
$("#voltage-factor-calc").val( cfg["battery"] / cfg["voltage-factor"] );
|
||||||
//$("#gravity").text(cfg["gravity"] + " SG");
|
//$("#gravity").text(cfg["gravity"] + " SG");
|
||||||
})
|
})
|
||||||
.fail(function () {
|
.fail(function () {
|
||||||
|
@ -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,9 +22,26 @@
|
|||||||
<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 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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -34,6 +49,7 @@
|
|||||||
</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);
|
||||||
|
@ -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);
|
||||||
|
176
html/format.htm
@ -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,9 +22,26 @@
|
|||||||
<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 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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -34,29 +49,54 @@
|
|||||||
</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,20 +129,22 @@
|
|||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let formatTemplates = [
|
let formatTemplates = [
|
||||||
{ "id": "GravityMon-Post", "format": "%7B%0A%20%22name%22%20%3A%20%22%24%7Bmdns%7D%22%2C%0A%20%22ID%22%3A%20%22%24%7Bid%7D%22%2C%0A%20%22token%22%20%3A%20%22gravmon%22%2C%0A%20%22interval%22%3A%20%24%7Bsleep-interval%7D%2C%0A%20%22temperature%22%3A%20%24%7Btemp%7D%2C%0A%20%22temp_units%22%3A%20%22%24%7Btemp-unit%7D%22%2C%0A%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%0A%20%22angle%22%3A%20%24%7Bangle%7D%2C%0A%20%22battery%22%3A%20%24%7Bbattery%7D%2C%0A%20%22RSSI%22%3A%20%24%7Brssi%7D%2C%0A%20%22corr-gravity%22%3A%20%24%7Bcorr-gravity%7D%2C%0A%20%22gravity-unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%0A%20%22run-time%22%3A%20%24%7Brun-time%7D%0A%7D" },
|
{ "id": "GravityMon-Post", "format": "%7B%20%22name%22%20%3A%20%22%24%7Bmdns%7D%22%2C%20%22ID%22%3A%20%22%24%7Bid%7D%22%2C%20%22token%22%20%3A%20%22%24%7Btoken%7D%22%2C%20%22interval%22%3A%20%24%7Bsleep-interval%7D%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22temp_units%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%22angle%22%3A%20%24%7Bangle%7D%2C%20%22battery%22%3A%20%24%7Bbattery%7D%2C%20%22RSSI%22%3A%20%24%7Brssi%7D%2C%20%22corr-gravity%22%3A%20%24%7Bcorr-gravity%7D%2C%20%22gravity-unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%20%22run-time%22%3A%20%24%7Brun-time%7D%7D" },
|
||||||
{ "id": "GravityMon-Get", "format": "%3Fname%3D%24%7Bmdns%7D%26id%3D%24%7Bid%7D%26token%3D%24%7Btoken2%7D%26interval%3D%24%7Bsleep-interval%7D%26temperature%3D%24%7Btemp%7D%26%0Atemp-units%3D%24%7Btemp-unit%7D%26gravity%3D%24%7Bgravity%7D%26angle%3D%24%7Bangle%7D%26battery%3D%24%7Bbattery%7D%26rssi%3D%24%7Brssi%7D%26%0Acorr-gravity%3D%24%7Bcorr-gravity%7D%26gravity-unit%3D%24%7Bgravity-unit%7D%26run-time%3D%24%7Brun-time%7D" },
|
{ "id": "GravityMon-Get", "format": "%3Fname%3D%24%7Bmdns%7D%26id%3D%24%7Bid%7D%26token%3D%24%7Btoken2%7D%26interval%3D%24%7Bsleep-interval%7D%26temperature%3D%24%7Btemp%7D%26%0Atemp-units%3D%24%7Btemp-unit%7D%26gravity%3D%24%7Bgravity%7D%26angle%3D%24%7Bangle%7D%26battery%3D%24%7Bbattery%7D%26rssi%3D%24%7Brssi%7D%26%0Acorr-gravity%3D%24%7Bcorr-gravity%7D%26gravity-unit%3D%24%7Bgravity-unit%7D%26run-time%3D%24%7Brun-time%7D" },
|
||||||
{ "id": "iSpindle-Post", "format": "%7B%0A%20%22name%22%20%3A%20%22%24%7Bmdns%7D%22%2C%0A%20%22ID%22%3A%20%22%24%7Bid%7D%22%2C%0A%20%22token%22%20%3A%20%22gravmon%22%2C%0A%20%22interval%22%3A%20%24%7Bsleep-interval%7D%2C%0A%20%22temperature%22%3A%20%24%7Btemp%7D%2C%0A%20%22temp_units%22%3A%20%22%24%7Btemp-unit%7D%22%2C%0A%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%0A%20%22angle%22%3A%20%24%7Bangle%7D%2C%0A%20%22battery%22%3A%20%24%7Bbattery%7D%2C%0A%20%22RSSI%22%3A%20%24%7Brssi%7D%0A%7D" },
|
{ "id": "iSpindle-Post", "format": "%7B%20%22name%22%20%3A%20%22%24%7Bmdns%7D%22%2C%20%22ID%22%3A%20%22%24%7Bid%7D%22%2C%20%22token%22%20%3A%20%22%24%7Btoken%7D%22%2C%20%22interval%22%3A%20%24%7Bsleep-interval%7D%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22temp_units%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%22angle%22%3A%20%24%7Bangle%7D%2C%20%22battery%22%3A%20%24%7Bbattery%7D%2C%20%22RSSI%22%3A%20%24%7Brssi%7D%7D" },
|
||||||
{ "id": "BrewFatherCustom-Post", "format": "%7B%0A%20%20%20%22name%22%3A%20%22%24%7Bmdns%7D%22%2C%0A%20%20%20%22temp%22%3A%20%24%7Btemp%7D%2C%0A%20%20%20%22aux_temp%22%3A%200%2C%0A%20%20%20%22ext_temp%22%3A%200%2C%0A%20%20%20%22temp_unit%22%3A%20%22%24%7Btemp-unit%7D%22%2C%0A%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%0A%20%20%20%22gravity_unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%0A%20%20%20%22pressure%22%3A%200%2C%0A%20%20%20%22pressure_unit%22%3A%20%22PSI%22%2C%0A%20%20%20%22ph%22%3A%200%2C%0A%20%20%20%22bpm%22%3A%200%2C%0A%20%20%20%22comment%22%3A%20%22%22%2C%0A%20%20%20%22beer%22%3A%20%22%22%2C%0A%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%0A%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%2Ftilt%3A%24%7Bangle%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftemp_units%3A%24%7Btemp-unit%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": "UBIDots1-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": "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": "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>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
@ -115,9 +157,12 @@
|
|||||||
<option value="GravityMon-Post">GravityMon (POST)</option>
|
<option value="GravityMon-Post">GravityMon (POST)</option>
|
||||||
<option value="iSpindle-Mqtt">iSpindle (MQTT)</option>
|
<option value="iSpindle-Mqtt">iSpindle (MQTT)</option>
|
||||||
<option value="HomeAssistant-Mqtt">Home Assistant (MQTT)</option>
|
<option value="HomeAssistant-Mqtt">Home Assistant (MQTT)</option>
|
||||||
<option value="UBIDots1-Post">UBIdots - Alternative 1 (POST)</option>
|
<option value="HomeAssistant-Mqtt2">Home Assistant - Auto register sensor (MQTT)</option>
|
||||||
<option value="BrewFatherCustom-Post">Brewfather Custom Endpoint (POST)</option>
|
<option value="UBIDots-Post">UBIdots (POST)</option>
|
||||||
|
<option value="BrewFatherCustom-Post">Brewfather - Custom Endpoint (POST)</option>
|
||||||
|
<option value="iSpindle-Post">Brewfather - iSpindle Endpoint (POST)</option>
|
||||||
<option value="GravityMon-Get">GravityMon (GET)</option>
|
<option value="GravityMon-Get">GravityMon (GET)</option>
|
||||||
|
<option value="Brewblox-Mqtt">BrewBlox (MQTT)</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<button class="btn btn-secondary" id="copy-btn" data-bs-toggle="tooltip" title="Copy the selected format template to the selected push target">Copy format</button>
|
<button class="btn btn-secondary" id="copy-btn" data-bs-toggle="tooltip" title="Copy the selected format template to the selected push target">Copy format</button>
|
||||||
@ -125,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>
|
||||||
@ -138,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)
|
||||||
@ -148,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();
|
||||||
@ -164,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();
|
||||||
|
|
||||||
|
/*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", "");
|
s = s.replaceAll("\n", "");
|
||||||
var obj = 'id=' + $("#id").val() + '&' + $("#push-target").val() + '=' + encodeURIComponent(s);
|
var obj = 'id=' + $("#id").val() + "&" + $("#push-target").val() + '=' + encodeURIComponent(s);
|
||||||
console.log(obj);
|
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";
|
||||||
@ -235,13 +355,15 @@
|
|||||||
doc = doc.replaceAll("${corr-gravity}", cfg["gravity"]);
|
doc = doc.replaceAll("${corr-gravity}", cfg["gravity"]);
|
||||||
doc = doc.replaceAll("${angle}", cfg["angle"]);
|
doc = doc.replaceAll("${angle}", cfg["angle"]);
|
||||||
doc = doc.replaceAll("${tilt}", cfg["angle"]);
|
doc = doc.replaceAll("${tilt}", cfg["angle"]);
|
||||||
|
doc = doc.replaceAll("${app-ver}", cfg["app-ver"]);
|
||||||
|
doc = doc.replaceAll("${app-build}", cfg["app-build"]);
|
||||||
|
|
||||||
// Format in a readable json string.
|
// Format in a readable json string.
|
||||||
try {
|
try {
|
||||||
var json = JSON.parse(doc);
|
var json = JSON.parse(doc);
|
||||||
doc = JSON.stringify(json, null, 2);
|
doc = JSON.stringify(json, null, 2);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log("Not a javascript object!")
|
console.log("Not a JSON object!")
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#preview").text(doc);
|
$("#preview").text(doc);
|
||||||
@ -258,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() {
|
||||||
@ -269,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
|
||||||
@ -276,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 );
|
||||||
@ -296,6 +422,8 @@
|
|||||||
$('#spinner').hide();
|
$('#spinner').hide();
|
||||||
setButtonDisabled( false );
|
setButtonDisabled( false );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateStatusField();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
267
html/index.htm
@ -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">
|
||||||
@ -73,66 +80,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="accordion" id="accordion">
|
<div class="accordion" id="accordion">
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="headingSoftware">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSoftware" aria-expanded="true" aria-controls="collapseSoftware">
|
|
||||||
<b>Device</b>
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseSoftware" class="accordion-collapse collapse show" aria-labelledby="headingSoftware" data-bs-parent="#accordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-4 bg-light">Current version:</div>
|
|
||||||
<div class="col-md-4 bg-light" id="app-ver">Loading...</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3" id="h-app-ver-new" hidden>
|
|
||||||
<div class="col-md-4 bg-light">New version:</div>
|
|
||||||
<div class="col-md-4 bg-light" id="app-ver-new">Loading...</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-4 bg-light">Host name:</div>
|
|
||||||
<div class="col-md-4 bg-light" id="mdns">Loading...</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-4 bg-light">Device ID:</div>
|
|
||||||
<div class="col-md-4 bg-light" id="id">Loading...</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-4 bg-light">Platform:</div>
|
|
||||||
<div class="col-md-4 bg-light" id="platform">Loading...</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-4 bg-light">SSID:</div>
|
|
||||||
<div class="col-md-4 bg-light" id="wifi-ssid">Loading...</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$("#log-btn").click(function(e){
|
|
||||||
loadLog();
|
|
||||||
});
|
|
||||||
setInterval(function() {
|
|
||||||
loadLog();
|
|
||||||
}, 3000); //5 seconds
|
|
||||||
|
|
||||||
function loadLog() {
|
|
||||||
$("#logContent").load("/log");
|
|
||||||
//$("#logContent").load("/test/status.json");
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#collapseLog" aria-expanded="false" aria-controls="collapseLog" data-bs-toggle="tooltip" title="Load and show the last 10 errors that has occured on the device">
|
|
||||||
View error log
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="collapse row-margin-10" id="collapseLog">
|
|
||||||
<div class="card card-body">
|
|
||||||
<pre><code class="card-text" id="logContent"></code></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 class="accordion-header" id="headingData">
|
<h2 class="accordion-header" id="headingData">
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseData" aria-expanded="true" aria-controls="collapseData">
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseData" aria-expanded="true" aria-controls="collapseData">
|
||||||
@ -173,12 +120,180 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="headingSoftware">
|
||||||
|
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSoftware" aria-expanded="true" aria-controls="collapseSoftware">
|
||||||
|
<b>Device</b>
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseSoftware" class="accordion-collapse collapse show" aria-labelledby="headingSoftware" data-bs-parent="#accordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4 bg-light">Current version:</div>
|
||||||
|
<div class="col-md-4 bg-light" id="app-ver">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3" id="h-app-ver-new" hidden>
|
||||||
|
<div class="col-md-4 bg-light">New version:</div>
|
||||||
|
<div class="col-md-4 bg-light" id="app-ver-new">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4 bg-light">Host name:</div>
|
||||||
|
<div class="col-md-4 bg-light" id="mdns">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4 bg-light">Device ID:</div>
|
||||||
|
<div class="col-md-4 bg-light" id="id">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4 bg-light">Platform:</div>
|
||||||
|
<div class="col-md-4 bg-light" id="platform">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4 bg-light">SSID:</div>
|
||||||
|
<div class="col-md-4 bg-light" id="wifi-ssid">Loading...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$("#log-btn").click(function(e){
|
||||||
|
loadLog();
|
||||||
|
});
|
||||||
|
setInterval(function() {
|
||||||
|
loadLog();
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
function loadLog() {
|
||||||
|
var url2 = "/log2";
|
||||||
|
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>
|
||||||
|
|
||||||
|
<button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#collapseLog" aria-expanded="false" aria-controls="collapseLog" data-bs-toggle="tooltip" title="Load and show the last 10 errors that has occured on the device">
|
||||||
|
View error log
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn btn-secondary btn-sm" type="button" data-bs-toggle="tooltip" name="github-btn" id="github-btn" title="Go to github and place a issue">
|
||||||
|
Submit a issue on github
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn btn-secondary btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSupport" aria-expanded="false" aria-controls="collapseSupport" data-bs-toggle="tooltip" name="support-btn" id="support-btn" title="Collect data relevant for a support case">
|
||||||
|
Gather support information
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="collapse row-margin-10" id="collapseLog">
|
||||||
|
<div class="card card-body">
|
||||||
|
<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 class="collapse row-margin-10" id="collapseSupport">
|
||||||
|
<div class="card card-body">
|
||||||
|
<pre><code class="card-text" id="supportContent">Collecting support data, please wait...</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
var debug = {};
|
||||||
|
|
||||||
window.onload = start;
|
window.onload = start;
|
||||||
|
|
||||||
|
$("#github-btn").click(function(e){
|
||||||
|
window.location.href = "https://github.com/mp-se/gravitymon/issues";
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#support-btn").click(function(e){
|
||||||
|
$('#spinner').show();
|
||||||
|
|
||||||
|
var url = "/api/config";
|
||||||
|
//var url = "/test/config.json";
|
||||||
|
$.getJSON(url, function (cfg) {
|
||||||
|
debug = {};
|
||||||
|
debug["mdns"] = cfg["mdns"];
|
||||||
|
debug["id"] = cfg["id"];
|
||||||
|
|
||||||
|
debug["sleep-interval"] = cfg["sleep-interval"];
|
||||||
|
debug["temp-format"] = cfg["temp-format"];
|
||||||
|
|
||||||
|
debug["gravity-format"] = cfg["gravity-format"];
|
||||||
|
debug["gravity-temp-adjustment"] = cfg["gravity-temp-adjustment"];
|
||||||
|
|
||||||
|
debug["voltage-factor"] = cfg["voltage-factor"];
|
||||||
|
debug["platform"] = cfg["platform"];
|
||||||
|
debug["ble"] = cfg["ble"];
|
||||||
|
debug["gyro-temp"] = cfg["gyro-temp"];
|
||||||
|
debug["gyro-calibration-data"] = cfg["gyro-calibration-data"];
|
||||||
|
debug["temp-adjustment-value"] = cfg["temp-adjustment-value"];
|
||||||
|
|
||||||
|
var url = "/api/status";
|
||||||
|
//var url = "/test/status.json";
|
||||||
|
$.getJSON(url, function (cfg) {
|
||||||
|
debug["runtime-average"] = cfg["runtime-average"];
|
||||||
|
debug["rssi"] = cfg["rssi"];
|
||||||
|
debug["app-ver"] = cfg["app-ver"];
|
||||||
|
debug["app-build"] = cfg["app-build"];
|
||||||
|
});
|
||||||
|
|
||||||
|
var url = "/api/config/format";
|
||||||
|
//var url = "/test/format.json";
|
||||||
|
$.getJSON(url, function (cfg) {
|
||||||
|
debug["formats"] = cfg;
|
||||||
|
|
||||||
|
var url = "/api/config/advanced";
|
||||||
|
//var url = "/test/adv.json";
|
||||||
|
$.getJSON(url, function (cfg) {
|
||||||
|
debug["advanced"] = cfg;
|
||||||
|
|
||||||
|
var url = "/api/upload";
|
||||||
|
//var url = "/test/upload.json";
|
||||||
|
$.getJSON(url, function (cfg) {
|
||||||
|
debug["files"] = cfg;
|
||||||
|
|
||||||
|
var url = "/log";
|
||||||
|
//var url = "/test/log";
|
||||||
|
$.ajax({url: url, method: 'get', success: function (data) {
|
||||||
|
debug["log"] = data.split("\n");
|
||||||
|
var s = JSON.stringify(debug, null, 2);
|
||||||
|
$("#supportContent").text( s );
|
||||||
|
$('#spinner').hide();
|
||||||
|
//navigator.clipboard.writeText(s);
|
||||||
|
//alert("Support information copied to clipboard");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$("#sleep-mode").click(function(e){
|
$("#sleep-mode").click(function(e){
|
||||||
console.log( "Blocking sleep mode = " + $("#sleep-mode").is(":checked"));
|
console.log( "Blocking sleep mode = " + $("#sleep-mode").is(":checked"));
|
||||||
$.ajax( {
|
$.ajax( {
|
||||||
@ -207,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 {
|
||||||
@ -236,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 );
|
||||||
@ -256,7 +379,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
setInterval(getStatus, 3000);
|
setInterval(getStatus, 5000);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -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,9 +22,26 @@
|
|||||||
<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 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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -75,7 +90,7 @@
|
|||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<button class="btn btn-primary" id="test-btn" data-bs-toggle="tooltip" title="Test all push targets">Test</button>
|
<button type="button" class="btn btn-primary" id="test-btn" data-bs-toggle="tooltip" title="Test all push targets">Test</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
179
html/upload.htm
@ -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>
|
|
400
lib/ESP_DoubleResetDetector/ESP_DoubleResetDetector.h
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
/****************************************************************************************************************************
|
||||||
|
ESP_DoubleResetDetector.h
|
||||||
|
For ESP8266 / ESP32 boards
|
||||||
|
|
||||||
|
ESP_DoubleResetDetector is a library for the ESP8266/Arduino platform
|
||||||
|
to enable trigger configure mode by resetting ESP32 / ESP8266 twice.
|
||||||
|
|
||||||
|
Forked from DataCute https://github.com/datacute/DoubleResetDetector
|
||||||
|
|
||||||
|
Built by Khoi Hoang https://github.com/khoih-prog/ESP_DoubleResetDetector
|
||||||
|
Licensed under MIT license
|
||||||
|
Version: 1.3.2
|
||||||
|
|
||||||
|
Version Modified By Date Comments
|
||||||
|
------- ----------- ---------- -----------
|
||||||
|
1.0.0 K Hoang 15/12/2019 Initial coding
|
||||||
|
1.0.1 K Hoang 30/12/2019 Now can use EEPROM or SPIFFS for both ESP8266 and ESP32. RTC still OK for ESP8266
|
||||||
|
1.0.2 K Hoang 10/04/2020 Fix bug by left-over cpp file and in example.
|
||||||
|
1.0.3 K Hoang 13/05/2020 Update to use LittleFS for ESP8266 core 2.7.1+
|
||||||
|
1.1.0 K Hoang 04/12/2020 Add support to LittleFS for ESP32 using LITTLEFS Library
|
||||||
|
1.1.1 K Hoang 28/12/2020 Suppress all possible compiler warnings
|
||||||
|
1.1.2 K Hoang 10/10/2021 Update `platform.ini` and `library.json`
|
||||||
|
1.2.0 K Hoang 26/11/2021 Auto detect ESP32 core and use either built-in LittleFS or LITTLEFS library
|
||||||
|
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.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
|
||||||
|
|
||||||
|
#ifndef ESP_DoubleResetDetector_H
|
||||||
|
#define ESP_DoubleResetDetector_H
|
||||||
|
|
||||||
|
#ifndef DOUBLERESETDETECTOR_DEBUG
|
||||||
|
#define DOUBLERESETDETECTOR_DEBUG false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && (ARDUINO >= 100)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#else
|
||||||
|
#include <WProgram.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ESP_DOUBLE_RESET_DETECTOR_VERSION
|
||||||
|
#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_MINOR 3
|
||||||
|
#define ESP_DOUBLE_RESET_DETECTOR_VERSION_PATCH 2
|
||||||
|
|
||||||
|
#define ESP_DOUBLE_RESET_DETECTOR_VERSION_INT 1003002
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ESP_DOUBLERESETDETECTOR_VERSION ESP_DOUBLE_RESET_DETECTOR_VERSION
|
||||||
|
|
||||||
|
//#define ESP_DRD_USE_EEPROM false
|
||||||
|
//#define ESP_DRD_USE_LITTLEFS false
|
||||||
|
//#define ESP_DRD_USE_SPIFFS false
|
||||||
|
//#define ESP8266_DRD_USE_RTC false //true
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#if (!ESP_DRD_USE_EEPROM && !ESP_DRD_USE_SPIFFS && !ESP_DRD_USE_LITTLEFS)
|
||||||
|
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
#warning Neither EEPROM, SPIFFS nor LittleFS selected. Default to EEPROM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP_DRD_USE_EEPROM
|
||||||
|
#undef ESP_DRD_USE_EEPROM
|
||||||
|
#define ESP_DRD_USE_EEPROM true
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#if (!ESP8266_DRD_USE_RTC && !ESP_DRD_USE_EEPROM && !ESP_DRD_USE_SPIFFS && !ESP_DRD_USE_LITTLEFS)
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
#warning Neither RTC, EEPROM, LITTLEFS nor SPIFFS selected. Default to EEPROM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP_DRD_USE_EEPROM
|
||||||
|
#undef ESP_DRD_USE_EEPROM
|
||||||
|
#define ESP_DRD_USE_EEPROM true
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//default to use EEPROM, otherwise, use LITTLEFS (higher priority), then SPIFFS
|
||||||
|
#if ESP_DRD_USE_EEPROM
|
||||||
|
#include <EEPROM.h>
|
||||||
|
|
||||||
|
#define FLAG_DATA_SIZE 4
|
||||||
|
|
||||||
|
#ifndef EEPROM_SIZE
|
||||||
|
#define EEPROM_SIZE 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EEPROM_START
|
||||||
|
#define EEPROM_START 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif ( ESP_DRD_USE_LITTLEFS || ESP_DRD_USE_SPIFFS )
|
||||||
|
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
|
||||||
|
#if ESP_DRD_USE_LITTLEFS
|
||||||
|
// Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h
|
||||||
|
//#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2)
|
||||||
|
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
#warning Using ESP32 Core 1.0.6 or 2.0.0+
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The library has been merged into esp32 core from release 1.0.6
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
#define FileFS LittleFS
|
||||||
|
#define FS_Name "LittleFS"
|
||||||
|
#else
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
#warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The library has been merged into esp32 core from release 1.0.6
|
||||||
|
#include <LITTLEFS.h> // https://github.com/lorol/LITTLEFS
|
||||||
|
|
||||||
|
#define FileFS LITTLEFS
|
||||||
|
#define FS_Name "LittleFS"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include "SPIFFS.h"
|
||||||
|
// ESP32 core 1.0.4 still uses SPIFFS
|
||||||
|
#define FileFS SPIFFS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
// From ESP8266 core 2.7.1
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
#if ESP_DRD_USE_LITTLEFS
|
||||||
|
#define FileFS LittleFS
|
||||||
|
#else
|
||||||
|
#define FileFS SPIFFS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #if ESP_DRD_USE_EEPROM
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define DRD_FILENAME "/drd.dat"
|
||||||
|
|
||||||
|
#endif //#if ESP_DRD_USE_EEPROM
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define DOUBLERESETDETECTOR_FLAG_SET 0xD0D01234
|
||||||
|
#define DOUBLERESETDETECTOR_FLAG_CLEAR 0xD0D04321
|
||||||
|
|
||||||
|
class DoubleResetDetector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DoubleResetDetector(int timeout, int address)
|
||||||
|
{
|
||||||
|
#if ESP_DRD_USE_EEPROM
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.printf("EEPROM size = %d, start = %d\n", EEPROM_SIZE, EEPROM_START);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
|
#elif ( ESP_DRD_USE_LITTLEFS || ESP_DRD_USE_SPIFFS )
|
||||||
|
// LittleFS / SPIFFS code
|
||||||
|
if (!FileFS.begin())
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
|
||||||
|
#if ESP_DRD_USE_LITTLEFS
|
||||||
|
Serial.println("LittleFS failed!. Please use SPIFFS or EEPROM.");
|
||||||
|
#else
|
||||||
|
Serial.println("SPIFFS failed!. Please use LittleFS or EEPROM.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef ESP8266
|
||||||
|
//RTC only for ESP8266
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this->timeout = timeout * 1000;
|
||||||
|
this->address = address;
|
||||||
|
doubleResetDetected = false;
|
||||||
|
waitingForDoubleReset = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool detectDoubleReset()
|
||||||
|
{
|
||||||
|
doubleResetDetected = detectRecentlyResetFlag();
|
||||||
|
|
||||||
|
if (doubleResetDetected)
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("doubleResetDetected");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
clearRecentlyResetFlag();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("No doubleResetDetected");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setRecentlyResetFlag();
|
||||||
|
waitingForDoubleReset = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doubleResetDetected;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
bool waitingForDRD()
|
||||||
|
{
|
||||||
|
return waitingForDoubleReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if (waitingForDoubleReset && millis() > timeout)
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Stop doubleResetDetecting");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
clearRecentlyResetFlag();
|
||||||
|
waitingForDoubleReset = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool doubleResetDetected;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t DOUBLERESETDETECTOR_FLAG;
|
||||||
|
unsigned long timeout;
|
||||||
|
int address;
|
||||||
|
bool waitingForDoubleReset;
|
||||||
|
|
||||||
|
bool detectRecentlyResetFlag()
|
||||||
|
{
|
||||||
|
#if (ESP_DRD_USE_EEPROM)
|
||||||
|
EEPROM.get(EEPROM_START, DOUBLERESETDETECTOR_FLAG);
|
||||||
|
doubleResetDetectorFlag = DOUBLERESETDETECTOR_FLAG;
|
||||||
|
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.printf("EEPROM Flag read = 0x%X\n", DOUBLERESETDETECTOR_FLAG);
|
||||||
|
#endif
|
||||||
|
#elif ( ESP_DRD_USE_LITTLEFS || ESP_DRD_USE_SPIFFS )
|
||||||
|
// LittleFS / SPIFFS code
|
||||||
|
if (FileFS.exists(DRD_FILENAME))
|
||||||
|
{
|
||||||
|
// if config file exists, load
|
||||||
|
File file = FileFS.open(DRD_FILENAME, "r");
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Loading config file failed");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
file.readBytes((char *) &DOUBLERESETDETECTOR_FLAG, sizeof(DOUBLERESETDETECTOR_FLAG));
|
||||||
|
doubleResetDetectorFlag = DOUBLERESETDETECTOR_FLAG;
|
||||||
|
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
|
||||||
|
#if ESP_DRD_USE_LITTLEFS
|
||||||
|
Serial.printf("LittleFS Flag read = 0x%X\n", DOUBLERESETDETECTOR_FLAG);
|
||||||
|
#else
|
||||||
|
Serial.printf("SPIFFS Flag read = 0x%X\n", DOUBLERESETDETECTOR_FLAG);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef ESP8266
|
||||||
|
//RTC only for ESP8266
|
||||||
|
ESP.rtcUserMemoryRead(address, &doubleResetDetectorFlag, sizeof(doubleResetDetectorFlag));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
doubleResetDetected = (doubleResetDetectorFlag == DOUBLERESETDETECTOR_FLAG_SET);
|
||||||
|
return doubleResetDetected;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setRecentlyResetFlag()
|
||||||
|
{
|
||||||
|
doubleResetDetectorFlag = DOUBLERESETDETECTOR_FLAG_SET;
|
||||||
|
|
||||||
|
DOUBLERESETDETECTOR_FLAG = DOUBLERESETDETECTOR_FLAG_SET;
|
||||||
|
|
||||||
|
#if (ESP_DRD_USE_EEPROM)
|
||||||
|
EEPROM.put(EEPROM_START, DOUBLERESETDETECTOR_FLAG);
|
||||||
|
EEPROM.commit();
|
||||||
|
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
delay(1000);
|
||||||
|
EEPROM.get(EEPROM_START, DOUBLERESETDETECTOR_FLAG);
|
||||||
|
|
||||||
|
Serial.printf("SetFlag write = 0x%X\n", DOUBLERESETDETECTOR_FLAG);
|
||||||
|
#endif
|
||||||
|
#elif ( ESP_DRD_USE_LITTLEFS || ESP_DRD_USE_SPIFFS )
|
||||||
|
// LittleFS / SPIFFS code
|
||||||
|
File file = FileFS.open(DRD_FILENAME, "w");
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Saving config file...");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
file.write((uint8_t *) &DOUBLERESETDETECTOR_FLAG, sizeof(DOUBLERESETDETECTOR_FLAG));
|
||||||
|
file.close();
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Saving config file OK");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Saving config file failed");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef ESP8266
|
||||||
|
//RTC only for ESP8266
|
||||||
|
ESP.rtcUserMemoryWrite(address, &doubleResetDetectorFlag, sizeof(doubleResetDetectorFlag));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void clearRecentlyResetFlag()
|
||||||
|
{
|
||||||
|
doubleResetDetectorFlag = DOUBLERESETDETECTOR_FLAG_CLEAR;
|
||||||
|
DOUBLERESETDETECTOR_FLAG = DOUBLERESETDETECTOR_FLAG_CLEAR;
|
||||||
|
|
||||||
|
#if (ESP_DRD_USE_EEPROM)
|
||||||
|
//DOUBLERESETDETECTOR_FLAG = DOUBLERESETDETECTOR_FLAG_CLEAR;
|
||||||
|
EEPROM.put(EEPROM_START, DOUBLERESETDETECTOR_FLAG);
|
||||||
|
EEPROM.commit();
|
||||||
|
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
delay(1000);
|
||||||
|
EEPROM.get(EEPROM_START, DOUBLERESETDETECTOR_FLAG);
|
||||||
|
|
||||||
|
Serial.printf("ClearFlag write = 0x%X\n", DOUBLERESETDETECTOR_FLAG);
|
||||||
|
#endif
|
||||||
|
#elif ( ESP_DRD_USE_LITTLEFS || ESP_DRD_USE_SPIFFS )
|
||||||
|
// LittleFS / SPIFFS code
|
||||||
|
File file = FileFS.open(DRD_FILENAME, "w");
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Saving config file...");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
file.write((uint8_t *) &DOUBLERESETDETECTOR_FLAG, sizeof(DOUBLERESETDETECTOR_FLAG));
|
||||||
|
file.close();
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Saving config file OK");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if (DOUBLERESETDETECTOR_DEBUG)
|
||||||
|
Serial.println("Saving config file failed");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#ifdef ESP8266
|
||||||
|
//RTC only for ESP8266
|
||||||
|
ESP.rtcUserMemoryWrite(address, &doubleResetDetectorFlag, sizeof(doubleResetDetectorFlag));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t doubleResetDetectorFlag;
|
||||||
|
};
|
||||||
|
#endif // ESP_DoubleResetDetector_H
|
2138
lib/ESP_WifiManager/ESP_WiFiManager-Impl.h
Normal file
42
lib/ESP_WifiManager/ESP_WiFiManager.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/****************************************************************************************************************************
|
||||||
|
ESP_WiFiManager.h
|
||||||
|
For ESP8266 / ESP32 boards
|
||||||
|
|
||||||
|
ESP_WiFiManager is a library for the ESP8266/Arduino platform
|
||||||
|
(https://github.com/esp8266/Arduino) to enable easy
|
||||||
|
configuration and reconfiguration of WiFi credentials using a Captive Portal
|
||||||
|
inspired by:
|
||||||
|
http://www.esp8266.com/viewtopic.php?f=29&t=2520
|
||||||
|
https://github.com/chriscook8/esp-arduino-apboot
|
||||||
|
https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/
|
||||||
|
|
||||||
|
Modified from Tzapu https://github.com/tzapu/WiFiManager
|
||||||
|
and from Ken Taylor https://github.com/kentaylor
|
||||||
|
|
||||||
|
Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager
|
||||||
|
Licensed under MIT license
|
||||||
|
|
||||||
|
Version: 1.11.0
|
||||||
|
|
||||||
|
Version Modified By Date Comments
|
||||||
|
------- ----------- ---------- -----------
|
||||||
|
1.0.0 K Hoang 07/10/2019 Initial coding
|
||||||
|
...
|
||||||
|
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.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
|
||||||
|
|
||||||
|
#ifndef ESP_WiFiManager_h
|
||||||
|
#define ESP_WiFiManager_h
|
||||||
|
|
||||||
|
#include <ESP_WiFiManager.hpp> //https://github.com/khoih-prog/ESP_WiFiManager
|
||||||
|
#include <ESP_WiFiManager-Impl.h> //https://github.com/khoih-prog/ESP_WiFiManager
|
||||||
|
|
||||||
|
#endif // ESP_WiFiManager_h
|
||||||
|
|
731
lib/ESP_WifiManager/ESP_WiFiManager.hpp
Normal file
98
lib/ESP_WifiManager/ESP_WiFiManager_Debug.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/****************************************************************************************************************************
|
||||||
|
ESP_WiFiManager_Debug.h
|
||||||
|
For ESP8266 / ESP32 boards
|
||||||
|
|
||||||
|
ESP_WiFiManager is a library for the ESP8266/Arduino platform
|
||||||
|
(https://github.com/esp8266/Arduino) to enable easy
|
||||||
|
configuration and reconfiguration of WiFi credentials using a Captive Portal
|
||||||
|
inspired by:
|
||||||
|
http://www.esp8266.com/viewtopic.php?f=29&t=2520
|
||||||
|
https://github.com/chriscook8/esp-arduino-apboot
|
||||||
|
https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/
|
||||||
|
|
||||||
|
Modified from Tzapu https://github.com/tzapu/WiFiManager
|
||||||
|
and from Ken Taylor https://github.com/kentaylor
|
||||||
|
|
||||||
|
Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager
|
||||||
|
Licensed under MIT license
|
||||||
|
|
||||||
|
Version: 1.11.0
|
||||||
|
|
||||||
|
Version Modified By Date Comments
|
||||||
|
------- ----------- ---------- -----------
|
||||||
|
1.0.0 K Hoang 07/10/2019 Initial coding
|
||||||
|
...
|
||||||
|
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.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
|
||||||
|
|
||||||
|
#ifndef ESP_WiFiManager_Debug_H
|
||||||
|
#define ESP_WiFiManager_Debug_H
|
||||||
|
|
||||||
|
#ifdef WIFIMGR_DEBUG_PORT
|
||||||
|
#define WM_DBG_PORT WIFIMGR_DEBUG_PORT
|
||||||
|
#else
|
||||||
|
#define WM_DBG_PORT Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Change _WIFIMGR_LOGLEVEL_ to set tracing and logging verbosity
|
||||||
|
// 0: DISABLED: no logging
|
||||||
|
// 1: ERROR: errors
|
||||||
|
// 2: WARN: errors and warnings
|
||||||
|
// 3: INFO: errors, warnings and informational (default)
|
||||||
|
// 4: DEBUG: errors, warnings, informational and debug
|
||||||
|
|
||||||
|
#ifndef _WIFIMGR_LOGLEVEL_
|
||||||
|
#define _WIFIMGR_LOGLEVEL_ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char WM_MARK[] = "[WM] ";
|
||||||
|
const char WM_SP[] = " ";
|
||||||
|
|
||||||
|
#define WM_PRINT WM_DBG_PORT.print
|
||||||
|
#define WM_PRINTLN WM_DBG_PORT.println
|
||||||
|
|
||||||
|
#define WM_PRINT_MARK WM_PRINT(WM_MARK)
|
||||||
|
#define WM_PRINT_SP WM_PRINT(WM_SP)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define LOGERROR(x) if(_WIFIMGR_LOGLEVEL_>0) { WM_PRINT_MARK; WM_PRINTLN(x); }
|
||||||
|
#define LOGERROR0(x) if(_WIFIMGR_LOGLEVEL_>0) { WM_PRINT(x); }
|
||||||
|
#define LOGERROR1(x,y) if(_WIFIMGR_LOGLEVEL_>0) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINTLN(y); }
|
||||||
|
#define LOGERROR2(x,y,z) if(_WIFIMGR_LOGLEVEL_>0) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINTLN(z); }
|
||||||
|
#define LOGERROR3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>0) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINT(z); WM_PRINT_SP; WM_PRINTLN(w); }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define LOGWARN(x) if(_WIFIMGR_LOGLEVEL_>1) { WM_PRINT_MARK; WM_PRINTLN(x); }
|
||||||
|
#define LOGWARN0(x) if(_WIFIMGR_LOGLEVEL_>1) { WM_PRINT(x); }
|
||||||
|
#define LOGWARN1(x,y) if(_WIFIMGR_LOGLEVEL_>1) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINTLN(y); }
|
||||||
|
#define LOGWARN2(x,y,z) if(_WIFIMGR_LOGLEVEL_>1) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINTLN(z); }
|
||||||
|
#define LOGWARN3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>1) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINT(z); WM_PRINT_SP; WM_PRINTLN(w); }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define LOGINFO(x) if(_WIFIMGR_LOGLEVEL_>2) { WM_PRINT_MARK; WM_PRINTLN(x); }
|
||||||
|
#define LOGINFO0(x) if(_WIFIMGR_LOGLEVEL_>2) { WM_PRINT(x); }
|
||||||
|
#define LOGINFO1(x,y) if(_WIFIMGR_LOGLEVEL_>2) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINTLN(y); }
|
||||||
|
#define LOGINFO2(x,y,z) if(_WIFIMGR_LOGLEVEL_>2) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINTLN(z); }
|
||||||
|
#define LOGINFO3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>2) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINT(z); WM_PRINT_SP; WM_PRINTLN(w); }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define LOGDEBUG(x) if(_WIFIMGR_LOGLEVEL_>3) { WM_PRINT_MARK; WM_PRINTLN(x); }
|
||||||
|
#define LOGDEBUG0(x) if(_WIFIMGR_LOGLEVEL_>3) { WM_PRINT(x); }
|
||||||
|
#define LOGDEBUG1(x,y) if(_WIFIMGR_LOGLEVEL_>3) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINTLN(y); }
|
||||||
|
#define LOGDEBUG2(x,y,z) if(_WIFIMGR_LOGLEVEL_>3) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINTLN(z); }
|
||||||
|
#define LOGDEBUG3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>3) { WM_PRINT_MARK; WM_PRINT(x); WM_PRINT_SP; WM_PRINT(y); WM_PRINT_SP; WM_PRINT(z); WM_PRINT_SP; WM_PRINTLN(w); }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#endif //ESP_WiFiManager_Debug_H
|
1532
lib/ESP_WifiManager/utils/TZ.h
Normal file
@ -195,11 +195,7 @@ uint8_t OneWire::reset(void)
|
|||||||
// Write a bit. Port and bit is used to cut lookup time and provide
|
// Write a bit. Port and bit is used to cut lookup time and provide
|
||||||
// more certain timing.
|
// more certain timing.
|
||||||
//
|
//
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
|
||||||
void IRAM_ATTR OneWire::write_bit(uint8_t v)
|
|
||||||
#else
|
|
||||||
void OneWire::write_bit(uint8_t v)
|
void OneWire::write_bit(uint8_t v)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||||
@ -227,11 +223,7 @@ void OneWire::write_bit(uint8_t v)
|
|||||||
// Read a bit. Port and bit is used to cut lookup time and provide
|
// Read a bit. Port and bit is used to cut lookup time and provide
|
||||||
// more certain timing.
|
// more certain timing.
|
||||||
//
|
//
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
|
||||||
uint8_t IRAM_ATTR OneWire::read_bit(void)
|
|
||||||
#else
|
|
||||||
uint8_t OneWire::read_bit(void)
|
uint8_t OneWire::read_bit(void)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||||
|
@ -99,18 +99,10 @@ class OneWire
|
|||||||
|
|
||||||
// Write a bit. The bus is always left powered at the end, see
|
// Write a bit. The bus is always left powered at the end, see
|
||||||
// note in write() about that.
|
// note in write() about that.
|
||||||
#if defined (ARDUINO_ARCH_ESP32)
|
|
||||||
void IRAM_ATTR write_bit(uint8_t v);
|
|
||||||
#else
|
|
||||||
void write_bit(uint8_t v);
|
void write_bit(uint8_t v);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Read a bit.
|
// Read a bit.
|
||||||
#if defined (ARDUINO_ARCH_ESP32)
|
|
||||||
uint8_t IRAM_ATTR read_bit(void);
|
|
||||||
#else
|
|
||||||
uint8_t read_bit(void);
|
uint8_t read_bit(void);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Stop forcing power onto the bus. You only need to do this if
|
// Stop forcing power onto the bus. You only need to do this if
|
||||||
// you used the 'power' flag to write() or used a write_bit() call
|
// you used the 'power' flag to write() or used a write_bit() call
|
||||||
|
@ -127,10 +127,14 @@
|
|||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
IO_REG_TYPE directRead(IO_REG_TYPE pin)
|
IO_REG_TYPE directRead(IO_REG_TYPE pin)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
return (GPIO.in.val >> pin) & 0x1;
|
||||||
|
#else // plain ESP32
|
||||||
if ( pin < 32 )
|
if ( pin < 32 )
|
||||||
return (GPIO.in >> pin) & 0x1;
|
return (GPIO.in >> pin) & 0x1;
|
||||||
else if ( pin < 40 )
|
else if ( pin < 46 )
|
||||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -138,38 +142,38 @@ IO_REG_TYPE directRead(IO_REG_TYPE pin)
|
|||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
void directWriteLow(IO_REG_TYPE pin)
|
void directWriteLow(IO_REG_TYPE pin)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
GPIO.out_w1tc.val = ((uint32_t)1 << pin);
|
||||||
|
#else // plain ESP32
|
||||||
if ( pin < 32 )
|
if ( pin < 32 )
|
||||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||||
else if ( pin < 34 )
|
else if ( pin < 46 )
|
||||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
void directWriteHigh(IO_REG_TYPE pin)
|
void directWriteHigh(IO_REG_TYPE pin)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
GPIO.out_w1ts.val = ((uint32_t)1 << pin);
|
||||||
|
#else // plain ESP32
|
||||||
if ( pin < 32 )
|
if ( pin < 32 )
|
||||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||||
else if ( pin < 34 )
|
else if ( pin < 46 )
|
||||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
void directModeInput(IO_REG_TYPE pin)
|
void directModeInput(IO_REG_TYPE pin)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
|
||||||
|
#else
|
||||||
if ( digitalPinIsValid(pin) )
|
if ( digitalPinIsValid(pin) )
|
||||||
{
|
{
|
||||||
#if defined(ESP_ARDUINO_VERSION)
|
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
|
||||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0)
|
|
||||||
int pin_io = rtc_io_number_get((gpio_num_t)pin);
|
|
||||||
uint32_t rtc_reg(rtc_io_desc[pin_io].reg);
|
|
||||||
|
|
||||||
if ( rtc_reg ) // RTC pins PULL settings
|
|
||||||
{
|
|
||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin_io].mux);
|
|
||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin_io].pullup | rtc_io_desc[pin_io].pulldown);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
||||||
|
|
||||||
if ( rtc_reg ) // RTC pins PULL settings
|
if ( rtc_reg ) // RTC pins PULL settings
|
||||||
@ -177,40 +181,25 @@ void directModeInput(IO_REG_TYPE pin)
|
|||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// Input
|
||||||
if ( pin < 32 )
|
if ( pin < 32 )
|
||||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||||
else
|
else
|
||||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||||
|
|
||||||
uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
|
||||||
pinFunction |= FUN_IE; // input enable but required for output as well?
|
|
||||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
|
||||||
|
|
||||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
|
||||||
|
|
||||||
GPIO.pin[pin].val = 0;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
void directModeOutput(IO_REG_TYPE pin)
|
void directModeOutput(IO_REG_TYPE pin)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
|
||||||
|
#else
|
||||||
if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs
|
if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs
|
||||||
{
|
{
|
||||||
#if defined(ESP_ARDUINO_VERSION)
|
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
|
||||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0)
|
|
||||||
int pin_io = rtc_io_number_get((gpio_num_t)pin);
|
|
||||||
uint32_t rtc_reg(rtc_io_desc[pin_io].reg);
|
|
||||||
|
|
||||||
if ( rtc_reg ) // RTC pins PULL settings
|
|
||||||
{
|
|
||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin_io].mux);
|
|
||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin_io].pullup | rtc_io_desc[pin_io].pulldown);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
|
||||||
|
|
||||||
if ( rtc_reg ) // RTC pins PULL settings
|
if ( rtc_reg ) // RTC pins PULL settings
|
||||||
@ -218,21 +207,14 @@ void directModeOutput(IO_REG_TYPE pin)
|
|||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// Output
|
||||||
if ( pin < 32 )
|
if ( pin < 32 )
|
||||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||||
else // already validated to pins <= 33
|
else // already validated to pins <= 33
|
||||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||||
|
|
||||||
uint32_t pinFunction((uint32_t)2 << FUN_DRV_S); // what are the drivers?
|
|
||||||
pinFunction |= FUN_IE; // input enable but required for output as well?
|
|
||||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
|
||||||
|
|
||||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
|
||||||
|
|
||||||
GPIO.pin[pin].val = 0;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DIRECT_READ(base, pin) directRead(pin)
|
#define DIRECT_READ(base, pin) directRead(pin)
|
||||||
@ -445,6 +427,20 @@ void directWriteHigh(IO_REG_TYPE mask)
|
|||||||
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
|
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
|
||||||
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
|
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_MBED_RP2040)|| defined(ARDUINO_ARCH_RP2040)
|
||||||
|
#define delayMicroseconds(time) busy_wait_us(time)
|
||||||
|
#define PIN_TO_BASEREG(pin) (0)
|
||||||
|
#define PIN_TO_BITMASK(pin) (pin)
|
||||||
|
#define IO_REG_TYPE unsigned int
|
||||||
|
#define IO_REG_BASE_ATTR
|
||||||
|
#define IO_REG_MASK_ATTR
|
||||||
|
#define DIRECT_READ(base, pin) digitalRead(pin)
|
||||||
|
#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW)
|
||||||
|
#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH)
|
||||||
|
#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT)
|
||||||
|
#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT)
|
||||||
|
#warning "OneWire. RP2040 in Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite."
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define PIN_TO_BASEREG(pin) (0)
|
#define PIN_TO_BASEREG(pin) (0)
|
||||||
#define PIN_TO_BITMASK(pin) (pin)
|
#define PIN_TO_BITMASK(pin) (pin)
|
||||||
|
@ -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,9 +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();
|
||||||
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
|
||||||
@ -356,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
|
||||||
@ -375,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
|
||||||
@ -389,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
|
||||||
@ -408,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
|
||||||
@ -422,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
|
||||||
@ -441,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
|
||||||
|
|
||||||
|
@ -2556,8 +2556,8 @@ void MPU6050_Base::setClockSource(uint8_t source) {
|
|||||||
* -------------+------------------
|
* -------------+------------------
|
||||||
* 0 | 1.25 Hz
|
* 0 | 1.25 Hz
|
||||||
* 1 | 2.5 Hz
|
* 1 | 2.5 Hz
|
||||||
* 2 | 5 Hz
|
* 2 | 20 Hz
|
||||||
* 3 | 10 Hz
|
* 3 | 40 Hz
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* For further information regarding the MPU-60X0's power modes, please refer to
|
* For further information regarding the MPU-60X0's power modes, please refer to
|
||||||
@ -3371,25 +3371,27 @@ void MPU6050_Base::PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops){
|
|||||||
resetDMP();
|
resetDMP();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPU6050_Base::PrintActiveOffsets() {
|
int16_t * MPU6050_Base::GetActiveOffsets() {
|
||||||
uint8_t AOffsetRegister = (getDeviceID() < 0x38 )? MPU6050_RA_XA_OFFS_H:0x77;
|
uint8_t AOffsetRegister = (getDeviceID() < 0x38 )? MPU6050_RA_XA_OFFS_H:0x77;
|
||||||
int16_t Data[3];
|
if(AOffsetRegister == 0x06) I2Cdev::readWords(devAddr, AOffsetRegister, 3, (uint16_t *)offsets, I2Cdev::readTimeout, wireObj);
|
||||||
//Serial.print(F("Offset Register 0x"));
|
else {
|
||||||
//Serial.print(AOffsetRegister>>4,HEX);Serial.print(AOffsetRegister&0x0F,HEX);
|
I2Cdev::readWords(devAddr, AOffsetRegister, 1, (uint16_t *)offsets, I2Cdev::readTimeout, wireObj);
|
||||||
Serial.print(F("\n// X Accel Y Accel Z Accel X Gyro Y Gyro Z Gyro\n// OFFSETS "));
|
I2Cdev::readWords(devAddr, AOffsetRegister+3, 1, (uint16_t *)(offsets+1), I2Cdev::readTimeout, wireObj);
|
||||||
if(AOffsetRegister == 0x06) I2Cdev::readWords(devAddr, AOffsetRegister, 3, (uint16_t *)Data, I2Cdev::readTimeout, wireObj);
|
I2Cdev::readWords(devAddr, AOffsetRegister+6, 1, (uint16_t *)(offsets+2), I2Cdev::readTimeout, wireObj);
|
||||||
else {
|
}
|
||||||
I2Cdev::readWords(devAddr, AOffsetRegister, 1, (uint16_t *)Data, I2Cdev::readTimeout, wireObj);
|
I2Cdev::readWords(devAddr, 0x13, 3, (uint16_t *)(offsets+3), I2Cdev::readTimeout, wireObj);
|
||||||
I2Cdev::readWords(devAddr, AOffsetRegister+3, 1, (uint16_t *)Data+1, I2Cdev::readTimeout, wireObj);
|
return offsets;
|
||||||
I2Cdev::readWords(devAddr, AOffsetRegister+6, 1, (uint16_t *)Data+2, I2Cdev::readTimeout, wireObj);
|
}
|
||||||
}
|
|
||||||
// A_OFFSET_H_READ_A_OFFS(Data);
|
void MPU6050_Base::PrintActiveOffsets() {
|
||||||
Serial.print((float)Data[0], 5); Serial.print(", ");
|
GetActiveOffsets();
|
||||||
Serial.print((float)Data[1], 5); Serial.print(", ");
|
// A_OFFSET_H_READ_A_OFFS(Data);
|
||||||
Serial.print((float)Data[2], 5); Serial.print(", ");
|
Serial.print((float)offsets[0], 5); Serial.print(",\t");
|
||||||
I2Cdev::readWords(devAddr, 0x13, 3, (uint16_t *)Data, I2Cdev::readTimeout, wireObj);
|
Serial.print((float)offsets[1], 5); Serial.print(",\t");
|
||||||
// XG_OFFSET_H_READ_OFFS_USR(Data);
|
Serial.print((float)offsets[2], 5); Serial.print(",\t");
|
||||||
Serial.print((float)Data[0], 5); Serial.print(", ");
|
|
||||||
Serial.print((float)Data[1], 5); Serial.print(", ");
|
// XG_OFFSET_H_READ_OFFS_USR(Data);
|
||||||
Serial.print((float)Data[2], 5); Serial.print("\n");
|
Serial.print((float)offsets[3], 5); Serial.print(",\t");
|
||||||
|
Serial.print((float)offsets[4], 5); Serial.print(",\t");
|
||||||
|
Serial.print((float)offsets[5], 5); Serial.print("\n\n");
|
||||||
}
|
}
|
@ -832,12 +832,16 @@ class MPU6050_Base {
|
|||||||
void CalibrateAccel(uint8_t Loops = 15);// Fine tune after setting offsets with less Loops.
|
void CalibrateAccel(uint8_t Loops = 15);// Fine tune after setting offsets with less Loops.
|
||||||
void PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops); // Does the math
|
void PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops); // Does the math
|
||||||
void PrintActiveOffsets(); // See the results of the Calibration
|
void PrintActiveOffsets(); // See the results of the Calibration
|
||||||
|
int16_t * GetActiveOffsets();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t devAddr;
|
uint8_t devAddr;
|
||||||
void *wireObj;
|
void *wireObj;
|
||||||
uint8_t buffer[14];
|
uint8_t buffer[14];
|
||||||
uint32_t fifoTimeout = MPU6050_FIFO_DEFAULT_TIMEOUT;
|
uint32_t fifoTimeout = MPU6050_FIFO_DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int16_t offsets[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef I2CDEVLIB_MPU6050_TYPEDEF
|
#ifndef I2CDEVLIB_MPU6050_TYPEDEF
|
||||||
|
397
platformio.ini
@ -15,199 +15,328 @@ include_dir = lib
|
|||||||
[common_env_data]
|
[common_env_data]
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
platform = espressif8266 @ 3.2.0
|
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.0.0\""
|
-DGYRO_DISABLE_LOGGING
|
||||||
-D CFG_GITREV=\""beta-1\""
|
-DCALC_DISABLE_LOGGING
|
||||||
#!python script/git_rev.py
|
-DHELPER_DISABLE_LOGGING
|
||||||
lib_deps = # Switched to forks for better version control.
|
-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.1\""
|
||||||
|
#-DCFG_GITREV=\""beta-3\""
|
||||||
|
!python script/git_rev.py
|
||||||
|
lib_deps =
|
||||||
# Using local copy of these libraries
|
# Using local copy of these libraries
|
||||||
#https://github.com/jrowberg/i2cdevlib.git#<document>
|
# https://github.com/mp-se/i2cdevlib.git#<document>
|
||||||
#https://github.com/PaulStoffregen/OneWire
|
# https://github.com/mp-se/OneWire
|
||||||
#https://github.com/milesburton/Arduino-Temperature-Control-Library
|
# https://github.com/mp-se/Arduino-Temperature-Control-Library
|
||||||
https://github.com/mp-se/ESP_WiFiManager#v1.9.0 # https://github.com/khoih-prog/ESP_WiFiManager
|
# https://github.com/khoih-prog/ESP_WiFiManager
|
||||||
https://github.com/mp-se/ESP_DoubleResetDetector#v1.2.1 # 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
|
||||||
|
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
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 = release
|
build_type = release
|
||||||
|
#build_type = debug
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
|
build_src_filter = +<*> -<../test/tests*.cpp>
|
||||||
|
monitor_filters = esp8266_exception_decoder
|
||||||
|
|
||||||
[env:gravity-perf]
|
[env:gravity-unit]
|
||||||
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 COLLECT_PERFDATA
|
-D LOG_LEVEL=4
|
||||||
-D LOG_LEVEL=5
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
https://github.com/mp-se/incbin # https://github.com/graphitemaster/incbin
|
||||||
|
https://github.com/bxparks/AUnit#v1.6.1
|
||||||
${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 = debug
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
|
build_src_filter = +<*> -<main.cpp> +<../test/tests*.cpp>
|
||||||
|
monitor_filters = esp8266_exception_decoder
|
||||||
|
|
||||||
[env:gravity32-release]
|
[env:gravity32-release]
|
||||||
framework = arduino
|
framework = ${common_env_data.framework}
|
||||||
platform = espressif32 @ 3.5.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
|
build_unflags =
|
||||||
script/copy_firmware.py
|
${common_env_data.build_unflags}
|
||||||
script/create_versionjson.py
|
build_flags =
|
||||||
|
-Wl,-Map,output.map
|
||||||
|
#-DCORE_DEBUG_LEVEL=0
|
||||||
|
${common_env_data.build_flags}
|
||||||
|
-D LOG_LEVEL=5
|
||||||
|
-DESP32D1
|
||||||
|
-DCORE_DEBUG_LEVEL=0
|
||||||
|
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
|
lib_deps =
|
||||||
|
${common_env_data.lib_deps}
|
||||||
|
${common_env_data.lib_deps32}
|
||||||
|
lib_ignore =
|
||||||
|
board = wemos_d1_mini32
|
||||||
|
build_type = release
|
||||||
|
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:gravity32c3-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 =
|
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
|
||||||
-D CFG_DISABLE_LOGGING # Turn off verbose/notice logging to reduce size and dont overload uart (applies to LOG_LEVEL6)
|
-DESP32C3
|
||||||
-D GYRO_DISABLE_LOGGING
|
-DARDUINO_ESP32C3_DEV
|
||||||
-D CALC_DISABLE_LOGGING
|
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
-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/lorol/LITTLEFS#1.0.6
|
${common_env_data.lib_deps32}
|
||||||
https://github.com/mp-se/NimBLE-Arduino#1.3.8 # https://github.com/h2zero/NimBLE-Arduino
|
lib_ignore =
|
||||||
board = featheresp32
|
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:gravity32-perf]
|
[env:gravity32c3v1-release]
|
||||||
framework = arduino
|
framework = ${common_env_data.framework}
|
||||||
platform = espressif32 @ 3.5.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
|
||||||
|
-DREDUCE_WIFI_POWER # Enable this if v1.0 chip is used
|
||||||
|
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps}
|
${common_env_data.lib_deps}
|
||||||
https://github.com/lorol/LITTLEFS#1.0.6
|
${common_env_data.lib_deps32}
|
||||||
https://github.com/mp-se/NimBLE-Arduino#1.3.8 # https://github.com/h2zero/NimBLE-Arduino
|
lib_ignore =
|
||||||
board = featheresp32
|
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:gravity32-release2]
|
[env:gravity32s2-release]
|
||||||
#framework = arduino
|
framework = ${common_env_data.framework}
|
||||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip # build fails
|
platform = ${common_env_data.platform32}
|
||||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip
|
upload_speed = ${common_env_data.upload_speed}
|
||||||
#platform = espressif32 @ 4.1.0
|
monitor_speed = ${common_env_data.monitor_speed}
|
||||||
#upload_speed = ${common_env_data.upload_speed}
|
extra_scripts = ${common_env_data.extra_scripts}
|
||||||
#monitor_speed = ${common_env_data.monitor_speed}
|
build_unflags =
|
||||||
#extra_scripts =
|
${common_env_data.build_unflags}
|
||||||
# script/copy_html.py
|
build_flags =
|
||||||
# script/copy_firmware.py
|
-Wl,-Map,output.map
|
||||||
# script/create_versionjson.py
|
${common_env_data.build_flags}
|
||||||
#build_unflags =
|
-DLOG_LEVEL=5
|
||||||
# ${common_env_data.build_unflags}
|
-DCORE_DEBUG_LEVEL=0
|
||||||
#build_flags =
|
-DESP32S2
|
||||||
# ${common_env_data.build_flags}
|
-DARDUINO_ESP32S2_DEV
|
||||||
# -D ESPRESSIF32_20 # v2.0 framework
|
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
# -D LOG_LEVEL=5
|
lib_deps =
|
||||||
#lib_deps =
|
${common_env_data.lib_deps}
|
||||||
# ${common_env_data.lib_deps}
|
lib_ignore =
|
||||||
# https://github.com/mp-se/NimBLE-Arduino#1.3.8 # https://github.com/h2zero/NimBLE-Arduino
|
board = lolin_s2_mini
|
||||||
#board = featheresp32
|
build_type = release
|
||||||
#build_type = release
|
board_build.partitions = part32.csv
|
||||||
#board_build.partitions = part32.csv
|
board_build.filesystem = littlefs
|
||||||
#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: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_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
|
-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
|
||||||
|
|
||||||
|
# This is a version for the floaty hardware. No DSB18 sensor and no battery measurement.
|
||||||
|
[env:gravity32lite-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
|
||||||
|
-DESP32LITE
|
||||||
|
-DFLOATY
|
||||||
|
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||||
|
lib_deps =
|
||||||
|
${common_env_data.lib_deps}
|
||||||
|
${common_env_data.lib_deps32}
|
||||||
|
lib_ignore =
|
||||||
|
board = lolin32_lite
|
||||||
|
build_type = release
|
||||||
|
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
|
||||||
|
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
requests
|
@ -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,44 @@ 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 == "gravity32c3v1-release" :
|
||||||
|
target = dir + "/bin/firmware32c3v1.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 == "gravity32s2-release" :
|
||||||
|
target = dir + "/bin/firmware32s2.bin"
|
||||||
|
source = dir + "/.pio/build/" + name + "/firmware.bin"
|
||||||
|
print( "Copy file : " + 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 )
|
||||||
|
|
||||||
|
if name == "gravity32lite-release" :
|
||||||
|
target = dir + "/bin/firmware32lite.bin"
|
||||||
|
source = dir + "/.pio/build/" + name + "/firmware.bin"
|
||||||
|
print( "Copy file : " + source + " -> " + target )
|
||||||
|
shutil.copyfile( source, target )
|
||||||
|
|
||||||
|
target = dir + "/bin/partitions32lite.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)
|
||||||
|
@ -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 )
|
|
@ -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")
|
||||||
|
|
||||||
|
10
src/ble.cpp
@ -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>
|
||||||
@ -41,9 +41,15 @@ BleSender::BleSender(const char* color) {
|
|||||||
|
|
||||||
// boost power to maximum, these might be changed once battery life using BLE
|
// boost power to maximum, these might be changed once battery life using BLE
|
||||||
// has been tested.
|
// has been tested.
|
||||||
|
#if defined(ESP32C3) && defined(REDUCE_WIFI_POWER)
|
||||||
|
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P6);
|
||||||
|
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P6);
|
||||||
|
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, ESP_PWR_LVL_P6);
|
||||||
|
#else
|
||||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9);
|
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9);
|
||||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9);
|
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9);
|
||||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, ESP_PWR_LVL_P9);
|
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, ESP_PWR_LVL_P9);
|
||||||
|
#endif
|
||||||
|
|
||||||
_advertising = BLEDevice::getAdvertising();
|
_advertising = BLEDevice::getAdvertising();
|
||||||
_color = color;
|
_color = color;
|
||||||
@ -99,4 +105,4 @@ void BleSender::sendData(float tempF, float gravSG) {
|
|||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ESP32
|
#endif // ESP32 && !ESP32S2
|
||||||
|
@ -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_
|
||||||
|
64
src/calc.cpp
@ -27,15 +27,13 @@ SOFTWARE.
|
|||||||
#include <calc.hpp>
|
#include <calc.hpp>
|
||||||
#include <main.hpp>
|
#include <main.hpp>
|
||||||
|
|
||||||
//
|
|
||||||
// Use values to derive a formula
|
|
||||||
//
|
|
||||||
int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
||||||
int formulaBufferSize, int order) {
|
int formulaBufferSize, int order) {
|
||||||
int noAngles = 0;
|
int noAngles = 0;
|
||||||
RawFormulaData fd2;
|
RawFormulaData fd2;
|
||||||
|
|
||||||
// Check how many valid values we have got and make sure we have a full series.
|
// Check how many valid values we have got and make sure we have a full
|
||||||
|
// series.
|
||||||
for (int i = 0; i < FORMULA_DATA_SIZE; i++) {
|
for (int i = 0; i < FORMULA_DATA_SIZE; i++) {
|
||||||
if (fd.a[i]) {
|
if (fd.a[i]) {
|
||||||
fd2.a[noAngles] = fd.a[i];
|
fd2.a[noAngles] = fd.a[i];
|
||||||
@ -50,9 +48,8 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
|||||||
order, noAngles);
|
order, noAngles);
|
||||||
#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];
|
||||||
@ -62,7 +59,8 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
|||||||
// Returned value is 0 if no error
|
// Returned value is 0 if no error
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
||||||
Log.verbose(F("CALC: Finshied processing data points, order = %d." CR), order);
|
Log.verbose(F("CALC: Finshied processing data points, order = %d." CR),
|
||||||
|
order);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Print the formula based on 'order'
|
// Print the formula based on 'order'
|
||||||
@ -96,18 +94,15 @@ 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[20];
|
writeErrorLog(
|
||||||
snprintf(&s[0], sizeof(s), "%.8f", dev);
|
"CALC: Validation failed on angle %.2f, deviation too large %.4f "
|
||||||
Log.error(F("CALC: Deviation to large: %s" CR), &s[0]);
|
"SG, formula order %d",
|
||||||
|
fd.a[i], dev * 1000, order);
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
ErrorFileLog errLog;
|
|
||||||
errLog.addEntry(
|
|
||||||
F("CALC: Error validating created formula. Deviation to large, "
|
|
||||||
"formula rejected."));
|
|
||||||
return ERR_FORMULA_UNABLETOFFIND;
|
return ERR_FORMULA_UNABLETOFFIND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,15 +111,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Calculates gravity according to supplied formula, compatible with
|
|
||||||
// iSpindle/Fermentrack formula
|
|
||||||
//
|
|
||||||
double calculateGravity(double angle, double temp, const char *tempFormula) {
|
double calculateGravity(double angle, double temp, const char *tempFormula) {
|
||||||
const char *formula = myConfig.getGravityFormula();
|
const char *formula = myConfig.getGravityFormula();
|
||||||
|
|
||||||
@ -162,27 +152,23 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Do a standard gravity temperature correction. This is a simple way to adjust
|
// Do a standard gravity temperature correction. This is a simple way to adjust
|
||||||
// for differnt worth temperatures. This function uses C as temperature.
|
// for differnt worth temperatures. This function uses C as temperature.
|
||||||
//
|
//
|
||||||
// Source: https://homebrewacademy.com/hydrometer-temperature-correction/
|
// Source: https://homebrewacademy.com/hydrometer-temperature-correction/
|
||||||
//
|
double gravityTemperatureCorrectionC(double gravitySG, double tempC,
|
||||||
double gravityTemperatureCorrectionC(double gravity, double tempC,
|
|
||||||
double calTempC) {
|
double calTempC) {
|
||||||
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
||||||
Log.verbose(F("CALC: Adjusting gravity based on temperature, gravity %F, "
|
Log.verbose(F("CALC: Adjusting gravity based on temperature, gravity %F, "
|
||||||
"temp %F, calTemp %F." CR),
|
"temp %F, calTemp %F." CR),
|
||||||
gravity, tempC, calTempC);
|
gravitySG, tempC, calTempC);
|
||||||
#endif
|
#endif
|
||||||
// float tempF = convertCtoF(tempC);
|
double tempF = convertCtoF(tempC);
|
||||||
// float calTempF = convertCtoF(calTempC);
|
double calTempF = convertCtoF(calTempC);
|
||||||
|
|
||||||
const char *formula =
|
const char *formula =
|
||||||
"gravity*((1.00130346-0.000134722124*temp+0.00000204052596*temp^2-0."
|
"gravity*((1.00130346-0.000134722124*temp+0.00000204052596*temp^2-0."
|
||||||
"00000000232820948*temp^3)/"
|
"00000000232820948*temp^3)/"
|
||||||
@ -191,7 +177,7 @@ double gravityTemperatureCorrectionC(double gravity, double tempC,
|
|||||||
|
|
||||||
// Store variable names and pointers.
|
// Store variable names and pointers.
|
||||||
te_variable vars[] = {
|
te_variable vars[] = {
|
||||||
{"gravity", &gravity}, {"temp", &tempC}, {"cal", &calTempC}};
|
{"gravity", &gravitySG}, {"temp", &tempF}, {"cal", &calTempF}};
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
// Compile the expression with variables.
|
// Compile the expression with variables.
|
||||||
@ -202,18 +188,18 @@ double gravityTemperatureCorrectionC(double gravity, double tempC,
|
|||||||
te_free(expr);
|
te_free(expr);
|
||||||
|
|
||||||
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
||||||
char s[10];
|
char s[80];
|
||||||
snprintf(&s[0], sizeof(s), "%.8f", g);
|
snprintf(&s[0], sizeof(s), "Corrected gravity=%.8f, input gravity=%.8f", g,
|
||||||
Log.verbose(F("CALC: Corrected gravity is %s." CR), &s[0]);
|
gravitySG);
|
||||||
|
Log.verbose(F("CALC: %s." CR), &s[0]);
|
||||||
#endif
|
#endif
|
||||||
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 gravity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
@ -32,9 +32,8 @@ SOFTWARE.
|
|||||||
|
|
||||||
double calculateGravity(double angle, double tempC,
|
double calculateGravity(double angle, double tempC,
|
||||||
const char *tempFormula = 0);
|
const char *tempFormula = 0);
|
||||||
double gravityTemperatureCorrectionC(
|
double gravityTemperatureCorrectionC(double gravity, double tempC,
|
||||||
double gravity, double tempC,
|
double calTempC);
|
||||||
double calTempC = myAdvancedConfig.getDefaultCalibrationTemp());
|
|
||||||
int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
||||||
int formulaBufferSize, int order);
|
int formulaBufferSize, int order);
|
||||||
|
|
||||||
|
@ -86,12 +86,14 @@ void Config::createJson(DynamicJsonDocument& doc) {
|
|||||||
doc[PARAM_PUSH_MQTT_USER] = getMqttUser();
|
doc[PARAM_PUSH_MQTT_USER] = getMqttUser();
|
||||||
doc[PARAM_PUSH_MQTT_PASS] = getMqttPass();
|
doc[PARAM_PUSH_MQTT_PASS] = getMqttPass();
|
||||||
doc[PARAM_SLEEP_INTERVAL] = getSleepInterval();
|
doc[PARAM_SLEEP_INTERVAL] = getSleepInterval();
|
||||||
doc[PARAM_VOLTAGEFACTOR] = getVoltageFactor();
|
doc[PARAM_VOLTAGE_FACTOR] = getVoltageFactor();
|
||||||
|
doc[PARAM_VOLTAGE_CONFIG] = getVoltageConfig();
|
||||||
doc[PARAM_GRAVITY_FORMULA] = getGravityFormula();
|
doc[PARAM_GRAVITY_FORMULA] = getGravityFormula();
|
||||||
doc[PARAM_GRAVITY_FORMAT] = String(getGravityFormat());
|
doc[PARAM_GRAVITY_FORMAT] = String(getGravityFormat());
|
||||||
doc[PARAM_TEMP_ADJ] = getTempSensorAdjC();
|
doc[PARAM_TEMP_ADJ] = getTempSensorAdjC();
|
||||||
doc[PARAM_GRAVITY_TEMP_ADJ] = isGravityTempAdj();
|
doc[PARAM_GRAVITY_TEMP_ADJ] = isGravityTempAdj();
|
||||||
doc[PARAM_GYRO_TEMP] = isGyroTemp();
|
doc[PARAM_GYRO_TEMP] = isGyroTemp();
|
||||||
|
doc[PARAM_STORAGE_SLEEP] = isStorageSleep();
|
||||||
|
|
||||||
JsonObject cal = doc.createNestedObject(PARAM_GYRO_CALIBRATION);
|
JsonObject cal = doc.createNestedObject(PARAM_GYRO_CALIBRATION);
|
||||||
cal["ax"] = _gyroCalibration.ax;
|
cal["ax"] = _gyroCalibration.ax;
|
||||||
@ -143,17 +145,16 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(CFG_JSON_BUFSIZE);
|
DynamicJsonDocument doc(3000);
|
||||||
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);
|
||||||
@ -174,33 +175,30 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.notice(F("CFG : Size of configuration file=%d bytes." CR),
|
Log.notice(F("CFG : Size of configuration file=%d bytes." CR),
|
||||||
configFile.size());
|
configFile.size());
|
||||||
|
|
||||||
DynamicJsonDocument doc(CFG_JSON_BUFSIZE);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,14 +251,18 @@ bool Config::loadFile() {
|
|||||||
|
|
||||||
if (!doc[PARAM_SLEEP_INTERVAL].isNull())
|
if (!doc[PARAM_SLEEP_INTERVAL].isNull())
|
||||||
setSleepInterval(doc[PARAM_SLEEP_INTERVAL].as<int>());
|
setSleepInterval(doc[PARAM_SLEEP_INTERVAL].as<int>());
|
||||||
if (!doc[PARAM_VOLTAGEFACTOR].isNull())
|
if (!doc[PARAM_VOLTAGE_FACTOR].isNull())
|
||||||
setVoltageFactor(doc[PARAM_VOLTAGEFACTOR].as<float>());
|
setVoltageFactor(doc[PARAM_VOLTAGE_FACTOR].as<float>());
|
||||||
|
if (!doc[PARAM_VOLTAGE_CONFIG].isNull())
|
||||||
|
setVoltageConfig(doc[PARAM_VOLTAGE_CONFIG].as<float>());
|
||||||
if (!doc[PARAM_GRAVITY_FORMULA].isNull())
|
if (!doc[PARAM_GRAVITY_FORMULA].isNull())
|
||||||
setGravityFormula(doc[PARAM_GRAVITY_FORMULA]);
|
setGravityFormula(doc[PARAM_GRAVITY_FORMULA]);
|
||||||
if (!doc[PARAM_GRAVITY_TEMP_ADJ].isNull())
|
if (!doc[PARAM_GRAVITY_TEMP_ADJ].isNull())
|
||||||
setGravityTempAdj(doc[PARAM_GRAVITY_TEMP_ADJ].as<bool>());
|
setGravityTempAdj(doc[PARAM_GRAVITY_TEMP_ADJ].as<bool>());
|
||||||
if (!doc[PARAM_GYRO_TEMP].isNull())
|
if (!doc[PARAM_GYRO_TEMP].isNull())
|
||||||
setGyroTemp(doc[PARAM_GYRO_TEMP].as<bool>());
|
setGyroTemp(doc[PARAM_GYRO_TEMP].as<bool>());
|
||||||
|
if (!doc[PARAM_STORAGE_SLEEP].isNull())
|
||||||
|
setStorageSleep(doc[PARAM_STORAGE_SLEEP].as<bool>());
|
||||||
if (!doc[PARAM_GRAVITY_FORMAT].isNull()) {
|
if (!doc[PARAM_GRAVITY_FORMAT].isNull()) {
|
||||||
String s = doc[PARAM_GRAVITY_FORMAT];
|
String s = doc[PARAM_GRAVITY_FORMAT];
|
||||||
setGravityFormat(s.charAt(0));
|
setGravityFormat(s.charAt(0));
|
||||||
@ -371,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,10 +392,11 @@ bool AdvancedConfig::saveFile() {
|
|||||||
doc[PARAM_HW_PUSH_INTERVAL_INFLUX] = this->getPushIntervalInflux();
|
doc[PARAM_HW_PUSH_INTERVAL_INFLUX] = this->getPushIntervalInflux();
|
||||||
doc[PARAM_HW_PUSH_INTERVAL_MQTT] = this->getPushIntervalMqtt();
|
doc[PARAM_HW_PUSH_INTERVAL_MQTT] = this->getPushIntervalMqtt();
|
||||||
doc[PARAM_HW_TEMPSENSOR_RESOLUTION] = this->getTempSensorResolution();
|
doc[PARAM_HW_TEMPSENSOR_RESOLUTION] = this->getTempSensorResolution();
|
||||||
|
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);
|
||||||
@ -422,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +478,10 @@ bool AdvancedConfig::loadFile() {
|
|||||||
if (!doc[PARAM_HW_PUSH_INTERVAL_MQTT].isNull())
|
if (!doc[PARAM_HW_PUSH_INTERVAL_MQTT].isNull())
|
||||||
this->setPushIntervalMqtt(doc[PARAM_HW_PUSH_INTERVAL_MQTT].as<int>());
|
this->setPushIntervalMqtt(doc[PARAM_HW_PUSH_INTERVAL_MQTT].as<int>());
|
||||||
if (!doc[PARAM_HW_TEMPSENSOR_RESOLUTION].isNull())
|
if (!doc[PARAM_HW_TEMPSENSOR_RESOLUTION].isNull())
|
||||||
this->setTempSensorResolution(doc[PARAM_HW_TEMPSENSOR_RESOLUTION].as<int>());
|
this->setTempSensorResolution(
|
||||||
|
doc[PARAM_HW_TEMPSENSOR_RESOLUTION].as<int>());
|
||||||
|
if (!doc[PARAM_HW_IGNORE_LOW_ANGLES].isNull())
|
||||||
|
setIgnoreLowAnges(doc[PARAM_HW_IGNORE_LOW_ANGLES].as<bool>());
|
||||||
|
|
||||||
Log.notice(F("CFG : Configuration file " CFG_HW_FILENAME " loaded." CR));
|
Log.notice(F("CFG : Configuration file " CFG_HW_FILENAME " loaded." CR));
|
||||||
return true;
|
return true;
|
||||||
|
@ -27,8 +27,6 @@ SOFTWARE.
|
|||||||
#include <helper.hpp>
|
#include <helper.hpp>
|
||||||
#include <resources.hpp>
|
#include <resources.hpp>
|
||||||
|
|
||||||
#define CFG_JSON_BUFSIZE 3192
|
|
||||||
|
|
||||||
#define CFG_APPNAME "GravityMon" // Name of firmware
|
#define CFG_APPNAME "GravityMon" // Name of firmware
|
||||||
#define CFG_FILENAME "/gravitymon.json" // Name of config file
|
#define CFG_FILENAME "/gravitymon.json" // Name of config file
|
||||||
#define CFG_HW_FILENAME "/hardware.json" // Name of config file for hw
|
#define CFG_HW_FILENAME "/hardware.json" // Name of config file for hw
|
||||||
@ -56,12 +54,12 @@ struct RawFormulaData {
|
|||||||
|
|
||||||
class AdvancedConfig {
|
class AdvancedConfig {
|
||||||
private:
|
private:
|
||||||
int _wifiPortalTimeout = 120;
|
int _wifiPortalTimeout = 120; // seconds
|
||||||
int _wifiConnectTimeout = 20;
|
int _wifiConnectTimeout = 20; // seconds
|
||||||
float _maxFormulaCreationDeviation = 1.6;
|
float _maxFormulaCreationDeviation = 3; // SG
|
||||||
float _defaultCalibrationTemp = 20.0;
|
float _defaultCalibrationTemp = 20.0; // C
|
||||||
int _gyroSensorMovingThreashold = 500;
|
int _gyroSensorMovingThreashold = 500;
|
||||||
int _tempSensorResolution = 9;
|
int _tempSensorResolution = 9; // bits
|
||||||
int _gyroReadCount = 50;
|
int _gyroReadCount = 50;
|
||||||
int _gyroReadDelay = 3150; // us, empirical, to hold sampling to 200 Hz
|
int _gyroReadDelay = 3150; // us, empirical, to hold sampling to 200 Hz
|
||||||
int _pushTimeout = 10; // seconds
|
int _pushTimeout = 10; // seconds
|
||||||
@ -70,6 +68,7 @@ class AdvancedConfig {
|
|||||||
int _pushIntervalHttp3 = 0;
|
int _pushIntervalHttp3 = 0;
|
||||||
int _pushIntervalInflux = 0;
|
int _pushIntervalInflux = 0;
|
||||||
int _pushIntervalMqtt = 0;
|
int _pushIntervalMqtt = 0;
|
||||||
|
bool _IgnoreLowAnges = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getWifiPortalTimeout() { return _wifiPortalTimeout; }
|
int getWifiPortalTimeout() { return _wifiPortalTimeout; }
|
||||||
@ -87,8 +86,7 @@ class AdvancedConfig {
|
|||||||
|
|
||||||
int getTempSensorResolution() { return _tempSensorResolution; }
|
int getTempSensorResolution() { return _tempSensorResolution; }
|
||||||
void setTempSensorResolution(int t) {
|
void setTempSensorResolution(int t) {
|
||||||
if (t>=9 && t<=12)
|
if (t >= 9 && t <= 12) _tempSensorResolution = t;
|
||||||
_tempSensorResolution = t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float getDefaultCalibrationTemp() { return _defaultCalibrationTemp; }
|
float getDefaultCalibrationTemp() { return _defaultCalibrationTemp; }
|
||||||
@ -128,6 +126,9 @@ class AdvancedConfig {
|
|||||||
: true;
|
: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool isIgnoreLowAnges() { return _IgnoreLowAnges; }
|
||||||
|
void setIgnoreLowAnges(bool b) { _IgnoreLowAnges = b; }
|
||||||
|
|
||||||
bool saveFile();
|
bool saveFile();
|
||||||
bool loadFile();
|
bool loadFile();
|
||||||
};
|
};
|
||||||
@ -142,10 +143,26 @@ 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 = 0.59;
|
||||||
|
#elif defined(ESP32LITE)
|
||||||
|
float _voltageFactor = 1.59;
|
||||||
|
#else // ESP32
|
||||||
|
float _voltageFactor = 1.3;
|
||||||
|
#endif
|
||||||
|
float _voltageConfig = 4.15;
|
||||||
float _tempSensorAdjC = 0;
|
float _tempSensorAdjC = 0;
|
||||||
int _sleepInterval = 900;
|
int _sleepInterval = 900;
|
||||||
|
#if defined(FLOATY)
|
||||||
|
bool _gyroTemp = true;
|
||||||
|
#else
|
||||||
bool _gyroTemp = false;
|
bool _gyroTemp = false;
|
||||||
|
#endif
|
||||||
|
bool _storageSleep = false;
|
||||||
|
|
||||||
// Wifi Config
|
// Wifi Config
|
||||||
String _wifiSSID[2] = {"", ""};
|
String _wifiSSID[2] = {"", ""};
|
||||||
@ -181,7 +198,8 @@ class Config {
|
|||||||
|
|
||||||
// Gyro calibration and formula calculation data
|
// Gyro calibration and formula calculation data
|
||||||
RawGyroData _gyroCalibration = {0, 0, 0, 0, 0, 0};
|
RawGyroData _gyroCalibration = {0, 0, 0, 0, 0, 0};
|
||||||
RawFormulaData _formulaData = {{0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}};
|
RawFormulaData _formulaData = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
|
||||||
|
|
||||||
void formatFileSystem();
|
void formatFileSystem();
|
||||||
|
|
||||||
@ -199,8 +217,18 @@ class Config {
|
|||||||
|
|
||||||
const bool isGyroTemp() { return _gyroTemp; }
|
const bool isGyroTemp() { return _gyroTemp; }
|
||||||
void setGyroTemp(bool b) {
|
void setGyroTemp(bool b) {
|
||||||
|
#if defined(FLOATY)
|
||||||
|
// Floaty hardware dont have a temp sensor, uses gyro temperature
|
||||||
|
#else
|
||||||
_gyroTemp = b;
|
_gyroTemp = b;
|
||||||
_saveNeeded = true;
|
_saveNeeded = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool isStorageSleep() { return _storageSleep; }
|
||||||
|
void setStorageSleep(bool b) {
|
||||||
|
_storageSleep = b;
|
||||||
|
_saveNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getOtaURL() { return _otaURL.c_str(); }
|
const char* getOtaURL() { return _otaURL.c_str(); }
|
||||||
@ -367,6 +395,16 @@ class Config {
|
|||||||
_saveNeeded = true;
|
_saveNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getVoltageConfig() { return _voltageConfig; }
|
||||||
|
void setVoltageConfig(float f) {
|
||||||
|
_voltageConfig = f;
|
||||||
|
_saveNeeded = true;
|
||||||
|
}
|
||||||
|
void setVoltageConfig(String s) {
|
||||||
|
_voltageConfig = s.toFloat();
|
||||||
|
_saveNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
float getTempSensorAdjC() { return _tempSensorAdjC; }
|
float getTempSensorAdjC() { return _tempSensorAdjC; }
|
||||||
void setTempSensorAdjC(float f) {
|
void setTempSensorAdjC(float f) {
|
||||||
_tempSensorAdjC = f;
|
_tempSensorAdjC = f;
|
||||||
|
87
src/gyro.cpp
@ -30,22 +30,42 @@ MPU6050 accelgyro;
|
|||||||
#define GYRO_USE_INTERRUPT // Use interrupt to detect when new sample is ready
|
#define GYRO_USE_INTERRUPT // Use interrupt to detect when new sample is ready
|
||||||
#define GYRO_SHOW_MINMAX // Will calculate the min/max values when doing
|
#define GYRO_SHOW_MINMAX // Will calculate the min/max values when doing
|
||||||
// calibration
|
// calibration
|
||||||
// #define GYRO_CALIBRATE_STARTUP // Will calibrate sensor at startup
|
|
||||||
|
|
||||||
//
|
|
||||||
// Initialize the sensor chip.
|
|
||||||
//
|
|
||||||
bool GyroSensor::setup() {
|
bool GyroSensor::setup() {
|
||||||
|
int clock = 400000;
|
||||||
|
#if defined(FLOATY)
|
||||||
|
pinMode(PIN_VCC, OUTPUT);
|
||||||
|
pinMode(PIN_GND, OUTPUT_OPEN_DRAIN);
|
||||||
|
digitalWrite(PIN_VCC, HIGH);
|
||||||
|
digitalWrite(PIN_GND, LOW);
|
||||||
|
delay(10); // Wait for the pins to settle or we will fail to connect
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
/* For testing pin config of new boards with led.
|
||||||
|
pinMode(PIN_SDA, OUTPUT);
|
||||||
|
pinMode(PIN_SCL, OUTPUT);
|
||||||
|
for(int i = 0, j = LOW, k = LOW; i < 100; i++) {
|
||||||
|
|
||||||
|
digitalWrite(PIN_SDA, k);
|
||||||
|
digitalWrite(PIN_SCL, j);
|
||||||
|
k = !k;
|
||||||
|
delay(300);
|
||||||
|
digitalWrite(PIN_SDA, k);
|
||||||
|
k = !k;
|
||||||
|
j = !j;
|
||||||
|
delay(300);
|
||||||
|
}*/
|
||||||
|
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Setting up hardware." CR));
|
Log.verbose(F("GYRO: Setting up hardware." CR));
|
||||||
#endif
|
#endif
|
||||||
Wire.begin(PIN_SDA, PIN_SCL);
|
Wire.begin(PIN_SDA, PIN_SCL);
|
||||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having
|
Wire.setClock(clock); // 400kHz I2C clock.
|
||||||
// compilation difficulties
|
|
||||||
|
|
||||||
if (!accelgyro.testConnection()) {
|
uint8_t id = accelgyro.getDeviceID();
|
||||||
ErrorFileLog errLog;
|
|
||||||
errLog.addEntry(F("GYRO: Failed to connect to gyro, is it connected?"));
|
if (id != 0x34 && id != 0x38) { // Allow both MPU6050 and MPU6500
|
||||||
|
writeErrorLog("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)
|
||||||
@ -67,11 +87,6 @@ bool GyroSensor::setup() {
|
|||||||
accelgyro.setIntDataReadyEnabled(true);
|
accelgyro.setIntDataReadyEnabled(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GYRO_CALIBRATE_STARTUP)
|
|
||||||
// Run the calibration at start, useful for testing.
|
|
||||||
calibrateSensor();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Once we have calibration values stored we just apply them from the
|
// Once we have calibration values stored we just apply them from the
|
||||||
// config.
|
// config.
|
||||||
_calibrationOffset = myConfig.getGyroCalibration();
|
_calibrationOffset = myConfig.getGyroCalibration();
|
||||||
@ -80,19 +95,17 @@ bool GyroSensor::setup() {
|
|||||||
return _sensorConnected;
|
return _sensorConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Set sensor in sleep mode to conserve battery
|
|
||||||
//
|
|
||||||
void GyroSensor::enterSleep() {
|
void GyroSensor::enterSleep() {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Setting up hardware." CR));
|
Log.verbose(F("GYRO: Setting up hardware." CR));
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(FLOATY)
|
||||||
|
digitalWrite(PIN_VCC, LOW);
|
||||||
|
#else
|
||||||
accelgyro.setSleepEnabled(true);
|
accelgyro.setSleepEnabled(true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Do a number of reads to get a more stable value.
|
|
||||||
//
|
|
||||||
void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
||||||
const int delayTime) {
|
const int delayTime) {
|
||||||
RawGyroDataL average = {0, 0, 0, 0, 0, 0};
|
RawGyroDataL average = {0, 0, 0, 0, 0, 0};
|
||||||
@ -104,7 +117,8 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
|||||||
|
|
||||||
// Set some initial values
|
// Set some initial values
|
||||||
#if defined(GYRO_SHOW_MINMAX)
|
#if defined(GYRO_SHOW_MINMAX)
|
||||||
RawGyroData min, max;
|
RawGyroData min = {0, 0, 0};
|
||||||
|
RawGyroData max = {0, 0, 0};
|
||||||
accelgyro.getAcceleration(&min.ax, &min.ay, &min.az);
|
accelgyro.getAcceleration(&min.ax, &min.ay, &min.az);
|
||||||
min.temp = accelgyro.getTemperature();
|
min.temp = accelgyro.getTemperature();
|
||||||
max = min;
|
max = min;
|
||||||
@ -178,9 +192,6 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Calcuate the angles (tilt)
|
|
||||||
//
|
|
||||||
float GyroSensor::calculateAngle(RawGyroData &raw) {
|
float GyroSensor::calculateAngle(RawGyroData &raw) {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Calculating the angle." CR));
|
Log.verbose(F("GYRO: Calculating the angle." CR));
|
||||||
@ -208,9 +219,6 @@ float GyroSensor::calculateAngle(RawGyroData &raw) {
|
|||||||
return vY;
|
return vY;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Check if the values are high that indicate that the sensor is moving.
|
|
||||||
//
|
|
||||||
bool GyroSensor::isSensorMoving(RawGyroData &raw) {
|
bool GyroSensor::isSensorMoving(RawGyroData &raw) {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Checking for sensor movement." CR));
|
Log.verbose(F("GYRO: Checking for sensor movement." CR));
|
||||||
@ -228,9 +236,6 @@ bool GyroSensor::isSensorMoving(RawGyroData &raw) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Read the tilt angle from the gyro.
|
|
||||||
//
|
|
||||||
bool GyroSensor::read() {
|
bool GyroSensor::read() {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Getting new gyro position." CR));
|
Log.verbose(F("GYRO: Getting new gyro position." CR));
|
||||||
@ -269,9 +274,6 @@ bool GyroSensor::read() {
|
|||||||
return _validValue;
|
return _validValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Dump the stored calibration values.
|
|
||||||
//
|
|
||||||
void GyroSensor::dumpCalibration() {
|
void GyroSensor::dumpCalibration() {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Accel offset\t%d\t%d\t%d" CR), _calibrationOffset.ax,
|
Log.verbose(F("GYRO: Accel offset\t%d\t%d\t%d" CR), _calibrationOffset.ax,
|
||||||
@ -281,9 +283,6 @@ void GyroSensor::dumpCalibration() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Update the sensor with out calculated offsets.
|
|
||||||
//
|
|
||||||
void GyroSensor::applyCalibration() {
|
void GyroSensor::applyCalibration() {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Applying calibration offsets to sensor." CR));
|
Log.verbose(F("GYRO: Applying calibration offsets to sensor." CR));
|
||||||
@ -292,9 +291,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,22 +304,19 @@ void GyroSensor::applyCalibration() {
|
|||||||
accelgyro.setZGyroOffset(_calibrationOffset.gz);
|
accelgyro.setZGyroOffset(_calibrationOffset.gz);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Calculate the offsets for calibration.
|
|
||||||
//
|
|
||||||
void GyroSensor::calibrateSensor() {
|
void GyroSensor::calibrateSensor() {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
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();
|
||||||
@ -330,14 +325,10 @@ void GyroSensor::calibrateSensor() {
|
|||||||
_calibrationOffset.gy = accelgyro.getYGyroOffset();
|
_calibrationOffset.gy = accelgyro.getYGyroOffset();
|
||||||
_calibrationOffset.gz = accelgyro.getZGyroOffset();
|
_calibrationOffset.gz = accelgyro.getZGyroOffset();
|
||||||
|
|
||||||
// Save the calibrated values
|
|
||||||
myConfig.setGyroCalibration(_calibrationOffset);
|
myConfig.setGyroCalibration(_calibrationOffset);
|
||||||
myConfig.saveFile();
|
myConfig.saveFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Calibrate the device.
|
|
||||||
//
|
|
||||||
void GyroSensor::debug() {
|
void GyroSensor::debug() {
|
||||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||||
Log.verbose(F("GYRO: Debug - Clock src %d." CR),
|
Log.verbose(F("GYRO: Debug - Clock src %d." CR),
|
||||||
|
286
src/helper.cpp
@ -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,127 @@ 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);
|
||||||
|
// Havent found a good way to get exception cause from an 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 +182,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 +190,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 +200,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 +215,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,57 +223,82 @@ 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
|
||||||
"SKIP_SLEEP "
|
"SKIP_SLEEP "
|
||||||
#endif
|
#endif
|
||||||
#ifdef EMBED_HTML
|
|
||||||
"EMBED_HTML "
|
|
||||||
#endif
|
|
||||||
#ifdef COLLECT_PERFDATA
|
#ifdef COLLECT_PERFDATA
|
||||||
"PERFDATA "
|
"PERFDATA "
|
||||||
#endif
|
|
||||||
#ifdef ACTIVATE_OTA
|
|
||||||
"OTA "
|
|
||||||
#endif
|
#endif
|
||||||
CR),
|
CR),
|
||||||
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();
|
#if defined(USE_SERIAL_PINS) && defined(ESP8266)
|
||||||
Serial.begin(serialSpeed);
|
uint8_t txPin = 3;
|
||||||
|
EspSerial.begin(serialSpeed, SERIAL_8N1, SERIAL_TX_ONLY, txPin);
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
EspSerial.begin(serialSpeed);
|
||||||
|
#elif defined(USE_SERIAL_PINS) && defined(ESP32C3)
|
||||||
|
EspSerial.begin(115200L, SERIAL_8N1, 20, 21);
|
||||||
|
#elif defined(ESP32C3)
|
||||||
|
EspSerial.begin(115200L);
|
||||||
|
#elif defined(USE_SERIAL_PINS) && defined(ESP32S2)
|
||||||
|
EspSerial.begin(115200L, SERIAL_8N1, 37, 39);
|
||||||
|
#elif defined(ESP32S2)
|
||||||
|
EspSerial.begin(115200L);
|
||||||
|
#elif defined(USE_SERIAL_PINS) && defined(ESP32LITE)
|
||||||
|
EspSerial.begin(serialSpeed, SERIAL_8N1, 16, 17);
|
||||||
|
#elif defined(USE_SERIAL_PINS) && defined(ESP32)
|
||||||
|
EspSerial.begin(serialSpeed, SERIAL_8N1, 1, 3);
|
||||||
|
#elif defined(ESP32)
|
||||||
|
EspSerial.begin(115200L);
|
||||||
|
#endif
|
||||||
|
|
||||||
getLog()->begin(LOG_LEVEL, &Serial, true);
|
EspSerial.println("Serial connection established");
|
||||||
|
EspSerial.setDebugOutput(true);
|
||||||
|
getLog()->begin(LOG_LEVEL, &EspSerial, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
bool checkPinConnected() {
|
||||||
// Read and calculate the battery voltage
|
#if defined(ESP8266)
|
||||||
//
|
pinMode(PIN_CFG1, INPUT);
|
||||||
|
#else
|
||||||
|
pinMode(PIN_CFG1, INPUT_PULLDOWN);
|
||||||
|
#endif
|
||||||
|
pinMode(PIN_CFG2, OUTPUT);
|
||||||
|
delay(5);
|
||||||
|
digitalWrite(PIN_CFG2, 1);
|
||||||
|
delay(5);
|
||||||
|
int i = digitalRead(PIN_CFG1);
|
||||||
|
digitalWrite(PIN_CFG2, 0);
|
||||||
|
return i == LOW ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatteryVoltage::BatteryVoltage() {
|
||||||
|
#if defined(ESP8266)
|
||||||
|
pinMode(PIN_VOLT, INPUT);
|
||||||
|
#else
|
||||||
|
pinMode(PIN_VOLT, 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)
|
||||||
float factor = myConfig.getVoltageFactor(); // Default value is 1.63
|
float factor = myConfig.getVoltageFactor(); // Default value is 1.63
|
||||||
int v = analogRead(PIN_A0);
|
int v = analogRead(PIN_VOLT);
|
||||||
|
|
||||||
// An ESP8266 has a ADC range of 0-1023 and a maximum voltage of 3.3V
|
// An ESP8266 has a ADC range of 0-1023 and a maximum voltage of 3.3V
|
||||||
// An ESP32 has an ADC range of 0-4095 and a maximum voltage of 3.3V
|
// An ESP32 has an ADC range of 0-4095 and a maximum voltage of 3.3V
|
||||||
@ -257,9 +319,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;
|
||||||
@ -276,17 +335,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);
|
||||||
|
|
||||||
@ -299,9 +352,6 @@ void PerfLogging::stop(const char* key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Print the collected performance data
|
|
||||||
//
|
|
||||||
void PerfLogging::print() {
|
void PerfLogging::print() {
|
||||||
PerfEntry* pe = first;
|
PerfEntry* pe = first;
|
||||||
|
|
||||||
@ -311,14 +361,13 @@ 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;
|
||||||
|
|
||||||
if (myConfig.isInfluxSSL()) {
|
if (myConfig.isInfluxSSL()) {
|
||||||
Log.warning(F("PERF: InfluxDB2 with SSL is not supported when pushing performance data, skipping" CR));
|
Log.warning(
|
||||||
|
F("PERF: InfluxDB2 with SSL is not supported when pushing performance "
|
||||||
|
"data, skipping" CR));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +441,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) {
|
||||||
@ -413,29 +462,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);
|
||||||
@ -479,9 +518,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());
|
||||||
|
@ -28,16 +28,24 @@ 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);
|
||||||
|
|
||||||
|
// Force config mode
|
||||||
|
bool checkPinConnected();
|
||||||
|
|
||||||
// Show build options
|
// Show build options
|
||||||
void printBuildOptions();
|
void printBuildOptions();
|
||||||
|
|
||||||
@ -67,16 +75,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 +91,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; }
|
||||||
};
|
};
|
||||||
|
103
src/main.cpp
@ -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>
|
||||||
@ -32,13 +34,15 @@ SOFTWARE.
|
|||||||
#include <webserver.hpp>
|
#include <webserver.hpp>
|
||||||
#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
|
||||||
@ -50,9 +54,6 @@ uint32_t stableGyroMillis; // Used to calculate the total time since last
|
|||||||
|
|
||||||
RunMode runMode = RunMode::gravityMode;
|
RunMode runMode = RunMode::gravityMode;
|
||||||
|
|
||||||
//
|
|
||||||
// Check if we should be in sleep mode
|
|
||||||
//
|
|
||||||
void checkSleepMode(float angle, float volt) {
|
void checkSleepMode(float angle, float volt) {
|
||||||
#if defined(SKIP_SLEEPMODE)
|
#if defined(SKIP_SLEEPMODE)
|
||||||
runMode = RunMode::configurationMode;
|
runMode = RunMode::configurationMode;
|
||||||
@ -83,8 +84,12 @@ void checkSleepMode(float angle, float volt) {
|
|||||||
Log.notice(F("MAIN: Sleep mode disabled from web interface." CR));
|
Log.notice(F("MAIN: Sleep mode disabled from web interface." CR));
|
||||||
#endif
|
#endif
|
||||||
runMode = RunMode::configurationMode;
|
runMode = RunMode::configurationMode;
|
||||||
} else if ((volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15)) {
|
} else if ((volt < myConfig.getVoltageConfig() &&
|
||||||
|
(angle > 85 && angle < 95)) ||
|
||||||
|
(volt > myConfig.getVoltageConfig())) {
|
||||||
runMode = RunMode::configurationMode;
|
runMode = RunMode::configurationMode;
|
||||||
|
} else if (angle < 5 && myConfig.isStorageSleep()) {
|
||||||
|
runMode = RunMode::storageMode;
|
||||||
} else {
|
} else {
|
||||||
runMode = RunMode::gravityMode;
|
runMode = RunMode::gravityMode;
|
||||||
}
|
}
|
||||||
@ -104,25 +109,30 @@ void checkSleepMode(float angle, float volt) {
|
|||||||
volt);
|
volt);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case RunMode::storageMode:
|
||||||
|
#if !defined(MAIN_DISABLE_LOGGING)
|
||||||
|
Log.notice(F("MAIN: run mode STORAGE (angle=%F)." CR), angle);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are in storage mode, just go back to sleep
|
||||||
|
if (runMode == RunMode::storageMode) {
|
||||||
|
Log.notice(
|
||||||
|
F("Main: Storage mode entered, going to sleep for maximum time." CR));
|
||||||
|
#if defined(ESP8266)
|
||||||
|
ESP.deepSleep(0); // indefinite sleep
|
||||||
|
#else
|
||||||
|
ESP.deepSleep(0); // indefinite sleep
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Setup
|
|
||||||
//
|
|
||||||
void setup() {
|
void setup() {
|
||||||
LOG_PERF_START("run-time");
|
LOG_PERF_START("run-time");
|
||||||
LOG_PERF_START("main-setup");
|
LOG_PERF_START("main-setup");
|
||||||
runtimeMillis = millis();
|
runtimeMillis = millis();
|
||||||
|
|
||||||
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
|
|
||||||
// Add a delay so that serial is started.
|
|
||||||
// delay(3000);
|
|
||||||
#if defined(ESP8266)
|
|
||||||
Log.verbose(F("Main: Reset reason %s." CR), ESP.getResetInfo().c_str());
|
|
||||||
#else // defined (ESP32)
|
|
||||||
#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),
|
||||||
@ -142,11 +152,17 @@ 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();
|
||||||
LOG_PERF_STOP("main-config-load");
|
LOG_PERF_STOP("main-config-load");
|
||||||
|
|
||||||
|
sleepModeAlwaysSkip = checkPinConnected();
|
||||||
|
if (sleepModeAlwaysSkip) {
|
||||||
|
Log.notice(F("Main: Forcing config mode since D7/D8 are connected." CR));
|
||||||
|
}
|
||||||
|
|
||||||
// Setup watchdog
|
// Setup watchdog
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
ESP.wdtDisable();
|
ESP.wdtDisable();
|
||||||
@ -177,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) {
|
||||||
@ -238,11 +256,8 @@ void setup() {
|
|||||||
millis(); // Dont include time for wifi connection
|
millis(); // Dont include time for wifi connection
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Main loop that does gravity readings and push data to targets
|
// Main loop that does gravity readings and push data to targets
|
||||||
//
|
|
||||||
// Return true if gravity reading was successful
|
// Return true if gravity reading was successful
|
||||||
//
|
|
||||||
bool loopReadGravity() {
|
bool loopReadGravity() {
|
||||||
float angle = 0;
|
float angle = 0;
|
||||||
|
|
||||||
@ -264,7 +279,12 @@ bool loopReadGravity() {
|
|||||||
LOG_PERF_STOP("loop-temp-read");
|
LOG_PERF_STOP("loop-temp-read");
|
||||||
|
|
||||||
float gravitySG = calculateGravity(angle, tempC);
|
float gravitySG = calculateGravity(angle, tempC);
|
||||||
float corrGravitySG = gravityTemperatureCorrectionC(gravitySG, tempC);
|
float corrGravitySG = gravityTemperatureCorrectionC(
|
||||||
|
gravitySG, tempC, myAdvancedConfig.getDefaultCalibrationTemp());
|
||||||
|
|
||||||
|
if (myConfig.isGravityTempAdj()) {
|
||||||
|
gravitySG = corrGravitySG;
|
||||||
|
}
|
||||||
|
|
||||||
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
|
||||||
Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%FC, gravity=%F, "
|
Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%FC, gravity=%F, "
|
||||||
@ -275,17 +295,25 @@ bool loopReadGravity() {
|
|||||||
bool pushExpired = (abs((int32_t)(millis() - pushMillis)) >
|
bool pushExpired = (abs((int32_t)(millis() - pushMillis)) >
|
||||||
(myConfig.getSleepInterval() * 1000));
|
(myConfig.getSleepInterval() * 1000));
|
||||||
|
|
||||||
|
if (myAdvancedConfig.isIgnoreLowAnges() &&
|
||||||
|
(angle < myConfig.getFormulaData().a[0])) {
|
||||||
|
Log.warning(
|
||||||
|
F("Main: Angle is lower than water, so we regard this as faulty and "
|
||||||
|
"dont send any data." CR));
|
||||||
|
pushExpired = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (pushExpired || runMode == RunMode::gravityMode) {
|
if (pushExpired || runMode == RunMode::gravityMode) {
|
||||||
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.
|
||||||
@ -303,15 +331,14 @@ bool loopReadGravity() {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Log.error(F("MAIN: No gyro value found, the device might be moving." CR));
|
// Log.error(F("MAIN: No gyro value found, the device might be moving."
|
||||||
|
// CR));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Wrapper for loopGravity that only calls every 200ms so that we dont overload
|
// Wrapper for loopGravity that only calls every 200ms so that we dont overload
|
||||||
// this.
|
// this.
|
||||||
//
|
|
||||||
void loopGravityOnInterval() {
|
void loopGravityOnInterval() {
|
||||||
if (abs((int32_t)(millis() - loopMillis)) > interval) {
|
if (abs((int32_t)(millis() - loopMillis)) > interval) {
|
||||||
loopReadGravity();
|
loopReadGravity();
|
||||||
@ -327,9 +354,6 @@ void loopGravityOnInterval() {
|
|||||||
|
|
||||||
bool skipRunTimeLog = false;
|
bool skipRunTimeLog = false;
|
||||||
|
|
||||||
//
|
|
||||||
// Main loop that determines if device should go to sleep
|
|
||||||
//
|
|
||||||
void goToSleep(int sleepInterval) {
|
void goToSleep(int sleepInterval) {
|
||||||
float volt = myBatteryVoltage.getVoltage();
|
float volt = myBatteryVoltage.getVoltage();
|
||||||
float runtime = (millis() - runtimeMillis);
|
float runtime = (millis() - runtimeMillis);
|
||||||
@ -350,16 +374,17 @@ void goToSleep(int sleepInterval) {
|
|||||||
deepSleep(sleepInterval);
|
deepSleep(sleepInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Main loops
|
|
||||||
//
|
|
||||||
void loop() {
|
void loop() {
|
||||||
switch (runMode) {
|
switch (runMode) {
|
||||||
case RunMode::configurationMode:
|
case RunMode::storageMode:
|
||||||
if (myWifi.isConnected()) myWebServerHandler.loop();
|
// This point is never reached, just here to remove warning.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RunMode::configurationMode:
|
||||||
|
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;
|
||||||
|
108
src/main.hpp
@ -29,35 +29,113 @@ SOFTWARE.
|
|||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
enum RunMode { gravityMode = 0, configurationMode = 1, wifiSetupMode = 2 };
|
enum RunMode {
|
||||||
|
gravityMode = 0,
|
||||||
|
configurationMode = 1,
|
||||||
|
wifiSetupMode = 2,
|
||||||
|
storageMode = 3
|
||||||
|
};
|
||||||
extern RunMode runMode;
|
extern RunMode runMode;
|
||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
|
// Hardware config for ESP8266-d1, iSpindel hardware
|
||||||
|
// ------------------------------------------------------
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#define ESP_RESET ESP.reset
|
#define ESP_RESET ESP.reset
|
||||||
#define PIN_SDA D3
|
#define PIN_SDA D3
|
||||||
#define PIN_SCL D4
|
#define PIN_SCL D4
|
||||||
|
#define PIN_CFG1 D8
|
||||||
|
#define PIN_CFG2 D7
|
||||||
#define PIN_DS D6
|
#define PIN_DS D6
|
||||||
#define PIN_LED 2
|
#define PIN_LED 2
|
||||||
// #define PIN_A0 A0
|
#define PIN_VOLT PIN_A0
|
||||||
#else // defined (ESP32)
|
#elif defined(ESP32C3)
|
||||||
#if defined(ESPRESSIF32_20)
|
// Hardware config for ESP32-c3-mini, iSpindel hardware
|
||||||
#include <LittleFS.h>
|
// ------------------------------------------------------
|
||||||
#else
|
|
||||||
#include <LITTLEFS.h>
|
|
||||||
#define LittleFS LITTLEFS
|
|
||||||
#endif
|
|
||||||
#include <FS.h>
|
#include <FS.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 // JTAG_DEBUG
|
||||||
|
#define PIN_CFG1 A5
|
||||||
|
#define PIN_CFG2 A4
|
||||||
|
#define PIN_DS A3
|
||||||
|
#define PIN_VOLT 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)
|
||||||
|
// Hardware config for ESP32-s2-mini, iSpindel hardware
|
||||||
|
// ------------------------------------------------------
|
||||||
|
#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 A17
|
||||||
|
#define PIN_SCL A15
|
||||||
|
#define PIN_CFG1 A11
|
||||||
|
#define PIN_CFG2 A10
|
||||||
|
#define PIN_DS A8
|
||||||
|
#define PIN_VOLT A2
|
||||||
|
#define PIN_LED LED_BUILTIN
|
||||||
|
#elif defined(ESP32LITE)
|
||||||
|
// Hardware config for ESP32-lite, Floaty hardware
|
||||||
|
// ------------------------------------------------------
|
||||||
|
#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 A17
|
||||||
|
#define PIN_SCL A19
|
||||||
|
#define PIN_DS A3
|
||||||
|
#define PIN_VOLT A7
|
||||||
|
#define PIN_CFG1 A14
|
||||||
|
#define PIN_CFG2 A13
|
||||||
|
#define PIN_VCC A5
|
||||||
|
#define PIN_GND A18
|
||||||
|
#define PIN_LED LED_BUILTIN
|
||||||
|
#else // defined (ESP32)
|
||||||
|
// Hardware config for ESP32-d1-min, iSpindel hardware
|
||||||
|
// ------------------------------------------------------
|
||||||
|
#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_CFG1 D8
|
||||||
|
#define PIN_CFG2 D7
|
||||||
|
#define PIN_LED LED_BUILTIN
|
||||||
|
#define PIN_VOLT PIN_A0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PIN_LED 2
|
#if defined(USE_SERIAL_PINS) && (defined(ESP32C3) || defined(ESP32S2))
|
||||||
|
// #define EspSerial Serial0 // We cant use Serial on newer boards since this is
|
||||||
|
// using USBC port
|
||||||
|
#define EspSerial \
|
||||||
|
Serial0 // We cant use Serial on newer boards since this is using USBC port
|
||||||
|
#else
|
||||||
|
#define EspSerial Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // SRC_MAIN_HPP_
|
#endif // SRC_MAIN_HPP_
|
||||||
|
@ -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");
|
||||||
|
|
||||||
@ -108,8 +102,8 @@ void PushIntervalTracker::save() {
|
|||||||
void PushTarget::sendAll(float angle, float gravitySG, float corrGravitySG,
|
void PushTarget::sendAll(float angle, float gravitySG, float corrGravitySG,
|
||||||
float tempC, float runTime) {
|
float tempC, float runTime) {
|
||||||
printHeap("PUSH");
|
printHeap("PUSH");
|
||||||
_http.setReuse(false);
|
_http.setReuse(true);
|
||||||
_httpSecure.setReuse(false);
|
_httpSecure.setReuse(true);
|
||||||
|
|
||||||
TemplatingEngine engine;
|
TemplatingEngine engine;
|
||||||
engine.initialize(angle, gravitySG, corrGravitySG, tempC, runTime);
|
engine.initialize(angle, gravitySG, corrGravitySG, tempC, runTime);
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,9 +199,11 @@ void PushTarget::sendInfluxDb2(TemplatingEngine& engine, bool isSecure) {
|
|||||||
String auth = "Token " + String(myConfig.getInfluxDb2PushToken());
|
String auth = "Token " + String(myConfig.getInfluxDb2PushToken());
|
||||||
|
|
||||||
if (isSecure) {
|
if (isSecure) {
|
||||||
#if defined( ESP8266 )
|
#if defined(ESP8266)
|
||||||
if (runMode == RunMode::configurationMode) {
|
if (runMode == RunMode::configurationMode) {
|
||||||
Log.notice(F("PUSH: Skipping InfluxDB since SSL is enabled and we are in config mode." CR));
|
Log.notice(
|
||||||
|
F("PUSH: Skipping InfluxDB since SSL is enabled and we are in config "
|
||||||
|
"mode." CR));
|
||||||
_lastCode = -100;
|
_lastCode = -100;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -218,7 +215,6 @@ void PushTarget::sendInfluxDb2(TemplatingEngine& engine, bool isSecure) {
|
|||||||
_httpSecure.setTimeout(myAdvancedConfig.getPushTimeout() * 1000);
|
_httpSecure.setTimeout(myAdvancedConfig.getPushTimeout() * 1000);
|
||||||
_httpSecure.begin(_wifiSecure, serverPath);
|
_httpSecure.begin(_wifiSecure, serverPath);
|
||||||
_httpSecure.addHeader(F("Authorization"), auth.c_str());
|
_httpSecure.addHeader(F("Authorization"), auth.c_str());
|
||||||
_httpSecure.setReuse(true);
|
|
||||||
_lastCode = _httpSecure.POST(doc);
|
_lastCode = _httpSecure.POST(doc);
|
||||||
} else {
|
} else {
|
||||||
_http.setTimeout(myAdvancedConfig.getPushTimeout() * 1000);
|
_http.setTimeout(myAdvancedConfig.getPushTimeout() * 1000);
|
||||||
@ -231,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) {
|
||||||
@ -260,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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,9 +288,11 @@ void PushTarget::sendHttpPost(TemplatingEngine& engine, bool isSecure,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (isSecure) {
|
if (isSecure) {
|
||||||
#if defined( ESP8266 )
|
#if defined(ESP8266)
|
||||||
if (runMode == RunMode::configurationMode) {
|
if (runMode == RunMode::configurationMode) {
|
||||||
Log.notice(F("PUSH: Skipping HTTP since SSL is enabled and we are in config mode." CR));
|
Log.notice(
|
||||||
|
F("PUSH: Skipping HTTP since SSL is enabled and we are in config "
|
||||||
|
"mode." CR));
|
||||||
_lastCode = -100;
|
_lastCode = -100;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -335,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) {
|
||||||
@ -370,9 +366,11 @@ void PushTarget::sendHttpGet(TemplatingEngine& engine, bool isSecure) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (isSecure) {
|
if (isSecure) {
|
||||||
#if defined( ESP8266 )
|
#if defined(ESP8266)
|
||||||
if (runMode == RunMode::configurationMode) {
|
if (runMode == RunMode::configurationMode) {
|
||||||
Log.notice(F("PUSH: Skipping HTTP since SSL is enabled and we are in config mode." CR));
|
Log.notice(
|
||||||
|
F("PUSH: Skipping HTTP since SSL is enabled and we are in config "
|
||||||
|
"mode." CR));
|
||||||
_lastCode = -100;
|
_lastCode = -100;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -394,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) {
|
||||||
@ -411,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;
|
||||||
@ -424,9 +423,11 @@ void PushTarget::sendMqtt(TemplatingEngine& engine, bool isSecure) {
|
|||||||
int port = myConfig.getMqttPort();
|
int port = myConfig.getMqttPort();
|
||||||
|
|
||||||
if (myConfig.isMqttSSL()) {
|
if (myConfig.isMqttSSL()) {
|
||||||
#if defined( ESP8266 )
|
#if defined(ESP8266)
|
||||||
if (runMode == RunMode::configurationMode) {
|
if (runMode == RunMode::configurationMode) {
|
||||||
Log.notice(F("PUSH: Skipping MQTT since SSL is enabled and we are in config mode." CR));
|
Log.notice(
|
||||||
|
F("PUSH: Skipping MQTT since SSL is enabled and we are in config "
|
||||||
|
"mode." CR));
|
||||||
_lastCode = -100;
|
_lastCode = -100;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -476,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;
|
||||||
|
@ -45,7 +45,7 @@ class PushTarget {
|
|||||||
void sendHttpPost(TemplatingEngine& engine, bool isSecure, int index);
|
void sendHttpPost(TemplatingEngine& engine, bool isSecure, int index);
|
||||||
void sendHttpGet(TemplatingEngine& engine, bool isSecure);
|
void sendHttpGet(TemplatingEngine& engine, bool isSecure);
|
||||||
void addHttpHeader(HTTPClient& http, String header);
|
void addHttpHeader(HTTPClient& http, String header);
|
||||||
void probeMaxFragement( String& serverPath );
|
void probeMaxFragement(String& serverPath);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void sendAll(float angle, float gravitySG, float corrGravitySG, float tempC,
|
void sendAll(float angle, float gravitySG, float corrGravitySG, float tempC,
|
||||||
@ -61,14 +61,15 @@ 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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class PushIntervalTracker {
|
class PushIntervalTracker {
|
||||||
private:
|
private:
|
||||||
int _counters[5] = { 0, 0, 0, 0, 0 };
|
int _counters[5] = {0, 0, 0, 0, 0};
|
||||||
void update(const int index, const int defaultValue);
|
void update(const int index, const int defaultValue);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -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
|
||||||
|
@ -53,13 +53,15 @@ SOFTWARE.
|
|||||||
#define PARAM_PUSH_MQTT_PORT "mqtt-port"
|
#define PARAM_PUSH_MQTT_PORT "mqtt-port"
|
||||||
#define PARAM_SLEEP_INTERVAL "sleep-interval"
|
#define PARAM_SLEEP_INTERVAL "sleep-interval"
|
||||||
#define PARAM_TEMPFORMAT "temp-format"
|
#define PARAM_TEMPFORMAT "temp-format"
|
||||||
#define PARAM_VOLTAGEFACTOR "voltage-factor"
|
#define PARAM_VOLTAGE_FACTOR "voltage-factor"
|
||||||
|
#define PARAM_VOLTAGE_CONFIG "voltage-config"
|
||||||
#define PARAM_GRAVITY_FORMULA "gravity-formula"
|
#define PARAM_GRAVITY_FORMULA "gravity-formula"
|
||||||
#define PARAM_GRAVITY_FORMAT "gravity-format"
|
#define PARAM_GRAVITY_FORMAT "gravity-format"
|
||||||
#define PARAM_GRAVITY_TEMP_ADJ "gravity-temp-adjustment"
|
#define PARAM_GRAVITY_TEMP_ADJ "gravity-temp-adjustment"
|
||||||
#define PARAM_TEMP_ADJ "temp-adjustment-value"
|
#define PARAM_TEMP_ADJ "temp-adjustment-value"
|
||||||
#define PARAM_GYRO_CALIBRATION "gyro-calibration-data"
|
#define PARAM_GYRO_CALIBRATION "gyro-calibration-data"
|
||||||
#define PARAM_GYRO_TEMP "gyro-temp"
|
#define PARAM_GYRO_TEMP "gyro-temp"
|
||||||
|
#define PARAM_STORAGE_SLEEP "storage-sleep"
|
||||||
#define PARAM_FORMULA_DATA "formula-calculation-data"
|
#define PARAM_FORMULA_DATA "formula-calculation-data"
|
||||||
#define PARAM_FILES "files"
|
#define PARAM_FILES "files"
|
||||||
#define PARAM_FILE_NAME "file-name"
|
#define PARAM_FILE_NAME "file-name"
|
||||||
@ -90,6 +92,7 @@ SOFTWARE.
|
|||||||
#define PARAM_HW_PUSH_INTERVAL_HTTP3 "int-http3"
|
#define PARAM_HW_PUSH_INTERVAL_HTTP3 "int-http3"
|
||||||
#define PARAM_HW_PUSH_INTERVAL_INFLUX "int-influx"
|
#define PARAM_HW_PUSH_INTERVAL_INFLUX "int-influx"
|
||||||
#define PARAM_HW_PUSH_INTERVAL_MQTT "int-mqtt"
|
#define PARAM_HW_PUSH_INTERVAL_MQTT "int-mqtt"
|
||||||
|
#define PARAM_HW_IGNORE_LOW_ANGLES "ignore-low-angles"
|
||||||
#define PARAM_FORMAT_HTTP1 "http-1"
|
#define PARAM_FORMAT_HTTP1 "http-1"
|
||||||
#define PARAM_FORMAT_HTTP2 "http-2"
|
#define PARAM_FORMAT_HTTP2 "http-2"
|
||||||
#define PARAM_FORMAT_HTTP3 "http-3"
|
#define PARAM_FORMAT_HTTP3 "http-3"
|
||||||
|
@ -80,9 +80,6 @@ const char mqttFormat[] PROGMEM =
|
|||||||
"ispindel/${mdns}/interval:${sleep-interval}|"
|
"ispindel/${mdns}/interval:${sleep-interval}|"
|
||||||
"ispindel/${mdns}/RSSI:${rssi}|";
|
"ispindel/${mdns}/RSSI:${rssi}|";
|
||||||
|
|
||||||
//
|
|
||||||
// Initialize the variables
|
|
||||||
//
|
|
||||||
void TemplatingEngine::initialize(float angle, float gravitySG,
|
void TemplatingEngine::initialize(float angle, float gravitySG,
|
||||||
float corrGravitySG, float tempC,
|
float corrGravitySG, float tempC,
|
||||||
float runTime) {
|
float runTime) {
|
||||||
@ -130,51 +127,54 @@ void TemplatingEngine::initialize(float angle, float gravitySG,
|
|||||||
setVal(TPL_GRAVITY_CORR_P, convertToPlato(corrGravitySG), 1);
|
setVal(TPL_GRAVITY_CORR_P, convertToPlato(corrGravitySG), 1);
|
||||||
setVal(TPL_GRAVITY_UNIT, myConfig.getGravityFormat());
|
setVal(TPL_GRAVITY_UNIT, myConfig.getGravityFormat());
|
||||||
|
|
||||||
|
setVal(TPL_APP_VER, CFG_APPVER);
|
||||||
|
setVal(TPL_APP_BUILD, CFG_GITREV);
|
||||||
|
|
||||||
#if LOG_LEVEL == 6
|
#if LOG_LEVEL == 6
|
||||||
// dumpAll();
|
// dumpAll();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// the useDefaultTemplate param is there to support unit tests.
|
||||||
// Create the data using defined template.
|
const char* TemplatingEngine::create(TemplatingEngine::Templates idx,
|
||||||
//
|
bool useDefaultTemplate) {
|
||||||
const String& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add code to load templates from disk if they exist.
|
if (!useDefaultTemplate) {
|
||||||
File file = LittleFS.open(fname, "r");
|
File file = LittleFS.open(fname, "r");
|
||||||
if (file) {
|
if (file) {
|
||||||
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LOG_LEVEL == 6
|
#if LOG_LEVEL == 6
|
||||||
@ -182,13 +182,29 @@ 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 "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// added to support more unit test scenarios.
|
||||||
|
const char* TemplatingEngine::create(const char* formatTemplate) {
|
||||||
|
_baseTemplate = String(formatTemplate);
|
||||||
|
|
||||||
|
// Insert data into template.
|
||||||
|
transform();
|
||||||
|
_baseTemplate.clear();
|
||||||
|
|
||||||
|
if (_output) return _output;
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
@ -53,6 +53,8 @@ SOFTWARE.
|
|||||||
#define TPL_GRAVITY_CORR_G "${corr-gravity-sg}"
|
#define TPL_GRAVITY_CORR_G "${corr-gravity-sg}"
|
||||||
#define TPL_GRAVITY_CORR_P "${corr-gravity-plato}"
|
#define TPL_GRAVITY_CORR_P "${corr-gravity-plato}"
|
||||||
#define TPL_GRAVITY_UNIT "${gravity-unit}" // G or P
|
#define TPL_GRAVITY_UNIT "${gravity-unit}" // G or P
|
||||||
|
#define TPL_APP_VER "${app-ver}"
|
||||||
|
#define TPL_APP_BUILD "${app-build}"
|
||||||
|
|
||||||
#define TPL_FNAME_HTTP1 "/http-1.tpl"
|
#define TPL_FNAME_HTTP1 "/http-1.tpl"
|
||||||
#define TPL_FNAME_HTTP2 "/http-2.tpl"
|
#define TPL_FNAME_HTTP2 "/http-2.tpl"
|
||||||
@ -73,33 +75,35 @@ class TemplatingEngine {
|
|||||||
String val;
|
String val;
|
||||||
};
|
};
|
||||||
|
|
||||||
KeyVal items[21] = {{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_TOKEN2, ""}, {TPL_APP_VER, ""},
|
||||||
|
{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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,22 +111,75 @@ 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);
|
||||||
|
strncat(_output, format + k, strlen(format + 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("\'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,9 +192,18 @@ 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,
|
||||||
|
bool useDefaultTemplate = false);
|
||||||
|
const char *create(const char *formatTemplate);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SRC_TEMPLATING_HPP_
|
#endif // SRC_TEMPLATING_HPP_
|
||||||
|
@ -35,15 +35,7 @@ DallasTemperature mySensors(&myOneWire);
|
|||||||
|
|
||||||
TempSensor myTempSensor;
|
TempSensor myTempSensor;
|
||||||
|
|
||||||
//
|
|
||||||
// Setup DS18B20 temp sensor. Doing setup is not that time consuming.
|
|
||||||
//
|
|
||||||
void TempSensor::setup() {
|
void TempSensor::setup() {
|
||||||
#if defined(SIMULATE_TEMP)
|
|
||||||
hasSensors = true;
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LOG_LEVEL == 6 && !defined(TSEN_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(TSEN_DISABLE_LOGGING)
|
||||||
Log.verbose(F("TSEN: Looking for temp sensors." CR));
|
Log.verbose(F("TSEN: Looking for temp sensors." CR));
|
||||||
#endif
|
#endif
|
||||||
@ -51,10 +43,10 @@ void TempSensor::setup() {
|
|||||||
|
|
||||||
if (mySensors.getDS18Count()) {
|
if (mySensors.getDS18Count()) {
|
||||||
#if !defined(TSEN_DISABLE_LOGGING)
|
#if !defined(TSEN_DISABLE_LOGGING)
|
||||||
Log.notice(F("TSEN: Found %d temperature sensor(s). Using %d resolution" CR),
|
Log.notice(
|
||||||
mySensors.getDS18Count(), myAdvancedConfig.getTempSensorResolution());
|
F("TSEN: Found %d temperature sensor(s). Using %d resolution" CR),
|
||||||
|
mySensors.getDS18Count(), myAdvancedConfig.getTempSensorResolution());
|
||||||
#endif
|
#endif
|
||||||
mySensors.setResolution(myAdvancedConfig.getTempSensorResolution());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the temp sensor adjustment values
|
// Set the temp sensor adjustment values
|
||||||
@ -66,14 +58,7 @@ void TempSensor::setup() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Retrieving value from sensor, value is in Celcius
|
|
||||||
//
|
|
||||||
float TempSensor::getValue(bool useGyro) {
|
float TempSensor::getValue(bool useGyro) {
|
||||||
#if defined(SIMULATE_TEMP)
|
|
||||||
return 21;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (useGyro) {
|
if (useGyro) {
|
||||||
// When using the gyro temperature only the first read value will be
|
// When using the gyro temperature only the first read value will be
|
||||||
// accurate so we will use this for processing.
|
// accurate so we will use this for processing.
|
||||||
@ -94,6 +79,7 @@ float TempSensor::getValue(bool useGyro) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the sensors
|
// Read the sensors
|
||||||
|
mySensors.setResolution(myAdvancedConfig.getTempSensorResolution());
|
||||||
mySensors.requestTemperatures();
|
mySensors.requestTemperatures();
|
||||||
|
|
||||||
float c = 0;
|
float c = 0;
|
||||||
|
@ -37,17 +37,18 @@ 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));
|
||||||
|
|
||||||
DynamicJsonDocument doc(CFG_JSON_BUFSIZE);
|
DynamicJsonDocument doc(2000);
|
||||||
myConfig.createJson(doc);
|
myConfig.createJson(doc);
|
||||||
|
|
||||||
doc[PARAM_PASS] = ""; // dont show the wifi password
|
doc[PARAM_PASS] = ""; // dont show the wifi password
|
||||||
|
doc[PARAM_PASS2] = "";
|
||||||
|
|
||||||
|
doc[PARAM_APP_VER] = String(CFG_APPVER);
|
||||||
|
doc[PARAM_APP_BUILD] = String(CFG_GITREV);
|
||||||
|
|
||||||
double angle = 0;
|
double angle = 0;
|
||||||
|
|
||||||
@ -68,8 +69,8 @@ void WebServerHandler::webHandleConfig() {
|
|||||||
doc[PARAM_TEMP_ADJ] = reduceFloatPrecision(myConfig.getTempSensorAdjC(), 1);
|
doc[PARAM_TEMP_ADJ] = reduceFloatPrecision(myConfig.getTempSensorAdjC(), 1);
|
||||||
|
|
||||||
if (myConfig.isGravityTempAdj()) {
|
if (myConfig.isGravityTempAdj()) {
|
||||||
gravity =
|
gravity = gravityTemperatureCorrectionC(
|
||||||
gravityTemperatureCorrectionC(gravity, tempC, myConfig.getTempFormat());
|
gravity, tempC, myAdvancedConfig.getDefaultCalibrationTemp());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myConfig.isGravityPlato()) {
|
if (myConfig.isGravityPlato()) {
|
||||||
@ -86,194 +87,87 @@ 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] = "esp32s2";
|
||||||
|
#elif defined(ESP32LITE)
|
||||||
|
doc[PARAM_PLATFORM] = "esp32lite";
|
||||||
|
#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;
|
||||||
out.reserve(CFG_JSON_BUFSIZE);
|
out.reserve(2000);
|
||||||
serializeJson(doc, out);
|
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");
|
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);
|
|
||||||
_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);
|
||||||
@ -291,9 +185,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));
|
||||||
@ -310,6 +201,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 {
|
||||||
@ -317,16 +209,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(512);
|
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();
|
||||||
|
|
||||||
@ -334,9 +237,13 @@ 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, tempC);
|
gravity = gravityTemperatureCorrectionC(
|
||||||
|
gravity, tempC, myAdvancedConfig.getDefaultCalibrationTemp());
|
||||||
}
|
}
|
||||||
if (myConfig.isGravityPlato()) {
|
if (myConfig.isGravityPlato()) {
|
||||||
doc[PARAM_GRAVITY] = reduceFloatPrecision(convertToPlato(gravity), 1);
|
doc[PARAM_GRAVITY] = reduceFloatPrecision(convertToPlato(gravity), 1);
|
||||||
@ -365,25 +272,29 @@ 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] = "esp32s2";
|
||||||
|
#elif defined(ESP32LITE)
|
||||||
|
doc[PARAM_PLATFORM] = "esp32lite";
|
||||||
|
#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;
|
||||||
out.reserve(300);
|
out.reserve(500);
|
||||||
serializeJson(doc, out);
|
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-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));
|
||||||
@ -404,9 +315,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);
|
||||||
@ -432,9 +340,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);
|
||||||
@ -464,9 +369,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);
|
||||||
@ -528,9 +430,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;
|
||||||
|
|
||||||
@ -547,9 +446,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);
|
||||||
@ -575,15 +471,15 @@ void WebServerHandler::webHandleConfigGravity() {
|
|||||||
myConfig.setGravityTempAdj(
|
myConfig.setGravityTempAdj(
|
||||||
_server->arg(PARAM_GRAVITY_TEMP_ADJ).equalsIgnoreCase("on") ? true
|
_server->arg(PARAM_GRAVITY_TEMP_ADJ).equalsIgnoreCase("on") ? true
|
||||||
: false);
|
: false);
|
||||||
|
else
|
||||||
|
myConfig.setGravityTempAdj(false);
|
||||||
|
|
||||||
myConfig.saveFile();
|
myConfig.saveFile();
|
||||||
_server->sendHeader("Location", "/config.htm#collapseGravity", true);
|
_server->sendHeader("Location", "/config.htm#collapseGravity", true);
|
||||||
_server->send(302, "text/plain", "Gravity config updated");
|
_server->send(302, "text/plain", "Gravity config updated");
|
||||||
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);
|
||||||
@ -601,8 +497,10 @@ void WebServerHandler::webHandleConfigHardware() {
|
|||||||
Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
|
Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_server->hasArg(PARAM_VOLTAGEFACTOR))
|
if (_server->hasArg(PARAM_VOLTAGE_FACTOR))
|
||||||
myConfig.setVoltageFactor(_server->arg(PARAM_VOLTAGEFACTOR).toFloat());
|
myConfig.setVoltageFactor(_server->arg(PARAM_VOLTAGE_FACTOR).toFloat());
|
||||||
|
if (_server->hasArg(PARAM_VOLTAGE_CONFIG))
|
||||||
|
myConfig.setVoltageConfig(_server->arg(PARAM_VOLTAGE_CONFIG).toFloat());
|
||||||
if (_server->hasArg(PARAM_TEMP_ADJ)) {
|
if (_server->hasArg(PARAM_TEMP_ADJ)) {
|
||||||
if (myConfig.isTempC()) {
|
if (myConfig.isTempC()) {
|
||||||
myConfig.setTempSensorAdjC(_server->arg(PARAM_TEMP_ADJ));
|
myConfig.setTempSensorAdjC(_server->arg(PARAM_TEMP_ADJ));
|
||||||
@ -618,15 +516,21 @@ void WebServerHandler::webHandleConfigHardware() {
|
|||||||
if (_server->hasArg(PARAM_GYRO_TEMP))
|
if (_server->hasArg(PARAM_GYRO_TEMP))
|
||||||
myConfig.setGyroTemp(
|
myConfig.setGyroTemp(
|
||||||
_server->arg(PARAM_GYRO_TEMP).equalsIgnoreCase("on") ? true : false);
|
_server->arg(PARAM_GYRO_TEMP).equalsIgnoreCase("on") ? true : false);
|
||||||
|
else
|
||||||
|
myConfig.setGyroTemp(false);
|
||||||
|
if (_server->hasArg(PARAM_STORAGE_SLEEP))
|
||||||
|
myConfig.setStorageSleep(
|
||||||
|
_server->arg(PARAM_STORAGE_SLEEP).equalsIgnoreCase("on") ? true
|
||||||
|
: false);
|
||||||
|
else
|
||||||
|
myConfig.setStorageSleep(false);
|
||||||
|
|
||||||
myConfig.saveFile();
|
myConfig.saveFile();
|
||||||
_server->sendHeader("Location", "/config.htm#collapseHardware", true);
|
_server->sendHeader("Location", "/config.htm#collapseHardware", true);
|
||||||
_server->send(302, "text/plain", "Hardware config updated");
|
_server->send(302, "text/plain", "Hardware config updated");
|
||||||
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);
|
||||||
@ -656,9 +560,11 @@ void WebServerHandler::webHandleConfigAdvancedWrite() {
|
|||||||
if (_server->hasArg(PARAM_HW_FORMULA_DEVIATION))
|
if (_server->hasArg(PARAM_HW_FORMULA_DEVIATION))
|
||||||
myAdvancedConfig.setMaxFormulaCreationDeviation(
|
myAdvancedConfig.setMaxFormulaCreationDeviation(
|
||||||
_server->arg(PARAM_HW_FORMULA_DEVIATION).toFloat());
|
_server->arg(PARAM_HW_FORMULA_DEVIATION).toFloat());
|
||||||
if (_server->hasArg(PARAM_HW_FORMULA_CALIBRATION_TEMP))
|
if (_server->hasArg(PARAM_HW_FORMULA_CALIBRATION_TEMP)) {
|
||||||
myAdvancedConfig.SetDefaultCalibrationTemp(
|
float t = _server->arg(PARAM_HW_FORMULA_CALIBRATION_TEMP).toFloat();
|
||||||
_server->arg(PARAM_HW_FORMULA_CALIBRATION_TEMP).toFloat());
|
if (myConfig.isTempF()) t = convertFtoC(t);
|
||||||
|
myAdvancedConfig.SetDefaultCalibrationTemp(t);
|
||||||
|
}
|
||||||
if (_server->hasArg(PARAM_HW_WIFI_PORTAL_TIMEOUT))
|
if (_server->hasArg(PARAM_HW_WIFI_PORTAL_TIMEOUT))
|
||||||
myAdvancedConfig.setWifiPortalTimeout(
|
myAdvancedConfig.setWifiPortalTimeout(
|
||||||
_server->arg(PARAM_HW_WIFI_PORTAL_TIMEOUT).toInt());
|
_server->arg(PARAM_HW_WIFI_PORTAL_TIMEOUT).toInt());
|
||||||
@ -686,6 +592,13 @@ void WebServerHandler::webHandleConfigAdvancedWrite() {
|
|||||||
if (_server->hasArg(PARAM_HW_TEMPSENSOR_RESOLUTION))
|
if (_server->hasArg(PARAM_HW_TEMPSENSOR_RESOLUTION))
|
||||||
myAdvancedConfig.setTempSensorResolution(
|
myAdvancedConfig.setTempSensorResolution(
|
||||||
_server->arg(PARAM_HW_TEMPSENSOR_RESOLUTION).toInt());
|
_server->arg(PARAM_HW_TEMPSENSOR_RESOLUTION).toInt());
|
||||||
|
if (_server->hasArg(PARAM_HW_IGNORE_LOW_ANGLES))
|
||||||
|
myAdvancedConfig.setIgnoreLowAnges(
|
||||||
|
_server->arg(PARAM_HW_IGNORE_LOW_ANGLES).equalsIgnoreCase("on")
|
||||||
|
? true
|
||||||
|
: false);
|
||||||
|
else
|
||||||
|
myAdvancedConfig.setIgnoreLowAnges(false);
|
||||||
|
|
||||||
myAdvancedConfig.saveFile();
|
myAdvancedConfig.saveFile();
|
||||||
_server->sendHeader("Location", "/config.htm#collapseAdvanced", true);
|
_server->sendHeader("Location", "/config.htm#collapseAdvanced", true);
|
||||||
@ -693,14 +606,11 @@ 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));
|
||||||
|
|
||||||
DynamicJsonDocument doc(512);
|
DynamicJsonDocument doc(500);
|
||||||
|
|
||||||
doc[PARAM_HW_GYRO_READ_COUNT] = myAdvancedConfig.getGyroReadCount();
|
doc[PARAM_HW_GYRO_READ_COUNT] = myAdvancedConfig.getGyroReadCount();
|
||||||
// doc[PARAM_HW_GYRO_READ_DELAY] = myAdvancedConfig.getGyroReadDelay();
|
// doc[PARAM_HW_GYRO_READ_DELAY] = myAdvancedConfig.getGyroReadDelay();
|
||||||
@ -711,8 +621,9 @@ void WebServerHandler::webHandleConfigAdvancedRead() {
|
|||||||
doc[PARAM_HW_WIFI_PORTAL_TIMEOUT] = myAdvancedConfig.getWifiPortalTimeout();
|
doc[PARAM_HW_WIFI_PORTAL_TIMEOUT] = myAdvancedConfig.getWifiPortalTimeout();
|
||||||
doc[PARAM_HW_WIFI_CONNECT_TIMEOUT] = myAdvancedConfig.getWifiConnectTimeout();
|
doc[PARAM_HW_WIFI_CONNECT_TIMEOUT] = myAdvancedConfig.getWifiConnectTimeout();
|
||||||
doc[PARAM_HW_PUSH_TIMEOUT] = myAdvancedConfig.getPushTimeout();
|
doc[PARAM_HW_PUSH_TIMEOUT] = myAdvancedConfig.getPushTimeout();
|
||||||
|
float t = myAdvancedConfig.getDefaultCalibrationTemp();
|
||||||
doc[PARAM_HW_FORMULA_CALIBRATION_TEMP] =
|
doc[PARAM_HW_FORMULA_CALIBRATION_TEMP] =
|
||||||
myAdvancedConfig.getDefaultCalibrationTemp();
|
myConfig.isTempC() ? t : reduceFloatPrecision(convertCtoF(t), 1);
|
||||||
doc[PARAM_HW_PUSH_INTERVAL_HTTP1] = myAdvancedConfig.getPushIntervalHttp1();
|
doc[PARAM_HW_PUSH_INTERVAL_HTTP1] = myAdvancedConfig.getPushIntervalHttp1();
|
||||||
doc[PARAM_HW_PUSH_INTERVAL_HTTP2] = myAdvancedConfig.getPushIntervalHttp2();
|
doc[PARAM_HW_PUSH_INTERVAL_HTTP2] = myAdvancedConfig.getPushIntervalHttp2();
|
||||||
doc[PARAM_HW_PUSH_INTERVAL_HTTP3] = myAdvancedConfig.getPushIntervalHttp3();
|
doc[PARAM_HW_PUSH_INTERVAL_HTTP3] = myAdvancedConfig.getPushIntervalHttp3();
|
||||||
@ -720,27 +631,26 @@ void WebServerHandler::webHandleConfigAdvancedRead() {
|
|||||||
doc[PARAM_HW_PUSH_INTERVAL_MQTT] = myAdvancedConfig.getPushIntervalMqtt();
|
doc[PARAM_HW_PUSH_INTERVAL_MQTT] = myAdvancedConfig.getPushIntervalMqtt();
|
||||||
doc[PARAM_HW_TEMPSENSOR_RESOLUTION] =
|
doc[PARAM_HW_TEMPSENSOR_RESOLUTION] =
|
||||||
myAdvancedConfig.getTempSensorResolution();
|
myAdvancedConfig.getTempSensorResolution();
|
||||||
|
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;
|
||||||
out.reserve(512);
|
out.reserve(500);
|
||||||
serializeJson(doc, out);
|
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-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));
|
||||||
|
|
||||||
DynamicJsonDocument doc(512);
|
DynamicJsonDocument doc(500);
|
||||||
const RawFormulaData& fd = myConfig.getFormulaData();
|
const RawFormulaData& fd = myConfig.getFormulaData();
|
||||||
|
|
||||||
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
|
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
|
||||||
@ -758,10 +668,13 @@ void WebServerHandler::webHandleFormulaRead() {
|
|||||||
doc[PARAM_ERROR] = "Internal error creating formula.";
|
doc[PARAM_ERROR] = "Internal error creating formula.";
|
||||||
break;
|
break;
|
||||||
case ERR_FORMULA_NOTENOUGHVALUES:
|
case ERR_FORMULA_NOTENOUGHVALUES:
|
||||||
doc[PARAM_ERROR] = "Not enough values to create formula.";
|
doc[PARAM_ERROR] =
|
||||||
|
"Not enough values to create formula, need at least 3 angles.";
|
||||||
break;
|
break;
|
||||||
case ERR_FORMULA_UNABLETOFFIND:
|
case ERR_FORMULA_UNABLETOFFIND:
|
||||||
doc[PARAM_ERROR] = "Unable to find an accurate formula based on input.";
|
doc[PARAM_ERROR] =
|
||||||
|
"Unable to find an accurate formula based on input, check error log "
|
||||||
|
"and graph below.";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
doc[PARAM_GRAVITY_FORMULA] = myConfig.getGravityFormula();
|
doc[PARAM_GRAVITY_FORMULA] = myConfig.getGravityFormula();
|
||||||
@ -804,20 +717,18 @@ 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;
|
||||||
out.reserve(256);
|
out.reserve(500);
|
||||||
serializeJson(doc, out);
|
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-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);
|
||||||
@ -854,17 +765,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);
|
||||||
@ -885,7 +792,8 @@ void WebServerHandler::webHandleTestPush() {
|
|||||||
float angle = myGyro.getAngle();
|
float angle = myGyro.getAngle();
|
||||||
float tempC = myTempSensor.getTempC(myConfig.isGyroTemp());
|
float tempC = myTempSensor.getTempC(myConfig.isGyroTemp());
|
||||||
float gravitySG = calculateGravity(angle, tempC);
|
float gravitySG = calculateGravity(angle, tempC);
|
||||||
float corrGravitySG = gravityTemperatureCorrectionC(gravitySG, tempC);
|
float corrGravitySG = gravityTemperatureCorrectionC(
|
||||||
|
gravitySG, tempC, myAdvancedConfig.getDefaultCalibrationTemp());
|
||||||
|
|
||||||
TemplatingEngine engine;
|
TemplatingEngine engine;
|
||||||
engine.initialize(angle, gravitySG, corrGravitySG, tempC, 2.1);
|
engine.initialize(angle, gravitySG, corrGravitySG, tempC, 2.1);
|
||||||
@ -908,10 +816,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();
|
||||||
@ -920,20 +829,17 @@ void WebServerHandler::webHandleTestPush() {
|
|||||||
String out;
|
String out;
|
||||||
out.reserve(100);
|
out.reserve(100);
|
||||||
serializeJson(doc, out);
|
serializeJson(doc, out);
|
||||||
|
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);
|
||||||
@ -959,9 +865,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) {
|
||||||
@ -975,62 +878,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(2048);
|
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(2048);
|
|
||||||
serializeJson(doc, out);
|
|
||||||
_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);
|
||||||
@ -1084,6 +985,7 @@ void WebServerHandler::webHandleFormulaWrite() {
|
|||||||
fd.g[9] = _server->arg("g10").toDouble();
|
fd.g[9] = _server->arg("g10").toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fd.g[0] = 1; // force first point to SG gravity of water
|
||||||
myConfig.setFormulaData(fd);
|
myConfig.setFormulaData(fd);
|
||||||
|
|
||||||
int e;
|
int e;
|
||||||
@ -1122,67 +1024,50 @@ 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 HTML_INDEX:
|
|
||||||
return "index.min.htm";
|
|
||||||
case HTML_CONFIG:
|
|
||||||
return "config.min.htm";
|
|
||||||
case HTML_CALIBRATION:
|
|
||||||
return "calibration.min.htm";
|
|
||||||
case HTML_FORMAT:
|
|
||||||
return "format.min.htm";
|
|
||||||
case HTML_ABOUT:
|
|
||||||
return "about.min.htm";
|
|
||||||
case 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);
|
||||||
|
|
||||||
|
// Show files in the filessytem at startup
|
||||||
|
#if defined(ESP8266)
|
||||||
|
FSInfo fs;
|
||||||
|
LittleFS.info(fs);
|
||||||
|
Log.notice(F("WEB : File system Total=%d, Used=%d." CR), fs.totalBytes,
|
||||||
|
fs.usedBytes);
|
||||||
|
Dir dir = LittleFS.openDir("/");
|
||||||
|
while (dir.next()) {
|
||||||
|
Log.notice(F("WEB : File=%s, %d bytes" CR), dir.fileName().c_str(),
|
||||||
|
dir.fileSize());
|
||||||
|
if (!dir.fileSize()) {
|
||||||
|
Log.notice(F("WEB : Empty file detected, removing file." CR));
|
||||||
|
LittleFS.remove(dir.fileName().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // ESP32
|
||||||
|
File root = LittleFS.open("/");
|
||||||
|
File f = root.openNextFile();
|
||||||
|
while (f) {
|
||||||
|
Log.notice(F("WEB : File=%s, %d bytes" CR), f.name(), f.size());
|
||||||
|
if (!f.size()) {
|
||||||
|
Log.notice(F("WEB : Empty file detected, removing file." CR));
|
||||||
|
LittleFS.remove(f.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
f = root.openNextFile();
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
root.close();
|
||||||
|
#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));
|
||||||
@ -1196,73 +1081,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
|
|
||||||
// Show files in the filessytem at startup
|
|
||||||
|
|
||||||
FSInfo fs;
|
|
||||||
LittleFS.info(fs);
|
|
||||||
Log.notice(F("WEB : File system Total=%d, Used=%d." CR), fs.totalBytes,
|
|
||||||
fs.usedBytes);
|
|
||||||
Dir dir = LittleFS.openDir("/");
|
|
||||||
while (dir.next()) {
|
|
||||||
Log.notice(F("WEB : File=%s, %d bytes" CR), dir.fileName().c_str(),
|
|
||||||
dir.fileSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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),
|
||||||
@ -1306,9 +1147,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();
|
||||||
|
@ -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 <WebServer.h>
|
#include <WebServer.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <Update.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
|
||||||
|
131
src/wifi.cpp
@ -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,65 +58,48 @@ 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;
|
||||||
|
|
||||||
// Check if there are stored WIFI Settings we can use.
|
// Check if there are stored WIFI Settings we can use.
|
||||||
#if defined(ESP32)
|
#if defined(ESP8266)
|
||||||
#warning \
|
|
||||||
"Cant read SSID on ESP32 until a connection has been made, this part will not work, change to WifiManager"
|
|
||||||
#endif
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
@ -136,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) && defined(REDUCE_WIFI_POWER)
|
||||||
|
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()) {
|
||||||
@ -164,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) && defined(REDUCE_WIFI_POWER)
|
||||||
|
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);
|
||||||
@ -187,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));
|
||||||
@ -253,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.
|
||||||
@ -279,16 +255,19 @@ bool WifiConnection::connect() {
|
|||||||
if (!waitForConnection(timeout)) {
|
if (!waitForConnection(timeout)) {
|
||||||
Log.warning(F("WIFI: Failed to connect to first SSID %s." CR),
|
Log.warning(F("WIFI: Failed to connect to first SSID %s." CR),
|
||||||
myConfig.getWifiSSID(0));
|
myConfig.getWifiSSID(0));
|
||||||
connectAsync(1);
|
|
||||||
|
|
||||||
if (waitForConnection(timeout)) {
|
if (strlen(myConfig.getWifiSSID(1))) {
|
||||||
Log.notice(
|
connectAsync(1);
|
||||||
F("WIFI: Connected to second SSID %s, making secondary default." CR),
|
|
||||||
myConfig.getWifiSSID(1));
|
|
||||||
|
|
||||||
myConfig.swapPrimaryWifi();
|
if (waitForConnection(timeout)) {
|
||||||
myConfig.saveFile();
|
Log.notice(F("WIFI: Connected to second SSID %s, making secondary "
|
||||||
return true;
|
"default." CR),
|
||||||
|
myConfig.getWifiSSID(1));
|
||||||
|
|
||||||
|
myConfig.swapPrimaryWifi();
|
||||||
|
myConfig.saveFile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.warning(F("WIFI: Failed to connect to any SSID." CR));
|
Log.warning(F("WIFI: Failed to connect to any SSID." CR));
|
||||||
@ -298,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
|
||||||
@ -309,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));
|
||||||
@ -328,6 +299,12 @@ 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";
|
||||||
|
#elif defined(ESP32LITE)
|
||||||
|
serverPath += "firmware32lite.bin";
|
||||||
#else // defined (ESP32)
|
#else // defined (ESP32)
|
||||||
serverPath += "firmware32.bin";
|
serverPath += "firmware32.bin";
|
||||||
#endif
|
#endif
|
||||||
@ -342,9 +319,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;
|
||||||
@ -359,9 +334,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);
|
||||||
@ -374,15 +346,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));
|
||||||
@ -415,8 +382,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),
|
||||||
@ -464,6 +430,8 @@ bool WifiConnection::checkFirmwareVersion() {
|
|||||||
}
|
}
|
||||||
http.end();
|
http.end();
|
||||||
|
|
||||||
|
if (_newFirmware) Log.notice(F("WIFI: Found new version." CR));
|
||||||
|
|
||||||
#if LOG_LEVEL == 6
|
#if LOG_LEVEL == 6
|
||||||
Log.verbose(F("WIFI: OTA found new version %s." CR),
|
Log.verbose(F("WIFI: OTA found new version %s." CR),
|
||||||
_newFirmware ? "true" : "false");
|
_newFirmware ? "true" : "false");
|
||||||
@ -472,9 +440,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)
|
||||||
|
@ -10,14 +10,18 @@ To reduce the need for adding custom endpoints for various services there is an
|
|||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
Since the format templates can be big this function can be quite slow on a small device such as the esp8266.
|
If format templates are large this feature can be slow on a small device such as the esp8266.
|
||||||
|
|
||||||
.. image:: images/format.png
|
.. image:: images/format.png
|
||||||
:width: 800
|
:width: 800
|
||||||
: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.
|
||||||
|
|
||||||
|
Saving an empty formula will reset it to the default value.
|
||||||
|
|
||||||
.. tip::
|
.. tip::
|
||||||
|
|
||||||
@ -95,4 +99,10 @@ These are the format keys available for use in the format.
|
|||||||
* - ${gravity-unit}
|
* - ${gravity-unit}
|
||||||
- Gravity format, `G` or `P`
|
- Gravity format, `G` or `P`
|
||||||
- G
|
- G
|
||||||
|
* - ${app-ver}
|
||||||
|
- Software version
|
||||||
|
- 1.1.0
|
||||||
|
* - ${app-build}
|
||||||
|
- Software revision (git hash)
|
||||||
|
- ..e456743
|
||||||
|
|
||||||
|
@ -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)
|
||||||
@ -58,27 +58,15 @@ Other parameters are the same as in the configuration guide.
|
|||||||
},
|
},
|
||||||
"formula-calculation-data": {
|
"formula-calculation-data": {
|
||||||
"a1":25,
|
"a1":25,
|
||||||
"a2":30,
|
"a10":0,
|
||||||
"a3":35,
|
|
||||||
"a4":40,
|
|
||||||
"a5":45,
|
|
||||||
"a5":0,
|
|
||||||
"a6":0,
|
|
||||||
"a7":0,
|
|
||||||
"a8":0,
|
|
||||||
"g1":1,
|
"g1":1,
|
||||||
"g2":1.01,
|
"g10":1
|
||||||
"g3":1.02,
|
|
||||||
"g4":1.03,
|
|
||||||
"g4":1.04,
|
|
||||||
"g5":1,
|
|
||||||
"g6":1,
|
|
||||||
"g7":1,
|
|
||||||
"g8":1
|
|
||||||
},
|
},
|
||||||
"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
|
||||||
}
|
}
|
||||||
@ -93,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``, ``esp32`` or ``esp32lite`` (floaty hardware)
|
||||||
|
* ``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.
|
||||||
|
|
||||||
@ -109,12 +99,14 @@ Other parameters are the same as in the configuration guide.
|
|||||||
"temp-c": 0,
|
"temp-c": 0,
|
||||||
"temp-f": 32,
|
"temp-f": 32,
|
||||||
"battery": 0,
|
"battery": 0,
|
||||||
|
"wifi-ssid": "connected SSID",
|
||||||
"temp-format": "C",
|
"temp-format": "C",
|
||||||
"sleep-mode": false,
|
"sleep-mode": false,
|
||||||
"token": "token",
|
"token": "token",
|
||||||
"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",
|
||||||
@ -125,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``-``a8`` are the angles/tilt readings (up to 8 are currently supported)
|
* ``a1``-``a10`` are the angles/tilt readings (up to 10 are currently supported)
|
||||||
* ``g1``-``g8`` 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
|
||||||
|
|
||||||
@ -142,6 +134,8 @@ Retrive the data used for formula calculation data via an HTTP GET command. Payl
|
|||||||
"a6": 0,
|
"a6": 0,
|
||||||
"a7": 0,
|
"a7": 0,
|
||||||
"a8": 0,
|
"a8": 0,
|
||||||
|
"a9": 0,
|
||||||
|
"a10": 0,
|
||||||
"g1": 1.000,
|
"g1": 1.000,
|
||||||
"g2": 1.053,
|
"g2": 1.053,
|
||||||
"g3": 1.062,
|
"g3": 1.062,
|
||||||
@ -150,6 +144,8 @@ Retrive the data used for formula calculation data via an HTTP GET command. Payl
|
|||||||
"g6": 1,
|
"g6": 1,
|
||||||
"g7": 1,
|
"g7": 1,
|
||||||
"g8": 1,
|
"g8": 1,
|
||||||
|
"g9": 1,
|
||||||
|
"g10": 1,
|
||||||
"error": "Potential error message",
|
"error": "Potential error message",
|
||||||
"gravity-format": "G",
|
"gravity-format": "G",
|
||||||
"gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436"
|
"gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436"
|
||||||
@ -165,16 +161,19 @@ Used for adjusting some internal constants and other advanced settings. Should b
|
|||||||
|
|
||||||
{
|
{
|
||||||
"gyro-read-count": 50,
|
"gyro-read-count": 50,
|
||||||
"gyro-read-delay": 3150,
|
|
||||||
"gyro-moving-threashold": 500,
|
"gyro-moving-threashold": 500,
|
||||||
"formula-max-deviation": 1.6,
|
"formula-max-deviation": 3.0,
|
||||||
"wifi-portaltimeout": 120,
|
"wifi-portal-timeout": 120,
|
||||||
|
"wifi-connect-timeout": 20,
|
||||||
|
"push-timeout": 10,
|
||||||
"formula-calibration-temp": 20,
|
"formula-calibration-temp": 20,
|
||||||
"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
|
||||||
@ -182,8 +181,11 @@ POST: /api/config/advanced
|
|||||||
|
|
||||||
Same parameters as above.
|
Same parameters as above.
|
||||||
|
|
||||||
Payload should be in standard format used for posting a form
|
Payload should be in standard format used for posting a form.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
``ignore-low-angles`` is defined as "on" or "off" when posting since this is the output values
|
||||||
|
from a checkbox, when reading data it's sent as boolean (true,false).
|
||||||
|
|
||||||
GET: /api/clearwifi
|
GET: /api/clearwifi
|
||||||
===================
|
===================
|
||||||
@ -237,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::
|
||||||
|
|
||||||
@ -324,8 +326,8 @@ 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``-``a8`` are the angles/tilt readings (up to 5 are currently supported)
|
* ``a1``-``a10`` are the angles/tilt readings (up to 10 are currently supported)
|
||||||
* ``g1``-``g8`` 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.
|
||||||
|
|
||||||
@ -340,6 +342,8 @@ Payload should be in standard format used for posting a form. Such as as: `id=va
|
|||||||
a6=0
|
a6=0
|
||||||
a7=0
|
a7=0
|
||||||
a8=0
|
a8=0
|
||||||
|
a9=0
|
||||||
|
a19=0
|
||||||
g1=1.000
|
g1=1.000
|
||||||
g2=1.053
|
g2=1.053
|
||||||
g3=1.062
|
g3=1.062
|
||||||
@ -348,13 +352,15 @@ Payload should be in standard format used for posting a form. Such as as: `id=va
|
|||||||
g6=1
|
g6=1
|
||||||
g7=1
|
g7=1
|
||||||
g8=1
|
g8=1
|
||||||
|
g9=1
|
||||||
|
g10=1
|
||||||
|
|
||||||
|
|
||||||
Calling the API's from Python
|
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 )
|
||||||
|
|
||||||
@ -433,6 +439,8 @@ The requests package converts the json to standard form post format.
|
|||||||
"a6": 0,
|
"a6": 0,
|
||||||
"a7": 0,
|
"a7": 0,
|
||||||
"a8": 0,
|
"a8": 0,
|
||||||
|
"a9": 0,
|
||||||
|
"a10": 0,
|
||||||
"g1": 1.000,
|
"g1": 1.000,
|
||||||
"g2": 1.053,
|
"g2": 1.053,
|
||||||
"g3": 1.062,
|
"g3": 1.062,
|
||||||
@ -440,6 +448,8 @@ The requests package converts the json to standard form post format.
|
|||||||
"g5": 1,
|
"g5": 1,
|
||||||
"g6": 1,
|
"g6": 1,
|
||||||
"g7": 1,
|
"g7": 1,
|
||||||
"g8": 1
|
"g8": 1,
|
||||||
|
"g9": 1,
|
||||||
|
"g10": 1
|
||||||
}
|
}
|
||||||
set_config( url, json )
|
set_config( url, json )
|
||||||
|
@ -29,18 +29,36 @@ 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-perf: Experimental version for ESP32.
|
* gravity32c3-release: Version for ESP32 C3 mini v2.1+.
|
||||||
|
* gravity32c3v1-release: Version for ESP32 C3 mini v1.0.
|
||||||
.. note::
|
* gravity32s2-release: Version for ESP32 S2 mini.
|
||||||
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,
|
* gravity32lite-release: Version for ESP32 lite (Floaty hardware).
|
||||||
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.
|
||||||
So only enable enough debugging to troubleshoot your changes.
|
So only enable enough debugging to troubleshoot your changes.
|
||||||
|
|
||||||
|
Serial debugging on battery
|
||||||
|
===========================
|
||||||
|
|
||||||
|
.. image:: images/serial.png
|
||||||
|
:width: 600
|
||||||
|
:alt: Serial output
|
||||||
|
|
||||||
|
On the ESP32 builds the serial output can be 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. In order to get this to work you need to compile the sofware
|
||||||
|
with the option **DUSE_SERIAL_PINS** and attach as USB to TTL cable to the correct pins.
|
||||||
|
|
||||||
|
You connect the 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
|
||||||
|
|
||||||
Source structure
|
Source structure
|
||||||
================
|
================
|
||||||
@ -68,8 +86,6 @@ Source structure
|
|||||||
- Source code for software
|
- Source code for software
|
||||||
* - /src_docs
|
* - /src_docs
|
||||||
- Source code for documentation
|
- Source code for documentation
|
||||||
* - /stl
|
|
||||||
- 3d models
|
|
||||||
* - /test
|
* - /test
|
||||||
- Test data for developing html files
|
- Test data for developing html files
|
||||||
|
|
||||||
@ -92,12 +108,15 @@ 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
|
||||||
- Password to the SSID
|
- Password to the SSID
|
||||||
* - CFG_APPVER
|
* - CFG_APPVER
|
||||||
- Defines the version of the compiled software
|
- Defines the version of the compiled software
|
||||||
|
* - USE_SERIAL_PINS
|
||||||
|
- Will send the serial console to the TX/RX pins on an ESP32 target so that debugging can be done when on battery
|
||||||
|
* - REDUCE_WIFI_POWER
|
||||||
|
- Will reduce wifi power to support the ESP32C3 v1.0 which has a bad antenna
|
||||||
|
* - FLOATY
|
||||||
|
- Build for the ESP32lite FLOATY hardware option (no DS18B20 and no battery monitor)
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = 'GravityMon'
|
project = 'GravityMon'
|
||||||
copyright = '2021-2022, Magnus Persson'
|
copyright = '2021-2023, 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.0.0'
|
release = '1.2.1'
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
@ -31,6 +31,7 @@ release = '1.0.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.
|
||||||
@ -47,6 +48,8 @@ exclude_patterns = []
|
|||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#
|
#
|
||||||
html_theme = 'furo'
|
html_theme = 'furo'
|
||||||
|
html_logo = "images/gravitymon_logo.png"
|
||||||
|
html_title = "GravityMon v1.2.0"
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
@ -10,7 +10,7 @@ One of the following conditions will place the device in ``configuration mode``:
|
|||||||
- Gyro has not been calibrated
|
- Gyro has not been calibrated
|
||||||
- Sleep mode has been disabled in the web interface
|
- Sleep mode has been disabled in the web interface
|
||||||
- Placed in horizontal mode 85-90 degrees
|
- Placed in horizontal mode 85-90 degrees
|
||||||
- Charger connected >4.15V
|
- Charger connected >4.15V (or the value that is configured). This does not work on the Floaty variant due to lack of hardware support.
|
||||||
|
|
||||||
|
|
||||||
Status
|
Status
|
||||||
@ -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 (this applies to esp8266 only).
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
@ -55,11 +56,12 @@ Device Setting
|
|||||||
|
|
||||||
* **Device name:**
|
* **Device name:**
|
||||||
|
|
||||||
This is unique name for the device. It will be used in pushing data as well as mDNS name on the network (<name>.local)
|
This is unique name for the device. It will be used in pushing data as well as mDNS name on the network (<name>.local).
|
||||||
|
The limitation is 63 chars but using long names might break endpoints that data is sent to if they have other limitations.
|
||||||
|
|
||||||
* **Temperature format:**
|
* **Temperature format:**
|
||||||
|
|
||||||
Choose between Celsius and Farenheight when displaying temperature.
|
Choose between Celsius and Fahrenheit when displaying temperature.
|
||||||
|
|
||||||
* **Interval:**
|
* **Interval:**
|
||||||
|
|
||||||
@ -92,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):**
|
||||||
|
|
||||||
@ -127,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.
|
||||||
|
|
||||||
@ -163,7 +165,7 @@ Name of organisation in Influx.
|
|||||||
|
|
||||||
* **Influx DB v2 Bucket:**
|
* **Influx DB v2 Bucket:**
|
||||||
|
|
||||||
Identifier for bucket.
|
Token for bucket. Don't use the bucket name.
|
||||||
|
|
||||||
* **Influx DB v2 Token:**
|
* **Influx DB v2 Token:**
|
||||||
|
|
||||||
@ -195,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:**
|
||||||
@ -214,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.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -231,7 +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:**
|
||||||
|
|
||||||
|
Defines the level of voltage when the device should enter config mode due to charging. This might vary between different battery manufacturers.
|
||||||
|
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:**
|
||||||
|
|
||||||
@ -242,9 +250,16 @@ 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**
|
||||||
|
|
||||||
|
When place on the cap (<5 degree tilt) the device will go into deep sleep forever (until reset). In order to wake it
|
||||||
|
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
|
||||||
|
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)**
|
||||||
|
|
||||||
If the build is using an ESP32 then you can send data over BLE, simulating a Tilt device. Choose the color that you want the device to simulate.
|
If the build is using an ESP32 then you can send data over BLE, simulating a Tilt device. Choose the color that you want the device to simulate.
|
||||||
@ -275,14 +290,56 @@ 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
|
||||||
:width: 800
|
:width: 800
|
||||||
:alt: Advanced Settings
|
:alt: Advanced Settings
|
||||||
|
|
||||||
* **Header:**
|
.. warning::
|
||||||
|
|
||||||
To be described
|
Change these parameters with caution. The wrong values might cause the device to become unresponsive.
|
||||||
|
|
||||||
|
|
||||||
|
* **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
|
||||||
|
movement. Too many reads will take time and affect battery life. 50 takes about 800 ms to execute.
|
||||||
|
|
||||||
|
* **Gyro moving threshold:**
|
||||||
|
|
||||||
|
This is the max amount of deviation allowed for a stable reading.
|
||||||
|
|
||||||
|
* **Formula deviation:**
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* **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.
|
||||||
|
|
||||||
|
* **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:**
|
||||||
|
|
||||||
|
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
|
||||||
|
take longer time to measure..
|
||||||
|
|
||||||
|
* **Wifi connect timeout:**
|
||||||
|
|
||||||
|
This is the amount of time allowed for a wifi connect.
|
||||||
|
|
||||||
|
* **Wifi portal timeout:**
|
||||||
|
|
||||||
|
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 (...):**
|
||||||
|
|
||||||
|
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
|
||||||
|
accept data every 15 min.
|
||||||
|
@ -1,5 +1,33 @@
|
|||||||
Contributing
|
Contributing
|
||||||
|
############
|
||||||
|
|
||||||
|
Anyone is welcome to contribute to this project or create their own variant of it. I would appreciate a PR if your feature would be of benefit other users.
|
||||||
|
|
||||||
|
In order to keep the source code in good condition I use `pre-commit <https://pre-commit.com/>`_ to validate and format the code using their standards for C++/C.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
The following command will run pre-commit on all the source files. Assuming you are in the project directory.
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
pre-commit run --files src/*
|
||||||
|
|
||||||
|
|
||||||
|
Design goals
|
||||||
------------
|
------------
|
||||||
|
|
||||||
This section is under construction.
|
My goals with this software has been the following:
|
||||||
|
|
||||||
|
* Create an open software for the excellent iSpindle hardware platform that is open and available for anyone.
|
||||||
|
* Add user requested features that have not made it into the iSpindle project.
|
||||||
|
* Focus on long battery life and stability.
|
||||||
|
* Explore new technologies and create the next generation gravity monitoring for home brewers.
|
||||||
|
|
||||||
|
I will do my best to assist users and respond to new features, pr and suggestions. But keep in mind I'm doing this on my spare time.
|
||||||
|
|
||||||
|
Regards, Magnus
|
||||||
|
@ -40,7 +40,7 @@ This is the format template used to create the json above.
|
|||||||
{
|
{
|
||||||
"name" : "${mdns}",
|
"name" : "${mdns}",
|
||||||
"ID": "${id}",
|
"ID": "${id}",
|
||||||
"token" : "gravmon",
|
"token" : "${token}",
|
||||||
"interval": ${sleep-interval},
|
"interval": ${sleep-interval},
|
||||||
"temperature": ${temp},
|
"temperature": ${temp},
|
||||||
"temp_units": "${temp-unit}",
|
"temp_units": "${temp-unit}",
|
||||||
@ -129,34 +129,18 @@ This is the format template used to create the json above.
|
|||||||
ispindel/${mdns}/interval:${sleep-interval}|
|
ispindel/${mdns}/interval:${sleep-interval}|
|
||||||
ispindel/${mdns}/RSSI:${rssi}|
|
ispindel/${mdns}/RSSI:${rssi}|
|
||||||
|
|
||||||
This is a format template that is compatible with v0.6. Just replace the `topic` with the topic you want to post data to.
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
|
|
||||||
topic:{"name":"gravmon", "ID":"${id}", "token":"gravmon", "interval": ${sleep-interval},
|
|
||||||
"temperature": ${temp}, "temp_units": "${temp-unit}", "gravity":${gravity},
|
|
||||||
"angle": ${angle}, "battery":${battery}, "rssi": ${rssi}, "corr-gravity":${corr-gravity},
|
|
||||||
"gravity-unit": "${gravity-unit}", "run-time": ${run-time}}|
|
|
||||||
|
|
||||||
|
|
||||||
version.json
|
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
|
||||||
|
|
||||||
{
|
{
|
||||||
"project":"gravmon",
|
"project":"gravmon",
|
||||||
"version":"0.7.0",
|
"version":"1.0.0",
|
||||||
"html": [
|
"html": [ ]
|
||||||
"index.min.htm",
|
|
||||||
"test.min.htm",
|
|
||||||
"config.min.htm",
|
|
||||||
"format.min.htm",
|
|
||||||
"calibration.min.htm",
|
|
||||||
"about.min.htm"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,33 @@ Create formula
|
|||||||
:width: 800
|
:width: 800
|
||||||
:alt: Formula data
|
:alt: Formula data
|
||||||
|
|
||||||
Here you can enter up to 5 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 formula with increasing level of complexity. It will start
|
||||||
|
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
|
||||||
|
high difference, it will fail. You can adjust the sensitivity under advanced settings if you have issues.
|
||||||
|
|
||||||
|
Under the Error Log you will also find hints to what problem the formula creator encountered. Here is an example:
|
||||||
|
|
||||||
|
`CALC: Validation failed on angle 33.430000, deviation too large 5.86, formula order 4`
|
||||||
|
|
||||||
|
`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 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.
|
||||||
|
|
||||||
|
.. image:: images/qa_1.png
|
||||||
|
:width: 400
|
||||||
|
:alt: Example of deviating value
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
.. image:: images/formula2.png
|
.. image:: images/formula2.png
|
||||||
:width: 800
|
:width: 800
|
||||||
:alt: Formula graph
|
:alt: Formula graph
|
||||||
|
|
||||||
Once the formula is created a graph over the entered values and a simulation of the formula will give you a nice overview on how the formula will work.
|
Once the formula is created a graph over the entered values and a simulation of the formula will give you a nice overview on how the formula will work.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.. _functionallity:
|
.. _functionality:
|
||||||
|
|
||||||
Functionallity
|
Functionality
|
||||||
==============
|
==============
|
||||||
|
|
||||||
The main features
|
The main features
|
||||||
@ -33,10 +33,10 @@ The main features
|
|||||||
|
|
||||||
Currently the device supports the following endpoints.
|
Currently the device supports the following endpoints.
|
||||||
|
|
||||||
* http or https
|
* http (ssl optional)
|
||||||
* influxdb v2
|
* influxdb v2 (ssl optional)
|
||||||
|
* MQTT (ssl optional)
|
||||||
* Brewfather
|
* Brewfather
|
||||||
* MQTT
|
|
||||||
* Home Assistant
|
* Home Assistant
|
||||||
* Brew Spy
|
* Brew Spy
|
||||||
* Brewers Friend
|
* Brewers Friend
|
||||||
@ -65,12 +65,10 @@ The main features
|
|||||||
Another big difference is that this software can create the gravity formula in the device, just enter the
|
Another big difference is that this software can create the gravity formula in the device, just enter the
|
||||||
angle/gravity data that you have collected. You will also see a graph simulating how the formula would work.
|
angle/gravity data that you have collected. You will also see a graph simulating how the formula would work.
|
||||||
|
|
||||||
Currently the device can handle 5 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.
|
||||||
|
|
||||||
If there is a need for more data points, raise a comment on github.
|
* **Customize the data format being sent to push targets**
|
||||||
|
|
||||||
* **Customize the data format beeing 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.
|
||||||
@ -81,12 +79,13 @@ 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**
|
||||||
|
|
||||||
When starting up in configuration mode the device will check for a software update from a webserver. This is an easily
|
When starting up in configuration mode the device will check for a software update from a webserver. This is an easily
|
||||||
way to keep the software up to date. In the future I might add a hosted endpoint for providing updates.
|
way to keep the software up to date. In the future I might add a hosted endpoint for providing updates. OTA can also be
|
||||||
|
done over a SSL connection.
|
||||||
|
|
||||||
* **DS18B20 temperature adjustments**
|
* **DS18B20 temperature adjustments**
|
||||||
|
|
||||||
@ -95,13 +94,14 @@ The main features
|
|||||||
|
|
||||||
* **Gyro Movement**
|
* **Gyro Movement**
|
||||||
|
|
||||||
The software will detect if the gyro is moving and if this is the case it will go back to sleep for 60seconds.
|
The software will detect if the gyro is moving and if this is the case it will go back to sleep for 60 seconds.
|
||||||
This way we should avoid faulty measurements and peaks in the graphs.
|
This way we should avoid faulty measurements and peaks in the graphs.
|
||||||
|
|
||||||
* **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 go into deep sleep for 60 seoncds and then retry later. This to conserve batter as much as possible.
|
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.
|
||||||
|
|
||||||
* **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,20 @@ 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.
|
||||||
|
|
||||||
|
* **Crash detection and Error Logging**
|
||||||
|
|
||||||
|
There is a build in logging function so that errors that occurs can be detected and logged to a file. On the ESP8266 crashes will also
|
||||||
|
be logged so that these problems can be detected and fixed. Crash logging is not available on the ESP32 variants.
|
||||||
|
|
||||||
* **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
|
||||||
@ -152,20 +157,45 @@ The main features
|
|||||||
|
|
||||||
See the :ref:`compiling-the-software` for more information.
|
See the :ref:`compiling-the-software` for more information.
|
||||||
|
|
||||||
* **Power measurements**
|
|
||||||
|
|
||||||
I've also create a project to measure the power consumption of the device, but more on this later.
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
For the 1.2 version I have been running some long term battery tests on a few of the boards and also comparing wifi vs Bluetooth. I was using a standard 2200 mA battery
|
||||||
|
that was fully charged at the start of the tests. All devices started with factory settings with only a change in push destination and 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.
|
For the wifi tests, I was pushing data every 30 seconds to a local influxdb2 server to reduce errors connected to slow response on the server side. The devices
|
||||||
|
was placed 2 meters from the wifi AP to ensure a good and stable wifi connection (so ideal conditions).
|
||||||
|
|
||||||
From what I have discovered it's the WIFI connection or latency to internet hosted that has the most impact on the battery life. The typical runtime in the tests above was around 2 seconds.
|
For the Bluetooth tests I was pusing data every 10 seconds to a linux server.
|
||||||
|
|
||||||
|
To make this comparable I measured how many times the device was able to wake up and push data before the battery was dead. I theory the power consumption when in
|
||||||
|
deep sleep is to low it can almost be ignored for the calculations. So the impact on battery is mainly caused by how long the device is awake. In the most optimal case
|
||||||
|
this can be as low as 1.5-2.0 seconds but in reality its probably around 3-4 seconds. Wifi consumes a lot of power so Bluetooth is a better option for long battery life.
|
||||||
|
|
||||||
|
.. list-table:: Battery power
|
||||||
|
:widths: 30 20 20 20
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - Device
|
||||||
|
- Transmissions
|
||||||
|
- 30s
|
||||||
|
- 300s / 15min
|
||||||
|
* - ESP 8266 (wifi)
|
||||||
|
- 26,000
|
||||||
|
- 9 days
|
||||||
|
- 90 days
|
||||||
|
* - ESP32 c3 (wifi)
|
||||||
|
- 12,000
|
||||||
|
- 4 days
|
||||||
|
- 43 days
|
||||||
|
* - ESP32 d1 (ble)
|
||||||
|
- 56,000
|
||||||
|
- 20 days
|
||||||
|
- 196 days
|
||||||
|
|
||||||
|
|
||||||
|
As you can see from the table above there is quite some differences between the boards and connection methods.
|
||||||
|
|
||||||
Performance
|
Performance
|
||||||
-----------
|
-----------
|
||||||
@ -173,7 +203,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.
|
@ -3,24 +3,138 @@
|
|||||||
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.
|
I'm not a hardware designer so I would recommend the following resources for more in depth information on this topic.
|
||||||
|
|
||||||
.. image:: images/ispindel.jpg
|
* `Cherry Philip Hardware design <https://github.com/cherryphilip74/iSpindel-PCB>`_
|
||||||
|
* `OpenSource Distilling <https://www.opensourcedistilling.com/ispindel>`_
|
||||||
|
|
||||||
|
iSpindle based on esp8266
|
||||||
|
=========================
|
||||||
|
|
||||||
|
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
|
Schema for esp8266 build
|
||||||
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.
|
++++++++++++++++++++++++
|
||||||
|
|
||||||
|
.. image:: images/schema_esp8266.png
|
||||||
|
:width: 700
|
||||||
|
:alt: Schema esp8266
|
||||||
|
|
||||||
|
iSpindle based on esp32
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Gravitymon supports a number of ESP32 boards that offers bluetooth support.
|
||||||
|
|
||||||
|
.. image:: images/esp32_hardware.jpg
|
||||||
|
:width: 500
|
||||||
|
:alt: iSpindle esp32 hardware options
|
||||||
|
|
||||||
|
* esp32d1 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. Don't buy v1.0 since that has a faulty wifi antenna.
|
||||||
|
* 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 or s2 are prefered). The esp32 d1 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 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
|
||||||
|
++++++++++++
|
||||||
|
|
||||||
|
This is model is fully supported by gravitymon. Same setup as for ESP32C3 mini.
|
||||||
|
|
||||||
|
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.
|
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.
|
.. image:: images/ispindel_esp32.jpg
|
||||||
|
|
||||||
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
|
:width: 500
|
||||||
:alt: Mounting esp32
|
:alt: Esp32 mini build
|
||||||
|
|
||||||
|
Schema for esp32 build
|
||||||
|
++++++++++++++++++++++
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This schema assumes that an ESP32 d1 mini (pin compatible with ESP8266). The ESP32 has two rows of pins but
|
||||||
|
only the inner row is used. The main difference is the added resistor R3 so we get a voltage divider for measuring battery.
|
||||||
|
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
|
||||||
|
:width: 700
|
||||||
|
: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
|
||||||
|
|
||||||
|
|
||||||
|
Floaty Hydrometer DIY based on esp32 lite
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
Here we have another projects that has build a device similar to the iSpindel but based on an ESP32 instead.
|
||||||
|
|
||||||
|
The setup is much simpler and attaches the GYRO to an ESP32 with a build in charger chip. GravityMon works on
|
||||||
|
this hardware platform as well but there are a few limitations:
|
||||||
|
|
||||||
|
* Temperature is read from the GYRO and cannot be changed. This works fine when measuring gravity but when in configuration mode the temperature will increase since it shows the chip temperature.
|
||||||
|
* No possibility to measure battery level (can be added with additional hardware).
|
||||||
|
|
||||||
|
|
||||||
|
Hardware extensions
|
||||||
|
===================
|
||||||
|
|
||||||
|
GravityMon has implemented a few additions to the standard iSpindel hardware. It's possible to channel the serial console to the TX/RX pins on the chip (these position also applies to all the
|
||||||
|
ESP32 chips for iSpindel). You need a USB to TTL converter for this to work. This enables you to read the serial console even when on battery (newer chips dont have a diode to remove).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
You need to compile the software using the -DUSE_SERIAL_PINS option to enable this feature.
|
||||||
|
|
||||||
|
Its also possible to force the device into configuration mode by connecting D7/D8 on the board during the startup sequence. This will enable the feature "gravity mode enabled during float".
|
||||||
|
|
||||||
|
.. image:: images/8266_pins.jpg
|
||||||
|
:width: 500
|
||||||
|
:alt: iSpindel pins
|
||||||
|
|
||||||
|
For the floaty device pins 16/17 are used as TX/RX pins and the 13/15 pins are used to force the device into configuration mode. Pin 35 can also be connected to the battery voltage via an voltage divider to be able to read the battery voltage.
|
||||||
|
|
||||||
|
.. image:: images/32lite_pins.jpg
|
||||||
|
:width: 500
|
||||||
|
:alt: Floaty pins
|
||||||
|
BIN
src_docs/source/images/32lite_pins.jpg
Normal file
After Width: | Height: | Size: 416 KiB |
BIN
src_docs/source/images/8266_pins.jpg
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
src_docs/source/images/buymecoffee.png
Normal file
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 40 KiB |