Compare commits
38 Commits
0071a09935
...
rev2
| Author | SHA1 | Date | |
|---|---|---|---|
| 96341cfd42 | |||
| c432f47dff | |||
| 123f75dd89 | |||
| 462c5f3db7 | |||
| 4f02a8f3d0 | |||
| 8196ae4601 | |||
| 7697cb4ae9 | |||
| dccdca3ad8 | |||
| d2c3fc0b46 | |||
| 1d9f0f119a | |||
| 037fc3391c | |||
| aeac15aa2c | |||
| 6ee4086716 | |||
| 013356c41e | |||
| c5b882d693 | |||
| d951d1d2be | |||
| 66a21928a4 | |||
| 021a5c68fa | |||
| 27ebbe22ac | |||
| f0e237cd71 | |||
| 7b0f3d20b0 | |||
| ef04f1077c | |||
| 47445d6cd5 | |||
| 78867ae8a3 | |||
| 0f581a54c5 | |||
| 82455c830f | |||
| d73b2c66cd | |||
| 0cc2638db2 | |||
| abbb8d918b | |||
| 67e9ae1bca | |||
| 2fa4b0761b | |||
| 9064d3cd01 | |||
| f16659c25c | |||
| 6364becbe2 | |||
| 76e182935b | |||
| eeaac9548e | |||
| 374b23d99a | |||
| bd18952fe2 |
17
.devcontainer/devcontainer.json
Normal file
17
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "Waterlevel Software Development",
|
||||||
|
"dockerComposeFile": "docker-compose.yaml",
|
||||||
|
"service": "app",
|
||||||
|
"workspaceFolder": "/workspace",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"platformio.platformio-ide",
|
||||||
|
"mutantdino.resourcemonitor",
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"meezilla.json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
9
.devcontainer/docker-compose.yaml
Normal file
9
.devcontainer/docker-compose.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: gitea.tobiasmaier.me/tobimai/devcontainer-pio:latest
|
||||||
|
user: tobi:tobi
|
||||||
|
volumes:
|
||||||
|
- ..:/workspace:cached
|
||||||
|
- /home/tobi/.ssh:/home/tobi/.ssh:ro
|
||||||
|
command: sleep infinity
|
||||||
@@ -1,28 +1,26 @@
|
|||||||
name: Test compiling project
|
name: Compilie project and upload binaries
|
||||||
|
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: debian:latest
|
image: gitea.tobiasmaier.me/tobimai/devcontainer-pio:2.1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install necessary dependencies
|
|
||||||
run: apt update && apt install nodejs python3 python3-pip git curl -y
|
|
||||||
- name: Install Platformio
|
|
||||||
run: pip install --break-system-packages --upgrade platformio
|
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
- name: Run PlatformIO build for SPIFFS (same in both platforms, so only one build is necessary)
|
||||||
|
run: which pio && id && pio run --target buildfs -e ESP32_INA233
|
||||||
- name: Run PlatformIO Tests
|
- name: Run PlatformIO Tests
|
||||||
run: pio test -e native
|
run: pio test -e native
|
||||||
- name: Run PlatformIO build for INA233
|
- name: Run PlatformIO build for INA233
|
||||||
run: pio run -e ESP32_INA233
|
run: pio run -e ESP32_INA233
|
||||||
- name: Run PlatformIO build for INA226
|
- name: Run PlatformIO build for INA226
|
||||||
run: pio run -e ESP32_INA226
|
run: pio run -e ESP32_INA226
|
||||||
- name: Run PlatformIO build for SPIFFS (same in both platforms, so only one build is necessary)
|
|
||||||
run: pio run --target buildfs -e ESP32_INA233
|
|
||||||
- name: Upload firmware binary for INA233
|
- name: Upload firmware binary for INA233
|
||||||
run: |
|
run: |
|
||||||
VERSION=$(sed -n 's/#define current_software_version Version{[[:space:]]*\([0-9]\+\),[[:space:]]*\([0-9]\+\),[[:space:]]*\([0-9]\+\)}/\1.\2.\3/p' src/global_data/defines.h)
|
VERSION=$(sed -n 's/#define current_software_version Version{[[:space:]]*\([0-9]\+\),[[:space:]]*\([0-9]\+\),[[:space:]]*\([0-9]\+\)}/\1.\2.\3/p' src/global_data/defines.h)
|
||||||
@@ -31,7 +29,7 @@ jobs:
|
|||||||
curl -X PUT \
|
curl -X PUT \
|
||||||
-H "Content-Type: application/octet-stream" \
|
-H "Content-Type: application/octet-stream" \
|
||||||
--data-binary @.pio/build/ESP32_INA233/firmware.bin \
|
--data-binary @.pio/build/ESP32_INA233/firmware.bin \
|
||||||
https://iot.tobiasmaier.me/firmware/waterlevel/INA233/${VERSION}
|
https://iot.tobiasmaier.me/firmware/waterlevel/INA233REV2/${VERSION}
|
||||||
|
|
||||||
- name: Upload firmware binary for INA226
|
- name: Upload firmware binary for INA226
|
||||||
run: |
|
run: |
|
||||||
@@ -41,7 +39,7 @@ jobs:
|
|||||||
curl -X PUT \
|
curl -X PUT \
|
||||||
-H "Content-Type: application/octet-stream" \
|
-H "Content-Type: application/octet-stream" \
|
||||||
--data-binary @.pio/build/ESP32_INA226/firmware.bin \
|
--data-binary @.pio/build/ESP32_INA226/firmware.bin \
|
||||||
https://iot.tobiasmaier.me/firmware/waterlevel/INA226/${VERSION}
|
https://iot.tobiasmaier.me/firmware/waterlevel/INA226REV2/${VERSION}
|
||||||
|
|
||||||
- name: Upload SPIFFS binary
|
- name: Upload SPIFFS binary
|
||||||
run: |
|
run: |
|
||||||
@@ -50,5 +48,5 @@ jobs:
|
|||||||
|
|
||||||
curl -X PUT \
|
curl -X PUT \
|
||||||
-H "Content-Type: application/octet-stream" \
|
-H "Content-Type: application/octet-stream" \
|
||||||
--data-binary @.pio/build/ESP32_INA233/spiffs.bin \
|
--data-binary @.pio/build/ESP32_INA233/littlefs.bin \
|
||||||
https://iot.tobiasmaier.me/filesystem/waterlevel/generic/${VERSION}
|
https://iot.tobiasmaier.me/filesystem/waterlevel/generic/${VERSION}
|
||||||
|
|||||||
24
.gitea/workflows/test_build.yaml
Normal file
24
.gitea/workflows/test_build.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Test project compilation
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches-ignore: ["main"]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: gitea.tobiasmaier.me/tobimai/devcontainer-pio:2.1
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Run PlatformIO build for SPIFFS (same in both platforms, so only one build is necessary)
|
||||||
|
run: which pio && id && pio run --target buildfs -e ESP32_INA233
|
||||||
|
- name: Run PlatformIO Tests
|
||||||
|
run: pio test -e native
|
||||||
|
- name: Run PlatformIO build for INA233
|
||||||
|
run: pio run -e ESP32_INA233
|
||||||
|
- name: Run PlatformIO build for INA226
|
||||||
|
run: pio run -e ESP32_INA226
|
||||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
|
"pioarduino.pioarduino-ide",
|
||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
|
|||||||
23
.vscode/settings.json
vendored
23
.vscode/settings.json
vendored
@@ -1,6 +1,27 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"iostream": "cpp",
|
"iostream": "cpp",
|
||||||
"random": "cpp"
|
"random": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"array": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"regex": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"format": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"span": "cpp",
|
||||||
|
"text_encoding": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"*.inc": "cpp",
|
||||||
|
"cstddef": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@ function fetchTelemetryData() {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
document.getElementById('uptime').textContent = data.uptime_seconds ? (roundToTwo(data.uptime_seconds) + ' s') : 'XXX';
|
document.getElementById('uptime').textContent = data.uptime_seconds ? (roundToTwo(data.uptime_seconds) + ' s') : 'XXX';
|
||||||
document.getElementById('heap').textContent = data.heap_percent ? (roundToTwo(data.heap_percent) + ' %%') : 'XXX';
|
document.getElementById('heap').textContent = data.heap_percent ? (roundToTwo(data.heap_percent) + ' %%') : 'XXX';
|
||||||
|
document.getElementById('temperature').textContent = data.heap_percent ? (roundToTwo(data.temperature) + ' °C') : 'XXX';
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error("There was an error fetching data from the API", error);
|
console.error("There was an error fetching data from the API", error);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="/chota.css">
|
<link rel="stylesheet" href="/chota.css">
|
||||||
@@ -19,9 +20,6 @@
|
|||||||
<a href="/export">Data export</a>
|
<a href="/export">Data export</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-right">
|
|
||||||
<a class="button outline">Button</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -121,6 +119,10 @@
|
|||||||
<td>Heap usage: </td>
|
<td>Heap usage: </td>
|
||||||
<td id="heap">XXX</td>
|
<td id="heap">XXX</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CPU Temperature: </td>
|
||||||
|
<td id="temperature">XXX</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
</body>
|
</body>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const ws = new WebSocket('ws://' + window.location.host + '/ws');
|
const webSocket = new WebSocket('webSocket://' + window.location.host + '/webSocket');
|
||||||
|
|
||||||
ws.onopen = function() {
|
webSocket.onopen = function() {
|
||||||
console.log('WebSocket connection opened.');
|
console.log('WebSocket connection opened.');
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = function(event) {
|
webSocket.onmessage = function(event) {
|
||||||
console.log('Progress:', event.data);
|
console.log('Progress:', event.data);
|
||||||
// Update the progress bar
|
// Update the progress bar
|
||||||
let progress = parseInt(event.data);
|
let progress = parseInt(event.data);
|
||||||
@@ -48,11 +48,11 @@
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onerror = function(error) {
|
webSocket.onerror = function(error) {
|
||||||
console.error('WebSocket error:', error);
|
console.error('WebSocket error:', error);
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = function() {
|
webSocket.onclose = function() {
|
||||||
console.log('WebSocket connection closed.');
|
console.log('WebSocket connection closed.');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -1 +1 @@
|
|||||||
8
|
9
|
||||||
@@ -17,7 +17,7 @@ void listNetworkInterfaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setEthernetAsDefault() {
|
void setEthernetAsDefault() {
|
||||||
Log.verbose("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||||
listNetworkInterfaces();
|
listNetworkInterfaces();
|
||||||
// Attempt to locate the Ethernet network interface.
|
// Attempt to locate the Ethernet network interface.
|
||||||
// (The name may vary—on some systems it might be "eth0")
|
// (The name may vary—on some systems it might be "eth0")
|
||||||
@@ -31,8 +31,8 @@ void setEthernetAsDefault() {
|
|||||||
struct netif *eth_netif2 = netif_find("ETH_DEF");
|
struct netif *eth_netif2 = netif_find("ETH_DEF");
|
||||||
if (netif) {
|
if (netif) {
|
||||||
netif_set_default(eth_netif2);
|
netif_set_default(eth_netif2);
|
||||||
Log.verbose("Ethernet set as default network interface.");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Ethernet set as default network interface.");
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("Could not find Ethernet netif.");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Could not find Ethernet netif.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,31 @@ uint16_t get_word(uint8_t address, uint8_t reg) {
|
|||||||
return (data[1] << 8) | data[0];
|
return (data[1] << 8) | data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String INA233::get_device_model() {
|
||||||
|
char data[7]; // Array size includes space for the null terminator
|
||||||
|
|
||||||
|
// Request data from the PMBus device
|
||||||
|
Wire.beginTransmission(INA233::_address);
|
||||||
|
Wire.write(0x9A); // Command to read the manufacturer ID
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom(INA233::_address, 7);
|
||||||
|
|
||||||
|
if (Wire.available() == 7) {
|
||||||
|
uint8_t i = Wire.read();
|
||||||
|
data[0] = Wire.read();
|
||||||
|
data[1] = Wire.read();
|
||||||
|
data[2] = Wire.read();
|
||||||
|
data[3] = Wire.read();
|
||||||
|
data[4] = Wire.read();
|
||||||
|
data[5] = Wire.read();
|
||||||
|
data[6] = '\0'; // Null-terminate the string
|
||||||
|
} else {
|
||||||
|
return String("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void sendWord(uint8_t deviceAddress, uint8_t registerAddress, uint16_t value) {
|
void sendWord(uint8_t deviceAddress, uint8_t registerAddress, uint16_t value) {
|
||||||
Wire.beginTransmission(deviceAddress);
|
Wire.beginTransmission(deviceAddress);
|
||||||
@@ -32,6 +57,13 @@ void sendWord(uint8_t deviceAddress, uint8_t registerAddress, uint16_t value) {
|
|||||||
Wire.endTransmission();
|
Wire.endTransmission();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendByte(uint8_t deviceAddress, uint8_t registerAddress, uint8_t value) {
|
||||||
|
Wire.beginTransmission(deviceAddress);
|
||||||
|
Wire.write(registerAddress); // Send the register address
|
||||||
|
Wire.write((uint8_t)value); // Send the low byte first
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
INA233::INA233(const uint8_t address, TwoWire *wire)
|
INA233::INA233(const uint8_t address, TwoWire *wire)
|
||||||
{
|
{
|
||||||
_address = address;
|
_address = address;
|
||||||
@@ -85,7 +117,8 @@ float INA233::getBusVoltage() {
|
|||||||
|
|
||||||
float INA233::getShuntVoltage() {
|
float INA233::getShuntVoltage() {
|
||||||
uint16_t rawVoltage = get_word(INA233::_address, REGISTER_READ_VSHUNT);
|
uint16_t rawVoltage = get_word(INA233::_address, REGISTER_READ_VSHUNT);
|
||||||
float voltage = rawVoltage * pow(10,-4);
|
float voltage = rawVoltage * 2.5e-6;
|
||||||
|
|
||||||
return voltage;
|
return voltage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,4 +182,12 @@ void INA233::setShuntVoltageConversionTime(ConversionTime conversion_time) {
|
|||||||
|
|
||||||
uint16_t INA233::getConfigRegister() {
|
uint16_t INA233::getConfigRegister() {
|
||||||
return get_word(INA233::_address, REGISTER_CONFIGURATION);
|
return get_word(INA233::_address, REGISTER_CONFIGURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void INA233::reset() {
|
||||||
|
sendByte(INA233::_address, 0x12, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void INA233::setCalibrationRegister(int value) {
|
||||||
|
sendWord(INA233::_address, 0xD4, value);
|
||||||
}
|
}
|
||||||
@@ -7,45 +7,51 @@
|
|||||||
#define REGISTER_READ_VIN 0x88
|
#define REGISTER_READ_VIN 0x88
|
||||||
#define REGISTER_READ_VSHUNT 0xD1
|
#define REGISTER_READ_VSHUNT 0xD1
|
||||||
#define REGISTER_CONFIGURATION 0xD0
|
#define REGISTER_CONFIGURATION 0xD0
|
||||||
|
#define REGISTER_READ_IIN 0x89
|
||||||
|
|
||||||
enum AveragingMode {
|
enum AveragingMode {
|
||||||
averages_1 = B000,
|
averages_1 = 0b000,
|
||||||
averages_4 = B001,
|
averages_4 = 0b001,
|
||||||
averages_16 = B010,
|
averages_16 = 0b010,
|
||||||
averages_64 = B011,
|
averages_64 = 0b011,
|
||||||
averages_128 = B100,
|
averages_128 = 0b100,
|
||||||
averages_256 = B101,
|
averages_256 = 0b101,
|
||||||
averages_512 = B110,
|
averages_512 = 0b110,
|
||||||
averages_1024 = B111
|
averages_1024 = 0b111
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ConversionTime {
|
enum ConversionTime {
|
||||||
conversion_time_140uS = B000,
|
conversion_time_140uS = 0b000,
|
||||||
conversion_time_204uS = B001,
|
conversion_time_204uS = 0b001,
|
||||||
conversion_time_332us = B010,
|
conversion_time_332us = 0b010,
|
||||||
conversion_time_588uS = B011,
|
conversion_time_588uS = 0b011,
|
||||||
conversion_time_1100uS = B100,
|
conversion_time_1100uS = 0b100,
|
||||||
conversion_time_2116uS = B101,
|
conversion_time_2116uS = 0b101,
|
||||||
conversion_time_4156uS = B110,
|
conversion_time_4156uS = 0b110,
|
||||||
conversion_time_8244uS = B111
|
conversion_time_8244uS = 0b111
|
||||||
};
|
};
|
||||||
|
|
||||||
class INA233{
|
class INA233{
|
||||||
public:
|
public:
|
||||||
INA233(uint8_t addr, TwoWire *wire = &Wire);
|
String get_device_model();
|
||||||
bool begin(const uint8_t sda, const uint8_t scl);
|
INA233(uint8_t addr, TwoWire* wire = &Wire);
|
||||||
|
bool begin(const uint8_t sda, const uint8_t scl);
|
||||||
|
|
||||||
float getBusVoltage(void);
|
float getBusVoltage(void);
|
||||||
float getShuntVoltage_mV(void);
|
float getShuntVoltage_mV(void);
|
||||||
float getShuntVoltage(void);
|
float getShuntVoltage(void);
|
||||||
|
|
||||||
void setAveragingMode(AveragingMode);
|
void setAveragingMode(AveragingMode);
|
||||||
void setBusVoltageConversionTime(ConversionTime);
|
void setBusVoltageConversionTime(ConversionTime);
|
||||||
void setShuntVoltageConversionTime(ConversionTime);
|
void setShuntVoltageConversionTime(ConversionTime);
|
||||||
|
|
||||||
uint16_t getConfigRegister();
|
|
||||||
|
|
||||||
bool isConnected(void);
|
uint16_t getConfigRegister();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void setCalibrationRegister(int value);
|
||||||
|
|
||||||
|
bool isConnected(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float _current_LSB;
|
float _current_LSB;
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
|
#include <WiFiClient.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
#include <HTTPUpdate.h>
|
#include <HTTPUpdate.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -22,14 +23,14 @@ Firmware OTA::getLatestVersionOnServer() {
|
|||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
http.begin(_serverUrl);
|
http.begin(_serverUrl);
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
Log.verbose("HTTP Code: %d", httpCode);
|
Logger.log(0, ELOG_LEVEL_DEBUG, "HTTP Code: %d", httpCode);
|
||||||
|
|
||||||
if (httpCode != 200) {
|
if (httpCode != 200) {
|
||||||
return createErrorResponse("HTTP GET request failed with code " + String(httpCode));
|
return createErrorResponse("HTTP GET request failed with code " + String(httpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
String payload = http.getString();
|
String payload = http.getString();
|
||||||
Log.verbose("Payload: %s", payload.c_str());
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Payload: %s", payload.c_str());
|
||||||
DynamicJsonDocument doc(4096);
|
DynamicJsonDocument doc(4096);
|
||||||
DeserializationError error = deserializeJson(doc, payload);
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ Firmware OTA::getLatestVersionOnServer() {
|
|||||||
deviceConfig
|
deviceConfig
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("Configuration %s does not match current device configuration %s", deviceConfig.c_str(), _current_device_configuration.c_str());
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Configuration %s does not match current device configuration %s", deviceConfig.c_str(), _current_device_configuration.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +68,7 @@ Firmware OTA::getLatestVersionOnServer() {
|
|||||||
Configuration latest = getLatestConfiguration(configs.data(), configs.size());
|
Configuration latest = getLatestConfiguration(configs.data(), configs.size());
|
||||||
|
|
||||||
if (!isVersionNewer(_currentVersion, latest.version)) {
|
if (!isVersionNewer(_currentVersion, latest.version)) {
|
||||||
Log.verbose("No newer version found. Server version: %d.%d.%d", latest.version.major, latest.version.minor, latest.version.patch);
|
Logger.log(0, ELOG_LEVEL_DEBUG, "No newer version found. Server version: %d.%d.%d", latest.version.major, latest.version.minor, latest.version.patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Firmware{
|
return Firmware{
|
||||||
@@ -88,79 +89,79 @@ Firmware OTA::createErrorResponse(const String& errorMsg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void run_ota_update(String url, std::function<void()> callback_started, std::function<void()> callback_finished, std::function<void(int, int)> callback_progress, std::function<void(int)> callback_error) {
|
void run_ota_update(String url, std::function<void()> callback_started, std::function<void()> callback_finished, std::function<void(int, int)> callback_progress, std::function<void(int)> callback_error) {
|
||||||
Log.verbose("Starting OTA upgrade");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Starting OTA upgrade");
|
||||||
HTTPUpdate httpUpdate;
|
HTTPUpdate httpUpdate;
|
||||||
httpUpdate.onStart(callback_started);
|
httpUpdate.onStart(callback_started);
|
||||||
httpUpdate.onEnd(callback_finished);
|
httpUpdate.onEnd(callback_finished);
|
||||||
httpUpdate.onProgress(callback_progress);
|
httpUpdate.onProgress(callback_progress);
|
||||||
httpUpdate.onError(callback_error);
|
httpUpdate.onError(callback_error);
|
||||||
Log.verbose("Defined callbacks, Starting update now");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Defined callbacks, Starting update now");
|
||||||
|
|
||||||
t_httpUpdate_return ret;
|
t_httpUpdate_return ret;
|
||||||
|
|
||||||
if (url.startsWith("https")) {
|
if (url.startsWith("https")) {
|
||||||
Log.verbose("HTTPS URL");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "HTTPS URL");
|
||||||
WiFiClientSecure client;
|
WiFiClient client;
|
||||||
client.setInsecure();
|
// client.setInsecure();
|
||||||
ret = httpUpdate.update(client, url);
|
ret = httpUpdate.update(client, url);
|
||||||
} else if (url.startsWith("http")) {
|
} else if (url.startsWith("http")) {
|
||||||
Log.verbose("HTTP URL");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "HTTP URL");
|
||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
ret = httpUpdate.update(client, url);
|
ret = httpUpdate.update(client, url);
|
||||||
} else {
|
} else {
|
||||||
Log.error("URL is not valid: \n%s", url.c_str());
|
Logger.log(0, ELOG_LEVEL_ERROR, "URL is not valid: \n%s", url.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case HTTP_UPDATE_FAILED:
|
case HTTP_UPDATE_FAILED:
|
||||||
Log.error("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
case HTTP_UPDATE_NO_UPDATES:
|
||||||
Log.error("HTTP_UPDATE_NO_UPDATES");
|
Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_NO_UPDATES");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HTTP_UPDATE_OK:
|
case HTTP_UPDATE_OK:
|
||||||
Log.verbose("Update done");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Update done");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_ota_spiffs_update(String url, std::function<void()> callback_started, std::function<void()> callback_finished, std::function<void(int, int)> callback_progress, std::function<void(int)> callback_error) {
|
void run_ota_spiffs_update(String url, std::function<void()> callback_started, std::function<void()> callback_finished, std::function<void(int, int)> callback_progress, std::function<void(int)> callback_error) {
|
||||||
Log.verbose("Starting OTA SPIFFS upgrade");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Starting OTA SPIFFS upgrade");
|
||||||
HTTPUpdate httpUpdate;
|
HTTPUpdate httpUpdate;
|
||||||
httpUpdate.onStart(callback_started);
|
httpUpdate.onStart(callback_started);
|
||||||
httpUpdate.onEnd(callback_finished);
|
httpUpdate.onEnd(callback_finished);
|
||||||
httpUpdate.onProgress(callback_progress);
|
httpUpdate.onProgress(callback_progress);
|
||||||
httpUpdate.onError(callback_error);
|
httpUpdate.onError(callback_error);
|
||||||
Log.verbose("Defined callbacks, Starting update now");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "Defined callbacks, Starting update now");
|
||||||
|
|
||||||
t_httpUpdate_return ret;
|
t_httpUpdate_return ret;
|
||||||
|
|
||||||
if (url.startsWith("https")) {
|
if (url.startsWith("https")) {
|
||||||
Log.verbose("HTTPS URL");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "HTTPS URL");
|
||||||
WiFiClientSecure client;
|
WiFiClient client;
|
||||||
client.setInsecure();
|
// client.setInsecure();
|
||||||
ret = httpUpdate.updateSpiffs(client, url);
|
ret = httpUpdate.updateSpiffs(client, url);
|
||||||
} else if (url.startsWith("http")) {
|
} else if (url.startsWith("http")) {
|
||||||
Log.verbose("HTTP URL");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "HTTP URL");
|
||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
ret = httpUpdate.updateSpiffs(client, url);
|
ret = httpUpdate.updateSpiffs(client, url);
|
||||||
} else {
|
} else {
|
||||||
Log.error("URL is not valid: \n%s", url.c_str());
|
Logger.log(0, ELOG_LEVEL_ERROR, "URL is not valid: \n%s", url.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case HTTP_UPDATE_FAILED:
|
case HTTP_UPDATE_FAILED:
|
||||||
Log.error("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
case HTTP_UPDATE_NO_UPDATES:
|
||||||
Log.error("HTTP_UPDATE_NO_UPDATES");
|
Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_NO_UPDATES");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HTTP_UPDATE_OK:
|
case HTTP_UPDATE_OK:
|
||||||
Log.verbose("SPIFFS Update done");
|
Logger.log(0, ELOG_LEVEL_DEBUG, "SPIFFS Update done");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,38 +11,40 @@
|
|||||||
[platformio]
|
[platformio]
|
||||||
default_envs = ESP32_INA233, ESP32_INA226
|
default_envs = ESP32_INA233, ESP32_INA226
|
||||||
|
|
||||||
[env:ESP32_INA233]
|
[env:esp32_base]
|
||||||
platform = espressif32
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.32/platform-espressif32.zip
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
monitor_filters = esp32_exception_decoder
|
||||||
|
board_build.partitions = min_spiffs.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ottowinter/ESPAsyncWebServer-esphome@^3.3.0
|
esp32async/AsyncTCP @ ~3.4.9
|
||||||
bblanchon/ArduinoJson@^6.21.3
|
esp32async/ESPAsyncWebServer @ ~3.8.1
|
||||||
jsc/ArduinoLog
|
robtillaart/INA226@ ~0.6.4
|
||||||
fetchOTA
|
bblanchon/ArduinoJson@^6.21.3
|
||||||
INA322
|
x385832/Elog@~2.0.10
|
||||||
ESP32Ping
|
fetchOTA
|
||||||
board_build.partitions = default.csv
|
build_flags = -fexceptions
|
||||||
|
build_src_flags = -Wall -Wextra
|
||||||
|
|
||||||
|
|
||||||
|
[env:ESP32_INA233]
|
||||||
|
extends = env:esp32_base
|
||||||
|
lib_deps =
|
||||||
|
${env:esp32_base.lib_deps}
|
||||||
|
INA233
|
||||||
upload_protocol = espota
|
upload_protocol = espota
|
||||||
upload_port = 10.1.10.22
|
upload_port = 192.168.5.205
|
||||||
build_flags = -Wall -Wextra
|
|
||||||
|
|
||||||
[env:ESP32_INA226]
|
[env:ESP32_INA226]
|
||||||
platform = espressif32
|
extends = env:esp32_base
|
||||||
board = esp32dev
|
|
||||||
framework = arduino
|
|
||||||
monitor_speed = 115200
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ottowinter/ESPAsyncWebServer-esphome@^3.3.0
|
${env:esp32_base.lib_deps}
|
||||||
robtillaart/INA226@^0.4.4
|
robtillaart/INA226@ ~0.6.4
|
||||||
bblanchon/ArduinoJson@^6.21.3
|
|
||||||
jsc/ArduinoLog
|
|
||||||
ESP32Ping
|
|
||||||
board_build.partitions = default.csv
|
|
||||||
upload_protocol = espota
|
upload_protocol = espota
|
||||||
upload_port = 192.168.5.181
|
upload_port = 192.168.6.45
|
||||||
build_flags = -Wall -Wextra -DUSE_INA226
|
build_flags = ${env:esp32_base.build_flags} -DUSE_INA226
|
||||||
|
|
||||||
[env:native]
|
[env:native]
|
||||||
platform = native
|
platform = native
|
||||||
@@ -50,3 +52,4 @@ build_flags = -DUNIT_TEST -Ilib/fetchOTA/
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
fetchOTA
|
fetchOTA
|
||||||
arduino-libraries/ArduinoHttpClient@^0.6.1
|
arduino-libraries/ArduinoHttpClient@^0.6.1
|
||||||
|
|
||||||
|
|||||||
@@ -1,96 +1,36 @@
|
|||||||
#include "leds.h"
|
#include "leds.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
#include "../tools/tools.h"
|
#include "../tools/tools.h"
|
||||||
|
#include <tools/log.h>
|
||||||
|
|
||||||
extern ActiveErrors active_errors;
|
extern ActiveErrors active_errors;
|
||||||
extern WaterData water_data;
|
extern WaterData water_data;
|
||||||
|
|
||||||
void display_percentage(float percentage)
|
|
||||||
{
|
|
||||||
digitalWrite(LED_RED, 0);
|
|
||||||
|
|
||||||
if (percentage > 0) {
|
|
||||||
digitalWrite(LED_1, 1);
|
|
||||||
} else {
|
|
||||||
digitalWrite(LED_1, 0);
|
|
||||||
}
|
|
||||||
if (percentage > 20) {
|
|
||||||
digitalWrite(LED_2, 1);
|
|
||||||
} else {
|
|
||||||
digitalWrite(LED_2, 0);
|
|
||||||
}
|
|
||||||
if (percentage > 40) {
|
|
||||||
digitalWrite(LED_3, 1);
|
|
||||||
} else {
|
|
||||||
digitalWrite(LED_3, 0);
|
|
||||||
}
|
|
||||||
if (percentage > 60) {
|
|
||||||
digitalWrite(LED_4, 1);
|
|
||||||
} else {
|
|
||||||
digitalWrite(LED_4, 0);
|
|
||||||
}
|
|
||||||
if (percentage > 80) {
|
|
||||||
digitalWrite(LED_5, 1);
|
|
||||||
} else {
|
|
||||||
digitalWrite(LED_5, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (percentage > 10) {
|
|
||||||
delay(3000);
|
|
||||||
} else if (percentage > 0) {
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
digitalWrite(LED_1, 1);
|
|
||||||
delay(500);
|
|
||||||
digitalWrite(LED_1, 0);
|
|
||||||
delay(500);
|
|
||||||
}
|
|
||||||
} else if (percentage <= 0) {
|
|
||||||
for (int i = 0; i < 15; i++) {
|
|
||||||
digitalWrite(LED_1, 1);
|
|
||||||
delay(100);
|
|
||||||
digitalWrite(LED_1, 0);
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void display_error_code(byte err_code)
|
|
||||||
{
|
|
||||||
digitalWrite(LED_RED, 1);
|
|
||||||
digitalWrite(LED_1, bitRead(err_code, 0));
|
|
||||||
digitalWrite(LED_2, bitRead(err_code, 1));
|
|
||||||
digitalWrite(LED_3, bitRead(err_code, 2));
|
|
||||||
digitalWrite(LED_4, bitRead(err_code, 3));
|
|
||||||
digitalWrite(LED_5, bitRead(err_code, 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
void display_task(void* parameter)
|
void display_task(void* parameter)
|
||||||
{
|
{
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Starting display tasks");
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!is_error(active_errors)) {
|
if (!is_error(active_errors)) {
|
||||||
// We have no error, refresh status display and wait half a second
|
// We have no error, refresh status display and wait half a second
|
||||||
display_percentage(water_data.percentage);
|
ledcWrite(LED_GREEN, 255);
|
||||||
|
ledcWrite(LED_RED, 0);
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("Error detected");
|
ledcWrite(LED_RED, LED_RED_HIGH);
|
||||||
|
ledcWrite(LED_GREEN, 0);
|
||||||
// We have an error, display error code for 3 seconds and then water level for 3 seconds
|
|
||||||
if (active_errors.voltage_low) {
|
|
||||||
display_error_code(1);
|
|
||||||
delay(3000);
|
|
||||||
} else if (active_errors.voltage_high) {
|
|
||||||
display_error_code(2);
|
|
||||||
delay(3000);
|
|
||||||
} else if (active_errors.current_low) {
|
|
||||||
display_error_code(3);
|
|
||||||
delay(3000);
|
|
||||||
} else if (active_errors.current_high) {
|
|
||||||
display_error_code(4);
|
|
||||||
delay(3000);
|
|
||||||
} else {
|
|
||||||
delay(3000);
|
|
||||||
}
|
|
||||||
display_percentage(water_data.percentage);
|
|
||||||
}
|
}
|
||||||
|
delay(250);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Setup pin modes etc.
|
||||||
|
void led_setup() {
|
||||||
|
pinMode(LED_RED, OUTPUT);
|
||||||
|
pinMode(LED_GREEN, OUTPUT);
|
||||||
|
|
||||||
|
ledcAttach(LED_RED, LED_PWM_FREQUENCY, LED_PWM_RESOLUTION);
|
||||||
|
ledcAttach(LED_GREEN, LED_PWM_FREQUENCY, LED_PWM_RESOLUTION);
|
||||||
|
ledcWrite(LED_RED, LED_RED_HIGH);
|
||||||
|
ledcWrite(LED_GREEN, 255);
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#define LED_1 4
|
#define LED_RED 15
|
||||||
#define LED_2 2
|
#define LED_GREEN 2
|
||||||
#define LED_3 15
|
#define LED_PWM_FREQUENCY 5000
|
||||||
#define LED_4 13
|
#define LED_PWM_RESOLUTION 8
|
||||||
#define LED_5 12
|
#define LED_CHANNEL_RED 0
|
||||||
#define LED_RED 14
|
#define LED_CHANNEL_GREEN 1
|
||||||
|
|
||||||
void display_percentage(float percentage);
|
#define LED_RED_HIGH 150
|
||||||
void display_error_code(byte err_code);
|
|
||||||
void display_task(void* parameter);
|
// void display_error_code(byte err_code);
|
||||||
|
void display_task(void* parameter);
|
||||||
|
void led_setup();
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
#define water_level_min_key "water_level_min"
|
#define water_level_min_key "water_level_min"
|
||||||
#define water_level_max_key "water_level_max"
|
#define water_level_max_key "water_level_max"
|
||||||
#define water_volume_key "water_volume"
|
#define water_volume_key "water_volume"
|
||||||
#define current_software_version Version{1, 0, 1}
|
#define current_software_version Version{2, 2, 0}
|
||||||
#define REQUIRED_SPIFFS_VERSION Version{8, 0, 0}
|
#define REQUIRED_SPIFFS_VERSION Version{9, 0, 0}
|
||||||
|
|
||||||
#define RESISTOR_VALUE 4
|
#define RESISTOR_VALUE 4
|
||||||
@@ -29,6 +29,7 @@ struct NetworkData {
|
|||||||
struct DeviceTelemetry {
|
struct DeviceTelemetry {
|
||||||
float heap_used_percent;
|
float heap_used_percent;
|
||||||
int uptime_seconds;
|
int uptime_seconds;
|
||||||
|
float temperature;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ActiveErrors {
|
struct ActiveErrors {
|
||||||
|
|||||||
198
src/main.cpp
198
src/main.cpp
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
|
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
|
|
||||||
@@ -24,8 +24,11 @@
|
|||||||
#include "networking/json_builder.h"
|
#include "networking/json_builder.h"
|
||||||
#include "networking/responses.h"
|
#include "networking/responses.h"
|
||||||
#include <fetchOTA.h>
|
#include <fetchOTA.h>
|
||||||
#include <ESP32Ping.h>
|
#include "time.h"
|
||||||
|
#include "tools/log.h"
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
#define MYLOG 0
|
||||||
|
|
||||||
Preferences prefs;
|
Preferences prefs;
|
||||||
|
|
||||||
@@ -34,99 +37,83 @@ extern DeviceTelemetry telemetry;
|
|||||||
extern NetworkData wifi_data;
|
extern NetworkData wifi_data;
|
||||||
extern NetworkData ethernet_data;
|
extern NetworkData ethernet_data;
|
||||||
extern SensorData shunt_data;
|
extern SensorData shunt_data;
|
||||||
|
extern ActiveErrors active_errors;
|
||||||
extern "C" int rom_phy_get_vdd33();
|
|
||||||
|
|
||||||
Version current_spiffs_version;
|
Version current_spiffs_version;
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
AsyncWebSocket ws("/ws");
|
AsyncWebSocket webSocket("/webSocket");
|
||||||
#define FORMAT_LITTLEFS_IF_FAILED true
|
#define FORMAT_LITTLEFS_IF_FAILED true
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
Logger.registerSerial(MYLOG, ELOG_LEVEL_DEBUG, "Serial");
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Init LEDs");
|
||||||
|
led_setup();
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Init Starting prefs and Serial output");
|
||||||
prefs.begin("waterlevel", false);
|
prefs.begin("waterlevel", false);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
Log.begin(LOG_LEVEL_VERBOSE, &Serial);
|
|
||||||
Log.setSuffix(printSuffix);
|
|
||||||
Log.setPrefix(print_prefix);
|
|
||||||
|
|
||||||
Log.verbose("Init LEDs");
|
|
||||||
pinMode(LED_1, OUTPUT);
|
|
||||||
pinMode(LED_2, OUTPUT);
|
|
||||||
pinMode(LED_3, OUTPUT);
|
|
||||||
pinMode(LED_4, OUTPUT);
|
|
||||||
pinMode(LED_5, OUTPUT);
|
|
||||||
pinMode(LED_RED, OUTPUT);
|
|
||||||
display_error_code(31);
|
|
||||||
delay(500);
|
delay(500);
|
||||||
display_error_code(17);
|
LOG(ELOG_LEVEL_DEBUG, "Init Sensor");
|
||||||
init_sensor();
|
init_sensor();
|
||||||
|
|
||||||
Log.verbose("Beginning SPIFFS");
|
LOG(ELOG_LEVEL_DEBUG, "Beginning LittleFS");
|
||||||
SPIFFS.begin(true);
|
LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED);
|
||||||
|
|
||||||
// Read the current SPIFFS version from the versions file on the spiffs
|
// Read the current SPIFFS version from the versions file on the spiffs
|
||||||
File file = SPIFFS.open("/version", FILE_READ);
|
LOG(ELOG_LEVEL_DEBUG, "Reading LittleFS version");
|
||||||
|
File file = LittleFS.open("/version", FILE_READ);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
Serial.println("Failed to open version file for reading");
|
LOG( ELOG_LEVEL_ERROR, "Failed opening LittleFS version file");
|
||||||
} else {
|
} else {
|
||||||
String version = file.readStringUntil('\n');
|
String version = file.readStringUntil('\n');
|
||||||
Log.verbose("Version: %s", version);
|
|
||||||
current_spiffs_version = parseVersion(version.c_str());
|
current_spiffs_version = parseVersion(version.c_str());
|
||||||
Log.verbose("Current SPIFFS Version: %d.%d.%d", current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch);
|
LOG(ELOG_LEVEL_DEBUG, "Current LittleFS Version: %d.%d.%d", current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch);
|
||||||
}
|
}
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "LittleFS initialized");
|
||||||
|
|
||||||
Log.verbose("SPIFFS initialized");
|
|
||||||
display_error_code(19);
|
|
||||||
|
|
||||||
Log.verbose("Begin INA");
|
|
||||||
|
|
||||||
display_error_code(22);
|
|
||||||
|
|
||||||
/////////////////////////////// ROUTES ///////////////////////////////
|
/////////////////////////////// ROUTES ///////////////////////////////
|
||||||
Log.verbose("Route Setup");
|
LOG(ELOG_LEVEL_DEBUG, "Route Setup");
|
||||||
|
|
||||||
// Normal HTML stuff
|
// Normal HTML stuff
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/status.html", "text/html", false, processor); });
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/status.html", "text/html", false, processor); });
|
||||||
|
|
||||||
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/settings.html", "text/html", false, processor); });
|
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/settings.html", "text/html", false, processor); });
|
||||||
|
|
||||||
server.on("/export", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/data_export.html", "text/html", false); });
|
server.on("/export", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/data_export.html", "text/html", false); });
|
||||||
|
|
||||||
server.on("/logic.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/logic.js", "application/javascript", false, processor); });
|
server.on("/logic.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/logic.js", "application/javascript", false, processor); });
|
||||||
|
|
||||||
server.on("/update", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/update_progress.html", "text/html", false, processor); });
|
server.on("/update", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/update_progress.html", "text/html", false, processor); });
|
||||||
|
|
||||||
// API stuff - internal
|
// API stuff - internal
|
||||||
server.on("/update_wifi_credentials", HTTP_POST, [](AsyncWebServerRequest* request) {
|
server.on("/update_wifi_credentials", HTTP_POST, [](AsyncWebServerRequest* request) {
|
||||||
int params = request->params();
|
|
||||||
|
|
||||||
// For settings SSID
|
// For settings SSID
|
||||||
if (request->hasParam(ssid_key, true) && request->hasParam(wifi_password_key, true)) {
|
if (request->hasParam(ssid_key, true) && request->hasParam(wifi_password_key, true)) {
|
||||||
Log.verbose("Updating SSID config");
|
LOG(ELOG_LEVEL_DEBUG, "Updating SSID config");
|
||||||
AsyncWebParameter* ssid_param = request->getParam(ssid_key, true);
|
const AsyncWebParameter* ssid_param = request->getParam(ssid_key, true);
|
||||||
AsyncWebParameter* password_param = request->getParam(wifi_password_key, true);
|
const AsyncWebParameter* password_param = request->getParam(wifi_password_key, true);
|
||||||
prefs.putString(ssid_key, ssid_param->value().c_str());
|
prefs.putString(ssid_key, ssid_param->value().c_str());
|
||||||
prefs.putString(wifi_password_key, password_param->value().c_str());
|
prefs.putString(wifi_password_key, password_param->value().c_str());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages
|
request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages
|
||||||
}
|
}
|
||||||
request->send(SPIFFS, "/settings.html", "text/html", false, processor); // TODO add proper return templating
|
request->send(LittleFS, "/settings.html", "text/html", false, processor); // TODO add proper return templating
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/update_sensor_settings", HTTP_POST, [](AsyncWebServerRequest* request) {
|
server.on("/update_sensor_settings", HTTP_POST, [](AsyncWebServerRequest* request) {
|
||||||
int params = request->params();
|
int params = request->params();
|
||||||
|
|
||||||
if (request->hasParam(level_sensor_range_key, true) && request->hasParam(water_level_min_key, true) && request->hasParam(water_level_max_key, true) && request->hasParam(water_volume_key, true)) {
|
if (request->hasParam(level_sensor_range_key, true) && request->hasParam(water_level_min_key, true) && request->hasParam(water_level_max_key, true) && request->hasParam(water_volume_key, true)) {
|
||||||
Log.verbose("Updating Sensor config");
|
LOG(ELOG_LEVEL_DEBUG, "Updating Sensor config");
|
||||||
AsyncWebParameter* range_param = request->getParam(level_sensor_range_key, true);
|
const AsyncWebParameter* range_param = request->getParam(level_sensor_range_key, true);
|
||||||
AsyncWebParameter* level_min_param = request->getParam(water_level_min_key, true);
|
const AsyncWebParameter* level_min_param = request->getParam(water_level_min_key, true);
|
||||||
AsyncWebParameter* level_max_param = request->getParam(water_level_max_key, true);
|
const AsyncWebParameter* level_max_param = request->getParam(water_level_max_key, true);
|
||||||
AsyncWebParameter* liters_param = request->getParam(water_volume_key, true);
|
const AsyncWebParameter* liters_param = request->getParam(water_volume_key, true);
|
||||||
|
|
||||||
String range_str = range_param->value();
|
String range_str = range_param->value();
|
||||||
String level_min_str = level_min_param->value();
|
String level_min_str = level_min_param->value();
|
||||||
@@ -138,113 +125,76 @@ void setup()
|
|||||||
float level_max_float = level_max_str.toFloat();
|
float level_max_float = level_max_str.toFloat();
|
||||||
float liters_float = liters_str.toFloat();
|
float liters_float = liters_str.toFloat();
|
||||||
|
|
||||||
const char* paramCStr = range_str.c_str();
|
LOG(ELOG_LEVEL_DEBUG, "range_float:%D:", range_float);
|
||||||
char* endPtr;
|
|
||||||
|
|
||||||
// Convert the C string to a float using strtod
|
|
||||||
float value = strtod(paramCStr, &endPtr);
|
|
||||||
|
|
||||||
Log.verbose("range_float:%D:", range_float);
|
|
||||||
|
|
||||||
prefs.putFloat(level_sensor_range_key, range_float);
|
prefs.putFloat(level_sensor_range_key, range_float);
|
||||||
prefs.putFloat(water_level_min_key, level_min_float);
|
prefs.putFloat(water_level_min_key, level_min_float);
|
||||||
prefs.putFloat(water_level_max_key, level_max_float);
|
prefs.putFloat(water_level_max_key, level_max_float);
|
||||||
prefs.putFloat(water_volume_key, liters_float);
|
prefs.putFloat(water_volume_key, liters_float);
|
||||||
|
|
||||||
Log.verbose("range_float_after:%D:", prefs.getFloat(level_sensor_range_key, -1.0));
|
LOG(ELOG_LEVEL_DEBUG, "range_float_after:%D:", prefs.getFloat(level_sensor_range_key, -1.0));
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("!!!! FAIL lo");
|
LOG(ELOG_LEVEL_DEBUG, "!!!! FAIL lo");
|
||||||
for (int i = 0; i < params; i++) {
|
for (int i = 0; i < params; i++) {
|
||||||
AsyncWebParameter* p = request->getParam(i);
|
const AsyncWebParameter* p = request->getParam(i);
|
||||||
if (p->isFile()) { // p->isPost() is also true
|
if (p->isFile()) { // p->isPost() is also true
|
||||||
Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
LOG(ELOG_LEVEL_DEBUG, "POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
} else if (p->isPost()) {
|
} else if (p->isPost()) {
|
||||||
Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
LOG(ELOG_LEVEL_DEBUG, "POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
LOG(ELOG_LEVEL_DEBUG, "GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages
|
request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages
|
||||||
}
|
}
|
||||||
request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating
|
request->send(LittleFS, "/settings.html", "text/html", false); // TODO add proper return templating
|
||||||
});
|
});
|
||||||
|
|
||||||
setup_api_endpoints();
|
setup_api_endpoints();
|
||||||
display_error_code(23);
|
webSocket.onEvent(onWsEvent);
|
||||||
ws.onEvent(onWsEvent);
|
server.addHandler(&webSocket);
|
||||||
server.addHandler(&ws);
|
|
||||||
|
server.on("/chota.css", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/chota.css", "text/css", false); });
|
||||||
|
server.on("/gauge.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(LittleFS, "/gauge.js", "application/javascript", false); });
|
||||||
|
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "OTA Setup");
|
||||||
server.on("/chota.css", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/chota.css", "text/css", false); });
|
|
||||||
server.on("/gauge.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/gauge.js", "application/javascript", false); });
|
|
||||||
|
|
||||||
display_error_code(24);
|
|
||||||
|
|
||||||
Log.verbose("OTA Setup");
|
|
||||||
ArduinoOTA
|
ArduinoOTA
|
||||||
.onStart([]() {
|
.onStart([]() {
|
||||||
String type;
|
String type;
|
||||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||||
type = "sketch";
|
type = "sketch";
|
||||||
else // U_SPIFFS
|
else // U_SPIFFS
|
||||||
type = "filesystem";
|
type = "filesystem";
|
||||||
|
|
||||||
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
||||||
Log.verbose("Start updating %s", type); })
|
LOG(ELOG_LEVEL_DEBUG, "Start updating %s", type); })
|
||||||
.onEnd([]() { Log.verbose("\nEnd"); })
|
.onEnd([]() { LOG(ELOG_LEVEL_DEBUG, "\nEnd"); })
|
||||||
.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); })
|
.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); })
|
||||||
.onError([](ota_error_t error) {
|
.onError([](ota_error_t error) {
|
||||||
Serial.printf("Error[%u]: ", error);
|
Serial.printf("Error[%u]: ", error);
|
||||||
if (error == OTA_AUTH_ERROR) Log.verbose("Auth Failed");
|
if (error == OTA_AUTH_ERROR) LOG(ELOG_LEVEL_DEBUG, "Auth Failed");
|
||||||
else if (error == OTA_BEGIN_ERROR) Log.verbose("Begin Failed");
|
else if (error == OTA_BEGIN_ERROR) LOG(ELOG_LEVEL_DEBUG, "Begin Failed");
|
||||||
else if (error == OTA_CONNECT_ERROR) Log.verbose("Connect Failed");
|
else if (error == OTA_CONNECT_ERROR) LOG(ELOG_LEVEL_DEBUG, "Connect Failed");
|
||||||
else if (error == OTA_RECEIVE_ERROR) Log.verbose("Receive Failed");
|
else if (error == OTA_RECEIVE_ERROR) LOG(ELOG_LEVEL_DEBUG, "Receive Failed");
|
||||||
else if (error == OTA_END_ERROR) Log.verbose("End Failed"); });
|
else if (error == OTA_END_ERROR) LOG(ELOG_LEVEL_DEBUG, "End Failed"); });
|
||||||
|
|
||||||
display_error_code(26);
|
|
||||||
digitalWrite(LED_RED, 0);
|
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Starting main tasks");
|
||||||
xTaskCreate(ethernet_task, "EthernetTask", 4096, NULL, 1, NULL);
|
xTaskCreate(ethernet_task, "EthernetTask", 4096, NULL, 1, NULL);
|
||||||
delay(1000);
|
|
||||||
bool started = false;
|
|
||||||
if (ETH.linkUp()){
|
|
||||||
xTaskCreate(check_update_task, "CheckUpdateTask", 1024 * 8, NULL, 1, NULL);
|
|
||||||
started = true;
|
|
||||||
}
|
|
||||||
xTaskCreate(wifi_task, "WiFiTask", 10000, NULL, 1, NULL);
|
xTaskCreate(wifi_task, "WiFiTask", 10000, NULL, 1, NULL);
|
||||||
if (!started) {
|
xTaskCreate(read_sensor_task, "ReadSensorTask", 1024 * 4, NULL, 1, NULL);
|
||||||
xTaskCreate(check_update_task, "CheckUpdateTask", 1024 * 8, NULL, 1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Log.verbose("Starting webserver");
|
|
||||||
server.begin();
|
|
||||||
ArduinoOTA.begin();
|
|
||||||
display_error_code(25);
|
|
||||||
|
|
||||||
xTaskCreate(display_task, "DisplayTask", 10000, NULL, 1, NULL);
|
|
||||||
xTaskCreate(read_sensor_task, "ReadSensorTask", 2048, NULL, 1, NULL);
|
|
||||||
xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 2048, NULL, 1, NULL);
|
xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 2048, NULL, 1, NULL);
|
||||||
|
xTaskCreate(display_task, "DisplayTask", 10000, NULL, 1, NULL);
|
||||||
|
xTaskCreate(get_time_task, "GetTimeTask", 1024 * 4, NULL, 1, NULL);
|
||||||
|
|
||||||
// Wait until there is network connection
|
delay(5000);
|
||||||
while (true) {
|
xTaskCreate(check_update_task, "CheckUpdateTask", 1024 * 8, NULL, 1, NULL);
|
||||||
if (WiFi.status() == WL_CONNECTED || ETH.localIP()) {
|
|
||||||
int pingResult = Ping.ping("8.8.8.8"); // Use Google's public DNS server as a test IP
|
LOG(ELOG_LEVEL_DEBUG, "Starting webserver");
|
||||||
if (pingResult >= 0) {
|
server.begin();
|
||||||
Log.verbose("Network connection established");
|
LOG(ELOG_LEVEL_DEBUG, "Starting OTA handler");
|
||||||
break;
|
ArduinoOTA.begin();
|
||||||
} else {
|
|
||||||
Log.verbose("Network not ready, retrying...");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.verbose("No WiFi or Ethernet connection, retrying...");
|
|
||||||
}
|
|
||||||
delay(1000); // Delay to prevent rapid retry
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "json_builder.h"
|
#include "json_builder.h"
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
|
|
||||||
extern WaterData water_data;
|
extern WaterData water_data;
|
||||||
extern DeviceTelemetry telemetry;
|
extern DeviceTelemetry telemetry;
|
||||||
@@ -27,6 +27,7 @@ StaticJsonDocument<128> build_telemetry_json(DeviceTelemetry data) {
|
|||||||
StaticJsonDocument<128> doc;
|
StaticJsonDocument<128> doc;
|
||||||
doc["uptime_seconds"] = data.uptime_seconds;
|
doc["uptime_seconds"] = data.uptime_seconds;
|
||||||
doc["heap_percent"] = data.heap_used_percent;
|
doc["heap_percent"] = data.heap_used_percent;
|
||||||
|
doc["temperature"] = data.temperature;
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
#include <ETH.h>
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include "../global_data/defines.h"
|
#include "../global_data/defines.h"
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include "../global_data/global_data.h"
|
#include "../global_data/global_data.h"
|
||||||
|
#include <tools/log.h>
|
||||||
|
|
||||||
|
#define ETH_PHY_TYPE ETH_PHY_LAN8720
|
||||||
|
#define ETH_PHY_ADDR 0
|
||||||
|
#define ETH_PHY_MDC 23
|
||||||
|
#define ETH_PHY_MDIO 18
|
||||||
|
#define ETH_PHY_POWER 14
|
||||||
|
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
|
||||||
|
|
||||||
|
|
||||||
|
#include <ETH.h>
|
||||||
|
|
||||||
int64_t mac_address = ESP.getEfuseMac();
|
int64_t mac_address = ESP.getEfuseMac();
|
||||||
uint8_t failed_connection_attempts = 0;
|
uint8_t failed_connection_attempts = 0;
|
||||||
@@ -12,6 +22,7 @@ extern NetworkData wifi_data;
|
|||||||
extern NetworkData ethernet_data;
|
extern NetworkData ethernet_data;
|
||||||
extern Preferences prefs;
|
extern Preferences prefs;
|
||||||
|
|
||||||
|
// Defines the type of connection for which the hostname should be created
|
||||||
enum HostnameType {
|
enum HostnameType {
|
||||||
Wireless,
|
Wireless,
|
||||||
Ethernet,
|
Ethernet,
|
||||||
@@ -27,28 +38,28 @@ const char * get_hostname(HostnameType host_type) {
|
|||||||
return (hostname + "-wl").c_str();
|
return (hostname + "-wl").c_str();
|
||||||
case Ethernet:
|
case Ethernet:
|
||||||
return (hostname + "-eth").c_str();
|
return (hostname + "-eth").c_str();
|
||||||
case Generic:
|
default:
|
||||||
return hostname.c_str();
|
return hostname.c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_task(void* parameter)
|
void wifi_task(void* parameter)
|
||||||
{
|
{
|
||||||
Log.verbose("Starting WiFi Task");
|
LOG(ELOG_LEVEL_DEBUG, "Starting WiFi Task");
|
||||||
WiFi.setHostname(get_hostname(Wireless));
|
WiFi.setHostname(get_hostname(Wireless));
|
||||||
while (true) {
|
while (true) {
|
||||||
if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5) {
|
if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5) {
|
||||||
wifi_data.link = false;
|
wifi_data.link = false;
|
||||||
if (failed_connection_attempts > 5) {
|
if (failed_connection_attempts > 5) {
|
||||||
Log.verbose("Failed to connecto to currently saved SSID, starting SoftAP");
|
LOG(ELOG_LEVEL_WARNING, "Failed to connect to currently saved SSID, starting SoftAP");
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("No SSID saved, starting SoftAP");
|
LOG(ELOG_LEVEL_WARNING, "No SSID saved, starting SoftAP");
|
||||||
}
|
}
|
||||||
|
|
||||||
String ap_ssid = get_hostname(Wireless);
|
String ap_ssid = get_hostname(Wireless);
|
||||||
WiFi.softAP(ap_ssid, "");
|
WiFi.softAP(ap_ssid.c_str(), "");
|
||||||
|
|
||||||
Log.verbose("[WIFI_TASK] Waiting for SSID now...");
|
LOG(ELOG_LEVEL_DEBUG, "Waiting for SSID now...");
|
||||||
|
|
||||||
String old_ssid = prefs.getString(ssid_key, "xxx");
|
String old_ssid = prefs.getString(ssid_key, "xxx");
|
||||||
while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid) {
|
while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid) {
|
||||||
@@ -63,15 +74,16 @@ void wifi_task(void* parameter)
|
|||||||
wifi_data.link = true;
|
wifi_data.link = true;
|
||||||
wifi_data.network_name = WiFi.SSID();
|
wifi_data.network_name = WiFi.SSID();
|
||||||
wifi_data.ip_address = WiFi.localIP().toString();
|
wifi_data.ip_address = WiFi.localIP().toString();
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "WIFI connected; RSSI: %F, IP Address, %s, SSID: %s", float(WiFi.RSSI()), WiFi.localIP().toString(), prefs.getString(ssid_key, "NOSSID"));
|
||||||
// Log.verbose("RSSI: %F, IP Address, %p, SSID: %s", float(WiFi.RSSI()), WiFi.localIP(), prefs.getString(ssid_key, "NOSSID"));
|
delay(1000 * 60);
|
||||||
// Serial.println(WiFi.channel());
|
|
||||||
delay(5000);
|
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("Connecting to %s using password %s", prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, ""));
|
String ssid = prefs.getString(ssid_key, "");
|
||||||
|
String password = prefs.getString(wifi_password_key, "");
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Connecting to %s...", ssid);
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, ""));
|
WiFi.begin(ssid, password);
|
||||||
failed_connection_attempts++;
|
failed_connection_attempts++;
|
||||||
|
LOG(ELOG_LEVEL_WARNING, "Failed to connect, retrying...");
|
||||||
delay(5000);
|
delay(5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,14 +92,20 @@ void wifi_task(void* parameter)
|
|||||||
|
|
||||||
void ethernet_task(void* parameter)
|
void ethernet_task(void* parameter)
|
||||||
{
|
{
|
||||||
Log.verbose("Connecting Ethernet");
|
LOG(ELOG_LEVEL_DEBUG, "Starting Ethernet Task");
|
||||||
ETH.begin(0, 17, 23, 18);
|
ETH.begin();
|
||||||
ETH.setHostname(get_hostname(Ethernet));
|
ETH.setHostname(get_hostname(Ethernet));
|
||||||
while (true) {
|
while (true) {
|
||||||
ethernet_data.link = ETH.linkUp();
|
ethernet_data.link = ETH.linkUp();
|
||||||
ethernet_data.rssi = ETH.linkSpeed();
|
ethernet_data.rssi = ETH.linkSpeed();
|
||||||
ethernet_data.ip_address = ETH.localIP().toString();
|
ethernet_data.ip_address = ETH.localIP().toString();
|
||||||
// Log.verbose("Ethernet RSSI: %F, IP Address, %s, LINK: %s", float(ethernet_data.rssi), ethernet_data.ip_address, String(ethernet_data.link));
|
LOG(ELOG_LEVEL_DEBUG, "Ethernet RSSI: %F, IP Address, %s, LINK: %s", float(ethernet_data.rssi), ETH.localIP().toString(), String(ethernet_data.link));
|
||||||
|
|
||||||
|
if (ETH.linkUp() && !ETH.isDefault() && ETH.localIP().toString() != "0.0.0.0") {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Ethernet is up, setting to default");
|
||||||
|
ETH.setDefault();
|
||||||
|
}
|
||||||
|
|
||||||
delay(60 * 1000);
|
delay(60 * 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
#include "json_builder.h"
|
#include "json_builder.h"
|
||||||
#include "../tools/tools.h"
|
#include "../tools/tools.h"
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
@@ -71,6 +71,6 @@ void setup_api_endpoints(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
xTaskCreate(run_ota_update_task, "RunOTAUpdate", 1024 * 8, (void *)&args, 1, NULL);
|
xTaskCreate(run_ota_update_task, "RunOTAUpdate", 1024 * 8, (void *)&args, 1, NULL);
|
||||||
request->send(SPIFFS, "/update_progress.html", "text/html", false, processor);
|
request->send(LittleFS, "/update_progress.html", "text/html", false, processor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
void setup_api_endpoints();
|
void setup_api_endpoints();
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "../global_data/defines.h"
|
#include "../global_data/defines.h"
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
#include "Wire.h"
|
#include "Wire.h"
|
||||||
#include "../global_data/global_data.h"
|
#include "../global_data/global_data.h"
|
||||||
|
|
||||||
@@ -12,6 +12,10 @@ INA226 ina_sensor(0x40);
|
|||||||
#include <INA233.h>
|
#include <INA233.h>
|
||||||
INA233 ina_sensor(0x40);
|
INA233 ina_sensor(0x40);
|
||||||
#endif
|
#endif
|
||||||
|
#include <tools/log.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
extern Preferences prefs;
|
extern Preferences prefs;
|
||||||
extern WaterData water_data;
|
extern WaterData water_data;
|
||||||
@@ -22,27 +26,38 @@ extern SensorData shunt_data;
|
|||||||
float zero_value = 0.03; // Measured shunt voltage with nothing connected, used to fix measuring offset
|
float zero_value = 0.03; // Measured shunt voltage with nothing connected, used to fix measuring offset
|
||||||
|
|
||||||
void init_sensor(){
|
void init_sensor(){
|
||||||
ina_sensor.begin(33, 32);
|
|
||||||
#ifdef USE_INA226
|
#ifdef USE_INA226
|
||||||
|
Wire.begin(33, 32);
|
||||||
|
ina_sensor.begin();
|
||||||
ina_sensor.setMaxCurrentShunt(0.02, 4, false);
|
ina_sensor.setMaxCurrentShunt(0.02, 4, false);
|
||||||
ina_sensor.setBusVoltageConversionTime(7);
|
ina_sensor.setBusVoltageConversionTime(7);
|
||||||
ina_sensor.setShuntVoltageConversionTime(7);
|
ina_sensor.setShuntVoltageConversionTime(7);
|
||||||
ina_sensor.setAverage(4);
|
ina_sensor.setAverage(4);
|
||||||
#else
|
#else
|
||||||
|
ina_sensor.begin(33, 32);
|
||||||
|
ina_sensor.reset();
|
||||||
ina_sensor.setShuntVoltageConversionTime(conversion_time_8244uS);
|
ina_sensor.setShuntVoltageConversionTime(conversion_time_8244uS);
|
||||||
ina_sensor.setBusVoltageConversionTime(conversion_time_8244uS);
|
ina_sensor.setBusVoltageConversionTime(conversion_time_8244uS);
|
||||||
ina_sensor.setAveragingMode(averages_128);
|
ina_sensor.setAveragingMode(averages_128);
|
||||||
|
ina_sensor.setCalibrationRegister(128);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_sensor_task(void* parameter)
|
void read_sensor_task(void* parameter)
|
||||||
{
|
{
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Starting read sensor tasks");
|
||||||
while (true) {
|
while (true) {
|
||||||
// Get Values from sensor
|
// Get Values from sensor
|
||||||
|
#ifndef USE_INA226
|
||||||
|
String chip_id = ina_sensor.get_device_model();
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Chip Model: %s", chip_id.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
float bus_voltage = ina_sensor.getBusVoltage();
|
float bus_voltage = ina_sensor.getBusVoltage();
|
||||||
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
|
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "RAW Shunt voltage: %F mV", ina_sensor.getShuntVoltage_mV());
|
||||||
|
|
||||||
float shunt_current = shunt_voltage / RESISTOR_VALUE;
|
float shunt_current = shunt_voltage / RESISTOR_VALUE;
|
||||||
|
|
||||||
// Get values from storage
|
// Get values from storage
|
||||||
@@ -61,8 +76,8 @@ void read_sensor_task(void* parameter)
|
|||||||
float min_water_level_mA = 4 + min_water_level_mA_over_zero;
|
float min_water_level_mA = 4 + min_water_level_mA_over_zero;
|
||||||
float max_water_level_mA = 4 + max_water_level_mA_over_zero;
|
float max_water_level_mA = 4 + max_water_level_mA_over_zero;
|
||||||
|
|
||||||
// Log.verbose("max_water_level_mA: %F", max_water_level_mA);
|
LOG(ELOG_LEVEL_DEBUG, "max_water_level_mA: %F", max_water_level_mA);
|
||||||
// Log.verbose("min_water_level_mA_over_zero: %F", min_water_level_mA_over_zero);
|
LOG(ELOG_LEVEL_DEBUG, "min_water_level_mA_over_zero: %F", min_water_level_mA_over_zero);
|
||||||
|
|
||||||
// Current over the 0 level of the water
|
// Current over the 0 level of the water
|
||||||
float shunt_current_over_zero = shunt_current - min_water_level_mA;
|
float shunt_current_over_zero = shunt_current - min_water_level_mA;
|
||||||
@@ -82,10 +97,10 @@ void read_sensor_task(void* parameter)
|
|||||||
active_errors.current_high = shunt_current > 20.2;
|
active_errors.current_high = shunt_current > 20.2;
|
||||||
active_errors.voltage_low = bus_voltage < 23;
|
active_errors.voltage_low = bus_voltage < 23;
|
||||||
active_errors.voltage_high = bus_voltage > 25;
|
active_errors.voltage_high = bus_voltage > 25;
|
||||||
// Log.verbose("Shunt current: %F", shunt_current);
|
LOG(ELOG_LEVEL_DEBUG, "Shunt current: %F", shunt_current);
|
||||||
// Log.verbose("Shunt voltage: %F", shunt_voltage);
|
LOG(ELOG_LEVEL_DEBUG, "Shunt voltage: %F", shunt_voltage);
|
||||||
// Log.verbose("Bus voltage: %F", bus_voltage);
|
LOG(ELOG_LEVEL_DEBUG, "Bus voltage: %F", bus_voltage);
|
||||||
// Log.verbose("cm_over_zero: %F", cm_over_zero);
|
LOG(ELOG_LEVEL_DEBUG, "cm_over_zero: %F", cm_over_zero);
|
||||||
|
|
||||||
shunt_data.bus_voltage = bus_voltage;
|
shunt_data.bus_voltage = bus_voltage;
|
||||||
shunt_data.shunt_voltage = shunt_voltage;
|
shunt_data.shunt_voltage = shunt_voltage;
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
#include "telemetry.h"
|
#include "telemetry.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "../global_data/global_data.h"
|
#include "../global_data/global_data.h"
|
||||||
|
#include "tools/log.h"
|
||||||
|
|
||||||
|
extern "C" uint8_t temprature_sens_read();
|
||||||
|
|
||||||
extern DeviceTelemetry telemetry;
|
extern DeviceTelemetry telemetry;
|
||||||
|
|
||||||
void collect_internal_telemetry_task(void* parameter)
|
void collect_internal_telemetry_task(void* parameter)
|
||||||
{
|
{
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Starting internal telemetry tasks");
|
||||||
while (true) {
|
while (true) {
|
||||||
float heap_usage = (float(ESP.getFreeHeap()) / float(ESP.getHeapSize())) * 100;
|
float heap_usage = (float(ESP.getFreeHeap()) / float(ESP.getHeapSize())) * 100;
|
||||||
uint64_t uptime_seconds = millis() / 1000;
|
uint64_t uptime_seconds = millis() / 1000;
|
||||||
|
|
||||||
telemetry.heap_used_percent = heap_usage;
|
telemetry.heap_used_percent = heap_usage;
|
||||||
telemetry.uptime_seconds = uptime_seconds;
|
telemetry.uptime_seconds = uptime_seconds;
|
||||||
|
telemetry.temperature = (temprature_sens_read()-32) / 1.8;
|
||||||
delay(60000);
|
delay(60000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
12
src/tools/log.h
Normal file
12
src/tools/log.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include <Elog.h>
|
||||||
|
|
||||||
|
#define LOG(LEVEL, FMT, ...) \
|
||||||
|
do { \
|
||||||
|
Logger.log(0, LEVEL, "[Core: %i][Task: %s][Fn: %s] " FMT, \
|
||||||
|
xPortGetCoreID(), \
|
||||||
|
pcTaskGetName(xTaskGetCurrentTaskHandle()), \
|
||||||
|
__FUNCTION__, \
|
||||||
|
##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
@@ -1,31 +1,26 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include <ArduinoLog.h>
|
#include <Elog.h>
|
||||||
#include "../global_data/defines.h"
|
#include "../global_data/defines.h"
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <fetchOTA.h>
|
#include <fetchOTA.h>
|
||||||
#include <AsyncWebSocket.h>
|
#include <AsyncWebSocket.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "esp_sntp.h"
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
|
||||||
|
#ifdef USE_INA226
|
||||||
|
#define BOARD_VARIANT "INA226REV2"
|
||||||
|
#else
|
||||||
|
#define BOARD_VARIANT "INA233REV2"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern Preferences prefs;
|
extern Preferences prefs;
|
||||||
extern OTAStatus ota_status;
|
extern OTAStatus ota_status;
|
||||||
extern AsyncWebSocket ws;
|
extern AsyncWebSocket webSocket;
|
||||||
|
|
||||||
extern Version current_spiffs_version;
|
extern Version current_spiffs_version;
|
||||||
|
|
||||||
void printSuffix(Print* _logOutput, int logLevel)
|
|
||||||
{
|
|
||||||
_logOutput->print(CR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_prefix(Print* _logOutput, int logLevel)
|
|
||||||
{
|
|
||||||
_logOutput->print("WATERMETER - TESTLOL - C");
|
|
||||||
_logOutput->print(xPortGetCoreID());
|
|
||||||
_logOutput->print(" - ");
|
|
||||||
_logOutput->print(pcTaskGetName(xTaskGetCurrentTaskHandle()));
|
|
||||||
_logOutput->print(" - ");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_error(ActiveErrors active_errors) {
|
bool is_error(ActiveErrors active_errors) {
|
||||||
return active_errors.current_high || active_errors.current_low || active_errors.level_high || active_errors.level_low || active_errors.voltage_high || active_errors.voltage_low;
|
return active_errors.current_high || active_errors.current_low || active_errors.level_high || active_errors.level_low || active_errors.voltage_high || active_errors.voltage_low;
|
||||||
}
|
}
|
||||||
@@ -49,93 +44,117 @@ String processor(const String& var)
|
|||||||
|
|
||||||
// OTA Callbacks
|
// OTA Callbacks
|
||||||
void update_started() {
|
void update_started() {
|
||||||
Log.verbose("OTA Update started");
|
LOG(ELOG_LEVEL_DEBUG, "OTA Update started");
|
||||||
ota_status.update_progress = 0;
|
ota_status.update_progress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_finished() {
|
void update_finished() {
|
||||||
Log.verbose("OTA Update finished");
|
LOG(ELOG_LEVEL_DEBUG, "OTA Update finished");
|
||||||
ota_status.update_progress = -1;
|
ota_status.update_progress = -1;
|
||||||
ws.textAll(String(-1).c_str());
|
webSocket.textAll(String(-1).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_progress(int cur, int total) {
|
void update_progress(int cur, int total) {
|
||||||
ota_status.update_progress = 0;
|
ota_status.update_progress = 0;
|
||||||
if (cur != 0 ) {
|
if (cur != 0 ) {
|
||||||
ota_status.update_progress = int(float(cur)/float(total)*100);
|
ota_status.update_progress = int(float(cur)/float(total)*100);
|
||||||
Log.verbose("OTA Update progress: %d/%d, %i", cur, total, ota_status.update_progress);
|
LOG(ELOG_LEVEL_DEBUG, "OTA Update progress: %d/%d, %i", cur, total, ota_status.update_progress);
|
||||||
}
|
}
|
||||||
ws.textAll(String(ota_status.update_progress).c_str());
|
webSocket.textAll(String(ota_status.update_progress).c_str());
|
||||||
Log.verbose("OTA Update progress: %d/%d", cur, total);
|
LOG(ELOG_LEVEL_DEBUG, "OTA Update progress: %d/%d", cur, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_error(int err) {
|
void update_error(int err) {
|
||||||
Log.error("OTA Update error: %d", err);
|
LOG(ELOG_LEVEL_ERROR, "OTA Update error: %d", err);
|
||||||
ota_status.update_progress = -2;
|
ota_status.update_progress = -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_update_task(void* parameter) {
|
void check_update_task(void* parameter) {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Starting check Update Task");
|
||||||
ota_status.current_version = current_software_version;
|
ota_status.current_version = current_software_version;
|
||||||
ota_status.update_progress = -1;
|
ota_status.update_progress = -1;
|
||||||
#ifdef USE_INA226
|
|
||||||
OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", current_software_version, "INA226");
|
|
||||||
#else
|
|
||||||
OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", current_software_version, "INA233");
|
|
||||||
#endif
|
|
||||||
OTA spiffs_fs("https://iot.tobiasmaier.me/filesystem/waterlevel", REQUIRED_SPIFFS_VERSION, "generic");
|
|
||||||
|
|
||||||
|
|
||||||
// Init SPIFFS update and check for update
|
|
||||||
// If there is a SPIFSS update it will be ran automatically, as SPIFFS is necessary for the firmware to run
|
|
||||||
Firmware latest_spiff_version = spiffs_fs.getLatestVersionOnServer();
|
|
||||||
|
|
||||||
Log.verbose("Required SPIFFS Version: %d.%d.%d; Current SPIFFS version: %d.%d.%d; Server SPIFFS Version: %d.%d.%d", REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch, current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch, latest_spiff_version.version.major, latest_spiff_version.version.minor, latest_spiff_version.version.patch);
|
|
||||||
|
|
||||||
if (latest_spiff_version.valid) {
|
|
||||||
if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION)) {
|
|
||||||
// If Required SPIFFS version is newer than current version, update
|
|
||||||
Log.verbose("New SPIFFS version, running update now");
|
|
||||||
run_ota_spiffs_update(latest_spiff_version.url, update_started, update_finished, update_progress, update_error);
|
|
||||||
// Reboot just to be safe
|
|
||||||
ESP.restart();
|
|
||||||
} else if (isVersionNewer(REQUIRED_SPIFFS_VERSION, latest_spiff_version.version)) {
|
|
||||||
// If Server has new SPIFFS version but it's not required
|
|
||||||
Log.verbose("New SPIFFS version available: %d.%d.%d, current version: %d.%d.%d but not necessary to update", latest_spiff_version.version.major, latest_spiff_version.version.minor, latest_spiff_version.version.patch, REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch);
|
|
||||||
} else {
|
|
||||||
Log.verbose("No new SPIFFS version available");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", current_software_version, BOARD_VARIANT);
|
||||||
|
OTA littlefs_ota("https://iot.tobiasmaier.me/filesystem/waterlevel", REQUIRED_SPIFFS_VERSION, "generic");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Firmware fw = ota.getLatestVersionOnServer();
|
// Check if internet connection exists before running update, the web client seems to fail otherwise
|
||||||
if (fw.valid) {
|
|
||||||
Log.verbose("New firmware available: %d.%d.%d, current version: %d.%d.%d", fw.version.major, fw.version.minor, fw.version.patch, current_software_version.major, current_software_version.minor, current_software_version.patch);
|
if (check_for_internet_connection()) {
|
||||||
ota_status.latest_version = fw.version;
|
LOG(ELOG_LEVEL_DEBUG, "Ping sucessful, starting update checks");
|
||||||
ota_status.update_url = fw.url;
|
check_and_update_littleFS(littlefs_ota);
|
||||||
if (isVersionNewer(current_software_version, fw.version)) {
|
check_and_update_firmware(ota);
|
||||||
Log.verbose("Remote version is newer than current version");
|
|
||||||
ota_status.update_available = true;
|
|
||||||
} else {
|
|
||||||
ota_status.update_available = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (fw.version.major != 0 && fw.version.minor != 0 && fw.version.patch != 0) {
|
LOG(ELOG_LEVEL_WARNING, "Server did not respond to ping, waiting...");
|
||||||
ota_status.latest_version = fw.version;
|
|
||||||
ota_status.update_available = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.verbose("No new firmware available");
|
|
||||||
}
|
}
|
||||||
delay(1000 * 60 * 1);
|
delay(1000 * 60 * 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_and_update_littleFS(OTA littlefs) {
|
||||||
|
Firmware latest_fs_version = littlefs.getLatestVersionOnServer();
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Required SPIFFS Version: %d.%d.%d; Current SPIFFS version: %d.%d.%d; Server SPIFFS Version: %d.%d.%d", REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch, current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch, latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch);
|
||||||
|
|
||||||
|
if (latest_fs_version.valid) {
|
||||||
|
|
||||||
|
// If we need new version and the server has a new version
|
||||||
|
if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION) && isVersionNewer(current_spiffs_version, latest_fs_version.version)) {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "New SPIFFS version, running update now");
|
||||||
|
run_ota_spiffs_update(latest_fs_version.url, update_started, update_finished, update_progress, update_error);
|
||||||
|
ESP.restart();
|
||||||
|
|
||||||
|
// If we do not need a new version but one is available on the server
|
||||||
|
} else if (isVersionNewer(REQUIRED_SPIFFS_VERSION, latest_fs_version.version)) {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "New SPIFFS version available: %d.%d.%d, current version: %d.%d.%d but not necessary to update", latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch, REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch);
|
||||||
|
|
||||||
|
// If we need a new version but server has no new version
|
||||||
|
} else if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION)) {
|
||||||
|
LOG(ELOG_LEVEL_ERROR, "New LittleFS Version is needed, but not found on server");
|
||||||
|
|
||||||
|
// Catch case for the rest
|
||||||
|
} else {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "No new SPIFFS version available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_and_update_firmware(OTA ota){
|
||||||
|
Firmware fw = ota.getLatestVersionOnServer();
|
||||||
|
if (fw.valid) {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Firmware available on server: %d.%d.%d, current version: %d.%d.%d", fw.version.major, fw.version.minor, fw.version.patch, current_software_version.major, current_software_version.minor, current_software_version.patch);
|
||||||
|
ota_status.latest_version = fw.version;
|
||||||
|
ota_status.update_url = fw.url;
|
||||||
|
if (isVersionNewer(current_software_version, fw.version)) {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Remote version is newer than current version");
|
||||||
|
ota_status.update_available = true;
|
||||||
|
} else {
|
||||||
|
ota_status.update_available = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fw.version.major != 0 && fw.version.minor != 0 && fw.version.patch != 0) {
|
||||||
|
ota_status.latest_version = fw.version;
|
||||||
|
ota_status.update_available = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "No new firmware available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_for_internet_connection() {
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin("https://iot.tobiasmaier.me");
|
||||||
|
int code = http.sendRequest("HEAD");
|
||||||
|
if (code > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run_ota_update_task(void* parameter) {
|
void run_ota_update_task(void* parameter) {
|
||||||
TaskArgs_t *args = (TaskArgs_t *) parameter;
|
TaskArgs_t *args = (TaskArgs_t *) parameter;
|
||||||
Log.verbose("Running OTA upgrade now with URL: %s", args->ota_status.update_url.c_str());
|
LOG(ELOG_LEVEL_DEBUG, "Running OTA upgrade now with URL: %s", args->ota_status.update_url.c_str());
|
||||||
run_ota_update(args->ota_status.update_url, update_started, update_finished, update_progress, update_error);
|
run_ota_update(args->ota_status.update_url, update_started, update_finished, update_progress, update_error);
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
@@ -151,3 +170,36 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_time_task(void* parameter) {
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Starting GetTimeTask");
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Trying to get time from Internet");
|
||||||
|
|
||||||
|
sntp_set_time_sync_notification_cb(onTimeSync);
|
||||||
|
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
|
||||||
|
sntp_set_sync_interval(1000 * 60 * 60); //re-sync every hour
|
||||||
|
configTzTime("UTC0", "pool.ntp.org", "1.europe.pool.ntp.org", " time.Windows.com");
|
||||||
|
waitForTime();
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time stuff
|
||||||
|
|
||||||
|
// Handler to handle successful time sync
|
||||||
|
void onTimeSync(struct timeval* tv) {
|
||||||
|
struct tm timeinfo;
|
||||||
|
getLocalTime(&timeinfo);
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Time synchronized. New Time: %s", asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for succesful time sync
|
||||||
|
bool waitForTime() {
|
||||||
|
time_t now;
|
||||||
|
do {
|
||||||
|
time(&now);
|
||||||
|
if (now > 8 * 3600) break;
|
||||||
|
delay(500);
|
||||||
|
LOG(ELOG_LEVEL_WARNING, "No valid time.");
|
||||||
|
} while (true);
|
||||||
|
LOG(ELOG_LEVEL_DEBUG, "Found valid time.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -11,6 +11,13 @@ String processor(const String& var);
|
|||||||
void check_update_task(void* parameter);
|
void check_update_task(void* parameter);
|
||||||
void run_ota_update_task(void* parameter);
|
void run_ota_update_task(void* parameter);
|
||||||
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,void *arg, uint8_t *data, size_t len);
|
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,void *arg, uint8_t *data, size_t len);
|
||||||
|
void get_time_task(void* parameter);
|
||||||
|
|
||||||
|
void onTimeSync(struct timeval* tv);
|
||||||
|
bool waitForTime();
|
||||||
|
void check_and_update_firmware(OTA fw);
|
||||||
|
void check_and_update_littleFS(OTA littlefs);
|
||||||
|
bool check_for_internet_connection();
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
OTAStatus ota_status;
|
OTAStatus ota_status;
|
||||||
|
|||||||
Reference in New Issue
Block a user