Compare commits
104 Commits
v1.2.0-bet
...
v1.2.0
Author | SHA1 | Date | |
---|---|---|---|
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 |
19
.github/workflows/doc-build.yaml
vendored
@ -4,13 +4,14 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
#- dev
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: ammaraskar/sphinx-action@master
|
||||
with:
|
||||
@ -39,9 +40,19 @@ jobs:
|
||||
git config --local user.name "GitHub Action"
|
||||
git add .
|
||||
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
|
||||
# the return code.
|
||||
|
||||
- uses: wangyucode/sftp-upload-action@v1.4.8
|
||||
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
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
|
10
.github/workflows/pio-build-patch.yaml
vendored
@ -10,10 +10,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
@ -21,13 +21,13 @@ jobs:
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
@ -38,7 +38,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
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:
|
||||
add: 'bin'
|
||||
author_name: GitHub Action
|
||||
|
10
.github/workflows/pio-build.yaml
vendored
@ -10,10 +10,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
@ -21,7 +21,7 @@ jobs:
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
@ -36,9 +36,9 @@ jobs:
|
||||
git config --global advice.detachedHead false
|
||||
|
||||
- name: Run PlatformIO
|
||||
run: pio run -e gravity-release -e gravity32-release -e gravity32c3-release
|
||||
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:
|
||||
add: 'bin'
|
||||
author_name: GitHub Action
|
||||
|
6
.github/workflows/pre-commit.yaml
vendored
@ -11,9 +11,9 @@ jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v3
|
||||
- name: clang format support
|
||||
run: |
|
||||
sudo apt install clang-format cppcheck
|
||||
- uses: pre-commit/action@v2.0.3
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
|
7
.gitignore
vendored
@ -1,9 +1,6 @@
|
||||
.pio/*
|
||||
.vscode/*
|
||||
*.map
|
||||
test/*.md
|
||||
test/env/*
|
||||
test/configure_*.py
|
||||
TODO.md
|
||||
src_docs/_build/*
|
||||
data/*.min.htm
|
||||
.env/*
|
||||
*.pyc
|
44
README.md
@ -8,37 +8,25 @@
|
||||
|
||||
# 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, either an ESP32 d1 mini or ESP32 c3 mini which both are 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 or https://web.brewflasher.com
|
||||
Now also works with ESP32 d1 mini, ESP32 c3 mini, ESP32 S2 mini which both are pin compatible with ESP8266.
|
||||
|
||||
The documenation can be found here: https://mp-se.github.io/gravitymon/index.html
|
||||
Installation can be made using https://www.brewflasher.com or the web version at https://web.brewflasher.com
|
||||
|
||||
Note! If Brewflasher being flagged as malware by your antivirus software, try the web version.
|
||||
The documentation can be found here: https://www.gravitymon.com/docs.html
|
||||
|
||||
The main differences:
|
||||
---------------------
|
||||
Visit the gravitymon homepage here for more information about the project: https://www.gravitymon.com
|
||||
|
||||
* Operates in two modes gravity monitoring and configuration mode
|
||||
* Gravity mode is comparable to how the iSpindle works when collectintg data
|
||||
* Configuration mode has a modern HTML5 based web UI. No need to start the access point to change settings
|
||||
* Offloading some of the functionallity to run in the web browser, this allows for more advanced features.
|
||||
* REST API to enable scripted configuration
|
||||
* Send data to multiple endpoints and services at once (2xHTTP POST, HTTP GET, MQTT, INFLUXDB2)
|
||||
* Directly test all endpoints from user interface with feedback to simplify troubleshooting
|
||||
* Complete format customization for all endpoints using templates (dont really need to change the software to support new services)
|
||||
* Setup guides for how to send data to many popular services. Currently 10+ are documented
|
||||
* Automatic temperature adjustment of gravity (just tick a checkbox)
|
||||
* OTA support from webserver
|
||||
* Firmware update via web interface
|
||||
* Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity and let GravityMon creates a formula
|
||||
* Visual graph showing how formula will be interpreted based on entered values
|
||||
* Using the temperature sensor in gyro instead of DS18B20 (faster)
|
||||
* SSL support in all endpoints (no certificate validation due to limitations on esp8266).
|
||||
* Built in performance measurements (used to optimise code)
|
||||
* Storage mode when placed on cap (indefinite sleep)
|
||||
* Customize various hardware parameters to opimize device functionallity.
|
||||
*
|
||||
No code has been reused from the iSpindle project.
|
||||
If you want to support my work you can do that through these options
|
||||
|
||||
[<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
BIN
bin/firmware.bin
BIN
bin/firmware32c3v1.bin
Normal file
BIN
bin/firmware32lite.bin
Normal file
BIN
bin/firmware32s2.bin
Normal file
BIN
bin/partitions32lite.bin
Normal file
BIN
bin/partitions32s2.bin
Normal file
@ -1,35 +0,0 @@
|
||||
|
||||
User exception (panic/abort/assert)
|
||||
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
|
||||
|
||||
Panic core_esp8266_main.cpp:215 loop_task
|
||||
|
||||
>>>stack>>>
|
||||
|
||||
ctx: sys
|
||||
sp: 3fffff10 end: 3fffffb0 offset: 0000
|
||||
3fffff10: 00000000 02ac3bd9 40280793 3ffeaec4
|
||||
3fffff20: 000000fe 00000000 00000000 00000000
|
||||
3fffff30: 00000000 00000000 00000000 3fff1edc
|
||||
3fffff40: 3fff1fa8 3fff1fa8 3fff0280 3fff1e94
|
||||
3fffff50: 3fffdad0 00000000 3ffe8648 4022d992
|
||||
3fffff60: 402854b2 3fffdab0 00000000 4022d9ff
|
||||
3fffff70: 00000000 3fffdad0 3fff1e94 4022d0d8
|
||||
3fffff80: 40000f49 40000f49 3fffdab0 40000f49
|
||||
3fffff90: 40000e19 000b5a21 00000000 00000005
|
||||
3fffffa0: 00000000 aa55aa55 000000d0 401057f9
|
||||
<<<stack<<<
|
||||
|
||||
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
|
||||
|
||||
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
|
||||
|
||||
load 0x4010f000, len 3460, room 16
|
||||
tail 4
|
||||
chksum 0xcc
|
||||
load 0x3fff20b8, len 40, room 4
|
||||
tail 4
|
||||
chksum 0xc9
|
||||
csum 0xc9
|
||||
v000b5a30
|
||||
~ld
|
@ -39,7 +39,7 @@
|
||||
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/calibration.htm">Calibration</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
|
139
html/config.htm
@ -109,6 +109,10 @@
|
||||
<div id="collapseDevice" class="accordion-collapse collapse show" aria-labelledby="headingDevice" data-bs-parent="#accordion">
|
||||
<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">
|
||||
<input type="text" name="id" id="id1" hidden>
|
||||
|
||||
@ -240,17 +244,11 @@
|
||||
<div class="row mb-3">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
@ -329,17 +327,12 @@
|
||||
<div class="row mb-3">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
@ -415,7 +408,15 @@
|
||||
<div class="col-sm-2">
|
||||
<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>
|
||||
<label for="voltage-factor" class="col-sm-3 col-form-label" id="battery">Loading...</label>
|
||||
<div class="col-sm-2">
|
||||
<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 class="row mb-3">
|
||||
@ -467,23 +468,62 @@
|
||||
</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>
|
||||
<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/">
|
||||
</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="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="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>
|
||||
</form>
|
||||
|
||||
<div class="row mb-3">
|
||||
<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>
|
||||
@ -740,10 +780,40 @@
|
||||
// MPU-6050 consumes 4mA
|
||||
// DS18B20 consumes 1mA
|
||||
// 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
|
||||
var pwrSleep = 15; // mA per day
|
||||
var batt = 2000; // mA
|
||||
if($("#ble").val() != "")
|
||||
ble = true;
|
||||
|
||||
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;
|
||||
|
||||
@ -757,8 +827,11 @@
|
||||
var rt = parseInt($("#runtime-average").val());
|
||||
var j = 0;
|
||||
|
||||
if( rt>0 )
|
||||
console.log("Average runtime " + $("#runtime-average").val() )
|
||||
|
||||
if( rt>0 ) {
|
||||
j = estimateBatteryLife(i, rt);
|
||||
}
|
||||
|
||||
var t1 = Math.floor(i/60) + " m " + (i%60) + " s";
|
||||
var t2 = Math.floor(j/7) + " weeks " + Math.floor(j%7) + " days";
|
||||
@ -795,14 +868,14 @@
|
||||
$("#test-btn2").prop("disabled", b);
|
||||
$("#advanced-btn").prop("disabled", b);
|
||||
|
||||
checkAdvancedSection( b );
|
||||
checkAdvancedSection();
|
||||
}
|
||||
|
||||
$("#adv-config").click(function(e){
|
||||
checkAdvancedSection();
|
||||
});
|
||||
|
||||
function checkAdvancedSection( b ) {
|
||||
function checkAdvancedSection() {
|
||||
var b = $("#adv-config").is(":checked");
|
||||
|
||||
$("#advanced-btn").prop("disabled", b);
|
||||
@ -869,11 +942,15 @@
|
||||
$.getJSON(url, function (cfg) {
|
||||
console.log( cfg );
|
||||
|
||||
if(cfg["platform"]=="esp32" || cfg["platform"]=="esp32c3") {
|
||||
if(cfg["platform"]=="esp32" || cfg["platform"]=="esp32c3" || cfg["platform"]=="esp32lite") {
|
||||
$('#ble').prop('disabled', false);
|
||||
$("#ble").val(cfg["ble"]);
|
||||
}
|
||||
|
||||
if(cfg["platform"]=="esp32lite") {
|
||||
$('#gyro-temp').prop('disabled', true);
|
||||
}
|
||||
|
||||
$("#id1").val(cfg["id"]);
|
||||
$("#id2").val(cfg["id"]);
|
||||
$("#id3").val(cfg["id"]);
|
||||
@ -886,6 +963,12 @@
|
||||
if( cfg["gravity-format"] == "G" ) $("#gravity-format-g").click();
|
||||
else $("#gravity-format-p").click();
|
||||
$("#ota-url").val(cfg["ota-url"]);
|
||||
|
||||
if( cfg["ota-url"] == gravitymonUrl) {
|
||||
$("#gravitymon-com").prop( "checked", true );
|
||||
$("#ota-hide").hide();
|
||||
}
|
||||
|
||||
$("#token").val(cfg["token"]);
|
||||
$("#token2").val(cfg["token2"]);
|
||||
$("#http-push").val(cfg["http-push"]);
|
||||
@ -918,6 +1001,8 @@
|
||||
$("#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");
|
||||
})
|
||||
.fail(function () {
|
||||
|
@ -90,7 +90,7 @@
|
||||
|
||||
<div class="row mb-3">
|
||||
<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>
|
||||
|
||||
|
238
platformio.ini
@ -28,20 +28,20 @@ build_flags =
|
||||
#-D DOUBLERESETDETECTOR_DEBUG=true
|
||||
-DACTIVATE_OTA
|
||||
-DCFG_DISABLE_LOGGING # Turn off verbose/notice logging to reduce size and dont overload uart (applies to LOG_LEVEL6)
|
||||
-DGYRO_DISABLE_LOGGING
|
||||
-DCALC_DISABLE_LOGGING
|
||||
-DHELPER_DISABLE_LOGGING
|
||||
-DPUSH_DISABLE_LOGGING
|
||||
-DTSEN_DISABLE_LOGGING
|
||||
-DWIFI_DISABLE_LOGGING
|
||||
-DWEB_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
|
||||
-DUSE_LITTLEFS=true
|
||||
-DUSER_SSID=\""\"" # =\""myssid\""
|
||||
-DUSER_SSID_PWD=\""\"" # =\""mypwd\""
|
||||
-DCFG_APPVER="\"1.2.0\""
|
||||
-DCFG_GITREV=\""beta-1\""
|
||||
#!python script/git_rev.py
|
||||
#-DCFG_GITREV=\""beta-3\""
|
||||
!python script/git_rev.py
|
||||
lib_deps =
|
||||
# Using local copy of these libraries
|
||||
# https://github.com/mp-se/i2cdevlib.git#<document>
|
||||
@ -94,14 +94,35 @@ platform = ${common_env_data.platform}
|
||||
extra_scripts = ${common_env_data.extra_scripts}
|
||||
build_unflags = ${common_env_data.build_unflags}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
${common_env_data.build_flags}
|
||||
-D LOG_LEVEL=4
|
||||
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||
lib_deps =
|
||||
https://github.com/mp-se/incbin # https://github.com/graphitemaster/incbin
|
||||
${common_env_data.lib_deps}
|
||||
board = ${common_env_data.board}
|
||||
build_type = release
|
||||
board_build.filesystem = littlefs
|
||||
build_src_filter = +<*> -<../test/tests*.cpp>
|
||||
|
||||
[env:gravity-unit]
|
||||
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 = ${common_env_data.extra_scripts}
|
||||
build_unflags = ${common_env_data.build_unflags}
|
||||
build_flags =
|
||||
${common_env_data.build_flags}
|
||||
-D LOG_LEVEL=4
|
||||
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}
|
||||
board = ${common_env_data.board}
|
||||
build_type = release
|
||||
board_build.filesystem = littlefs
|
||||
build_src_filter = +<*> -<main.cpp> +<../test/tests*.cpp>
|
||||
|
||||
[env:gravity32-release]
|
||||
framework = ${common_env_data.framework}
|
||||
@ -116,6 +137,9 @@ build_flags =
|
||||
#-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}
|
||||
@ -125,13 +149,13 @@ 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
|
||||
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}
|
||||
@ -146,9 +170,9 @@ build_flags =
|
||||
${common_env_data.build_flags}
|
||||
-DLOG_LEVEL=5
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-DESP32C3
|
||||
-DESP32C3
|
||||
-DARDUINO_ESP32C3_DEV
|
||||
-DUSE_SERIAL0
|
||||
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps}
|
||||
${common_env_data.lib_deps32}
|
||||
@ -158,13 +182,79 @@ 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
|
||||
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:gravity32c3v1-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
|
||||
-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 =
|
||||
${common_env_data.lib_deps}
|
||||
${common_env_data.lib_deps32}
|
||||
lib_ignore =
|
||||
board = lolin_c3_mini
|
||||
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:gravity32s2-release]
|
||||
framework = ${common_env_data.framework}
|
||||
platform = ${common_env_data.platform32}
|
||||
upload_speed = ${common_env_data.upload_speed}
|
||||
monitor_speed = ${common_env_data.monitor_speed}
|
||||
extra_scripts = ${common_env_data.extra_scripts}
|
||||
build_unflags =
|
||||
${common_env_data.build_unflags}
|
||||
build_flags =
|
||||
-Wl,-Map,output.map
|
||||
${common_env_data.build_flags}
|
||||
-DLOG_LEVEL=5
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-DESP32S2
|
||||
-DARDUINO_ESP32S2_DEV
|
||||
#-DUSE_SERIAL_PINS # Use the TX/RX pins for the serial port
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps}
|
||||
lib_ignore =
|
||||
board = lolin_s2_mini
|
||||
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-debug]
|
||||
framework = ${common_env_data.framework}
|
||||
@ -178,13 +268,13 @@ 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
|
||||
-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 =
|
||||
@ -193,8 +283,8 @@ build_flags =
|
||||
-DLOG_LEVEL=6
|
||||
-DCORE_DEBUG_LEVEL=5
|
||||
-DJTAG_DEBUG
|
||||
-DESP32C3
|
||||
-DUSE_SERIAL0
|
||||
-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 =
|
||||
@ -206,42 +296,44 @@ 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
|
||||
html/calibration.min.htm
|
||||
html/config.min.htm
|
||||
html/firmware.min.htm
|
||||
html/format.min.htm
|
||||
html/about.min.htm
|
||||
html/index.min.htm
|
||||
html/test.min.htm
|
||||
|
||||
; [env:gravity32s2-release]
|
||||
; framework = ${common_env_data.framework}
|
||||
; platform = ${common_env_data.platform32}
|
||||
; upload_speed = ${common_env_data.upload_speed}
|
||||
; monitor_speed = ${common_env_data.monitor_speed}
|
||||
; extra_scripts = ${common_env_data.extra_scripts}
|
||||
; build_unflags =
|
||||
; ${common_env_data.build_unflags}
|
||||
; build_flags =
|
||||
; -Wl,-Map,output.map
|
||||
; ${common_env_data.build_flags}
|
||||
; -DLOG_LEVEL=5
|
||||
; -DCORE_DEBUG_LEVEL=0
|
||||
; -DESP32S2
|
||||
; -DARDUINO_ESP32S2_DEV
|
||||
; lib_deps =
|
||||
; ${common_env_data.lib_deps}
|
||||
; ${common_env_data.lib_deps32}
|
||||
; lib_ignore =
|
||||
; board = lolin_s2_mini
|
||||
; build_type = debug
|
||||
; board_build.partitions = part32.csv
|
||||
; board_build.filesystem = littlefs
|
||||
; board_build.embed_txtfiles =
|
||||
; html/calibration.min.htm
|
||||
; html/config.min.htm
|
||||
; html/firmware.min.htm
|
||||
; html/format.min.htm
|
||||
; html/about.min.htm
|
||||
; html/index.min.htm
|
||||
; html/test.min.htm
|
||||
# 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
|
@ -45,6 +45,12 @@ def after_build(source, target, env):
|
||||
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"
|
||||
print( "Copy file : " + source + " -> " + target )
|
||||
shutil.copyfile( source, target )
|
||||
|
||||
if name == "gravity32s2-release" :
|
||||
target = dir + "/bin/firmware32s2.bin"
|
||||
source = dir + "/.pio/build/" + name + "/firmware.bin"
|
||||
@ -56,6 +62,16 @@ def after_build(source, target, env):
|
||||
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): ")
|
||||
env.AddPostAction("buildprog", after_build)
|
||||
|
@ -41,9 +41,15 @@ BleSender::BleSender(const char* color) {
|
||||
|
||||
// boost power to maximum, these might be changed once battery life using BLE
|
||||
// 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_ADV, ESP_PWR_LVL_P9);
|
||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, ESP_PWR_LVL_P9);
|
||||
#endif
|
||||
|
||||
_advertising = BLEDevice::getAdvertising();
|
||||
_color = color;
|
||||
|
@ -27,9 +27,6 @@ SOFTWARE.
|
||||
#include <calc.hpp>
|
||||
#include <main.hpp>
|
||||
|
||||
//
|
||||
// Use values to derive a formula
|
||||
//
|
||||
int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
||||
int formulaBufferSize, int order) {
|
||||
int noAngles = 0;
|
||||
@ -118,10 +115,6 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
|
||||
return ERR_FORMULA_INTERNAL;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculates gravity according to supplied formula, compatible with
|
||||
// iSpindle/Fermentrack formula
|
||||
//
|
||||
double calculateGravity(double angle, double temp, const char *tempFormula) {
|
||||
const char *formula = myConfig.getGravityFormula();
|
||||
|
||||
@ -163,12 +156,10 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Do a standard gravity temperature correction. This is a simple way to adjust
|
||||
// for differnt worth temperatures. This function uses C as temperature.
|
||||
//
|
||||
// Source: https://homebrewacademy.com/hydrometer-temperature-correction/
|
||||
//
|
||||
double gravityTemperatureCorrectionC(double gravitySG, double tempC,
|
||||
double calTempC) {
|
||||
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
|
||||
|
@ -148,14 +148,20 @@ class Config {
|
||||
#elif defined(ESP32C3)
|
||||
float _voltageFactor = 1.3;
|
||||
#elif defined(ESP32S2)
|
||||
float _voltageFactor = 1.3;
|
||||
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;
|
||||
int _sleepInterval = 900;
|
||||
#if defined(FLOATY)
|
||||
bool _gyroTemp = true;
|
||||
#else
|
||||
bool _gyroTemp = false;
|
||||
#endif
|
||||
bool _storageSleep = false;
|
||||
|
||||
// Wifi Config
|
||||
@ -211,8 +217,12 @@ class Config {
|
||||
|
||||
const bool isGyroTemp() { return _gyroTemp; }
|
||||
void setGyroTemp(bool b) {
|
||||
#if defined(FLOATY)
|
||||
// Floaty hardware dont have a temp sensor, uses gyro temperature
|
||||
#else
|
||||
_gyroTemp = b;
|
||||
_saveNeeded = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
const bool isStorageSleep() { return _storageSleep; }
|
||||
|
73
src/gyro.cpp
@ -30,22 +30,41 @@ MPU6050 accelgyro;
|
||||
#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
|
||||
// calibration
|
||||
// #define GYRO_CALIBRATE_STARTUP // Will calibrate sensor at startup
|
||||
|
||||
//
|
||||
// Initialize the sensor chip.
|
||||
//
|
||||
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)
|
||||
Log.verbose(F("GYRO: Setting up hardware." CR));
|
||||
#endif
|
||||
Wire.begin(PIN_SDA, PIN_SCL);
|
||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having
|
||||
// compilation difficulties
|
||||
Wire.setClock(clock); // 400kHz I2C clock.
|
||||
|
||||
uint8_t id = accelgyro.getDeviceID();
|
||||
|
||||
if (id != 0x34 && id != 0x38) { // Allow both MPU6050 and MPU6000
|
||||
if (id != 0x34 && id != 0x38) { // Allow both MPU6050 and MPU6500
|
||||
writeErrorLog("GYRO: Failed to connect to gyro, is it connected?");
|
||||
_sensorConnected = false;
|
||||
} else {
|
||||
@ -68,11 +87,6 @@ bool GyroSensor::setup() {
|
||||
accelgyro.setIntDataReadyEnabled(true);
|
||||
#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
|
||||
// config.
|
||||
_calibrationOffset = myConfig.getGyroCalibration();
|
||||
@ -81,19 +95,17 @@ bool GyroSensor::setup() {
|
||||
return _sensorConnected;
|
||||
}
|
||||
|
||||
//
|
||||
// Set sensor in sleep mode to conserve battery
|
||||
//
|
||||
void GyroSensor::enterSleep() {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Setting up hardware." CR));
|
||||
#endif
|
||||
#if defined(FLOATY)
|
||||
digitalWrite(PIN_VCC, LOW);
|
||||
#else
|
||||
accelgyro.setSleepEnabled(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Do a number of reads to get a more stable value.
|
||||
//
|
||||
void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
||||
const int delayTime) {
|
||||
RawGyroDataL average = {0, 0, 0, 0, 0, 0};
|
||||
@ -105,7 +117,8 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
||||
|
||||
// Set some initial values
|
||||
#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);
|
||||
min.temp = accelgyro.getTemperature();
|
||||
max = min;
|
||||
@ -179,9 +192,6 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Calcuate the angles (tilt)
|
||||
//
|
||||
float GyroSensor::calculateAngle(RawGyroData &raw) {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Calculating the angle." CR));
|
||||
@ -209,9 +219,6 @@ float GyroSensor::calculateAngle(RawGyroData &raw) {
|
||||
return vY;
|
||||
}
|
||||
|
||||
//
|
||||
// Check if the values are high that indicate that the sensor is moving.
|
||||
//
|
||||
bool GyroSensor::isSensorMoving(RawGyroData &raw) {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Checking for sensor movement." CR));
|
||||
@ -229,9 +236,6 @@ bool GyroSensor::isSensorMoving(RawGyroData &raw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Read the tilt angle from the gyro.
|
||||
//
|
||||
bool GyroSensor::read() {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Getting new gyro position." CR));
|
||||
@ -270,9 +274,6 @@ bool GyroSensor::read() {
|
||||
return _validValue;
|
||||
}
|
||||
|
||||
//
|
||||
// Dump the stored calibration values.
|
||||
//
|
||||
void GyroSensor::dumpCalibration() {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Accel offset\t%d\t%d\t%d" CR), _calibrationOffset.ax,
|
||||
@ -282,9 +283,6 @@ void GyroSensor::dumpCalibration() {
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Update the sensor with out calculated offsets.
|
||||
//
|
||||
void GyroSensor::applyCalibration() {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Applying calibration offsets to sensor." CR));
|
||||
@ -306,9 +304,6 @@ void GyroSensor::applyCalibration() {
|
||||
accelgyro.setZGyroOffset(_calibrationOffset.gz);
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the offsets for calibration.
|
||||
//
|
||||
void GyroSensor::calibrateSensor() {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Calibrating sensor" CR));
|
||||
@ -330,14 +325,10 @@ void GyroSensor::calibrateSensor() {
|
||||
_calibrationOffset.gy = accelgyro.getYGyroOffset();
|
||||
_calibrationOffset.gz = accelgyro.getZGyroOffset();
|
||||
|
||||
// Save the calibrated values
|
||||
myConfig.setGyroCalibration(_calibrationOffset);
|
||||
myConfig.saveFile();
|
||||
}
|
||||
|
||||
//
|
||||
// Calibrate the device.
|
||||
//
|
||||
void GyroSensor::debug() {
|
||||
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
|
||||
Log.verbose(F("GYRO: Debug - Clock src %d." CR),
|
||||
|
@ -120,8 +120,7 @@ void checkResetReason() {
|
||||
}
|
||||
|
||||
Log.notice(F("HELP: Last reset cause '%s' (%d)" CR), rStr.c_str(), r);
|
||||
|
||||
#warning "TODO: Implement logging of crashes for esp32"
|
||||
// Havent found a good way to get exception cause from an ESP32
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -238,8 +237,29 @@ void printBuildOptions() {
|
||||
|
||||
SerialDebug::SerialDebug(const uint32_t serialSpeed) {
|
||||
// Start serial with auto-detected rate (default to defined BAUD)
|
||||
#if defined(USE_SERIAL_PINS) && defined(ESP8266)
|
||||
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
|
||||
|
||||
EspSerial.println("Serial connection established");
|
||||
EspSerial.setDebugOutput(true);
|
||||
getLog()->begin(LOG_LEVEL, &EspSerial, true);
|
||||
getLog()->setPrefix(printTimestamp);
|
||||
getLog()->notice(F("SDBG: Serial logging started at %u." CR), serialSpeed);
|
||||
@ -251,11 +271,26 @@ void printTimestamp(Print* _logOutput, int _logLevel) {
|
||||
_logOutput->print(c);
|
||||
}
|
||||
|
||||
bool checkPinConnected() {
|
||||
#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_A0, INPUT);
|
||||
pinMode(PIN_VOLT, INPUT);
|
||||
#else
|
||||
pinMode(PIN_A0, INPUT_PULLDOWN);
|
||||
pinMode(PIN_VOLT, INPUT_PULLDOWN);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -263,7 +298,7 @@ void BatteryVoltage::read() {
|
||||
// The analog pin can only handle 3.3V maximum voltage so we need to reduce
|
||||
// the voltage (from max 5V)
|
||||
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 ESP32 has an ADC range of 0-4095 and a maximum voltage of 3.3V
|
||||
|
@ -43,6 +43,9 @@ void checkResetReason();
|
||||
// Sleep mode
|
||||
void deepSleep(int t);
|
||||
|
||||
// Force config mode
|
||||
bool checkPinConnected();
|
||||
|
||||
// Show build options
|
||||
void printBuildOptions();
|
||||
|
||||
|
21
src/main.cpp
@ -133,11 +133,6 @@ void setup() {
|
||||
LOG_PERF_START("main-setup");
|
||||
runtimeMillis = millis();
|
||||
|
||||
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
|
||||
// Add a delay so that serial is started.
|
||||
// delay(3000);
|
||||
#endif
|
||||
|
||||
// Main startup
|
||||
#if defined(ESP8266)
|
||||
Log.notice(F("Main: Started setup for %s." CR),
|
||||
@ -163,6 +158,11 @@ void setup() {
|
||||
myAdvancedConfig.loadFile();
|
||||
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
|
||||
#if defined(ESP8266)
|
||||
ESP.wdtDisable();
|
||||
@ -256,11 +256,8 @@ void setup() {
|
||||
millis(); // Dont include time for wifi connection
|
||||
}
|
||||
|
||||
//
|
||||
// Main loop that does gravity readings and push data to targets
|
||||
//
|
||||
// Return true if gravity reading was successful
|
||||
//
|
||||
bool loopReadGravity() {
|
||||
float angle = 0;
|
||||
|
||||
@ -334,15 +331,14 @@ bool loopReadGravity() {
|
||||
}
|
||||
return true;
|
||||
} 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;
|
||||
}
|
||||
|
||||
//
|
||||
// Wrapper for loopGravity that only calls every 200ms so that we dont overload
|
||||
// this.
|
||||
//
|
||||
void loopGravityOnInterval() {
|
||||
if (abs((int32_t)(millis() - loopMillis)) > interval) {
|
||||
loopReadGravity();
|
||||
@ -358,9 +354,6 @@ void loopGravityOnInterval() {
|
||||
|
||||
bool skipRunTimeLog = false;
|
||||
|
||||
//
|
||||
// Main loop that determines if device should go to sleep
|
||||
//
|
||||
void goToSleep(int sleepInterval) {
|
||||
float volt = myBatteryVoltage.getVoltage();
|
||||
float runtime = (millis() - runtimeMillis);
|
||||
|
61
src/main.hpp
@ -38,14 +38,20 @@ enum RunMode {
|
||||
extern RunMode runMode;
|
||||
|
||||
#if defined(ESP8266)
|
||||
// Hardware config for ESP8266-d1, iSpindel hardware
|
||||
// ------------------------------------------------------
|
||||
#include <LittleFS.h>
|
||||
#define ESP_RESET ESP.reset
|
||||
#define PIN_SDA D3
|
||||
#define PIN_SCL D4
|
||||
#define PIN_CFG1 D8
|
||||
#define PIN_CFG2 D7
|
||||
#define PIN_DS D6
|
||||
#define PIN_LED 2
|
||||
// #define PIN_A0 A0
|
||||
#define PIN_VOLT PIN_A0
|
||||
#elif defined(ESP32C3)
|
||||
// Hardware config for ESP32-c3-mini, iSpindel hardware
|
||||
// ------------------------------------------------------
|
||||
#include <FS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
@ -60,14 +66,17 @@ extern RunMode runMode;
|
||||
#else
|
||||
#define PIN_SDA 7
|
||||
#define PIN_SCL 6
|
||||
#endif
|
||||
#endif // JTAG_DEBUG
|
||||
#define PIN_CFG1 A5
|
||||
#define PIN_CFG2 A4
|
||||
#define PIN_DS A3
|
||||
#define PIN_A0 A0
|
||||
#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)
|
||||
#elif defined(ESP32S2)
|
||||
// Hardware config for ESP32-s2-mini, iSpindel hardware
|
||||
// ------------------------------------------------------
|
||||
#include <FS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
@ -75,13 +84,35 @@ extern RunMode runMode;
|
||||
#define ESPhttpUpdate httpUpdate
|
||||
#define ESP_RESET ESP.restart
|
||||
#define ESP8266WebServer WebServer
|
||||
#define PIN_SDA SDA
|
||||
#define PIN_SCL SCL
|
||||
#define PIN_SDA A17
|
||||
#define PIN_SCL A15
|
||||
#define PIN_CFG1 A11
|
||||
#define PIN_CFG2 A10
|
||||
#define PIN_DS A8
|
||||
#define PIN_A0 A2
|
||||
#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>
|
||||
|
||||
@ -92,13 +123,17 @@ extern RunMode runMode;
|
||||
#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_A0 A4
|
||||
#define PIN_VOLT PIN_A0
|
||||
#endif
|
||||
|
||||
#if defined(ESP32C3) && defined(USE_SERIAL0)
|
||||
#define EspSerial Serial0
|
||||
// #warning "Using Serial0 for output RX/TX pins on ESP32C3"
|
||||
#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
|
||||
|
@ -80,9 +80,6 @@ const char mqttFormat[] PROGMEM =
|
||||
"ispindel/${mdns}/interval:${sleep-interval}|"
|
||||
"ispindel/${mdns}/RSSI:${rssi}|";
|
||||
|
||||
//
|
||||
// Initialize the variables
|
||||
//
|
||||
void TemplatingEngine::initialize(float angle, float gravitySG,
|
||||
float corrGravitySG, float tempC,
|
||||
float runTime) {
|
||||
@ -138,10 +135,9 @@ void TemplatingEngine::initialize(float angle, float gravitySG,
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Create the data using defined template.
|
||||
//
|
||||
const char* TemplatingEngine::create(TemplatingEngine::Templates idx) {
|
||||
// the useDefaultTemplate param is there to support unit tests.
|
||||
const char* TemplatingEngine::create(TemplatingEngine::Templates idx,
|
||||
bool useDefaultTemplate) {
|
||||
String fname;
|
||||
_baseTemplate.reserve(600);
|
||||
|
||||
@ -169,15 +165,16 @@ const char* TemplatingEngine::create(TemplatingEngine::Templates idx) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Add code to load templates from disk if they exist.
|
||||
File file = LittleFS.open(fname, "r");
|
||||
if (file) {
|
||||
char buf[file.size() + 1];
|
||||
memset(&buf[0], 0, file.size() + 1);
|
||||
file.readBytes(&buf[0], file.size());
|
||||
_baseTemplate = String(&buf[0]);
|
||||
file.close();
|
||||
Log.notice(F("TPL : Template loaded from disk %s." CR), fname.c_str());
|
||||
if (!useDefaultTemplate) {
|
||||
File file = LittleFS.open(fname, "r");
|
||||
if (file) {
|
||||
char buf[file.size() + 1];
|
||||
memset(&buf[0], 0, file.size() + 1);
|
||||
file.readBytes(&buf[0], file.size());
|
||||
_baseTemplate = String(&buf[0]);
|
||||
file.close();
|
||||
Log.notice(F("TPL : Template loaded from disk %s." CR), fname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#if LOG_LEVEL == 6
|
||||
|
@ -200,7 +200,8 @@ class TemplatingEngine {
|
||||
}
|
||||
void initialize(float angle, float gravitySG, float corrGravitySG,
|
||||
float tempC, float runTime);
|
||||
const char *create(TemplatingEngine::Templates idx);
|
||||
const char *create(TemplatingEngine::Templates idx,
|
||||
bool useDefaultTemplate = false);
|
||||
};
|
||||
|
||||
#endif // SRC_TEMPLATING_HPP_
|
||||
|
@ -35,15 +35,7 @@ DallasTemperature mySensors(&myOneWire);
|
||||
|
||||
TempSensor myTempSensor;
|
||||
|
||||
//
|
||||
// Setup DS18B20 temp sensor. Doing setup is not that time consuming.
|
||||
//
|
||||
void TempSensor::setup() {
|
||||
#if defined(SIMULATE_TEMP)
|
||||
hasSensors = true;
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL == 6 && !defined(TSEN_DISABLE_LOGGING)
|
||||
Log.verbose(F("TSEN: Looking for temp sensors." CR));
|
||||
#endif
|
||||
@ -66,14 +58,7 @@ void TempSensor::setup() {
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieving value from sensor, value is in Celcius
|
||||
//
|
||||
float TempSensor::getValue(bool useGyro) {
|
||||
#if defined(SIMULATE_TEMP)
|
||||
return 21;
|
||||
#endif
|
||||
|
||||
if (useGyro) {
|
||||
// When using the gyro temperature only the first read value will be
|
||||
// accurate so we will use this for processing.
|
||||
|
@ -90,7 +90,9 @@ void WebServerHandler::webHandleConfig() {
|
||||
#elif defined(ESP32C3)
|
||||
doc[PARAM_PLATFORM] = "esp32c3";
|
||||
#elif defined(ESP32S2)
|
||||
doc[PARAM_PLATFORM] = "esp32s3";
|
||||
doc[PARAM_PLATFORM] = "esp32s2";
|
||||
#elif defined(ESP32LITE)
|
||||
doc[PARAM_PLATFORM] = "esp32lite";
|
||||
#else // esp32 mini
|
||||
doc[PARAM_PLATFORM] = "esp32";
|
||||
#endif
|
||||
@ -273,7 +275,9 @@ void WebServerHandler::webHandleStatus() {
|
||||
#elif defined(ESP32C3)
|
||||
doc[PARAM_PLATFORM] = "esp32c3";
|
||||
#elif defined(ESP32S2)
|
||||
doc[PARAM_PLATFORM] = "esp32s3";
|
||||
doc[PARAM_PLATFORM] = "esp32s2";
|
||||
#elif defined(ESP32LITE)
|
||||
doc[PARAM_PLATFORM] = "esp32lite";
|
||||
#else // esp32 mini
|
||||
doc[PARAM_PLATFORM] = "esp32";
|
||||
#endif
|
||||
|
@ -118,7 +118,7 @@ void WifiConnection::startPortal() {
|
||||
ESP_WMParameter deviceName(mdns.c_str());
|
||||
myWifiManager->addParameter(&deviceName);
|
||||
|
||||
#if defined(ESP32C3)
|
||||
#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
|
||||
@ -157,7 +157,7 @@ void WifiConnection::connectAsync(int wifiIndex) {
|
||||
WiFi.persistent(true);
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
#if defined(ESP32C3)
|
||||
#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
|
||||
@ -303,6 +303,8 @@ bool WifiConnection::updateFirmware() {
|
||||
serverPath += "firmware32c3.bin";
|
||||
#elif defined(ESP32S2)
|
||||
serverPath += "firmware32s2.bin";
|
||||
#elif defined(ESP32LITE)
|
||||
serverPath += "firmware32lite.bin";
|
||||
#else // defined (ESP32)
|
||||
serverPath += "firmware32.bin";
|
||||
#endif
|
||||
@ -428,6 +430,8 @@ bool WifiConnection::checkFirmwareVersion() {
|
||||
}
|
||||
http.end();
|
||||
|
||||
if (_newFirmware) Log.notice(F("WIFI: Found new version." CR));
|
||||
|
||||
#if LOG_LEVEL == 6
|
||||
Log.verbose(F("WIFI: OTA found new version %s." CR),
|
||||
_newFirmware ? "true" : "false");
|
||||
|
@ -84,7 +84,7 @@ GET: /api/status
|
||||
Retrieve the current device status via an HTTP GET command. Payload is in JSON format.
|
||||
|
||||
* ``temp-format`` can be either ``C`` or ``F``
|
||||
* ``platform`` can be either ``esp8266``, ``esp32c3``, ``esp32s2`` 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
|
||||
|
||||
|
@ -30,13 +30,35 @@ In the platformio config there are 3 targets defined
|
||||
* gravity-debug; Maximum logging for trouble shooting, deep sleep is disabled.
|
||||
* gravity-release; Standard release
|
||||
* gravity32-release: Version for ESP32 mini.
|
||||
* gravity32-c3-release: Version for ESP32 C3 mini.
|
||||
* gravity32-s2-release: Version for ESP32 S2 mini.
|
||||
* gravity32c3-release: Version for ESP32 C3 mini v2.1+.
|
||||
* gravity32c3v1-release: Version for ESP32 C3 mini v1.0.
|
||||
* gravity32s2-release: Version for ESP32 S2 mini.
|
||||
* gravity32lite-release: Version for ESP32 lite (Floaty hardware).
|
||||
|
||||
.. 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.
|
||||
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
|
||||
================
|
||||
@ -92,4 +114,9 @@ This is a list of C++ defines that is used to enable/disable functions in the co
|
||||
- Password to the SSID
|
||||
* - CFG_APPVER
|
||||
- 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)
|
||||
|
@ -48,6 +48,8 @@ exclude_patterns = []
|
||||
# a list of builtin themes.
|
||||
#
|
||||
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,
|
||||
# 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
|
||||
- Sleep mode has been disabled in the web interface
|
||||
- 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
|
||||
@ -39,7 +39,7 @@ connection. It will show 0 if data has not been collected yet.
|
||||
|
||||
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 occurred while in `gravity mode`. From v1.1 it will also detect
|
||||
any abnormal restarts or crashes and record these in the logfile.
|
||||
any abnormal restarts or crashes and record these in the logfile (this applies to esp8266 only).
|
||||
|
||||
|
||||
Configuration
|
||||
|
@ -136,6 +136,11 @@ The main features
|
||||
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.
|
||||
|
||||
* **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**
|
||||
|
||||
I've also create a small library to measure execution code in some areas of the code that i know is time consuming. This
|
||||
@ -152,20 +157,45 @@ The main features
|
||||
|
||||
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
|
||||
------------
|
||||
|
||||
The long term battery test has now been completed. Using a 2200 mA battery and sending data every 5 minutes to a local server on my network. The battery lasted 47 days which is excellent battery life.
|
||||
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
|
||||
-----------
|
||||
|
@ -3,6 +3,11 @@
|
||||
Hardware
|
||||
########
|
||||
|
||||
I'm not a hardware designer so I would recommend the following resources for more in depth information on this topic.
|
||||
|
||||
* `Cherry Philip Hardware design <https://github.com/cherryphilip74/iSpindel-PCB>`_
|
||||
* `OpenSource Distilling <https://www.opensourcedistilling.com/ispindel>`_
|
||||
|
||||
iSpindle based on esp8266
|
||||
=========================
|
||||
|
||||
@ -23,20 +28,17 @@ Schema for esp8266 build
|
||||
iSpindle based on esp32
|
||||
=======================
|
||||
|
||||
I've experimented with porting my software version to esp32 and this is a selection of options i have been testing.
|
||||
|
||||
.. warning::
|
||||
Work to support esp32s2 is still ongoing, ESP32-mini and ESP32c3-mini is confirmed to be working. However I would recommend the C3 variant.
|
||||
Gravitymon supports a number of ESP32 boards that offers bluetooth support.
|
||||
|
||||
.. image:: images/esp32_hardware.jpg
|
||||
:width: 500
|
||||
:alt: iSpindle esp32 hardware options
|
||||
|
||||
* esp32 mini, this was the first board i tried which is a smaller form factor of the first generetion esp32 with 2 cores. Slow on connecting to wifi is the main downside.
|
||||
* esp32c3 mini, a newer version based on the latest risc v7 architecture, is seen as the replacement for the esp8266 with bluetooth support.
|
||||
* 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 and s2 are prefered). The esp32 mini is a larger formfactor and can be hard to fit into the tube.
|
||||
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
|
||||
@ -46,7 +48,7 @@ It's possible to use this PCB and mount an ESP32 mini on top of that (c3 and s2
|
||||
ESP32c3 mini
|
||||
++++++++++++
|
||||
|
||||
This is model is now fully supported by gravitymon.
|
||||
This is model is fully supported by gravitymon.
|
||||
|
||||
.. image:: images/ispindel_esp32c3.jpg
|
||||
:width: 500
|
||||
@ -61,7 +63,7 @@ Here is an image of where I added the resistor for the voltage divider.
|
||||
ESP32s2 mini
|
||||
++++++++++++
|
||||
|
||||
Work in progress...
|
||||
This is model is fully supported by gravitymon. Same setup as for ESP32C3 mini.
|
||||
|
||||
ESP32 d1 mini
|
||||
+++++++++++++
|
||||
@ -76,7 +78,7 @@ Schema for esp32 build
|
||||
++++++++++++++++++++++
|
||||
|
||||
.. note::
|
||||
This schema assumes that an ESP32 D1 Mini (pin compatible with ESP8266 D1 Mini is used). The ESP32 has two rows of pins but
|
||||
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.
|
||||
|
||||
@ -85,7 +87,7 @@ Schema for esp32 build
|
||||
: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.
|
||||
@ -104,3 +106,35 @@ The reed switch is the glass tube visible under the esp8266.
|
||||
: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 |
BIN
src_docs/source/images/gravitymon_logo.png
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
src_docs/source/images/gravitymon_logo_s.png
Normal file
After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 127 KiB |
@ -3,57 +3,18 @@
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to GravityMon's documentation!
|
||||
######################################
|
||||
Welcome to GravityMon
|
||||
#####################
|
||||
|
||||
.. note::
|
||||
This documentation reflects **v1.2 - beta 1**. Last updated 2022-10-15
|
||||
|
||||
User interface overview
|
||||
-----------------------
|
||||
|
||||
This animation shows how the user interface is structured, it reflects an older version but the structure is the same.
|
||||
|
||||
.. image:: images/gravitymon.gif
|
||||
:width: 800
|
||||
:alt: User Inteface Walkthrough
|
||||
|
||||
.. _main_features:
|
||||
|
||||
Main features
|
||||
-------------
|
||||
|
||||
* Support either an ESP8266-d1-mini, ESP32-mini or ESP32C3-mini board (see :ref:`hardware`)
|
||||
* Operates in two modes gravity monitoring and configuration mode
|
||||
* Gravity mode is comparable to how the iSpindle works when collecting data
|
||||
* Configuration mode has a modern HTML5 based web UI. No need to start the access point to change settings
|
||||
* Offloading some of the functionality to run in the web browser, this allows for more advanced features.
|
||||
* REST API to enable scripted configuration
|
||||
* Send data to multiple endpoints and services at once (2xHTTP POST, HTTP GET, MQTT, INFLUXDB2)
|
||||
* Directly test all endpoints from user interface with feedback to simplify troubleshooting
|
||||
* Complete format customization for all endpoints using templates (don't really need to change the software to support new services)
|
||||
* Setup guides for how to send data to many popular services. Currently 10+ are documented
|
||||
* Automatic temperature adjustment of gravity (just tick a checkbox)
|
||||
* OTA support from webserver
|
||||
* Firmware update via web interface
|
||||
* Built in function to create gravity formulas, no need for additional software, just enter tilt/gravity and let GravityMon creates a formula
|
||||
* Visual graph showing how formula will be interpreted based on entered values
|
||||
* Using the temperature sensor in gyro instead of DS18B20 (faster)
|
||||
* SSL support in all endpoints (no certificate validation due to limitations on esp8266).
|
||||
* Built in performance measurements (used to optimize code)
|
||||
* Storage mode when placed on cap (indefinite sleep)
|
||||
* Customize various hardware parameters to optimize device functionality.
|
||||
|
||||
For a complete breakdown see the :ref:`functionality`
|
||||
|
||||
.. note::
|
||||
If you are missing some feature, please reach out on `Github <https://github.com/mp-se/gravitymon/discussions>`_ or `homebrewtalk.com <https://www.homebrewtalk.com/threads/replacement-firmware-for-ispindel-gravitymon.698058/>`_
|
||||
This documentation reflects **v1.2.0**. Last updated 2022-12-06
|
||||
|
||||
What is GravityMon?
|
||||
--------------------
|
||||
|
||||
GravityMon is used to measure gravity and temperature during fermentation of beer and report the progress. The graph below is
|
||||
an example on how the fermentation process can be tracked. The graph has been rendered using Fermentrack.
|
||||
GravityMon is a electronic hydrometer software that can be used to measure gravity and temperature during fermentation of beer and report the progress to a number of external
|
||||
services. Is uses a gyro to measure the gravity since there is a correlation between gravity an the density of the fluid. Based on the density the hydrometer will float at a different angle.
|
||||
The graph below is an example on how the fermentation process can be tracked. The graph has been rendered using Fermentrack.
|
||||
|
||||
.. image:: images/fermentation.png
|
||||
:width: 500
|
||||
@ -61,10 +22,11 @@ an example on how the fermentation process can be tracked. The graph has been re
|
||||
|
||||
GravityMon is a replacement firmware for the iSpindle and uses the same hardware configuration and is 100% compatible. It
|
||||
implements a lot of the features that has been requested in the original iSpindle project but never implemented for
|
||||
various reasons. Here is a list of :ref:`main_features`.
|
||||
various reasons.
|
||||
|
||||
From v0.9 the firmware also supports a iSpindle built using an ESP32 d1 mini (pin compatible with esp8266). Currently this is an experimental
|
||||
version but since it has more memory and processing capacity it could support more functions. See :ref:`hardware`.
|
||||
The firmware also supports a iSpindle built using an ESP32 which is pin compatible with esp8266, currently there are 3 options that are
|
||||
supported ESP32-D1 mini, ESP32-C3 mini, ESP32-S2 mini, ESP32 lite (floaty). See :ref:`hardware`. The more modern hardware will allow better support for SSL and
|
||||
other memory intensive functions.
|
||||
|
||||
I started GravityMon because I like to create software and wanted to do some microcontroller programming. I had done a few
|
||||
projects based on esp8266 and also started to brew beer so this combination was quite natural.
|
||||
@ -77,18 +39,19 @@ My approach to this software is a little different from that the original iSpind
|
||||
The github repository can be found here; `GravityMon on Github <https://github.com/mp-se/gravitymon>`_
|
||||
|
||||
.. note::
|
||||
I don't take responsibility for any errors or issues caused by the software. The software is provided as-is. I will however
|
||||
try my best to fix issues that might occur.
|
||||
I don't take responsibility for any errors or issues caused by the software or hardware.
|
||||
The software is provided as-is. I will however try my best to fix issues that might occur.
|
||||
|
||||
I have tested this software on 40+ brews with good results.
|
||||
|
||||
User interface overview
|
||||
-----------------------
|
||||
|
||||
Documentation for older versions
|
||||
--------------------------------
|
||||
|
||||
* Docs for: `v1.0 <https://mp-se.github.io/gravitymon/v1.0/index.html>`_
|
||||
* Docs for: `v0.9 <https://mp-se.github.io/gravitymon/v0.9/index.html>`_
|
||||
This animation shows how the features of the user interface. It's for an older version but the main features are the same.
|
||||
|
||||
.. image:: images/gravitymon.gif
|
||||
:width: 800
|
||||
:alt: User Inteface Walkthrough
|
||||
|
||||
Software architecture
|
||||
---------------------
|
||||
@ -174,13 +137,12 @@ the following libraries and without these this would have been much more difficu
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
intro
|
||||
releases
|
||||
functionality
|
||||
intro
|
||||
installation
|
||||
configuration
|
||||
troubleshooting
|
||||
q_and_a
|
||||
releases
|
||||
hardware
|
||||
formula
|
||||
services
|
||||
advanced
|
||||
@ -188,8 +150,9 @@ the following libraries and without these this would have been much more difficu
|
||||
data
|
||||
compiling
|
||||
contributing
|
||||
hardware
|
||||
license
|
||||
troubleshooting
|
||||
q_and_a
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
@ -3,11 +3,13 @@
|
||||
Installation
|
||||
------------
|
||||
|
||||
You have these 3 options for flashing this firmware.
|
||||
You have these 5 options for flashing this firmware.
|
||||
|
||||
* Brewflasher via USB serial
|
||||
* Brewflasher WEB via USB serial
|
||||
* Esptool via USB serial
|
||||
* iSpindel web interface
|
||||
* iSpindel web interface (only ESP8266)
|
||||
* Build from source and flash via VSCode + Platformio
|
||||
|
||||
Brewflasher
|
||||
===========
|
||||
@ -16,6 +18,13 @@ The preferred option for flashing GravityMon is using BrewFlasher, its a tools t
|
||||
on both Windows and Mac. You can download the latest version from here: `Brewflasher <https://www.brewflasher.com/>`_ there is also a web based version
|
||||
available here `Brewflasher WEB <https://web.brewflasher.com/>`_.
|
||||
|
||||
In order to flash an C3 board you will need Brewflasher 1.5 or newer.
|
||||
|
||||
.. note::
|
||||
The S2 and C3 chips might need to be put in flash mode before flashing can be done. Hold the button on the opposite side from the RST button,
|
||||
press the RST button and release it before the first button you pressed. This should force the chip into download mode. If you connect a serial
|
||||
terminal it should say "waiting for download".
|
||||
|
||||
.. image:: images/brewflasher.png
|
||||
:width: 600
|
||||
:alt: Serial output
|
||||
@ -36,14 +45,17 @@ In the /bin directory you will find 4 different firmware builds;
|
||||
|
||||
* **firmware32c3.bin**
|
||||
|
||||
This is the release build for an ESP32c3-mini variant. When flashing an ESP32 you also need the *partition32c3.bin* file that outlines the flash memory structure. Due to
|
||||
the size of the firmware we are using a custom partition setup.
|
||||
This is the release build for an ESP32c3-mini variant v2.1 or newer. When flashing an ESP32 you also need the *partition32c3.bin* file that outlines the flash memory structure. Due to
|
||||
the size of the firmware we are using a custom partition setup. If you have a v1.0 board use the firmware32c3v1.bin instead.
|
||||
|
||||
* **firmware32s2.bin**
|
||||
|
||||
This is the release build for an ESP32s2-mini variant. When flashing an ESP32 you also need the *partition32s2.bin* file that outlines the flash memory structure. Due to
|
||||
the size of the firmware we are using a custom partition setup.
|
||||
|
||||
* **firmware32lite.bin**
|
||||
|
||||
This is the release build for an ESP32lite which is used by the floaty build (clone).
|
||||
|
||||
Esptool (esp8266)
|
||||
=================
|
||||
@ -53,10 +65,14 @@ here; `esptool home page <https://docs.espressif.com/projects/esptool/en/latest/
|
||||
|
||||
Windows 10 should install a driver for the USB -> Serial automatically when you connect a esp8266.
|
||||
|
||||
The basic command for flashing on Windows is;
|
||||
The basic command for flashing an ESP8266 on Windows is;
|
||||
|
||||
``esptool.py --port COM4 write_flash 0x0 firmware.bin``
|
||||
|
||||
The basic command for flashing an ESP32C3 on Windows is;
|
||||
|
||||
``esptool.py --port COM6 write_flash --flash_mode dio 0x8000 .\partitions32c3.bin 0x10000 .\firmware32c3.bin``
|
||||
|
||||
If there are issues you can try do erase the flash first using this command;
|
||||
|
||||
``esptool.py --port COM4 erase_flash``
|
||||
@ -100,23 +116,6 @@ Serial Monitoring
|
||||
To check output from the device (logs) there are several tools out there. I found this simple tool in the Windows Store called ``Serial Port Monitoring``.
|
||||
Just select a baud rate of 115200, 8N1.
|
||||
|
||||
.. image:: images/serial.png
|
||||
:width: 600
|
||||
:alt: Serial output
|
||||
|
||||
On the build for esp32c3 the serial output is written to UART0 which is connected to the RX/TX pins on the chip. This way the serial output can be viewed
|
||||
without a connection to the USB port, convinient when running the device on battery power.
|
||||
|
||||
You need a USB to TTL cable that you connect the TX, RX and GND pins. **Dont connect the power pin** if you are powering the device from USB or Battery.
|
||||
|
||||
.. image:: images/usb-ttl.jpg
|
||||
:width: 300
|
||||
:alt: USB to TTL cable
|
||||
|
||||
.. image:: images/serial_esp32c3.jpg
|
||||
:width: 300
|
||||
:alt: Serial output ESP32c3
|
||||
|
||||
.. _setup_wifi:
|
||||
|
||||
Configuring WIFI
|
||||
|
@ -3,23 +3,31 @@
|
||||
Releases
|
||||
########
|
||||
|
||||
v1.2.0 - beta1
|
||||
==============
|
||||
v1.2.0
|
||||
======
|
||||
|
||||
Features
|
||||
++++++++
|
||||
* Added function to calcualate voltage factor based on measured value.
|
||||
* Updated battery estimation for the various esp32 boards.
|
||||
* Added support for the ESP32 lite board which is used in the Floaty Hydrometer variant.
|
||||
* Added support for the ESP32 C3 mini board
|
||||
* Added support for the ESP32 S2 mini board
|
||||
* Serial output is written to TX/RX pins instead of the USB connection for the ESP32c3. This way the serial console can be viewed when running on battery power.
|
||||
* Merged in unit tests and api tests into this project
|
||||
* Added option to download firmware updates from https://www.gravitymon.com
|
||||
|
||||
Documentation
|
||||
+++++++++++++
|
||||
* Added section about the Floaty hardware
|
||||
* Fixed schema errors in hardware section and linked PCB options
|
||||
* Updated hardware section with options for ESP32 boards
|
||||
* Updated installation instructions.
|
||||
|
||||
Issues adressed
|
||||
++++++++++++++++
|
||||
* BUG: The first portion of a format template was lost when doing conversion.
|
||||
|
||||
Documentation
|
||||
+++++++++++++
|
||||
* Updated hardware section with options for ESP32 boards
|
||||
* Updated installation instructions.
|
||||
|
||||
v1.1.1
|
||||
======
|
||||
* BUG: The text before the first variable was missed in the conversion of a format template.
|
||||
|
643
test/apitests.py
Normal file
@ -0,0 +1,643 @@
|
||||
import unittest, requests, json, time
|
||||
|
||||
ver = "1.2.0"
|
||||
|
||||
#host = "192.168.1.195"
|
||||
#id = "6ac6f6"
|
||||
|
||||
host = "192.168.1.106"
|
||||
id = "3045f4"
|
||||
|
||||
# python3 -m unittest -v apitests.API.test_bug_79
|
||||
# python3 -m unittest -v apitests
|
||||
|
||||
def call_api_post( path, json ):
|
||||
url = "http://" + host + path
|
||||
return requests.post( url, data=json )
|
||||
|
||||
def call_api_get( path ):
|
||||
url = "http://" + host + path
|
||||
return requests.get( url )
|
||||
|
||||
class API(unittest.TestCase):
|
||||
|
||||
# Do factory reset for testing
|
||||
def test_factory(self):
|
||||
r = call_api_get( "/api/status" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
r = call_api_get( "/api/factory?id=" + j["id"])
|
||||
time.sleep(4)
|
||||
|
||||
# Check that all parameters exist
|
||||
def test_status(self):
|
||||
r = call_api_get( "/api/status" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["wifi-ssid"], "@home")
|
||||
self.assertNotEqual(j["angle"], 0)
|
||||
self.assertNotEqual(j["gravity"], 2)
|
||||
self.assertNotEqual(j["temp-c"], 0)
|
||||
self.assertNotEqual(j["temp-f"], 0)
|
||||
self.assertNotEqual(j["battery"], 0)
|
||||
self.assertNotEqual(j["temp-format"], "")
|
||||
self.assertNotEqual(j["gravity-format"], "")
|
||||
self.assertNotEqual(j["sleep-mode"], True)
|
||||
self.assertNotEqual(j["rssi"], 0)
|
||||
self.assertNotEqual(j["app-ver"], "0.0.0")
|
||||
self.assertNotEqual(j["app-build"], "test")
|
||||
self.assertNotEqual(j["mdns"], "")
|
||||
self.assertNotEqual(j["platform"], "")
|
||||
self.assertNotEqual(j["runtime-average"], -1)
|
||||
|
||||
# Check that all parameters exist
|
||||
def test_config_1(self):
|
||||
j = { "id": id, "http-push": "https://push.me", "token": "mytoken", "token2": "mytoken2", "http-push2": "http://push.me", "http-push3": "http://push.me", "influxdb2-push": "http://influx.db", "influxdb2-org": "my-org",
|
||||
"influxdb2-bucket": "my-bucket", "influxdb2-auth": "my-secret", "mqtt-push": "mqtt.com", "mqtt-port": 1883, "mqtt-user": "my-user",
|
||||
"mqtt-pass": "my-pass", "http-push-h1": "header1", "http-push-h2": "header2", "http-push2-h1": "header1(2)", "http-push2-h2": "header2(2)" }
|
||||
r = call_api_post( "/api/config/push", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["http-push-h1"], "header1")
|
||||
self.assertEqual(j["http-push-h2"], "header2")
|
||||
self.assertEqual(j["http-push2-h1"], "header1(2)")
|
||||
self.assertEqual(j["http-push2-h2"], "header2(2)")
|
||||
|
||||
# Check that all parameters exist
|
||||
def test_config_2(self):
|
||||
j = { "id": id, "mdns": "gravmon", "temp-format": "C", "sleep-interval": 300 }
|
||||
r = call_api_post( "/api/config/device", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_config_3(self):
|
||||
j = { "id": id, "http-push": "https://push.me", "token": "mytoken", "token2": "mytoken2", "http-push2": "http://push.me", "http-push3": "http://push.me", "influxdb2-push": "http://influx.db", "influxdb2-org": "my-org",
|
||||
"influxdb2-bucket": "my-bucket", "influxdb2-auth": "my-secret", "mqtt-push": "mqtt.com", "mqtt-port": 1883, "mqtt-user": "my-user",
|
||||
"mqtt-pass": "my-pass" }
|
||||
r = call_api_post( "/api/config/push", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_config_4(self):
|
||||
j = { "id": id, "ota-url": "http://ota.url/path", "voltage-factor": 1.55, "temp-adjustment-value": -2, "gyro-temp": "on", "ble": "color" }
|
||||
r = call_api_post( "/api/config/hardware", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["ble"], "color")
|
||||
self.assertEqual(j["ota-url"], "http://ota.url/path")
|
||||
self.assertEqual(j["voltage-factor"], 1.55)
|
||||
self.assertEqual(j["temp-adjustment-value"], -2)
|
||||
self.assertEqual(j["gyro-temp"], True)
|
||||
# These are read only here, just checking them.
|
||||
self.assertNotEqual(j["gyro-calibration-data"]["ax"], 0.0001)
|
||||
self.assertNotEqual(j["gyro-calibration-data"]["ay"], 0.0001)
|
||||
self.assertNotEqual(j["gyro-calibration-data"]["az"], 0.0001)
|
||||
self.assertNotEqual(j["gyro-calibration-data"]["gx"], 0.0001)
|
||||
self.assertNotEqual(j["gyro-calibration-data"]["gy"], 0.0001)
|
||||
self.assertNotEqual(j["gyro-calibration-data"]["gz"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a1"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a2"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a3"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a4"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a5"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a6"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a7"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a8"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a9"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["a10"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g1"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g2"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g3"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g4"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g5"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g6"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g7"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g8"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g9"], 0.0001)
|
||||
self.assertNotEqual(j["formula-calculation-data"]["g10"], 0.0001)
|
||||
self.assertNotEqual(j["angle"], 0)
|
||||
self.assertNotEqual(j["gravity"], -10)
|
||||
self.assertNotEqual(j["battery"], 0)
|
||||
|
||||
def test_config_5(self):
|
||||
j = { "id": id, "gravity-formula": "my-formula", "gravity-temp-adjustment": "on", "gravity-format": "G" }
|
||||
r = call_api_post( "/api/config/gravity", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["gravity-format"], "G")
|
||||
self.assertEqual(j["gravity-formula"], "my-formula")
|
||||
self.assertEqual(j["gravity-temp-adjustment"], True)
|
||||
|
||||
def test_config_6(self):
|
||||
j = { "id": id, "mdns": "gravmon", "temp-format": "F", "sleep-interval": 300 }
|
||||
r = call_api_post( "/api/config/device", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["mdns"], "gravmon")
|
||||
self.assertEqual(j["wifi-ssid"], "@home")
|
||||
self.assertEqual(j["wifi-pass"], "") # Should not be displayed in API
|
||||
self.assertEqual(j["temp-format"], "F")
|
||||
self.assertEqual(j["sleep-interval"], 300)
|
||||
|
||||
def test_config_7(self):
|
||||
j = { "id": id, "ota-url": "", "voltage-factor": 1.55, "temp-adjustment-value": -2, "gyro-temp": "off", "ble": "blue" }
|
||||
r = call_api_post( "/api/config/hardware", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["ble"], "blue")
|
||||
self.assertEqual(j["ota-url"], "")
|
||||
self.assertEqual(j["voltage-factor"], 1.55)
|
||||
self.assertEqual(j["temp-adjustment-value"], -2)
|
||||
self.assertEqual(j["gyro-temp"], False)
|
||||
|
||||
def test_config_8(self):
|
||||
j = { "id": id, "gravity-formula": "", "gravity-temp-adjustment": "off", "gravity-format": "P" }
|
||||
r = call_api_post( "/api/config/gravity", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gravity-format"], "P")
|
||||
self.assertEqual(j["gravity-temp-adjustment"], False)
|
||||
self.assertEqual(j["gravity-formula"], "")
|
||||
|
||||
def test_config_9(self):
|
||||
j = { "id": id, "gravity-temp-adjustment": "on" }
|
||||
r = call_api_post( "/api/config/gravity", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gravity-temp-adjustment"], True)
|
||||
|
||||
j = { "id": id } # No checkbox tag should set it to false.
|
||||
r = call_api_post( "/api/config/gravity", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gravity-temp-adjustment"], False)
|
||||
|
||||
def test_config_A(self):
|
||||
j = { "id": id, "gyro-temp": "on" }
|
||||
r = call_api_post( "/api/config/hardware", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gyro-temp"], True)
|
||||
|
||||
j = { "id": id } # No checkbox tag should set it to false.
|
||||
r = call_api_post( "/api/config/hardware", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gyro-temp"], False)
|
||||
|
||||
# Check formula api (sg mode)
|
||||
def test_formula_sg_1(self):
|
||||
# Ensure we have SG defined as gravity
|
||||
j = { "id": id, "gravity-formula": "", "gravity-temp-adjustment": "off", "gravity-format": "G" }
|
||||
r = call_api_post("/api/config/gravity", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_formula_sg_2(self):
|
||||
# Fails due to wrong id
|
||||
j = { "id": "wrong", "g1": 0, "g2": 1, "g3": 1.02, "g4": 1.0333, "g5": 1.00011, "g6": 1, "g7": 1, "g8": 1, "g9": 1, "g10": 1, "a1": 0, "a2": 25, "a3": 25.5, "a4": 25.55, "a5": 25.555, "a6": 0, "a7": 0, "a8": 0, "a9": 0, "a10": 0, "gravity-formula": "ThisShouldChange" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertNotEqual(r.status_code, 200)
|
||||
|
||||
# Fails due to to few values
|
||||
j = { "id": id, "g1": 0, "g2": 1, "g3": 1.02, "g4": 1.0333, "g5": 1.00011, "g6": 1, "g7": 1, "g8": 1, "g9": 1, "g10": 1, "a1": 0, "a2": 25, "a3": 0, "a4": 0, "a5": 0, "a6": 0, "a7": 0, "a8": 0, "a9": 0, "a10": 0, "gravity-formula": "ThisShouldChange" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# Checks that values from last call was stored
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gravity-formula"], "")
|
||||
self.assertEqual(j["error"], "Not enough values to create formula, need at least 3 angles.")
|
||||
|
||||
def test_formula_sg_3(self):
|
||||
# Check a simple formula
|
||||
j = { "id": id, "g1": 1.0, "g2": 1.01, "g3": 1.02, "g4": 1.03, "g5": 1.04, "g6": 1.05, "g7": 1.06, "g8": 1.07, "g9": 1.08, "g10": 1.1, "a1": 25, "a2": 30, "a3": 35, "a4": 40, "a5": 45, "a6": 50, "a7": 55, "a8": 60, "a9": 65, "a10": 70, "gravity-formula": "ThisShouldChange" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gravity-formula"], "0.00000909*tilt^2+0.00124545*tilt+0.96445455")
|
||||
|
||||
# Check formula api (plato mode)
|
||||
def test_formula_plato_1(self):
|
||||
# Ensure we have Plato defined as gravity
|
||||
j = { "id": id, "gravity-formula": "", "gravity-temp-adjustment": "off", "gravity-format": "P" }
|
||||
r = call_api_post("/api/config/gravity", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_formula_plato_2(self):
|
||||
# Fails due to to few values
|
||||
j = { "id": id, "g1": 0, "g2": 3, "g3": 5.3, "g4": 7.44, "g5": 8.555, "g6": 9, "g7": 9.1, "g8": 9.2, "g9": 9.3, "g10": 9.4, "a1": 0, "a2": 25, "a3": 25.5, "a4": 25.55, "a5": 25.555, "a6": 35, "a7": 36, "a8": 37, "a9": 38, "a10": 39, "gravity-formula": "ThisShouldChange" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# Checks that values from last call was stored
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["g1"], 0)
|
||||
self.assertEqual(j["g2"], 3)
|
||||
self.assertEqual(j["g3"], 5.3)
|
||||
self.assertEqual(j["g4"], 7.4)
|
||||
self.assertEqual(j["g5"], 8.6)
|
||||
self.assertEqual(j["g6"], 9)
|
||||
self.assertEqual(j["g7"], 9.1)
|
||||
self.assertEqual(j["g8"], 9.2)
|
||||
self.assertEqual(j["g9"], 9.3)
|
||||
self.assertEqual(j["g10"], 9.4)
|
||||
self.assertEqual(j["a1"], 0)
|
||||
self.assertEqual(j["a2"], 25)
|
||||
self.assertEqual(j["a3"], 25.5)
|
||||
self.assertEqual(j["a4"], 25.55)
|
||||
self.assertEqual(j["a5"], 25.56)
|
||||
self.assertEqual(j["a6"], 35)
|
||||
self.assertEqual(j["a7"], 36)
|
||||
self.assertEqual(j["a8"], 37)
|
||||
self.assertEqual(j["a9"], 38)
|
||||
self.assertEqual(j["a10"], 39)
|
||||
self.assertEqual(j["gravity-format"], "P")
|
||||
self.assertEqual(j["gravity-formula"], "-0.00012155*tilt^2+0.00874785*tilt+0.88003318")
|
||||
self.assertEqual(j["error"], "")
|
||||
|
||||
def test_formula_plato_3(self):
|
||||
j = { "id": id, "g1": 0, "g2": 3, "g3": 0, "g4": 0, "g5": 0, "g6": 0, "g7": 0, "g8": 0, "g9": 0, "g10": 0, "a1": 0, "a2": 25, "a3": 0, "a4": 0, "a5": 0, "a6": 0, "a7": 0, "a8": 0, "a9": 0, "a10": 0, "gravity-formula": "ThisShouldChange" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# Checks that values from last call was stored
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["error"], "Not enough values to create formula, need at least 3 angles.")
|
||||
|
||||
def test_formula_plato_4(self):
|
||||
# Ensure we have Plato defined as gravity
|
||||
j = { "id": id, "gravity-formula": "", "gravity-temp-adjustment": "off", "gravity-format": "P" }
|
||||
r = call_api_post("/api/config/gravity", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# Check a simple formula
|
||||
j = { "id": id, "g1": 1.0, "g2": 1.1, "g3": 1.2, "g4": 1.3, "g5": 1.4, "g6": 1.5, "g7": 1.6, "g8": 1.7, "g9": 1.8, "g10": 1.9, "a1": 25, "a2": 30, "a3": 35, "a4": 40, "a5": 45, "a6": 50, "a7": 55, "a8": 60, "a9": 65, "a10": 70, "gravity-formula": "ThisShouldChange" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
#self.assertEqual(j["gravity-formula"], "0.00000001*tilt^2+0.00007752*tilt+1.00193428") # 1.6 max deviation
|
||||
self.assertEqual(j["gravity-formula"], "-0.00000352*tilt^2+0.00045454*tilt+0.99231483") # 3.0 max deviation
|
||||
|
||||
# Check format api
|
||||
def test_pushtest_1(self):
|
||||
j = { "id": id, "http-push": "http://push.me", "token": "mytoken", "token2": "mytoken2", "http-push2": "http://push.me", "http-push3": "http://push.me", "brewfather-push": "http://push.me", "influxdb2-push": "http://influx.db", "influxdb2-org": "my-org",
|
||||
"influxdb2-bucket": "my-bucket", "influxdb2-auth": "my-secret", "mqtt-push": "mqtt.com", "mqtt-port": 1883, "mqtt-user": "my-user",
|
||||
"mqtt-pass": "my-pass", "http-push-h1": "header1", "http-push-h2": "header2", "http-push2-h1": "header1(2)", "http-push2-h2": "header2(2)" }
|
||||
r = call_api_post( "/api/config/push", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_pushtest_2(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=http-1" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], False)
|
||||
self.assertEqual(j["enabled"], True)
|
||||
self.assertEqual(j["code"], -1)
|
||||
|
||||
def test_pushtest_3(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=http-2" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], False)
|
||||
self.assertEqual(j["enabled"], True)
|
||||
self.assertEqual(j["code"], -1)
|
||||
|
||||
def test_pushtest_4(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=http-3" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], False)
|
||||
self.assertEqual(j["enabled"], True)
|
||||
self.assertEqual(j["code"], -1)
|
||||
|
||||
def test_pushtest_5(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=influxdb" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], False)
|
||||
self.assertEqual(j["enabled"], True)
|
||||
self.assertEqual(j["code"], -1)
|
||||
|
||||
def test_pushtest_6(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=mqtt" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], False)
|
||||
self.assertEqual(j["enabled"], True)
|
||||
self.assertEqual(j["code"], -3)
|
||||
|
||||
# Check format api
|
||||
def test_push_1(self):
|
||||
r = call_api_get( "/api/factory?id=" + id)
|
||||
time.sleep(4)
|
||||
|
||||
# Note: The endpoint test.php does not validate the payload, it only accepts the request and return 200.
|
||||
j = { "id": id, "http-push": "http://www.allerum.net/test.php", "http-push2": "http://www.allerum.net/test.php", "http-push3": "http://www.allerum.net/test.php", "mqtt-push": "192.168.1.16", "mqtt-port": 1883, "mqtt-user": "", "mqtt-pass": "" }
|
||||
r = call_api_post( "/api/config/push", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_push_2(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=http-1" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], True)
|
||||
|
||||
def test_push_3(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=http-2" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], True)
|
||||
|
||||
def test_push_4(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=http-3" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], True)
|
||||
|
||||
def test_push_5(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=mqtt" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["success"], True)
|
||||
|
||||
def test_push_6(self):
|
||||
r = call_api_get( "/api/test/push?id=" + id + "&format=influx" )
|
||||
# TODO: Figure out how to test the influx db setup. Create my own mockup ?
|
||||
|
||||
# Check format api
|
||||
def test_format_1(self):
|
||||
j = { "id": id, "http-1": "one" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_2(self):
|
||||
j = { "id": id, "http-2": "two" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_3(self):
|
||||
j = { "id": id, "http-3": "five" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_4(self):
|
||||
j = { "id": id, "influxdb": "three" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_5(self):
|
||||
j = { "id": id, "mqtt": "four" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_6(self):
|
||||
r = call_api_get( "/api/config/format" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
self.assertEqual(j["http-1"], "one")
|
||||
self.assertEqual(j["http-2"], "two")
|
||||
self.assertEqual(j["http-3"], "five")
|
||||
self.assertEqual(j["influxdb"], "three")
|
||||
self.assertEqual(j["mqtt"], "four")
|
||||
|
||||
def test_format_7(self):
|
||||
j = { "id": id, "http-1": "" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_8(self):
|
||||
j = { "id": id, "http-2": "" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_9(self):
|
||||
j = { "id": id, "http-3": "" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_A(self):
|
||||
j = { "id": id, "influxdb": "" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_B(self):
|
||||
j = { "id": id, "mqtt": "" }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_format_C(self):
|
||||
r = call_api_get( "/api/config/format" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
#print(j["http-1"])
|
||||
#print(j["http-2"])
|
||||
#print(j["http-3"])
|
||||
#print(j["influxdb"])
|
||||
#print(j["mqtt"])
|
||||
self.assertEqual(j["http-1"], "%7B%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%2Dinterval%7D%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22temp%5Funits%22%3A%20%22%24%7Btemp%2Dunit%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%2Dgravity%22%3A%20%24%7Bcorr%2Dgravity%7D%2C%20%22gravity%2Dunit%22%3A%20%22%24%7Bgravity%2Dunit%7D%22%2C%20%22run%2Dtime%22%3A%20%24%7Brun%2Dtime%7D%20%7D")
|
||||
self.assertEqual(j["http-2"], "%7B%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%2Dinterval%7D%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22temp%5Funits%22%3A%20%22%24%7Btemp%2Dunit%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%2Dgravity%22%3A%20%24%7Bcorr%2Dgravity%7D%2C%20%22gravity%2Dunit%22%3A%20%22%24%7Bgravity%2Dunit%7D%22%2C%20%22run%2Dtime%22%3A%20%24%7Brun%2Dtime%7D%20%7D")
|
||||
self.assertEqual(j["http-3"], "%3Fname%3D%24%7Bmdns%7D%26id%3D%24%7Bid%7D%26token%3D%24%7Btoken2%7D%26interval%3D%24%7Bsleep%2Dinterval%7D%26temperature%3D%24%7Btemp%7D%26temp%2Dunits%3D%24%7Btemp%2Dunit%7D%26gravity%3D%24%7Bgravity%7D%26angle%3D%24%7Bangle%7D%26battery%3D%24%7Bbattery%7D%26rssi%3D%24%7Brssi%7D%26corr%2Dgravity%3D%24%7Bcorr%2Dgravity%7D%26gravity%2Dunit%3D%24%7Bgravity%2Dunit%7D%26run%2Dtime%3D%24%7Brun%2Dtime%7D")
|
||||
self.assertEqual(j["influxdb"], "measurement%2Chost%3D%24%7Bmdns%7D%2Cdevice%3D%24%7Bid%7D%2Ctemp%2Dformat%3D%24%7Btemp%2Dunit%7D%2Cgravity%2Dformat%3D%24%7Bgravity%2Dunit%7D%20gravity%3D%24%7Bgravity%7D%2Ccorr%2Dgravity%3D%24%7Bcorr%2Dgravity%7D%2Cangle%3D%24%7Bangle%7D%2Ctemp%3D%24%7Btemp%7D%2Cbattery%3D%24%7Bbattery%7D%2Crssi%3D%24%7Brssi%7D%0A")
|
||||
self.assertEqual(j["mqtt"], "ispindel%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Bangle%7D%7Cispindel%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7Cispindel%2F%24%7Bmdns%7D%2Ftemp%5Funits%3A%24%7Btemp%2Dunit%7D%7Cispindel%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7Cispindel%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7Cispindel%2F%24%7Bmdns%7D%2Finterval%3A%24%7Bsleep%2Dinterval%7D%7Cispindel%2F%24%7Bmdns%7D%2FRSSI%3A%24%7Brssi%7D%7C")
|
||||
|
||||
# Toggle sleep mode
|
||||
def toggle_sleepmode_1(self):
|
||||
j = { "id": id, "sleep-mode": "on" }
|
||||
r = call_api_post( "/api/status/sleepmode" )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/status" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["sleep-mode"], True)
|
||||
|
||||
def toggle_sleepmode_2(self):
|
||||
j = { "id": id, "sleep-mode": "off" }
|
||||
r = call_api_post( "/api/status/sleepmode" )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/status" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["sleep-mode"], False)
|
||||
|
||||
# Clear setting
|
||||
def default_settings_1(self):
|
||||
j = { "id": id, "mdns": "gravmon", "temp-format": "C", "sleep-interval": 300 }
|
||||
r = call_api_post( "/api/config/device", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def default_settings_2(self):
|
||||
j = { "id": id, "token": "", "token2": "", "http-push": "", "http-push2": "", "http-push3": "", "influxdb2-push": "", "influxdb2-org": "", "influxdb2-bucket": "",
|
||||
"influxdb2-auth": "", "mqtt-push": "", "mqtt-port": 1883, "mqtt-user": "", "mqtt-pass": "" }
|
||||
r = call_api_post( "/api/config/push", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def default_settings_3(self):
|
||||
j = { "id": id, "ota-url": "", "voltage-factor": 1.55, "temp-adjustment-value": -2, "gyro-temp": "off" }
|
||||
r = call_api_post( "/api/config/hardware", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def default_settings_4(self):
|
||||
j = { "id": id, "gravity-formula": "", "gravity-temp-adjustment": "off", "gravity-format": "G" }
|
||||
r = call_api_post( "/api/config/gravity", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# Check advanced
|
||||
def test_advanced_config_1(self):
|
||||
r = call_api_get( "/api/status" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["id"], id)
|
||||
r = call_api_get( "/api/factory?id=" + j["id"])
|
||||
time.sleep(4)
|
||||
|
||||
r = call_api_get( "/api/config/advanced" )
|
||||
j = json.loads(r.text)
|
||||
#print(j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gyro-read-count"], 50)
|
||||
self.assertEqual(j["tempsensor-resolution"], 9)
|
||||
self.assertEqual(j["gyro-moving-threashold"], 500)
|
||||
self.assertEqual(j["formula-max-deviation"], 3)
|
||||
self.assertEqual(j["formula-calibration-temp"], 20)
|
||||
self.assertEqual(j["wifi-portal-timeout"], 120)
|
||||
self.assertEqual(j["wifi-connect-timeout"], 20)
|
||||
self.assertEqual(j["ignore-low-angles"], False)
|
||||
self.assertEqual(j["formula-calibration-temp"], 20)
|
||||
self.assertEqual(j["int-http1"], 0)
|
||||
self.assertEqual(j["int-http2"], 0)
|
||||
self.assertEqual(j["int-http3"], 0)
|
||||
self.assertEqual(j["int-influx"], 0)
|
||||
self.assertEqual(j["int-mqtt"], 0)
|
||||
|
||||
def test_advanced_config_2(self):
|
||||
j = { "id": id, "gyro-read-count": 51, "tempsensor-resolution": 10, "gyro-moving-threashold": 501, "formula-max-deviation": 1.7, "ignore-low-angles": "on",
|
||||
"formula-calibration-temp": 21, "wifi-portal-timeout": 121, "wifi-connect-timeout": 21, "int-http1": 1, "int-http2": 2, "int-http3": 3, "int-influx": 4, "int-mqtt": 5 }
|
||||
r = call_api_post( "/api/config/advanced", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config/advanced" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["gyro-read-count"], 51)
|
||||
self.assertEqual(j["tempsensor-resolution"], 10)
|
||||
self.assertEqual(j["gyro-moving-threashold"], 501)
|
||||
self.assertEqual(j["formula-max-deviation"], 1.7)
|
||||
self.assertEqual(j["formula-calibration-temp"], 21)
|
||||
self.assertEqual(j["wifi-portal-timeout"], 121)
|
||||
self.assertEqual(j["wifi-connect-timeout"], 21)
|
||||
self.assertEqual(j["ignore-low-angles"], True)
|
||||
self.assertEqual(j["int-http1"], 1)
|
||||
self.assertEqual(j["int-http2"], 2)
|
||||
self.assertEqual(j["int-http3"], 3)
|
||||
self.assertEqual(j["int-influx"], 4)
|
||||
self.assertEqual(j["int-mqtt"], 5)
|
||||
|
||||
def test_advanced_config_3(self):
|
||||
j = { "id": id, "ignore-low-angles": "on" }
|
||||
r = call_api_post( "/api/config/advanced", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config/advanced" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["ignore-low-angles"], True)
|
||||
|
||||
j = { "id": id } # Skipping checkbox variable should set it to false
|
||||
r = call_api_post( "/api/config/advanced", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config/advanced" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["ignore-low-angles"], False)
|
||||
|
||||
def test_bug_71(self):
|
||||
format = "gm%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%20%22ID%22%3A%22%24%7Bid%7D%22%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22gravity%22%3A%24%7Bgravity%7D%2C%22angle%22%3A%20%24%7Bangle%7D%2C%20%22battery%22%3A%24%7Bbattery%7D%2C%20%22rssi%22%3A%20%24%7Brssi%7D%7D"
|
||||
j = { "id": id, "mqtt": format }
|
||||
r = call_api_post( "/api/config/format", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/config/format" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["mqtt"], format)
|
||||
|
||||
def test_bug_79(self):
|
||||
j = { "id": id, "formula-max-deviation": 1.7 }
|
||||
r = call_api_post( "/api/config/advanced", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
j = { "id": id, "g1": 1.0, "g2": 1.009, "g3": 1.014, "g4": 1.027, "g5": 1.037, "g6": 1.042, "g7": 1.051, "g8": 1.060, "g9": 1.073, "g10": 1.078, "a1": 23.52, "a2": 26.47, "a3": 29.87, "a4": 33.43, "a5": 38.16, "a6": 40.6, "a7": 45.85, "a8": 50.12, "a9": 56.55, "a10": 59.078, "gravity-formula": "" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["error"], 'Unable to find an accurate formula based on input, check error log and graph below.')
|
||||
|
||||
j = { "id": id, "formula-max-deviation": 4 }
|
||||
r = call_api_post( "/api/config/advanced", j )
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
j = { "id": id, "g1": 1.0, "g2": 1.009, "g3": 1.014, "g4": 1.027, "g5": 1.037, "g6": 1.042, "g7": 1.051, "g8": 1.060, "g9": 1.073, "g10": 1.078, "a1": 23.52, "a2": 26.47, "a3": 29.87, "a4": 33.43, "a5": 38.16, "a6": 40.6, "a7": 45.85, "a8": 50.12, "a9": 56.55, "a10": 59.078, "gravity-formula": "" }
|
||||
r = call_api_post("/api/formula", j)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
r = call_api_get( "/api/formula" )
|
||||
j = json.loads(r.text)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(j["error"], '')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -3,7 +3,7 @@
|
||||
"wifi-ssid2": "ssid 2",
|
||||
"mdns": "gravmon3",
|
||||
"id": "7376ef",
|
||||
"ota-url": "http://192.168.1.100:80/firmware/gravmon/",
|
||||
"ota-url": "https://www.gravitymon.com/firmware/",
|
||||
"temp-format": "C",
|
||||
"http-push": "http://192.168.1.10:9090/api/v1/ZYfjlUNeiuyu9N/telemetry",
|
||||
"http-push-h1": "Auth: Basic T7IF9DD9fF3RDddE=",
|
||||
|
@ -1,91 +0,0 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
host = "192.168.1.1" # IP adress (or name) of the device to send these settings to
|
||||
id = "ee1bfc" # Device ID (shown in serial console during startup or in UI)
|
||||
|
||||
def set_config( url, json ):
|
||||
headers = { "ContentType": "application/json" }
|
||||
print( url )
|
||||
#print( json )
|
||||
resp = requests.post( url, headers=headers, data=json )
|
||||
if resp.status_code != 200 :
|
||||
print ( "Failed " )
|
||||
else :
|
||||
print ( "Success " )
|
||||
|
||||
#
|
||||
# Configure the device settings.
|
||||
#
|
||||
url = "http://" + host + "/api/config/device"
|
||||
json = { "id": id,
|
||||
"mdns": "gravmon", # Name of the device
|
||||
"temp-format": "C", # Temperature format C or F
|
||||
"sleep-interval": 30 # Sleep interval in seconds
|
||||
}
|
||||
set_config( url, json )
|
||||
|
||||
#
|
||||
# Configure the push settings. Blank means that its no used.
|
||||
#
|
||||
url = "http://" + host + "/api/config/push"
|
||||
json = { "id": id,
|
||||
"token": "",
|
||||
"http-push": "http://192.168.1.1/ispindel", # HTTP endpoint
|
||||
"http-push2": "", # HTTP endpoint2
|
||||
"http-push-h1": "Content-Type: application/json",
|
||||
"http-push-h2": "",
|
||||
"http-push2-h1": "Content-Type: application/json",
|
||||
"http-push2-h2": "",
|
||||
"influxdb2-push": "", # InfluxDB2 settings
|
||||
"influxdb2-org": "",
|
||||
"influxdb2-bucket": "",
|
||||
"influxdb2-auth": "" ,
|
||||
"mqtt-push": "",
|
||||
"mqtt-port": 1883,
|
||||
"mqtt-user": "",
|
||||
"mqtt-pass": ""
|
||||
}
|
||||
set_config( url, json )
|
||||
|
||||
|
||||
#
|
||||
# Configure the gravity settings.
|
||||
#
|
||||
url = "http://" + host + "/api/config/gravity"
|
||||
json = { "id": id,
|
||||
"gravity-formula": "", # If you want to set the gravity formula
|
||||
"gravity-format": "G",
|
||||
"gravity-temp-adjustment": "off" # on or off
|
||||
}
|
||||
set_config( url, json )
|
||||
|
||||
#
|
||||
# Configure the hardware settings.
|
||||
#
|
||||
url = "http://" + host + "/api/config/hardware"
|
||||
json = { "id": id,
|
||||
"voltage-factor": 1.59, # Default value for voltage calculation
|
||||
"temp-adjustment": 0, # If temp sensor needs to be corrected
|
||||
"gyro-temp": "off", # Use the temp sensor in the gyro
|
||||
"ota-url": "" # if the device should seach for a new update when active
|
||||
}
|
||||
set_config( url, json )
|
||||
|
||||
#
|
||||
# Configure the gravity formula settings. If this is called the formula will be updated based on these measurements (zero angle values will be ignored)
|
||||
#
|
||||
url = "http://" + host + "/api/formula"
|
||||
json = { "id": id,
|
||||
"a1": 22.4,
|
||||
"a2": 54.4,
|
||||
"a3": 58,
|
||||
"a4": 0,
|
||||
"a5": 0,
|
||||
"g1": 1.000,
|
||||
"g2": 1.053,
|
||||
"g3": 1.062,
|
||||
"g4": 1,
|
||||
"g5": 1
|
||||
}
|
||||
set_config( url, json )
|
82
test/tests.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <main.hpp>
|
||||
|
||||
using aunit::Printer;
|
||||
using aunit::TestRunner;
|
||||
using aunit::Verbosity;
|
||||
|
||||
/*
|
||||
// Boolean
|
||||
assertEqual(a, b)
|
||||
assertNotEqual(a, b)
|
||||
assertLess(a, b)
|
||||
assertMore(a, b)
|
||||
assertLessOrEqual(a, b)
|
||||
assertMoreOrEqual(a, b)
|
||||
|
||||
// String
|
||||
assertStringCaseEqual(a, b)
|
||||
assertStringCaseNotEqual(a, b)
|
||||
assertNear(a, b, error)
|
||||
assertNotNear(a, b, error)
|
||||
checkTestDone(name)
|
||||
checkTestNotDone(name)
|
||||
checkTestPass(name)
|
||||
checkTestNotPass(name)
|
||||
checkTestFail(name)
|
||||
checkTestNotFail(name)
|
||||
checkTestSkip(name)
|
||||
checkTestNotSkip(name)
|
||||
checkTestExpire(name) [*]
|
||||
checkTestNotExpire(name) [*]
|
||||
assertTestDone(name)
|
||||
assertTestNotDone(name)
|
||||
assertTestPass(name)
|
||||
assertTestNotPass(name)
|
||||
assertTestFail(name)
|
||||
assertTestNotFail(name)
|
||||
assertTestSkip(name)
|
||||
assertTestNotSkip(name)
|
||||
assertTestExpire(name) [*]
|
||||
assertTestNotExpire(name) [*]
|
||||
*/
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Gravitymon - Unit Test Build");
|
||||
delay(2000);
|
||||
Printer::setPrinter(&Serial);
|
||||
// TestRunner::setVerbosity(Verbosity::kAll);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
TestRunner::run();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
// EOF
|
31
test/tests_ble.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <main.hpp>
|
||||
|
||||
// No unit testing for the BLE module.
|
||||
|
||||
// EOF
|
67
test/tests_calc.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
|
||||
#include <calc.hpp>
|
||||
#include <helper.hpp>
|
||||
|
||||
// TODO: Add more test cases to explore formula creation error conditions when
|
||||
// values are out of bounds
|
||||
// TODO: Add more test cases to check order 3 + 4 formula creation as well.
|
||||
|
||||
test(calc_createFormula1) {
|
||||
char buffer[100];
|
||||
RawFormulaData fd = {
|
||||
{0.0, 25.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 1.0, 1.02, 1.033, 1.00011, 1.0, 1.0, 1.0, 1.0, 1.0}};
|
||||
int i = createFormula(fd, &buffer[0], sizeof(buffer), 2);
|
||||
assertEqual(i, ERR_FORMULA_NOTENOUGHVALUES);
|
||||
}
|
||||
|
||||
test(calc_createFormula2) {
|
||||
char buffer[100];
|
||||
RawFormulaData fd = {
|
||||
{25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0},
|
||||
{1.0, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.1}};
|
||||
int i = createFormula(fd, &buffer[0], sizeof(buffer), 2);
|
||||
assertEqual(i, 0);
|
||||
assertEqual(&buffer[0], "0.00000909*tilt^2+0.00124545*tilt+0.96445455");
|
||||
}
|
||||
|
||||
test(calc_calculateGravity) {
|
||||
const char* formula = "0.00000909*tilt^2+0.00124545*tilt+0.96445455";
|
||||
double g = calculateGravity(30, 20, formula);
|
||||
float v1 = reduceFloatPrecision(g, 2);
|
||||
float v2 = 1.01;
|
||||
assertEqual(v1, v2);
|
||||
}
|
||||
|
||||
test(calc_gravityTemperatureCorrectionC) {
|
||||
double g = gravityTemperatureCorrectionC(1.02, 45.0, 20.0);
|
||||
float v1 = reduceFloatPrecision(g, 2);
|
||||
float v2 = 1.03;
|
||||
assertEqual(v1, v2);
|
||||
}
|
||||
|
||||
// EOF
|
73
test/tests_config.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
|
||||
#include <config.hpp>
|
||||
|
||||
test(config_defaultValues) {
|
||||
assertEqual(myConfig.getGravityFormat(), 'G');
|
||||
assertEqual(myConfig.getTempFormat(), 'C');
|
||||
assertEqual(myConfig.getSleepInterval(), 900);
|
||||
assertEqual(myConfig.getTempSensorAdjC(), 0.0);
|
||||
float f = 4.15;
|
||||
assertEqual(myConfig.getVoltageConfig(), f);
|
||||
}
|
||||
|
||||
test(config_advDefaultValues) {
|
||||
assertEqual(myAdvancedConfig.getDefaultCalibrationTemp(), 20.0);
|
||||
assertEqual(myAdvancedConfig.getGyroReadCount(), 50);
|
||||
assertEqual(myAdvancedConfig.getGyroReadDelay(), 3150);
|
||||
assertEqual(myAdvancedConfig.getGyroSensorMovingThreashold(), 500);
|
||||
assertEqual(myAdvancedConfig.getMaxFormulaCreationDeviation(), 3.0);
|
||||
assertEqual(myAdvancedConfig.getPushIntervalHttp1(), 0);
|
||||
assertEqual(myAdvancedConfig.getPushIntervalHttp2(), 0);
|
||||
assertEqual(myAdvancedConfig.getPushIntervalHttp3(), 0);
|
||||
assertEqual(myAdvancedConfig.getPushIntervalMqtt(), 0);
|
||||
assertEqual(myAdvancedConfig.getPushIntervalInflux(), 0);
|
||||
assertEqual(myAdvancedConfig.getPushTimeout(), 10);
|
||||
assertEqual(myAdvancedConfig.getTempSensorResolution(), 9);
|
||||
assertEqual(myAdvancedConfig.getWifiConnectTimeout(), 20);
|
||||
assertEqual(myAdvancedConfig.getWifiPortalTimeout(), 120);
|
||||
assertEqual(myAdvancedConfig.isIgnoreLowAnges(), false);
|
||||
}
|
||||
|
||||
test(config_tempFormat) {
|
||||
myConfig.setTempFormat('F');
|
||||
assertEqual(myConfig.getTempFormat(), 'F');
|
||||
myConfig.setTempFormat('C');
|
||||
assertEqual(myConfig.getTempFormat(), 'C');
|
||||
myConfig.setTempFormat('X');
|
||||
assertEqual(myConfig.getTempFormat(), 'C');
|
||||
}
|
||||
|
||||
test(config_gravityFormat) {
|
||||
myConfig.setGravityFormat('P');
|
||||
assertEqual(myConfig.getGravityFormat(), 'P');
|
||||
myConfig.setGravityFormat('G');
|
||||
assertEqual(myConfig.getGravityFormat(), 'G');
|
||||
myConfig.setGravityFormat('X');
|
||||
assertEqual(myConfig.getGravityFormat(), 'G');
|
||||
}
|
||||
|
||||
// EOF
|
44
test/tests_gyro.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
|
||||
#include <gyro.hpp>
|
||||
|
||||
test(gyro_connectGyro) {
|
||||
myGyro.setup();
|
||||
assertEqual(myGyro.isConnected(), true);
|
||||
}
|
||||
|
||||
test(gyro_readGyro) {
|
||||
myGyro.setup();
|
||||
assertEqual(myGyro.read(), true);
|
||||
}
|
||||
|
||||
test(gyro_readGyroTemp) {
|
||||
myGyro.setup();
|
||||
assertNotEqual(myGyro.getInitialSensorTempC(), -273.0);
|
||||
assertNotEqual(myGyro.getSensorTempC(), -273.0);
|
||||
}
|
||||
|
||||
// EOF
|
93
test/tests_helper.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
|
||||
#include <helper.hpp>
|
||||
|
||||
BatteryVoltage myBatteryVoltage;
|
||||
|
||||
test(helper_convertToPlato) {
|
||||
double p = convertToPlato(1.008);
|
||||
char buffer[20];
|
||||
String s = convertFloatToString(p, &buffer[0], 2);
|
||||
s.trim();
|
||||
assertEqual(s, "2.06");
|
||||
}
|
||||
|
||||
test(helper_convertToSG) {
|
||||
double p = convertToSG(2.06);
|
||||
char buffer[20];
|
||||
String s = convertFloatToString(p, &buffer[0], 3);
|
||||
s.trim();
|
||||
assertEqual(s, "1.008");
|
||||
}
|
||||
|
||||
test(helper_convertCtoF) {
|
||||
float t = convertCtoF(20.0);
|
||||
assertEqual(t, 68.0);
|
||||
}
|
||||
|
||||
test(helper_convertFtoC) {
|
||||
float t = convertFtoC(68.0);
|
||||
assertEqual(t, 20.0);
|
||||
}
|
||||
|
||||
test(helper_urlEncode) {
|
||||
String s = urlencode("Hello world");
|
||||
assertEqual(s, "Hello%20world");
|
||||
}
|
||||
|
||||
test(helper_urlDecode) {
|
||||
String s = urldecode("Hello%20world");
|
||||
assertEqual(s, "Hello world");
|
||||
}
|
||||
|
||||
test(helper_convertFloatToString) {
|
||||
char buffer[20];
|
||||
String s = convertFloatToString(20.2, &buffer[0], 2);
|
||||
s.trim();
|
||||
assertEqual(s, "20.20");
|
||||
}
|
||||
|
||||
test(helper_reduceFloatPrecision1) {
|
||||
float v = 20.233;
|
||||
float f = reduceFloatPrecision(v, 2);
|
||||
v = 20.23;
|
||||
assertEqual(f, v);
|
||||
}
|
||||
|
||||
test(helper_reduceFloatPrecision2) {
|
||||
float v = 20.238;
|
||||
float f = reduceFloatPrecision(v, 2);
|
||||
v = 20.24;
|
||||
assertEqual(f, v);
|
||||
}
|
||||
|
||||
test(helper_readBatteryVoltage) {
|
||||
myBatteryVoltage.read();
|
||||
float f = myBatteryVoltage.getVoltage();
|
||||
assertMoreOrEqual(f, 2.0);
|
||||
}
|
||||
|
||||
// EOF
|
32
test/tests_pushtarget.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <main.hpp>
|
||||
|
||||
// TODO: Build some php scripts that run on gravitymon.com for testing the push
|
||||
// data.
|
||||
|
||||
// EOF
|
128
test/tests_templating.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
|
||||
#include <config.hpp>
|
||||
#include <templating.hpp>
|
||||
|
||||
test(template_applyTemplate1) {
|
||||
TemplatingEngine e;
|
||||
char buffer[20];
|
||||
myConfig.setMDNS("gravitymon");
|
||||
|
||||
e.initialize(45.0, 1.123, 1.223, 21.2, 2.98);
|
||||
String s = e.create(TemplatingEngine::TEMPLATE_HTTP1);
|
||||
String id = myConfig.getID();
|
||||
String batt =
|
||||
convertFloatToString(myBatteryVoltage.getVoltage(), &buffer[0], 2);
|
||||
batt.trim();
|
||||
String v = "{\"name\" : \"gravitymon\", \"ID\": \"" + id +
|
||||
"\", \"token\" : \"\", \"interval\": 900, \"temperature\": 21.2, "
|
||||
"\"temp_units\": \"C\", \"gravity\": 1.1230, \"angle\": 45.00, "
|
||||
"\"battery\": " +
|
||||
batt +
|
||||
", \"RSSI\": 31, \"corr-gravity\": 1.2230, \"gravity-unit\": "
|
||||
"\"G\", \"run-time\": 3.0 }";
|
||||
assertEqual(s, v);
|
||||
}
|
||||
|
||||
test(template_applyTemplate2) {
|
||||
TemplatingEngine e;
|
||||
char buffer[20];
|
||||
myConfig.setMDNS("gravitymon");
|
||||
|
||||
e.initialize(45.0, 1.123, 1.223, 21.2, 2.98);
|
||||
String s = e.create(TemplatingEngine::TEMPLATE_HTTP2);
|
||||
String id = myConfig.getID();
|
||||
String batt =
|
||||
convertFloatToString(myBatteryVoltage.getVoltage(), &buffer[0], 2);
|
||||
batt.trim();
|
||||
String v = "{\"name\" : \"gravitymon\", \"ID\": \"" + id +
|
||||
"\", \"token\" : \"\", \"interval\": 900, \"temperature\": 21.2, "
|
||||
"\"temp_units\": \"C\", \"gravity\": 1.1230, \"angle\": 45.00, "
|
||||
"\"battery\": " +
|
||||
batt +
|
||||
", \"RSSI\": 31, \"corr-gravity\": 1.2230, \"gravity-unit\": "
|
||||
"\"G\", \"run-time\": 3.0 }";
|
||||
assertEqual(s, v);
|
||||
}
|
||||
|
||||
test(template_applyTemplate3) {
|
||||
TemplatingEngine e;
|
||||
char buffer[20];
|
||||
myConfig.setMDNS("gravitymon");
|
||||
|
||||
e.initialize(45.0, 1.123, 1.223, 21.2, 2.98);
|
||||
String s = e.create(TemplatingEngine::TEMPLATE_HTTP3);
|
||||
String id = myConfig.getID();
|
||||
String batt =
|
||||
convertFloatToString(myBatteryVoltage.getVoltage(), &buffer[0], 2);
|
||||
batt.trim();
|
||||
String v = "?name=gravitymon&id=" + id +
|
||||
"&token=&interval=900&temperature=21.2&temp-units=C&gravity=1."
|
||||
"1230&angle=45.00&battery=" +
|
||||
batt + "&rssi=31&corr-gravity=1.2230&gravity-unit=G&run-time=3.0";
|
||||
assertEqual(s, v);
|
||||
}
|
||||
|
||||
test(template_applyTemplate4) {
|
||||
TemplatingEngine e;
|
||||
char buffer[20];
|
||||
myConfig.setMDNS("gravitymon");
|
||||
|
||||
e.initialize(45.0, 1.123, 1.223, 21.2, 2.98);
|
||||
String s = e.create(TemplatingEngine::TEMPLATE_INFLUX);
|
||||
String id = myConfig.getID();
|
||||
String batt =
|
||||
convertFloatToString(myBatteryVoltage.getVoltage(), &buffer[0], 2);
|
||||
batt.trim();
|
||||
String v =
|
||||
"measurement,host=gravitymon,device=" + id +
|
||||
",temp-format=C,gravity-format=G "
|
||||
"gravity=1.1230,corr-gravity=1.2230,angle=45.00,temp=21.2,battery=" +
|
||||
batt + ",rssi=31\n";
|
||||
assertEqual(s, v);
|
||||
}
|
||||
|
||||
test(template_applyTemplate5) {
|
||||
TemplatingEngine e;
|
||||
char buffer[20];
|
||||
myConfig.setMDNS("gravitymon");
|
||||
|
||||
e.initialize(45.0, 1.123, 1.223, 21.2, 2.98);
|
||||
String s = e.create(TemplatingEngine::TEMPLATE_MQTT);
|
||||
String batt =
|
||||
convertFloatToString(myBatteryVoltage.getVoltage(), &buffer[0], 2);
|
||||
batt.trim();
|
||||
String v =
|
||||
"ispindel/gravitymon/tilt:45.00|ispindel/gravitymon/"
|
||||
"temperature:21.2|ispindel/gravitymon/temp_units:C|ispindel/gravitymon/"
|
||||
"battery:" +
|
||||
batt +
|
||||
"|ispindel/gravitymon/gravity:1.1230|ispindel/gravitymon/"
|
||||
"interval:900|ispindel/gravitymon/RSSI:31|";
|
||||
assertEqual(s, v);
|
||||
}
|
||||
|
||||
// EOF
|
34
test/tests_tempsensor.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
|
||||
#include <tempsensor.hpp>
|
||||
|
||||
test(temp_readSensor) {
|
||||
myTempSensor.setup();
|
||||
myTempSensor.getTempC();
|
||||
assertEqual(myTempSensor.isSensorAttached(), true);
|
||||
}
|
||||
|
||||
// EOF
|
32
test/tests_webserver.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <main.hpp>
|
||||
|
||||
// No unit testing for the WEB module. These tests are done using python script
|
||||
// and the API's
|
||||
|
||||
// EOF
|
32
test/tests_wifi.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Magnus
|
||||
|
||||
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 above 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.
|
||||
*/
|
||||
#include <AUnit.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <main.hpp>
|
||||
|
||||
// No unit testing for the WIFI module. These tests are manual when testing the
|
||||
// installation steps.
|
||||
|
||||
// EOF
|